From c4fcffe436fbfb5b0f3b7be2e5ee103ec74932f7 Mon Sep 17 00:00:00 2001 From: Rene Stoeckel Date: Wed, 22 Sep 2004 19:22:16 +0000 Subject: major refactoring in game, server and client package --- src/jake2/Defines.java | 69 +- src/jake2/Jake2.java | 131 +- src/jake2/client/CL.java | 3207 +++++----- src/jake2/client/CL_ents.java | 1281 ++-- src/jake2/client/CL_fx.java | 2324 ++++--- src/jake2/client/CL_input.java | 675 +- src/jake2/client/CL_inv.java | 93 +- src/jake2/client/CL_newfx.java | 2000 +++--- src/jake2/client/CL_parse.java | 1525 +++-- src/jake2/client/CL_pred.java | 552 +- src/jake2/client/CL_tent.java | 3482 +++++------ src/jake2/client/CL_view.java | 340 +- src/jake2/client/Console.java | 1166 ++-- src/jake2/client/M.java | 1157 ++-- src/jake2/client/Menu.java | 9794 +++++++++++++++--------------- src/jake2/client/SCR.java | 3946 ++++++------ src/jake2/client/V.java | 774 ++- src/jake2/game/Cmd.java | 2541 ++++---- src/jake2/game/Fire.java | 1106 ++-- src/jake2/game/Game.java | 30 - src/jake2/game/GameAI.java | 6037 ++++++++++-------- src/jake2/game/GameAIAdapters.java | 1046 ---- src/jake2/game/GameBase.java | 1364 +++-- src/jake2/game/GameFunc.java | 2721 +++++++-- src/jake2/game/GameFuncAdapters.java | 1638 ----- src/jake2/game/GameMisc.java | 2374 +++++--- src/jake2/game/GameMiscAdapters.java | 1016 ---- src/jake2/game/GamePWeapon.java | 2786 ++++----- src/jake2/game/GameSVCmds.java | 583 +- src/jake2/game/GameSave.java | 594 +- src/jake2/game/GameSpawn.java | 1593 +++-- src/jake2/game/GameSpawnAdapters.java | 220 - src/jake2/game/GameTarget.java | 1104 +++- src/jake2/game/GameTargetAdapters.java | 581 -- src/jake2/game/GameTrigger.java | 808 ++- src/jake2/game/GameTriggerAdapters.java | 359 -- src/jake2/game/GameTurret.java | 604 +- src/jake2/game/GameTurretAdapters.java | 283 - src/jake2/game/GameUtil.java | 3038 +++++---- src/jake2/game/GameUtilAdapters.java | 635 -- src/jake2/game/GameWeapon.java | 628 +- src/jake2/game/GameWeaponAdapters.java | 474 -- src/jake2/game/Info.java | 454 +- src/jake2/game/M_Actor.java | 2695 ++++---- src/jake2/game/M_Berserk.java | 1682 ++--- src/jake2/game/M_Boss2.java | 1943 +++--- src/jake2/game/M_Boss3.java | 145 +- src/jake2/game/M_Boss31.java | 2180 ++++--- src/jake2/game/M_Boss32.java | 3427 ++++++----- src/jake2/game/M_Brain.java | 2078 ++++--- src/jake2/game/M_Chick.java | 2271 ++++--- src/jake2/game/M_Flash.java | 1191 ++-- src/jake2/game/M_Flipper.java | 1345 ++-- src/jake2/game/M_Float.java | 2201 ++++--- src/jake2/game/M_Flyer.java | 1772 +++--- src/jake2/game/M_Gladiator.java | 1190 ++-- src/jake2/game/M_Gunner.java | 1902 +++--- src/jake2/game/M_Hover.java | 1847 +++--- src/jake2/game/M_Infantry.java | 1863 +++--- src/jake2/game/M_Insane.java | 2226 ++++--- src/jake2/game/M_Medic.java | 2272 ++++--- src/jake2/game/M_Mutant.java | 1851 +++--- src/jake2/game/M_Parasite.java | 1498 +++-- src/jake2/game/M_Player.java | 638 +- src/jake2/game/M_Rider.java | 29 - src/jake2/game/M_Soldier.java | 3365 ++++++---- src/jake2/game/M_SoldierAdapters.java | 655 -- src/jake2/game/M_Supertank.java | 2199 ++++--- src/jake2/game/M_Tank.java | 2635 ++++---- src/jake2/game/Monster.java | 648 +- src/jake2/game/MonsterAdapters.java | 92 - src/jake2/game/PlayerClient.java | 2869 +++++---- src/jake2/game/PlayerClientAdapters.java | 291 +- src/jake2/game/PlayerHud.java | 981 +-- src/jake2/game/PlayerTrail.java | 227 +- src/jake2/game/PlayerView.java | 2110 +++---- src/jake2/game/edict_t.java | 1350 ++-- src/jake2/game/game_import_t.java | 488 +- src/jake2/game/game_locals_t.java | 191 +- src/jake2/game/gitem_t.java | 252 +- src/jake2/game/pmove_t.java | 169 +- src/jake2/qcommon/CM.java | 3779 ++++++------ src/jake2/qcommon/Cbuf.java | 452 +- src/jake2/qcommon/Cvar.java | 854 ++- src/jake2/qcommon/MSG.java | 1105 ++-- src/jake2/qcommon/Netchan.java | 707 ++- src/jake2/qcommon/PMove.java | 2421 ++++---- src/jake2/qcommon/Q2DataDialog.java | 854 +-- src/jake2/qcommon/netchan_t.java | 122 +- src/jake2/render/fastjogl/Image.java | 3263 +++++----- src/jake2/render/fastjogl/Light.java | 1414 +++-- src/jake2/render/fastjogl/Mesh.java | 1340 ++-- src/jake2/render/fastjogl/Misc.java | 272 +- src/jake2/render/fastjogl/Model.java | 2558 ++++---- src/jake2/render/fastjogl/Surf.java | 2764 ++++----- src/jake2/render/fastjogl/Warp.java | 1353 ++--- src/jake2/render/jogl/Image.java | 3288 +++++----- src/jake2/render/jogl/Light.java | 1438 +++-- src/jake2/render/jogl/Mesh.java | 1637 +++-- src/jake2/render/jogl/Warp.java | 1341 ++-- src/jake2/render/medge_t.java | 67 +- src/jake2/render/mvertex_t.java | 58 +- src/jake2/server/SV.java | 2298 ++++--- src/jake2/server/SV_CCMDS.java | 390 +- src/jake2/server/SV_ENTS.java | 1203 ++-- src/jake2/server/SV_GAME.java | 617 +- src/jake2/server/SV_INIT.java | 962 +-- src/jake2/server/SV_MAIN.java | 2034 ++++--- src/jake2/server/SV_SEND.java | 266 +- src/jake2/server/SV_USER.java | 1408 +++-- src/jake2/server/SV_WORLD.java | 1198 ++-- src/jake2/server/server_static_t.java | 98 +- src/jake2/server/server_t.java | 124 +- src/jake2/sound/joal/JOALSoundImpl.java | 7 +- src/jake2/sound/jsound/SND_DMA.java | 2306 ++++--- src/jake2/sound/jsound/SND_MIX.java | 935 +-- src/jake2/sys/IN.java | 386 +- src/jake2/sys/Sys.java | 436 +- src/jake2/util/Lib.java | 83 +- src/jake2/util/Math3D.java | 105 +- src/jake2/util/QuakeFile.java | 314 +- 121 files changed, 87217 insertions(+), 82941 deletions(-) delete mode 100644 src/jake2/game/Game.java delete mode 100644 src/jake2/game/GameAIAdapters.java delete mode 100644 src/jake2/game/GameFuncAdapters.java delete mode 100644 src/jake2/game/GameMiscAdapters.java delete mode 100644 src/jake2/game/GameSpawnAdapters.java delete mode 100644 src/jake2/game/GameTargetAdapters.java delete mode 100644 src/jake2/game/GameTriggerAdapters.java delete mode 100644 src/jake2/game/GameTurretAdapters.java delete mode 100644 src/jake2/game/GameUtilAdapters.java delete mode 100644 src/jake2/game/GameWeaponAdapters.java delete mode 100644 src/jake2/game/M_Rider.java delete mode 100644 src/jake2/game/M_SoldierAdapters.java delete mode 100644 src/jake2/game/MonsterAdapters.java (limited to 'src') diff --git a/src/jake2/Defines.java b/src/jake2/Defines.java index 43bad3b..5a7cf29 100644 --- a/src/jake2/Defines.java +++ b/src/jake2/Defines.java @@ -19,29 +19,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Created on 31.10.2003 by RST. -// $Id: Defines.java,v 1.4 2004-09-10 19:02:57 salomo Exp $ +// $Id: Defines.java,v 1.5 2004-09-22 19:22:14 salomo Exp $ /** Contains the definitions for the game engine. */ package jake2; +import jake2.game.pmove_t; import jake2.util.*; -public class Defines extends Math3D { - - // used by filefinders in Sys - public final static int FILEISREADABLE = 1; - public final static int FILEISWRITABLE = 2; - public final static int FILEISFILE = 4; - public final static int FILEISDIRECTORY = 8; - - // datentyp konstanten - // groesse in bytes - public final static int SIZE_OF_SHORT = 2; - public final static int SIZE_OF_INT = 4; - public final static int SIZE_OF_LONG = 8; - public final static int SIZE_OF_FLOAT = 4; - public final static int SIZE_OF_DOUBLE = 8; +public class Defines { public final static int WEAPON_READY = 0; public final static int WEAPON_ACTIVATING = 1; @@ -169,15 +156,6 @@ public class Defines extends Math3D { public final static int SURF_FLOWING = 0x40; // scroll towards angle public final static int SURF_NODRAW = 0x80; // don't bother referencing the texture - // pmove->pm_flags - public final static int PMF_DUCKED = 1; - public final static int PMF_JUMP_HELD = 2; - public final static int PMF_ON_GROUND = 4; - public final static int PMF_TIME_WATERJUMP = 8; // pm_time is waterjump - public final static int PMF_TIME_LAND = 16; // pm_time is time before rejump - public final static int PMF_TIME_TELEPORT = 32; // pm_time is non-moving time - public final static int PMF_NO_PREDICTION = 64; // temporarily disables prediction (used for grappling hook) - // // button bits // @@ -1355,4 +1333,43 @@ public class Defines extends Math3D { public final static int MAX_LOCAL_SERVERS = 8; public final static String NO_SERVER_STRING = ""; public final static int NUM_ADDRESSBOOK_ENTRIES = 9; -} + + public final static int STEPSIZE = 18; + + + public static final float MOVE_STOP_EPSILON = 0.1f; + + /* + ================== + PM_StepSlideMove + + Each intersection will try to step over the obstruction instead of + sliding along it. + + Returns a new origin, velocity, and contact entity + Does not modify any world state? + ================== + */ + public final static float MIN_STEP_NORMAL = 0.7f; // can't step up onto very steep slopes + + + // used by filefinders in Sys + public final static int FILEISREADABLE = 1; + + public final static int FILEISWRITABLE = 2; + + public final static int FILEISFILE = 4; + + public final static int FILEISDIRECTORY = 8; + + // datentyp konstanten + // groesse in bytes + public final static int SIZE_OF_SHORT = 2; + + public final static int SIZE_OF_INT = 4; + + public final static int SIZE_OF_LONG = 8; + + public final static int SIZE_OF_FLOAT = 4; + + public final static int SIZE_OF_DOUBLE = 8;} diff --git a/src/jake2/Jake2.java b/src/jake2/Jake2.java index 8701969..174ef13 100644 --- a/src/jake2/Jake2.java +++ b/src/jake2/Jake2.java @@ -2,27 +2,27 @@ * Jake2.java * Copyright (C) 2003 * - * $Id: Jake2.java,v 1.4 2004-09-19 19:53:51 hzi Exp $ + * $Id: Jake2.java,v 1.5 2004-09-22 19:22:14 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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; import jake2.client.SCR; @@ -36,45 +36,64 @@ import jake2.sys.Sys; */ public final class Jake2 { - public static Q2DataDialog Q2Dialog = new Q2DataDialog(); - - /** - * main is used to start the game. Quake2 for Java supports the - * following command line arguments: - * @param args - */ - public static void main(String[] args) { - - Q2Dialog.setVisible(true); - - // in C the first arg is the filename - int argc = (args == null) ? 1 : args.length + 1; - String[] c_args = new String[argc]; - c_args[0] = "Jake2"; - if (argc > 1) { - System.arraycopy(args, 0, c_args, 1, argc - 1); - } - Qcommon.Init(c_args); - - Globals.nostdout = Cvar.Get("nostdout", "0", 0); - - int oldtime = Sys.Milliseconds(); - int newtime; - int time; - while (true) { - // find time spending rendering last frame - newtime = Sys.Milliseconds(); - time = newtime - oldtime; - - // TODO this is a timer hack for Win2000 - // System.currentTimeMillis() resolution bug - if (time == 0 && (Globals.cl_timedemo.value != 0 || SCR.fps.value != 0)) { - time++; - } - - if (time > 0) - Qcommon.Frame(time); - oldtime = newtime; - } - } -} + static class MemMonitor implements Runnable { + public void run() { + while (true) { + Com.Printf("Memory:" + + (Runtime.getRuntime().totalMemory() - Runtime + .getRuntime().freeMemory()) + "\n"); + try { + Thread.sleep(1000); + } catch (Exception e) { + } + } + } + } + + public static Q2DataDialog Q2Dialog = new Q2DataDialog(); + + /** + * main is used to start the game. Quake2 for Java supports the following + * command line arguments: + * + * @param args + */ + public static void main(String[] args) { + + Q2Dialog.setVisible(true); + + // uncomment to have a memory debugger (RST). + //new Thread(new MemMonitor()).start(); + + // in C the first arg is the filename + int argc = (args == null) ? 1 : args.length + 1; + String[] c_args = new String[argc]; + c_args[0] = "Jake2"; + if (argc > 1) { + System.arraycopy(args, 0, c_args, 1, argc - 1); + } + Qcommon.Init(c_args); + + Globals.nostdout = Cvar.Get("nostdout", "0", 0); + + int oldtime = Sys.Milliseconds(); + int newtime; + int time; + while (true) { + // find time spending rendering last frame + newtime = Sys.Milliseconds(); + time = newtime - oldtime; + + // TODO this is a timer hack for Win2000 + // System.currentTimeMillis() resolution bug + if (time == 0 + && (Globals.cl_timedemo.value != 0 || SCR.fps.value != 0)) { + time++; + } + + if (time > 0) + Qcommon.Frame(time); + oldtime = newtime; + } + } +} \ No newline at end of file diff --git a/src/jake2/client/CL.java b/src/jake2/client/CL.java index 3170112..dcdf7db 100644 --- a/src/jake2/client/CL.java +++ b/src/jake2/client/CL.java @@ -2,36 +2,39 @@ * CL.java * Copyright (C) 2004 * - * $Id: CL.java,v 1.10 2004-09-08 09:37:39 hzi Exp $ + * $Id: CL.java,v 1.11 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; import jake2.Defines; import jake2.Globals; import jake2.game.*; import jake2.qcommon.*; +import jake2.qcommon.qfiles.dmdl_t; import jake2.server.SV_MAIN; import jake2.sound.*; import jake2.sys.*; +import jake2.util.Lib; +import jake2.util.Math3D; import jake2.util.Vargs; import java.io.IOException; @@ -42,1590 +45,1630 @@ import java.nio.ByteOrder; /** * CL */ -public final class CL extends CL_pred { - - /* - ==================== - CL_WriteDemoMessage - - Dumps the current net message, prefixed by the length - ==================== - */ - static void WriteDemoMessage() { - int swlen; - - // the first eight bytes are just packet sequencing stuff - swlen = net_message.cursize - 8; - - try { - cls.demofile.writeInt(swlen); - //fwrite (&swlen, 4, 1, cls.demofile); - cls.demofile.write(net_message.data, 8, swlen); - //fwrite (net_message.data+8, len, 1, cls.demofile); - } catch (IOException e) {} - - } - - /* - ==================== - CL_Stop_f - - stop recording a demo - ==================== - */ - static xcommand_t Stop_f = new xcommand_t() { - public void execute() { - try { - - int len; - - if (!cls.demorecording) { - Com.Printf("Not recording a demo.\n"); - return; - } - - // finish up - len = -1; - cls.demofile.writeInt(len); - cls.demofile.close(); - cls.demofile = null; - cls.demorecording = false; - Com.Printf("Stopped demo.\n"); - } - catch (IOException e) { - } - } - }; - - /* - ==================== - CL_Record_f - - record - - Begins recording a demo from the current position - ==================== - */ - static entity_state_t nullstate = new entity_state_t(null); - - static xcommand_t Record_f = new xcommand_t() { - public void execute() { - try { - String name; - byte buf_data[] = new byte[MAX_MSGLEN]; - sizebuf_t buf = new sizebuf_t(); - int i; - entity_state_t ent; - - if (Cmd.Argc() != 2) { - Com.Printf("record \n"); - return; - } - - if (cls.demorecording) { - Com.Printf("Already recording.\n"); - return; - } - - if (cls.state != ca_active) { - Com.Printf("You must be in a level to record.\n"); - return; - } - - // - // open the demo file - // - name = FS.Gamedir() + "/demos/" + Cmd.Argv(1) + ".dm2"; - - Com.Printf("recording to " + name + ".\n"); - FS.CreatePath(name); - cls.demofile = new RandomAccessFile(name, "rw"); - if (cls.demofile == null) { - Com.Printf("ERROR: couldn't open.\n"); - return; - } - cls.demorecording = true; - - // don't start saving messages until a non-delta compressed message is received - cls.demowaiting = true; - - // - // write out messages to hold the startup information - // - SZ.Init(buf, buf_data, MAX_MSGLEN); - - // send the serverdata - MSG.WriteByte(buf, svc_serverdata); - MSG.WriteInt(buf, PROTOCOL_VERSION); - MSG.WriteInt(buf, 0x10000 + cl.servercount); - MSG.WriteByte(buf, 1); // demos are always attract loops - MSG.WriteString(buf, cl.gamedir); - MSG.WriteShort(buf, cl.playernum); - - MSG.WriteString(buf, cl.configstrings[CS_NAME]); - - // configstrings - for (i = 0; i < MAX_CONFIGSTRINGS; i++) { - if (cl.configstrings[i].length()>0) { - if (buf.cursize + cl.configstrings[i].length() + 32 > buf.maxsize) { // write it out - //len = LittleLong(buf.cursize); - //fwrite(& len, 4, 1, cls.demofile); - cls.demofile.writeInt(buf.cursize); - //fwrite(buf.data, buf.cursize, 1, cls.demofile); - cls.demofile.write(buf.data, 0, buf.cursize); - buf.cursize = 0; - } - - MSG.WriteByte(buf, svc_configstring); - MSG.WriteShort(buf, i); - MSG.WriteString(buf, cl.configstrings[i]); - } - - } - - // baselines - //memset( nullstate, 0, sizeof(nullstate)); - for (i = 0; i < MAX_EDICTS; i++) { - ent = cl_entities[i].baseline; - if (ent.modelindex == 0) - continue; - - if (buf.cursize + 64 > buf.maxsize) { // write it out - //len = LittleLong(buf.cursize); - //fwrite(& len, 4, 1, cls.demofile); - cls.demofile.writeInt(buf.cursize); - //fwrite(buf.data, buf.cursize, 1, cls.demofile); - cls.demofile.write(buf.data, 0, buf.cursize); - buf.cursize = 0; - } - - MSG.WriteByte(buf, svc_spawnbaseline); - MSG.WriteDeltaEntity(nullstate, cl_entities[i].baseline, buf, true, true); - } - - MSG.WriteByte(buf, svc_stufftext); - MSG.WriteString(buf, "precache\n"); - - // write it to the demo file - - //len = LittleLong(buf.cursize); - //fwrite(& len, 4, 1, cls.demofile); - cls.demofile.writeInt(buf.cursize); - //fwrite(buf.data, buf.cursize, 1, cls.demofile); - cls.demofile.write(buf.data, 0, buf.cursize); - // the rest of the demo file will be individual frames - - } - catch (IOException e) { - } - } - }; - - /* - ================== - CL_ForwardToServer_f - ================== - */ - static xcommand_t ForwardToServer_f = new xcommand_t() { - public void execute() { - if (cls.state != ca_connected && cls.state != ca_active) { - Com.Printf("Can't \"" + Cmd.Argv(0) + "\", not connected\n"); - return; - } - - // don't forward the first argument - if (Cmd.Argc() > 1) { - MSG.WriteByte(cls.netchan.message, clc_stringcmd); - SZ.Print(cls.netchan.message, Cmd.Args()); - } - } - }; - - /* - ================== - CL_Pause_f - ================== - */ - static xcommand_t Pause_f = new xcommand_t() { - public void execute() { - // never pause in multiplayer - - if (Cvar.VariableValue("maxclients") > 1 || Globals.server_state == 0) { - Cvar.SetValue("paused", 0); - return; - } - - Cvar.SetValue("paused", cl_paused.value); - } - }; - - /* - ================== - CL_Quit_f - ================== - */ - static xcommand_t Quit_f = new xcommand_t() { - public void execute() { - Disconnect(); - Com.Quit(); - } - }; - - /* - ======================= - CL_SendConnectPacket - - We have gotten a challenge from the server, so try and - connect. - ====================== - */ - static void SendConnectPacket() { - netadr_t adr = new netadr_t(); - int port; - - if (!NET.StringToAdr(cls.servername, adr)) { - Com.Printf("Bad server address\n"); - cls.connect_time = 0; - return; - } - if (adr.port == 0) - adr.port = PORT_SERVER; - // adr.port = BigShort(PORT_SERVER); - - port = (int) Cvar.VariableValue("qport"); - userinfo_modified = false; - - Netchan.OutOfBandPrint( - NS_CLIENT, - adr, - "connect " + PROTOCOL_VERSION + " " + port + " " + cls.challenge + " \"" + Cvar.Userinfo() + "\"\n"); - } - - /* - ================= - CL_CheckForResend - - Resend a connect message if the last one has timed out - ================= - */ - static void CheckForResend() { - netadr_t adr = new netadr_t(); - - // if the local server is running and we aren't - // then connect - if (cls.state == ca_disconnected && Globals.server_state != 0) { - cls.state = ca_connecting; - cls.servername = "localhost"; - // we don't need a challenge on the localhost - CL.SendConnectPacket(); - return; - } - - // resend if we haven't gotten a reply yet - if (cls.state != ca_connecting) - return; - - if (cls.realtime - cls.connect_time < 3000) - return; - - if (!NET.StringToAdr(cls.servername, adr)) { - Com.Printf("Bad server address\n"); - cls.state = ca_disconnected; - return; - } - if (adr.port == 0) - // adr.port = BigShort(PORT_SERVER); - adr.port = PORT_SERVER; - - cls.connect_time = cls.realtime; // for retransmit requests - - Com.Printf("Connecting to " + cls.servername + "...\n"); - - Netchan.OutOfBandPrint(NS_CLIENT, adr, "getchallenge\n"); - } - - /* - ================ - CL_Connect_f - - ================ - */ - static xcommand_t Connect_f = new xcommand_t() { - public void execute() { - String server; - - if (Cmd.Argc() != 2) { - Com.Printf("usage: connect \n"); - return; - } - - if (Globals.server_state != 0) { - // if running a local server, kill it and reissue - SV_MAIN.SV_Shutdown("Server quit\n", false); - } else { - CL.Disconnect(); - } - - server = Cmd.Argv(1); - - NET.Config(true); // allow remote - - CL.Disconnect(); - - cls.state = ca_connecting; - //strncpy (cls.servername, server, sizeof(cls.servername)-1); - cls.servername = server; - cls.connect_time = -99999; - // CL_CheckForResend() will fire immediately - } - }; - - /* - ===================== - CL_Rcon_f - - Send the rest of the command line over as - an unconnected command. - ===================== - */ - static xcommand_t Rcon_f = new xcommand_t() { - public void execute() { - StringBuffer message = new StringBuffer(1024); - int i; - netadr_t to = new netadr_t(); - - if (rcon_client_password.string == null) { - Com.Printf("You must set 'rcon_password' before\nissuing an rcon command.\n"); - return; - } - - message.append((char)255); - message.append((char)255); - message.append((char)255); - message.append((char)255); - - NET.Config(true); // allow remote - - //strcat (message, "rcon "); - message.append("rcon "); - - //strcat (message, rcon_client_password.string); - message.append(rcon_client_password.string); - //strcat (message, " "); - message.append(" "); - - for (i = 1; i < Cmd.Argc(); i++) { - //strcat (message, Cmd.Argv(i)); - message.append(Cmd.Argv(i)); - //strcat (message, " "); - message.append(" "); - } - - if (cls.state >= ca_connected) - to = cls.netchan.remote_address; - else { - if (rcon_address.string.length() == 0) { - Com.Printf( - "You must either be connected,\nor set the 'rcon_address' cvar\nto issue rcon commands\n"); - - return; - } - NET.StringToAdr(rcon_address.string, to); - if (to.port == 0) - //to.port = BigShort (PORT_SERVER); - to.port = PORT_SERVER; - } - message.append('\0'); - String b = message.toString(); - NET.SendPacket(NS_CLIENT, b.length(), b.getBytes(), to); - } - }; - - /* - ===================== - CL_ClearState - - ===================== - */ - - static void ClearState() { - S.StopAllSounds(); - CL.ClearEffects(); - CL.ClearTEnts(); - - // wipe the entire cl structure - - cl = new client_state_t(); - for (int i = 0; i < cl_entities.length; i++) { - cl_entities[i] = new centity_t(); - } - - SZ.Clear(cls.netchan.message); - } - - /* - ===================== - CL_Disconnect - - Goes from a connected state to full screen console state - Sends a disconnect message to the server - This is also called on Com_Error, so it shouldn't cause any errors - ===================== - */ - - static void Disconnect() { - - String fin; - - if (cls.state == ca_disconnected) - return; - - if (cl_timedemo != null && cl_timedemo.value != 0.0f) { - int time; - - time = (int) (Sys.Milliseconds() - cl.timedemo_start); - if (time > 0) - Com.Printf( - "%i frames, %3.1f seconds: %3.1f fps\n", - new Vargs(3).add(cl.timedemo_frames).add(time / 1000.0).add(cl.timedemo_frames * 1000.0 / time)); - } - - VectorClear(cl.refdef.blend); - //re.CinematicSetPalette(null); - - Menu.ForceMenuOff(); - - cls.connect_time = 0; - - // SCR.StopCinematic(); - - if (cls.demorecording) - CL.Stop_f.execute(); - - // send a disconnect message to the server - fin = (char) clc_stringcmd + "disconnect"; - Netchan.Transmit(cls.netchan, fin.length(), fin.getBytes()); - Netchan.Transmit(cls.netchan, fin.length(), fin.getBytes()); - Netchan.Transmit(cls.netchan, fin.length(), fin.getBytes()); - - CL.ClearState(); - - // stop download - if (cls.download != null) { - fclose(cls.download); - cls.download = null; - // fclose(cls.download); - // cls.download = NULL; - } - - cls.state = ca_disconnected; - } - - static xcommand_t Disconnect_f = new xcommand_t() { - public void execute() { - Com.Error(ERR_DROP, "Disconnected from server"); - } - }; - - /* - ================= - CL_Changing_f - - Just sent as a hint to the client that they should - drop to full console - ================= - */ - static xcommand_t Changing_f = new xcommand_t() { - public void execute() { - //ZOID - //if we are downloading, we don't change! - // This so we don't suddenly stop downloading a map - - if (cls.download != null) - return; - - SCR.BeginLoadingPlaque(); - cls.state = ca_connected; // not active anymore, but not disconnected - Com.Printf("\nChanging map...\n"); - } - }; - - /* - ================= - CL_Reconnect_f - - The server is changing levels - ================= - */ - static xcommand_t Reconnect_f = new xcommand_t() { - public void execute() { - //ZOID - //if we are downloading, we don't change! This so we don't suddenly stop downloading a map - if (cls.download != null) - return; - - S.StopAllSounds(); - if (cls.state == ca_connected) { - Com.Printf("reconnecting...\n"); - cls.state = ca_connected; - MSG.WriteChar(cls.netchan.message, clc_stringcmd); - MSG.WriteString(cls.netchan.message, "new"); - return; - } - - if (cls.servername != null) { - if (cls.state >= ca_connected) { - CL.Disconnect(); - cls.connect_time = cls.realtime - 1500; - } else - cls.connect_time = -99999; // fire immediately - - cls.state = ca_connecting; - Com.Printf("reconnecting...\n"); - } - } - }; - - /* - ================= - CL_ParseStatusMessage - - Handle a reply from a ping - ================= - */ - static void ParseStatusMessage() { - String s; - - s = MSG.ReadString(net_message); - - Com.Printf(s + "\n"); - Menu.AddToServerList(net_from, s); - } - - /* - ================= - CL_PingServers_f - ================= - */ - static xcommand_t PingServers_f = new xcommand_t() { - public void execute() { - int i; - netadr_t adr = new netadr_t(); - //char name[32]; - String name; - String adrstring; - cvar_t noudp; - cvar_t noipx; - - NET.Config(true); // allow remote - - // send a broadcast packet - Com.Printf("pinging broadcast...\n"); - - noudp = Cvar.Get("noudp", "0", CVAR_NOSET); - if (noudp.value == 0.0f) { - adr.type = NA_BROADCAST; - adr.port = PORT_SERVER; - //adr.port = BigShort(PORT_SERVER); - Netchan.OutOfBandPrint(NS_CLIENT, adr, "info " + PROTOCOL_VERSION); - } - - // we use no IPX - noipx = Cvar.Get("noipx", "1", CVAR_NOSET); - if (noipx.value == 0.0f) { - adr.type = NA_BROADCAST_IPX; - //adr.port = BigShort(PORT_SERVER); - adr.port = PORT_SERVER; - Netchan.OutOfBandPrint(NS_CLIENT, adr, "info " + PROTOCOL_VERSION); - } - - // send a packet to each address book entry - for (i = 0; i < 16; i++) { - //Com_sprintf (name, sizeof(name), "adr%i", i); - name = "adr" + i; - adrstring = Cvar.VariableString(name); - if (adrstring == null || adrstring.length() == 0) - continue; - - Com.Printf("pinging " + adrstring + "...\n"); - if (!NET.StringToAdr(adrstring, adr)) { - Com.Printf("Bad address: " + adrstring + "\n"); - continue; - } - if (adr.port == 0) - //adr.port = BigShort(PORT_SERVER); - adr.port = PORT_SERVER; - Netchan.OutOfBandPrint(NS_CLIENT, adr, "info " + PROTOCOL_VERSION); - } - } - }; - - - /* - ================= - CL_Skins_f - - Load or download any custom player skins and models - ================= - */ - static xcommand_t Skins_f = new xcommand_t() { - public void execute() { - int i; - - for (i = 0; i < MAX_CLIENTS; i++) { - if (cl.configstrings[CS_PLAYERSKINS + i] == null) - continue; - Com.Printf("client " + i + ": " + cl.configstrings[CS_PLAYERSKINS + i] + "\n"); - SCR.UpdateScreen(); - Sys.SendKeyEvents(); // pump message loop - CL.ParseClientinfo(i); - } - } - }; - - /* - ================= - CL_ConnectionlessPacket - - Responses to broadcasts, etc - ================= - */ - static void ConnectionlessPacket() { - String s; - String c; - - MSG.BeginReading(net_message); - MSG.ReadLong(net_message); // skip the -1 - - s = MSG.ReadStringLine(net_message); - - Cmd.TokenizeString(s.toCharArray(), false); - - c = Cmd.Argv(0); - - Com.Printf(NET.AdrToString(net_from) + ": " + c + "\n"); - - // server connection - if (c.equals("client_connect")) { - if (cls.state == ca_connected) { - Com.Printf("Dup connect received. Ignored.\n"); - return; - } - Netchan.Setup(NS_CLIENT, cls.netchan, net_from, cls.quakePort); - MSG.WriteChar(cls.netchan.message, clc_stringcmd); - MSG.WriteString(cls.netchan.message, "new"); - cls.state = ca_connected; - return; - } - - // server responding to a status broadcast - if (c.equals("info")) { - CL.ParseStatusMessage(); - return; - } - - // remote command from gui front end - if (c.equals ("cmd")) { - if (!NET.IsLocalAddress(net_from)) { - Com.Printf("Command packet from remote host. Ignored.\n"); - return; - } - s = MSG.ReadString(net_message); - Cbuf.AddText(s); - Cbuf.AddText("\n"); - return; - } - // print command from somewhere - if (c.equals("print")) { - s = MSG.ReadString(net_message); - Com.Printf(s); - return; - } - - // ping from somewhere - if (c.equals("ping")) { - Netchan.OutOfBandPrint(NS_CLIENT, net_from, "ack"); - return; - } - - // challenge from the server we are connecting to - if (c.equals("challenge")) { - cls.challenge = Integer.parseInt(Cmd.Argv(1)); - CL.SendConnectPacket(); - return; - } - - // echo request from server - if (c.equals("echo")) { - Netchan.OutOfBandPrint(NS_CLIENT, net_from, Cmd.Argv(1)); - return; - } - - Com.Printf("Unknown command.\n"); - } - - /* - ================= - CL_DumpPackets - - A vain attempt to help bad TCP stacks that cause problems - when they overflow - ================= - */ - static void DumpPackets() { - while (NET.GetPacket(NS_CLIENT, net_from, net_message)) { - Com.Printf("dumping a packet\n"); - } - } - - /* - ================= - CL_ReadPackets - ================= - */ - static void ReadPackets() { - while (NET.GetPacket(NS_CLIENT, net_from, net_message)) { - - // - // remote command packet - // - if (net_message.data[0] == -1 && net_message.data[1] == -1 - && net_message.data[2] == -1 && net_message.data[3] == -1) { - // if (*(int *)net_message.data == -1) - CL.ConnectionlessPacket(); - continue; - } - - if (cls.state == ca_disconnected || cls.state == ca_connecting) - continue; // dump it if not connected - - if (net_message.cursize < 8) { - Com.Printf(NET.AdrToString(net_from) + ": Runt packet\n"); - continue; - } - - // - // packet from server - // - if (!NET.CompareAdr(net_from, cls.netchan.remote_address)) { - Com.DPrintf(NET.AdrToString(net_from) + ":sequenced packet without connection\n"); - continue; - } - if (!Netchan.Process(cls.netchan, net_message)) - continue; // wasn't accepted for some reason - ParseServerMessage(); - } - - // - // check timeout - // - if (cls.state >= ca_connected && cls.realtime - cls.netchan.last_received > cl_timeout.value * 1000) { - if (++cl.timeoutcount > 5) // timeoutcount saves debugger - { - Com.Printf("\nServer connection timed out.\n"); - CL.Disconnect(); - return; - } - } - else - cl.timeoutcount = 0; - } - - // ============================================================================= - - /* - ============== - CL_FixUpGender_f - ============== - */ - static void FixUpGender() { - - String sk; - - if (gender_auto.value != 0.0f) { - - if (gender.modified) { - // was set directly, don't override the user - gender.modified = false; - return; - } - - sk = skin.string; - if (sk.startsWith("male") || sk.startsWith("cyborg")) - Cvar.Set("gender", "male"); - else if (sk.startsWith("female") || sk.startsWith("crackhor")) - Cvar.Set("gender", "female"); - else - Cvar.Set("gender", "none"); - gender.modified = false; - } - } - - /* - ============== - CL_Userinfo_f - ============== - */ - static xcommand_t Userinfo_f = new xcommand_t() { - public void execute() { - Com.Printf("User info settings:\n"); - Info.Print(Cvar.Userinfo()); - } - }; - - /* - ================= - CL_Snd_Restart_f - - Restart the sound subsystem so it can pick up - new parameters and flush all sounds - ================= - */ - static xcommand_t Snd_Restart_f = new xcommand_t() { - public void execute() { - S.Shutdown(); - S.Init(); - CL.RegisterSounds(); - } - }; - - static int precache_check; // for autodownload of precache items - static int precache_spawncount; - static int precache_tex; - static int precache_model_skin; - - static byte precache_model[]; // used for skin checking in alias models - - public static final int PLAYER_MULT = 5; - - // ENV_CNT is map load, ENV_CNT+1 is first env map - public static final int ENV_CNT = (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT); - public static final int TEXTURE_CNT = (ENV_CNT + 13); - - static String env_suf[] = { "rt", "bk", "lf", "ft", "up", "dn" }; - - public static void RequestNextDownload() { - int map_checksum = 0; // for detecting cheater maps - //char fn[MAX_OSPATH]; - String fn; - - qfiles.dmdl_t pheader; - - if (cls.state != ca_connected) - return; - - if (SV_MAIN.allow_download.value == 0 && precache_check < ENV_CNT) - precache_check = ENV_CNT; - - // ZOID - if (precache_check == CS_MODELS) { // confirm map - precache_check = CS_MODELS + 2; // 0 isn't used - if (SV_MAIN.allow_download_maps.value != 0) - if (!CheckOrDownloadFile(cl.configstrings[CS_MODELS + 1])) - return; // started a download - } - if (precache_check >= CS_MODELS && precache_check < CS_MODELS + MAX_MODELS) { - if (SV_MAIN.allow_download_models.value != 0) { - while (precache_check < CS_MODELS + MAX_MODELS && cl.configstrings[precache_check].length() > 0) { - if (cl.configstrings[precache_check].charAt(0) == '*' || cl.configstrings[precache_check].charAt(0) == '#') { - precache_check++; - continue; - } - if (precache_model_skin == 0) { - if (!CheckOrDownloadFile(cl.configstrings[precache_check])) { - precache_model_skin = 1; - return; // started a download - } - precache_model_skin = 1; - } - - // checking for skins in the model - if (precache_model == null) { - - precache_model = FS.LoadFile(cl.configstrings[precache_check]); - if (precache_model == null) { - precache_model_skin = 0; - precache_check++; - continue; // couldn't load it - } - ByteBuffer bb = ByteBuffer.wrap(precache_model); - bb.order(ByteOrder.LITTLE_ENDIAN); - - int header = bb.getInt(); - - if (header != qfiles.IDALIASHEADER) { - // not an alias model - FS.FreeFile(precache_model); - precache_model = null; - precache_model_skin = 0; - precache_check++; - continue; - } - pheader = new qfiles.dmdl_t(ByteBuffer.wrap(precache_model).order(ByteOrder.LITTLE_ENDIAN)); - if (pheader.version != ALIAS_VERSION) { - precache_check++; - precache_model_skin = 0; - continue; // couldn't load it - } - } - - pheader = new qfiles.dmdl_t(ByteBuffer.wrap(precache_model).order(ByteOrder.LITTLE_ENDIAN)); - - int num_skins = pheader.num_skins; - - while (precache_model_skin - 1 < num_skins) { - //Com.Printf("critical code section because of endian mess!\n"); - - String name = - new String( - precache_model, - pheader.ofs_skins + (precache_model_skin - 1) * MAX_SKINNAME, - MAX_SKINNAME * num_skins); - - if (!CheckOrDownloadFile(name)) { - precache_model_skin++; - return; // started a download - } - precache_model_skin++; - } - if (precache_model != null) { - FS.FreeFile(precache_model); - precache_model = null; - } - precache_model_skin = 0; - precache_check++; - } - } - precache_check = CS_SOUNDS; - } - if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS + MAX_SOUNDS) { - if (SV_MAIN.allow_download_sounds.value != 0) { - if (precache_check == CS_SOUNDS) - precache_check++; // zero is blank - while (precache_check < CS_SOUNDS + MAX_SOUNDS && cl.configstrings[precache_check].length() > 0) { - if (cl.configstrings[precache_check].charAt(0) == '*') { - precache_check++; - continue; - } - fn = "sound/" + cl.configstrings[precache_check++]; - if (!CheckOrDownloadFile(fn)) - return; // started a download - } - } - precache_check = CS_IMAGES; - } - if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES + MAX_IMAGES) { - if (precache_check == CS_IMAGES) - precache_check++; // zero is blank - - while (precache_check < CS_IMAGES + MAX_IMAGES && cl.configstrings[precache_check].length() > 0) { - fn = "pics/" + cl.configstrings[precache_check++] + ".pcx"; - if (!CheckOrDownloadFile(fn)) - return; // started a download - } - precache_check = CS_PLAYERSKINS; - } - // skins are special, since a player has three things to download: - // model, weapon model and skin - // so precache_check is now *3 - if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) { - if (SV_MAIN.allow_download_players.value != 0) { - while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) { - - int i, n; - //char model[MAX_QPATH], skin[MAX_QPATH], * p; - String model, skin; - - i = (precache_check - CS_PLAYERSKINS) / PLAYER_MULT; - n = (precache_check - CS_PLAYERSKINS) % PLAYER_MULT; - - if (cl.configstrings[CS_PLAYERSKINS + i].length() == 0) { - precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT; - continue; - } - - int pos = cl.configstrings[CS_PLAYERSKINS + i].indexOf('\\'); - if (pos != -1) - pos++; - else - pos = 0; - - model = cl.configstrings[CS_PLAYERSKINS + i].substring(pos); - - pos = model.indexOf('/'); - - if (pos == -1) - pos = model.indexOf('\\'); - - if (pos != -1) { - skin = model.substring(pos + 1); - } - else - skin = ""; - - switch (n) { - case 0 : // model - fn = "players/" + model + "/tris.md2"; - if (!CheckOrDownloadFile(fn)) { - precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1; - return; // started a download - } - n++; - /*FALL THROUGH*/ - - case 1 : // weapon model - fn = "players/" + model + "/weapon.md2"; - if (!CheckOrDownloadFile(fn)) { - precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2; - return; // started a download - } - n++; - /*FALL THROUGH*/ - - case 2 : // weapon skin - fn = "players/" + model + "/weapon.pcx"; - if (!CheckOrDownloadFile(fn)) { - precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3; - return; // started a download - } - n++; - /*FALL THROUGH*/ - - case 3 : // skin - fn = "players/" + model + "/" + skin + ".pcx"; - if (!CheckOrDownloadFile(fn)) { - precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4; - return; // started a download - } - n++; - /*FALL THROUGH*/ - - case 4 : // skin_i - fn = "players/" + model + "/" + skin + "_i.pcx"; - if (!CheckOrDownloadFile(fn)) { - precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5; - return; // started a download - } - // move on to next model - precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT; - } - } - } - // precache phase completed - precache_check = ENV_CNT; - } - - if (precache_check == ENV_CNT) { - precache_check = ENV_CNT + 1; - - int iw[] = {map_checksum}; - - CM.CM_LoadMap(cl.configstrings[CS_MODELS + 1], true, iw); - map_checksum = iw[0]; - - if ((map_checksum ^ atoi(cl.configstrings[CS_MAPCHECKSUM])) != 0) { - Com.Error( - ERR_DROP, - "Local map version differs from server: " + map_checksum + " != '" + cl.configstrings[CS_MAPCHECKSUM] + "'\n"); - return; - } - } - - if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) { - if (SV_MAIN.allow_download.value != 0 && SV_MAIN.allow_download_maps.value != 0) { - while (precache_check < TEXTURE_CNT) { - int n = precache_check++ -ENV_CNT - 1; - - if ((n & 1) != 0) - fn = "env/" + cl.configstrings[CS_SKY] + env_suf[n / 2] + ".pcx"; - else - fn = "env/" + cl.configstrings[CS_SKY] + env_suf[n / 2] + ".tga"; - if (!CheckOrDownloadFile(fn)) - return; // started a download - } - } - precache_check = TEXTURE_CNT; - } - - if (precache_check == TEXTURE_CNT) { - precache_check = TEXTURE_CNT + 1; - precache_tex = 0; - } - - // confirm existance of textures, download any that don't exist - if (precache_check == TEXTURE_CNT + 1) { - // from qcommon/cmodel.c - // extern int numtexinfo; - // extern mapsurface_t map_surfaces[]; - - if (SV_MAIN.allow_download.value != 0 && SV_MAIN.allow_download_maps.value != 0) { - while (precache_tex < CM.numtexinfo) { - //char fn[MAX_OSPATH]; - - fn = "textures/" + CM.map_surfaces[precache_tex++].rname + ".wal"; - if (!CheckOrDownloadFile(fn)) - return; // started a download - } - } - precache_check = TEXTURE_CNT + 999; - } - - // ZOID - CL.RegisterSounds(); - PrepRefresh(); - - MSG.WriteByte(cls.netchan.message, clc_stringcmd); - MSG.WriteString(cls.netchan.message, "begin " + precache_spawncount + "\n"); - } - - /* - ================= - CL_Precache_f - - The server will send this command right - before allowing the client into the server - ================= - */ - static xcommand_t Precache_f = new xcommand_t() { - public void execute() { - /* Yet another hack to let old demos work - the old precache sequence */ - - if (Cmd.Argc() < 2) { - - int iw[] ={0};// for detecting cheater maps - - - CM.CM_LoadMap(cl.configstrings[CS_MODELS + 1], true, iw); - int mapchecksum = iw[0] ; - CL.RegisterSounds(); - CL.PrepRefresh(); - return; - } - - precache_check = CS_MODELS; - precache_spawncount = atoi(Cmd.Argv(1)); - precache_model = null; - precache_model_skin = 0; - - RequestNextDownload(); - } - }; - - /* - ================= - CL_InitLocal - ================= - */ - public static void InitLocal() { - cls.state = Defines.ca_disconnected; - cls.realtime = Sys.Milliseconds(); - - InitInput(); - - // never used !! -// adr0 = Cvar.Get("adr0", "", CVAR_ARCHIVE); -// adr1 = Cvar.Get("adr1", "", CVAR_ARCHIVE); -// adr2 = Cvar.Get("adr2", "", CVAR_ARCHIVE); -// adr3 = Cvar.Get("adr3", "", CVAR_ARCHIVE); -// adr4 = Cvar.Get("adr4", "", CVAR_ARCHIVE); -// adr5 = Cvar.Get("adr5", "", CVAR_ARCHIVE); -// adr6 = Cvar.Get("adr6", "", CVAR_ARCHIVE); -// adr7 = Cvar.Get("adr7", "", CVAR_ARCHIVE); -// adr8 = Cvar.Get("adr8", "", CVAR_ARCHIVE); - - // - // register our variables - // - cl_stereo_separation = Cvar.Get("cl_stereo_separation", "0.4", CVAR_ARCHIVE); - cl_stereo = Cvar.Get("cl_stereo", "0", 0); - - cl_add_blend = Cvar.Get("cl_blend", "1", 0); - cl_add_lights = Cvar.Get("cl_lights", "1", 0); - cl_add_particles = Cvar.Get("cl_particles", "1", 0); - cl_add_entities = Cvar.Get("cl_entities", "1", 0); - cl_gun = Cvar.Get("cl_gun", "1", 0); - cl_footsteps = Cvar.Get("cl_footsteps", "1", 0); - cl_noskins = Cvar.Get("cl_noskins", "0", 0); - cl_autoskins = Cvar.Get("cl_autoskins", "0", 0); - cl_predict = Cvar.Get("cl_predict", "1", 0); - - cl_maxfps = Cvar.Get("cl_maxfps", "90", 0); - - cl_upspeed = Cvar.Get("cl_upspeed", "200", 0); - cl_forwardspeed = Cvar.Get("cl_forwardspeed", "200", 0); - cl_sidespeed = Cvar.Get("cl_sidespeed", "200", 0); - cl_yawspeed = Cvar.Get("cl_yawspeed", "140", 0); - cl_pitchspeed = Cvar.Get("cl_pitchspeed", "150", 0); - cl_anglespeedkey = Cvar.Get("cl_anglespeedkey", "1.5", 0); - - cl_run = Cvar.Get("cl_run", "0", CVAR_ARCHIVE); - lookspring = Cvar.Get("lookspring", "0", CVAR_ARCHIVE); - lookstrafe = Cvar.Get("lookstrafe", "0", CVAR_ARCHIVE); - sensitivity = Cvar.Get("sensitivity", "3", CVAR_ARCHIVE); - - m_pitch = Cvar.Get("m_pitch", "0.022", CVAR_ARCHIVE); - m_yaw = Cvar.Get("m_yaw", "0.022", 0); - m_forward = Cvar.Get("m_forward", "1", 0); - m_side = Cvar.Get("m_side", "1", 0); - - cl_shownet = Cvar.Get("cl_shownet", "0", 0); - cl_showmiss = Cvar.Get("cl_showmiss", "0", 0); - cl_showclamp = Cvar.Get("showclamp", "0", 0); - cl_timeout = Cvar.Get("cl_timeout", "120", 0); - cl_paused = Cvar.Get("paused", "0", 0); - cl_timedemo = Cvar.Get("timedemo", "0", 0); - - rcon_client_password = Cvar.Get("rcon_password", "", 0); - rcon_address = Cvar.Get("rcon_address", "", 0); - - cl_lightlevel = Cvar.Get("r_lightlevel", "0", 0); - - // - // userinfo - // - info_password = Cvar.Get("password", "", CVAR_USERINFO); - info_spectator = Cvar.Get("spectator", "0", CVAR_USERINFO); - name = Cvar.Get("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE); - skin = Cvar.Get("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE); - rate = Cvar.Get("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE); // FIXME - msg = Cvar.Get("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE); - hand = Cvar.Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE); - fov = Cvar.Get("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE); - gender = Cvar.Get("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE); - gender_auto = Cvar.Get("gender_auto", "1", CVAR_ARCHIVE); - gender.modified = false; // clear this so we know when user sets it manually - - cl_vwep = Cvar.Get("cl_vwep", "1", CVAR_ARCHIVE); - - // - // register our commands - // - Cmd.AddCommand("cmd", ForwardToServer_f); - Cmd.AddCommand("pause", Pause_f); - Cmd.AddCommand("pingservers", PingServers_f); - Cmd.AddCommand("skins", Skins_f); - - Cmd.AddCommand("userinfo", Userinfo_f); - Cmd.AddCommand("snd_restart", Snd_Restart_f); - - Cmd.AddCommand("changing", Changing_f); - Cmd.AddCommand("disconnect", Disconnect_f); - Cmd.AddCommand("record", Record_f); - Cmd.AddCommand("stop", Stop_f); - - Cmd.AddCommand("quit", Quit_f); - - Cmd.AddCommand("connect", Connect_f); - Cmd.AddCommand("reconnect", Reconnect_f); - - Cmd.AddCommand("rcon", Rcon_f); - - Cmd.AddCommand("precache", Precache_f); - - Cmd.AddCommand("download", Download_f); - - // - // forward to server commands - // - // the only thing this does is allow command completion - // to work -- all unknown commands are automatically - // forwarded to the server - Cmd.AddCommand("wave", null); - Cmd.AddCommand("inven", null); - Cmd.AddCommand("kill", null); - Cmd.AddCommand("use", null); - Cmd.AddCommand("drop", null); - Cmd.AddCommand("say", null); - Cmd.AddCommand("say_team", null); - Cmd.AddCommand("info", null); - Cmd.AddCommand("prog", null); - Cmd.AddCommand("give", null); - Cmd.AddCommand("god", null); - Cmd.AddCommand("notarget", null); - Cmd.AddCommand("noclip", null); - Cmd.AddCommand("invuse", null); - Cmd.AddCommand("invprev", null); - Cmd.AddCommand("invnext", null); - Cmd.AddCommand("invdrop", null); - Cmd.AddCommand("weapnext", null); - Cmd.AddCommand("weapprev", null); - - } - - /* - =============== - CL_WriteConfiguration - - Writes key bindings and archived cvars to config.cfg - =============== - */ - static void WriteConfiguration() { - RandomAccessFile f; - String path; - - if (cls.state == ca_uninitialized) - return; - - path = FS.Gamedir() + "/config.cfg"; - f = fopen(path, "rw"); - if (f == null) { - Com.Printf("Couldn't write config.cfg.\n"); - return; - } - try - { - f.seek(0); - f.setLength(0); - } - catch (IOException e1) - {} - try { - f.writeBytes("// generated by quake, do not modify\n"); - } - catch (IOException e) {} - - Key.WriteBindings(f); - fclose(f); - Cvar.WriteVariables(path); - } - - /* - ================== - CL_FixCvarCheats - - ================== - */ - public static class cheatvar_t { - String name; - String value; - cvar_t var; - } - - public static String cheatvarsinfo[][] = { { "timescale", "1" }, { - "timedemo", "0" }, { - "r_drawworld", "1" }, { - "cl_testlights", "0" }, { - "r_fullbright", "0" }, { - "r_drawflat", "0" }, { - "paused", "0" }, { - "fixedtime", "0" }, { - "sw_draworder", "0" }, { - "gl_lightmap", "0" }, { - "gl_saturatelighting", "0" }, { - null, null } - }; - public static cheatvar_t cheatvars[]; - - static { - cheatvars = new cheatvar_t[cheatvarsinfo.length]; - for (int n = 0; n < cheatvarsinfo.length; n++) { - cheatvars[n] = new cheatvar_t(); - cheatvars[n].name = cheatvarsinfo[n][0]; - cheatvars[n].value = cheatvarsinfo[n][1]; - } - } - - static int numcheatvars; - - public static void FixCvarCheats() { - int i; - cheatvar_t var; - - if ("1".equals(cl.configstrings[CS_MAXCLIENTS]) || 0 == cl.configstrings[CS_MAXCLIENTS].length()) - return; // single player can cheat - - // find all the cvars if we haven't done it yet - if (0 == numcheatvars) { - while (cheatvars[numcheatvars].name != null) { - cheatvars[numcheatvars].var = Cvar.Get(cheatvars[numcheatvars].name, cheatvars[numcheatvars].value, 0); - numcheatvars++; - } - } - - // make sure they are all set to the proper values - for (i = 0; i < numcheatvars; i++) { - var = cheatvars[i]; - if (!var.var.string.equals(var.value)) { - Cvar.Set(var.name, var.value); - } - } - } - - // ============================================================================ - - /* - ================== - CL_SendCommand - - ================== - */ - public static void SendCommand() { - // get new key events - Sys.SendKeyEvents(); - - // allow mice or other external controllers to add commands - IN.Commands(); - - // process console commands - Cbuf.Execute(); - - // fix any cheating cvars - FixCvarCheats(); - - // send intentions now - SendCmd(); - - // resend a connection request if necessary - CheckForResend(); - } - - /* - ================== - CL_Frame - - ================== - */ - private static int extratime; -// private static int lasttimecalled; - - public static void Frame(int msec) { - - extratime += msec; - - if (cl_timedemo.value == 0.0f) { - if (cls.state == ca_connected && extratime < 100) { - return; // don't flood packets out while connecting - } - if (extratime < 1000 / cl_maxfps.value) { - return; // framerate is too high - } - } - - // let the mouse activate or deactivate - IN.Frame(); - - // decide the simulation time - cls.frametime = extratime / 1000.0f; - cl.time += extratime; - cls.realtime = curtime; - - extratime = 0; - - if (cls.frametime > (1.0f / 5)) - cls.frametime = (1.0f / 5); - - // if in the debugger last frame, don't timeout - if (msec > 5000) - cls.netchan.last_received = Sys.Milliseconds(); - - // fetch results from server - CL.ReadPackets(); - - // send a new command message to the server - SendCommand(); - - // predict all unacknowledged movements - CL.PredictMovement(); - - // allow rendering DLL change - VID.CheckChanges(); - if (!cl.refresh_prepped && cls.state == ca_active) { - CL.PrepRefresh(); - // force GC after level loading - System.gc(); - } - - SCR.UpdateScreen(); - - // update audio - S.Update(cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up); - - // advance local effects for next frame - CL.RunDLights(); - CL.RunLightStyles(); - - SCR.RunConsole(); - - cls.framecount++; - if (cls.state != ca_active || cls.key_dest != key_game) { - try { - Thread.sleep(20); - } catch (InterruptedException e) {} - } - } - - // ============================================================================ +public final class CL { + + static int precache_check; // for autodownload of precache items + + static int precache_spawncount; + + static int precache_tex; + + static int precache_model_skin; + + static byte precache_model[]; // used for skin checking in alias models + + public static final int PLAYER_MULT = 5; + + /* + * ================== CL_FixCvarCheats + * + * ================== + */ + public static class cheatvar_t { + String name; + + String value; + + cvar_t var; + } + + public static String cheatvarsinfo[][] = { { "timescale", "1" }, + { "timedemo", "0" }, { "r_drawworld", "1" }, + { "cl_testlights", "0" }, { "r_fullbright", "0" }, + { "r_drawflat", "0" }, { "paused", "0" }, { "fixedtime", "0" }, + { "sw_draworder", "0" }, { "gl_lightmap", "0" }, + { "gl_saturatelighting", "0" }, { null, null } }; + + public static cheatvar_t cheatvars[]; + + static { + cheatvars = new cheatvar_t[cheatvarsinfo.length]; + for (int n = 0; n < cheatvarsinfo.length; n++) { + cheatvars[n] = new cheatvar_t(); + cheatvars[n].name = cheatvarsinfo[n][0]; + cheatvars[n].value = cheatvarsinfo[n][1]; + } + } + + static int numcheatvars; + + /* + * ==================== CL_Stop_f + * + * stop recording a demo ==================== + */ + static xcommand_t Stop_f = new xcommand_t() { + public void execute() { + try { + + int len; + + if (!Globals.cls.demorecording) { + Com.Printf("Not recording a demo.\n"); + return; + } + + // finish up + len = -1; + Globals.cls.demofile.writeInt(len); + Globals.cls.demofile.close(); + Globals.cls.demofile = null; + Globals.cls.demorecording = false; + Com.Printf("Stopped demo.\n"); + } catch (IOException e) { + } + } + }; + + /* + * ==================== CL_Record_f + * + * record + * + * Begins recording a demo from the current position ==================== + */ + static entity_state_t nullstate = new entity_state_t(null); + + static xcommand_t Record_f = new xcommand_t() { + public void execute() { + try { + String name; + byte buf_data[] = new byte[Defines.MAX_MSGLEN]; + sizebuf_t buf = new sizebuf_t(); + int i; + entity_state_t ent; + + if (Cmd.Argc() != 2) { + Com.Printf("record \n"); + return; + } + + if (Globals.cls.demorecording) { + Com.Printf("Already recording.\n"); + return; + } + + if (Globals.cls.state != Defines.ca_active) { + Com.Printf("You must be in a level to record.\n"); + return; + } + + // + // open the demo file + // + name = FS.Gamedir() + "/demos/" + Cmd.Argv(1) + ".dm2"; + + Com.Printf("recording to " + name + ".\n"); + FS.CreatePath(name); + Globals.cls.demofile = new RandomAccessFile(name, "rw"); + if (Globals.cls.demofile == null) { + Com.Printf("ERROR: couldn't open.\n"); + return; + } + Globals.cls.demorecording = true; + + // don't start saving messages until a non-delta compressed + // message is received + Globals.cls.demowaiting = true; + + // + // write out messages to hold the startup information + // + SZ.Init(buf, buf_data, Defines.MAX_MSGLEN); + + // send the serverdata + MSG.WriteByte(buf, Defines.svc_serverdata); + MSG.WriteInt(buf, Defines.PROTOCOL_VERSION); + MSG.WriteInt(buf, 0x10000 + Globals.cl.servercount); + MSG.WriteByte(buf, 1); // demos are always attract loops + MSG.WriteString(buf, Globals.cl.gamedir); + MSG.WriteShort(buf, Globals.cl.playernum); + + MSG.WriteString(buf, Globals.cl.configstrings[Defines.CS_NAME]); + + // configstrings + for (i = 0; i < Defines.MAX_CONFIGSTRINGS; i++) { + if (Globals.cl.configstrings[i].length() > 0) { + if (buf.cursize + Globals.cl.configstrings[i].length() + + 32 > buf.maxsize) { // write it out + //len = LittleLong(buf.cursize); + //fwrite(& len, 4, 1, cls.demofile); + Globals.cls.demofile.writeInt(buf.cursize); + //fwrite(buf.data, buf.cursize, 1, cls.demofile); + Globals.cls.demofile + .write(buf.data, 0, buf.cursize); + buf.cursize = 0; + } + + MSG.WriteByte(buf, Defines.svc_configstring); + MSG.WriteShort(buf, i); + MSG.WriteString(buf, Globals.cl.configstrings[i]); + } + + } + + // baselines + //memset( nullstate, 0, sizeof(nullstate)); + for (i = 0; i < Defines.MAX_EDICTS; i++) { + ent = Globals.cl_entities[i].baseline; + if (ent.modelindex == 0) + continue; + + if (buf.cursize + 64 > buf.maxsize) { // write it out + //len = LittleLong(buf.cursize); + //fwrite(& len, 4, 1, cls.demofile); + Globals.cls.demofile.writeInt(buf.cursize); + //fwrite(buf.data, buf.cursize, 1, cls.demofile); + Globals.cls.demofile.write(buf.data, 0, buf.cursize); + buf.cursize = 0; + } + + MSG.WriteByte(buf, Defines.svc_spawnbaseline); + MSG.WriteDeltaEntity(nullstate, + Globals.cl_entities[i].baseline, buf, true, true); + } + + MSG.WriteByte(buf, Defines.svc_stufftext); + MSG.WriteString(buf, "precache\n"); + + // write it to the demo file + + //len = LittleLong(buf.cursize); + //fwrite(& len, 4, 1, cls.demofile); + Globals.cls.demofile.writeInt(buf.cursize); + //fwrite(buf.data, buf.cursize, 1, cls.demofile); + Globals.cls.demofile.write(buf.data, 0, buf.cursize); + // the rest of the demo file will be individual frames + + } catch (IOException e) { + } + } + }; + + /* + * ================== CL_ForwardToServer_f ================== + */ + static xcommand_t ForwardToServer_f = new xcommand_t() { + public void execute() { + if (Globals.cls.state != Defines.ca_connected + && Globals.cls.state != Defines.ca_active) { + Com.Printf("Can't \"" + Cmd.Argv(0) + "\", not connected\n"); + return; + } + + // don't forward the first argument + if (Cmd.Argc() > 1) { + MSG.WriteByte(Globals.cls.netchan.message, + Defines.clc_stringcmd); + SZ.Print(Globals.cls.netchan.message, Cmd.Args()); + } + } + }; + + /* + * ================== CL_Pause_f ================== + */ + static xcommand_t Pause_f = new xcommand_t() { + public void execute() { + // never pause in multiplayer + + if (Cvar.VariableValue("maxclients") > 1 + || Globals.server_state == 0) { + Cvar.SetValue("paused", 0); + return; + } + + Cvar.SetValue("paused", Globals.cl_paused.value); + } + }; + + /* + * ================== CL_Quit_f ================== + */ + static xcommand_t Quit_f = new xcommand_t() { + public void execute() { + Disconnect(); + Com.Quit(); + } + }; + + /* + * ================ CL_Connect_f + * + * ================ + */ + static xcommand_t Connect_f = new xcommand_t() { + public void execute() { + String server; + + if (Cmd.Argc() != 2) { + Com.Printf("usage: connect \n"); + return; + } + + if (Globals.server_state != 0) { + // if running a local server, kill it and reissue + SV_MAIN.SV_Shutdown("Server quit\n", false); + } else { + Disconnect(); + } + + server = Cmd.Argv(1); + + NET.Config(true); // allow remote + + Disconnect(); + + Globals.cls.state = Defines.ca_connecting; + //strncpy (cls.servername, server, sizeof(cls.servername)-1); + Globals.cls.servername = server; + Globals.cls.connect_time = -99999; + // CL_CheckForResend() will fire immediately + } + }; + + /* + * ===================== CL_Rcon_f + * + * Send the rest of the command line over as an unconnected command. + * ===================== + */ + static xcommand_t Rcon_f = new xcommand_t() { + public void execute() { + StringBuffer message = new StringBuffer(1024); + int i; + netadr_t to = new netadr_t(); + + if (Globals.rcon_client_password.string == null) { + Com + .Printf("You must set 'rcon_password' before\nissuing an rcon command.\n"); + return; + } + + message.append((char) 255); + message.append((char) 255); + message.append((char) 255); + message.append((char) 255); + + NET.Config(true); // allow remote + + //strcat (message, "rcon "); + message.append("rcon "); + + //strcat (message, rcon_client_password.string); + message.append(Globals.rcon_client_password.string); + //strcat (message, " "); + message.append(" "); + + for (i = 1; i < Cmd.Argc(); i++) { + //strcat (message, Cmd.Argv(i)); + message.append(Cmd.Argv(i)); + //strcat (message, " "); + message.append(" "); + } + + if (Globals.cls.state >= Defines.ca_connected) + to = Globals.cls.netchan.remote_address; + else { + if (Globals.rcon_address.string.length() == 0) { + Com + .Printf("You must either be connected,\nor set the 'rcon_address' cvar\nto issue rcon commands\n"); + + return; + } + NET.StringToAdr(Globals.rcon_address.string, to); + if (to.port == 0) + //to.port = BigShort (PORT_SERVER); + to.port = Defines.PORT_SERVER; + } + message.append('\0'); + String b = message.toString(); + NET.SendPacket(Defines.NS_CLIENT, b.length(), b.getBytes(), to); + } + }; + + static xcommand_t Disconnect_f = new xcommand_t() { + public void execute() { + Com.Error(Defines.ERR_DROP, "Disconnected from server"); + } + }; + + /* + * ================= CL_Changing_f + * + * Just sent as a hint to the client that they should drop to full console + * ================= + */ + static xcommand_t Changing_f = new xcommand_t() { + public void execute() { + //ZOID + //if we are downloading, we don't change! + // This so we don't suddenly stop downloading a map + + if (Globals.cls.download != null) + return; + + SCR.BeginLoadingPlaque(); + Globals.cls.state = Defines.ca_connected; // not active anymore, but + // not disconnected + Com.Printf("\nChanging map...\n"); + } + }; + + /* + * ================= CL_Reconnect_f + * + * The server is changing levels ================= + */ + static xcommand_t Reconnect_f = new xcommand_t() { + public void execute() { + //ZOID + //if we are downloading, we don't change! This so we don't suddenly + // stop downloading a map + if (Globals.cls.download != null) + return; + + S.StopAllSounds(); + if (Globals.cls.state == Defines.ca_connected) { + Com.Printf("reconnecting...\n"); + Globals.cls.state = Defines.ca_connected; + MSG.WriteChar(Globals.cls.netchan.message, + Defines.clc_stringcmd); + MSG.WriteString(Globals.cls.netchan.message, "new"); + return; + } + + if (Globals.cls.servername != null) { + if (Globals.cls.state >= Defines.ca_connected) { + Disconnect(); + Globals.cls.connect_time = Globals.cls.realtime - 1500; + } else + Globals.cls.connect_time = -99999; // fire immediately + + Globals.cls.state = Defines.ca_connecting; + Com.Printf("reconnecting...\n"); + } + } + }; + + /* + * ================= CL_PingServers_f ================= + */ + static xcommand_t PingServers_f = new xcommand_t() { + public void execute() { + int i; + netadr_t adr = new netadr_t(); + //char name[32]; + String name; + String adrstring; + cvar_t noudp; + cvar_t noipx; + + NET.Config(true); // allow remote + + // send a broadcast packet + Com.Printf("pinging broadcast...\n"); + + noudp = Cvar.Get("noudp", "0", Defines.CVAR_NOSET); + if (noudp.value == 0.0f) { + adr.type = Defines.NA_BROADCAST; + adr.port = Defines.PORT_SERVER; + //adr.port = BigShort(PORT_SERVER); + Netchan.OutOfBandPrint(Defines.NS_CLIENT, adr, "info " + + Defines.PROTOCOL_VERSION); + } + + // we use no IPX + noipx = Cvar.Get("noipx", "1", Defines.CVAR_NOSET); + if (noipx.value == 0.0f) { + adr.type = Defines.NA_BROADCAST_IPX; + //adr.port = BigShort(PORT_SERVER); + adr.port = Defines.PORT_SERVER; + Netchan.OutOfBandPrint(Defines.NS_CLIENT, adr, "info " + + Defines.PROTOCOL_VERSION); + } + + // send a packet to each address book entry + for (i = 0; i < 16; i++) { + //Com_sprintf (name, sizeof(name), "adr%i", i); + name = "adr" + i; + adrstring = Cvar.VariableString(name); + if (adrstring == null || adrstring.length() == 0) + continue; + + Com.Printf("pinging " + adrstring + "...\n"); + if (!NET.StringToAdr(adrstring, adr)) { + Com.Printf("Bad address: " + adrstring + "\n"); + continue; + } + if (adr.port == 0) + //adr.port = BigShort(PORT_SERVER); + adr.port = Defines.PORT_SERVER; + Netchan.OutOfBandPrint(Defines.NS_CLIENT, adr, "info " + + Defines.PROTOCOL_VERSION); + } + } + }; + + /* + * ================= CL_Skins_f + * + * Load or download any custom player skins and models ================= + */ + static xcommand_t Skins_f = new xcommand_t() { + public void execute() { + int i; + + for (i = 0; i < Defines.MAX_CLIENTS; i++) { + if (Globals.cl.configstrings[Defines.CS_PLAYERSKINS + i] == null) + continue; + Com.Printf("client " + i + ": " + + Globals.cl.configstrings[Defines.CS_PLAYERSKINS + i] + + "\n"); + SCR.UpdateScreen(); + Sys.SendKeyEvents(); // pump message loop + CL_parse.ParseClientinfo(i); + } + } + }; + + /* + * ============== CL_Userinfo_f ============== + */ + static xcommand_t Userinfo_f = new xcommand_t() { + public void execute() { + Com.Printf("User info settings:\n"); + Info.Print(Cvar.Userinfo()); + } + }; + + /* + * ================= CL_Snd_Restart_f + * + * Restart the sound subsystem so it can pick up new parameters and flush + * all sounds ================= + */ + static xcommand_t Snd_Restart_f = new xcommand_t() { + public void execute() { + S.Shutdown(); + S.Init(); + CL_parse.RegisterSounds(); + } + }; + + // ENV_CNT is map load, ENV_CNT+1 is first env map + public static final int ENV_CNT = (Defines.CS_PLAYERSKINS + Defines.MAX_CLIENTS + * CL.PLAYER_MULT); + + public static final int TEXTURE_CNT = (ENV_CNT + 13); + + static String env_suf[] = { "rt", "bk", "lf", "ft", "up", "dn" }; + + /* + * ================= CL_Precache_f + * + * The server will send this command right before allowing the client into + * the server ================= + */ + static xcommand_t Precache_f = new xcommand_t() { + public void execute() { + /* + * Yet another hack to let old demos work the old precache sequence + */ + + if (Cmd.Argc() < 2) { + + int iw[] = { 0 }; // for detecting cheater maps + + CM.CM_LoadMap(Globals.cl.configstrings[Defines.CS_MODELS + 1], + true, iw); + int mapchecksum = iw[0]; + CL_parse.RegisterSounds(); + CL_view.PrepRefresh(); + return; + } + + CL.precache_check = Defines.CS_MODELS; + CL.precache_spawncount = Lib.atoi(Cmd.Argv(1)); + CL.precache_model = null; + CL.precache_model_skin = 0; + + RequestNextDownload(); + } + }; + + /* + * ================== CL_Frame + * + * ================== + */ + private static int extratime; + + // ============================================================================ + + /* + * =============== CL_Shutdown + * + * FIXME: this is a callback from Sys_Quit and Com_Error. It would be better + * to run quit through here before the final handoff to the sys code. + * =============== + */ + static boolean isdown = false; + + /* + * ==================== CL_WriteDemoMessage + * + * Dumps the current net message, prefixed by the length + * ==================== + */ + static void WriteDemoMessage() { + int swlen; + + // the first eight bytes are just packet sequencing stuff + swlen = Globals.net_message.cursize - 8; + + try { + Globals.cls.demofile.writeInt(swlen); + //fwrite (&swlen, 4, 1, cls.demofile); + Globals.cls.demofile.write(Globals.net_message.data, 8, swlen); + //fwrite (net_message.data+8, len, 1, cls.demofile); + } catch (IOException e) { + } + + } + + /* + * ======================= CL_SendConnectPacket + * + * We have gotten a challenge from the server, so try and connect. + * ====================== + */ + static void SendConnectPacket() { + netadr_t adr = new netadr_t(); + int port; + + if (!NET.StringToAdr(Globals.cls.servername, adr)) { + Com.Printf("Bad server address\n"); + Globals.cls.connect_time = 0; + return; + } + if (adr.port == 0) + adr.port = Defines.PORT_SERVER; + // adr.port = BigShort(PORT_SERVER); + + port = (int) Cvar.VariableValue("qport"); + Globals.userinfo_modified = false; + + Netchan.OutOfBandPrint(Defines.NS_CLIENT, adr, "connect " + + Defines.PROTOCOL_VERSION + " " + port + " " + + Globals.cls.challenge + " \"" + Cvar.Userinfo() + "\"\n"); + } + + /* + * ================= CL_CheckForResend + * + * Resend a connect message if the last one has timed out ================= + */ + static void CheckForResend() { + netadr_t adr = new netadr_t(); + + // if the local server is running and we aren't + // then connect + if (Globals.cls.state == Defines.ca_disconnected + && Globals.server_state != 0) { + Globals.cls.state = Defines.ca_connecting; + Globals.cls.servername = "localhost"; + // we don't need a challenge on the localhost + SendConnectPacket(); + return; + } + + // resend if we haven't gotten a reply yet + if (Globals.cls.state != Defines.ca_connecting) + return; + + if (Globals.cls.realtime - Globals.cls.connect_time < 3000) + return; + + if (!NET.StringToAdr(Globals.cls.servername, adr)) { + Com.Printf("Bad server address\n"); + Globals.cls.state = Defines.ca_disconnected; + return; + } + if (adr.port == 0) + // adr.port = BigShort(PORT_SERVER); + adr.port = Defines.PORT_SERVER; + + Globals.cls.connect_time = Globals.cls.realtime; // for retransmit + // requests + + Com.Printf("Connecting to " + Globals.cls.servername + "...\n"); + + Netchan.OutOfBandPrint(Defines.NS_CLIENT, adr, "getchallenge\n"); + } + + /* + * ===================== CL_ClearState + * + * ===================== + */ + + static void ClearState() { + S.StopAllSounds(); + CL_fx.ClearEffects(); + CL_tent.ClearTEnts(); + + // wipe the entire cl structure + + Globals.cl = new client_state_t(); + for (int i = 0; i < Globals.cl_entities.length; i++) { + Globals.cl_entities[i] = new centity_t(); + } + + SZ.Clear(Globals.cls.netchan.message); + } + + /* + * ===================== CL_Disconnect + * + * Goes from a connected state to full screen console state Sends a + * disconnect message to the server This is also called on Com_Error, so it + * shouldn't cause any errors ===================== + */ + + static void Disconnect() { + + String fin; + + if (Globals.cls.state == Defines.ca_disconnected) + return; + + if (Globals.cl_timedemo != null && Globals.cl_timedemo.value != 0.0f) { + int time; + + time = (int) (Sys.Milliseconds() - Globals.cl.timedemo_start); + if (time > 0) + Com.Printf("%i frames, %3.1f seconds: %3.1f fps\n", + new Vargs(3).add(Globals.cl.timedemo_frames).add( + time / 1000.0).add( + Globals.cl.timedemo_frames * 1000.0 / time)); + } + + Math3D.VectorClear(Globals.cl.refdef.blend); + //re.CinematicSetPalette(null); + + Menu.ForceMenuOff(); + + Globals.cls.connect_time = 0; + + // SCR.StopCinematic(); + + if (Globals.cls.demorecording) + Stop_f.execute(); + + // send a disconnect message to the server + fin = (char) Defines.clc_stringcmd + "disconnect"; + Netchan.Transmit(Globals.cls.netchan, fin.length(), fin.getBytes()); + Netchan.Transmit(Globals.cls.netchan, fin.length(), fin.getBytes()); + Netchan.Transmit(Globals.cls.netchan, fin.length(), fin.getBytes()); + + ClearState(); + + // stop download + if (Globals.cls.download != null) { + Lib.fclose(Globals.cls.download); + Globals.cls.download = null; + // fclose(cls.download); + // cls.download = NULL; + } + + Globals.cls.state = Defines.ca_disconnected; + } + + /* + * ================= CL_ParseStatusMessage + * + * Handle a reply from a ping ================= + */ + static void ParseStatusMessage() { + String s; + + s = MSG.ReadString(Globals.net_message); + + Com.Printf(s + "\n"); + Menu.AddToServerList(Globals.net_from, s); + } + + /* + * ================= CL_ConnectionlessPacket + * + * Responses to broadcasts, etc ================= + */ + static void ConnectionlessPacket() { + String s; + String c; + + MSG.BeginReading(Globals.net_message); + MSG.ReadLong(Globals.net_message); // skip the -1 + + s = MSG.ReadStringLine(Globals.net_message); + + Cmd.TokenizeString(s.toCharArray(), false); + + c = Cmd.Argv(0); + + Com.Printf(NET.AdrToString(Globals.net_from) + ": " + c + "\n"); + + // server connection + if (c.equals("client_connect")) { + if (Globals.cls.state == Defines.ca_connected) { + Com.Printf("Dup connect received. Ignored.\n"); + return; + } + Netchan.Setup(Defines.NS_CLIENT, Globals.cls.netchan, + Globals.net_from, Globals.cls.quakePort); + MSG.WriteChar(Globals.cls.netchan.message, Defines.clc_stringcmd); + MSG.WriteString(Globals.cls.netchan.message, "new"); + Globals.cls.state = Defines.ca_connected; + return; + } + + // server responding to a status broadcast + if (c.equals("info")) { + ParseStatusMessage(); + return; + } + + // remote command from gui front end + if (c.equals("cmd")) { + if (!NET.IsLocalAddress(Globals.net_from)) { + Com.Printf("Command packet from remote host. Ignored.\n"); + return; + } + s = MSG.ReadString(Globals.net_message); + Cbuf.AddText(s); + Cbuf.AddText("\n"); + return; + } + // print command from somewhere + if (c.equals("print")) { + s = MSG.ReadString(Globals.net_message); + Com.Printf(s); + return; + } + + // ping from somewhere + if (c.equals("ping")) { + Netchan.OutOfBandPrint(Defines.NS_CLIENT, Globals.net_from, "ack"); + return; + } + + // challenge from the server we are connecting to + if (c.equals("challenge")) { + Globals.cls.challenge = Integer.parseInt(Cmd.Argv(1)); + SendConnectPacket(); + return; + } + + // echo request from server + if (c.equals("echo")) { + Netchan.OutOfBandPrint(Defines.NS_CLIENT, Globals.net_from, Cmd + .Argv(1)); + return; + } + + Com.Printf("Unknown command.\n"); + } + + /* + * ================= CL_DumpPackets + * + * A vain attempt to help bad TCP stacks that cause problems when they + * overflow ================= + */ + static void DumpPackets() { + while (NET.GetPacket(Defines.NS_CLIENT, Globals.net_from, + Globals.net_message)) { + Com.Printf("dumping a packet\n"); + } + } + + /* + * ================= CL_ReadPackets ================= + */ + static void ReadPackets() { + while (NET.GetPacket(Defines.NS_CLIENT, Globals.net_from, + Globals.net_message)) { + + // + // remote command packet + // + if (Globals.net_message.data[0] == -1 + && Globals.net_message.data[1] == -1 + && Globals.net_message.data[2] == -1 + && Globals.net_message.data[3] == -1) { + // if (*(int *)net_message.data == -1) + ConnectionlessPacket(); + continue; + } + + if (Globals.cls.state == Defines.ca_disconnected + || Globals.cls.state == Defines.ca_connecting) + continue; // dump it if not connected + + if (Globals.net_message.cursize < 8) { + Com.Printf(NET.AdrToString(Globals.net_from) + + ": Runt packet\n"); + continue; + } + + // + // packet from server + // + if (!NET.CompareAdr(Globals.net_from, + Globals.cls.netchan.remote_address)) { + Com.DPrintf(NET.AdrToString(Globals.net_from) + + ":sequenced packet without connection\n"); + continue; + } + if (!Netchan.Process(Globals.cls.netchan, Globals.net_message)) + continue; // wasn't accepted for some reason + CL_parse.ParseServerMessage(); + } + + // + // check timeout + // + if (Globals.cls.state >= Defines.ca_connected + && Globals.cls.realtime - Globals.cls.netchan.last_received > Globals.cl_timeout.value * 1000) { + if (++Globals.cl.timeoutcount > 5) // timeoutcount saves debugger + { + Com.Printf("\nServer connection timed out.\n"); + Disconnect(); + return; + } + } else + Globals.cl.timeoutcount = 0; + } + + // ============================================================================= + + /* + * ============== CL_FixUpGender_f ============== + */ + static void FixUpGender() { + + String sk; + + if (Globals.gender_auto.value != 0.0f) { + + if (Globals.gender.modified) { + // was set directly, don't override the user + Globals.gender.modified = false; + return; + } + + sk = Globals.skin.string; + if (sk.startsWith("male") || sk.startsWith("cyborg")) + Cvar.Set("gender", "male"); + else if (sk.startsWith("female") || sk.startsWith("crackhor")) + Cvar.Set("gender", "female"); + else + Cvar.Set("gender", "none"); + Globals.gender.modified = false; + } + } + + public static void RequestNextDownload() { + int map_checksum = 0; // for detecting cheater maps + //char fn[MAX_OSPATH]; + String fn; + + qfiles.dmdl_t pheader; + + if (Globals.cls.state != Defines.ca_connected) + return; + + if (SV_MAIN.allow_download.value == 0 && CL.precache_check < ENV_CNT) + CL.precache_check = ENV_CNT; + + // ZOID + if (CL.precache_check == Defines.CS_MODELS) { // confirm map + CL.precache_check = Defines.CS_MODELS + 2; // 0 isn't used + if (SV_MAIN.allow_download_maps.value != 0) + if (!CL_parse + .CheckOrDownloadFile(Globals.cl.configstrings[Defines.CS_MODELS + 1])) + return; // started a download + } + if (CL.precache_check >= Defines.CS_MODELS + && CL.precache_check < Defines.CS_MODELS + Defines.MAX_MODELS) { + if (SV_MAIN.allow_download_models.value != 0) { + while (CL.precache_check < Defines.CS_MODELS + + Defines.MAX_MODELS + && Globals.cl.configstrings[CL.precache_check].length() > 0) { + if (Globals.cl.configstrings[CL.precache_check].charAt(0) == '*' + || Globals.cl.configstrings[CL.precache_check] + .charAt(0) == '#') { + CL.precache_check++; + continue; + } + if (CL.precache_model_skin == 0) { + if (!CL_parse + .CheckOrDownloadFile(Globals.cl.configstrings[CL.precache_check])) { + CL.precache_model_skin = 1; + return; // started a download + } + CL.precache_model_skin = 1; + } + + // checking for skins in the model + if (CL.precache_model == null) { + + CL.precache_model = FS + .LoadFile(Globals.cl.configstrings[CL.precache_check]); + if (CL.precache_model == null) { + CL.precache_model_skin = 0; + CL.precache_check++; + continue; // couldn't load it + } + ByteBuffer bb = ByteBuffer.wrap(CL.precache_model); + bb.order(ByteOrder.LITTLE_ENDIAN); + + int header = bb.getInt(); + + if (header != qfiles.IDALIASHEADER) { + // not an alias model + FS.FreeFile(CL.precache_model); + CL.precache_model = null; + CL.precache_model_skin = 0; + CL.precache_check++; + continue; + } + pheader = new qfiles.dmdl_t(ByteBuffer.wrap( + CL.precache_model).order( + ByteOrder.LITTLE_ENDIAN)); + if (pheader.version != Defines.ALIAS_VERSION) { + CL.precache_check++; + CL.precache_model_skin = 0; + continue; // couldn't load it + } + } + + pheader = new qfiles.dmdl_t(ByteBuffer.wrap( + CL.precache_model).order(ByteOrder.LITTLE_ENDIAN)); + + int num_skins = pheader.num_skins; + + while (CL.precache_model_skin - 1 < num_skins) { + //Com.Printf("critical code section because of endian + // mess!\n"); + + String name = new String(CL.precache_model, + pheader.ofs_skins + + (CL.precache_model_skin - 1) + * Defines.MAX_SKINNAME, + Defines.MAX_SKINNAME * num_skins); + + if (!CL_parse.CheckOrDownloadFile(name)) { + CL.precache_model_skin++; + return; // started a download + } + CL.precache_model_skin++; + } + if (CL.precache_model != null) { + FS.FreeFile(CL.precache_model); + CL.precache_model = null; + } + CL.precache_model_skin = 0; + CL.precache_check++; + } + } + CL.precache_check = Defines.CS_SOUNDS; + } + if (CL.precache_check >= Defines.CS_SOUNDS + && CL.precache_check < Defines.CS_SOUNDS + Defines.MAX_SOUNDS) { + if (SV_MAIN.allow_download_sounds.value != 0) { + if (CL.precache_check == Defines.CS_SOUNDS) + CL.precache_check++; // zero is blank + while (CL.precache_check < Defines.CS_SOUNDS + + Defines.MAX_SOUNDS + && Globals.cl.configstrings[CL.precache_check].length() > 0) { + if (Globals.cl.configstrings[CL.precache_check].charAt(0) == '*') { + CL.precache_check++; + continue; + } + fn = "sound/" + + Globals.cl.configstrings[CL.precache_check++]; + if (!CL_parse.CheckOrDownloadFile(fn)) + return; // started a download + } + } + CL.precache_check = Defines.CS_IMAGES; + } + if (CL.precache_check >= Defines.CS_IMAGES + && CL.precache_check < Defines.CS_IMAGES + Defines.MAX_IMAGES) { + if (CL.precache_check == Defines.CS_IMAGES) + CL.precache_check++; // zero is blank + + while (CL.precache_check < Defines.CS_IMAGES + Defines.MAX_IMAGES + && Globals.cl.configstrings[CL.precache_check].length() > 0) { + fn = "pics/" + Globals.cl.configstrings[CL.precache_check++] + + ".pcx"; + if (!CL_parse.CheckOrDownloadFile(fn)) + return; // started a download + } + CL.precache_check = Defines.CS_PLAYERSKINS; + } + // skins are special, since a player has three things to download: + // model, weapon model and skin + // so precache_check is now *3 + if (CL.precache_check >= Defines.CS_PLAYERSKINS + && CL.precache_check < Defines.CS_PLAYERSKINS + + Defines.MAX_CLIENTS * CL.PLAYER_MULT) { + if (SV_MAIN.allow_download_players.value != 0) { + while (CL.precache_check < Defines.CS_PLAYERSKINS + + Defines.MAX_CLIENTS * CL.PLAYER_MULT) { + + int i, n; + //char model[MAX_QPATH], skin[MAX_QPATH], * p; + String model, skin; + + i = (CL.precache_check - Defines.CS_PLAYERSKINS) + / CL.PLAYER_MULT; + n = (CL.precache_check - Defines.CS_PLAYERSKINS) + % CL.PLAYER_MULT; + + if (Globals.cl.configstrings[Defines.CS_PLAYERSKINS + i] + .length() == 0) { + CL.precache_check = Defines.CS_PLAYERSKINS + (i + 1) + * CL.PLAYER_MULT; + continue; + } + + int pos = Globals.cl.configstrings[Defines.CS_PLAYERSKINS + + i].indexOf('\\'); + if (pos != -1) + pos++; + else + pos = 0; + + model = Globals.cl.configstrings[Defines.CS_PLAYERSKINS + i] + .substring(pos); + + pos = model.indexOf('/'); + + if (pos == -1) + pos = model.indexOf('\\'); + + if (pos != -1) { + skin = model.substring(pos + 1); + } else + skin = ""; + + switch (n) { + case 0: // model + fn = "players/" + model + "/tris.md2"; + if (!CL_parse.CheckOrDownloadFile(fn)) { + CL.precache_check = Defines.CS_PLAYERSKINS + i + * CL.PLAYER_MULT + 1; + return; // started a download + } + n++; + /* FALL THROUGH */ + + case 1: // weapon model + fn = "players/" + model + "/weapon.md2"; + if (!CL_parse.CheckOrDownloadFile(fn)) { + CL.precache_check = Defines.CS_PLAYERSKINS + i + * CL.PLAYER_MULT + 2; + return; // started a download + } + n++; + /* FALL THROUGH */ + + case 2: // weapon skin + fn = "players/" + model + "/weapon.pcx"; + if (!CL_parse.CheckOrDownloadFile(fn)) { + CL.precache_check = Defines.CS_PLAYERSKINS + i + * CL.PLAYER_MULT + 3; + return; // started a download + } + n++; + /* FALL THROUGH */ + + case 3: // skin + fn = "players/" + model + "/" + skin + ".pcx"; + if (!CL_parse.CheckOrDownloadFile(fn)) { + CL.precache_check = Defines.CS_PLAYERSKINS + i + * CL.PLAYER_MULT + 4; + return; // started a download + } + n++; + /* FALL THROUGH */ + + case 4: // skin_i + fn = "players/" + model + "/" + skin + "_i.pcx"; + if (!CL_parse.CheckOrDownloadFile(fn)) { + CL.precache_check = Defines.CS_PLAYERSKINS + i + * CL.PLAYER_MULT + 5; + return; // started a download + } + // move on to next model + CL.precache_check = Defines.CS_PLAYERSKINS + (i + 1) + * CL.PLAYER_MULT; + } + } + } + // precache phase completed + CL.precache_check = ENV_CNT; + } + + if (CL.precache_check == ENV_CNT) { + CL.precache_check = ENV_CNT + 1; + + int iw[] = { map_checksum }; + + CM.CM_LoadMap(Globals.cl.configstrings[Defines.CS_MODELS + 1], + true, iw); + map_checksum = iw[0]; + + if ((map_checksum ^ Lib + .atoi(Globals.cl.configstrings[Defines.CS_MAPCHECKSUM])) != 0) { + Com + .Error( + Defines.ERR_DROP, + "Local map version differs from server: " + + map_checksum + + " != '" + + Globals.cl.configstrings[Defines.CS_MAPCHECKSUM] + + "'\n"); + return; + } + } + + if (CL.precache_check > ENV_CNT && CL.precache_check < TEXTURE_CNT) { + if (SV_MAIN.allow_download.value != 0 + && SV_MAIN.allow_download_maps.value != 0) { + while (CL.precache_check < TEXTURE_CNT) { + int n = CL.precache_check++ - ENV_CNT - 1; + + if ((n & 1) != 0) + fn = "env/" + Globals.cl.configstrings[Defines.CS_SKY] + + env_suf[n / 2] + ".pcx"; + else + fn = "env/" + Globals.cl.configstrings[Defines.CS_SKY] + + env_suf[n / 2] + ".tga"; + if (!CL_parse.CheckOrDownloadFile(fn)) + return; // started a download + } + } + CL.precache_check = TEXTURE_CNT; + } + + if (CL.precache_check == TEXTURE_CNT) { + CL.precache_check = TEXTURE_CNT + 1; + CL.precache_tex = 0; + } + + // confirm existance of textures, download any that don't exist + if (CL.precache_check == TEXTURE_CNT + 1) { + // from qcommon/cmodel.c + // extern int numtexinfo; + // extern mapsurface_t map_surfaces[]; + + if (SV_MAIN.allow_download.value != 0 + && SV_MAIN.allow_download_maps.value != 0) { + while (CL.precache_tex < CM.numtexinfo) { + //char fn[MAX_OSPATH]; + + fn = "textures/" + CM.map_surfaces[CL.precache_tex++].rname + + ".wal"; + if (!CL_parse.CheckOrDownloadFile(fn)) + return; // started a download + } + } + CL.precache_check = TEXTURE_CNT + 999; + } + + // ZOID + CL_parse.RegisterSounds(); + CL_view.PrepRefresh(); + + MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd); + MSG.WriteString(Globals.cls.netchan.message, "begin " + + CL.precache_spawncount + "\n"); + } + + /* + * ================= CL_InitLocal ================= + */ + public static void InitLocal() { + Globals.cls.state = Defines.ca_disconnected; + Globals.cls.realtime = Sys.Milliseconds(); + + CL_input.InitInput(); + + // never used !! + // adr0 = Cvar.Get("adr0", "", CVAR_ARCHIVE); + // adr1 = Cvar.Get("adr1", "", CVAR_ARCHIVE); + // adr2 = Cvar.Get("adr2", "", CVAR_ARCHIVE); + // adr3 = Cvar.Get("adr3", "", CVAR_ARCHIVE); + // adr4 = Cvar.Get("adr4", "", CVAR_ARCHIVE); + // adr5 = Cvar.Get("adr5", "", CVAR_ARCHIVE); + // adr6 = Cvar.Get("adr6", "", CVAR_ARCHIVE); + // adr7 = Cvar.Get("adr7", "", CVAR_ARCHIVE); + // adr8 = Cvar.Get("adr8", "", CVAR_ARCHIVE); + + // + // register our variables + // + Globals.cl_stereo_separation = Cvar.Get("cl_stereo_separation", "0.4", + Defines.CVAR_ARCHIVE); + Globals.cl_stereo = Cvar.Get("cl_stereo", "0", 0); + + Globals.cl_add_blend = Cvar.Get("cl_blend", "1", 0); + Globals.cl_add_lights = Cvar.Get("cl_lights", "1", 0); + Globals.cl_add_particles = Cvar.Get("cl_particles", "1", 0); + Globals.cl_add_entities = Cvar.Get("cl_entities", "1", 0); + Globals.cl_gun = Cvar.Get("cl_gun", "1", 0); + Globals.cl_footsteps = Cvar.Get("cl_footsteps", "1", 0); + Globals.cl_noskins = Cvar.Get("cl_noskins", "0", 0); + Globals.cl_autoskins = Cvar.Get("cl_autoskins", "0", 0); + Globals.cl_predict = Cvar.Get("cl_predict", "1", 0); + + Globals.cl_maxfps = Cvar.Get("cl_maxfps", "90", 0); + + Globals.cl_upspeed = Cvar.Get("cl_upspeed", "200", 0); + Globals.cl_forwardspeed = Cvar.Get("cl_forwardspeed", "200", 0); + Globals.cl_sidespeed = Cvar.Get("cl_sidespeed", "200", 0); + Globals.cl_yawspeed = Cvar.Get("cl_yawspeed", "140", 0); + Globals.cl_pitchspeed = Cvar.Get("cl_pitchspeed", "150", 0); + Globals.cl_anglespeedkey = Cvar.Get("cl_anglespeedkey", "1.5", 0); + + Globals.cl_run = Cvar.Get("cl_run", "0", Defines.CVAR_ARCHIVE); + Globals.lookspring = Cvar.Get("lookspring", "0", Defines.CVAR_ARCHIVE); + Globals.lookstrafe = Cvar.Get("lookstrafe", "0", Defines.CVAR_ARCHIVE); + Globals.sensitivity = Cvar + .Get("sensitivity", "3", Defines.CVAR_ARCHIVE); + + Globals.m_pitch = Cvar.Get("m_pitch", "0.022", Defines.CVAR_ARCHIVE); + Globals.m_yaw = Cvar.Get("m_yaw", "0.022", 0); + Globals.m_forward = Cvar.Get("m_forward", "1", 0); + Globals.m_side = Cvar.Get("m_side", "1", 0); + + Globals.cl_shownet = Cvar.Get("cl_shownet", "0", 0); + Globals.cl_showmiss = Cvar.Get("cl_showmiss", "0", 0); + Globals.cl_showclamp = Cvar.Get("showclamp", "0", 0); + Globals.cl_timeout = Cvar.Get("cl_timeout", "120", 0); + Globals.cl_paused = Cvar.Get("paused", "0", 0); + Globals.cl_timedemo = Cvar.Get("timedemo", "0", 0); + + Globals.rcon_client_password = Cvar.Get("rcon_password", "", 0); + Globals.rcon_address = Cvar.Get("rcon_address", "", 0); + + Globals.cl_lightlevel = Cvar.Get("r_lightlevel", "0", 0); + + // + // userinfo + // + Globals.info_password = Cvar.Get("password", "", Defines.CVAR_USERINFO); + Globals.info_spectator = Cvar.Get("spectator", "0", + Defines.CVAR_USERINFO); + Globals.name = Cvar.Get("name", "unnamed", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.skin = Cvar.Get("skin", "male/grunt", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.rate = Cvar.Get("rate", "25000", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); // FIXME + Globals.msg = Cvar.Get("msg", "1", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.hand = Cvar.Get("hand", "0", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.fov = Cvar.Get("fov", "90", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.gender = Cvar.Get("gender", "male", Defines.CVAR_USERINFO + | Defines.CVAR_ARCHIVE); + Globals.gender_auto = Cvar + .Get("gender_auto", "1", Defines.CVAR_ARCHIVE); + Globals.gender.modified = false; // clear this so we know when user sets + // it manually + + Globals.cl_vwep = Cvar.Get("cl_vwep", "1", Defines.CVAR_ARCHIVE); + + // + // register our commands + // + Cmd.AddCommand("cmd", ForwardToServer_f); + Cmd.AddCommand("pause", Pause_f); + Cmd.AddCommand("pingservers", PingServers_f); + Cmd.AddCommand("skins", Skins_f); + + Cmd.AddCommand("userinfo", Userinfo_f); + Cmd.AddCommand("snd_restart", Snd_Restart_f); + + Cmd.AddCommand("changing", Changing_f); + Cmd.AddCommand("disconnect", Disconnect_f); + Cmd.AddCommand("record", Record_f); + Cmd.AddCommand("stop", Stop_f); + + Cmd.AddCommand("quit", Quit_f); + + Cmd.AddCommand("connect", Connect_f); + Cmd.AddCommand("reconnect", Reconnect_f); + + Cmd.AddCommand("rcon", Rcon_f); + + Cmd.AddCommand("precache", Precache_f); + + Cmd.AddCommand("download", CL_parse.Download_f); + + // + // forward to server commands + // + // the only thing this does is allow command completion + // to work -- all unknown commands are automatically + // forwarded to the server + Cmd.AddCommand("wave", null); + Cmd.AddCommand("inven", null); + Cmd.AddCommand("kill", null); + Cmd.AddCommand("use", null); + Cmd.AddCommand("drop", null); + Cmd.AddCommand("say", null); + Cmd.AddCommand("say_team", null); + Cmd.AddCommand("info", null); + Cmd.AddCommand("prog", null); + Cmd.AddCommand("give", null); + Cmd.AddCommand("god", null); + Cmd.AddCommand("notarget", null); + Cmd.AddCommand("noclip", null); + Cmd.AddCommand("invuse", null); + Cmd.AddCommand("invprev", null); + Cmd.AddCommand("invnext", null); + Cmd.AddCommand("invdrop", null); + Cmd.AddCommand("weapnext", null); + Cmd.AddCommand("weapprev", null); + + } + + /* + * =============== CL_WriteConfiguration + * + * Writes key bindings and archived cvars to config.cfg =============== + */ + static void WriteConfiguration() { + RandomAccessFile f; + String path; + + if (Globals.cls.state == Defines.ca_uninitialized) + return; + + path = FS.Gamedir() + "/config.cfg"; + f = Lib.fopen(path, "rw"); + if (f == null) { + Com.Printf("Couldn't write config.cfg.\n"); + return; + } + try { + f.seek(0); + f.setLength(0); + } catch (IOException e1) { + } + try { + f.writeBytes("// generated by quake, do not modify\n"); + } catch (IOException e) { + } + + Key.WriteBindings(f); + Lib.fclose(f); + Cvar.WriteVariables(path); + } + + public static void FixCvarCheats() { + int i; + CL.cheatvar_t var; + + if ("1".equals(Globals.cl.configstrings[Defines.CS_MAXCLIENTS]) + || 0 == Globals.cl.configstrings[Defines.CS_MAXCLIENTS] + .length()) + return; // single player can cheat + + // find all the cvars if we haven't done it yet + if (0 == CL.numcheatvars) { + while (CL.cheatvars[CL.numcheatvars].name != null) { + CL.cheatvars[CL.numcheatvars].var = Cvar.Get( + CL.cheatvars[CL.numcheatvars].name, + CL.cheatvars[CL.numcheatvars].value, 0); + CL.numcheatvars++; + } + } + + // make sure they are all set to the proper values + for (i = 0; i < CL.numcheatvars; i++) { + var = CL.cheatvars[i]; + if (!var.var.string.equals(var.value)) { + Cvar.Set(var.name, var.value); + } + } + } + + // ============================================================================ + + /* + * ================== CL_SendCommand + * + * ================== + */ + public static void SendCommand() { + // get new key events + Sys.SendKeyEvents(); + + // allow mice or other external controllers to add commands + IN.Commands(); + + // process console commands + Cbuf.Execute(); + + // fix any cheating cvars + FixCvarCheats(); + + // send intentions now + CL_input.SendCmd(); + + // resend a connection request if necessary + CheckForResend(); + } + + // private static int lasttimecalled; + + public static void Frame(int msec) { + + extratime += msec; + + if (Globals.cl_timedemo.value == 0.0f) { + if (Globals.cls.state == Defines.ca_connected && extratime < 100) { + return; // don't flood packets out while connecting + } + if (extratime < 1000 / Globals.cl_maxfps.value) { + return; // framerate is too high + } + } + + // let the mouse activate or deactivate + IN.Frame(); + + // decide the simulation time + Globals.cls.frametime = extratime / 1000.0f; + Globals.cl.time += extratime; + Globals.cls.realtime = Globals.curtime; + + extratime = 0; + + if (Globals.cls.frametime > (1.0f / 5)) + Globals.cls.frametime = (1.0f / 5); + + // if in the debugger last frame, don't timeout + if (msec > 5000) + Globals.cls.netchan.last_received = Sys.Milliseconds(); + + // fetch results from server + ReadPackets(); + + // send a new command message to the server + SendCommand(); + + // predict all unacknowledged movements + CL_pred.PredictMovement(); + + // allow rendering DLL change + VID.CheckChanges(); + if (!Globals.cl.refresh_prepped + && Globals.cls.state == Defines.ca_active) { + CL_view.PrepRefresh(); + // force GC after level loading + System.gc(); + } + + SCR.UpdateScreen(); + + // update audio + S.Update(Globals.cl.refdef.vieworg, Globals.cl.v_forward, + Globals.cl.v_right, Globals.cl.v_up); + + // advance local effects for next frame + CL_fx.RunDLights(); + CL_fx.RunLightStyles(); - /* - =============== - CL_Shutdown + SCR.RunConsole(); - FIXME: this is a callback from Sys_Quit and Com_Error. It would be better - to run quit through here before the final handoff to the sys code. - =============== - */ - static boolean isdown = false; - public static void Shutdown() { + Globals.cls.framecount++; + if (Globals.cls.state != Defines.ca_active + || Globals.cls.key_dest != Defines.key_game) { + try { + Thread.sleep(20); + } catch (InterruptedException e) { + } + } + } - if (isdown) { - System.out.print("recursive shutdown\n"); - return; - } - isdown = true; + public static void Shutdown() { - WriteConfiguration(); + if (isdown) { + System.out.print("recursive shutdown\n"); + return; + } + isdown = true; - S.Shutdown(); - IN.Shutdown(); - VID.Shutdown(); - } + WriteConfiguration(); - /** - * initialize client subsystem - */ - public static void Init() { - if (Globals.dedicated.value != 0.0f) - return; // nothing running on the client + S.Shutdown(); + IN.Shutdown(); + VID.Shutdown(); + } - // all archived variables will now be loaded + /** + * initialize client subsystem + */ + public static void Init() { + if (Globals.dedicated.value != 0.0f) + return; // nothing running on the client - Console.Init(); //ok + // all archived variables will now be loaded - S.Init(); //empty - VID.Init(); + Console.Init(); //ok - V.Init(); + S.Init(); //empty + VID.Init(); - Globals.net_message.data = Globals.net_message_buffer; - Globals.net_message.maxsize = Globals.net_message_buffer.length; + V.Init(); - Menu.Init(); + Globals.net_message.data = Globals.net_message_buffer; + Globals.net_message.maxsize = Globals.net_message_buffer.length; - SCR.Init(); - //Globals.cls.disable_screen = 1.0f; // don't draw yet + Menu.Init(); - CL.InitLocal(); - IN.Init(); + SCR.Init(); + //Globals.cls.disable_screen = 1.0f; // don't draw yet - FS.ExecAutoexec(); - Cbuf.Execute(); - } + InitLocal(); + IN.Init(); - /** - * Called after an ERR_DROP was thrown. - */ - public static void Drop() { - if (Globals.cls.state == Defines.ca_uninitialized) - return; - if (Globals.cls.state == Defines.ca_disconnected) - return; + FS.ExecAutoexec(); + Cbuf.Execute(); + } - CL.Disconnect(); + /** + * Called after an ERR_DROP was thrown. + */ + public static void Drop() { + if (Globals.cls.state == Defines.ca_uninitialized) + return; + if (Globals.cls.state == Defines.ca_disconnected) + return; - // drop loading plaque unless this is the initial game start - if (Globals.cls.disable_servercount != -1) - SCR.EndLoadingPlaque(); // get rid of loading plaque - } + Disconnect(); -} + // drop loading plaque unless this is the initial game start + if (Globals.cls.disable_servercount != -1) + SCR.EndLoadingPlaque(); // get rid of loading plaque + } +} \ No newline at end of file diff --git a/src/jake2/client/CL_ents.java b/src/jake2/client/CL_ents.java index 37d044c..df189fa 100644 --- a/src/jake2/client/CL_ents.java +++ b/src/jake2/client/CL_ents.java @@ -1,74 +1,79 @@ /* - * CL_ents.java + * java * Copyright (C) 2004 * - * $Id: CL_ents.java,v 1.5 2004-07-12 20:47:01 hzi Exp $ + * $Id: CL_ents.java,v 1.6 2004-09-22 19:22:07 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; +import jake2.Defines; +import jake2.Globals; import jake2.game.entity_state_t; import jake2.game.player_state_t; -import jake2.qcommon.*; +import jake2.game.pmove_t; +import jake2.qcommon.Com; +import jake2.qcommon.FS; +import jake2.qcommon.MSG; import jake2.render.model_t; +import jake2.util.Math3D; /** * CL_ents */ // cl_ents.c -- entity parsing and management -public class CL_ents extends CL_inv { +/* + * ========================================================================= + * + * FRAME PARSING + * + * ========================================================================= + */ +public class CL_ents { + static int bitcounts[] = new int[32]; /// just for protocol profiling - /* - ========================================================================= - - FRAME PARSING - - ========================================================================= - */ + static int bfg_lightramp[] = { 300, 400, 600, 300, 150, 75 }; /* - ================= - CL_ParseEntityBits - - Returns the entity number and the header bits - ================= - */ - static int bitcounts[] = new int[32]; /// just for protocol profiling + * ================= CL_ParseEntityBits + * + * Returns the entity number and the header bits ================= + */ public static int ParseEntityBits(int bits[]) { int b, total; int i; int number; - total = MSG.ReadByte(net_message); - if ((total & U_MOREBITS1) != 0) { - b = MSG.ReadByte(net_message); + total = MSG.ReadByte(Globals.net_message); + if ((total & Defines.U_MOREBITS1) != 0) { + b = MSG.ReadByte(Globals.net_message); total |= b << 8; } - if ((total & U_MOREBITS2) != 0) { - b = MSG.ReadByte(net_message); + if ((total & Defines.U_MOREBITS2) != 0) { + b = MSG.ReadByte(Globals.net_message); total |= b << 16; } - if ((total & U_MOREBITS3) != 0) { - b = MSG.ReadByte(net_message); + if ((total & Defines.U_MOREBITS3) != 0) { + b = MSG.ReadByte(Globals.net_message); total |= b << 24; } @@ -77,10 +82,10 @@ public class CL_ents extends CL_inv { if ((total & (1 << i)) != 0) bitcounts[i]++; - if ((total & U_NUMBER16) != 0) - number = MSG.ReadShort(net_message); + if ((total & Defines.U_NUMBER16) != 0) + number = MSG.ReadShort(Globals.net_message); else - number = MSG.ReadByte(net_message); + number = MSG.ReadByte(Globals.net_message); bits[0] = total; @@ -88,155 +93,152 @@ public class CL_ents extends CL_inv { } /* - ================== - CL_ParseDelta - - Can go from either a baseline or a previous packet_entity - ================== - */ + * ================== CL_ParseDelta + * + * Can go from either a baseline or a previous packet_entity + * ================== + */ public static void ParseDelta(entity_state_t from, entity_state_t to, int number, int bits) { // set everything to the state we are delta'ing from to.set(from); - VectorCopy(from.origin, to.old_origin); + Math3D.VectorCopy(from.origin, to.old_origin); to.number = number; - if ((bits & U_MODEL) != 0) - to.modelindex = MSG.ReadByte(net_message); - if ((bits & U_MODEL2) != 0) - to.modelindex2 = MSG.ReadByte(net_message); - if ((bits & U_MODEL3) != 0) - to.modelindex3 = MSG.ReadByte(net_message); - if ((bits & U_MODEL4) != 0) - to.modelindex4 = MSG.ReadByte(net_message); - - if ((bits & U_FRAME8) != 0) - to.frame = MSG.ReadByte(net_message); - if ((bits & U_FRAME16) != 0) - to.frame = MSG.ReadShort(net_message); - - if ((bits & U_SKIN8) != 0 && (bits & U_SKIN16) != 0) //used for laser colors - to.skinnum = MSG.ReadLong(net_message); - else if ((bits & U_SKIN8) != 0) - to.skinnum = MSG.ReadByte(net_message); - else if ((bits & U_SKIN16) != 0) - to.skinnum = MSG.ReadShort(net_message); - - if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16)) - to.effects = MSG.ReadLong(net_message); - else if ((bits & U_EFFECTS8) != 0) - to.effects = MSG.ReadByte(net_message); - else if ((bits & U_EFFECTS16) != 0) - to.effects = MSG.ReadShort(net_message); - - if ((bits & (U_RENDERFX8 | U_RENDERFX16)) == (U_RENDERFX8 | U_RENDERFX16)) - to.renderfx = MSG.ReadLong(net_message); - else if ((bits & U_RENDERFX8) != 0) - to.renderfx = MSG.ReadByte(net_message); - else if ((bits & U_RENDERFX16) != 0) - to.renderfx = MSG.ReadShort(net_message); - - if ((bits & U_ORIGIN1) != 0) - to.origin[0] = MSG.ReadCoord(net_message); - if ((bits & U_ORIGIN2) != 0) - to.origin[1] = MSG.ReadCoord(net_message); - if ((bits & U_ORIGIN3) != 0) - to.origin[2] = MSG.ReadCoord(net_message); - - if ((bits & U_ANGLE1) != 0) - to.angles[0] = MSG.ReadAngle(net_message); - if ((bits & U_ANGLE2) != 0) - to.angles[1] = MSG.ReadAngle(net_message); - if ((bits & U_ANGLE3) != 0) - to.angles[2] = MSG.ReadAngle(net_message); - - if ((bits & U_OLDORIGIN) != 0) - MSG.ReadPos(net_message, to.old_origin); - - if ((bits & U_SOUND) != 0) - to.sound = MSG.ReadByte(net_message); - - if ((bits & U_EVENT) != 0) - to.event = MSG.ReadByte(net_message); + if ((bits & Defines.U_MODEL) != 0) + to.modelindex = MSG.ReadByte(Globals.net_message); + if ((bits & Defines.U_MODEL2) != 0) + to.modelindex2 = MSG.ReadByte(Globals.net_message); + if ((bits & Defines.U_MODEL3) != 0) + to.modelindex3 = MSG.ReadByte(Globals.net_message); + if ((bits & Defines.U_MODEL4) != 0) + to.modelindex4 = MSG.ReadByte(Globals.net_message); + + if ((bits & Defines.U_FRAME8) != 0) + to.frame = MSG.ReadByte(Globals.net_message); + if ((bits & Defines.U_FRAME16) != 0) + to.frame = MSG.ReadShort(Globals.net_message); + + if ((bits & Defines.U_SKIN8) != 0 && (bits & Defines.U_SKIN16) != 0) //used + // for + // laser + // colors + to.skinnum = MSG.ReadLong(Globals.net_message); + else if ((bits & Defines.U_SKIN8) != 0) + to.skinnum = MSG.ReadByte(Globals.net_message); + else if ((bits & Defines.U_SKIN16) != 0) + to.skinnum = MSG.ReadShort(Globals.net_message); + + if ((bits & (Defines.U_EFFECTS8 | Defines.U_EFFECTS16)) == (Defines.U_EFFECTS8 | Defines.U_EFFECTS16)) + to.effects = MSG.ReadLong(Globals.net_message); + else if ((bits & Defines.U_EFFECTS8) != 0) + to.effects = MSG.ReadByte(Globals.net_message); + else if ((bits & Defines.U_EFFECTS16) != 0) + to.effects = MSG.ReadShort(Globals.net_message); + + if ((bits & (Defines.U_RENDERFX8 | Defines.U_RENDERFX16)) == (Defines.U_RENDERFX8 | Defines.U_RENDERFX16)) + to.renderfx = MSG.ReadLong(Globals.net_message); + else if ((bits & Defines.U_RENDERFX8) != 0) + to.renderfx = MSG.ReadByte(Globals.net_message); + else if ((bits & Defines.U_RENDERFX16) != 0) + to.renderfx = MSG.ReadShort(Globals.net_message); + + if ((bits & Defines.U_ORIGIN1) != 0) + to.origin[0] = MSG.ReadCoord(Globals.net_message); + if ((bits & Defines.U_ORIGIN2) != 0) + to.origin[1] = MSG.ReadCoord(Globals.net_message); + if ((bits & Defines.U_ORIGIN3) != 0) + to.origin[2] = MSG.ReadCoord(Globals.net_message); + + if ((bits & Defines.U_ANGLE1) != 0) + to.angles[0] = MSG.ReadAngle(Globals.net_message); + if ((bits & Defines.U_ANGLE2) != 0) + to.angles[1] = MSG.ReadAngle(Globals.net_message); + if ((bits & Defines.U_ANGLE3) != 0) + to.angles[2] = MSG.ReadAngle(Globals.net_message); + + if ((bits & Defines.U_OLDORIGIN) != 0) + MSG.ReadPos(Globals.net_message, to.old_origin); + + if ((bits & Defines.U_SOUND) != 0) + to.sound = MSG.ReadByte(Globals.net_message); + + if ((bits & Defines.U_EVENT) != 0) + to.event = MSG.ReadByte(Globals.net_message); else to.event = 0; - if ((bits & U_SOLID) != 0) - to.solid = MSG.ReadShort(net_message); + if ((bits & Defines.U_SOLID) != 0) + to.solid = MSG.ReadShort(Globals.net_message); } /* - ================== - CL_DeltaEntity - - Parses deltas from the given base and adds the resulting entity - to the current frame - ================== - */ + * ================== CL_DeltaEntity + * + * Parses deltas from the given base and adds the resulting entity to the + * current frame ================== + */ public static void DeltaEntity(frame_t frame, int newnum, entity_state_t old, int bits) { centity_t ent; entity_state_t state; - ent = cl_entities[newnum]; + ent = Globals.cl_entities[newnum]; - state = cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES - 1)]; - cl.parse_entities++; + state = Globals.cl_parse_entities[Globals.cl.parse_entities & (Defines.MAX_PARSE_ENTITIES - 1)]; + Globals.cl.parse_entities++; frame.num_entities++; ParseDelta(old, state, newnum, bits); // some data changes will force no lerping - if (state.modelindex != ent.current.modelindex - || state.modelindex2 != ent.current.modelindex2 - || state.modelindex3 != ent.current.modelindex3 - || state.modelindex4 != ent.current.modelindex4 - || Math.abs(state.origin[0] - ent.current.origin[0]) > 512 - || Math.abs(state.origin[1] - ent.current.origin[1]) > 512 - || Math.abs(state.origin[2] - ent.current.origin[2]) > 512 - || state.event == EV_PLAYER_TELEPORT - || state.event == EV_OTHER_TELEPORT) { + if (state.modelindex != ent.current.modelindex || state.modelindex2 != ent.current.modelindex2 + || state.modelindex3 != ent.current.modelindex3 || state.modelindex4 != ent.current.modelindex4 + || Math.abs(state.origin[0] - ent.current.origin[0]) > 512 || Math.abs(state.origin[1] - ent.current.origin[1]) > 512 + || Math.abs(state.origin[2] - ent.current.origin[2]) > 512 || state.event == Defines.EV_PLAYER_TELEPORT + || state.event == Defines.EV_OTHER_TELEPORT) { ent.serverframe = -99; } - if (ent.serverframe != cl.frame.serverframe - 1) { // wasn't in last update, so initialize some things + if (ent.serverframe != Globals.cl.frame.serverframe - 1) { // wasn't in + // last + // update, so + // initialize + // some + // things ent.trailcount = 1024; // for diminishing rocket / grenade trails // duplicate the current state so lerping doesn't hurt anything ent.prev.set(state); - if (state.event == EV_OTHER_TELEPORT) { - VectorCopy(state.origin, ent.prev.origin); - VectorCopy(state.origin, ent.lerp_origin); - } - else { - VectorCopy(state.old_origin, ent.prev.origin); - VectorCopy(state.old_origin, ent.lerp_origin); + if (state.event == Defines.EV_OTHER_TELEPORT) { + Math3D.VectorCopy(state.origin, ent.prev.origin); + Math3D.VectorCopy(state.origin, ent.lerp_origin); + } else { + Math3D.VectorCopy(state.old_origin, ent.prev.origin); + Math3D.VectorCopy(state.old_origin, ent.lerp_origin); } - } - else { // shuffle the last state to previous + } else { // shuffle the last state to previous // Copy ! ent.prev.set(ent.current); } - ent.serverframe = cl.frame.serverframe; + ent.serverframe = Globals.cl.frame.serverframe; // Copy ! ent.current.set(state); } /* - ================== - CL_ParsePacketEntities - - An svc_packetentities has just been parsed, deal with the - rest of the data stream. - ================== - */ + * ================== CL_ParsePacketEntities + * + * An svc_packetentities has just been parsed, deal with the rest of the + * data stream. ================== + */ public static void ParsePacketEntities(frame_t oldframe, frame_t newframe) { int newnum; - int bits=0; + int bits = 0; - entity_state_t oldstate=null; + entity_state_t oldstate = null; int oldnum; - newframe.parse_entities = cl.parse_entities; + newframe.parse_entities = Globals.cl.parse_entities; newframe.num_entities = 0; // delta from the entities present in oldframe @@ -245,30 +247,31 @@ public class CL_ents extends CL_inv { oldnum = 99999; else { // oldindex == 0. hoz -// if (oldindex >= oldframe.num_entities) -// oldnum = 99999; -// else { - oldstate = cl_parse_entities[(oldframe.parse_entities + oldindex) & (MAX_PARSE_ENTITIES - 1)]; - oldnum = oldstate.number; -// } + // if (oldindex >= oldframe.num_entities) + // oldnum = 99999; + // else { + oldstate = Globals.cl_parse_entities[(oldframe.parse_entities + oldindex) & (Defines.MAX_PARSE_ENTITIES - 1)]; + oldnum = oldstate.number; + // } } while (true) { - int iw[] = {bits}; + int iw[] = { bits }; newnum = ParseEntityBits(iw); bits = iw[0]; - if (newnum >= MAX_EDICTS) - Com.Error(ERR_DROP, "CL_ParsePacketEntities: bad number:" + newnum); + if (newnum >= Defines.MAX_EDICTS) + Com.Error(Defines.ERR_DROP, "CL_ParsePacketEntities: bad number:" + newnum); - if (net_message.readcount > net_message.cursize) - Com.Error(ERR_DROP, "CL_ParsePacketEntities: end of message"); + if (Globals.net_message.readcount > Globals.net_message.cursize) + Com.Error(Defines.ERR_DROP, "CL_ParsePacketEntities: end of message"); if (0 == newnum) break; - while (oldnum < newnum) { // one or more entities from the old packet are unchanged - if (cl_shownet.value == 3) + while (oldnum < newnum) { // one or more entities from the old + // packet are unchanged + if (Globals.cl_shownet.value == 3) Com.Printf(" unchanged: " + oldnum + "\n"); DeltaEntity(newframe, oldnum, oldstate, 0); @@ -277,13 +280,15 @@ public class CL_ents extends CL_inv { if (oldindex >= oldframe.num_entities) oldnum = 99999; else { - oldstate = cl_parse_entities[(oldframe.parse_entities + oldindex) & (MAX_PARSE_ENTITIES - 1)]; + oldstate = Globals.cl_parse_entities[(oldframe.parse_entities + oldindex) & (Defines.MAX_PARSE_ENTITIES - 1)]; oldnum = oldstate.number; } } - if ((bits & U_REMOVE) != 0) { // the entity present in oldframe is not in the current frame - if (cl_shownet.value == 3) + if ((bits & Defines.U_REMOVE) != 0) { // the entity present in + // oldframe is not in the + // current frame + if (Globals.cl_shownet.value == 3) Com.Printf(" remove: " + newnum + "\n"); if (oldnum != newnum) Com.Printf("U_REMOVE: oldnum != newnum\n"); @@ -293,14 +298,14 @@ public class CL_ents extends CL_inv { if (oldindex >= oldframe.num_entities) oldnum = 99999; else { - oldstate = cl_parse_entities[(oldframe.parse_entities + oldindex) & (MAX_PARSE_ENTITIES - 1)]; + oldstate = Globals.cl_parse_entities[(oldframe.parse_entities + oldindex) & (Defines.MAX_PARSE_ENTITIES - 1)]; oldnum = oldstate.number; } continue; } if (oldnum == newnum) { // delta from previous state - if (cl_shownet.value == 3) + if (Globals.cl_shownet.value == 3) Com.Printf(" delta: " + newnum + "\n"); DeltaEntity(newframe, newnum, oldstate, bits); @@ -309,24 +314,25 @@ public class CL_ents extends CL_inv { if (oldindex >= oldframe.num_entities) oldnum = 99999; else { - oldstate = cl_parse_entities[(oldframe.parse_entities + oldindex) & (MAX_PARSE_ENTITIES - 1)]; + oldstate = Globals.cl_parse_entities[(oldframe.parse_entities + oldindex) & (Defines.MAX_PARSE_ENTITIES - 1)]; oldnum = oldstate.number; } continue; } if (oldnum > newnum) { // delta from baseline - if (cl_shownet.value == 3) + if (Globals.cl_shownet.value == 3) Com.Printf(" baseline: " + newnum + "\n"); - DeltaEntity(newframe, newnum, cl_entities[newnum].baseline, bits); + DeltaEntity(newframe, newnum, Globals.cl_entities[newnum].baseline, bits); continue; } } // any remaining entities in the old frame are copied over - while (oldnum != 99999) { // one or more entities from the old packet are unchanged - if (cl_shownet.value == 3) + while (oldnum != 99999) { // one or more entities from the old packet + // are unchanged + if (Globals.cl_shownet.value == 3) Com.Printf(" unchanged: " + oldnum + "\n"); DeltaEntity(newframe, oldnum, oldstate, 0); @@ -335,17 +341,15 @@ public class CL_ents extends CL_inv { if (oldindex >= oldframe.num_entities) oldnum = 99999; else { - oldstate = cl_parse_entities[(oldframe.parse_entities + oldindex) & (MAX_PARSE_ENTITIES - 1)]; + oldstate = Globals.cl_parse_entities[(oldframe.parse_entities + oldindex) & (Defines.MAX_PARSE_ENTITIES - 1)]; oldnum = oldstate.number; } } } /* - =================== - CL_ParsePlayerstate - =================== - */ + * =================== CL_ParsePlayerstate =================== + */ public static void ParsePlayerstate(frame_t oldframe, frame_t newframe) { int flags; player_state_t state; @@ -361,233 +365,230 @@ public class CL_ents extends CL_inv { //memset (state, 0, sizeof(*state)); state.clear(); - flags = MSG.ReadShort(net_message); + flags = MSG.ReadShort(Globals.net_message); // // parse the pmove_state_t // - if ((flags & PS_M_TYPE) != 0) - state.pmove.pm_type = MSG.ReadByte(net_message); + if ((flags & Defines.PS_M_TYPE) != 0) + state.pmove.pm_type = MSG.ReadByte(Globals.net_message); - if ((flags & PS_M_ORIGIN) != 0) { - state.pmove.origin[0] = MSG.ReadShort(net_message); - state.pmove.origin[1] = MSG.ReadShort(net_message); - state.pmove.origin[2] = MSG.ReadShort(net_message); + if ((flags & Defines.PS_M_ORIGIN) != 0) { + state.pmove.origin[0] = MSG.ReadShort(Globals.net_message); + state.pmove.origin[1] = MSG.ReadShort(Globals.net_message); + state.pmove.origin[2] = MSG.ReadShort(Globals.net_message); } - if ((flags & PS_M_VELOCITY) != 0) { - state.pmove.velocity[0] = MSG.ReadShort(net_message); - state.pmove.velocity[1] = MSG.ReadShort(net_message); - state.pmove.velocity[2] = MSG.ReadShort(net_message); + if ((flags & Defines.PS_M_VELOCITY) != 0) { + state.pmove.velocity[0] = MSG.ReadShort(Globals.net_message); + state.pmove.velocity[1] = MSG.ReadShort(Globals.net_message); + state.pmove.velocity[2] = MSG.ReadShort(Globals.net_message); } - if ((flags & PS_M_TIME) != 0) - { - state.pmove.pm_time = (byte) MSG.ReadByte(net_message); + if ((flags & Defines.PS_M_TIME) != 0) { + state.pmove.pm_time = (byte) MSG.ReadByte(Globals.net_message); } - if ((flags & PS_M_FLAGS) != 0) - state.pmove.pm_flags = (byte) MSG.ReadByte(net_message); + if ((flags & Defines.PS_M_FLAGS) != 0) + state.pmove.pm_flags = (byte) MSG.ReadByte(Globals.net_message); - if ((flags & PS_M_GRAVITY) != 0) - state.pmove.gravity = MSG.ReadShort(net_message); + if ((flags & Defines.PS_M_GRAVITY) != 0) + state.pmove.gravity = MSG.ReadShort(Globals.net_message); - if ((flags & PS_M_DELTA_ANGLES) != 0) { - state.pmove.delta_angles[0] = MSG.ReadShort(net_message); - state.pmove.delta_angles[1] = MSG.ReadShort(net_message); - state.pmove.delta_angles[2] = MSG.ReadShort(net_message); + if ((flags & Defines.PS_M_DELTA_ANGLES) != 0) { + state.pmove.delta_angles[0] = MSG.ReadShort(Globals.net_message); + state.pmove.delta_angles[1] = MSG.ReadShort(Globals.net_message); + state.pmove.delta_angles[2] = MSG.ReadShort(Globals.net_message); } - if (cl.attractloop) - state.pmove.pm_type = PM_FREEZE; // demo playback + if (Globals.cl.attractloop) + state.pmove.pm_type = Defines.PM_FREEZE; // demo playback // // parse the rest of the player_state_t // - if ((flags & PS_VIEWOFFSET) != 0) { - state.viewoffset[0] = MSG.ReadChar(net_message) * 0.25f; - state.viewoffset[1] = MSG.ReadChar(net_message) * 0.25f; - state.viewoffset[2] = MSG.ReadChar(net_message) * 0.25f; + if ((flags & Defines.PS_VIEWOFFSET) != 0) { + state.viewoffset[0] = MSG.ReadChar(Globals.net_message) * 0.25f; + state.viewoffset[1] = MSG.ReadChar(Globals.net_message) * 0.25f; + state.viewoffset[2] = MSG.ReadChar(Globals.net_message) * 0.25f; } - if ((flags & PS_VIEWANGLES) != 0) { - state.viewangles[0] = MSG.ReadAngle16(net_message); - state.viewangles[1] = MSG.ReadAngle16(net_message); - state.viewangles[2] = MSG.ReadAngle16(net_message); + if ((flags & Defines.PS_VIEWANGLES) != 0) { + state.viewangles[0] = MSG.ReadAngle16(Globals.net_message); + state.viewangles[1] = MSG.ReadAngle16(Globals.net_message); + state.viewangles[2] = MSG.ReadAngle16(Globals.net_message); } - if ((flags & PS_KICKANGLES) != 0) { - - state.kick_angles[0] = MSG.ReadChar(net_message) * 0.25f; - state.kick_angles[1] = MSG.ReadChar(net_message) * 0.25f; - state.kick_angles[2] = MSG.ReadChar(net_message) * 0.25f; - + if ((flags & Defines.PS_KICKANGLES) != 0) { + + state.kick_angles[0] = MSG.ReadChar(Globals.net_message) * 0.25f; + state.kick_angles[1] = MSG.ReadChar(Globals.net_message) * 0.25f; + state.kick_angles[2] = MSG.ReadChar(Globals.net_message) * 0.25f; + } - if ((flags & PS_WEAPONINDEX) != 0) { - state.gunindex = MSG.ReadByte(net_message); + if ((flags & Defines.PS_WEAPONINDEX) != 0) { + state.gunindex = MSG.ReadByte(Globals.net_message); } - if ((flags & PS_WEAPONFRAME) != 0) { - state.gunframe = MSG.ReadByte(net_message); - state.gunoffset[0] = MSG.ReadChar(net_message) * 0.25f; - state.gunoffset[1] = MSG.ReadChar(net_message) * 0.25f; - state.gunoffset[2] = MSG.ReadChar(net_message) * 0.25f; - state.gunangles[0] = MSG.ReadChar(net_message) * 0.25f; - state.gunangles[1] = MSG.ReadChar(net_message) * 0.25f; - state.gunangles[2] = MSG.ReadChar(net_message) * 0.25f; + if ((flags & Defines.PS_WEAPONFRAME) != 0) { + state.gunframe = MSG.ReadByte(Globals.net_message); + state.gunoffset[0] = MSG.ReadChar(Globals.net_message) * 0.25f; + state.gunoffset[1] = MSG.ReadChar(Globals.net_message) * 0.25f; + state.gunoffset[2] = MSG.ReadChar(Globals.net_message) * 0.25f; + state.gunangles[0] = MSG.ReadChar(Globals.net_message) * 0.25f; + state.gunangles[1] = MSG.ReadChar(Globals.net_message) * 0.25f; + state.gunangles[2] = MSG.ReadChar(Globals.net_message) * 0.25f; } - if ((flags & PS_BLEND) != 0) { - state.blend[0] = MSG.ReadByte(net_message) / 255.0f; - state.blend[1] = MSG.ReadByte(net_message) / 255.0f; - state.blend[2] = MSG.ReadByte(net_message) / 255.0f; - state.blend[3] = MSG.ReadByte(net_message) / 255.0f; + if ((flags & Defines.PS_BLEND) != 0) { + state.blend[0] = MSG.ReadByte(Globals.net_message) / 255.0f; + state.blend[1] = MSG.ReadByte(Globals.net_message) / 255.0f; + state.blend[2] = MSG.ReadByte(Globals.net_message) / 255.0f; + state.blend[3] = MSG.ReadByte(Globals.net_message) / 255.0f; } - if ((flags & PS_FOV) != 0) - state.fov = MSG.ReadByte(net_message); + if ((flags & Defines.PS_FOV) != 0) + state.fov = MSG.ReadByte(Globals.net_message); - if ((flags & PS_RDFLAGS) != 0) - state.rdflags = MSG.ReadByte(net_message); + if ((flags & Defines.PS_RDFLAGS) != 0) + state.rdflags = MSG.ReadByte(Globals.net_message); // parse stats - statbits = MSG.ReadLong(net_message); - for (i = 0; i < MAX_STATS; i++) - if ((statbits & (1 << i))!=0) - state.stats[i] = MSG.ReadShort(net_message); + statbits = MSG.ReadLong(Globals.net_message); + for (i = 0; i < Defines.MAX_STATS; i++) + if ((statbits & (1 << i)) != 0) + state.stats[i] = MSG.ReadShort(Globals.net_message); } /* - ================== - CL_FireEntityEvents - - ================== - */ + * ================== CL_FireEntityEvents + * + * ================== + */ public static void FireEntityEvents(frame_t frame) { entity_state_t s1; int pnum, num; for (pnum = 0; pnum < frame.num_entities; pnum++) { - num = (frame.parse_entities + pnum) & (MAX_PARSE_ENTITIES - 1); - s1 = cl_parse_entities[num]; - if (s1.event!=0) - EntityEvent(s1); + num = (frame.parse_entities + pnum) & (Defines.MAX_PARSE_ENTITIES - 1); + s1 = Globals.cl_parse_entities[num]; + if (s1.event != 0) + CL_fx.EntityEvent(s1); // EF_TELEPORTER acts like an event, but is not cleared each frame - if ((s1.effects & EF_TELEPORTER)!=0) + if ((s1.effects & Defines.EF_TELEPORTER) != 0) CL_fx.TeleporterParticles(s1); } } /* - ================ - CL_ParseFrame - ================ - */ + * ================ CL_ParseFrame ================ + */ public static void ParseFrame() { int cmd; int len; frame_t old; //memset( cl.frame, 0, sizeof(cl.frame)); - cl.frame.reset(); + Globals.cl.frame.reset(); - cl.frame.serverframe = MSG.ReadLong(net_message); - cl.frame.deltaframe = MSG.ReadLong(net_message); - cl.frame.servertime = cl.frame.serverframe * 100; + Globals.cl.frame.serverframe = MSG.ReadLong(Globals.net_message); + Globals.cl.frame.deltaframe = MSG.ReadLong(Globals.net_message); + Globals.cl.frame.servertime = Globals.cl.frame.serverframe * 100; // BIG HACK to let old demos continue to work - if (cls.serverProtocol != 26) - cl.surpressCount = MSG.ReadByte(net_message); + if (Globals.cls.serverProtocol != 26) + Globals.cl.surpressCount = MSG.ReadByte(Globals.net_message); - if (cl_shownet.value == 3) - Com.Printf(" frame:" + cl.frame.serverframe + " delta:" + cl.frame.deltaframe + "\n"); + if (Globals.cl_shownet.value == 3) + Com.Printf(" frame:" + Globals.cl.frame.serverframe + " delta:" + Globals.cl.frame.deltaframe + "\n"); // If the frame is delta compressed from data that we // no longer have available, we must suck up the rest of // the frame, but not use it, then ask for a non-compressed - // message - if (cl.frame.deltaframe <= 0) { - cl.frame.valid = true; // uncompressed frame + // message + if (Globals.cl.frame.deltaframe <= 0) { + Globals.cl.frame.valid = true; // uncompressed frame old = null; - cls.demowaiting = false; // we can start recording now - } - else { - old = cl.frames[cl.frame.deltaframe & UPDATE_MASK]; + Globals.cls.demowaiting = false; // we can start recording now + } else { + old = Globals.cl.frames[Globals.cl.frame.deltaframe & Defines.UPDATE_MASK]; if (!old.valid) { // should never happen Com.Printf("Delta from invalid frame (not supposed to happen!).\n"); } - if (old.serverframe != cl.frame.deltaframe) { // The frame that the server did the delta from + if (old.serverframe != Globals.cl.frame.deltaframe) { // The frame + // that the + // server did + // the delta + // from // is too old, so we can't reconstruct it properly. Com.Printf("Delta frame too old.\n"); - } - else if (cl.parse_entities - old.parse_entities > MAX_PARSE_ENTITIES - 128) { + } else if (Globals.cl.parse_entities - old.parse_entities > Defines.MAX_PARSE_ENTITIES - 128) { Com.Printf("Delta parse_entities too old.\n"); - } - else - cl.frame.valid = true; // valid delta parse + } else + Globals.cl.frame.valid = true; // valid delta parse } - // clamp time - if (cl.time > cl.frame.servertime) - cl.time = cl.frame.servertime; - else if (cl.time < cl.frame.servertime - 100) - cl.time = cl.frame.servertime - 100; + // clamp time + if (Globals.cl.time > Globals.cl.frame.servertime) + Globals.cl.time = Globals.cl.frame.servertime; + else if (Globals.cl.time < Globals.cl.frame.servertime - 100) + Globals.cl.time = Globals.cl.frame.servertime - 100; // read areabits - len = MSG.ReadByte(net_message); - MSG.ReadData(net_message, cl.frame.areabits, len); + len = MSG.ReadByte(Globals.net_message); + MSG.ReadData(Globals.net_message, Globals.cl.frame.areabits, len); // read playerinfo - cmd = MSG.ReadByte(net_message); + cmd = MSG.ReadByte(Globals.net_message); CL_parse.SHOWNET(CL_parse.svc_strings[cmd]); - if (cmd != svc_playerinfo) - Com.Error(ERR_DROP, "CL_ParseFrame: not playerinfo"); - ParsePlayerstate(old, cl.frame); + if (cmd != Defines.svc_playerinfo) + Com.Error(Defines.ERR_DROP, "CL_ParseFrame: not playerinfo"); + ParsePlayerstate(old, Globals.cl.frame); // read packet entities - cmd = MSG.ReadByte(net_message); + cmd = MSG.ReadByte(Globals.net_message); CL_parse.SHOWNET(CL_parse.svc_strings[cmd]); - if (cmd != svc_packetentities) - Com.Error(ERR_DROP, "CL_ParseFrame: not packetentities"); - - ParsePacketEntities(old, cl.frame); + if (cmd != Defines.svc_packetentities) + Com.Error(Defines.ERR_DROP, "CL_ParseFrame: not packetentities"); + + ParsePacketEntities(old, Globals.cl.frame); // save the frame off in the backup array for later delta comparisons - cl.frames[cl.frame.serverframe & UPDATE_MASK].set(cl.frame); + Globals.cl.frames[Globals.cl.frame.serverframe & Defines.UPDATE_MASK].set(Globals.cl.frame); - if (cl.frame.valid) { + if (Globals.cl.frame.valid) { // getting a valid frame message ends the connection process - if (cls.state != ca_active) { - cls.state = ca_active; - cl.force_refdef = true; - - cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0] * 0.125f; - cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1] * 0.125f; - cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2] * 0.125f; - - VectorCopy(cl.frame.playerstate.viewangles, cl.predicted_angles); - if (cls.disable_servercount != cl.servercount && cl.refresh_prepped) + if (Globals.cls.state != Defines.ca_active) { + Globals.cls.state = Defines.ca_active; + Globals.cl.force_refdef = true; + + Globals.cl.predicted_origin[0] = Globals.cl.frame.playerstate.pmove.origin[0] * 0.125f; + Globals.cl.predicted_origin[1] = Globals.cl.frame.playerstate.pmove.origin[1] * 0.125f; + Globals.cl.predicted_origin[2] = Globals.cl.frame.playerstate.pmove.origin[2] * 0.125f; + + Math3D.VectorCopy(Globals.cl.frame.playerstate.viewangles, Globals.cl.predicted_angles); + if (Globals.cls.disable_servercount != Globals.cl.servercount && Globals.cl.refresh_prepped) SCR.EndLoadingPlaque(); // get rid of loading plaque } - cl.sound_prepped = true; // can start mixing ambient sounds + Globals.cl.sound_prepped = true; // can start mixing ambient sounds // fire entity events - FireEntityEvents(cl.frame); + FireEntityEvents(Globals.cl.frame); CL_pred.CheckPredictionError(); } } /* - ========================================================================== - - INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS - - ========================================================================== - */ - - public static model_t S_RegisterSexedModel(entity_state_t ent, String base) { + * ========================================================================== + * + * INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS + * + * ========================================================================== + */ + + public static model_t S_RegisterSexedModel(entity_state_t ent, String base) { int n; model_t mdl; String model; @@ -595,38 +596,38 @@ public class CL_ents extends CL_inv { // determine what model the client is using model = ""; - - n = CS_PLAYERSKINS + ent.number - 1; - - if (cl.configstrings[n].length() >0) { - - int pos = cl.configstrings[n].indexOf('\\'); - if (pos!=-1) { + + n = Defines.CS_PLAYERSKINS + ent.number - 1; + + if (Globals.cl.configstrings[n].length() > 0) { + + int pos = Globals.cl.configstrings[n].indexOf('\\'); + if (pos != -1) { pos++; - model = cl.configstrings[n].substring(pos); + model = Globals.cl.configstrings[n].substring(pos); pos = model.indexOf('/'); - if (pos !=-1) - model = model.substring(0,pos); + if (pos != -1) + model = model.substring(0, pos); } } // if we can't figure it out, they're male - if (model.length()==0) + if (model.length() == 0) model = "male"; - buffer= "players/" + model + "/" + base + 1; - mdl = re.RegisterModel(buffer); - if (mdl==null) { + buffer = "players/" + model + "/" + base + 1; + mdl = Globals.re.RegisterModel(buffer); + if (mdl == null) { // not found, try default weapon model - buffer = "players/" + model + "/weapon.md2"; - mdl = re.RegisterModel(buffer); - if (mdl==null) { + buffer = "players/" + model + "/weapon.md2"; + mdl = Globals.re.RegisterModel(buffer); + if (mdl == null) { // no, revert to the male model - buffer="players/male/" + base + 1; - mdl = re.RegisterModel(buffer); - if (mdl==null) { + buffer = "players/male/" + base + 1; + mdl = Globals.re.RegisterModel(buffer); + if (mdl == null) { // last try, default male weapon.md2 buffer = "players/male/weapon.md2"; - mdl = re.RegisterModel(buffer); + mdl = Globals.re.RegisterModel(buffer); } } } @@ -634,220 +635,215 @@ public class CL_ents extends CL_inv { return mdl; } - // PMM - used in shell code + // PMM - used in shell code /* - =============== - CL_AddPacketEntities - - =============== - */ - static int bfg_lightramp[] = { 300, 400, 600, 300, 150, 75 }; - - static void AddPacketEntities(frame_t frame) { + * =============== CL_AddPacketEntities + * + * =============== + */ + static void AddPacketEntities(frame_t frame) { entity_t ent; entity_state_t s1; float autorotate; int i; int pnum; - centity_t cent; + centity_t cent; int autoanim; - clientinfo_t ci; + clientinfo_t ci; int effects, renderfx; // bonus items rotate at a fixed rate - autorotate = anglemod(cl.time / 10); + autorotate = Math3D.anglemod(Globals.cl.time / 10); // brush models can auto animate their frames - autoanim = 2 * cl.time / 1000; + autoanim = 2 * Globals.cl.time / 1000; //memset( ent, 0, sizeof(ent)); ent = new entity_t(); for (pnum = 0; pnum < frame.num_entities; pnum++) { - s1 = cl_parse_entities[(frame.parse_entities + pnum) & (MAX_PARSE_ENTITIES - 1)]; + s1 = Globals.cl_parse_entities[(frame.parse_entities + pnum) & (Defines.MAX_PARSE_ENTITIES - 1)]; - cent = cl_entities[s1.number]; + cent = Globals.cl_entities[s1.number]; effects = s1.effects; renderfx = s1.renderfx; // set frame - if ((effects & EF_ANIM01)!=0) + if ((effects & Defines.EF_ANIM01) != 0) ent.frame = autoanim & 1; - else if ((effects & EF_ANIM23)!=0) + else if ((effects & Defines.EF_ANIM23) != 0) ent.frame = 2 + (autoanim & 1); - else if ((effects & EF_ANIM_ALL)!=0) + else if ((effects & Defines.EF_ANIM_ALL) != 0) ent.frame = autoanim; - else if ((effects & EF_ANIM_ALLFAST)!=0) - ent.frame = cl.time / 100; + else if ((effects & Defines.EF_ANIM_ALLFAST) != 0) + ent.frame = Globals.cl.time / 100; else ent.frame = s1.frame; // quad and pent can do different things on client - if ((effects & EF_PENT)!=0) { - effects &= ~EF_PENT; - effects |= EF_COLOR_SHELL; - renderfx |= RF_SHELL_RED; + if ((effects & Defines.EF_PENT) != 0) { + effects &= ~Defines.EF_PENT; + effects |= Defines.EF_COLOR_SHELL; + renderfx |= Defines.RF_SHELL_RED; } - if ((effects & EF_QUAD)!=0) { - effects &= ~EF_QUAD; - effects |= EF_COLOR_SHELL; - renderfx |= RF_SHELL_BLUE; + if ((effects & Defines.EF_QUAD) != 0) { + effects &= ~Defines.EF_QUAD; + effects |= Defines.EF_COLOR_SHELL; + renderfx |= Defines.RF_SHELL_BLUE; } // ====== // PMM - if ((effects & EF_DOUBLE)!=0) { - effects &= ~EF_DOUBLE; - effects |= EF_COLOR_SHELL; - renderfx |= RF_SHELL_DOUBLE; + if ((effects & Defines.EF_DOUBLE) != 0) { + effects &= ~Defines.EF_DOUBLE; + effects |= Defines.EF_COLOR_SHELL; + renderfx |= Defines.RF_SHELL_DOUBLE; } - if ((effects & EF_HALF_DAMAGE) !=0){ - effects &= ~EF_HALF_DAMAGE; - effects |= EF_COLOR_SHELL; - renderfx |= RF_SHELL_HALF_DAM; + if ((effects & Defines.EF_HALF_DAMAGE) != 0) { + effects &= ~Defines.EF_HALF_DAMAGE; + effects |= Defines.EF_COLOR_SHELL; + renderfx |= Defines.RF_SHELL_HALF_DAM; } // pmm // ====== ent.oldframe = cent.prev.frame; - ent.backlerp = 1.0f - cl.lerpfrac; + ent.backlerp = 1.0f - Globals.cl.lerpfrac; - if ((renderfx & (RF_FRAMELERP | RF_BEAM))!=0) { // step origin discretely, because the frames + if ((renderfx & (Defines.RF_FRAMELERP | Defines.RF_BEAM)) != 0) { + // step origin discretely, because the frames // do the animation properly - VectorCopy(cent.current.origin, ent.origin); - VectorCopy(cent.current.old_origin, ent.oldorigin); - } - else { // interpolate origin + Math3D.VectorCopy(cent.current.origin, ent.origin); + Math3D.VectorCopy(cent.current.old_origin, ent.oldorigin); + } else { // interpolate origin for (i = 0; i < 3; i++) { - ent.origin[i] = - ent.oldorigin[i] = cent.prev.origin[i] + cl.lerpfrac * (cent.current.origin[i] - cent.prev.origin[i]); + ent.origin[i] = ent.oldorigin[i] = cent.prev.origin[i] + Globals.cl.lerpfrac + * (cent.current.origin[i] - cent.prev.origin[i]); } } // create a new entity // tweak the color of beams - if ((renderfx & RF_BEAM)!=0) { // the four beam colors are encoded in 32 bits of skinnum (hack) + if ((renderfx & Defines.RF_BEAM) != 0) { // the four beam colors are + // encoded in 32 bits of + // skinnum (hack) ent.alpha = 0.30f; - ent.skinnum = (s1.skinnum >> ((rnd.nextInt(4)) * 8)) & 0xff; + ent.skinnum = (s1.skinnum >> ((Globals.rnd.nextInt(4)) * 8)) & 0xff; Math.random(); ent.model = null; - } - else { + } else { // set skin if (s1.modelindex == 255) { // use custom player skin ent.skinnum = 0; - ci = cl.clientinfo[s1.skinnum & 0xff]; + ci = Globals.cl.clientinfo[s1.skinnum & 0xff]; ent.skin = ci.skin; ent.model = ci.model; - if (null==ent.skin || null==ent.model) { - ent.skin = cl.baseclientinfo.skin; - ent.model = cl.baseclientinfo.model; + if (null == ent.skin || null == ent.model) { + ent.skin = Globals.cl.baseclientinfo.skin; + ent.model = Globals.cl.baseclientinfo.model; } // ============ // PGM - if ((renderfx & RF_USE_DISGUISE)!=0) { + if ((renderfx & Defines.RF_USE_DISGUISE) != 0) { if (ent.skin.name.startsWith("players/male")) { - ent.skin = re.RegisterSkin("players/male/disguise.pcx"); - ent.model = re.RegisterModel("players/male/tris.md2"); - } - else if (ent.skin.name.startsWith( "players/female")) { - ent.skin = re.RegisterSkin("players/female/disguise.pcx"); - ent.model = re.RegisterModel("players/female/tris.md2"); - } - else if (ent.skin.name.startsWith("players/cyborg")) { - ent.skin = re.RegisterSkin("players/cyborg/disguise.pcx"); - ent.model = re.RegisterModel("players/cyborg/tris.md2"); + ent.skin = Globals.re.RegisterSkin("players/male/disguise.pcx"); + ent.model = Globals.re.RegisterModel("players/male/tris.md2"); + } else if (ent.skin.name.startsWith("players/female")) { + ent.skin = Globals.re.RegisterSkin("players/female/disguise.pcx"); + ent.model = Globals.re.RegisterModel("players/female/tris.md2"); + } else if (ent.skin.name.startsWith("players/cyborg")) { + ent.skin = Globals.re.RegisterSkin("players/cyborg/disguise.pcx"); + ent.model = Globals.re.RegisterModel("players/cyborg/tris.md2"); } } // PGM // ============ - } - else { + } else { ent.skinnum = s1.skinnum; ent.skin = null; - ent.model = cl.model_draw[s1.modelindex]; + ent.model = Globals.cl.model_draw[s1.modelindex]; } } // only used for black hole model right now, FIXME: do better - if (renderfx == RF_TRANSLUCENT) + if (renderfx == Defines.RF_TRANSLUCENT) ent.alpha = 0.70f; // render effects (fullbright, translucent, etc) - if ((effects & EF_COLOR_SHELL)!=0) + if ((effects & Defines.EF_COLOR_SHELL) != 0) ent.flags = 0; // renderfx go on color shell entity else ent.flags = renderfx; // calculate angles - if ((effects & EF_ROTATE)!=0) { // some bonus items auto-rotate + if ((effects & Defines.EF_ROTATE) != 0) { // some bonus items + // auto-rotate ent.angles[0] = 0; ent.angles[1] = autorotate; ent.angles[2] = 0; } // RAFAEL - else if ((effects & EF_SPINNINGLIGHTS)!=0) { + else if ((effects & Defines.EF_SPINNINGLIGHTS) != 0) { ent.angles[0] = 0; - ent.angles[1] = anglemod(cl.time / 2) + s1.angles[1]; + ent.angles[1] = Math3D.anglemod(Globals.cl.time / 2) + s1.angles[1]; ent.angles[2] = 180; { - float[] forward={0,0,0}; - float[] start={0,0,0}; + float[] forward = { 0, 0, 0 }; + float[] start = { 0, 0, 0 }; - AngleVectors(ent.angles, forward, null, null); - VectorMA(ent.origin, 64, forward, start); + Math3D.AngleVectors(ent.angles, forward, null, null); + Math3D.VectorMA(ent.origin, 64, forward, start); V.AddLight(start, 100, 1, 0, 0); } - } - else { // interpolate angles + } else { // interpolate angles float a1, a2; for (i = 0; i < 3; i++) { a1 = cent.current.angles[i]; a2 = cent.prev.angles[i]; - ent.angles[i] = LerpAngle(a2, a1, cl.lerpfrac); + ent.angles[i] = Math3D.LerpAngle(a2, a1, Globals.cl.lerpfrac); } } - if (s1.number == cl.playernum + 1) { - ent.flags |= RF_VIEWERMODEL; // only draw from mirrors + if (s1.number == Globals.cl.playernum + 1) { + ent.flags |= Defines.RF_VIEWERMODEL; // only draw from mirrors // FIXME: still pass to refresh - if ((effects & EF_FLAG1)!=0) + if ((effects & Defines.EF_FLAG1) != 0) V.AddLight(ent.origin, 225, 1.0f, 0.1f, 0.1f); - else if ((effects & EF_FLAG2)!=0) + else if ((effects & Defines.EF_FLAG2) != 0) V.AddLight(ent.origin, 225, 0.1f, 0.1f, 1.0f); - else if ((effects & EF_TAGTRAIL)!=0) //PGM + else if ((effects & Defines.EF_TAGTRAIL) != 0) //PGM V.AddLight(ent.origin, 225, 1.0f, 1.0f, 0.0f); //PGM - else if ((effects & EF_TRACKERTRAIL)!=0) //PGM + else if ((effects & Defines.EF_TRACKERTRAIL) != 0) //PGM V.AddLight(ent.origin, 225, -1.0f, -1.0f, -1.0f); //PGM continue; } // if set to invisible, skip - if (s1.modelindex==0) + if (s1.modelindex == 0) continue; - if ((effects & EF_BFG)!=0) { - ent.flags |= RF_TRANSLUCENT; + if ((effects & Defines.EF_BFG) != 0) { + ent.flags |= Defines.RF_TRANSLUCENT; ent.alpha = 0.30f; } // RAFAEL - if ((effects & EF_PLASMA)!=0) { - ent.flags |= RF_TRANSLUCENT; + if ((effects & Defines.EF_PLASMA) != 0) { + ent.flags |= Defines.RF_TRANSLUCENT; ent.alpha = 0.6f; } - if ((effects & EF_SPHERETRANS)!=0) { - ent.flags |= RF_TRANSLUCENT; - // PMM - *sigh* yet more EF overloading - if ((effects & EF_TRACKERTRAIL)!=0) + if ((effects & Defines.EF_SPHERETRANS) != 0) { + ent.flags |= Defines.RF_TRANSLUCENT; + // PMM - *sigh* yet more EF overloading + if ((effects & Defines.EF_TRACKERTRAIL) != 0) ent.alpha = 0.6f; else ent.alpha = 0.3f; @@ -855,50 +851,54 @@ public class CL_ents extends CL_inv { // pmm // add to refresh list - V.AddEntity( ent); + V.AddEntity(ent); // color shells generate a seperate entity for the main model - if ((effects & EF_COLOR_SHELL)!=0) { + if ((effects & Defines.EF_COLOR_SHELL) != 0) { /* - PMM - at this point, all of the shells have been handled - if we're in the rogue pack, set up the custom mixing, otherwise just - keep going - if(Developer_searchpath(2) == 2) - { - all of the solo colors are fine. we need to catch any of the combinations that look bad - (double & half) and turn them into the appropriate color, and make double/quad something special - + * PMM - at this point, all of the shells have been handled if + * we're in the rogue pack, set up the custom mixing, otherwise + * just keep going if(Developer_searchpath(2) == 2) { all of the + * solo colors are fine. we need to catch any of the + * combinations that look bad (double & half) and turn them into + * the appropriate color, and make double/quad something special + * */ - if ((renderfx & RF_SHELL_HALF_DAM)!=0) { + if ((renderfx & Defines.RF_SHELL_HALF_DAM) != 0) { if (FS.Developer_searchpath(2) == 2) { - // ditch the half damage shell if any of red, blue, or double are on - if ((renderfx & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE))!=0) - renderfx &= ~RF_SHELL_HALF_DAM; + // ditch the half damage shell if any of red, blue, or + // double are on + if ((renderfx & (Defines.RF_SHELL_RED | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE)) != 0) + renderfx &= ~Defines.RF_SHELL_HALF_DAM; } } - if ((renderfx & RF_SHELL_DOUBLE)!=0) { + if ((renderfx & Defines.RF_SHELL_DOUBLE) != 0) { if (FS.Developer_searchpath(2) == 2) { - // lose the yellow shell if we have a red, blue, or green shell - if ((renderfx & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_GREEN))!=0) - renderfx &= ~RF_SHELL_DOUBLE; - // if we have a red shell, turn it to purple by adding blue - if ((renderfx & RF_SHELL_RED)!=0) - renderfx |= RF_SHELL_BLUE; - // if we have a blue shell (and not a red shell), turn it to cyan by adding green - else if ((renderfx & RF_SHELL_BLUE)!=0) - // go to green if it's on already, otherwise do cyan (flash green) - if ((renderfx & RF_SHELL_GREEN)!=0) - renderfx &= ~RF_SHELL_BLUE; + // lose the yellow shell if we have a red, blue, or + // green shell + if ((renderfx & (Defines.RF_SHELL_RED | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_GREEN)) != 0) + renderfx &= ~Defines.RF_SHELL_DOUBLE; + // if we have a red shell, turn it to purple by adding + // blue + if ((renderfx & Defines.RF_SHELL_RED) != 0) + renderfx |= Defines.RF_SHELL_BLUE; + // if we have a blue shell (and not a red shell), turn + // it to cyan by adding green + else if ((renderfx & Defines.RF_SHELL_BLUE) != 0) + // go to green if it's on already, otherwise do cyan + // (flash green) + if ((renderfx & Defines.RF_SHELL_GREEN) != 0) + renderfx &= ~Defines.RF_SHELL_BLUE; else - renderfx |= RF_SHELL_GREEN; + renderfx |= Defines.RF_SHELL_GREEN; } } // } // pmm - ent.flags = renderfx | RF_TRANSLUCENT; + ent.flags = renderfx | Defines.RF_TRANSLUCENT; ent.alpha = 0.30f; - V.AddEntity( ent); + V.AddEntity(ent); } ent.skin = null; // never use a custom skin on others @@ -907,146 +907,138 @@ public class CL_ents extends CL_inv { ent.alpha = 0; // duplicate for linked models - if (s1.modelindex2!=0) { + if (s1.modelindex2 != 0) { if (s1.modelindex2 == 255) { // custom weapon - ci = cl.clientinfo[s1.skinnum & 0xff]; + ci = Globals.cl.clientinfo[s1.skinnum & 0xff]; i = (s1.skinnum >> 8); // 0 is default weapon model - if (0==cl_vwep.value || i > MAX_CLIENTWEAPONMODELS - 1) + if (0 == Globals.cl_vwep.value || i > Defines.MAX_CLIENTWEAPONMODELS - 1) i = 0; ent.model = ci.weaponmodel[i]; - if (null==ent.model) { + if (null == ent.model) { if (i != 0) ent.model = ci.weaponmodel[0]; - if (null==ent.model) - ent.model = cl.baseclientinfo.weaponmodel[0]; + if (null == ent.model) + ent.model = Globals.cl.baseclientinfo.weaponmodel[0]; } - } - else - ent.model = cl.model_draw[s1.modelindex2]; - - // PMM - check for the defender sphere shell .. make it translucent - // replaces the previous version which used the high bit on modelindex2 to determine transparency - if (cl.configstrings[CS_MODELS + (s1.modelindex2)].equalsIgnoreCase( "models/items/shell/tris.md2")) { + } else + ent.model = Globals.cl.model_draw[s1.modelindex2]; + + // PMM - check for the defender sphere shell .. make it + // translucent + // replaces the previous version which used the high bit on + // modelindex2 to determine transparency + if (Globals.cl.configstrings[Defines.CS_MODELS + (s1.modelindex2)].equalsIgnoreCase("models/items/shell/tris.md2")) { ent.alpha = 0.32f; - ent.flags = RF_TRANSLUCENT; + ent.flags = Defines.RF_TRANSLUCENT; } // pmm - V.AddEntity( ent); + V.AddEntity(ent); //PGM - make sure these get reset. ent.flags = 0; ent.alpha = 0; //PGM } - if (s1.modelindex3!=0) { - ent.model = cl.model_draw[s1.modelindex3]; - V.AddEntity( ent); + if (s1.modelindex3 != 0) { + ent.model = Globals.cl.model_draw[s1.modelindex3]; + V.AddEntity(ent); } - if (s1.modelindex4!=0) { - ent.model = cl.model_draw[s1.modelindex4]; - V.AddEntity( ent); + if (s1.modelindex4 != 0) { + ent.model = Globals.cl.model_draw[s1.modelindex4]; + V.AddEntity(ent); } - if ((effects & EF_POWERSCREEN)!=0) { + if ((effects & Defines.EF_POWERSCREEN) != 0) { ent.model = CL_tent.cl_mod_powerscreen; ent.oldframe = 0; ent.frame = 0; - ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN); + ent.flags |= (Defines.RF_TRANSLUCENT | Defines.RF_SHELL_GREEN); ent.alpha = 0.30f; - V.AddEntity( ent); + V.AddEntity(ent); } // add automatic particle trails - if ((effects & ~EF_ROTATE)!=0) { - if ((effects & EF_ROCKET)!=0) { - RocketTrail(cent.lerp_origin, ent.origin, cent); + if ((effects & ~Defines.EF_ROTATE) != 0) { + if ((effects & Defines.EF_ROCKET) != 0) { + CL_fx.RocketTrail(cent.lerp_origin, ent.origin, cent); V.AddLight(ent.origin, 200, 1, 1, 0); } - // PGM - Do not reorder EF_BLASTER and EF_HYPERBLASTER. - // EF_BLASTER | EF_TRACKER is a special case for EF_BLASTER2... Cheese! - else if ((effects & EF_BLASTER)!=0) { + // PGM - Do not reorder EF_BLASTER and EF_HYPERBLASTER. + // EF_BLASTER | EF_TRACKER is a special case for EF_BLASTER2... + // Cheese! + else if ((effects & Defines.EF_BLASTER) != 0) { // CL_BlasterTrail (cent.lerp_origin, ent.origin); // PGM - if ((effects & EF_TRACKER)!=0) // lame... problematic? - { + if ((effects & Defines.EF_TRACKER) != 0) // lame... + // problematic? + { CL_newfx.BlasterTrail2(cent.lerp_origin, ent.origin); V.AddLight(ent.origin, 200, 0, 1, 0); - } - else { - BlasterTrail(cent.lerp_origin, ent.origin); + } else { + CL_fx.BlasterTrail(cent.lerp_origin, ent.origin); V.AddLight(ent.origin, 200, 1, 1, 0); } // PGM - } - else if ((effects & EF_HYPERBLASTER)!=0) { - if ((effects & EF_TRACKER)!=0) // PGM overloaded for blaster2. + } else if ((effects & Defines.EF_HYPERBLASTER) != 0) { + if ((effects & Defines.EF_TRACKER) != 0) // PGM overloaded + // for blaster2. V.AddLight(ent.origin, 200, 0, 1, 0); // PGM - else // PGM + else + // PGM V.AddLight(ent.origin, 200, 1, 1, 0); - } - else if ((effects & EF_GIB)!=0) { - DiminishingTrail(cent.lerp_origin, ent.origin, cent, effects); - } - else if ((effects & EF_GRENADE)!=0) { - DiminishingTrail(cent.lerp_origin, ent.origin, cent, effects); - } - else if ((effects & EF_FLIES)!=0) { - FlyEffect(cent, ent.origin); - } - else if ((effects & EF_BFG)!=0) { - - - if ((effects & EF_ANIM_ALLFAST)!=0) { - BfgParticles( ent); + } else if ((effects & Defines.EF_GIB) != 0) { + CL_fx.DiminishingTrail(cent.lerp_origin, ent.origin, cent, effects); + } else if ((effects & Defines.EF_GRENADE) != 0) { + CL_fx.DiminishingTrail(cent.lerp_origin, ent.origin, cent, effects); + } else if ((effects & Defines.EF_FLIES) != 0) { + CL_fx.FlyEffect(cent, ent.origin); + } else if ((effects & Defines.EF_BFG) != 0) { + + if ((effects & Defines.EF_ANIM_ALLFAST) != 0) { + CL_fx.BfgParticles(ent); i = 200; - } - else { + } else { i = bfg_lightramp[s1.frame]; } V.AddLight(ent.origin, i, 0, 1, 0); } // RAFAEL - else if ((effects & EF_TRAP)!=0) { + else if ((effects & Defines.EF_TRAP) != 0) { ent.origin[2] += 32; - TrapParticles( ent); - i = (rnd.nextInt(100)) + 100; + CL_fx.TrapParticles(ent); + i = (Globals.rnd.nextInt(100)) + 100; V.AddLight(ent.origin, i, 1, 0.8f, 0.1f); - } - else if ((effects & EF_FLAG1)!=0) { - FlagTrail(cent.lerp_origin, ent.origin, 242); + } else if ((effects & Defines.EF_FLAG1) != 0) { + CL_fx.FlagTrail(cent.lerp_origin, ent.origin, 242); V.AddLight(ent.origin, 225, 1, 0.1f, 0.1f); - } - else if ((effects & EF_FLAG2)!=0) { - FlagTrail(cent.lerp_origin, ent.origin, 115); + } else if ((effects & Defines.EF_FLAG2) != 0) { + CL_fx.FlagTrail(cent.lerp_origin, ent.origin, 115); V.AddLight(ent.origin, 225, 0.1f, 0.1f, 1); } // ====== // ROGUE - else if ((effects & EF_TAGTRAIL)!=0) { + else if ((effects & Defines.EF_TAGTRAIL) != 0) { CL_newfx.TagTrail(cent.lerp_origin, ent.origin, 220); V.AddLight(ent.origin, 225, 1.0f, 1.0f, 0.0f); - } - else if ((effects & EF_TRACKERTRAIL)!=0) { - if ((effects & EF_TRACKER)!=0) { + } else if ((effects & Defines.EF_TRACKERTRAIL) != 0) { + if ((effects & Defines.EF_TRACKER) != 0) { float intensity; - intensity = (float) (50 + (500 * (Math.sin(cl.time / 500.0) + 1.0))); + intensity = (float) (50 + (500 * (Math.sin(Globals.cl.time / 500.0) + 1.0))); // FIXME - check out this effect in rendition - if (vidref_val == VIDREF_GL) + if (Globals.vidref_val == Defines.VIDREF_GL) V.AddLight(ent.origin, intensity, -1.0f, -1.0f, -1.0f); else V.AddLight(ent.origin, -1.0f * intensity, 1.0f, 1.0f, 1.0f); - } - else { + } else { CL_newfx.Tracker_Shell(cent.lerp_origin); V.AddLight(ent.origin, 155, -1.0f, -1.0f, -1.0f); } - } - else if ((effects & EF_TRACKER)!=0) { + } else if ((effects & Defines.EF_TRACKER) != 0) { CL_newfx.TrackerTrail(cent.lerp_origin, ent.origin, 0); // FIXME - check out this effect in rendition - if (vidref_val == VIDREF_GL) + if (Globals.vidref_val == Defines.VIDREF_GL) V.AddLight(ent.origin, 200, -1, -1, -1); else V.AddLight(ent.origin, -200, 1, 1, 1); @@ -1054,42 +1046,40 @@ public class CL_ents extends CL_inv { // ROGUE // ====== // RAFAEL - else if ((effects & EF_GREENGIB)!=0) { - DiminishingTrail(cent.lerp_origin, ent.origin, cent, effects); + else if ((effects & Defines.EF_GREENGIB) != 0) { + CL_fx.DiminishingTrail(cent.lerp_origin, ent.origin, cent, effects); } // RAFAEL - else if ((effects & EF_IONRIPPER)!=0) { - IonripperTrail(cent.lerp_origin, ent.origin); + else if ((effects & Defines.EF_IONRIPPER) != 0) { + CL_fx.IonripperTrail(cent.lerp_origin, ent.origin); V.AddLight(ent.origin, 100, 1, 0.5f, 0.5f); } // RAFAEL - else if ((effects & EF_BLUEHYPERBLASTER)!=0) { + else if ((effects & Defines.EF_BLUEHYPERBLASTER) != 0) { V.AddLight(ent.origin, 200, 0, 0, 1); } // RAFAEL - else if ((effects & EF_PLASMA)!=0) { - if ((effects & EF_ANIM_ALLFAST)!=0) { - BlasterTrail(cent.lerp_origin, ent.origin); + else if ((effects & Defines.EF_PLASMA) != 0) { + if ((effects & Defines.EF_ANIM_ALLFAST) != 0) { + CL_fx.BlasterTrail(cent.lerp_origin, ent.origin); } V.AddLight(ent.origin, 130, 1, 0.5f, 0.5f); } } - VectorCopy(ent.origin, cent.lerp_origin); + Math3D.VectorCopy(ent.origin, cent.lerp_origin); } } /* - ============== - CL_AddViewWeapon - ============== - */ - static void AddViewWeapon(player_state_t ps, player_state_t ops) { + * ============== CL_AddViewWeapon ============== + */ + static void AddViewWeapon(player_state_t ps, player_state_t ops) { entity_t gun; // view model int i; // allow the gun to be completely removed - if (0==cl_gun.value) + if (0 == Globals.cl_gun.value) return; // don't draw gun if in wide angle view @@ -1099,25 +1089,25 @@ public class CL_ents extends CL_inv { //memset( gun, 0, sizeof(gun)); gun = new entity_t(); - if (gun_model!=null) - gun.model = gun_model; // development tool + if (Globals.gun_model != null) + gun.model = Globals.gun_model; // development tool else - gun.model = cl.model_draw[ps.gunindex]; - - if (gun.model==null) + gun.model = Globals.cl.model_draw[ps.gunindex]; + + if (gun.model == null) return; // set up gun position for (i = 0; i < 3; i++) { - gun.origin[i] = cl.refdef.vieworg[i] + ops.gunoffset[i] + cl.lerpfrac * (ps.gunoffset[i] - ops.gunoffset[i]); - gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle(ops.gunangles[i], ps.gunangles[i], cl.lerpfrac); + gun.origin[i] = Globals.cl.refdef.vieworg[i] + ops.gunoffset[i] + Globals.cl.lerpfrac + * (ps.gunoffset[i] - ops.gunoffset[i]); + gun.angles[i] = Globals.cl.refdef.viewangles[i] + Math3D.LerpAngle(ops.gunangles[i], ps.gunangles[i], Globals.cl.lerpfrac); } - if (gun_frame!=0) { - gun.frame = gun_frame; // development tool - gun.oldframe = gun_frame; // development tool - } - else { + if (Globals.gun_frame != 0) { + gun.frame = Globals.gun_frame; // development tool + gun.oldframe = Globals.gun_frame; // development tool + } else { gun.frame = ps.gunframe; if (gun.frame == 0) gun.oldframe = 0; // just changed weapons, don't lerp from old @@ -1125,159 +1115,146 @@ public class CL_ents extends CL_inv { gun.oldframe = ops.gunframe; } - gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL; - gun.backlerp = 1.0f - cl.lerpfrac; - VectorCopy(gun.origin, gun.oldorigin); // don't lerp at all - V.AddEntity( gun); + gun.flags = Defines.RF_MINLIGHT | Defines.RF_DEPTHHACK | Defines.RF_WEAPONMODEL; + gun.backlerp = 1.0f - Globals.cl.lerpfrac; + Math3D.VectorCopy(gun.origin, gun.oldorigin); // don't lerp at all + V.AddEntity(gun); } /* - =============== - CL_CalcViewValues - - Sets cl.refdef view values - =============== - */ + * =============== CL_CalcViewValues + * + * Sets cl.refdef view values =============== + */ static void CalcViewValues() { int i; float lerp, backlerp; - frame_t oldframe; - player_state_t ps, ops; + frame_t oldframe; + player_state_t ps, ops; // find the previous frame to interpolate from - ps = cl.frame.playerstate; - - i = (cl.frame.serverframe - 1) & UPDATE_MASK; - oldframe = cl.frames[i]; - - if (oldframe.serverframe != cl.frame.serverframe - 1 || !oldframe.valid) - oldframe = cl.frame; // previous frame was dropped or involid - ops = oldframe.playerstate; + ps = Globals.cl.frame.playerstate; + + i = (Globals.cl.frame.serverframe - 1) & Defines.UPDATE_MASK; + oldframe = Globals.cl.frames[i]; + + if (oldframe.serverframe != Globals.cl.frame.serverframe - 1 || !oldframe.valid) + oldframe = Globals.cl.frame; // previous frame was dropped or + // involid + ops = oldframe.playerstate; // see if the player entity was teleported this frame if (Math.abs(ops.pmove.origin[0] - ps.pmove.origin[0]) > 256 * 8 - || Math.abs(ops.pmove.origin[1] - ps.pmove.origin[1]) > 256 * 8 - || Math.abs(ops.pmove.origin[2] - ps.pmove.origin[2]) > 256 * 8) + || Math.abs(ops.pmove.origin[1] - ps.pmove.origin[1]) > 256 * 8 + || Math.abs(ops.pmove.origin[2] - ps.pmove.origin[2]) > 256 * 8) ops = ps; // don't interpolate - lerp = cl.lerpfrac; + lerp = Globals.cl.lerpfrac; // calculate the origin - if ((cl_predict.value!=0) && 0==(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION)) { // use predicted values + if ((Globals.cl_predict.value != 0) && 0 == (Globals.cl.frame.playerstate.pmove.pm_flags & pmove_t.PMF_NO_PREDICTION)) { // use + // predicted + // values int delta; backlerp = 1.0f - lerp; for (i = 0; i < 3; i++) { - cl.refdef.vieworg[i] = - cl.predicted_origin[i] - + ops.viewoffset[i] - + cl.lerpfrac * (ps.viewoffset[i] - ops.viewoffset[i]) - - backlerp * cl.prediction_error[i]; + Globals.cl.refdef.vieworg[i] = Globals.cl.predicted_origin[i] + ops.viewoffset[i] + Globals.cl.lerpfrac + * (ps.viewoffset[i] - ops.viewoffset[i]) - backlerp * Globals.cl.prediction_error[i]; } // smooth out stair climbing - delta = (int) (cls.realtime - cl.predicted_step_time); + delta = (int) (Globals.cls.realtime - Globals.cl.predicted_step_time); if (delta < 100) - cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01; - } - else { // just use interpolated values + Globals.cl.refdef.vieworg[2] -= Globals.cl.predicted_step * (100 - delta) * 0.01; + } else { // just use interpolated values for (i = 0; i < 3; i++) - cl.refdef.vieworg[i] = - ops.pmove.origin[i] * 0.125f - + ops.viewoffset[i] - + lerp * (ps.pmove.origin[i] * 0.125f + ps.viewoffset[i] - (ops.pmove.origin[i] * 0.125f + ops.viewoffset[i])); + Globals.cl.refdef.vieworg[i] = ops.pmove.origin[i] * 0.125f + ops.viewoffset[i] + lerp + * (ps.pmove.origin[i] * 0.125f + ps.viewoffset[i] - (ops.pmove.origin[i] * 0.125f + ops.viewoffset[i])); } - // if not running a demo or on a locked frame, add the local angle movement - if (cl.frame.playerstate.pmove.pm_type < PM_DEAD) { // use predicted values + // if not running a demo or on a locked frame, add the local angle + // movement + if (Globals.cl.frame.playerstate.pmove.pm_type < Defines.PM_DEAD) { // use + // predicted + // values for (i = 0; i < 3; i++) - cl.refdef.viewangles[i] = cl.predicted_angles[i]; - } - else { // just use interpolated values + Globals.cl.refdef.viewangles[i] = Globals.cl.predicted_angles[i]; + } else { // just use interpolated values for (i = 0; i < 3; i++) - cl.refdef.viewangles[i] = LerpAngle(ops.viewangles[i], ps.viewangles[i], lerp); + Globals.cl.refdef.viewangles[i] = Math3D.LerpAngle(ops.viewangles[i], ps.viewangles[i], lerp); } for (i = 0; i < 3; i++) - cl.refdef.viewangles[i] += LerpAngle(ops.kick_angles[i], ps.kick_angles[i], lerp); + Globals.cl.refdef.viewangles[i] += Math3D.LerpAngle(ops.kick_angles[i], ps.kick_angles[i], lerp); - AngleVectors(cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up); + Math3D.AngleVectors(Globals.cl.refdef.viewangles, Globals.cl.v_forward, Globals.cl.v_right, Globals.cl.v_up); // interpolate field of view - cl.refdef.fov_x = ops.fov + lerp * (ps.fov - ops.fov); + Globals.cl.refdef.fov_x = ops.fov + lerp * (ps.fov - ops.fov); // don't interpolate blend color for (i = 0; i < 4; i++) - cl.refdef.blend[i] = ps.blend[i]; + Globals.cl.refdef.blend[i] = ps.blend[i]; // add the weapon AddViewWeapon(ps, ops); } /* - =============== - CL_AddEntities - - Emits all entities, particles, and lights to the refresh - =============== - */ + * =============== CL_AddEntities + * + * Emits all entities, particles, and lights to the refresh =============== + */ static void AddEntities() { - if (cls.state != ca_active) + if (Globals.cls.state != Defines.ca_active) return; - if (cl.time > cl.frame.servertime) { - if (cl_showclamp.value!=0) - Com.Printf("high clamp " + (cl.time - cl.frame.servertime) + "\n"); - cl.time = cl.frame.servertime; - cl.lerpfrac = 1.0f; - } - else if (cl.time < cl.frame.servertime - 100) { - if (cl_showclamp.value!=0) - Com.Printf("low clamp " + (cl.frame.servertime - 100 - cl.time)+"\n"); - cl.time = cl.frame.servertime - 100; - cl.lerpfrac = 0; - } - else - cl.lerpfrac = 1.0f - (cl.frame.servertime - cl.time) * 0.01f; - - if (cl_timedemo.value!=0) - cl.lerpfrac = 1.0f; - - - /* is ok.. - CL_AddPacketEntities (cl.frame); - CL_AddTEnts (); - CL_AddParticles (); - CL_AddDLights (); - CL_AddLightStyles (); - */ - + if (Globals.cl.time > Globals.cl.frame.servertime) { + if (Globals.cl_showclamp.value != 0) + Com.Printf("high clamp " + (Globals.cl.time - Globals.cl.frame.servertime) + "\n"); + Globals.cl.time = Globals.cl.frame.servertime; + Globals.cl.lerpfrac = 1.0f; + } else if (Globals.cl.time < Globals.cl.frame.servertime - 100) { + if (Globals.cl_showclamp.value != 0) + Com.Printf("low clamp " + (Globals.cl.frame.servertime - 100 - Globals.cl.time) + "\n"); + Globals.cl.time = Globals.cl.frame.servertime - 100; + Globals.cl.lerpfrac = 0; + } else + Globals.cl.lerpfrac = 1.0f - (Globals.cl.frame.servertime - Globals.cl.time) * 0.01f; + + if (Globals.cl_timedemo.value != 0) + Globals.cl.lerpfrac = 1.0f; + + /* + * is ok.. CL_AddPacketEntities (cl.frame); CL_AddTEnts (); + * CL_AddParticles (); CL_AddDLights (); CL_AddLightStyles (); + */ + CalcViewValues(); - // PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun - AddPacketEntities( cl.frame); + // PMM - moved this here so the heat beam has the right values for the + // vieworg, and can lock the beam to the gun + AddPacketEntities(Globals.cl.frame); CL_tent.AddTEnts(); - AddParticles(); + CL_fx.AddParticles(); CL_fx.AddDLights(); - AddLightStyles(); + CL_fx.AddLightStyles(); } /* - =============== - CL_GetEntitySoundOrigin - - Called to get the sound spatialization origin - =============== - */ + * =============== CL_GetEntitySoundOrigin + * + * Called to get the sound spatialization origin =============== + */ public static void GetEntitySoundOrigin(int ent, float[] org) { centity_t old; - if (ent < 0 || ent >= MAX_EDICTS) - Com.Error(ERR_DROP, "CL_GetEntitySoundOrigin: bad ent"); - old = cl_entities[ent]; - VectorCopy(old.lerp_origin, org); + if (ent < 0 || ent >= Defines.MAX_EDICTS) + Com.Error(Defines.ERR_DROP, "CL_GetEntitySoundOrigin: bad ent"); + old = Globals.cl_entities[ent]; + Math3D.VectorCopy(old.lerp_origin, org); // FIXME: bmodel issues... } - -} +} \ No newline at end of file diff --git a/src/jake2/client/CL_fx.java b/src/jake2/client/CL_fx.java index 529101b..3032f81 100644 --- a/src/jake2/client/CL_fx.java +++ b/src/jake2/client/CL_fx.java @@ -1,92 +1,136 @@ /* - * CL_fx.java + * java * Copyright (C) 2004 * - * $Id: CL_fx.java,v 1.5 2004-07-13 11:09:55 hzi Exp $ + * $Id: CL_fx.java,v 1.6 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; +import jake2.Defines; import jake2.Globals; import jake2.game.M_Flash; import jake2.game.entity_state_t; import jake2.qcommon.Com; import jake2.qcommon.MSG; -import jake2.sound.*; +import jake2.sound.S; +import jake2.util.Lib; +import jake2.util.Math3D; /** - * CL_fx + * Client Graphics Effects. */ -public class CL_fx extends CL_tent { - - static final float INSTANT_PARTICLE = -10000.0f; - +public class CL_fx { + static class cdlight_t { int key; // so entities can reuse same entry + float[] color = { 0, 0, 0 }; + float[] origin = { 0, 0, 0 }; + float radius; + float die; // stop lighting after this time + //float decay; // drop this each second float minlight; // don't add when contributing less + void clear() { radius = minlight = color[0] = color[1] = color[2] = 0; } } - static float[][] avelocities = new float[NUMVERTEXNORMALS][3]; + static cparticle_t[] particles = new cparticle_t[Defines.MAX_PARTICLES]; + static { + for (int i = 0; i < particles.length; i++) + particles[i] = new cparticle_t(); + } + + static int cl_numparticles = Defines.MAX_PARTICLES; - /* - ============================================================== + static final float INSTANT_PARTICLE = -10000.0f; - LIGHT STYLE MANAGEMENT + static float[][] avelocities = new float[Defines.NUMVERTEXNORMALS][3]; - ============================================================== - */ + static clightstyle_t[] cl_lightstyle = new clightstyle_t[Defines.MAX_LIGHTSTYLES]; + + static int lastofs; + + /* + * ============================================================== + * + * LIGHT STYLE MANAGEMENT + * + * ============================================================== + */ static class clightstyle_t { int length; + float[] value = new float[3]; - float[] map = new float[MAX_QPATH]; + + float[] map = new float[Defines.MAX_QPATH]; + void clear() { value[0] = value[1] = value[2] = length = 0; for (int i = 0; i < map.length; i++) map[i] = 0.0f; } } - static clightstyle_t[] cl_lightstyle = new clightstyle_t[MAX_LIGHTSTYLES]; + static { - for(int i=0; i= MAX_QPATH) - Com.Error(ERR_DROP, "svc_lightstyle length=" + j); + if (j >= Defines.MAX_QPATH) + Com.Error(Defines.ERR_DROP, "svc_lightstyle length=" + j); cl_lightstyle[i].length = j; @@ -136,10 +178,8 @@ public class CL_fx extends CL_tent { } /* - ================ - CL_AddLightStyles - ================ - */ + * ================ CL_AddLightStyles ================ + */ static void AddLightStyles() { clightstyle_t ls; @@ -150,44 +190,17 @@ public class CL_fx extends CL_tent { } /* - ============================================================== - - DLIGHT MANAGEMENT - - ============================================================== - */ - - static cdlight_t[] cl_dlights = new cdlight_t[MAX_DLIGHTS]; - static { - for (int i = 0; i < cl_dlights.length; i++) - cl_dlights[i] = new cdlight_t(); - } - - /* - ================ - CL_ClearDlights - ================ - */ - static void ClearDlights() { - // memset (cl_dlights, 0, sizeof(cl_dlights)); - for (int i = 0; i < cl_dlights.length; i++) { - cl_dlights[i].clear(); - } - } - - /* - =============== - CL_AllocDlight - - =============== - */ + * =============== CL_AllocDlight + * + * =============== + */ static cdlight_t AllocDlight(int key) { int i; cdlight_t dl; // first look for an exact key match - if (key != 0) { - for (i = 0; i < MAX_DLIGHTS; i++) { + if (key != 0) { + for (i = 0; i < Defines.MAX_DLIGHTS; i++) { dl = cl_dlights[i]; if (dl.key == key) { //memset (dl, 0, sizeof(*dl)); @@ -199,9 +212,9 @@ public class CL_fx extends CL_tent { } // then look for anything else - for (i = 0; i < MAX_DLIGHTS; i++) { + for (i = 0; i < Defines.MAX_DLIGHTS; i++) { dl = cl_dlights[i]; - if (dl.die < cl.time) { + if (dl.die < Globals.cl.time) { //memset (dl, 0, sizeof(*dl)); dl.clear(); dl.key = key; @@ -218,36 +231,33 @@ public class CL_fx extends CL_tent { } /* - =============== - CL_NewDlight - =============== - */ + * =============== CL_NewDlight =============== + */ static void NewDlight(int key, float x, float y, float z, float radius, float time) { cdlight_t dl; - dl = CL.AllocDlight(key); + dl = AllocDlight(key); dl.origin[0] = x; dl.origin[1] = y; dl.origin[2] = z; dl.radius = radius; - dl.die = cl.time + time; + dl.die = Globals.cl.time + time; } /* - =============== - CL_RunDLights - - =============== - */ + * =============== CL_RunDLights + * + * =============== + */ static void RunDLights() { cdlight_t dl; - for (int i = 0; i < MAX_DLIGHTS; i++) { + for (int i = 0; i < Defines.MAX_DLIGHTS; i++) { dl = cl_dlights[i]; if (dl.radius == 0.0f) continue; - if (dl.die < cl.time) { + if (dl.die < Globals.cl.time) { dl.radius = 0.0f; return; } @@ -258,37 +268,35 @@ public class CL_fx extends CL_tent { } /* - ============== - CL_ParseMuzzleFlash - ============== - */ + * ============== CL_ParseMuzzleFlash ============== + */ static void ParseMuzzleFlash() { float[] fv = new float[3]; float[] rv = new float[3]; float volume; String soundname; - int i = MSG.ReadShort(net_message); - if (i < 1 || i >= MAX_EDICTS) - Com.Error(ERR_DROP, "CL_ParseMuzzleFlash: bad entity"); + int i = MSG.ReadShort(Globals.net_message); + if (i < 1 || i >= Defines.MAX_EDICTS) + Com.Error(Defines.ERR_DROP, "CL_ParseMuzzleFlash: bad entity"); - int weapon = MSG.ReadByte(net_message); - int silenced = weapon & MZ_SILENCED; - weapon &= ~MZ_SILENCED; + int weapon = MSG.ReadByte(Globals.net_message); + int silenced = weapon & Defines.MZ_SILENCED; + weapon &= ~Defines.MZ_SILENCED; - centity_t pl = cl_entities[i]; + centity_t pl = Globals.cl_entities[i]; - cdlight_t dl = CL.AllocDlight(i); - VectorCopy(pl.current.origin, dl.origin); - AngleVectors(pl.current.angles, fv, rv, null); - VectorMA(dl.origin, 18, fv, dl.origin); - VectorMA(dl.origin, 16, rv, dl.origin); + cdlight_t dl = AllocDlight(i); + Math3D.VectorCopy(pl.current.origin, dl.origin); + Math3D.AngleVectors(pl.current.angles, fv, rv, null); + Math3D.VectorMA(dl.origin, 18, fv, dl.origin); + Math3D.VectorMA(dl.origin, 16, rv, dl.origin); if (silenced != 0) - dl.radius = 100 + (rnd.nextInt() & 31); + dl.radius = 100 + (Globals.rnd.nextInt() & 31); else - dl.radius = 200 + (rnd.nextInt() & 31); + dl.radius = 200 + (Globals.rnd.nextInt() & 31); dl.minlight = 32; - dl.die = cl.time; // + 0.1; + dl.die = Globals.cl.time; // + 0.1; if (silenced != 0) volume = 0.2f; @@ -296,682 +304,682 @@ public class CL_fx extends CL_tent { volume = 1; switch (weapon) { - case MZ_BLASTER : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0); - break; - case MZ_BLUEHYPERBLASTER : - dl.color[0] = 0; - dl.color[1] = 0; - dl.color[2] = 1; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0); - break; - case MZ_HYPERBLASTER : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0); - break; - case MZ_MACHINEGUN : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); - soundname = "weapons/machgf" + ((rnd.nextInt(5)) + 1) + "b.wav"; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0); - break; - case MZ_SHOTGUN : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0); - S.StartSound(null, i, CHAN_AUTO, S.RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1f); - break; - case MZ_SSHOTGUN : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0); - break; - case MZ_CHAINGUN1 : - dl.radius = 200 + (rnd.nextInt() & 31); - dl.color[0] = 1; - dl.color[1] = 0.25f; - dl.color[2] = 0; - //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); - soundname = "weapons/machgf" + ((rnd.nextInt(5)) + 1) + "b.wav"; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0); - break; - case MZ_CHAINGUN2 : - dl.radius = 225 + (rnd.nextInt() & 31); - dl.color[0] = 1; - dl.color[1] = 0.5f; - dl.color[2] = 0; - dl.die = cl.time + 0.1f; // long delay - //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); - soundname = "weapons/machgf" + ((rnd.nextInt(5)) + 1) + "b.wav"; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0); - //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); - soundname = "weapons/machgf" + ((rnd.nextInt(5)) + 1) + "b.wav"; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0.05f); - break; - case MZ_CHAINGUN3 : - dl.radius = 250 + (rnd.nextInt() & 31); - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - dl.die = cl.time + 0.1f; // long delay - //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); - soundname = "weapons/machgf" + ((rnd.nextInt(5)) + 1) + "b.wav"; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0); - //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); - soundname = "weapons/machgf" + ((rnd.nextInt(5)) + 1) + "b.wav"; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0.033f); - //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); - soundname = "weapons/machgf" + ((rnd.nextInt(5)) + 1) + "b.wav"; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0.066f); - break; - case MZ_RAILGUN : - dl.color[0] = 0.5f; - dl.color[1] = 0.5f; - dl.color[2] = 1.0f; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0); - break; - case MZ_ROCKET : - dl.color[0] = 1; - dl.color[1] = 0.5f; - dl.color[2] = 0.2f; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0); - S.StartSound(null, i, CHAN_AUTO, S.RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1f); - break; - case MZ_GRENADE : - dl.color[0] = 1; - dl.color[1] = 0.5f; - dl.color[2] = 0; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0); - S.StartSound(null, i, CHAN_AUTO, S.RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1f); - break; - case MZ_BFG : - dl.color[0] = 0; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0); - break; - - case MZ_LOGIN : - dl.color[0] = 0; - dl.color[1] = 1; - dl.color[2] = 0; - dl.die = cl.time + 1.0f; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0); - CL.LogoutEffect(pl.current.origin, weapon); - break; - case MZ_LOGOUT : - dl.color[0] = 1; - dl.color[1] = 0; - dl.color[2] = 0; - dl.die = cl.time + 1.0f; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0); - CL.LogoutEffect(pl.current.origin, weapon); - break; - case MZ_RESPAWN : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - dl.die = cl.time + 1.0f; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0); - CL.LogoutEffect(pl.current.origin, weapon); - break; - // RAFAEL - case MZ_PHALANX : - dl.color[0] = 1; - dl.color[1] = 0.5f; - dl.color[2] = 0.5f; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0); - break; - // RAFAEL - case MZ_IONRIPPER : - dl.color[0] = 1; - dl.color[1] = 0.5f; - dl.color[2] = 0.5f; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0); - break; - - // ====================== - // PGM - case MZ_ETF_RIFLE : - dl.color[0] = 0.9f; - dl.color[1] = 0.7f; - dl.color[2] = 0; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0); - break; - case MZ_SHOTGUN2 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0); - break; - case MZ_HEATBEAM : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - dl.die = cl.time + 100; - // S.StartSound (null, i, CHAN_WEAPON, S.RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0); - break; - case MZ_BLASTER2 : - dl.color[0] = 0; - dl.color[1] = 1; - dl.color[2] = 0; - // FIXME - different sound for blaster2 ?? - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0); - break; - case MZ_TRACKER : - // negative flashes handled the same in gl/soft until CL_AddDLights - dl.color[0] = -1; - dl.color[1] = -1; - dl.color[2] = -1; - S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0); - break; - case MZ_NUKE1 : - dl.color[0] = 1; - dl.color[1] = 0; - dl.color[2] = 0; - dl.die = cl.time + 100; - break; - case MZ_NUKE2 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - dl.die = cl.time + 100; - break; - case MZ_NUKE4 : - dl.color[0] = 0; - dl.color[1] = 0; - dl.color[2] = 1; - dl.die = cl.time + 100; - break; - case MZ_NUKE8 : - dl.color[0] = 0; - dl.color[1] = 1; - dl.color[2] = 1; - dl.die = cl.time + 100; - break; - // PGM - // ====================== + case Defines.MZ_BLASTER: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/blastf1a.wav"), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_BLUEHYPERBLASTER: + dl.color[0] = 0; + dl.color[1] = 0; + dl.color[2] = 1; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/hyprbf1a.wav"), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_HYPERBLASTER: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/hyprbf1a.wav"), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_MACHINEGUN: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + //Com_sprintf(soundname, sizeof(soundname), + // "weapons/machgf%ib.wav", (rand() % 5) + 1); + soundname = "weapons/machgf" + ((Globals.rnd.nextInt(5)) + 1) + "b.wav"; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound(soundname), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_SHOTGUN: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/shotgf1b.wav"), volume, Defines.ATTN_NORM, 0); + S.StartSound(null, i, Defines.CHAN_AUTO, S.RegisterSound("weapons/shotgr1b.wav"), volume, Defines.ATTN_NORM, 0.1f); + break; + case Defines.MZ_SSHOTGUN: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/sshotf1b.wav"), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_CHAINGUN1: + dl.radius = 200 + (Globals.rnd.nextInt() & 31); + dl.color[0] = 1; + dl.color[1] = 0.25f; + dl.color[2] = 0; + //Com_sprintf(soundname, sizeof(soundname), + // "weapons/machgf%ib.wav", (rand() % 5) + 1); + soundname = "weapons/machgf" + ((Globals.rnd.nextInt(5)) + 1) + "b.wav"; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound(soundname), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_CHAINGUN2: + dl.radius = 225 + (Globals.rnd.nextInt() & 31); + dl.color[0] = 1; + dl.color[1] = 0.5f; + dl.color[2] = 0; + dl.die = Globals.cl.time + 0.1f; // long delay + //Com_sprintf(soundname, sizeof(soundname), + // "weapons/machgf%ib.wav", (rand() % 5) + 1); + soundname = "weapons/machgf" + ((Globals.rnd.nextInt(5)) + 1) + "b.wav"; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound(soundname), volume, Defines.ATTN_NORM, 0); + //Com_sprintf(soundname, sizeof(soundname), + // "weapons/machgf%ib.wav", (rand() % 5) + 1); + soundname = "weapons/machgf" + ((Globals.rnd.nextInt(5)) + 1) + "b.wav"; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound(soundname), volume, Defines.ATTN_NORM, 0.05f); + break; + case Defines.MZ_CHAINGUN3: + dl.radius = 250 + (Globals.rnd.nextInt() & 31); + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + dl.die = Globals.cl.time + 0.1f; // long delay + //Com_sprintf(soundname, sizeof(soundname), + // "weapons/machgf%ib.wav", (rand() % 5) + 1); + soundname = "weapons/machgf" + ((Globals.rnd.nextInt(5)) + 1) + "b.wav"; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound(soundname), volume, Defines.ATTN_NORM, 0); + //Com_sprintf(soundname, sizeof(soundname), + // "weapons/machgf%ib.wav", (rand() % 5) + 1); + soundname = "weapons/machgf" + ((Globals.rnd.nextInt(5)) + 1) + "b.wav"; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound(soundname), volume, Defines.ATTN_NORM, 0.033f); + //Com_sprintf(soundname, sizeof(soundname), + // "weapons/machgf%ib.wav", (rand() % 5) + 1); + soundname = "weapons/machgf" + ((Globals.rnd.nextInt(5)) + 1) + "b.wav"; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound(soundname), volume, Defines.ATTN_NORM, 0.066f); + break; + case Defines.MZ_RAILGUN: + dl.color[0] = 0.5f; + dl.color[1] = 0.5f; + dl.color[2] = 1.0f; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/railgf1a.wav"), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_ROCKET: + dl.color[0] = 1; + dl.color[1] = 0.5f; + dl.color[2] = 0.2f; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/rocklf1a.wav"), volume, Defines.ATTN_NORM, 0); + S.StartSound(null, i, Defines.CHAN_AUTO, S.RegisterSound("weapons/rocklr1b.wav"), volume, Defines.ATTN_NORM, 0.1f); + break; + case Defines.MZ_GRENADE: + dl.color[0] = 1; + dl.color[1] = 0.5f; + dl.color[2] = 0; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), volume, Defines.ATTN_NORM, 0); + S.StartSound(null, i, Defines.CHAN_AUTO, S.RegisterSound("weapons/grenlr1b.wav"), volume, Defines.ATTN_NORM, 0.1f); + break; + case Defines.MZ_BFG: + dl.color[0] = 0; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/bfg__f1y.wav"), volume, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ_LOGIN: + dl.color[0] = 0; + dl.color[1] = 1; + dl.color[2] = 0; + dl.die = Globals.cl.time + 1.0f; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), 1, Defines.ATTN_NORM, 0); + LogoutEffect(pl.current.origin, weapon); + break; + case Defines.MZ_LOGOUT: + dl.color[0] = 1; + dl.color[1] = 0; + dl.color[2] = 0; + dl.die = Globals.cl.time + 1.0f; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), 1, Defines.ATTN_NORM, 0); + LogoutEffect(pl.current.origin, weapon); + break; + case Defines.MZ_RESPAWN: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + dl.die = Globals.cl.time + 1.0f; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), 1, Defines.ATTN_NORM, 0); + LogoutEffect(pl.current.origin, weapon); + break; + // RAFAEL + case Defines.MZ_PHALANX: + dl.color[0] = 1; + dl.color[1] = 0.5f; + dl.color[2] = 0.5f; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/plasshot.wav"), volume, Defines.ATTN_NORM, 0); + break; + // RAFAEL + case Defines.MZ_IONRIPPER: + dl.color[0] = 1; + dl.color[1] = 0.5f; + dl.color[2] = 0.5f; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/rippfire.wav"), volume, Defines.ATTN_NORM, 0); + break; + + // ====================== + // PGM + case Defines.MZ_ETF_RIFLE: + dl.color[0] = 0.9f; + dl.color[1] = 0.7f; + dl.color[2] = 0; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/nail1.wav"), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_SHOTGUN2: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/shotg2.wav"), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_HEATBEAM: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + dl.die = Globals.cl.time + 100; + // S.StartSound (null, i, CHAN_WEAPON, + // S.RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0); + break; + case Defines.MZ_BLASTER2: + dl.color[0] = 0; + dl.color[1] = 1; + dl.color[2] = 0; + // FIXME - different sound for blaster2 ?? + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/blastf1a.wav"), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_TRACKER: + // negative flashes handled the same in gl/soft until CL_AddDLights + dl.color[0] = -1; + dl.color[1] = -1; + dl.color[2] = -1; + S.StartSound(null, i, Defines.CHAN_WEAPON, S.RegisterSound("weapons/disint2.wav"), volume, Defines.ATTN_NORM, 0); + break; + case Defines.MZ_NUKE1: + dl.color[0] = 1; + dl.color[1] = 0; + dl.color[2] = 0; + dl.die = Globals.cl.time + 100; + break; + case Defines.MZ_NUKE2: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + dl.die = Globals.cl.time + 100; + break; + case Defines.MZ_NUKE4: + dl.color[0] = 0; + dl.color[1] = 0; + dl.color[2] = 1; + dl.die = Globals.cl.time + 100; + break; + case Defines.MZ_NUKE8: + dl.color[0] = 0; + dl.color[1] = 1; + dl.color[2] = 1; + dl.die = Globals.cl.time + 100; + break; + // PGM + // ====================== } } /* - ============== - CL_ParseMuzzleFlash2 - ============== - */ + * ============== CL_ParseMuzzleFlash2 ============== + */ static void ParseMuzzleFlash2() { float[] origin = new float[3]; float[] forward = new float[3]; float[] right = new float[3]; String soundname; - int ent = MSG.ReadShort(net_message); - if (ent < 1 || ent >= MAX_EDICTS) - Com.Error(ERR_DROP, "CL_ParseMuzzleFlash2: bad entity"); + int ent = MSG.ReadShort(Globals.net_message); + if (ent < 1 || ent >= Defines.MAX_EDICTS) + Com.Error(Defines.ERR_DROP, "CL_ParseMuzzleFlash2: bad entity"); - int flash_number = MSG.ReadByte(net_message); + int flash_number = MSG.ReadByte(Globals.net_message); // locate the origin - AngleVectors(cl_entities[ent].current.angles, forward, right, null); - origin[0] = - cl_entities[ent].current.origin[0] - + forward[0] * M_Flash.monster_flash_offset[flash_number][0] - + right[0] * M_Flash.monster_flash_offset[flash_number][1]; - origin[1] = - cl_entities[ent].current.origin[1] - + forward[1] * M_Flash.monster_flash_offset[flash_number][0] - + right[1] * M_Flash.monster_flash_offset[flash_number][1]; - origin[2] = - cl_entities[ent].current.origin[2] - + forward[2] * M_Flash.monster_flash_offset[flash_number][0] - + right[2] * M_Flash.monster_flash_offset[flash_number][1] - + M_Flash.monster_flash_offset[flash_number][2]; - - cdlight_t dl = CL.AllocDlight(ent); - VectorCopy(origin, dl.origin); - dl.radius = 200 + (rnd.nextInt() & 31); + Math3D.AngleVectors(Globals.cl_entities[ent].current.angles, forward, right, null); + origin[0] = Globals.cl_entities[ent].current.origin[0] + forward[0] * M_Flash.monster_flash_offset[flash_number][0] + right[0] + * M_Flash.monster_flash_offset[flash_number][1]; + origin[1] = Globals.cl_entities[ent].current.origin[1] + forward[1] * M_Flash.monster_flash_offset[flash_number][0] + right[1] + * M_Flash.monster_flash_offset[flash_number][1]; + origin[2] = Globals.cl_entities[ent].current.origin[2] + forward[2] * M_Flash.monster_flash_offset[flash_number][0] + right[2] + * M_Flash.monster_flash_offset[flash_number][1] + M_Flash.monster_flash_offset[flash_number][2]; + + cdlight_t dl = AllocDlight(ent); + Math3D.VectorCopy(origin, dl.origin); + dl.radius = 200 + (Globals.rnd.nextInt() & 31); dl.minlight = 32; - dl.die = cl.time; // + 0.1; + dl.die = Globals.cl.time; // + 0.1; switch (flash_number) { - case MZ2_INFANTRY_MACHINEGUN_1 : - case MZ2_INFANTRY_MACHINEGUN_2 : - case MZ2_INFANTRY_MACHINEGUN_3 : - case MZ2_INFANTRY_MACHINEGUN_4 : - case MZ2_INFANTRY_MACHINEGUN_5 : - case MZ2_INFANTRY_MACHINEGUN_6 : - case MZ2_INFANTRY_MACHINEGUN_7 : - case MZ2_INFANTRY_MACHINEGUN_8 : - case MZ2_INFANTRY_MACHINEGUN_9 : - case MZ2_INFANTRY_MACHINEGUN_10 : - case MZ2_INFANTRY_MACHINEGUN_11 : - case MZ2_INFANTRY_MACHINEGUN_12 : - case MZ2_INFANTRY_MACHINEGUN_13 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - CL.ParticleEffect(origin, vec3_origin, 0, 40); - CL.SmokeAndFlash(origin); - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_SOLDIER_MACHINEGUN_1 : - case MZ2_SOLDIER_MACHINEGUN_2 : - case MZ2_SOLDIER_MACHINEGUN_3 : - case MZ2_SOLDIER_MACHINEGUN_4 : - case MZ2_SOLDIER_MACHINEGUN_5 : - case MZ2_SOLDIER_MACHINEGUN_6 : - case MZ2_SOLDIER_MACHINEGUN_7 : - case MZ2_SOLDIER_MACHINEGUN_8 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - CL.ParticleEffect(origin, vec3_origin, 0, 40); - CL.SmokeAndFlash(origin); - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_GUNNER_MACHINEGUN_1 : - case MZ2_GUNNER_MACHINEGUN_2 : - case MZ2_GUNNER_MACHINEGUN_3 : - case MZ2_GUNNER_MACHINEGUN_4 : - case MZ2_GUNNER_MACHINEGUN_5 : - case MZ2_GUNNER_MACHINEGUN_6 : - case MZ2_GUNNER_MACHINEGUN_7 : - case MZ2_GUNNER_MACHINEGUN_8 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - CL.ParticleEffect(origin, vec3_origin, 0, 40); - CL.SmokeAndFlash(origin); - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_ACTOR_MACHINEGUN_1 : - case MZ2_SUPERTANK_MACHINEGUN_1 : - case MZ2_SUPERTANK_MACHINEGUN_2 : - case MZ2_SUPERTANK_MACHINEGUN_3 : - case MZ2_SUPERTANK_MACHINEGUN_4 : - case MZ2_SUPERTANK_MACHINEGUN_5 : - case MZ2_SUPERTANK_MACHINEGUN_6 : - case MZ2_TURRET_MACHINEGUN : // PGM - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - - CL.ParticleEffect(origin, vec3_origin, 0, 40); - CL.SmokeAndFlash(origin); - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_BOSS2_MACHINEGUN_L1 : - case MZ2_BOSS2_MACHINEGUN_L2 : - case MZ2_BOSS2_MACHINEGUN_L3 : - case MZ2_BOSS2_MACHINEGUN_L4 : - case MZ2_BOSS2_MACHINEGUN_L5 : - case MZ2_CARRIER_MACHINEGUN_L1 : // PMM - case MZ2_CARRIER_MACHINEGUN_L2 : // PMM - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - - CL.ParticleEffect(origin, vec3_origin, 0, 40); - CL.SmokeAndFlash(origin); - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0); - break; - - case MZ2_SOLDIER_BLASTER_1 : - case MZ2_SOLDIER_BLASTER_2 : - case MZ2_SOLDIER_BLASTER_3 : - case MZ2_SOLDIER_BLASTER_4 : - case MZ2_SOLDIER_BLASTER_5 : - case MZ2_SOLDIER_BLASTER_6 : - case MZ2_SOLDIER_BLASTER_7 : - case MZ2_SOLDIER_BLASTER_8 : - case MZ2_TURRET_BLASTER : // PGM - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_FLYER_BLASTER_1 : - case MZ2_FLYER_BLASTER_2 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_MEDIC_BLASTER_1 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_HOVER_BLASTER_1 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_FLOAT_BLASTER_1 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_SOLDIER_SHOTGUN_1 : - case MZ2_SOLDIER_SHOTGUN_2 : - case MZ2_SOLDIER_SHOTGUN_3 : - case MZ2_SOLDIER_SHOTGUN_4 : - case MZ2_SOLDIER_SHOTGUN_5 : - case MZ2_SOLDIER_SHOTGUN_6 : - case MZ2_SOLDIER_SHOTGUN_7 : - case MZ2_SOLDIER_SHOTGUN_8 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - CL.SmokeAndFlash(origin); - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_TANK_BLASTER_1 : - case MZ2_TANK_BLASTER_2 : - case MZ2_TANK_BLASTER_3 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_TANK_MACHINEGUN_1 : - case MZ2_TANK_MACHINEGUN_2 : - case MZ2_TANK_MACHINEGUN_3 : - case MZ2_TANK_MACHINEGUN_4 : - case MZ2_TANK_MACHINEGUN_5 : - case MZ2_TANK_MACHINEGUN_6 : - case MZ2_TANK_MACHINEGUN_7 : - case MZ2_TANK_MACHINEGUN_8 : - case MZ2_TANK_MACHINEGUN_9 : - case MZ2_TANK_MACHINEGUN_10 : - case MZ2_TANK_MACHINEGUN_11 : - case MZ2_TANK_MACHINEGUN_12 : - case MZ2_TANK_MACHINEGUN_13 : - case MZ2_TANK_MACHINEGUN_14 : - case MZ2_TANK_MACHINEGUN_15 : - case MZ2_TANK_MACHINEGUN_16 : - case MZ2_TANK_MACHINEGUN_17 : - case MZ2_TANK_MACHINEGUN_18 : - case MZ2_TANK_MACHINEGUN_19 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - CL.ParticleEffect(origin, vec3_origin, 0, 40); - CL.SmokeAndFlash(origin); - //Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5); - soundname = "tank/tnkatk2" + (char) ('a' + rnd.nextInt(5)) + ".wav"; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound(soundname), 1, ATTN_NORM, 0); - break; - - case MZ2_CHICK_ROCKET_1 : - case MZ2_TURRET_ROCKET : // PGM - dl.color[0] = 1; - dl.color[1] = 0.5f; - dl.color[2] = 0.2f; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_TANK_ROCKET_1 : - case MZ2_TANK_ROCKET_2 : - case MZ2_TANK_ROCKET_3 : - dl.color[0] = 1; - dl.color[1] = 0.5f; - dl.color[2] = 0.2f; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_SUPERTANK_ROCKET_1 : - case MZ2_SUPERTANK_ROCKET_2 : - case MZ2_SUPERTANK_ROCKET_3 : - case MZ2_BOSS2_ROCKET_1 : - case MZ2_BOSS2_ROCKET_2 : - case MZ2_BOSS2_ROCKET_3 : - case MZ2_BOSS2_ROCKET_4 : - case MZ2_CARRIER_ROCKET_1 : - // case MZ2_CARRIER_ROCKET_2: - // case MZ2_CARRIER_ROCKET_3: - // case MZ2_CARRIER_ROCKET_4: - dl.color[0] = 1; - dl.color[1] = 0.5f; - dl.color[2] = 0.2f; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_GUNNER_GRENADE_1 : - case MZ2_GUNNER_GRENADE_2 : - case MZ2_GUNNER_GRENADE_3 : - case MZ2_GUNNER_GRENADE_4 : - dl.color[0] = 1; - dl.color[1] = 0.5f; - dl.color[2] = 0; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_GLADIATOR_RAILGUN_1 : - // PMM - case MZ2_CARRIER_RAILGUN : - case MZ2_WIDOW_RAIL : - // pmm - dl.color[0] = 0.5f; - dl.color[1] = 0.5f; - dl.color[2] = 1.0f; - break; - - // --- Xian's shit starts --- - case MZ2_MAKRON_BFG : - dl.color[0] = 0.5f; - dl.color[1] = 1; - dl.color[2] = 0.5f; - //S.StartSound (null, ent, CHAN_WEAPON, S.RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_MAKRON_BLASTER_1 : - case MZ2_MAKRON_BLASTER_2 : - case MZ2_MAKRON_BLASTER_3 : - case MZ2_MAKRON_BLASTER_4 : - case MZ2_MAKRON_BLASTER_5 : - case MZ2_MAKRON_BLASTER_6 : - case MZ2_MAKRON_BLASTER_7 : - case MZ2_MAKRON_BLASTER_8 : - case MZ2_MAKRON_BLASTER_9 : - case MZ2_MAKRON_BLASTER_10 : - case MZ2_MAKRON_BLASTER_11 : - case MZ2_MAKRON_BLASTER_12 : - case MZ2_MAKRON_BLASTER_13 : - case MZ2_MAKRON_BLASTER_14 : - case MZ2_MAKRON_BLASTER_15 : - case MZ2_MAKRON_BLASTER_16 : - case MZ2_MAKRON_BLASTER_17 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_JORG_MACHINEGUN_L1 : - case MZ2_JORG_MACHINEGUN_L2 : - case MZ2_JORG_MACHINEGUN_L3 : - case MZ2_JORG_MACHINEGUN_L4 : - case MZ2_JORG_MACHINEGUN_L5 : - case MZ2_JORG_MACHINEGUN_L6 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - CL.ParticleEffect(origin, vec3_origin, 0, 40); - CL.SmokeAndFlash(origin); - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_JORG_MACHINEGUN_R1 : - case MZ2_JORG_MACHINEGUN_R2 : - case MZ2_JORG_MACHINEGUN_R3 : - case MZ2_JORG_MACHINEGUN_R4 : - case MZ2_JORG_MACHINEGUN_R5 : - case MZ2_JORG_MACHINEGUN_R6 : - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - CL.ParticleEffect(origin, vec3_origin, 0, 40); - CL.SmokeAndFlash(origin); - break; - - case MZ2_JORG_BFG_1 : - dl.color[0] = 0.5f; - dl.color[1] = 1; - dl.color[2] = 0.5f; - break; - - case MZ2_BOSS2_MACHINEGUN_R1 : - case MZ2_BOSS2_MACHINEGUN_R2 : - case MZ2_BOSS2_MACHINEGUN_R3 : - case MZ2_BOSS2_MACHINEGUN_R4 : - case MZ2_BOSS2_MACHINEGUN_R5 : - case MZ2_CARRIER_MACHINEGUN_R1 : // PMM - case MZ2_CARRIER_MACHINEGUN_R2 : // PMM - - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - - CL.ParticleEffect(origin, vec3_origin, 0, 40); - CL.SmokeAndFlash(origin); - break; - - // ====== - // ROGUE - case MZ2_STALKER_BLASTER : - case MZ2_DAEDALUS_BLASTER : - case MZ2_MEDIC_BLASTER_2 : - case MZ2_WIDOW_BLASTER : - case MZ2_WIDOW_BLASTER_SWEEP1 : - case MZ2_WIDOW_BLASTER_SWEEP2 : - case MZ2_WIDOW_BLASTER_SWEEP3 : - case MZ2_WIDOW_BLASTER_SWEEP4 : - case MZ2_WIDOW_BLASTER_SWEEP5 : - case MZ2_WIDOW_BLASTER_SWEEP6 : - case MZ2_WIDOW_BLASTER_SWEEP7 : - case MZ2_WIDOW_BLASTER_SWEEP8 : - case MZ2_WIDOW_BLASTER_SWEEP9 : - case MZ2_WIDOW_BLASTER_100 : - case MZ2_WIDOW_BLASTER_90 : - case MZ2_WIDOW_BLASTER_80 : - case MZ2_WIDOW_BLASTER_70 : - case MZ2_WIDOW_BLASTER_60 : - case MZ2_WIDOW_BLASTER_50 : - case MZ2_WIDOW_BLASTER_40 : - case MZ2_WIDOW_BLASTER_30 : - case MZ2_WIDOW_BLASTER_20 : - case MZ2_WIDOW_BLASTER_10 : - case MZ2_WIDOW_BLASTER_0 : - case MZ2_WIDOW_BLASTER_10L : - case MZ2_WIDOW_BLASTER_20L : - case MZ2_WIDOW_BLASTER_30L : - case MZ2_WIDOW_BLASTER_40L : - case MZ2_WIDOW_BLASTER_50L : - case MZ2_WIDOW_BLASTER_60L : - case MZ2_WIDOW_BLASTER_70L : - case MZ2_WIDOW_RUN_1 : - case MZ2_WIDOW_RUN_2 : - case MZ2_WIDOW_RUN_3 : - case MZ2_WIDOW_RUN_4 : - case MZ2_WIDOW_RUN_5 : - case MZ2_WIDOW_RUN_6 : - case MZ2_WIDOW_RUN_7 : - case MZ2_WIDOW_RUN_8 : - dl.color[0] = 0; - dl.color[1] = 1; - dl.color[2] = 0; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_WIDOW_DISRUPTOR : - dl.color[0] = -1; - dl.color[1] = -1; - dl.color[2] = -1; - S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0); - break; - - case MZ2_WIDOW_PLASMABEAM : - case MZ2_WIDOW2_BEAMER_1 : - case MZ2_WIDOW2_BEAMER_2 : - case MZ2_WIDOW2_BEAMER_3 : - case MZ2_WIDOW2_BEAMER_4 : - case MZ2_WIDOW2_BEAMER_5 : - case MZ2_WIDOW2_BEAM_SWEEP_1 : - case MZ2_WIDOW2_BEAM_SWEEP_2 : - case MZ2_WIDOW2_BEAM_SWEEP_3 : - case MZ2_WIDOW2_BEAM_SWEEP_4 : - case MZ2_WIDOW2_BEAM_SWEEP_5 : - case MZ2_WIDOW2_BEAM_SWEEP_6 : - case MZ2_WIDOW2_BEAM_SWEEP_7 : - case MZ2_WIDOW2_BEAM_SWEEP_8 : - case MZ2_WIDOW2_BEAM_SWEEP_9 : - case MZ2_WIDOW2_BEAM_SWEEP_10 : - case MZ2_WIDOW2_BEAM_SWEEP_11 : - dl.radius = 300 + (rnd.nextInt() & 100); - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 0; - dl.die = cl.time + 200; - break; - // ROGUE - // ====== - - // --- Xian's shit ends --- + case Defines.MZ2_INFANTRY_MACHINEGUN_1: + case Defines.MZ2_INFANTRY_MACHINEGUN_2: + case Defines.MZ2_INFANTRY_MACHINEGUN_3: + case Defines.MZ2_INFANTRY_MACHINEGUN_4: + case Defines.MZ2_INFANTRY_MACHINEGUN_5: + case Defines.MZ2_INFANTRY_MACHINEGUN_6: + case Defines.MZ2_INFANTRY_MACHINEGUN_7: + case Defines.MZ2_INFANTRY_MACHINEGUN_8: + case Defines.MZ2_INFANTRY_MACHINEGUN_9: + case Defines.MZ2_INFANTRY_MACHINEGUN_10: + case Defines.MZ2_INFANTRY_MACHINEGUN_11: + case Defines.MZ2_INFANTRY_MACHINEGUN_12: + case Defines.MZ2_INFANTRY_MACHINEGUN_13: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + ParticleEffect(origin, Globals.vec3_origin, 0, 40); + CL_tent.SmokeAndFlash(origin); + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("infantry/infatck1.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_SOLDIER_MACHINEGUN_1: + case Defines.MZ2_SOLDIER_MACHINEGUN_2: + case Defines.MZ2_SOLDIER_MACHINEGUN_3: + case Defines.MZ2_SOLDIER_MACHINEGUN_4: + case Defines.MZ2_SOLDIER_MACHINEGUN_5: + case Defines.MZ2_SOLDIER_MACHINEGUN_6: + case Defines.MZ2_SOLDIER_MACHINEGUN_7: + case Defines.MZ2_SOLDIER_MACHINEGUN_8: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + ParticleEffect(origin, Globals.vec3_origin, 0, 40); + CL_tent.SmokeAndFlash(origin); + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("soldier/solatck3.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_GUNNER_MACHINEGUN_1: + case Defines.MZ2_GUNNER_MACHINEGUN_2: + case Defines.MZ2_GUNNER_MACHINEGUN_3: + case Defines.MZ2_GUNNER_MACHINEGUN_4: + case Defines.MZ2_GUNNER_MACHINEGUN_5: + case Defines.MZ2_GUNNER_MACHINEGUN_6: + case Defines.MZ2_GUNNER_MACHINEGUN_7: + case Defines.MZ2_GUNNER_MACHINEGUN_8: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + ParticleEffect(origin, Globals.vec3_origin, 0, 40); + CL_tent.SmokeAndFlash(origin); + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("gunner/gunatck2.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_ACTOR_MACHINEGUN_1: + case Defines.MZ2_SUPERTANK_MACHINEGUN_1: + case Defines.MZ2_SUPERTANK_MACHINEGUN_2: + case Defines.MZ2_SUPERTANK_MACHINEGUN_3: + case Defines.MZ2_SUPERTANK_MACHINEGUN_4: + case Defines.MZ2_SUPERTANK_MACHINEGUN_5: + case Defines.MZ2_SUPERTANK_MACHINEGUN_6: + case Defines.MZ2_TURRET_MACHINEGUN: // PGM + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + + ParticleEffect(origin, Globals.vec3_origin, 0, 40); + CL_tent.SmokeAndFlash(origin); + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("infantry/infatck1.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_BOSS2_MACHINEGUN_L1: + case Defines.MZ2_BOSS2_MACHINEGUN_L2: + case Defines.MZ2_BOSS2_MACHINEGUN_L3: + case Defines.MZ2_BOSS2_MACHINEGUN_L4: + case Defines.MZ2_BOSS2_MACHINEGUN_L5: + case Defines.MZ2_CARRIER_MACHINEGUN_L1: // PMM + case Defines.MZ2_CARRIER_MACHINEGUN_L2: // PMM + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + + ParticleEffect(origin, Globals.vec3_origin, 0, 40); + CL_tent.SmokeAndFlash(origin); + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("infantry/infatck1.wav"), 1, Defines.ATTN_NONE, 0); + break; + + case Defines.MZ2_SOLDIER_BLASTER_1: + case Defines.MZ2_SOLDIER_BLASTER_2: + case Defines.MZ2_SOLDIER_BLASTER_3: + case Defines.MZ2_SOLDIER_BLASTER_4: + case Defines.MZ2_SOLDIER_BLASTER_5: + case Defines.MZ2_SOLDIER_BLASTER_6: + case Defines.MZ2_SOLDIER_BLASTER_7: + case Defines.MZ2_SOLDIER_BLASTER_8: + case Defines.MZ2_TURRET_BLASTER: // PGM + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("soldier/solatck2.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_FLYER_BLASTER_1: + case Defines.MZ2_FLYER_BLASTER_2: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("flyer/flyatck3.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_MEDIC_BLASTER_1: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("medic/medatck1.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_HOVER_BLASTER_1: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("hover/hovatck1.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_FLOAT_BLASTER_1: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("floater/fltatck1.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_SOLDIER_SHOTGUN_1: + case Defines.MZ2_SOLDIER_SHOTGUN_2: + case Defines.MZ2_SOLDIER_SHOTGUN_3: + case Defines.MZ2_SOLDIER_SHOTGUN_4: + case Defines.MZ2_SOLDIER_SHOTGUN_5: + case Defines.MZ2_SOLDIER_SHOTGUN_6: + case Defines.MZ2_SOLDIER_SHOTGUN_7: + case Defines.MZ2_SOLDIER_SHOTGUN_8: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + CL_tent.SmokeAndFlash(origin); + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("soldier/solatck1.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_TANK_BLASTER_1: + case Defines.MZ2_TANK_BLASTER_2: + case Defines.MZ2_TANK_BLASTER_3: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("tank/tnkatck3.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_TANK_MACHINEGUN_1: + case Defines.MZ2_TANK_MACHINEGUN_2: + case Defines.MZ2_TANK_MACHINEGUN_3: + case Defines.MZ2_TANK_MACHINEGUN_4: + case Defines.MZ2_TANK_MACHINEGUN_5: + case Defines.MZ2_TANK_MACHINEGUN_6: + case Defines.MZ2_TANK_MACHINEGUN_7: + case Defines.MZ2_TANK_MACHINEGUN_8: + case Defines.MZ2_TANK_MACHINEGUN_9: + case Defines.MZ2_TANK_MACHINEGUN_10: + case Defines.MZ2_TANK_MACHINEGUN_11: + case Defines.MZ2_TANK_MACHINEGUN_12: + case Defines.MZ2_TANK_MACHINEGUN_13: + case Defines.MZ2_TANK_MACHINEGUN_14: + case Defines.MZ2_TANK_MACHINEGUN_15: + case Defines.MZ2_TANK_MACHINEGUN_16: + case Defines.MZ2_TANK_MACHINEGUN_17: + case Defines.MZ2_TANK_MACHINEGUN_18: + case Defines.MZ2_TANK_MACHINEGUN_19: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + ParticleEffect(origin, Globals.vec3_origin, 0, 40); + CL_tent.SmokeAndFlash(origin); + //Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", + // 'a' + rand() % 5); + soundname = "tank/tnkatk2" + (char) ('a' + Globals.rnd.nextInt(5)) + ".wav"; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound(soundname), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_CHICK_ROCKET_1: + case Defines.MZ2_TURRET_ROCKET: // PGM + dl.color[0] = 1; + dl.color[1] = 0.5f; + dl.color[2] = 0.2f; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("chick/chkatck2.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_TANK_ROCKET_1: + case Defines.MZ2_TANK_ROCKET_2: + case Defines.MZ2_TANK_ROCKET_3: + dl.color[0] = 1; + dl.color[1] = 0.5f; + dl.color[2] = 0.2f; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("tank/tnkatck1.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_SUPERTANK_ROCKET_1: + case Defines.MZ2_SUPERTANK_ROCKET_2: + case Defines.MZ2_SUPERTANK_ROCKET_3: + case Defines.MZ2_BOSS2_ROCKET_1: + case Defines.MZ2_BOSS2_ROCKET_2: + case Defines.MZ2_BOSS2_ROCKET_3: + case Defines.MZ2_BOSS2_ROCKET_4: + case Defines.MZ2_CARRIER_ROCKET_1: + // case MZ2_CARRIER_ROCKET_2: + // case MZ2_CARRIER_ROCKET_3: + // case MZ2_CARRIER_ROCKET_4: + dl.color[0] = 1; + dl.color[1] = 0.5f; + dl.color[2] = 0.2f; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("tank/rocket.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_GUNNER_GRENADE_1: + case Defines.MZ2_GUNNER_GRENADE_2: + case Defines.MZ2_GUNNER_GRENADE_3: + case Defines.MZ2_GUNNER_GRENADE_4: + dl.color[0] = 1; + dl.color[1] = 0.5f; + dl.color[2] = 0; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("gunner/gunatck3.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_GLADIATOR_RAILGUN_1: + // PMM + case Defines.MZ2_CARRIER_RAILGUN: + case Defines.MZ2_WIDOW_RAIL: + // pmm + dl.color[0] = 0.5f; + dl.color[1] = 0.5f; + dl.color[2] = 1.0f; + break; + + // --- Xian's shit starts --- + case Defines.MZ2_MAKRON_BFG: + dl.color[0] = 0.5f; + dl.color[1] = 1; + dl.color[2] = 0.5f; + //S.StartSound (null, ent, CHAN_WEAPON, + // S.RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0); + break; + + case Defines.MZ2_MAKRON_BLASTER_1: + case Defines.MZ2_MAKRON_BLASTER_2: + case Defines.MZ2_MAKRON_BLASTER_3: + case Defines.MZ2_MAKRON_BLASTER_4: + case Defines.MZ2_MAKRON_BLASTER_5: + case Defines.MZ2_MAKRON_BLASTER_6: + case Defines.MZ2_MAKRON_BLASTER_7: + case Defines.MZ2_MAKRON_BLASTER_8: + case Defines.MZ2_MAKRON_BLASTER_9: + case Defines.MZ2_MAKRON_BLASTER_10: + case Defines.MZ2_MAKRON_BLASTER_11: + case Defines.MZ2_MAKRON_BLASTER_12: + case Defines.MZ2_MAKRON_BLASTER_13: + case Defines.MZ2_MAKRON_BLASTER_14: + case Defines.MZ2_MAKRON_BLASTER_15: + case Defines.MZ2_MAKRON_BLASTER_16: + case Defines.MZ2_MAKRON_BLASTER_17: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("makron/blaster.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_JORG_MACHINEGUN_L1: + case Defines.MZ2_JORG_MACHINEGUN_L2: + case Defines.MZ2_JORG_MACHINEGUN_L3: + case Defines.MZ2_JORG_MACHINEGUN_L4: + case Defines.MZ2_JORG_MACHINEGUN_L5: + case Defines.MZ2_JORG_MACHINEGUN_L6: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + ParticleEffect(origin, Globals.vec3_origin, 0, 40); + CL_tent.SmokeAndFlash(origin); + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("boss3/xfire.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_JORG_MACHINEGUN_R1: + case Defines.MZ2_JORG_MACHINEGUN_R2: + case Defines.MZ2_JORG_MACHINEGUN_R3: + case Defines.MZ2_JORG_MACHINEGUN_R4: + case Defines.MZ2_JORG_MACHINEGUN_R5: + case Defines.MZ2_JORG_MACHINEGUN_R6: + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + ParticleEffect(origin, Globals.vec3_origin, 0, 40); + CL_tent.SmokeAndFlash(origin); + break; + + case Defines.MZ2_JORG_BFG_1: + dl.color[0] = 0.5f; + dl.color[1] = 1; + dl.color[2] = 0.5f; + break; + + case Defines.MZ2_BOSS2_MACHINEGUN_R1: + case Defines.MZ2_BOSS2_MACHINEGUN_R2: + case Defines.MZ2_BOSS2_MACHINEGUN_R3: + case Defines.MZ2_BOSS2_MACHINEGUN_R4: + case Defines.MZ2_BOSS2_MACHINEGUN_R5: + case Defines.MZ2_CARRIER_MACHINEGUN_R1: // PMM + case Defines.MZ2_CARRIER_MACHINEGUN_R2: // PMM + + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + + ParticleEffect(origin, Globals.vec3_origin, 0, 40); + CL_tent.SmokeAndFlash(origin); + break; + + // ====== + // ROGUE + case Defines.MZ2_STALKER_BLASTER: + case Defines.MZ2_DAEDALUS_BLASTER: + case Defines.MZ2_MEDIC_BLASTER_2: + case Defines.MZ2_WIDOW_BLASTER: + case Defines.MZ2_WIDOW_BLASTER_SWEEP1: + case Defines.MZ2_WIDOW_BLASTER_SWEEP2: + case Defines.MZ2_WIDOW_BLASTER_SWEEP3: + case Defines.MZ2_WIDOW_BLASTER_SWEEP4: + case Defines.MZ2_WIDOW_BLASTER_SWEEP5: + case Defines.MZ2_WIDOW_BLASTER_SWEEP6: + case Defines.MZ2_WIDOW_BLASTER_SWEEP7: + case Defines.MZ2_WIDOW_BLASTER_SWEEP8: + case Defines.MZ2_WIDOW_BLASTER_SWEEP9: + case Defines.MZ2_WIDOW_BLASTER_100: + case Defines.MZ2_WIDOW_BLASTER_90: + case Defines.MZ2_WIDOW_BLASTER_80: + case Defines.MZ2_WIDOW_BLASTER_70: + case Defines.MZ2_WIDOW_BLASTER_60: + case Defines.MZ2_WIDOW_BLASTER_50: + case Defines.MZ2_WIDOW_BLASTER_40: + case Defines.MZ2_WIDOW_BLASTER_30: + case Defines.MZ2_WIDOW_BLASTER_20: + case Defines.MZ2_WIDOW_BLASTER_10: + case Defines.MZ2_WIDOW_BLASTER_0: + case Defines.MZ2_WIDOW_BLASTER_10L: + case Defines.MZ2_WIDOW_BLASTER_20L: + case Defines.MZ2_WIDOW_BLASTER_30L: + case Defines.MZ2_WIDOW_BLASTER_40L: + case Defines.MZ2_WIDOW_BLASTER_50L: + case Defines.MZ2_WIDOW_BLASTER_60L: + case Defines.MZ2_WIDOW_BLASTER_70L: + case Defines.MZ2_WIDOW_RUN_1: + case Defines.MZ2_WIDOW_RUN_2: + case Defines.MZ2_WIDOW_RUN_3: + case Defines.MZ2_WIDOW_RUN_4: + case Defines.MZ2_WIDOW_RUN_5: + case Defines.MZ2_WIDOW_RUN_6: + case Defines.MZ2_WIDOW_RUN_7: + case Defines.MZ2_WIDOW_RUN_8: + dl.color[0] = 0; + dl.color[1] = 1; + dl.color[2] = 0; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("tank/tnkatck3.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_WIDOW_DISRUPTOR: + dl.color[0] = -1; + dl.color[1] = -1; + dl.color[2] = -1; + S.StartSound(null, ent, Defines.CHAN_WEAPON, S.RegisterSound("weapons/disint2.wav"), 1, Defines.ATTN_NORM, 0); + break; + + case Defines.MZ2_WIDOW_PLASMABEAM: + case Defines.MZ2_WIDOW2_BEAMER_1: + case Defines.MZ2_WIDOW2_BEAMER_2: + case Defines.MZ2_WIDOW2_BEAMER_3: + case Defines.MZ2_WIDOW2_BEAMER_4: + case Defines.MZ2_WIDOW2_BEAMER_5: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_1: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_2: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_3: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_4: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_5: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_6: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_7: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_8: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_9: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_10: + case Defines.MZ2_WIDOW2_BEAM_SWEEP_11: + dl.radius = 300 + (Globals.rnd.nextInt() & 100); + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 0; + dl.die = Globals.cl.time + 200; + break; + // ROGUE + // ====== + + // --- Xian's shit ends --- } } /* - =============== - CL_AddDLights - - =============== - */ + * =============== CL_AddDLights + * + * =============== + */ static void AddDLights() { cdlight_t dl; // ===== // PGM - if (vidref_val == VIDREF_GL) { - for (int i = 0; i < MAX_DLIGHTS; i++) { + if (Globals.vidref_val == Defines.VIDREF_GL) { + for (int i = 0; i < Defines.MAX_DLIGHTS; i++) { dl = cl_dlights[i]; if (dl.radius == 0.0f) continue; V.AddLight(dl.origin, dl.radius, dl.color[0], dl.color[1], dl.color[2]); } } else { - for (int i = 0; i < MAX_DLIGHTS; i++) { + for (int i = 0; i < Defines.MAX_DLIGHTS; i++) { dl = cl_dlights[i]; if (dl.radius == 0.0f) continue; // negative light in software. only black allowed if ((dl.color[0] < 0) || (dl.color[1] < 0) || (dl.color[2] < 0)) { - dl.radius = - (dl.radius); + dl.radius = -(dl.radius); dl.color[0] = 1; dl.color[1] = 1; dl.color[2] = 1; @@ -984,47 +992,24 @@ public class CL_fx extends CL_tent { } /* - ============================================================== - - PARTICLE MANAGEMENT - - ============================================================== - */ - - static final int PARTICLE_GRAVITY = 40; - static cparticle_t active_particles, free_particles; - - static cparticle_t[] particles = new cparticle_t[MAX_PARTICLES]; - static { - for (int i = 0; i < particles.length; i++) - particles[i] = new cparticle_t(); - } - static int cl_numparticles = MAX_PARTICLES; + * =============== CL_ClearParticles =============== + */ + static void ClearParticles() { + int i; - /* - =============== - CL_ClearParticles - =============== - */ - static void ClearParticles() - { - int i; - free_particles = particles[0]; active_particles = null; - for (i=0 ; i 0) { @@ -1386,29 +1352,28 @@ public class CL_fx extends CL_tent { free_particles = p.next; p.next = active_particles; active_particles = p; - VectorClear(p.accel); + Math3D.VectorClear(p.accel); - p.time = cl.time; + p.time = Globals.cl.time; p.alpha = 1.0f; p.alphavel = -1.0f / (0.3f + Globals.rnd.nextFloat() * 0.2f); p.color = 0xe0; for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand(); - p.vel[j] = crand() * 5; + p.org[j] = move[j] + Lib.crand(); + p.vel[j] = Lib.crand() * 5; p.accel[j] = 0; } - VectorAdd(move, vec, move); + Math3D.VectorAdd(move, vec, move); } } /* - =============== - CL_QuadTrail - - =============== - */ + * =============== CL_QuadTrail + * + * =============== + */ static void QuadTrail(float[] start, float[] end) { float[] move = new float[3]; float[] vec = new float[3]; @@ -1417,12 +1382,12 @@ public class CL_fx extends CL_tent { cparticle_t p; int dec; - VectorCopy(start, move); - VectorSubtract(end, start, vec); - len = VectorNormalize(vec); + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); dec = 5; - VectorScale(vec, 5, vec); + Math3D.VectorScale(vec, 5, vec); while (len > 0) { len -= dec; @@ -1433,29 +1398,28 @@ public class CL_fx extends CL_tent { free_particles = p.next; p.next = active_particles; active_particles = p; - VectorClear(p.accel); + Math3D.VectorClear(p.accel); - p.time = cl.time; + p.time = Globals.cl.time; p.alpha = 1.0f; p.alphavel = -1.0f / (0.8f + Globals.rnd.nextFloat() * 0.2f); p.color = 115; for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * 16; - p.vel[j] = crand() * 5; + p.org[j] = move[j] + Lib.crand() * 16; + p.vel[j] = Lib.crand() * 5; p.accel[j] = 0; } - VectorAdd(move, vec, move); + Math3D.VectorAdd(move, vec, move); } } /* - =============== - CL_FlagTrail - - =============== - */ + * =============== CL_FlagTrail + * + * =============== + */ static void FlagTrail(float[] start, float[] end, float color) { float[] move = new float[3]; float[] vec = new float[3]; @@ -1464,12 +1428,12 @@ public class CL_fx extends CL_tent { cparticle_t p; int dec; - VectorCopy(start, move); - VectorSubtract(end, start, vec); - len = VectorNormalize(vec); + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); dec = 5; - VectorScale(vec, 5, vec); + Math3D.VectorScale(vec, 5, vec); while (len > 0) { len -= dec; @@ -1480,29 +1444,28 @@ public class CL_fx extends CL_tent { free_particles = p.next; p.next = active_particles; active_particles = p; - VectorClear(p.accel); + Math3D.VectorClear(p.accel); - p.time = cl.time; + p.time = Globals.cl.time; p.alpha = 1.0f; p.alphavel = -1.0f / (0.8f + Globals.rnd.nextFloat() * 0.2f); p.color = color; for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * 16; - p.vel[j] = crand() * 5; + p.org[j] = move[j] + Lib.crand() * 16; + p.vel[j] = Lib.crand() * 5; p.accel[j] = 0; } - VectorAdd(move, vec, move); + Math3D.VectorAdd(move, vec, move); } } /* - =============== - CL_DiminishingTrail - - =============== - */ + * =============== CL_DiminishingTrail + * + * =============== + */ static void DiminishingTrail(float[] start, float[] end, centity_t old, int flags) { float[] move = new float[3]; float[] vec = new float[3]; @@ -1510,12 +1473,12 @@ public class CL_fx extends CL_tent { float orgscale; float velscale; - VectorCopy(start, move); - VectorSubtract(end, start, vec); - float len = VectorNormalize(vec); + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + float len = Math3D.VectorNormalize(vec); float dec = 0.5f; - VectorScale(vec, dec, vec); + Math3D.VectorScale(vec, dec, vec); if (old.trailcount > 900) { orgscale = 4; @@ -1535,42 +1498,42 @@ public class CL_fx extends CL_tent { return; // drop less particles as it flies - if ((rand() & 1023) < old.trailcount) { + if ((Lib.rand() & 1023) < old.trailcount) { p = free_particles; free_particles = p.next; p.next = active_particles; active_particles = p; - VectorClear(p.accel); + Math3D.VectorClear(p.accel); - p.time = cl.time; + p.time = Globals.cl.time; - if ((flags & EF_GIB) != 0) { + if ((flags & Defines.EF_GIB) != 0) { p.alpha = 1.0f; p.alphavel = -1.0f / (1.0f + Globals.rnd.nextFloat() * 0.4f); - p.color = 0xe8 + (rand() & 7); + p.color = 0xe8 + (Lib.rand() & 7); for (int j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * orgscale; - p.vel[j] = crand() * velscale; + p.org[j] = move[j] + Lib.crand() * orgscale; + p.vel[j] = Lib.crand() * velscale; p.accel[j] = 0; } p.vel[2] -= PARTICLE_GRAVITY; - } else if ((flags & EF_GREENGIB) != 0) { + } else if ((flags & Defines.EF_GREENGIB) != 0) { p.alpha = 1.0f; p.alphavel = -1.0f / (1.0f + Globals.rnd.nextFloat() * 0.4f); - p.color = 0xdb + (rand() & 7); + p.color = 0xdb + (Lib.rand() & 7); for (int j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * orgscale; - p.vel[j] = crand() * velscale; + p.org[j] = move[j] + Lib.crand() * orgscale; + p.vel[j] = Lib.crand() * velscale; p.accel[j] = 0; } p.vel[2] -= PARTICLE_GRAVITY; } else { p.alpha = 1.0f; p.alphavel = -1.0f / (1.0f + Globals.rnd.nextFloat() * 0.2f); - p.color = 4 + (rand() & 7); + p.color = 4 + (Lib.rand() & 7); for (int j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * orgscale; - p.vel[j] = crand() * velscale; + p.org[j] = move[j] + Lib.crand() * orgscale; + p.vel[j] = Lib.crand() * velscale; } p.accel[2] = 20; } @@ -1579,16 +1542,15 @@ public class CL_fx extends CL_tent { old.trailcount -= 5; if (old.trailcount < 100) old.trailcount = 100; - VectorAdd(move, vec, move); + Math3D.VectorAdd(move, vec, move); } } /* - =============== - CL_RocketTrail - - =============== - */ + * =============== CL_RocketTrail + * + * =============== + */ static void RocketTrail(float[] start, float[] end, centity_t old) { float[] move = new float[3]; float[] vec = new float[3]; @@ -1598,15 +1560,15 @@ public class CL_fx extends CL_tent { float dec; // smoke - CL.DiminishingTrail(start, end, old, EF_ROCKET); + DiminishingTrail(start, end, old, Defines.EF_ROCKET); // fire - VectorCopy(start, move); - VectorSubtract(end, start, vec); - len = VectorNormalize(vec); + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); dec = 1; - VectorScale(vec, dec, vec); + Math3D.VectorScale(vec, dec, vec); while (len > 0) { len -= dec; @@ -1614,34 +1576,33 @@ public class CL_fx extends CL_tent { if (free_particles == null) return; - if ((rand() & 7) == 0) { + if ((Lib.rand() & 7) == 0) { p = free_particles; free_particles = p.next; p.next = active_particles; active_particles = p; - VectorClear(p.accel); - p.time = cl.time; + Math3D.VectorClear(p.accel); + p.time = Globals.cl.time; p.alpha = 1.0f; p.alphavel = -1.0f / (1.0f + Globals.rnd.nextFloat() * 0.2f); - p.color = 0xdc + (rand() & 3); + p.color = 0xdc + (Lib.rand() & 3); for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * 5; - p.vel[j] = crand() * 20; + p.org[j] = move[j] + Lib.crand() * 5; + p.vel[j] = Lib.crand() * 20; } p.accel[2] = -PARTICLE_GRAVITY; } - VectorAdd(move, vec, move); + Math3D.VectorAdd(move, vec, move); } } /* - =============== - CL_RailTrail - - =============== - */ + * =============== CL_RailTrail + * + * =============== + */ static void RailTrail(float[] start, float[] end) { float[] move = new float[3]; float[] vec = new float[3]; @@ -1656,11 +1617,11 @@ public class CL_fx extends CL_tent { float[] dir = new float[3]; byte clr = 0x74; - VectorCopy(start, move); - VectorSubtract(end, start, vec); - len = VectorNormalize(vec); + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); - MakeNormalVectors(vec, right, up); + Math3D.MakeNormalVectors(vec, right, up); for (i = 0; i < len; i++) { if (free_particles == null) @@ -1671,30 +1632,30 @@ public class CL_fx extends CL_tent { p.next = active_particles; active_particles = p; - p.time = cl.time; - VectorClear(p.accel); + p.time = Globals.cl.time; + Math3D.VectorClear(p.accel); d = i * 0.1f; - c = (float)Math.cos(d); - s = (float)Math.sin(d); + c = (float) Math.cos(d); + s = (float) Math.sin(d); - VectorScale(right, c, dir); - VectorMA(dir, s, up, dir); + Math3D.VectorScale(right, c, dir); + Math3D.VectorMA(dir, s, up, dir); p.alpha = 1.0f; p.alphavel = -1.0f / (1.0f + Globals.rnd.nextFloat() * 0.2f); - p.color = clr + (rand() & 7); + p.color = clr + (Lib.rand() & 7); for (j = 0; j < 3; j++) { p.org[j] = move[j] + dir[j] * 3; p.vel[j] = dir[j] * 6; } - VectorAdd(move, vec, move); + Math3D.VectorAdd(move, vec, move); } dec = 0.75f; - VectorScale(vec, dec, vec); - VectorCopy(start, move); + Math3D.VectorScale(vec, dec, vec); + Math3D.VectorCopy(start, move); while (len > 0) { len -= dec; @@ -1706,29 +1667,27 @@ public class CL_fx extends CL_tent { p.next = active_particles; active_particles = p; - p.time = cl.time; - VectorClear(p.accel); + p.time = Globals.cl.time; + Math3D.VectorClear(p.accel); p.alpha = 1.0f; p.alphavel = -1.0f / (0.6f + Globals.rnd.nextFloat() * 0.2f); - p.color = 0x0 + rand() & 15; + p.color = 0x0 + Lib.rand() & 15; for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * 3; - p.vel[j] = crand() * 3; + p.org[j] = move[j] + Lib.crand() * 3; + p.vel[j] = Lib.crand() * 3; p.accel[j] = 0; } - VectorAdd(move, vec, move); + Math3D.VectorAdd(move, vec, move); } } // RAFAEL /* - =============== - CL_IonripperTrail - =============== - */ + * =============== CL_IonripperTrail =============== + */ static void IonripperTrail(float[] start, float[] ent) { float[] move = new float[3]; float[] vec = new float[3]; @@ -1737,30 +1696,30 @@ public class CL_fx extends CL_tent { cparticle_t p; int dec; int left = 0; - - VectorCopy(start, move); - VectorSubtract(ent, start, vec); - len = VectorNormalize(vec); - + + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(ent, start, vec); + len = Math3D.VectorNormalize(vec); + dec = 5; - VectorScale(vec, 5, vec); - + Math3D.VectorScale(vec, 5, vec); + while (len > 0) { len -= dec; - + if (free_particles == null) return; p = free_particles; free_particles = p.next; p.next = active_particles; active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; p.alpha = 0.5f; p.alphavel = -1.0f / (0.3f + Globals.rnd.nextFloat() * 0.2f); - p.color = 0xe4 + (rand() & 3); - + p.color = 0xe4 + (Lib.rand() & 3); + for (j = 0; j < 3; j++) { p.org[j] = move[j]; p.accel[j] = 0; @@ -1772,20 +1731,19 @@ public class CL_fx extends CL_tent { left = 1; p.vel[0] = -10; } - + p.vel[1] = 0; p.vel[2] = 0; - - VectorAdd(move, vec, move); + + Math3D.VectorAdd(move, vec, move); } } /* - =============== - CL_BubbleTrail - - =============== - */ + * =============== CL_BubbleTrail + * + * =============== + */ static void BubbleTrail(float[] start, float[] end) { float[] move = new float[3]; float[] vec = new float[3]; @@ -1794,12 +1752,12 @@ public class CL_fx extends CL_tent { cparticle_t p; float dec; - VectorCopy(start, move); - VectorSubtract(end, start, vec); - len = VectorNormalize(vec); + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); dec = 32; - VectorScale(vec, dec, vec); + Math3D.VectorScale(vec, dec, vec); for (i = 0; i < len; i += dec) { if (free_particles == null) @@ -1810,65 +1768,57 @@ public class CL_fx extends CL_tent { p.next = active_particles; active_particles = p; - VectorClear(p.accel); - p.time = cl.time; + Math3D.VectorClear(p.accel); + p.time = Globals.cl.time; p.alpha = 1.0f; p.alphavel = -1.0f / (1.0f + Globals.rnd.nextFloat() * 0.2f); - p.color = 4 + (rand() & 7); + p.color = 4 + (Lib.rand() & 7); for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * 2; - p.vel[j] = crand() * 5; + p.org[j] = move[j] + Lib.crand() * 2; + p.vel[j] = Lib.crand() * 5; } p.vel[2] += 6; - VectorAdd(move, vec, move); + Math3D.VectorAdd(move, vec, move); } } /* - =============== - CL_FlyParticles - =============== - */ - private static final int BEAMLENGTH = 16; - static void FlyParticles (float [] origin, int count) - { - int i; - cparticle_t p; - float angle; - float sp, sy, cp, cy; - float [] forward= new float[3]; - float dist = 64; - float ltime; - - - if (count > NUMVERTEXNORMALS) - count = NUMVERTEXNORMALS; - - if (avelocities[0][0] == 0.0f) - { - for (i=0 ; i Defines.NUMVERTEXNORMALS) + count = Defines.NUMVERTEXNORMALS; + + if (avelocities[0][0] == 0.0f) { + for (i = 0; i < Defines.NUMVERTEXNORMALS; i++) { + avelocities[i][0] = (Lib.rand() & 255) * 0.01f; + avelocities[i][1] = (Lib.rand() & 255) * 0.01f; + avelocities[i][2] = (Lib.rand() & 255) * 0.01f; } } - - ltime = cl.time / 1000.0f; - for (i=0 ; i 0) { @@ -2025,31 +1971,31 @@ public class CL_fx extends CL_tent { free_particles = p.next; p.next = active_particles; active_particles = p; - VectorClear(p.accel); + Math3D.VectorClear(p.accel); - p.time = cl.time; + p.time = Globals.cl.time; p.alpha = 1.0f; p.alphavel = -1.0f / (0.3f + Globals.rnd.nextFloat() * 0.2f); p.color = 0xe0; for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand(); - p.vel[j] = crand() * 15; + p.org[j] = move[j] + Lib.crand(); + p.vel[j] = Lib.crand() * 15; p.accel[j] = 0; } p.accel[2] = PARTICLE_GRAVITY; - VectorAdd(move, vec, move); + Math3D.VectorAdd(move, vec, move); } int i, k; - //cparticle_t p; + //cparticle_t p; float vel; float[] dir = new float[3]; float[] org = new float[3]; ent.origin[2] += 14; - VectorCopy(ent.origin, org); + Math3D.VectorCopy(ent.origin, org); for (i = -2; i <= 2; i += 4) for (j = -2; j <= 2; j += 4) @@ -2061,23 +2007,23 @@ public class CL_fx extends CL_tent { p.next = active_particles; active_particles = p; - p.time = cl.time; - p.color = 0xe0 + (rand() & 3); + p.time = Globals.cl.time; + p.color = 0xe0 + (Lib.rand() & 3); p.alpha = 1.0f; - p.alphavel = -1.0f / (0.3f + (rand() & 7) * 0.02f); + p.alphavel = -1.0f / (0.3f + (Lib.rand() & 7) * 0.02f); - p.org[0] = org[0] + i + ((rand() & 23) * crand()); - p.org[1] = org[1] + j + ((rand() & 23) * crand()); - p.org[2] = org[2] + k + ((rand() & 23) * crand()); + p.org[0] = org[0] + i + ((Lib.rand() & 23) * Lib.crand()); + p.org[1] = org[1] + j + ((Lib.rand() & 23) * Lib.crand()); + p.org[2] = org[2] + k + ((Lib.rand() & 23) * Lib.crand()); dir[0] = j * 8; dir[1] = i * 8; dir[2] = k * 8; - VectorNormalize(dir); - vel = 50 + rand() & 63; - VectorScale(dir, vel, p.vel); + Math3D.VectorNormalize(dir); + vel = 50 + Lib.rand() & 63; + Math3D.VectorScale(dir, vel, p.vel); p.accel[0] = p.accel[1] = 0; p.accel[2] = -PARTICLE_GRAVITY; @@ -2085,12 +2031,9 @@ public class CL_fx extends CL_tent { } - /* - =============== - CL_BFGExplosionParticles - =============== - */ + * =============== CL_BFGExplosionParticles =============== + */ // FIXME combined with CL_ExplosionParticles static void BFGExplosionParticles(float[] org) { int i, j; @@ -2104,12 +2047,12 @@ public class CL_fx extends CL_tent { p.next = active_particles; active_particles = p; - p.time = cl.time; - p.color = 0xd0 + (rand() & 7); + p.time = Globals.cl.time; + p.color = 0xd0 + (Lib.rand() & 7); for (j = 0; j < 3; j++) { - p.org[j] = org[j] + ((rand() % 32) - 16); - p.vel[j] = (rand() % 384) - 192; + p.org[j] = org[j] + ((Lib.rand() % 32) - 16); + p.vel[j] = (Lib.rand() % 384) - 192; } p.accel[0] = p.accel[1] = 0; @@ -2121,11 +2064,10 @@ public class CL_fx extends CL_tent { } /* - =============== - CL_TeleportParticles - - =============== - */ + * =============== CL_TeleportParticles + * + * =============== + */ static void TeleportParticles(float[] org) { cparticle_t p; @@ -2142,23 +2084,23 @@ public class CL_fx extends CL_tent { p.next = active_particles; active_particles = p; - p.time = cl.time; - p.color = 7 + (rand() & 7); + p.time = Globals.cl.time; + p.color = 7 + (Lib.rand() & 7); p.alpha = 1.0f; - p.alphavel = -1.0f / (0.3f + (rand() & 7) * 0.02f); + p.alphavel = -1.0f / (0.3f + (Lib.rand() & 7) * 0.02f); - p.org[0] = org[0] + i + (rand() & 3); - p.org[1] = org[1] + j + (rand() & 3); - p.org[2] = org[2] + k + (rand() & 3); + p.org[0] = org[0] + i + (Lib.rand() & 3); + p.org[1] = org[1] + j + (Lib.rand() & 3); + p.org[2] = org[2] + k + (Lib.rand() & 3); dir[0] = j * 8; dir[1] = i * 8; dir[2] = k * 8; - VectorNormalize(dir); - vel = 50 + (rand() & 63); - VectorScale(dir, vel, p.vel); + Math3D.VectorNormalize(dir); + vel = 50 + (Lib.rand() & 63); + Math3D.VectorScale(dir, vel, p.vel); p.accel[0] = p.accel[1] = 0; p.accel[2] = -PARTICLE_GRAVITY; @@ -2166,10 +2108,8 @@ public class CL_fx extends CL_tent { } /* - =============== - CL_AddParticles - =============== - */ + * =============== CL_AddParticles =============== + */ static void AddParticles() { cparticle_t p, next; float alpha; @@ -2187,7 +2127,7 @@ public class CL_fx extends CL_tent { // PMM - added INSTANT_PARTICLE handling for heat beam if (p.alphavel != INSTANT_PARTICLE) { - time = (cl.time - p.time) * 0.001f; + time = (Globals.cl.time - p.time) * 0.001f; alpha = p.alpha + time * p.alphavel; if (alpha <= 0) { // faded out p.next = free_particles; @@ -2208,7 +2148,7 @@ public class CL_fx extends CL_tent { if (alpha > 1.0) alpha = 1; - color = (int)p.color; + color = (int) p.color; time2 = time * time; @@ -2226,52 +2166,68 @@ public class CL_fx extends CL_tent { active_particles = active; } - - /* - ============== - CL_EntityEvent - - An entity has just been parsed that has an event value - the female events are there for backwards compatability - ============== - */ + /* + * ============== CL_EntityEvent + * + * An entity has just been parsed that has an event value + * + * the female events are there for backwards compatability ============== + */ static void EntityEvent(entity_state_t ent) { switch (ent.event) { - case EV_ITEM_RESPAWN : - S.StartSound(null, ent.number, CHAN_WEAPON, S.RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0); - CL.ItemRespawnParticles(ent.origin); - break; - case EV_PLAYER_TELEPORT : - S.StartSound(null, ent.number, CHAN_WEAPON, S.RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0); - CL.TeleportParticles(ent.origin); - break; - case EV_FOOTSTEP : - if (cl_footsteps.value != 0.0f) - S.StartSound(null, ent.number, CHAN_BODY, cl_sfx_footsteps[rand() & 3], 1, ATTN_NORM, 0); - break; - case EV_FALLSHORT : - S.StartSound(null, ent.number, CHAN_AUTO, S.RegisterSound("player/land1.wav"), 1, ATTN_NORM, 0); - break; - case EV_FALL : - S.StartSound(null, ent.number, CHAN_AUTO, S.RegisterSound("*fall2.wav"), 1, ATTN_NORM, 0); - break; - case EV_FALLFAR : - S.StartSound(null, ent.number, CHAN_AUTO, S.RegisterSound("*fall1.wav"), 1, ATTN_NORM, 0); - break; + case Defines.EV_ITEM_RESPAWN: + S.StartSound(null, ent.number, Defines.CHAN_WEAPON, S.RegisterSound("items/respawn1.wav"), 1, Defines.ATTN_IDLE, 0); + ItemRespawnParticles(ent.origin); + break; + case Defines.EV_PLAYER_TELEPORT: + S.StartSound(null, ent.number, Defines.CHAN_WEAPON, S.RegisterSound("misc/tele1.wav"), 1, Defines.ATTN_IDLE, 0); + TeleportParticles(ent.origin); + break; + case Defines.EV_FOOTSTEP: + if (Globals.cl_footsteps.value != 0.0f) + S.StartSound(null, ent.number, Defines.CHAN_BODY, CL_tent.cl_sfx_footsteps[Lib.rand() & 3], 1, Defines.ATTN_NORM, 0); + break; + case Defines.EV_FALLSHORT: + S.StartSound(null, ent.number, Defines.CHAN_AUTO, S.RegisterSound("player/land1.wav"), 1, Defines.ATTN_NORM, 0); + break; + case Defines.EV_FALL: + S.StartSound(null, ent.number, Defines.CHAN_AUTO, S.RegisterSound("*fall2.wav"), 1, Defines.ATTN_NORM, 0); + break; + case Defines.EV_FALLFAR: + S.StartSound(null, ent.number, Defines.CHAN_AUTO, S.RegisterSound("*fall1.wav"), 1, Defines.ATTN_NORM, 0); + break; } } /* - ============== - CL_ClearEffects - - ============== - */ + * ============== CL_ClearEffects + * + * ============== + */ static void ClearEffects() { - CL.ClearParticles(); - CL.ClearDlights(); - CL.ClearLightStyles(); + ClearParticles(); + ClearDlights(); + ClearLightStyles(); } -} + /* + * ============================================================== + * + * PARTICLE MANAGEMENT + * + * ============================================================== + */ + + static final int PARTICLE_GRAVITY = 40; + + static cparticle_t active_particles, free_particles; + + /* + * =============== CL_BigTeleportParticles =============== + */ + private static int[] colortable = { 2 * 8, 13 * 8, 21 * 8, 18 * 8 }; + + private static final int BEAMLENGTH = 16; + +} \ No newline at end of file diff --git a/src/jake2/client/CL_input.java b/src/jake2/client/CL_input.java index 47132bb..b470967 100644 --- a/src/jake2/client/CL_input.java +++ b/src/jake2/client/CL_input.java @@ -1,30 +1,32 @@ /* - * CL_input.java + * java * Copyright (C) 2004 * - * $Id: CL_input.java,v 1.3 2004-07-09 06:50:50 hzi Exp $ + * $Id: CL_input.java,v 1.4 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; +import jake2.Defines; +import jake2.Globals; import jake2.game.*; import jake2.game.Cmd; import jake2.game.usercmd_t; @@ -32,57 +34,73 @@ import jake2.qcommon.*; import jake2.qcommon.Cvar; import jake2.qcommon.xcommand_t; import jake2.sys.IN; +import jake2.util.Math3D; /** * CL_input */ -public class CL_input extends CL_ents { - +public class CL_input { + static long frame_msec; + static long old_sys_frame_time; static cvar_t cl_nodelta; /* - =============================================================================== - - KEY BUTTONS - - Continuous button event tracking is complicated by the fact that two different - input sources (say, mouse button 1 and the control key) can both press the - same button, but the button should only be released when both of the - pressing key have been released. - - When a key event issues a button command (+forward, +attack, etc), it appends - its key number as a parameter to the command so it can be matched up with - the release. - - state bit 0 is the current state of the key - state bit 1 is edge triggered on the up to down transition - state bit 2 is edge triggered on the down to up transition - - - Key_Event (int key, qboolean down, unsigned time); - - +mlook src time - - =============================================================================== - */ + * =============================================================================== + * + * KEY BUTTONS + * + * Continuous button event tracking is complicated by the fact that two + * different input sources (say, mouse button 1 and the control key) can + * both press the same button, but the button should only be released when + * both of the pressing key have been released. + * + * When a key event issues a button command (+forward, +attack, etc), it + * appends its key number as a parameter to the command so it can be matched + * up with the release. + * + * state bit 0 is the current state of the key state bit 1 is edge triggered + * on the up to down transition state bit 2 is edge triggered on the down to + * up transition + * + * + * Key_Event (int key, qboolean down, unsigned time); + * + * +mlook src time + * + * =============================================================================== + */ static kbutton_t in_klook = new kbutton_t(); + static kbutton_t in_left = new kbutton_t(); + static kbutton_t in_right = new kbutton_t(); + static kbutton_t in_forward = new kbutton_t(); + static kbutton_t in_back = new kbutton_t(); + static kbutton_t in_lookup = new kbutton_t(); + static kbutton_t in_lookdown = new kbutton_t(); + static kbutton_t in_moveleft = new kbutton_t(); + static kbutton_t in_moveright = new kbutton_t(); + public static kbutton_t in_strafe = new kbutton_t(); + static kbutton_t in_speed = new kbutton_t(); + static kbutton_t in_use = new kbutton_t(); + static kbutton_t in_attack = new kbutton_t(); + static kbutton_t in_up = new kbutton_t(); + static kbutton_t in_down = new kbutton_t(); static int in_impulse; @@ -95,10 +113,10 @@ public class CL_input extends CL_ents { if (c.length() > 0) k = Integer.parseInt(c); else - k = -1; // typed manually at the console for continuous down + k = -1; // typed manually at the console for continuous down if (k == b.down[0] || k == b.down[1]) - return; // repeating key + return; // repeating key if (b.down[0] == 0) b.down[0] = k; @@ -110,15 +128,15 @@ public class CL_input extends CL_ents { } if ((b.state & 1) != 0) - return; // still down + return; // still down // save timestamp c = Cmd.Argv(2); b.downtime = Long.parseLong(c); if (b.downtime == 0) - b.downtime = sys_frame_time - 100; + b.downtime = Globals.sys_frame_time - 100; - b.state |= 3; // down + impulse down + b.state |= 3; // down + impulse down } static void KeyUp(kbutton_t b) { @@ -130,9 +148,10 @@ public class CL_input extends CL_ents { if (c.length() > 0) k = Integer.parseInt(c); else { - // typed manually at the console, assume for unsticking, so clear all + // typed manually at the console, assume for unsticking, so clear + // all b.down[0] = b.down[1] = 0; - b.state = 4; // impulse up + b.state = 4; // impulse up return; } @@ -141,12 +160,12 @@ public class CL_input extends CL_ents { else if (b.down[1] == k) b.down[1] = 0; else - return; // key up without coresponding down (menu pass through) + return; // key up without coresponding down (menu pass through) if (b.down[0] != 0 || b.down[1] != 0) - return; // some other key is still holding it down + return; // some other key is still holding it down if ((b.state & 1) == 0) - return; // still up (this should not happen) + return; // still up (this should not happen) // save timestamp c = Cmd.Argv(2); @@ -156,69 +175,155 @@ public class CL_input extends CL_ents { else b.msec += 10; - b.state &= ~1; // now up - b.state |= 4; // impulse up - } - - static void IN_KLookDown() {KeyDown(in_klook);} - static void IN_KLookUp() {KeyUp(in_klook);} - static void IN_UpDown() {KeyDown(in_up);} - static void IN_UpUp() {KeyUp(in_up);} - static void IN_DownDown() {KeyDown(in_down);} - static void IN_DownUp() {KeyUp(in_down);} - static void IN_LeftDown() {KeyDown(in_left);} - static void IN_LeftUp() {KeyUp(in_left);} - static void IN_RightDown() {KeyDown(in_right);} - static void IN_RightUp() {KeyUp(in_right);} - static void IN_ForwardDown() {KeyDown(in_forward);} - static void IN_ForwardUp() {KeyUp(in_forward);} - static void IN_BackDown() {KeyDown(in_back);} - static void IN_BackUp() {KeyUp(in_back);} - static void IN_LookupDown() {KeyDown(in_lookup);} - static void IN_LookupUp() {KeyUp(in_lookup);} - static void IN_LookdownDown() {KeyDown(in_lookdown);} - static void IN_LookdownUp() {KeyUp(in_lookdown);} - static void IN_MoveleftDown() {KeyDown(in_moveleft);} - static void IN_MoveleftUp() {KeyUp(in_moveleft);} - static void IN_MoverightDown() {KeyDown(in_moveright);} - static void IN_MoverightUp() {KeyUp(in_moveright);} - - static void IN_SpeedDown() {KeyDown(in_speed);} - static void IN_SpeedUp() {KeyUp(in_speed);} - static void IN_StrafeDown() {KeyDown(in_strafe);} - static void IN_StrafeUp() {KeyUp(in_strafe);} - - static void IN_AttackDown() {KeyDown(in_attack);} - static void IN_AttackUp() {KeyUp(in_attack);} - - static void IN_UseDown () {KeyDown(in_use);} - static void IN_UseUp () {KeyUp(in_use);} - - static void IN_Impulse () {in_impulse=Integer.parseInt(Cmd.Argv(1));} + b.state &= ~1; // now up + b.state |= 4; // impulse up + } - /* - =============== - CL_KeyState + static void IN_KLookDown() { + KeyDown(in_klook); + } + + static void IN_KLookUp() { + KeyUp(in_klook); + } + + static void IN_UpDown() { + KeyDown(in_up); + } + + static void IN_UpUp() { + KeyUp(in_up); + } + + static void IN_DownDown() { + KeyDown(in_down); + } + + static void IN_DownUp() { + KeyUp(in_down); + } + + static void IN_LeftDown() { + KeyDown(in_left); + } + + static void IN_LeftUp() { + KeyUp(in_left); + } + + static void IN_RightDown() { + KeyDown(in_right); + } + + static void IN_RightUp() { + KeyUp(in_right); + } + + static void IN_ForwardDown() { + KeyDown(in_forward); + } - Returns the fraction of the frame that the key was down - =============== - */ + static void IN_ForwardUp() { + KeyUp(in_forward); + } + + static void IN_BackDown() { + KeyDown(in_back); + } + + static void IN_BackUp() { + KeyUp(in_back); + } + + static void IN_LookupDown() { + KeyDown(in_lookup); + } + + static void IN_LookupUp() { + KeyUp(in_lookup); + } + + static void IN_LookdownDown() { + KeyDown(in_lookdown); + } + + static void IN_LookdownUp() { + KeyUp(in_lookdown); + } + + static void IN_MoveleftDown() { + KeyDown(in_moveleft); + } + + static void IN_MoveleftUp() { + KeyUp(in_moveleft); + } + + static void IN_MoverightDown() { + KeyDown(in_moveright); + } + + static void IN_MoverightUp() { + KeyUp(in_moveright); + } + + static void IN_SpeedDown() { + KeyDown(in_speed); + } + + static void IN_SpeedUp() { + KeyUp(in_speed); + } + + static void IN_StrafeDown() { + KeyDown(in_strafe); + } + + static void IN_StrafeUp() { + KeyUp(in_strafe); + } + + static void IN_AttackDown() { + KeyDown(in_attack); + } + + static void IN_AttackUp() { + KeyUp(in_attack); + } + + static void IN_UseDown() { + KeyDown(in_use); + } + + static void IN_UseUp() { + KeyUp(in_use); + } + + static void IN_Impulse() { + in_impulse = Integer.parseInt(Cmd.Argv(1)); + } + + /* + * =============== CL_KeyState + * + * Returns the fraction of the frame that the key was down =============== + */ static float KeyState(kbutton_t key) { float val; long msec; - key.state &= 1; // clear impulses + key.state &= 1; // clear impulses msec = key.msec; key.msec = 0; if (key.state != 0) { // still down - msec += sys_frame_time - key.downtime; - key.downtime = sys_frame_time; + msec += Globals.sys_frame_time - key.downtime; + key.downtime = Globals.sys_frame_time; } - val = (float)msec / frame_msec; + val = (float) msec / frame_msec; if (val < 0) val = 0; if (val > 1) @@ -227,105 +332,99 @@ public class CL_input extends CL_ents { return val; } -// ========================================================================== + // ========================================================================== /* - ================ - CL_AdjustAngles - - Moves the local angle positions - ================ - */ + * ================ CL_AdjustAngles + * + * Moves the local angle positions ================ + */ static void AdjustAngles() { float speed; float up, down; if ((in_speed.state & 1) != 0) - speed = cls.frametime * cl_anglespeedkey.value; + speed = Globals.cls.frametime * Globals.cl_anglespeedkey.value; else - speed = cls.frametime; + speed = Globals.cls.frametime; if ((in_strafe.state & 1) == 0) { - cl.viewangles[YAW] -= speed * cl_yawspeed.value * CL.KeyState(in_right); - cl.viewangles[YAW] += speed * cl_yawspeed.value * CL.KeyState(in_left); + Globals.cl.viewangles[Defines.YAW] -= speed * Globals.cl_yawspeed.value * KeyState(in_right); + Globals.cl.viewangles[Defines.YAW] += speed * Globals.cl_yawspeed.value * KeyState(in_left); } if ((in_klook.state & 1) != 0) { - cl.viewangles[PITCH] -= speed * cl_pitchspeed.value * CL.KeyState(in_forward); - cl.viewangles[PITCH] += speed * cl_pitchspeed.value * CL.KeyState(in_back); + Globals.cl.viewangles[Defines.PITCH] -= speed * Globals.cl_pitchspeed.value * KeyState(in_forward); + Globals.cl.viewangles[Defines.PITCH] += speed * Globals.cl_pitchspeed.value * KeyState(in_back); } - up = CL.KeyState(in_lookup); - down = CL.KeyState(in_lookdown); + up = KeyState(in_lookup); + down = KeyState(in_lookdown); - cl.viewangles[PITCH] -= speed * cl_pitchspeed.value * up; - cl.viewangles[PITCH] += speed * cl_pitchspeed.value * down; + Globals.cl.viewangles[Defines.PITCH] -= speed * Globals.cl_pitchspeed.value * up; + Globals.cl.viewangles[Defines.PITCH] += speed * Globals.cl_pitchspeed.value * down; } /* - ================ - CL_BaseMove - - Send the intended movement message to the server - ================ - */ - static void BaseMove(usercmd_t cmd) { - CL.AdjustAngles(); + * ================ CL_BaseMove + * + * Send the intended movement message to the server ================ + */ + static void BaseMove(usercmd_t cmd) { + AdjustAngles(); //memset (cmd, 0, sizeof(*cmd)); cmd.reset(); - VectorCopy(cl.viewangles, cmd.angles); + Math3D.VectorCopy(Globals.cl.viewangles, cmd.angles); if ((in_strafe.state & 1) != 0) { - cmd.sidemove += cl_sidespeed.value * CL.KeyState(in_right); - cmd.sidemove -= cl_sidespeed.value * CL.KeyState(in_left); + cmd.sidemove += Globals.cl_sidespeed.value * KeyState(in_right); + cmd.sidemove -= Globals.cl_sidespeed.value * KeyState(in_left); } - cmd.sidemove += cl_sidespeed.value * CL.KeyState(in_moveright); - cmd.sidemove -= cl_sidespeed.value * CL.KeyState(in_moveleft); + cmd.sidemove += Globals.cl_sidespeed.value * KeyState(in_moveright); + cmd.sidemove -= Globals.cl_sidespeed.value * KeyState(in_moveleft); - cmd.upmove += cl_upspeed.value * CL.KeyState(in_up); - cmd.upmove -= cl_upspeed.value * CL.KeyState(in_down); + cmd.upmove += Globals.cl_upspeed.value * KeyState(in_up); + cmd.upmove -= Globals.cl_upspeed.value * KeyState(in_down); if ((in_klook.state & 1) == 0) { - cmd.forwardmove += cl_forwardspeed.value * CL.KeyState(in_forward); - cmd.forwardmove -= cl_forwardspeed.value * CL.KeyState(in_back); + cmd.forwardmove += Globals.cl_forwardspeed.value * KeyState(in_forward); + cmd.forwardmove -= Globals.cl_forwardspeed.value * KeyState(in_back); } // // adjust for speed key / running // - if (((in_speed.state & 1) ^ (int) (cl_run.value)) != 0) { + if (((in_speed.state & 1) ^ (int) (Globals.cl_run.value)) != 0) { cmd.forwardmove *= 2; cmd.sidemove *= 2; cmd.upmove *= 2; } - + } static void ClampPitch() { - float pitch; + float pitch; - pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]); + pitch = Math3D.SHORT2ANGLE(Globals.cl.frame.playerstate.pmove.delta_angles[Defines.PITCH]); if (pitch > 180) pitch -= 360; - if (cl.viewangles[PITCH] + pitch < -360) - cl.viewangles[PITCH] += 360; // wrapped - if (cl.viewangles[PITCH] + pitch > 360) - cl.viewangles[PITCH] -= 360; // wrapped + if (Globals.cl.viewangles[Defines.PITCH] + pitch < -360) + Globals.cl.viewangles[Defines.PITCH] += 360; // wrapped + if (Globals.cl.viewangles[Defines.PITCH] + pitch > 360) + Globals.cl.viewangles[Defines.PITCH] -= 360; // wrapped - if (cl.viewangles[PITCH] + pitch > 89) - cl.viewangles[PITCH] = 89 - pitch; - if (cl.viewangles[PITCH] + pitch < -89) - cl.viewangles[PITCH] = -89 - pitch; + if (Globals.cl.viewangles[Defines.PITCH] + pitch > 89) + Globals.cl.viewangles[Defines.PITCH] = 89 - pitch; + if (Globals.cl.viewangles[Defines.PITCH] + pitch < -89) + Globals.cl.viewangles[Defines.PITCH] = -89 - pitch; } /* - ============== - CL_FinishMove - ============== - */ + * ============== CL_FinishMove ============== + */ static void FinishMove(usercmd_t cmd) { int ms; int i; @@ -334,140 +433,230 @@ public class CL_input extends CL_ents { // figure button bits // if ((in_attack.state & 3) != 0) - cmd.buttons |= BUTTON_ATTACK; + cmd.buttons |= Defines.BUTTON_ATTACK; in_attack.state &= ~2; if ((in_use.state & 3) != 0) - cmd.buttons |= BUTTON_USE; + cmd.buttons |= Defines.BUTTON_USE; in_use.state &= ~2; - if (Key.anykeydown != 0 && cls.key_dest == key_game) - cmd.buttons |= BUTTON_ANY; + if (Key.anykeydown != 0 && Globals.cls.key_dest == Defines.key_game) + cmd.buttons |= Defines.BUTTON_ANY; // send milliseconds of time to apply the move - ms = (int)(cls.frametime * 1000); + ms = (int) (Globals.cls.frametime * 1000); if (ms > 250) ms = 100; // time was unreasonable - cmd.msec = (byte)ms; + cmd.msec = (byte) ms; - CL.ClampPitch(); + ClampPitch(); for (i = 0; i < 3; i++) - cmd.angles[i] = (short)ANGLE2SHORT(cl.viewangles[i]); + cmd.angles[i] = (short) Math3D.ANGLE2SHORT(Globals.cl.viewangles[i]); - cmd.impulse = (byte)in_impulse; + cmd.impulse = (byte) in_impulse; in_impulse = 0; // send the ambient light level at the player's current position - cmd.lightlevel = (byte)cl_lightlevel.value; + cmd.lightlevel = (byte) Globals.cl_lightlevel.value; } /* - ================= - CL_CreateCmd - ================= - */ + * ================= CL_CreateCmd ================= + */ static usercmd_t CreateCmd() { usercmd_t cmd = new usercmd_t(); - frame_msec = sys_frame_time - old_sys_frame_time; + frame_msec = Globals.sys_frame_time - old_sys_frame_time; if (frame_msec < 1) frame_msec = 1; if (frame_msec > 200) frame_msec = 200; // get basic movement from keyboard - CL.BaseMove(cmd); + BaseMove(cmd); // allow mice or other external controllers to add to the move IN.Move(cmd); - CL.FinishMove(cmd); + FinishMove(cmd); - old_sys_frame_time = sys_frame_time; + old_sys_frame_time = Globals.sys_frame_time; return cmd; } /* - ============ - CL_InitInput - ============ - */ + * ============ CL_InitInput ============ + */ static void InitInput() { Cmd.AddCommand("centerview", new xcommand_t() { - public void execute() {IN.CenterView();}}); + public void execute() { + IN.CenterView(); + } + }); Cmd.AddCommand("+moveup", new xcommand_t() { - public void execute() {IN_UpDown();}}); + public void execute() { + IN_UpDown(); + } + }); Cmd.AddCommand("-moveup", new xcommand_t() { - public void execute() {IN_UpUp();}}); + public void execute() { + IN_UpUp(); + } + }); Cmd.AddCommand("+movedown", new xcommand_t() { - public void execute() {IN_DownDown();}}); + public void execute() { + IN_DownDown(); + } + }); Cmd.AddCommand("-movedown", new xcommand_t() { - public void execute() {IN_DownUp();}}); + public void execute() { + IN_DownUp(); + } + }); Cmd.AddCommand("+left", new xcommand_t() { - public void execute() {IN_LeftDown();}}); + public void execute() { + IN_LeftDown(); + } + }); Cmd.AddCommand("-left", new xcommand_t() { - public void execute() {IN_LeftUp();}}); + public void execute() { + IN_LeftUp(); + } + }); Cmd.AddCommand("+right", new xcommand_t() { - public void execute() {IN_RightDown();}}); + public void execute() { + IN_RightDown(); + } + }); Cmd.AddCommand("-right", new xcommand_t() { - public void execute() {IN_RightUp();}}); + public void execute() { + IN_RightUp(); + } + }); Cmd.AddCommand("+forward", new xcommand_t() { - public void execute() {IN_ForwardDown();}}); + public void execute() { + IN_ForwardDown(); + } + }); Cmd.AddCommand("-forward", new xcommand_t() { - public void execute() {IN_ForwardUp();}}); + public void execute() { + IN_ForwardUp(); + } + }); Cmd.AddCommand("+back", new xcommand_t() { - public void execute() {IN_BackDown();}}); + public void execute() { + IN_BackDown(); + } + }); Cmd.AddCommand("-back", new xcommand_t() { - public void execute() {IN_BackUp();}}); + public void execute() { + IN_BackUp(); + } + }); Cmd.AddCommand("+lookup", new xcommand_t() { - public void execute() {IN_LookupDown();}}); + public void execute() { + IN_LookupDown(); + } + }); Cmd.AddCommand("-lookup", new xcommand_t() { - public void execute() {IN_LookupUp();}}); + public void execute() { + IN_LookupUp(); + } + }); Cmd.AddCommand("+lookdown", new xcommand_t() { - public void execute() {IN_LookdownDown();}}); + public void execute() { + IN_LookdownDown(); + } + }); Cmd.AddCommand("-lookdown", new xcommand_t() { - public void execute() {IN_LookdownUp();}}); + public void execute() { + IN_LookdownUp(); + } + }); Cmd.AddCommand("+strafe", new xcommand_t() { - public void execute() {IN_StrafeDown();}}); + public void execute() { + IN_StrafeDown(); + } + }); Cmd.AddCommand("-strafe", new xcommand_t() { - public void execute() {IN_StrafeUp();}}); + public void execute() { + IN_StrafeUp(); + } + }); Cmd.AddCommand("+moveleft", new xcommand_t() { - public void execute() {IN_MoveleftDown();}}); + public void execute() { + IN_MoveleftDown(); + } + }); Cmd.AddCommand("-moveleft", new xcommand_t() { - public void execute() {IN_MoveleftUp();}}); + public void execute() { + IN_MoveleftUp(); + } + }); Cmd.AddCommand("+moveright", new xcommand_t() { - public void execute() {IN_MoverightDown();}}); + public void execute() { + IN_MoverightDown(); + } + }); Cmd.AddCommand("-moveright", new xcommand_t() { - public void execute() {IN_MoverightUp();}}); + public void execute() { + IN_MoverightUp(); + } + }); Cmd.AddCommand("+speed", new xcommand_t() { - public void execute() {IN_SpeedDown();}}); + public void execute() { + IN_SpeedDown(); + } + }); Cmd.AddCommand("-speed", new xcommand_t() { - public void execute() {IN_SpeedUp();}}); + public void execute() { + IN_SpeedUp(); + } + }); Cmd.AddCommand("+attack", new xcommand_t() { - public void execute() {IN_AttackDown();}}); + public void execute() { + IN_AttackDown(); + } + }); Cmd.AddCommand("-attack", new xcommand_t() { - public void execute() {IN_AttackUp();}}); + public void execute() { + IN_AttackUp(); + } + }); Cmd.AddCommand("+use", new xcommand_t() { - public void execute() {IN_UseDown();}}); + public void execute() { + IN_UseDown(); + } + }); Cmd.AddCommand("-use", new xcommand_t() { - public void execute() {IN_UseUp();}}); + public void execute() { + IN_UseUp(); + } + }); Cmd.AddCommand("impulse", new xcommand_t() { - public void execute() {IN_Impulse();}}); + public void execute() { + IN_Impulse(); + } + }); Cmd.AddCommand("+klook", new xcommand_t() { - public void execute() {IN_KLookDown();}}); + public void execute() { + IN_KLookDown(); + } + }); Cmd.AddCommand("-klook", new xcommand_t() { - public void execute() {IN_KLookUp();}}); + public void execute() { + IN_KLookUp(); + } + }); - cl_nodelta = Cvar.Get("cl_nodelta", "0",0); + cl_nodelta = Cvar.Get("cl_nodelta", "0", 0); } /* - ================= - CL_SendCmd - ================= - */ + * ================= CL_SendCmd ================= + */ static void SendCmd() { sizebuf_t buf = new sizebuf_t(); byte[] data = new byte[128]; @@ -479,42 +668,46 @@ public class CL_input extends CL_ents { // build a command even if not connected // save this command off for prediction - i = cls.netchan.outgoing_sequence & (CMD_BACKUP - 1); - cmd = cl.cmds[i]; - cl.cmd_time[i] = (int)cls.realtime; // for netgraph ping calculation + i = Globals.cls.netchan.outgoing_sequence & (Defines.CMD_BACKUP - 1); + cmd = Globals.cl.cmds[i]; + Globals.cl.cmd_time[i] = (int) Globals.cls.realtime; // for netgraph + // ping calculation - cmd.set(CL.CreateCmd()); + cmd.set(CreateCmd()); - cl.cmd.set(cmd); + Globals.cl.cmd.set(cmd); - if (cls.state == ca_disconnected || cls.state == ca_connecting) + if (Globals.cls.state == Defines.ca_disconnected || Globals.cls.state == Defines.ca_connecting) return; - - if (cls.state == ca_connected) { - if (cls.netchan.message.cursize != 0 || curtime - cls.netchan.last_sent > 1000) - Netchan.Transmit(cls.netchan, 0, new byte[0]); + + if (Globals.cls.state == Defines.ca_connected) { + if (Globals.cls.netchan.message.cursize != 0 || Globals.curtime - Globals.cls.netchan.last_sent > 1000) + Netchan.Transmit(Globals.cls.netchan, 0, new byte[0]); return; } // send a userinfo update if needed - if (userinfo_modified) { + if (Globals.userinfo_modified) { CL.FixUpGender(); - userinfo_modified = false; - MSG.WriteByte(cls.netchan.message, clc_userinfo); - MSG.WriteString(cls.netchan.message, Cvar.Userinfo()); + Globals.userinfo_modified = false; + MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_userinfo); + MSG.WriteString(Globals.cls.netchan.message, Cvar.Userinfo()); } SZ.Init(buf, data, data.length); - if (cmd.buttons != 0 - && cl.cinematictime > 0 - && !cl.attractloop - && cls.realtime - cl.cinematictime > 1000) { // skip the rest of the cinematic + if (cmd.buttons != 0 && Globals.cl.cinematictime > 0 && !Globals.cl.attractloop + && Globals.cls.realtime - Globals.cl.cinematictime > 1000) { // skip + // the + // rest + // of + // the + // cinematic SCR.FinishCinematic(); } // begin a client move command - MSG.WriteByte(buf, clc_move); + MSG.WriteByte(buf, Defines.clc_move); // save the position for a checksum byte checksumIndex = buf.cursize; @@ -522,39 +715,39 @@ public class CL_input extends CL_ents { // let the server know what the last frame we // got was, so the next message can be delta compressed - if (cl_nodelta.value != 0.0f || !cl.frame.valid || cls.demowaiting) + if (cl_nodelta.value != 0.0f || !Globals.cl.frame.valid || Globals.cls.demowaiting) MSG.WriteLong(buf, -1); // no compression else - MSG.WriteLong(buf, cl.frame.serverframe); + MSG.WriteLong(buf, Globals.cl.frame.serverframe); // send this and the previous cmds in the message, so // if the last packet was dropped, it can be recovered - i = (cls.netchan.outgoing_sequence - 2) & (CMD_BACKUP - 1); - cmd = cl.cmds[i]; + i = (Globals.cls.netchan.outgoing_sequence - 2) & (Defines.CMD_BACKUP - 1); + cmd = Globals.cl.cmds[i]; //memset (nullcmd, 0, sizeof(nullcmd)); nullcmd.reset(); MSG.WriteDeltaUsercmd(buf, nullcmd, cmd); oldcmd = cmd; - i = (cls.netchan.outgoing_sequence - 1) & (CMD_BACKUP - 1); - cmd = cl.cmds[i]; - + i = (Globals.cls.netchan.outgoing_sequence - 1) & (Defines.CMD_BACKUP - 1); + cmd = Globals.cl.cmds[i]; + MSG.WriteDeltaUsercmd(buf, oldcmd, cmd); oldcmd = cmd; - i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP - 1); - cmd = cl.cmds[i]; + i = (Globals.cls.netchan.outgoing_sequence) & (Defines.CMD_BACKUP - 1); + cmd = Globals.cl.cmds[i]; MSG.WriteDeltaUsercmd(buf, oldcmd, cmd); // calculate a checksum over the move commands - buf.data[checksumIndex] = Com.BlockSequenceCRCByte(buf.data, checksumIndex + 1, buf.cursize - checksumIndex - 1, cls.netchan.outgoing_sequence); + buf.data[checksumIndex] = Com.BlockSequenceCRCByte(buf.data, checksumIndex + 1, buf.cursize - checksumIndex - 1, + Globals.cls.netchan.outgoing_sequence); // // deliver the message // - Netchan.Transmit(cls.netchan, buf.cursize, buf.data); + Netchan.Transmit(Globals.cls.netchan, buf.cursize, buf.data); } - -} +} \ No newline at end of file diff --git a/src/jake2/client/CL_inv.java b/src/jake2/client/CL_inv.java index ba219c7..ee7764a 100644 --- a/src/jake2/client/CL_inv.java +++ b/src/jake2/client/CL_inv.java @@ -2,32 +2,33 @@ * CL_fx.java * Copyright (C) 2004 * - * $Id: CL_inv.java,v 1.1 2004-07-07 19:58:37 hzi Exp $ + * $Id: CL_inv.java,v 1.2 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.01.2004 by RST. - package jake2.client; +import jake2.Defines; +import jake2.Globals; import jake2.qcommon.Com; import jake2.qcommon.MSG; import jake2.util.Vargs; @@ -35,28 +36,24 @@ import jake2.util.Vargs; /** * CL_inv */ -public class CL_inv extends CL_newfx { +public class CL_inv { /* - ================ - CL_ParseInventory - ================ - */ + * ================ CL_ParseInventory ================ + */ static void ParseInventory() { int i; - for (i = 0; i < MAX_ITEMS; i++) - cl.inventory[i] = MSG.ReadShort(net_message); + for (i = 0; i < Defines.MAX_ITEMS; i++) + Globals.cl.inventory[i] = MSG.ReadShort(Globals.net_message); } /* - ================ - Inv_DrawString - ================ - */ + * ================ Inv_DrawString ================ + */ static void Inv_DrawString(int x, int y, String string) { for (int i = 0; i < string.length(); i++) { - re.DrawChar(x, y, string.charAt(i)); + Globals.re.DrawChar(x, y, string.charAt(i)); x += 8; } } @@ -70,16 +67,14 @@ public class CL_inv extends CL_newfx { } /* - ================ - CL_DrawInventory - ================ - */ + * ================ CL_DrawInventory ================ + */ static final int DISPLAY_ITEMS = 17; static void DrawInventory() { int i, j; int num, selected_num, item; - int[] index = new int[MAX_ITEMS]; + int[] index = new int[Defines.MAX_ITEMS]; String string; int x, y; String binding; @@ -87,14 +82,14 @@ public class CL_inv extends CL_newfx { int selected; int top; - selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM]; + selected = Globals.cl.frame.playerstate.stats[Defines.STAT_SELECTED_ITEM]; num = 0; selected_num = 0; - for (i = 0; i < MAX_ITEMS; i++) { + for (i = 0; i < Defines.MAX_ITEMS; i++) { if (i == selected) selected_num = num; - if (cl.inventory[i] != 0) { + if (Globals.cl.inventory[i] != 0) { index[num] = i; num++; } @@ -107,13 +102,13 @@ public class CL_inv extends CL_newfx { if (top < 0) top = 0; - x = (viddef.width - 256) / 2; - y = (viddef.height - 240) / 2; + x = (Globals.viddef.width - 256) / 2; + y = (Globals.viddef.height - 240) / 2; // repaint everything next frame SCR.DirtyScreen(); - re.DrawPic(x, y + 8, "inventory"); + Globals.re.DrawPic(x, y + 8, "inventory"); y += 24; x += 24; @@ -123,30 +118,28 @@ public class CL_inv extends CL_newfx { for (i = top; i < num && i < top + DISPLAY_ITEMS; i++) { item = index[i]; // search for a binding - //Com_sprintf (binding, sizeof(binding), "use %s", cl.configstrings[CS_ITEMS+item]); - binding = "use " + cl.configstrings[CS_ITEMS + item]; + //Com_sprintf (binding, sizeof(binding), "use %s", + // cl.configstrings[CS_ITEMS+item]); + binding = "use " + Globals.cl.configstrings[Defines.CS_ITEMS + item]; bind = ""; for (j = 0; j < 256; j++) - if (keybindings[j] != null && keybindings[j].equals(binding)) { + if (Globals.keybindings[j] != null && Globals.keybindings[j].equals(binding)) { bind = Key.KeynumToString(j); break; } - string = - Com.sprintf( - "%6s %3i %s", - new Vargs(3).add(bind).add(cl.inventory[item]).add(cl.configstrings[CS_ITEMS + item])); + string = Com.sprintf("%6s %3i %s", new Vargs(3).add(bind).add(Globals.cl.inventory[item]).add( + Globals.cl.configstrings[Defines.CS_ITEMS + item])); if (item != selected) SetStringHighBit(string); else // draw a blinky cursor by the selected item - { - if (((int) (cls.realtime * 10) & 1) != 0) - re.DrawChar(x - 8, y, 15); + { + if (((int) (Globals.cls.realtime * 10) & 1) != 0) + Globals.re.DrawChar(x - 8, y, 15); } Inv_DrawString(x, y, string); y += 8; } } - -} +} \ No newline at end of file diff --git a/src/jake2/client/CL_newfx.java b/src/jake2/client/CL_newfx.java index 5346226..690cd57 100644 --- a/src/jake2/client/CL_newfx.java +++ b/src/jake2/client/CL_newfx.java @@ -2,1028 +2,1010 @@ * CL_newfx.java * Copyright (C) 2004 * - * $Id: CL_newfx.java,v 1.3 2004-07-08 20:24:29 hzi Exp $ + * $Id: CL_newfx.java,v 1.4 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.01.2004 by RST. - package jake2.client; +import jake2.Defines; import jake2.Globals; - +import jake2.client.CL_fx.cdlight_t; +import jake2.util.Lib; +import jake2.util.Math3D; /** * CL_newfx */ -public class CL_newfx extends CL_fx { - - - - static void Flashlight(int ent, float[] pos) { - cdlight_t dl; - - dl = CL.AllocDlight(ent); - VectorCopy(pos, dl.origin); - dl.radius = 400; - dl.minlight = 250; - dl.die = cl.time + 100; - dl.color[0] = 1; - dl.color[1] = 1; - dl.color[2] = 1; - } - - /* - ====== - CL_ColorFlash - flash of light - ====== - */ - static void ColorFlash(float[] pos, int ent, int intensity, float r, float g, float b) { - cdlight_t dl; - - if ((vidref_val == VIDREF_SOFT) && ((r < 0) || (g < 0) || (b < 0))) { - intensity = -intensity; - r = -r; - g = -g; - b = -b; - } - - dl = CL.AllocDlight(ent); - VectorCopy(pos, dl.origin); - dl.radius = intensity; - dl.minlight = 250; - dl.die = cl.time + 100; - dl.color[0] = r; - dl.color[1] = g; - dl.color[2] = b; - } - - /* - ====== - CL_DebugTrail - ====== - */ - static void DebugTrail(float[] start, float[] end) { - float[] move = new float[3]; - float[] vec = new float[3]; - - float len; - // int j; - cparticle_t p; - float dec; - float[] right = new float[3]; - float[] up = new float[3]; - // int i; - // float d, c, s; - // float[] dir; - - VectorCopy(start, move); - VectorSubtract(end, start, vec); - len = VectorNormalize(vec); - - MakeNormalVectors(vec, right, up); - - // VectorScale(vec, RT2_SKIP, vec); - - // dec = 1.0; - // dec = 0.75; - dec = 3; - VectorScale(vec, dec, vec); - VectorCopy(start, move); - - while (len > 0) { - len -= dec; - - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - - p.time = cl.time; - VectorClear(p.accel); - VectorClear(p.vel); - p.alpha = 1.0f; - p.alphavel = -0.1f; - // p.alphavel = 0; - p.color = 0x74 + (rand() & 7); - VectorCopy(move, p.org); - /* - for (j=0 ; j<3 ; j++) - { - p.org[j] = move[j] + crand()*2; - p.vel[j] = crand()*3; - p.accel[j] = 0; - } - */ - VectorAdd(move, vec, move); - } - - } - - /* - =============== - CL_SmokeTrail - =============== - */ - static void SmokeTrail(float[] start, float[] end, int colorStart, int colorRun, int spacing) { - float[] move = new float[3]; - float[] vec = new float[3]; - float len; - int j; - cparticle_t p; - - VectorCopy(start, move); - VectorSubtract(end, start, vec); - len = VectorNormalize(vec); - - VectorScale(vec, spacing, vec); - - // FIXME: this is a really silly way to have a loop - while (len > 0) { - len -= spacing; - - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; - - p.alpha = 1.0f; - p.alphavel = -1.0f / (1 + Globals.rnd.nextFloat() * 0.5f); - p.color = colorStart + (rand() % colorRun); - for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * 3; - p.accel[j] = 0; - } - p.vel[2] = 20 + crand() * 5; - - VectorAdd(move, vec, move); - } - } - - static void ForceWall(float[] start, float[] end, int color) { - float[] move = new float[3]; - float[] vec = new float[3]; - ; - float len; - int j; - cparticle_t p; - - VectorCopy(start, move); - VectorSubtract(end, start, vec); - len = VectorNormalize(vec); - - VectorScale(vec, 4, vec); - - // FIXME: this is a really silly way to have a loop - while (len > 0) { - len -= 4; - - if (free_particles == null) - return; - - if (Globals.rnd.nextFloat() > 0.3) { - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; - - p.alpha = 1.0f; - p.alphavel = -1.0f / (3.0f + Globals.rnd.nextFloat() * 0.5f); - p.color = color; - for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * 3; - p.accel[j] = 0; - } - p.vel[0] = 0; - p.vel[1] = 0; - p.vel[2] = -40 - (crand() * 10); - } - - VectorAdd(move, vec, move); - } - } - -// static void FlameEffects(centity_t ent, float[] origin) { -// int n, count; -// int j; -// cparticle_t p; -// -// count = rand() & 0xF; -// -// for (n = 0; n < count; n++) { -// if (free_particles == null) -// return; -// -// p = free_particles; -// free_particles = p.next; -// p.next = active_particles; -// active_particles = p; -// -// VectorClear(p.accel); -// p.time = cl.time; -// -// p.alpha = 1.0f; -// p.alphavel = -1.0f / (1 + frand() * 0.2f); -// p.color = 226 + (rand() % 4); -// for (j = 0; j < 3; j++) { -// p.org[j] = origin[j] + crand() * 5; -// p.vel[j] = crand() * 5; -// } -// p.vel[2] = crand() * -10; -// p.accel[2] = -PARTICLE_GRAVITY; -// } -// -// count = rand() & 0x7; -// -// for (n = 0; n < count; n++) { -// if (free_particles == null) -// return; -// p = free_particles; -// free_particles = p.next; -// p.next = active_particles; -// active_particles = p; -// VectorClear(p.accel); -// -// p.time = cl.time; -// -// p.alpha = 1.0f; -// p.alphavel = -1.0f / (1 + frand() * 0.5f); -// p.color = 0 + (rand() % 4); -// for (j = 0; j < 3; j++) { -// p.org[j] = origin[j] + crand() * 3; -// } -// p.vel[2] = 20 + crand() * 5; -// } -// -// } - - - /* - =============== - CL_GenericParticleEffect - =============== - */ - static void GenericParticleEffect(float[] org, float[] dir, int color, int count, int numcolors, int dirspread, float alphavel) { - int i, j; - cparticle_t p; - float d; - - for (i = 0; i < count; i++) { - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - - p.time = cl.time; - if (numcolors > 1) - p.color = color + (rand() & numcolors); - else - p.color = color; - - d = rand() & dirspread; - for (j = 0; j < 3; j++) { - p.org[j] = org[j] + ((rand() & 7) - 4) + d * dir[j]; - p.vel[j] = crand() * 20; - } - - p.accel[0] = p.accel[1] = 0; - p.accel[2] = -PARTICLE_GRAVITY; - // VectorCopy (accel, p.accel); - p.alpha = 1.0f; - - p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * alphavel); - // p.alphavel = alphavel; - } - } - - /* - =============== - CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns) - - =============== - */ - static void BubbleTrail2 (float[] start, float[] end, int dist) - { - float[] move = new float[3]; - float[] vec = new float[3];; - float len; - int i, j; - cparticle_t p; - float dec; - - VectorCopy (start, move); - VectorSubtract (end, start, vec); - len = VectorNormalize (vec); - - dec = dist; - VectorScale (vec, dec, vec); - - for (i=0 ; i step * 5) // don't bother after the 5th ring - break; - - for (rot = 0; rot < M_PI2; rot += rstep) { - - if (free_particles == null) - return; - - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - - p.time = cl.time; - VectorClear(p.accel); - // rot+= fmod(ltime, 12.0)*M_PI; - // c = cos(rot)/2.0; - // s = sin(rot)/2.0; - // variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2; - variance = 0.5f; - c = (float) (Math.cos(rot) * variance); - s = (float) (Math.sin(rot) * variance); - - // trim it so it looks like it's starting at the origin - if (i < 10) { - VectorScale(right, c * (i / 10.0f), dir); - VectorMA(dir, s * (i / 10.0f), up, dir); - } else { - VectorScale(right, c, dir); - VectorMA(dir, s, up, dir); - } - - p.alpha = 0.5f; - // p.alphavel = -1.0 / (1+frand()*0.2); - p.alphavel = -1000.0f; - // p.color = 0x74 + (rand()&7); - p.color = 223 - (rand() & 7); - for (j = 0; j < 3; j++) { - p.org[j] = move[j] + dir[j] * 3; - // p.vel[j] = dir[j]*6; - p.vel[j] = 0; - } - } - VectorAdd(move, vec, move); - } - } - - /* - =============== - CL_ParticleSteamEffect - - Puffs with velocity along direction, with some randomness thrown in - =============== - */ - static void ParticleSteamEffect(float[] org, float[] dir, int color, int count, int magnitude) { - int i, j; - cparticle_t p; - float d; - float[] r = new float[3]; - float[] u = new float[3]; - - // vectoangles2 (dir, angle_dir); - // AngleVectors (angle_dir, f, r, u); - - MakeNormalVectors(dir, r, u); - - for (i = 0; i < count; i++) { - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - - p.time = cl.time; - p.color = color + (rand() & 7); - - for (j = 0; j < 3; j++) { - p.org[j] = org[j] + magnitude * 0.1f * crand(); - // p.vel[j] = dir[j]*magnitude; - } - VectorScale(dir, magnitude, p.vel); - d = crand() * magnitude / 3; - VectorMA(p.vel, d, r, p.vel); - d = crand() * magnitude / 3; - VectorMA(p.vel, d, u, p.vel); - - p.accel[0] = p.accel[1] = 0; - p.accel[2] = -PARTICLE_GRAVITY / 2; - p.alpha = 1.0f; - - p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * 0.3f); - } - } - - static void ParticleSteamEffect2(cl_sustain_t self) - // float[] org, float[] dir, int color, int count, int magnitude) - { - int i, j; - cparticle_t p; - float d; - float[] r = new float[3]; - float[] u = new float[3]; - float[] dir = new float[3]; - - // vectoangles2 (dir, angle_dir); - // AngleVectors (angle_dir, f, r, u); - - VectorCopy(self.dir, dir); - MakeNormalVectors(dir, r, u); - - for (i = 0; i < self.count; i++) { - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - - p.time = cl.time; - p.color = self.color + (rand() & 7); - - for (j = 0; j < 3; j++) { - p.org[j] = self.org[j] + self.magnitude * 0.1f * crand(); - // p.vel[j] = dir[j]*magnitude; - } - VectorScale(dir, self.magnitude, p.vel); - d = crand() * self.magnitude / 3; - VectorMA(p.vel, d, r, p.vel); - d = crand() * self.magnitude / 3; - VectorMA(p.vel, d, u, p.vel); - - p.accel[0] = p.accel[1] = 0; - p.accel[2] = -PARTICLE_GRAVITY / 2; - p.alpha = 1.0f; - - p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * 0.3f); - } - self.nextthink += self.thinkinterval; - } - - /* - =============== - CL_TrackerTrail - =============== - */ - static void TrackerTrail(float[] start, float[] end, int particleColor) { - float[] move = new float[3]; - float[] vec = new float[3]; - float[] forward = new float[3]; - float[] right = new float[3]; - float[] up = new float[3]; - float[] angle_dir = new float[3]; - float len; - cparticle_t p; - int dec; - float dist; - - VectorCopy(start, move); - VectorSubtract(end, start, vec); - len = VectorNormalize(vec); - - VectorCopy(vec, forward); - vectoangles(forward, angle_dir); - AngleVectors(angle_dir, forward, right, up); - - dec = 3; - VectorScale(vec, 3, vec); - - // FIXME: this is a really silly way to have a loop - while (len > 0) { - len -= dec; - - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; - - p.alpha = 1.0f; - p.alphavel = -2.0f; - p.color = particleColor; - dist = DotProduct(move, forward); - VectorMA(move, (float)(8 * Math.cos(dist)), up, p.org); - for (int j=0 ; j<3 ; j++) { - p.vel[j] = 0; - p.accel[j] = 0; - } - p.vel[2] = 5; - - VectorAdd (move, vec, move); - } - } - - static void Tracker_Shell(float[] origin) { - float[] dir = new float[3]; - int i; - cparticle_t p; - - for(i=0;i<300;i++) { - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; - - p.alpha = 1.0f; - p.alphavel = INSTANT_PARTICLE; - p.color = 0; - - dir[0] = crand(); - dir[1] = crand(); - dir[2] = crand(); - VectorNormalize(dir); - - VectorMA(origin, 40, dir, p.org); - } - } - - static void MonsterPlasma_Shell(float[] origin) { - float[] dir = new float[3]; - int i; - cparticle_t p; - - for (i = 0; i < 40; i++) { - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; - - p.alpha = 1.0f; - p.alphavel = INSTANT_PARTICLE; - p.color = 0xe0; - - dir[0] = crand(); - dir[1] = crand(); - dir[2] = crand(); - VectorNormalize(dir); - - VectorMA(origin, 10, dir, p.org); - // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p.org); - } - } - - private static int[] wb_colortable = {2*8,13*8,21*8,18*8}; - static void Widowbeamout(cl_sustain_t self) { - float[] dir = new float[3]; - int i; - cparticle_t p; - - float ratio; - - ratio = 1.0f - (((float)self.endtime - (float)cl.time) / 2100.0f); - - for (i = 0; i < 300; i++) { - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; - - p.alpha = 1.0f; - p.alphavel = INSTANT_PARTICLE; - p.color = wb_colortable[rand() & 3]; - - dir[0] = crand(); - dir[1] = crand(); - dir[2] = crand(); - VectorNormalize(dir); - - VectorMA(self.org, (45.0f * ratio), dir, p.org); - // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p.org); - } - } - - private static int[] nb_colortable = {110, 112, 114, 116}; - static void Nukeblast(cl_sustain_t self) { - float[] dir = new float[3]; - int i; - cparticle_t p; - - float ratio; - - ratio = 1.0f - (((float)self.endtime - (float)cl.time) / 1000.0f); - - for (i = 0; i < 700; i++) { - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; - - p.alpha = 1.0f; - p.alphavel = INSTANT_PARTICLE; - p.color = nb_colortable[rand() & 3]; - - dir[0] = crand(); - dir[1] = crand(); - dir[2] = crand(); - VectorNormalize(dir); - - VectorMA(self.org, (200.0f * ratio), dir, p.org); - // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p.org); - } - } - - private static int[] ws_colortable = {2*8,13*8,21*8,18*8}; - static void WidowSplash(float[] org) { - int i; - cparticle_t p; - float[] dir = new float[3]; - - for (i = 0; i < 256; i++) { - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - - p.time = cl.time; - p.color = ws_colortable[rand() & 3]; - - dir[0] = crand(); - dir[1] = crand(); - dir[2] = crand(); - VectorNormalize(dir); - VectorMA(org, 45.0f, dir, p.org); - VectorMA(vec3_origin, 40.0f, dir, p.vel); - - p.accel[0] = p.accel[1] = 0; - p.alpha = 1.0f; - - p.alphavel = -0.8f / (0.5f + Globals.rnd.nextFloat() * 0.3f); - } - - } - - static void Tracker_Explode(float[] origin) { - float[] dir = new float[3]; - float[] backdir = new float[3]; - int i; - cparticle_t p; - - for (i = 0; i < 300; i++) { - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; - - p.alpha = 1.0f; - p.alphavel = -1.0f; - p.color = 0; - - dir[0] = crand(); - dir[1] = crand(); - dir[2] = crand(); - VectorNormalize(dir); - VectorScale(dir, -1, backdir); - - VectorMA(origin, 64, dir, p.org); - VectorScale(backdir, 64, p.vel); - } - - } - - /* - =============== - CL_TagTrail - - =============== - */ - static void TagTrail(float[] start, float[] end, float color) { - float[] move = new float[3]; - float[] vec = new float[3]; - float len; - int j; - cparticle_t p; - int dec; - - VectorCopy(start, move); - VectorSubtract(end, start, vec); - len = VectorNormalize(vec); - - dec = 5; - VectorScale(vec, 5, vec); - - while (len >= 0) { - len -= dec; - - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; - - p.alpha = 1.0f; - p.alphavel = -1.0f / (0.8f + Globals.rnd.nextFloat() * 0.2f); - p.color = color; - for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand() * 16; - p.vel[j] = crand() * 5; - p.accel[j] = 0; - } - - VectorAdd(move, vec, move); - } - } - - /* - =============== - CL_ColorExplosionParticles - =============== - */ - static void ColorExplosionParticles(float[] org, int color, int run) { - int i, j; - cparticle_t p; - - for (i = 0; i < 128; i++) { - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - - p.time = cl.time; - p.color = color + (rand() % run); - - for (j = 0; j < 3; j++) { - p.org[j] = org[j] + ((rand() % 32) - 16); - p.vel[j] = (rand() % 256) - 128; - } - - p.accel[0] = p.accel[1] = 0; - p.accel[2] = -PARTICLE_GRAVITY; - p.alpha = 1.0f; - - p.alphavel = -0.4f / (0.6f + Globals.rnd.nextFloat() * 0.2f); - } - } - - /* - =============== - CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity - =============== - */ - static void ParticleSmokeEffect (float[] org, float[] dir, int color, int count, int magnitude) - { - int i, j; - cparticle_t p; - float d; - float[] r = new float[3]; - float[] u = new float[3]; - - MakeNormalVectors (dir, r, u); - - for (i=0 ; i 0) { - len -= dec; - - if (free_particles == null) - return; - p = free_particles; - free_particles = p.next; - p.next = active_particles; - active_particles = p; - VectorClear(p.accel); - - p.time = cl.time; - - p.alpha = 1.0f; - p.alphavel = -1.0f / (0.3f + Globals.rnd.nextFloat() * 0.2f); - p.color = 0xd0; - for (j = 0; j < 3; j++) { - p.org[j] = move[j] + crand(); - p.vel[j] = crand() * 5; - p.accel[j] = 0; - } - - VectorAdd(move, vec, move); - } - } - -} +public class CL_newfx { + + static void Flashlight(int ent, float[] pos) { + CL_fx.cdlight_t dl; + + dl = CL_fx.AllocDlight(ent); + Math3D.VectorCopy(pos, dl.origin); + dl.radius = 400; + dl.minlight = 250; + dl.die = Globals.cl.time + 100; + dl.color[0] = 1; + dl.color[1] = 1; + dl.color[2] = 1; + } + + /* + * ====== CL_ColorFlash - flash of light ====== + */ + static void ColorFlash(float[] pos, int ent, int intensity, float r, + float g, float b) { + CL_fx.cdlight_t dl; + + if ((Globals.vidref_val == Defines.VIDREF_SOFT) + && ((r < 0) || (g < 0) || (b < 0))) { + intensity = -intensity; + r = -r; + g = -g; + b = -b; + } + + dl = CL_fx.AllocDlight(ent); + Math3D.VectorCopy(pos, dl.origin); + dl.radius = intensity; + dl.minlight = 250; + dl.die = Globals.cl.time + 100; + dl.color[0] = r; + dl.color[1] = g; + dl.color[2] = b; + } + + /* + * ====== CL_DebugTrail ====== + */ + static void DebugTrail(float[] start, float[] end) { + float[] move = new float[3]; + float[] vec = new float[3]; + + float len; + // int j; + cparticle_t p; + float dec; + float[] right = new float[3]; + float[] up = new float[3]; + // int i; + // float d, c, s; + // float[] dir; + + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); + + Math3D.MakeNormalVectors(vec, right, up); + + // VectorScale(vec, RT2_SKIP, vec); + + // dec = 1.0; + // dec = 0.75; + dec = 3; + Math3D.VectorScale(vec, dec, vec); + Math3D.VectorCopy(start, move); + + while (len > 0) { + len -= dec; + + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + + p.time = Globals.cl.time; + Math3D.VectorClear(p.accel); + Math3D.VectorClear(p.vel); + p.alpha = 1.0f; + p.alphavel = -0.1f; + // p.alphavel = 0; + p.color = 0x74 + (Lib.rand() & 7); + Math3D.VectorCopy(move, p.org); + /* + * for (j=0 ; j <3 ; j++) { p.org[j] = move[j] + crand()*2; p.vel[j] = + * crand()*3; p.accel[j] = 0; } + */ + Math3D.VectorAdd(move, vec, move); + } + + } + + /* + * =============== CL_SmokeTrail =============== + */ + static void SmokeTrail(float[] start, float[] end, int colorStart, + int colorRun, int spacing) { + float[] move = new float[3]; + float[] vec = new float[3]; + float len; + int j; + cparticle_t p; + + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); + + Math3D.VectorScale(vec, spacing, vec); + + // FIXME: this is a really silly way to have a loop + while (len > 0) { + len -= spacing; + + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = -1.0f / (1 + Globals.rnd.nextFloat() * 0.5f); + p.color = colorStart + (Lib.rand() % colorRun); + for (j = 0; j < 3; j++) { + p.org[j] = move[j] + Lib.crand() * 3; + p.accel[j] = 0; + } + p.vel[2] = 20 + Lib.crand() * 5; + + Math3D.VectorAdd(move, vec, move); + } + } + + static void ForceWall(float[] start, float[] end, int color) { + float[] move = new float[3]; + float[] vec = new float[3]; + ; + float len; + int j; + cparticle_t p; + + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); + + Math3D.VectorScale(vec, 4, vec); + + // FIXME: this is a really silly way to have a loop + while (len > 0) { + len -= 4; + + if (CL_fx.free_particles == null) + return; + + if (Globals.rnd.nextFloat() > 0.3) { + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = -1.0f / (3.0f + Globals.rnd.nextFloat() * 0.5f); + p.color = color; + for (j = 0; j < 3; j++) { + p.org[j] = move[j] + Lib.crand() * 3; + p.accel[j] = 0; + } + p.vel[0] = 0; + p.vel[1] = 0; + p.vel[2] = -40 - (Lib.crand() * 10); + } + + Math3D.VectorAdd(move, vec, move); + } + } + + // static void FlameEffects(centity_t ent, float[] origin) { + // int n, count; + // int j; + // cparticle_t p; + // + // count = rand() & 0xF; + // + // for (n = 0; n < count; n++) { + // if (free_particles == null) + // return; + // + // p = free_particles; + // free_particles = p.next; + // p.next = active_particles; + // active_particles = p; + // + // VectorClear(p.accel); + // p.time = cl.time; + // + // p.alpha = 1.0f; + // p.alphavel = -1.0f / (1 + frand() * 0.2f); + // p.color = 226 + (rand() % 4); + // for (j = 0; j < 3; j++) { + // p.org[j] = origin[j] + crand() * 5; + // p.vel[j] = crand() * 5; + // } + // p.vel[2] = crand() * -10; + // p.accel[2] = -PARTICLE_GRAVITY; + // } + // + // count = rand() & 0x7; + // + // for (n = 0; n < count; n++) { + // if (free_particles == null) + // return; + // p = free_particles; + // free_particles = p.next; + // p.next = active_particles; + // active_particles = p; + // VectorClear(p.accel); + // + // p.time = cl.time; + // + // p.alpha = 1.0f; + // p.alphavel = -1.0f / (1 + frand() * 0.5f); + // p.color = 0 + (rand() % 4); + // for (j = 0; j < 3; j++) { + // p.org[j] = origin[j] + crand() * 3; + // } + // p.vel[2] = 20 + crand() * 5; + // } + // + // } + + /* + * =============== CL_GenericParticleEffect =============== + */ + static void GenericParticleEffect(float[] org, float[] dir, int color, + int count, int numcolors, int dirspread, float alphavel) { + int i, j; + cparticle_t p; + float d; + + for (i = 0; i < count; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + + p.time = Globals.cl.time; + if (numcolors > 1) + p.color = color + (Lib.rand() & numcolors); + else + p.color = color; + + d = Lib.rand() & dirspread; + for (j = 0; j < 3; j++) { + p.org[j] = org[j] + ((Lib.rand() & 7) - 4) + d * dir[j]; + p.vel[j] = Lib.crand() * 20; + } + + p.accel[0] = p.accel[1] = 0; + p.accel[2] = -CL_fx.PARTICLE_GRAVITY; + // VectorCopy (accel, p.accel); + p.alpha = 1.0f; + + p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * alphavel); + // p.alphavel = alphavel; + } + } + + /* + * =============== CL_BubbleTrail2 (lets you control the # of bubbles by + * setting the distance between the spawns) + * + * =============== + */ + static void BubbleTrail2(float[] start, float[] end, int dist) { + float[] move = new float[3]; + float[] vec = new float[3]; + ; + float len; + int i, j; + cparticle_t p; + float dec; + + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); + + dec = dist; + Math3D.VectorScale(vec, dec, vec); + + for (i = 0; i < len; i += dec) { + if (CL_fx.free_particles == null) + return; + + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + + Math3D.VectorClear(p.accel); + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = -1.0f / (1 + Globals.rnd.nextFloat() * 0.1f); + p.color = 4 + (Lib.rand() & 7); + for (j = 0; j < 3; j++) { + p.org[j] = move[j] + Lib.crand() * 2; + p.vel[j] = Lib.crand() * 10; + } + p.org[2] -= 4; + // p.vel[2] += 6; + p.vel[2] += 20; + + Math3D.VectorAdd(move, vec, move); + } + } + + static void Heatbeam(float[] start, float[] forward) { + float[] move = new float[3]; + float[] vec = new float[3]; + float len; + int j; + cparticle_t p; + float[] right = new float[3]; + float[] up = new float[3]; + int i; + float c, s; + float[] dir = new float[3]; + float ltime; + float step = 32.0f, rstep; + float start_pt; + float rot; + float variance; + float[] end = new float[3]; + + Math3D.VectorMA(start, 4096, forward, end); + + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); + + // FIXME - pmm - these might end up using old values? + // MakeNormalVectors (vec, right, up); + Math3D.VectorCopy(Globals.cl.v_right, right); + Math3D.VectorCopy(Globals.cl.v_up, up); + if (Globals.vidref_val == Defines.VIDREF_GL) { // GL mode + Math3D.VectorMA(move, -0.5f, right, move); + Math3D.VectorMA(move, -0.5f, up, move); + } + // otherwise assume SOFT + + ltime = (float) Globals.cl.time / 1000.0f; + start_pt = ltime * 96.0f % step; + Math3D.VectorMA(move, start_pt, vec, move); + + Math3D.VectorScale(vec, step, vec); + + // Com_Printf ("%f\n", ltime); + rstep = (float) (Math.PI / 10.0); + float M_PI2 = (float) (Math.PI * 2.0); + for (i = (int) start_pt; i < len; i += step) { + if (i > step * 5) // don't bother after the 5th ring + break; + + for (rot = 0; rot < M_PI2; rot += rstep) { + + if (CL_fx.free_particles == null) + return; + + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + + p.time = Globals.cl.time; + Math3D.VectorClear(p.accel); + // rot+= fmod(ltime, 12.0)*M_PI; + // c = cos(rot)/2.0; + // s = sin(rot)/2.0; + // variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2; + variance = 0.5f; + c = (float) (Math.cos(rot) * variance); + s = (float) (Math.sin(rot) * variance); + + // trim it so it looks like it's starting at the origin + if (i < 10) { + Math3D.VectorScale(right, c * (i / 10.0f), dir); + Math3D.VectorMA(dir, s * (i / 10.0f), up, dir); + } else { + Math3D.VectorScale(right, c, dir); + Math3D.VectorMA(dir, s, up, dir); + } + + p.alpha = 0.5f; + // p.alphavel = -1.0 / (1+frand()*0.2); + p.alphavel = -1000.0f; + // p.color = 0x74 + (rand()&7); + p.color = 223 - (Lib.rand() & 7); + for (j = 0; j < 3; j++) { + p.org[j] = move[j] + dir[j] * 3; + // p.vel[j] = dir[j]*6; + p.vel[j] = 0; + } + } + Math3D.VectorAdd(move, vec, move); + } + } + + /* + * =============== CL_ParticleSteamEffect + * + * Puffs with velocity along direction, with some randomness thrown in + * =============== + */ + static void ParticleSteamEffect(float[] org, float[] dir, int color, + int count, int magnitude) { + int i, j; + cparticle_t p; + float d; + float[] r = new float[3]; + float[] u = new float[3]; + + // vectoangles2 (dir, angle_dir); + // AngleVectors (angle_dir, f, r, u); + + Math3D.MakeNormalVectors(dir, r, u); + + for (i = 0; i < count; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + + p.time = Globals.cl.time; + p.color = color + (Lib.rand() & 7); + + for (j = 0; j < 3; j++) { + p.org[j] = org[j] + magnitude * 0.1f * Lib.crand(); + // p.vel[j] = dir[j]*magnitude; + } + Math3D.VectorScale(dir, magnitude, p.vel); + d = Lib.crand() * magnitude / 3; + Math3D.VectorMA(p.vel, d, r, p.vel); + d = Lib.crand() * magnitude / 3; + Math3D.VectorMA(p.vel, d, u, p.vel); + + p.accel[0] = p.accel[1] = 0; + p.accel[2] = -CL_fx.PARTICLE_GRAVITY / 2; + p.alpha = 1.0f; + + p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * 0.3f); + } + } + + static void ParticleSteamEffect2(cl_sustain_t self) + // float[] org, float[] dir, int color, int count, int magnitude) + { + int i, j; + cparticle_t p; + float d; + float[] r = new float[3]; + float[] u = new float[3]; + float[] dir = new float[3]; + + // vectoangles2 (dir, angle_dir); + // AngleVectors (angle_dir, f, r, u); + + Math3D.VectorCopy(self.dir, dir); + Math3D.MakeNormalVectors(dir, r, u); + + for (i = 0; i < self.count; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + + p.time = Globals.cl.time; + p.color = self.color + (Lib.rand() & 7); + + for (j = 0; j < 3; j++) { + p.org[j] = self.org[j] + self.magnitude * 0.1f * Lib.crand(); + // p.vel[j] = dir[j]*magnitude; + } + Math3D.VectorScale(dir, self.magnitude, p.vel); + d = Lib.crand() * self.magnitude / 3; + Math3D.VectorMA(p.vel, d, r, p.vel); + d = Lib.crand() * self.magnitude / 3; + Math3D.VectorMA(p.vel, d, u, p.vel); + + p.accel[0] = p.accel[1] = 0; + p.accel[2] = -CL_fx.PARTICLE_GRAVITY / 2; + p.alpha = 1.0f; + + p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * 0.3f); + } + self.nextthink += self.thinkinterval; + } + + /* + * =============== CL_TrackerTrail =============== + */ + static void TrackerTrail(float[] start, float[] end, int particleColor) { + float[] move = new float[3]; + float[] vec = new float[3]; + float[] forward = new float[3]; + float[] right = new float[3]; + float[] up = new float[3]; + float[] angle_dir = new float[3]; + float len; + cparticle_t p; + int dec; + float dist; + + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); + + Math3D.VectorCopy(vec, forward); + Math3D.vectoangles(forward, angle_dir); + Math3D.AngleVectors(angle_dir, forward, right, up); + + dec = 3; + Math3D.VectorScale(vec, 3, vec); + + // FIXME: this is a really silly way to have a loop + while (len > 0) { + len -= dec; + + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = -2.0f; + p.color = particleColor; + dist = Math3D.DotProduct(move, forward); + Math3D.VectorMA(move, (float) (8 * Math.cos(dist)), up, p.org); + for (int j = 0; j < 3; j++) { + p.vel[j] = 0; + p.accel[j] = 0; + } + p.vel[2] = 5; + + Math3D.VectorAdd(move, vec, move); + } + } + + static void Tracker_Shell(float[] origin) { + float[] dir = new float[3]; + int i; + cparticle_t p; + + for (i = 0; i < 300; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = CL_fx.INSTANT_PARTICLE; + p.color = 0; + + dir[0] = Lib.crand(); + dir[1] = Lib.crand(); + dir[2] = Lib.crand(); + Math3D.VectorNormalize(dir); + + Math3D.VectorMA(origin, 40, dir, p.org); + } + } + + static void MonsterPlasma_Shell(float[] origin) { + float[] dir = new float[3]; + int i; + cparticle_t p; + + for (i = 0; i < 40; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = CL_fx.INSTANT_PARTICLE; + p.color = 0xe0; + + dir[0] = Lib.crand(); + dir[1] = Lib.crand(); + dir[2] = Lib.crand(); + Math3D.VectorNormalize(dir); + + Math3D.VectorMA(origin, 10, dir, p.org); + // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), + // dir, p.org); + } + } + + private static int[] wb_colortable = { 2 * 8, 13 * 8, 21 * 8, 18 * 8 }; + + static void Widowbeamout(cl_sustain_t self) { + float[] dir = new float[3]; + int i; + cparticle_t p; + + float ratio; + + ratio = 1.0f - (((float) self.endtime - (float) Globals.cl.time) / 2100.0f); + + for (i = 0; i < 300; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = CL_fx.INSTANT_PARTICLE; + p.color = wb_colortable[Lib.rand() & 3]; + + dir[0] = Lib.crand(); + dir[1] = Lib.crand(); + dir[2] = Lib.crand(); + Math3D.VectorNormalize(dir); + + Math3D.VectorMA(self.org, (45.0f * ratio), dir, p.org); + // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), + // dir, p.org); + } + } + + private static int[] nb_colortable = { 110, 112, 114, 116 }; + + static void Nukeblast(cl_sustain_t self) { + float[] dir = new float[3]; + int i; + cparticle_t p; + + float ratio; + + ratio = 1.0f - (((float) self.endtime - (float) Globals.cl.time) / 1000.0f); + + for (i = 0; i < 700; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = CL_fx.INSTANT_PARTICLE; + p.color = nb_colortable[Lib.rand() & 3]; + + dir[0] = Lib.crand(); + dir[1] = Lib.crand(); + dir[2] = Lib.crand(); + Math3D.VectorNormalize(dir); + + Math3D.VectorMA(self.org, (200.0f * ratio), dir, p.org); + // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), + // dir, p.org); + } + } + + private static int[] ws_colortable = { 2 * 8, 13 * 8, 21 * 8, 18 * 8 }; + + static void WidowSplash(float[] org) { + int i; + cparticle_t p; + float[] dir = new float[3]; + + for (i = 0; i < 256; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + + p.time = Globals.cl.time; + p.color = ws_colortable[Lib.rand() & 3]; + + dir[0] = Lib.crand(); + dir[1] = Lib.crand(); + dir[2] = Lib.crand(); + Math3D.VectorNormalize(dir); + Math3D.VectorMA(org, 45.0f, dir, p.org); + Math3D.VectorMA(Globals.vec3_origin, 40.0f, dir, p.vel); + + p.accel[0] = p.accel[1] = 0; + p.alpha = 1.0f; + + p.alphavel = -0.8f / (0.5f + Globals.rnd.nextFloat() * 0.3f); + } + + } + + static void Tracker_Explode(float[] origin) { + float[] dir = new float[3]; + float[] backdir = new float[3]; + int i; + cparticle_t p; + + for (i = 0; i < 300; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = -1.0f; + p.color = 0; + + dir[0] = Lib.crand(); + dir[1] = Lib.crand(); + dir[2] = Lib.crand(); + Math3D.VectorNormalize(dir); + Math3D.VectorScale(dir, -1, backdir); + + Math3D.VectorMA(origin, 64, dir, p.org); + Math3D.VectorScale(backdir, 64, p.vel); + } + + } + + /* + * =============== CL_TagTrail + * + * =============== + */ + static void TagTrail(float[] start, float[] end, float color) { + float[] move = new float[3]; + float[] vec = new float[3]; + float len; + int j; + cparticle_t p; + int dec; + + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); + + dec = 5; + Math3D.VectorScale(vec, 5, vec); + + while (len >= 0) { + len -= dec; + + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = -1.0f / (0.8f + Globals.rnd.nextFloat() * 0.2f); + p.color = color; + for (j = 0; j < 3; j++) { + p.org[j] = move[j] + Lib.crand() * 16; + p.vel[j] = Lib.crand() * 5; + p.accel[j] = 0; + } + + Math3D.VectorAdd(move, vec, move); + } + } + + /* + * =============== CL_ColorExplosionParticles =============== + */ + static void ColorExplosionParticles(float[] org, int color, int run) { + int i, j; + cparticle_t p; + + for (i = 0; i < 128; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + + p.time = Globals.cl.time; + p.color = color + (Lib.rand() % run); + + for (j = 0; j < 3; j++) { + p.org[j] = org[j] + ((Lib.rand() % 32) - 16); + p.vel[j] = (Lib.rand() % 256) - 128; + } + + p.accel[0] = p.accel[1] = 0; + p.accel[2] = -CL_fx.PARTICLE_GRAVITY; + p.alpha = 1.0f; + + p.alphavel = -0.4f / (0.6f + Globals.rnd.nextFloat() * 0.2f); + } + } + + /* + * =============== CL_ParticleSmokeEffect - like the steam effect, but + * unaffected by gravity =============== + */ + static void ParticleSmokeEffect(float[] org, float[] dir, int color, + int count, int magnitude) { + int i, j; + cparticle_t p; + float d; + float[] r = new float[3]; + float[] u = new float[3]; + + Math3D.MakeNormalVectors(dir, r, u); + + for (i = 0; i < count; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + + p.time = Globals.cl.time; + p.color = color + (Lib.rand() & 7); + + for (j = 0; j < 3; j++) { + p.org[j] = org[j] + magnitude * 0.1f * Lib.crand(); + // p.vel[j] = dir[j]*magnitude; + } + Math3D.VectorScale(dir, magnitude, p.vel); + d = Lib.crand() * magnitude / 3; + Math3D.VectorMA(p.vel, d, r, p.vel); + d = Lib.crand() * magnitude / 3; + Math3D.VectorMA(p.vel, d, u, p.vel); + + p.accel[0] = p.accel[1] = p.accel[2] = 0; + p.alpha = 1.0f; + + p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * 0.3f); + } + } + + /* + * =============== CL_BlasterParticles2 + * + * Wall impact puffs (Green) =============== + */ + static void BlasterParticles2(float[] org, float[] dir, long color) { + int i, j; + cparticle_t p; + float d; + int count; + + count = 40; + for (i = 0; i < count; i++) { + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + + p.time = Globals.cl.time; + p.color = color + (Lib.rand() & 7); + + d = Lib.rand() & 15; + for (j = 0; j < 3; j++) { + p.org[j] = org[j] + ((Lib.rand() & 7) - 4) + d * dir[j]; + p.vel[j] = dir[j] * 30 + Lib.crand() * 40; + } + + p.accel[0] = p.accel[1] = 0; + p.accel[2] = -CL_fx.PARTICLE_GRAVITY; + p.alpha = 1.0f; + + p.alphavel = -1.0f / (0.5f + Globals.rnd.nextFloat() * 0.3f); + } + } + + /* + * =============== CL_BlasterTrail2 + * + * Green! =============== + */ + static void BlasterTrail2(float[] start, float[] end) { + float[] move = new float[3]; + float[] vec = new float[3]; + float len; + int j; + cparticle_t p; + int dec; + + Math3D.VectorCopy(start, move); + Math3D.VectorSubtract(end, start, vec); + len = Math3D.VectorNormalize(vec); + + dec = 5; + Math3D.VectorScale(vec, 5, vec); + + // FIXME: this is a really silly way to have a loop + while (len > 0) { + len -= dec; + + if (CL_fx.free_particles == null) + return; + p = CL_fx.free_particles; + CL_fx.free_particles = p.next; + p.next = CL_fx.active_particles; + CL_fx.active_particles = p; + Math3D.VectorClear(p.accel); + + p.time = Globals.cl.time; + + p.alpha = 1.0f; + p.alphavel = -1.0f / (0.3f + Globals.rnd.nextFloat() * 0.2f); + p.color = 0xd0; + for (j = 0; j < 3; j++) { + p.org[j] = move[j] + Lib.crand(); + p.vel[j] = Lib.crand() * 5; + p.accel[j] = 0; + } + + Math3D.VectorAdd(move, vec, move); + } + } +} \ No newline at end of file diff --git a/src/jake2/client/CL_parse.java b/src/jake2/client/CL_parse.java index 432df25..ecc1abe 100644 --- a/src/jake2/client/CL_parse.java +++ b/src/jake2/client/CL_parse.java @@ -2,27 +2,27 @@ * CL_parse.java * Copyright (C) 2004 * - * $Id: CL_parse.java,v 1.8 2004-07-30 06:03:40 hzi Exp $ + * $Id: CL_parse.java,v 1.9 2004-09-22 19:22:07 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; import jake2.Defines; @@ -41,753 +41,750 @@ import java.io.RandomAccessFile; /** * CL_parse */ -public class CL_parse extends CL_view { - - //// cl_parse.c -- parse a message received from the server - - public static String svc_strings[] = - { - "svc_bad", - "svc_muzzleflash", - "svc_muzzlflash2", - "svc_temp_entity", - "svc_layout", - "svc_inventory", - "svc_nop", - "svc_disconnect", - "svc_reconnect", - "svc_sound", - "svc_print", - "svc_stufftext", - "svc_serverdata", - "svc_configstring", - "svc_spawnbaseline", - "svc_centerprint", - "svc_download", - "svc_playerinfo", - "svc_packetentities", - "svc_deltapacketentities", - "svc_frame" }; - - // ============================================================================= - - public static String DownloadFileName(String fn) { - if ("players".equals(fn)) - return BASEDIRNAME + "/" + fn; - else - return FS.Gamedir() + "/" + fn; - } - - /* - =============== - CL_CheckOrDownloadFile - - Returns true if the file exists, otherwise it attempts - to start a download from the server. - =============== - */ - public static boolean CheckOrDownloadFile(String filename) { - RandomAccessFile fp; - String name; - - if (filename.indexOf("..") != -1) { - Com.Printf("Refusing to download a path with ..\n"); - return true; - } - - if (FS.LoadFile(filename) != null) { // it exists, no need to download - return true; - } - - cls.downloadname = filename; - - // download to a temp name, and only rename - // to the real name when done, so if interrupted - // a runt file wont be left - cls.downloadtempname = Com.StripExtension(cls.downloadname); - cls.downloadtempname += ".tmp"; - - // ZOID - // check to see if we already have a tmp for this file, if so, try to resume - // open the file if not opened yet - name = DownloadFileName(cls.downloadtempname); - - fp = fopen(name, "r+b"); - if (fp != null) { // it exists - long len = 0; - - try { - len = fp.length(); - } - catch (IOException e) { - }; - - cls.download = fp; - - // give the server an offset to start the download - Com.Printf("Resuming " + cls.downloadname + "\n"); - MSG.WriteByte(cls.netchan.message, clc_stringcmd); - MSG.WriteString(cls.netchan.message, "download " + cls.downloadname + " " + len); - } - else { - cls.downloadname = cls.downloadname; - - Com.Printf("Downloading " + cls.downloadname + "\n"); - MSG.WriteByte(cls.netchan.message, clc_stringcmd); - MSG.WriteString(cls.netchan.message, "download " + cls.downloadname); - } - - cls.downloadnumber++; - - return false; - } - - /* - =============== - CL_Download_f - - Request a download from the server - =============== - */ - static xcommand_t Download_f = new xcommand_t() { - public void execute() { - String filename; - - if (Cmd.Argc() != 2) { - Com.Printf("Usage: download \n"); - return; - } - - filename = Cmd.Argv(1); - - if (filename.indexOf("..") != -1) { - Com.Printf("Refusing to download a path with ..\n"); - return; - } - - if (FS.LoadFile(filename) != null) { // it exists, no need to download - Com.Printf("File already exists.\n"); - return; - } - - cls.downloadname = filename; - Com.Printf("Downloading " + cls.downloadname + "\n"); - - // download to a temp name, and only rename - // to the real name when done, so if interrupted - // a runt file wont be left - cls.downloadtempname = Com.StripExtension(cls.downloadname); - cls.downloadtempname += ".tmp"; - - MSG.WriteByte(cls.netchan.message, clc_stringcmd); - MSG.WriteString(cls.netchan.message, "download " + cls.downloadname); - - cls.downloadnumber++; - } - }; - - /* - ====================== - CL_RegisterSounds - ====================== - */ - static void RegisterSounds() { - S.BeginRegistration(); - CL.RegisterTEntSounds(); - for (int i = 1; i < MAX_SOUNDS; i++) { - if (cl.configstrings[CS_SOUNDS + i] == null || cl.configstrings[CS_SOUNDS + i].equals("") || cl.configstrings[CS_SOUNDS + i].equals("\0")) - break; - cl.sound_precache[i] = S.RegisterSound(cl.configstrings[CS_SOUNDS + i]); - Sys.SendKeyEvents(); // pump message loop - } - S.EndRegistration(); - } - - /* - ===================== - CL_ParseDownload - - A download message has been received from the server - ===================== - */ - public static void ParseDownload() { - - // read the data - int size = MSG.ReadShort(net_message); - int percent = MSG.ReadByte(net_message); - if (size == -1) { - Com.Printf("Server does not have this file.\n"); - if (cls.download != null) { - // if here, we tried to resume a file but the server said no - try { - cls.download.close(); - } catch (IOException e) {} - cls.download = null; - } - CL.RequestNextDownload(); - return; - } - - // open the file if not opened yet - if (cls.download == null) { - String name = DownloadFileName(cls.downloadtempname); - - FS.CreatePath(name); - - cls.download = fopen(name, "rw"); - if (cls.download == null) { - net_message.readcount += size; - Com.Printf("Failed to open " + cls.downloadtempname + "\n"); - CL.RequestNextDownload(); - return; - } - } - - //fwrite(net_message.data[net_message.readcount], 1, size, cls.download); - try { - cls.download.write(net_message.data, net_message.readcount, size); - } - catch (Exception e) { - } - net_message.readcount += size; - - if (percent != 100) { - // request next block - // change display routines by zoid - - MSG.WriteByte(cls.netchan.message, clc_stringcmd); - SZ.Print(cls.netchan.message, "nextdl"); - } - else { - String oldn, newn; - //char oldn[MAX_OSPATH]; - //char newn[MAX_OSPATH]; - - // Com.Printf ("100%%\n"); - - try { - cls.download.close(); - } catch (IOException e) {} - - // rename the temp file to it's final name - oldn = DownloadFileName(cls.downloadtempname); - newn = DownloadFileName(cls.downloadname); - int r = Lib.rename(oldn, newn); - if (r != 0) - Com.Printf("failed to rename.\n"); - - cls.download = null; - cls.downloadpercent = 0; - - // get another file if needed - - CL.RequestNextDownload(); - } - } - - /* - ===================================================================== - - SERVER CONNECTING MESSAGES - - ===================================================================== - */ - - /* - ================== - CL_ParseServerData - ================== - */ - //checked once, was ok. - public static void ParseServerData() { - - String str; - int i; - - Com.DPrintf("Serverdata packet received.\n"); - // - // wipe the client_state_t struct - // - CL.ClearState(); - cls.state = ca_connected; - - // parse protocol version number - i = MSG.ReadLong(net_message); - cls.serverProtocol = i; - - // BIG HACK to let demos from release work with the 3.0x patch!!! - if (Globals.server_state != 0 && PROTOCOL_VERSION == 34) { - } - else if (i != PROTOCOL_VERSION) - Com.Error(ERR_DROP, "Server returned version " + i + ", not " + PROTOCOL_VERSION); - - cl.servercount = MSG.ReadLong(net_message); - cl.attractloop = MSG.ReadByte(net_message) != 0; - - // game directory - str = MSG.ReadString(net_message); - cl.gamedir = str; - - // set gamedir - if (str.length() > 0 - && (FS.fs_gamedirvar.string == null || FS.fs_gamedirvar.string.length() == 0 || FS.fs_gamedirvar.string.equals(str)) - || (str.length() == 0 && (FS.fs_gamedirvar.string != null || FS.fs_gamedirvar.string.length() == 0))) - Cvar.Set("game", str); - - // parse player entity number - cl.playernum = MSG.ReadShort(net_message); - - // get the full level name - str = MSG.ReadString(net_message); - - if (cl.playernum == -1) { // playing a cinematic or showing a pic, not a level - SCR.PlayCinematic(str); - } - else { - // seperate the printfs so the server message can have a color -// Com.Printf( -// "\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); -// Com.Printf('\02' + str + "\n"); - Com.Printf("Levelname:" + str + "\n"); - // need to prep refresh at next oportunity - cl.refresh_prepped = false; - } - } - - /* - ================== - CL_ParseBaseline - ================== - */ - public static void ParseBaseline() { - entity_state_t es; - int newnum; - - entity_state_t nullstate = new entity_state_t(null); - //memset(nullstate, 0, sizeof(nullstate)); - int bits[] = {0}; - newnum = CL_ents.ParseEntityBits(bits); - es = cl_entities[newnum].baseline; - CL_ents.ParseDelta(nullstate, es, newnum, bits[0]); - } - - /* - ================ - CL_LoadClientinfo - - ================ - */ - public static void LoadClientinfo(clientinfo_t ci, String s) { - int i; - int t; - - //char model_name[MAX_QPATH]; - //char skin_name[MAX_QPATH]; - //char model_filename[MAX_QPATH]; - //char skin_filename[MAX_QPATH]; - //char weapon_filename[MAX_QPATH]; - - String model_name,skin_name,model_filename, skin_filename, weapon_filename; - - ci.cinfo = s; - //ci.cinfo[sizeof(ci.cinfo) - 1] = 0; - - // isolate the player's name - ci.name = s; - //ci.name[sizeof(ci.name) - 1] = 0; - - t = s.indexOf('\\'); - //t = strstr(s, "\\"); - - if (t!=-1) { - ci.name = s.substring(0,t); - s = s.substring(t + 1, s.length()); - //s = t + 1; - } - - if (cl_noskins.value!=0 || s.length()!=0) { - - model_filename=("players/male/tris.md2"); - weapon_filename=("players/male/weapon.md2"); - skin_filename=("players/male/grunt.pcx"); - ci.iconname=("/players/male/grunt_i.pcx"); - - ci.model = re.RegisterModel(model_filename); - - ci.weaponmodel = new model_t[Defines.MAX_CLIENTWEAPONMODELS]; - ci.weaponmodel[0] = re.RegisterModel(weapon_filename); - ci.skin = re.RegisterSkin(skin_filename); - ci.icon = re.RegisterPic(ci.iconname); - } - else { - // isolate the model name - - int pos = s.indexOf('/'); - - if (pos == -1) - pos = s.indexOf('/'); - if (pos == -1) - { - pos =0; - Com.Error(Defines.ERR_FATAL, "Invalid model name:" + s); - } - - model_name = s.substring(0,pos); - - // isolate the skin name - skin_name = s.substring(pos+1, s.length()); - - // model file - model_filename = "players/" + model_name + "/tris.md2"; - ci.model = re.RegisterModel(model_filename); - - if (ci.model==null) { - model_name = "male"; - model_filename= "players/male/tris.md2"; - ci.model = re.RegisterModel(model_filename); - } - - // skin file - skin_filename = "players/" + model_name +"/"+ skin_name + ".pcx"; - ci.skin = re.RegisterSkin(skin_filename); - - // if we don't have the skin and the model wasn't male, - // see if the male has it (this is for CTF's skins) - if (ci.skin==null && !model_name.equalsIgnoreCase("male")) { - // change model to male - model_name = "male"; - model_filename= "players/male/tris.md2"; - ci.model = re.RegisterModel(model_filename); - - // see if the skin exists for the male model - skin_filename= "players/" + model_name + "/"+ skin_name+".pcx"; - ci.skin = re.RegisterSkin(skin_filename); - } - - // if we still don't have a skin, it means that the male model didn't have - // it, so default to grunt - if (ci.skin==null) { - // see if the skin exists for the male model - skin_filename= "players/" + model_name + "/grunt.pcx"; - ci.skin = re.RegisterSkin(skin_filename); - } - - // weapon file - for (i = 0; i < num_cl_weaponmodels; i++) { - weapon_filename= "players/"+model_name +"/" + cl_weaponmodels[i]; - ci.weaponmodel[i] = re.RegisterModel(weapon_filename); - if (null==ci.weaponmodel[i] && model_name.equals("cyborg")) { - // try male - weapon_filename="players/male/" + cl_weaponmodels[i]; - ci.weaponmodel[i] = re.RegisterModel(weapon_filename); - } - if (0==cl_vwep.value) - break; // only one when vwep is off - } - - // icon file - ci.iconname= "/players/"+model_name+"/" + skin_name+"_i.pcx"; - ci.icon = re.RegisterPic(ci.iconname); - } - - // must have loaded all data types to be valud - if (ci.skin==null || ci.icon==null || ci.model==null || ci.weaponmodel[0]==null) { - ci.skin = null; - ci.icon = null; - ci.model = null; - ci.weaponmodel[0] = null; - return; - } - } - - /* - ================ - CL_ParseClientinfo - - Load the skin, icon, and model for a client - ================ - */ - static void ParseClientinfo(int player) { - String s; - clientinfo_t ci; - - s = cl.configstrings[player + CS_PLAYERSKINS]; - - ci = cl.clientinfo[player]; - - LoadClientinfo(ci, s); - } - - /* - ================ - CL_ParseConfigString - ================ - */ - public static void ParseConfigString() { - int i; - String s; - String olds; - - i = MSG.ReadShort(net_message); - - if (i < 0 || i >= MAX_CONFIGSTRINGS) - Com.Error(ERR_DROP, "configstring > MAX_CONFIGSTRINGS"); - - s = MSG.ReadString(net_message); - - olds=cl.configstrings[i]; - cl.configstrings[i] = s; - - // do something apropriate - - if (i >= CS_LIGHTS && i < CS_LIGHTS + MAX_LIGHTSTYLES) { - SetLightstyle(i - CS_LIGHTS); - } - else if (i >= CS_MODELS && i < CS_MODELS + MAX_MODELS) { - if (cl.refresh_prepped) { - cl.model_draw[i - CS_MODELS] = re.RegisterModel(cl.configstrings[i]); - if (cl.configstrings[i].startsWith("*")) - cl.model_clip[i - CS_MODELS] = CM.InlineModel(cl.configstrings[i]); - else - cl.model_clip[i - CS_MODELS] = null; - } - } - else if (i >= CS_SOUNDS && i < CS_SOUNDS + MAX_MODELS) { - if (cl.refresh_prepped) - cl.sound_precache[i - CS_SOUNDS] = S.RegisterSound(cl.configstrings[i]); - } - else if (i >= CS_IMAGES && i < CS_IMAGES + MAX_MODELS) { - if (cl.refresh_prepped) - cl.image_precache[i - CS_IMAGES] = re.RegisterPic(cl.configstrings[i]); - } - else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS + MAX_CLIENTS) { - if (cl.refresh_prepped && !olds.equals(s)) - ParseClientinfo(i - CS_PLAYERSKINS); - } - } - - /* - ===================================================================== - - ACTION MESSAGES - - ===================================================================== - */ - - /* - ================== - CL_ParseStartSoundPacket - ================== - */ - public static void ParseStartSoundPacket() { - float[] pos_v={0,0,0}; - float pos[]; - int channel, ent; - int sound_num; - float volume; - float attenuation; - int flags; - float ofs; - - flags = MSG.ReadByte(net_message); - sound_num = MSG.ReadByte(net_message); - - if ((flags & SND_VOLUME) != 0) - volume = MSG.ReadByte(net_message) / 255.0f; - else - volume = DEFAULT_SOUND_PACKET_VOLUME; - - if ((flags & SND_ATTENUATION) != 0) - attenuation = MSG.ReadByte(net_message) / 64.0f; - else - attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; - - if ((flags & SND_OFFSET) != 0) - ofs = MSG.ReadByte(net_message) / 1000.0f; - else - ofs = 0; - - if ((flags & SND_ENT) != 0) { // entity reletive - channel = MSG.ReadShort(net_message); - ent = channel >> 3; - if (ent > MAX_EDICTS) - Com.Error(ERR_DROP, "CL_ParseStartSoundPacket: ent = " + ent); - - channel &= 7; - } - else { - ent = 0; - channel = 0; - } - - if ((flags & SND_POS) != 0) { // positioned in space - MSG.ReadPos(net_message, pos_v); - - pos = pos_v; - } - else // use entity number - pos = null; - - if (null==cl.sound_precache[sound_num]) - return; - - S.StartSound(pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs); - } - - public static void SHOWNET(String s) { - if (cl_shownet.value >= 2) - Com.Printf(net_message.readcount - 1 + ":" + s + "\n"); - } - - /* - ===================== - CL_ParseServerMessage - ===================== - */ - public static void ParseServerMessage() { - int cmd; - String s; - int i; - - // - // if recording demos, copy the message out - // - //if (cl_shownet.value == 1) - //Com.Printf(net_message.cursize + " "); - //else if (cl_shownet.value >= 2) - //Com.Printf("------------------\n"); - - // - // parse the message - // - while (true) { - if (net_message.readcount > net_message.cursize) { - Com.Error(ERR_FATAL, "CL_ParseServerMessage: Bad server message:"); - break; - } - - cmd = MSG.ReadByte(net_message); - - if (cmd == -1) { - SHOWNET("END OF MESSAGE"); - break; - } - - if (cl_shownet.value >= 2) { - if (null == svc_strings[cmd]) - Com.Printf(net_message.readcount - 1 + ":BAD CMD " + cmd + "\n"); - else - SHOWNET(svc_strings[cmd]); - } - - // other commands - switch (cmd) { - default : - Com.Error(ERR_DROP, "CL_ParseServerMessage: Illegible server message\n"); - break; - - case svc_nop : - // Com.Printf ("svc_nop\n"); - break; - - case svc_disconnect : - Com.Error(ERR_DISCONNECT, "Server disconnected\n"); - break; - - case svc_reconnect : - Com.Printf("Server disconnected, reconnecting\n"); - if (cls.download != null) { - //ZOID, close download - try { - cls.download.close(); - } catch (IOException e) {} - cls.download = null; - } - cls.state = ca_connecting; - cls.connect_time = -99999; // CL_CheckForResend() will fire immediately - break; - - case svc_print : - i = MSG.ReadByte(net_message); - if (i == PRINT_CHAT) { - S.StartLocalSound("misc/talk.wav"); - con.ormask = 128; - } - Com.Printf(MSG.ReadString(net_message)); - con.ormask = 0; - break; - - case svc_centerprint : - SCR.CenterPrint(MSG.ReadString(net_message)); - break; - - case svc_stufftext : - s = MSG.ReadString(net_message); - Com.DPrintf("stufftext: " + s + "\n"); - Cbuf.AddText(s); - break; - - case svc_serverdata : - Cbuf.Execute(); // make sure any stuffed commands are done - ParseServerData(); - break; - - case svc_configstring : - ParseConfigString(); - break; - - case svc_sound : - ParseStartSoundPacket(); - break; - - case svc_spawnbaseline : - ParseBaseline(); - break; - - case svc_temp_entity : - ParseTEnt(); - break; - - case svc_muzzleflash : - CL_fx.ParseMuzzleFlash(); - break; - - case svc_muzzleflash2 : - ParseMuzzleFlash2(); - break; - - case svc_download : - ParseDownload(); - break; - - case svc_frame : - ParseFrame(); - break; - - case svc_inventory : - CL_inv.ParseInventory(); - break; - - case svc_layout : - s = MSG.ReadString(net_message); - cl.layout = s; - break; - - case svc_playerinfo : - case svc_packetentities : - case svc_deltapacketentities : - Com.Error(ERR_DROP, "Out of place frame data"); - break; - } - } - - CL_view.AddNetgraph(); - - // - // we don't know if it is ok to save a demo message until - // after we have parsed the frame - // - if (cls.demorecording && !cls.demowaiting) - CL.WriteDemoMessage(); - } -} +public class CL_parse { + + //// cl_parse.c -- parse a message received from the server + + public static String svc_strings[] = { "svc_bad", "svc_muzzleflash", + "svc_muzzlflash2", "svc_temp_entity", "svc_layout", + "svc_inventory", "svc_nop", "svc_disconnect", "svc_reconnect", + "svc_sound", "svc_print", "svc_stufftext", "svc_serverdata", + "svc_configstring", "svc_spawnbaseline", "svc_centerprint", + "svc_download", "svc_playerinfo", "svc_packetentities", + "svc_deltapacketentities", "svc_frame" }; + + // ============================================================================= + + public static String DownloadFileName(String fn) { + if ("players".equals(fn)) + return Globals.BASEDIRNAME + "/" + fn; + else + return FS.Gamedir() + "/" + fn; + } + + /* + * =============== CL_CheckOrDownloadFile + * + * Returns true if the file exists, otherwise it attempts to start a + * download from the server. =============== + */ + public static boolean CheckOrDownloadFile(String filename) { + RandomAccessFile fp; + String name; + + if (filename.indexOf("..") != -1) { + Com.Printf("Refusing to download a path with ..\n"); + return true; + } + + if (FS.LoadFile(filename) != null) { // it exists, no need to download + return true; + } + + Globals.cls.downloadname = filename; + + // download to a temp name, and only rename + // to the real name when done, so if interrupted + // a runt file wont be left + Globals.cls.downloadtempname = Com + .StripExtension(Globals.cls.downloadname); + Globals.cls.downloadtempname += ".tmp"; + + // ZOID + // check to see if we already have a tmp for this file, if so, try to + // resume + // open the file if not opened yet + name = DownloadFileName(Globals.cls.downloadtempname); + + fp = Lib.fopen(name, "r+b"); + if (fp != null) { // it exists + long len = 0; + + try { + len = fp.length(); + } catch (IOException e) { + } + ; + + Globals.cls.download = fp; + + // give the server an offset to start the download + Com.Printf("Resuming " + Globals.cls.downloadname + "\n"); + MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd); + MSG.WriteString(Globals.cls.netchan.message, "download " + + Globals.cls.downloadname + " " + len); + } else { + Globals.cls.downloadname = Globals.cls.downloadname; + + Com.Printf("Downloading " + Globals.cls.downloadname + "\n"); + MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd); + MSG.WriteString(Globals.cls.netchan.message, "download " + + Globals.cls.downloadname); + } + + Globals.cls.downloadnumber++; + + return false; + } + + /* + * =============== CL_Download_f + * + * Request a download from the server =============== + */ + public static xcommand_t Download_f = new xcommand_t() { + public void execute() { + String filename; + + if (Cmd.Argc() != 2) { + Com.Printf("Usage: download \n"); + return; + } + + filename = Cmd.Argv(1); + + if (filename.indexOf("..") != -1) { + Com.Printf("Refusing to download a path with ..\n"); + return; + } + + if (FS.LoadFile(filename) != null) { // it exists, no need to + // download + Com.Printf("File already exists.\n"); + return; + } + + Globals.cls.downloadname = filename; + Com.Printf("Downloading " + Globals.cls.downloadname + "\n"); + + // download to a temp name, and only rename + // to the real name when done, so if interrupted + // a runt file wont be left + Globals.cls.downloadtempname = Com + .StripExtension(Globals.cls.downloadname); + Globals.cls.downloadtempname += ".tmp"; + + MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd); + MSG.WriteString(Globals.cls.netchan.message, "download " + + Globals.cls.downloadname); + + Globals.cls.downloadnumber++; + } + }; + + /* + * ====================== CL_RegisterSounds ====================== + */ + public static void RegisterSounds() { + S.BeginRegistration(); + CL_tent.RegisterTEntSounds(); + for (int i = 1; i < Defines.MAX_SOUNDS; i++) { + if (Globals.cl.configstrings[Defines.CS_SOUNDS + i] == null + || Globals.cl.configstrings[Defines.CS_SOUNDS + i] + .equals("") + || Globals.cl.configstrings[Defines.CS_SOUNDS + i] + .equals("\0")) + break; + Globals.cl.sound_precache[i] = S + .RegisterSound(Globals.cl.configstrings[Defines.CS_SOUNDS + + i]); + Sys.SendKeyEvents(); // pump message loop + } + S.EndRegistration(); + } + + /* + * ===================== CL_ParseDownload + * + * A download message has been received from the server + * ===================== + */ + public static void ParseDownload() { + + // read the data + int size = MSG.ReadShort(Globals.net_message); + int percent = MSG.ReadByte(Globals.net_message); + if (size == -1) { + Com.Printf("Server does not have this file.\n"); + if (Globals.cls.download != null) { + // if here, we tried to resume a file but the server said no + try { + Globals.cls.download.close(); + } catch (IOException e) { + } + Globals.cls.download = null; + } + CL.RequestNextDownload(); + return; + } + + // open the file if not opened yet + if (Globals.cls.download == null) { + String name = DownloadFileName(Globals.cls.downloadtempname); + + FS.CreatePath(name); + + Globals.cls.download = Lib.fopen(name, "rw"); + if (Globals.cls.download == null) { + Globals.net_message.readcount += size; + Com.Printf("Failed to open " + Globals.cls.downloadtempname + + "\n"); + CL.RequestNextDownload(); + return; + } + } + + //fwrite(net_message.data[net_message.readcount], 1, size, + // cls.download); + try { + Globals.cls.download.write(Globals.net_message.data, + Globals.net_message.readcount, size); + } catch (Exception e) { + } + Globals.net_message.readcount += size; + + if (percent != 100) { + // request next block + // change display routines by zoid + + MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd); + SZ.Print(Globals.cls.netchan.message, "nextdl"); + } else { + String oldn, newn; + //char oldn[MAX_OSPATH]; + //char newn[MAX_OSPATH]; + + // Com.Printf ("100%%\n"); + + try { + Globals.cls.download.close(); + } catch (IOException e) { + } + + // rename the temp file to it's final name + oldn = DownloadFileName(Globals.cls.downloadtempname); + newn = DownloadFileName(Globals.cls.downloadname); + int r = Lib.rename(oldn, newn); + if (r != 0) + Com.Printf("failed to rename.\n"); + + Globals.cls.download = null; + Globals.cls.downloadpercent = 0; + + // get another file if needed + + CL.RequestNextDownload(); + } + } + + /* + * ===================================================================== + * + * SERVER CONNECTING MESSAGES + * + * ===================================================================== + */ + + /* + * ================== CL_ParseServerData ================== + */ + //checked once, was ok. + public static void ParseServerData() { + + String str; + int i; + + Com.DPrintf("Serverdata packet received.\n"); + // + // wipe the client_state_t struct + // + CL.ClearState(); + Globals.cls.state = Defines.ca_connected; + + // parse protocol version number + i = MSG.ReadLong(Globals.net_message); + Globals.cls.serverProtocol = i; + + // BIG HACK to let demos from release work with the 3.0x patch!!! + if (Globals.server_state != 0 && Defines.PROTOCOL_VERSION == 34) { + } else if (i != Defines.PROTOCOL_VERSION) + Com.Error(Defines.ERR_DROP, "Server returned version " + i + + ", not " + Defines.PROTOCOL_VERSION); + + Globals.cl.servercount = MSG.ReadLong(Globals.net_message); + Globals.cl.attractloop = MSG.ReadByte(Globals.net_message) != 0; + + // game directory + str = MSG.ReadString(Globals.net_message); + Globals.cl.gamedir = str; + + // set gamedir + if (str.length() > 0 + && (FS.fs_gamedirvar.string == null + || FS.fs_gamedirvar.string.length() == 0 || FS.fs_gamedirvar.string + .equals(str)) + || (str.length() == 0 && (FS.fs_gamedirvar.string != null || FS.fs_gamedirvar.string + .length() == 0))) + Cvar.Set("game", str); + + // parse player entity number + Globals.cl.playernum = MSG.ReadShort(Globals.net_message); + + // get the full level name + str = MSG.ReadString(Globals.net_message); + + if (Globals.cl.playernum == -1) { // playing a cinematic or showing a + // pic, not a level + SCR.PlayCinematic(str); + } else { + // seperate the printfs so the server message can have a color + // Com.Printf( + // "\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); + // Com.Printf('\02' + str + "\n"); + Com.Printf("Levelname:" + str + "\n"); + // need to prep refresh at next oportunity + Globals.cl.refresh_prepped = false; + } + } + + /* + * ================== CL_ParseBaseline ================== + */ + public static void ParseBaseline() { + entity_state_t es; + int newnum; + + entity_state_t nullstate = new entity_state_t(null); + //memset(nullstate, 0, sizeof(nullstate)); + int bits[] = { 0 }; + newnum = CL_ents.ParseEntityBits(bits); + es = Globals.cl_entities[newnum].baseline; + CL_ents.ParseDelta(nullstate, es, newnum, bits[0]); + } + + /* + * ================ CL_LoadClientinfo + * + * ================ + */ + public static void LoadClientinfo(clientinfo_t ci, String s) { + int i; + int t; + + //char model_name[MAX_QPATH]; + //char skin_name[MAX_QPATH]; + //char model_filename[MAX_QPATH]; + //char skin_filename[MAX_QPATH]; + //char weapon_filename[MAX_QPATH]; + + String model_name, skin_name, model_filename, skin_filename, weapon_filename; + + ci.cinfo = s; + //ci.cinfo[sizeof(ci.cinfo) - 1] = 0; + + // isolate the player's name + ci.name = s; + //ci.name[sizeof(ci.name) - 1] = 0; + + t = s.indexOf('\\'); + //t = strstr(s, "\\"); + + if (t != -1) { + ci.name = s.substring(0, t); + s = s.substring(t + 1, s.length()); + //s = t + 1; + } + + if (Globals.cl_noskins.value != 0 || s.length() != 0) { + + model_filename = ("players/male/tris.md2"); + weapon_filename = ("players/male/weapon.md2"); + skin_filename = ("players/male/grunt.pcx"); + ci.iconname = ("/players/male/grunt_i.pcx"); + + ci.model = Globals.re.RegisterModel(model_filename); + + ci.weaponmodel = new model_t[Defines.MAX_CLIENTWEAPONMODELS]; + ci.weaponmodel[0] = Globals.re.RegisterModel(weapon_filename); + ci.skin = Globals.re.RegisterSkin(skin_filename); + ci.icon = Globals.re.RegisterPic(ci.iconname); + } else { + // isolate the model name + + int pos = s.indexOf('/'); + + if (pos == -1) + pos = s.indexOf('/'); + if (pos == -1) { + pos = 0; + Com.Error(Defines.ERR_FATAL, "Invalid model name:" + s); + } + + model_name = s.substring(0, pos); + + // isolate the skin name + skin_name = s.substring(pos + 1, s.length()); + + // model file + model_filename = "players/" + model_name + "/tris.md2"; + ci.model = Globals.re.RegisterModel(model_filename); + + if (ci.model == null) { + model_name = "male"; + model_filename = "players/male/tris.md2"; + ci.model = Globals.re.RegisterModel(model_filename); + } + + // skin file + skin_filename = "players/" + model_name + "/" + skin_name + ".pcx"; + ci.skin = Globals.re.RegisterSkin(skin_filename); + + // if we don't have the skin and the model wasn't male, + // see if the male has it (this is for CTF's skins) + if (ci.skin == null && !model_name.equalsIgnoreCase("male")) { + // change model to male + model_name = "male"; + model_filename = "players/male/tris.md2"; + ci.model = Globals.re.RegisterModel(model_filename); + + // see if the skin exists for the male model + skin_filename = "players/" + model_name + "/" + skin_name + + ".pcx"; + ci.skin = Globals.re.RegisterSkin(skin_filename); + } + + // if we still don't have a skin, it means that the male model + // didn't have + // it, so default to grunt + if (ci.skin == null) { + // see if the skin exists for the male model + skin_filename = "players/" + model_name + "/grunt.pcx"; + ci.skin = Globals.re.RegisterSkin(skin_filename); + } + + // weapon file + for (i = 0; i < CL_view.num_cl_weaponmodels; i++) { + weapon_filename = "players/" + model_name + "/" + + CL_view.cl_weaponmodels[i]; + ci.weaponmodel[i] = Globals.re.RegisterModel(weapon_filename); + if (null == ci.weaponmodel[i] && model_name.equals("cyborg")) { + // try male + weapon_filename = "players/male/" + + CL_view.cl_weaponmodels[i]; + ci.weaponmodel[i] = Globals.re + .RegisterModel(weapon_filename); + } + if (0 == Globals.cl_vwep.value) + break; // only one when vwep is off + } + + // icon file + ci.iconname = "/players/" + model_name + "/" + skin_name + "_i.pcx"; + ci.icon = Globals.re.RegisterPic(ci.iconname); + } + + // must have loaded all data types to be valud + if (ci.skin == null || ci.icon == null || ci.model == null + || ci.weaponmodel[0] == null) { + ci.skin = null; + ci.icon = null; + ci.model = null; + ci.weaponmodel[0] = null; + return; + } + } + + /* + * ================ CL_ParseClientinfo + * + * Load the skin, icon, and model for a client ================ + */ + public static void ParseClientinfo(int player) { + String s; + clientinfo_t ci; + + s = Globals.cl.configstrings[player + Defines.CS_PLAYERSKINS]; + + ci = Globals.cl.clientinfo[player]; + + LoadClientinfo(ci, s); + } + + /* + * ================ CL_ParseConfigString ================ + */ + public static void ParseConfigString() { + int i; + String s; + String olds; + + i = MSG.ReadShort(Globals.net_message); + + if (i < 0 || i >= Defines.MAX_CONFIGSTRINGS) + Com.Error(Defines.ERR_DROP, "configstring > MAX_CONFIGSTRINGS"); + + s = MSG.ReadString(Globals.net_message); + + olds = Globals.cl.configstrings[i]; + Globals.cl.configstrings[i] = s; + + // do something apropriate + + if (i >= Defines.CS_LIGHTS + && i < Defines.CS_LIGHTS + Defines.MAX_LIGHTSTYLES) { + CL_fx.SetLightstyle(i - Defines.CS_LIGHTS); + } else if (i >= Defines.CS_MODELS + && i < Defines.CS_MODELS + Defines.MAX_MODELS) { + if (Globals.cl.refresh_prepped) { + Globals.cl.model_draw[i - Defines.CS_MODELS] = Globals.re + .RegisterModel(Globals.cl.configstrings[i]); + if (Globals.cl.configstrings[i].startsWith("*")) + Globals.cl.model_clip[i - Defines.CS_MODELS] = CM + .InlineModel(Globals.cl.configstrings[i]); + else + Globals.cl.model_clip[i - Defines.CS_MODELS] = null; + } + } else if (i >= Defines.CS_SOUNDS + && i < Defines.CS_SOUNDS + Defines.MAX_MODELS) { + if (Globals.cl.refresh_prepped) + Globals.cl.sound_precache[i - Defines.CS_SOUNDS] = S + .RegisterSound(Globals.cl.configstrings[i]); + } else if (i >= Defines.CS_IMAGES + && i < Defines.CS_IMAGES + Defines.MAX_MODELS) { + if (Globals.cl.refresh_prepped) + Globals.cl.image_precache[i - Defines.CS_IMAGES] = Globals.re + .RegisterPic(Globals.cl.configstrings[i]); + } else if (i >= Defines.CS_PLAYERSKINS + && i < Defines.CS_PLAYERSKINS + Defines.MAX_CLIENTS) { + if (Globals.cl.refresh_prepped && !olds.equals(s)) + ParseClientinfo(i - Defines.CS_PLAYERSKINS); + } + } + + /* + * ===================================================================== + * + * ACTION MESSAGES + * + * ===================================================================== + */ + + /* + * ================== CL_ParseStartSoundPacket ================== + */ + public static void ParseStartSoundPacket() { + float[] pos_v = { 0, 0, 0 }; + float pos[]; + int channel, ent; + int sound_num; + float volume; + float attenuation; + int flags; + float ofs; + + flags = MSG.ReadByte(Globals.net_message); + sound_num = MSG.ReadByte(Globals.net_message); + + if ((flags & Defines.SND_VOLUME) != 0) + volume = MSG.ReadByte(Globals.net_message) / 255.0f; + else + volume = Defines.DEFAULT_SOUND_PACKET_VOLUME; + + if ((flags & Defines.SND_ATTENUATION) != 0) + attenuation = MSG.ReadByte(Globals.net_message) / 64.0f; + else + attenuation = Defines.DEFAULT_SOUND_PACKET_ATTENUATION; + + if ((flags & Defines.SND_OFFSET) != 0) + ofs = MSG.ReadByte(Globals.net_message) / 1000.0f; + else + ofs = 0; + + if ((flags & Defines.SND_ENT) != 0) { // entity reletive + channel = MSG.ReadShort(Globals.net_message); + ent = channel >> 3; + if (ent > Defines.MAX_EDICTS) + Com.Error(Defines.ERR_DROP, "CL_ParseStartSoundPacket: ent = " + + ent); + + channel &= 7; + } else { + ent = 0; + channel = 0; + } + + if ((flags & Defines.SND_POS) != 0) { // positioned in space + MSG.ReadPos(Globals.net_message, pos_v); + + pos = pos_v; + } else + // use entity number + pos = null; + + if (null == Globals.cl.sound_precache[sound_num]) + return; + + S.StartSound(pos, ent, channel, Globals.cl.sound_precache[sound_num], + volume, attenuation, ofs); + } + + public static void SHOWNET(String s) { + if (Globals.cl_shownet.value >= 2) + Com.Printf(Globals.net_message.readcount - 1 + ":" + s + "\n"); + } + + /* + * ===================== CL_ParseServerMessage ===================== + */ + public static void ParseServerMessage() { + int cmd; + String s; + int i; + + // + // if recording demos, copy the message out + // + //if (cl_shownet.value == 1) + //Com.Printf(net_message.cursize + " "); + //else if (cl_shownet.value >= 2) + //Com.Printf("------------------\n"); + + // + // parse the message + // + while (true) { + if (Globals.net_message.readcount > Globals.net_message.cursize) { + Com.Error(Defines.ERR_FATAL, + "CL_ParseServerMessage: Bad server message:"); + break; + } + + cmd = MSG.ReadByte(Globals.net_message); + + if (cmd == -1) { + SHOWNET("END OF MESSAGE"); + break; + } + + if (Globals.cl_shownet.value >= 2) { + if (null == svc_strings[cmd]) + Com.Printf(Globals.net_message.readcount - 1 + ":BAD CMD " + + cmd + "\n"); + else + SHOWNET(svc_strings[cmd]); + } + + // other commands + switch (cmd) { + default: + Com.Error(Defines.ERR_DROP, + "CL_ParseServerMessage: Illegible server message\n"); + break; + + case Defines.svc_nop: + // Com.Printf ("svc_nop\n"); + break; + + case Defines.svc_disconnect: + Com.Error(Defines.ERR_DISCONNECT, "Server disconnected\n"); + break; + + case Defines.svc_reconnect: + Com.Printf("Server disconnected, reconnecting\n"); + if (Globals.cls.download != null) { + //ZOID, close download + try { + Globals.cls.download.close(); + } catch (IOException e) { + } + Globals.cls.download = null; + } + Globals.cls.state = Defines.ca_connecting; + Globals.cls.connect_time = -99999; // CL_CheckForResend() will + // fire immediately + break; + + case Defines.svc_print: + i = MSG.ReadByte(Globals.net_message); + if (i == Defines.PRINT_CHAT) { + S.StartLocalSound("misc/talk.wav"); + Globals.con.ormask = 128; + } + Com.Printf(MSG.ReadString(Globals.net_message)); + Globals.con.ormask = 0; + break; + + case Defines.svc_centerprint: + SCR.CenterPrint(MSG.ReadString(Globals.net_message)); + break; + + case Defines.svc_stufftext: + s = MSG.ReadString(Globals.net_message); + Com.DPrintf("stufftext: " + s + "\n"); + Cbuf.AddText(s); + break; + + case Defines.svc_serverdata: + Cbuf.Execute(); // make sure any stuffed commands are done + ParseServerData(); + break; + + case Defines.svc_configstring: + ParseConfigString(); + break; + + case Defines.svc_sound: + ParseStartSoundPacket(); + break; + + case Defines.svc_spawnbaseline: + ParseBaseline(); + break; + + case Defines.svc_temp_entity: + CL_tent.ParseTEnt(); + break; + + case Defines.svc_muzzleflash: + CL_fx.ParseMuzzleFlash(); + break; + + case Defines.svc_muzzleflash2: + CL_fx.ParseMuzzleFlash2(); + break; + + case Defines.svc_download: + ParseDownload(); + break; + + case Defines.svc_frame: + CL_ents.ParseFrame(); + break; + + case Defines.svc_inventory: + CL_inv.ParseInventory(); + break; + + case Defines.svc_layout: + s = MSG.ReadString(Globals.net_message); + Globals.cl.layout = s; + break; + + case Defines.svc_playerinfo: + case Defines.svc_packetentities: + case Defines.svc_deltapacketentities: + Com.Error(Defines.ERR_DROP, "Out of place frame data"); + break; + } + } + + CL_view.AddNetgraph(); + + // + // we don't know if it is ok to save a demo message until + // after we have parsed the frame + // + if (Globals.cls.demorecording && !Globals.cls.demowaiting) + CL.WriteDemoMessage(); + } +} \ No newline at end of file diff --git a/src/jake2/client/CL_pred.java b/src/jake2/client/CL_pred.java index 7f6a279..4b07099 100644 --- a/src/jake2/client/CL_pred.java +++ b/src/jake2/client/CL_pred.java @@ -2,286 +2,302 @@ * CL_pred.java * Copyright (C) 2004 * - * $Id: CL_pred.java,v 1.4 2004-07-19 19:20:22 hzi Exp $ + * $Id: CL_pred.java,v 1.5 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; +import jake2.Defines; +import jake2.Globals; +import jake2.Defines; +import jake2.game.pmove_t.PointContentsAdapter; +import jake2.game.pmove_t.TraceAdapter; + +import jake2.Globals; import jake2.game.*; import jake2.qcommon.*; +import jake2.util.Math3D; /** * CL_pred */ -public class CL_pred extends CL_parse { - - /* - =================== - CL_CheckPredictionError - =================== - */ - static void CheckPredictionError() { - int frame; - int[] delta = new int[3]; - int i; - int len; - - if (cl_predict.value == 0.0f || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION) != 0) - return; - - // calculate the last usercmd_t we sent that the server has processed - frame = cls.netchan.incoming_acknowledged; - frame &= (CMD_BACKUP - 1); - - // compare what the server returned with what we had predicted it to be - VectorSubtract(cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta); - - // save the prediction error for interpolation - len = Math.abs(delta[0]) + Math.abs(delta[1]) + Math.abs(delta[2]); - if (len > 640) // 80 world units - { // a teleport or something - VectorClear(cl.prediction_error); - } - else { - if (cl_showmiss.value != 0.0f && (delta[0] != 0 || delta[1] != 0 || delta[2] != 0)) - Com.Printf("prediction miss on " + cl.frame.serverframe + ": " + (delta[0] + delta[1] + delta[2]) + "\n"); - - VectorCopy(cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]); - - // save for error itnerpolation - for (i = 0; i < 3; i++) - cl.prediction_error[i] = delta[i] * 0.125f; - } - } - - /* - ==================== - CL_ClipMoveToEntities - - ==================== - */ - static void ClipMoveToEntities(float[] start, float[] mins, float[] maxs, float[] end, trace_t tr) { - int i, x, zd, zu; - trace_t trace; - int headnode; - float[] angles; - entity_state_t ent; - int num; - cmodel_t cmodel; - float[] bmins = new float[3]; - float[] bmaxs = new float[3]; - - for (i = 0; i < cl.frame.num_entities; i++) { - num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1); - ent = cl_parse_entities[num]; - - if (ent.solid == 0) - continue; - - if (ent.number == cl.playernum + 1) - continue; - - if (ent.solid == 31) { // special value for bmodel - cmodel = cl.model_clip[ent.modelindex]; - if (cmodel == null) - continue; - headnode = cmodel.headnode; - angles = ent.angles; - } - else { // encoded bbox - x = 8 * (ent.solid & 31); - zd = 8 * ((ent.solid >>> 5) & 31); - zu = 8 * ((ent.solid >>> 10) & 63) - 32; - - bmins[0] = bmins[1] = -x; - bmaxs[0] = bmaxs[1] = x; - bmins[2] = -zd; - bmaxs[2] = zu; - - headnode = CM.HeadnodeForBox(bmins, bmaxs); - angles = vec3_origin; // boxes don't rotate - } - - if (tr.allsolid) - return; - - trace = CM.TransformedBoxTrace(start, end, mins, maxs, headnode, MASK_PLAYERSOLID, ent.origin, angles); - - if (trace.allsolid || trace.startsolid || trace.fraction < tr.fraction) { - trace.ent = ent.surrounding_ent; - if (tr.startsolid) { - tr.set(trace); // rst: solved the Z U P P E L - P R O B L E M - tr.startsolid = true; - } - else - tr.set(trace); // rst: solved the Z U P P E L - P R O B L E M - } - else if (trace.startsolid) - tr.startsolid = true; - } - } - - /* - ================ - CL_PMTrace - ================ - */ - - public static edict_t DUMMY_ENT = new edict_t(-1); - - static trace_t PMTrace(float[] start, float[] mins, float[] maxs, float[] end) { - trace_t t; - - // check against world - t = CM.BoxTrace(start, end, mins, maxs, 0, MASK_PLAYERSOLID); - - if (t.fraction < 1.0f) { - t.ent = DUMMY_ENT; - } - - // check all other solid models - CL.ClipMoveToEntities(start, mins, maxs, end, t); - - return t; - } - - /* - ================= - PMpointcontents - - Returns the content identificator of the point. - ================= - */ - static int PMpointcontents(float[] point) { - int i; - entity_state_t ent; - int num; - cmodel_t cmodel; - int contents; - - contents = CM.PointContents(point, 0); - - for (i = 0; i < cl.frame.num_entities; i++) { - num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1); - ent = cl_parse_entities[num]; - - if (ent.solid != 31) // special value for bmodel - continue; - - cmodel = cl.model_clip[ent.modelindex]; - if (cmodel == null) - continue; - - contents |= CM.TransformedPointContents(point, cmodel.headnode, ent.origin, ent.angles); - } - return contents; - } - - /* - ================= - CL_PredictMovement - - Sets cl.predicted_origin and cl.predicted_angles - ================= - */ - static void PredictMovement() { - - if (cls.state != ca_active) - return; - - if (cl_paused.value != 0.0f) - return; - - if (cl_predict.value == 0.0f || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION) != 0) { - // just set angles - for (int i = 0; i < 3; i++) { - cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]); - } - return; - } - - int ack = cls.netchan.incoming_acknowledged; - int current = cls.netchan.outgoing_sequence; - - // if we are too far out of date, just freeze - if (current - ack >= CMD_BACKUP) { - if (cl_showmiss.value != 0.0f) - Com.Printf("exceeded CMD_BACKUP\n"); - return; - } - - // copy current state to pmove - //memset (pm, 0, sizeof(pm)); - pmove_t pm = new pmove_t(); - - pm.trace = new pmove_t.TraceAdapter() { - public trace_t trace(float[] start, float[] mins, float[] maxs, float[] end) { - return CL.PMTrace(start, mins, maxs, end); - } - }; - pm.pointcontents = new pmove_t.PointContentsAdapter() { - public int pointcontents(float[] point) { - return CL.PMpointcontents(point); - } - }; - - try { - PMove.pm_airaccelerate = Float.parseFloat(cl.configstrings[CS_AIRACCEL]); - } catch (Exception e) { - PMove.pm_airaccelerate = 0; - } - - // bugfix (rst) yeah !!!!!!!! found the solution to the B E W E G U N G S P R O B L E M. - pm.s.set(cl.frame.playerstate.pmove); - - // SCR_DebugGraph (current - ack - 1, 0); - int frame = 0; - - // run frames - usercmd_t cmd; - while (++ack < current) { - frame = ack & (CMD_BACKUP - 1); - cmd = cl.cmds[frame]; - - pm.cmd.set(cmd); - - PMove.Pmove(pm); - - // save for debug checking - VectorCopy(pm.s.origin, cl.predicted_origins[frame]); - } - - int oldframe = (ack - 2) & (CMD_BACKUP - 1); - int oldz = cl.predicted_origins[oldframe][2]; - int step = pm.s.origin[2] - oldz; - if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) != 0) { - cl.predicted_step = step * 0.125f; - cl.predicted_step_time = (int) (cls.realtime - cls.frametime * 500); - } - - // copy results out for rendering - cl.predicted_origin[0] = pm.s.origin[0] * 0.125f; - cl.predicted_origin[1] = pm.s.origin[1] * 0.125f; - cl.predicted_origin[2] = pm.s.origin[2] * 0.125f; - - VectorCopy(pm.viewangles, cl.predicted_angles); - } -} +public class CL_pred { + + /* + * =================== CL_CheckPredictionError =================== + */ + static void CheckPredictionError() { + int frame; + int[] delta = new int[3]; + int i; + int len; + + if (Globals.cl_predict.value == 0.0f + || (Globals.cl.frame.playerstate.pmove.pm_flags & pmove_t.PMF_NO_PREDICTION) != 0) + return; + + // calculate the last usercmd_t we sent that the server has processed + frame = Globals.cls.netchan.incoming_acknowledged; + frame &= (Defines.CMD_BACKUP - 1); + + // compare what the server returned with what we had predicted it to be + Math3D.VectorSubtract(Globals.cl.frame.playerstate.pmove.origin, + Globals.cl.predicted_origins[frame], delta); + + // save the prediction error for interpolation + len = Math.abs(delta[0]) + Math.abs(delta[1]) + Math.abs(delta[2]); + if (len > 640) // 80 world units + { // a teleport or something + Math3D.VectorClear(Globals.cl.prediction_error); + } else { + if (Globals.cl_showmiss.value != 0.0f + && (delta[0] != 0 || delta[1] != 0 || delta[2] != 0)) + Com.Printf("prediction miss on " + Globals.cl.frame.serverframe + + ": " + (delta[0] + delta[1] + delta[2]) + "\n"); + + Math3D.VectorCopy(Globals.cl.frame.playerstate.pmove.origin, + Globals.cl.predicted_origins[frame]); + + // save for error itnerpolation + for (i = 0; i < 3; i++) + Globals.cl.prediction_error[i] = delta[i] * 0.125f; + } + } + + /* + * ==================== CL_ClipMoveToEntities + * + * ==================== + */ + static void ClipMoveToEntities(float[] start, float[] mins, float[] maxs, + float[] end, trace_t tr) { + int i, x, zd, zu; + trace_t trace; + int headnode; + float[] angles; + entity_state_t ent; + int num; + cmodel_t cmodel; + float[] bmins = new float[3]; + float[] bmaxs = new float[3]; + + for (i = 0; i < Globals.cl.frame.num_entities; i++) { + num = (Globals.cl.frame.parse_entities + i) + & (Defines.MAX_PARSE_ENTITIES - 1); + ent = Globals.cl_parse_entities[num]; + + if (ent.solid == 0) + continue; + + if (ent.number == Globals.cl.playernum + 1) + continue; + + if (ent.solid == 31) { // special value for bmodel + cmodel = Globals.cl.model_clip[ent.modelindex]; + if (cmodel == null) + continue; + headnode = cmodel.headnode; + angles = ent.angles; + } else { // encoded bbox + x = 8 * (ent.solid & 31); + zd = 8 * ((ent.solid >>> 5) & 31); + zu = 8 * ((ent.solid >>> 10) & 63) - 32; + + bmins[0] = bmins[1] = -x; + bmaxs[0] = bmaxs[1] = x; + bmins[2] = -zd; + bmaxs[2] = zu; + + headnode = CM.HeadnodeForBox(bmins, bmaxs); + angles = Globals.vec3_origin; // boxes don't rotate + } + + if (tr.allsolid) + return; + + trace = CM.TransformedBoxTrace(start, end, mins, maxs, headnode, + Defines.MASK_PLAYERSOLID, ent.origin, angles); + + if (trace.allsolid || trace.startsolid + || trace.fraction < tr.fraction) { + trace.ent = ent.surrounding_ent; + if (tr.startsolid) { + tr.set(trace); // rst: solved the Z U P P E L - P R O B L E + // M + tr.startsolid = true; + } else + tr.set(trace); // rst: solved the Z U P P E L - P R O B L E + // M + } else if (trace.startsolid) + tr.startsolid = true; + } + } + + /* + * ================ CL_PMTrace ================ + */ + + public static edict_t DUMMY_ENT = new edict_t(-1); + + static trace_t PMTrace(float[] start, float[] mins, float[] maxs, + float[] end) { + trace_t t; + + // check against world + t = CM.BoxTrace(start, end, mins, maxs, 0, Defines.MASK_PLAYERSOLID); + + if (t.fraction < 1.0f) { + t.ent = DUMMY_ENT; + } + + // check all other solid models + ClipMoveToEntities(start, mins, maxs, end, t); + + return t; + } + + /* + * ================= PMpointcontents + * + * Returns the content identificator of the point. ================= + */ + static int PMpointcontents(float[] point) { + int i; + entity_state_t ent; + int num; + cmodel_t cmodel; + int contents; + + contents = CM.PointContents(point, 0); + + for (i = 0; i < Globals.cl.frame.num_entities; i++) { + num = (Globals.cl.frame.parse_entities + i) + & (Defines.MAX_PARSE_ENTITIES - 1); + ent = Globals.cl_parse_entities[num]; + + if (ent.solid != 31) // special value for bmodel + continue; + + cmodel = Globals.cl.model_clip[ent.modelindex]; + if (cmodel == null) + continue; + + contents |= CM.TransformedPointContents(point, cmodel.headnode, + ent.origin, ent.angles); + } + return contents; + } + + /* + * ================= CL_PredictMovement + * + * Sets cl.predicted_origin and cl.predicted_angles ================= + */ + static void PredictMovement() { + + if (Globals.cls.state != Defines.ca_active) + return; + + if (Globals.cl_paused.value != 0.0f) + return; + + if (Globals.cl_predict.value == 0.0f + || (Globals.cl.frame.playerstate.pmove.pm_flags & pmove_t.PMF_NO_PREDICTION) != 0) { + // just set angles + for (int i = 0; i < 3; i++) { + Globals.cl.predicted_angles[i] = Globals.cl.viewangles[i] + + Math3D + .SHORT2ANGLE(Globals.cl.frame.playerstate.pmove.delta_angles[i]); + } + return; + } + + int ack = Globals.cls.netchan.incoming_acknowledged; + int current = Globals.cls.netchan.outgoing_sequence; + + // if we are too far out of date, just freeze + if (current - ack >= Defines.CMD_BACKUP) { + if (Globals.cl_showmiss.value != 0.0f) + Com.Printf("exceeded CMD_BACKUP\n"); + return; + } + + // copy current state to pmove + //memset (pm, 0, sizeof(pm)); + pmove_t pm = new pmove_t(); + + pm.trace = new pmove_t.TraceAdapter() { + public trace_t trace(float[] start, float[] mins, float[] maxs, + float[] end) { + return PMTrace(start, mins, maxs, end); + } + }; + pm.pointcontents = new pmove_t.PointContentsAdapter() { + public int pointcontents(float[] point) { + return PMpointcontents(point); + } + }; + + try { + PMove.pm_airaccelerate = Float + .parseFloat(Globals.cl.configstrings[Defines.CS_AIRACCEL]); + } catch (Exception e) { + PMove.pm_airaccelerate = 0; + } + + // bugfix (rst) yeah !!!!!!!! found the solution to the B E W E G U N G + // S P R O B L E M. + pm.s.set(Globals.cl.frame.playerstate.pmove); + + // SCR_DebugGraph (current - ack - 1, 0); + int frame = 0; + + // run frames + usercmd_t cmd; + while (++ack < current) { + frame = ack & (Defines.CMD_BACKUP - 1); + cmd = Globals.cl.cmds[frame]; + + pm.cmd.set(cmd); + + PMove.Pmove(pm); + + // save for debug checking + Math3D.VectorCopy(pm.s.origin, Globals.cl.predicted_origins[frame]); + } + + int oldframe = (ack - 2) & (Defines.CMD_BACKUP - 1); + int oldz = Globals.cl.predicted_origins[oldframe][2]; + int step = pm.s.origin[2] - oldz; + if (step > 63 && step < 160 + && (pm.s.pm_flags & pmove_t.PMF_ON_GROUND) != 0) { + Globals.cl.predicted_step = step * 0.125f; + Globals.cl.predicted_step_time = (int) (Globals.cls.realtime - Globals.cls.frametime * 500); + } + + // copy results out for rendering + Globals.cl.predicted_origin[0] = pm.s.origin[0] * 0.125f; + Globals.cl.predicted_origin[1] = pm.s.origin[1] * 0.125f; + Globals.cl.predicted_origin[2] = pm.s.origin[2] * 0.125f; + + Math3D.VectorCopy(pm.viewangles, Globals.cl.predicted_angles); + } +} \ No newline at end of file diff --git a/src/jake2/client/CL_tent.java b/src/jake2/client/CL_tent.java index bca8edf..132fa4a 100644 --- a/src/jake2/client/CL_tent.java +++ b/src/jake2/client/CL_tent.java @@ -1,1722 +1,1804 @@ /* - * CL_tent.java + * java * Copyright (C) 2004 * - * $Id: CL_tent.java,v 1.4 2004-07-09 10:19:57 hzi Exp $ + * $Id: CL_tent.java,v 1.5 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; +import jake2.Defines; import jake2.Globals; +import jake2.client.cl_sustain_t.ThinkAdapter; import jake2.game.player_state_t; import jake2.qcommon.Com; import jake2.qcommon.MSG; import jake2.render.model_t; import jake2.sound.*; +import jake2.util.Lib; +import jake2.util.Math3D; /** * CL_tent */ -public class CL_tent extends Globals { - - static final int ex_free = 0; - static final int ex_explosion = 1; - static final int ex_misc = 2; - static final int ex_flash = 3; - static final int ex_mflash = 4; - static final int ex_poly = 5; - static final int ex_poly2 = 6; - - - static class explosion_t { - int type; - entity_t ent = new entity_t(); - - int frames; - float light; - float[] lightcolor = new float[3]; - float start; - int baseframe; - void clear() { - lightcolor[0] = lightcolor[1] = lightcolor[2] = - light = start = type = frames = baseframe = 0; - ent = new entity_t(); - } - } - - static final int MAX_EXPLOSIONS = 32; - static explosion_t[] cl_explosions = new explosion_t[MAX_EXPLOSIONS]; - static { - for (int i = 0; i < cl_explosions.length; i++) - cl_explosions[i] = new explosion_t(); - } - - static final int MAX_BEAMS = 32; - - static class beam_t { - int entity; - int dest_entity; - model_t model; - int endtime; - float[] offset = new float[3]; - float[] start = new float[3]; - float[] end = new float[3]; - void clear() { - offset[0] = offset[1] = offset[2] = - start[0] = start[1] = start[2] = - end[0] = end[1] = end[2] = - entity = dest_entity = endtime = 0; - model = null; - } - } - static beam_t[] cl_beams = new beam_t[MAX_BEAMS]; - // PMM - added this for player-linked beams. Currently only used by the plasma beam - static beam_t[] cl_playerbeams = new beam_t[MAX_BEAMS]; - static { - for (int i = 0; i < cl_beams.length; i++) - cl_beams[i] = new beam_t(); - for (int i = 0; i < cl_playerbeams.length; i++) - cl_playerbeams[i] = new beam_t(); - } - - static final int MAX_LASERS = 32; - - static class laser_t { - entity_t ent = new entity_t(); - int endtime; - void clear() { - endtime = 0; - ent = new entity_t(); - } - } - static laser_t[] cl_lasers = new laser_t[MAX_LASERS]; - static { - for (int i = 0; i < cl_lasers.length; i++) - cl_lasers[i] = new laser_t(); - } - -// ROGUE - static final int MAX_SUSTAINS = 32; - static cl_sustain_t[] cl_sustains = new cl_sustain_t[MAX_SUSTAINS]; - static { - for (int i = 0; i < cl_sustains.length; i++) - cl_sustains[i] = new cl_sustain_t(); - } -// ROGUE - - // all are references; - static sfx_t cl_sfx_ric1; - static sfx_t cl_sfx_ric2; - static sfx_t cl_sfx_ric3; - static sfx_t cl_sfx_lashit; - static sfx_t cl_sfx_spark5; - static sfx_t cl_sfx_spark6; - static sfx_t cl_sfx_spark7; - static sfx_t cl_sfx_railg; - static sfx_t cl_sfx_rockexp; - static sfx_t cl_sfx_grenexp; - static sfx_t cl_sfx_watrexp; - // RAFAEL - static sfx_t cl_sfx_plasexp; - static sfx_t cl_sfx_footsteps[] = new sfx_t[4]; - - static model_t cl_mod_explode; - static model_t cl_mod_smoke; - static model_t cl_mod_flash; - static model_t cl_mod_parasite_segment; - static model_t cl_mod_grapple_cable; - static model_t cl_mod_parasite_tip; - static model_t cl_mod_explo4; - static model_t cl_mod_bfg_explo; - static model_t cl_mod_powerscreen; - // RAFAEL - static model_t cl_mod_plasmaexplo; - - // ROGUE - static sfx_t cl_sfx_lightning; - static sfx_t cl_sfx_disrexp; - static model_t cl_mod_lightning; - static model_t cl_mod_heatbeam; - static model_t cl_mod_monster_heatbeam; - static model_t cl_mod_explo4_big; - -// ROGUE - /* - ================= - CL_RegisterTEntSounds - ================= - */ - static void RegisterTEntSounds() { - int i; - String name; - - // PMM - version stuff - // Com_Printf ("%s\n", ROGUE_VERSION_STRING); - // PMM - cl_sfx_ric1 = S.RegisterSound("world/ric1.wav"); - cl_sfx_ric2 = S.RegisterSound("world/ric2.wav"); - cl_sfx_ric3 = S.RegisterSound("world/ric3.wav"); - cl_sfx_lashit = S.RegisterSound("weapons/lashit.wav"); - cl_sfx_spark5 = S.RegisterSound("world/spark5.wav"); - cl_sfx_spark6 = S.RegisterSound("world/spark6.wav"); - cl_sfx_spark7 = S.RegisterSound("world/spark7.wav"); - cl_sfx_railg = S.RegisterSound("weapons/railgf1a.wav"); - cl_sfx_rockexp = S.RegisterSound("weapons/rocklx1a.wav"); - cl_sfx_grenexp = S.RegisterSound("weapons/grenlx1a.wav"); - cl_sfx_watrexp = S.RegisterSound("weapons/xpld_wat.wav"); - // RAFAEL - // cl_sfx_plasexp = S.RegisterSound ("weapons/plasexpl.wav"); - S.RegisterSound("player/land1.wav"); - - S.RegisterSound("player/fall2.wav"); - S.RegisterSound("player/fall1.wav"); - - for (i = 0; i < 4; i++) { - //Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1); - name = "player/step" + (i + 1) + ".wav"; - cl_sfx_footsteps[i] = S.RegisterSound(name); - } - - // PGM - cl_sfx_lightning = S.RegisterSound("weapons/tesla.wav"); - cl_sfx_disrexp = S.RegisterSound("weapons/disrupthit.wav"); - // version stuff - // sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID); - // if (name[0] == 'w') - // name[0] = 'W'; - // PGM - } - - /* - ================= - CL_RegisterTEntModels - ================= - */ - static void RegisterTEntModels() { - cl_mod_explode = re.RegisterModel("models/objects/explode/tris.md2"); - cl_mod_smoke = re.RegisterModel("models/objects/smoke/tris.md2"); - cl_mod_flash = re.RegisterModel("models/objects/flash/tris.md2"); - cl_mod_parasite_segment = re.RegisterModel("models/monsters/parasite/segment/tris.md2"); - cl_mod_grapple_cable = re.RegisterModel("models/ctf/segment/tris.md2"); - cl_mod_parasite_tip = re.RegisterModel("models/monsters/parasite/tip/tris.md2"); - cl_mod_explo4 = re.RegisterModel("models/objects/r_explode/tris.md2"); - cl_mod_bfg_explo = re.RegisterModel("sprites/s_bfg2.sp2"); - cl_mod_powerscreen = re.RegisterModel("models/items/armor/effect/tris.md2"); - - re.RegisterModel("models/objects/laser/tris.md2"); - re.RegisterModel("models/objects/grenade2/tris.md2"); - re.RegisterModel("models/weapons/v_machn/tris.md2"); - re.RegisterModel("models/weapons/v_handgr/tris.md2"); - re.RegisterModel("models/weapons/v_shotg2/tris.md2"); - re.RegisterModel("models/objects/gibs/bone/tris.md2"); - re.RegisterModel("models/objects/gibs/sm_meat/tris.md2"); - re.RegisterModel("models/objects/gibs/bone2/tris.md2"); - // RAFAEL - // re.RegisterModel ("models/objects/blaser/tris.md2"); - - re.RegisterPic("w_machinegun"); - re.RegisterPic("a_bullets"); - re.RegisterPic("i_health"); - re.RegisterPic("a_grenades"); - - // ROGUE - cl_mod_explo4_big = re.RegisterModel("models/objects/r_explode2/tris.md2"); - cl_mod_lightning = re.RegisterModel("models/proj/lightning/tris.md2"); - cl_mod_heatbeam = re.RegisterModel("models/proj/beam/tris.md2"); - cl_mod_monster_heatbeam = re.RegisterModel("models/proj/widowbeam/tris.md2"); - // ROGUE - } - - /* - ================= - CL_ClearTEnts - ================= - */ - static void ClearTEnts() { - // memset (cl_beams, 0, sizeof(cl_beams)); - for (int i = 0; i < cl_beams.length; i++) - cl_beams[i].clear(); - // memset (cl_explosions, 0, sizeof(cl_explosions)); - for (int i = 0; i < cl_explosions.length; i++) - cl_explosions[i].clear(); - // memset (cl_lasers, 0, sizeof(cl_lasers)); - for (int i = 0; i < cl_lasers.length; i++) - cl_lasers[i].clear(); - // - // ROGUE - // memset (cl_playerbeams, 0, sizeof(cl_playerbeams)); - for (int i = 0; i < cl_playerbeams.length; i++) - cl_playerbeams[i].clear(); - // memset (cl_sustains, 0, sizeof(cl_sustains)); - for (int i = 0; i < cl_sustains.length; i++) - cl_sustains[i].clear(); - // ROGUE - } - - /* - ================= - CL_AllocExplosion - ================= - */ - static explosion_t AllocExplosion() { - int i; - int time; - int index; - - for (i = 0; i < MAX_EXPLOSIONS; i++) { - if (cl_explosions[i].type == ex_free) { - //memset (&cl_explosions[i], 0, sizeof (cl_explosions[i])); - cl_explosions[i].clear(); - return cl_explosions[i]; - } - } - // find the oldest explosion - time = cl.time; - index = 0; - - for (i = 0; i < MAX_EXPLOSIONS; i++) - if (cl_explosions[i].start < time) { - time = (int)cl_explosions[i].start; - index = i; - } - //memset (&cl_explosions[index], 0, sizeof (cl_explosions[index])); - cl_explosions[index].clear(); - return cl_explosions[index]; - } - - /* - ================= - CL_SmokeAndFlash - ================= - */ - static void SmokeAndFlash(float[] origin) { - explosion_t ex; - - ex = CL.AllocExplosion(); - VectorCopy(origin, ex.ent.origin); - ex.type = ex_misc; - ex.frames = 4; - ex.ent.flags = RF_TRANSLUCENT; - ex.start = cl.frame.servertime - 100; - ex.ent.model = cl_mod_smoke; - - ex = CL.AllocExplosion(); - VectorCopy(origin, ex.ent.origin); - ex.type = ex_flash; - ex.ent.flags = RF_FULLBRIGHT; - ex.frames = 2; - ex.start = cl.frame.servertime - 100; - ex.ent.model = cl_mod_flash; - } - - /* - ================= - CL_ParseParticles - ================= - */ - static void ParseParticles() { - int color, count; - float[] pos = new float[3]; - float[] dir = new float[3]; - - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - - color = MSG.ReadByte(net_message); - - count = MSG.ReadByte(net_message); - - CL.ParticleEffect(pos, dir, color, count); - } - - /* - ================= - CL_ParseBeam - ================= - */ - static int ParseBeam(model_t model) { - int ent; - float[] start = new float[3]; - float[] end = new float[3]; - beam_t[] b; - int i; - - ent = MSG.ReadShort(net_message); - - MSG.ReadPos(net_message, start); - MSG.ReadPos(net_message, end); - - // override any beam with the same entity - b = cl_beams; - for (i = 0; i < MAX_BEAMS; i++) - if (b[i].entity == ent) { - b[i].entity = ent; - b[i].model = model; - b[i].endtime = cl.time + 200; - VectorCopy(start, b[i].start); - VectorCopy(end, b[i].end); - VectorClear(b[i].offset); - return ent; - } - - // find a free beam - b = cl_beams; - for (i = 0; i < MAX_BEAMS; i++) { - if (b[i].model == null || b[i].endtime < cl.time) { - b[i].entity = ent; - b[i].model = model; - b[i].endtime = cl.time + 200; - VectorCopy(start, b[i].start); - VectorCopy(end, b[i].end); - VectorClear(b[i].offset); - return ent; - } - } - Com.Printf("beam list overflow!\n"); - return ent; - } - - /* - ================= - CL_ParseBeam2 - ================= - */ - static int ParseBeam2(model_t model) { - int ent; - float[] start = new float[3]; - float[] end = new float[3]; - float[] offset = new float[3]; - beam_t[] b; - int i; - - ent = MSG.ReadShort(net_message); - - MSG.ReadPos(net_message, start); - MSG.ReadPos(net_message, end); - MSG.ReadPos(net_message, offset); - - // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]); - - // override any beam with the same entity - b = cl_beams; - for (i = 0; i < MAX_BEAMS; i++) - if (b[i].entity == ent) { - b[i].entity = ent; - b[i].model = model; - b[i].endtime = cl.time + 200; - VectorCopy(start, b[i].start); - VectorCopy(end, b[i].end); - VectorCopy(offset, b[i].offset); - return ent; - } - - // find a free beam - b = cl_beams; - for (i = 0; i < MAX_BEAMS; i++) { - if (b[i].model == null || b[i].endtime < cl.time) { - b[i].entity = ent; - b[i].model = model; - b[i].endtime = cl.time + 200; - VectorCopy(start, b[i].start); - VectorCopy(end, b[i].end); - VectorCopy(offset, b[i].offset); - return ent; - } - } - Com.Printf("beam list overflow!\n"); - return ent; - } - - // ROGUE - /* - ================= - CL_ParsePlayerBeam - - adds to the cl_playerbeam array instead of the cl_beams array - ================= - */ - static int ParsePlayerBeam(model_t model) { - int ent; - float[] start = new float[3]; - float[] end = new float[3]; - float[] offset = new float[3]; - beam_t[] b; - int i; - - ent = MSG.ReadShort(net_message); - - MSG.ReadPos(net_message, start); - MSG.ReadPos(net_message, end); - // PMM - network optimization - if (model == cl_mod_heatbeam) - VectorSet(offset, 2, 7, -3); - else if (model == cl_mod_monster_heatbeam) { - model = cl_mod_heatbeam; - VectorSet(offset, 0, 0, 0); - } else - MSG.ReadPos(net_message, offset); - - // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]); - - // override any beam with the same entity - // PMM - For player beams, we only want one per player (entity) so.. - b = cl_playerbeams; - for (i = 0; i < MAX_BEAMS; i++) { - if (b[i].entity == ent) { - b[i].entity = ent; - b[i].model = model; - b[i].endtime = cl.time + 200; - VectorCopy(start, b[i].start); - VectorCopy(end, b[i].end); - VectorCopy(offset, b[i].offset); - return ent; - } - } - - // find a free beam - b = cl_playerbeams; - for (i = 0; i < MAX_BEAMS; i++) { - if (b[i].model == null || b[i].endtime < cl.time) { - b[i].entity = ent; - b[i].model = model; - b[i].endtime = cl.time + 100; // PMM - this needs to be 100 to prevent multiple heatbeams - VectorCopy(start, b[i].start); - VectorCopy(end, b[i].end); - VectorCopy(offset, b[i].offset); - return ent; - } - } - Com.Printf("beam list overflow!\n"); - return ent; - } -// rogue - - /* - ================= - CL_ParseLightning - ================= - */ - static int ParseLightning(model_t model) { - int srcEnt, destEnt; - float[] start = new float[3]; - float[] end = new float[3]; - beam_t[] b; - int i; - - srcEnt = MSG.ReadShort(net_message); - destEnt = MSG.ReadShort(net_message); - - MSG.ReadPos(net_message, start); - MSG.ReadPos(net_message, end); - - // override any beam with the same source AND destination entities - b = cl_beams; - for (i = 0; i < MAX_BEAMS; i++) - if (b[i].entity == srcEnt && b[i].dest_entity == destEnt) { - // Com_Printf("%d: OVERRIDE %d . %d\n", cl.time, srcEnt, destEnt); - b[i].entity = srcEnt; - b[i].dest_entity = destEnt; - b[i].model = model; - b[i].endtime = cl.time + 200; - VectorCopy(start, b[i].start); - VectorCopy(end, b[i].end); - VectorClear(b[i].offset); - return srcEnt; - } - - // find a free beam - b = cl_beams; - for (i = 0; i < MAX_BEAMS; i++) { - if (b[i].model == null || b[i].endtime < cl.time) { - // Com_Printf("%d: NORMAL %d . %d\n", cl.time, srcEnt, destEnt); - b[i].entity = srcEnt; - b[i].dest_entity = destEnt; - b[i].model = model; - b[i].endtime = cl.time + 200; - VectorCopy(start, b[i].start); - VectorCopy(end, b[i].end); - VectorClear(b[i].offset); - return srcEnt; - } - } - Com.Printf("beam list overflow!\n"); - return srcEnt; - } - - /* - ================= - CL_ParseLaser - ================= - */ - static void ParseLaser(int colors) { - float[] start = new float[3]; - float[] end = new float[3]; - laser_t[] l; - int i; - - MSG.ReadPos(net_message, start); - MSG.ReadPos(net_message, end); - - l = cl_lasers; - for (i = 0; i < MAX_LASERS; i++) { - if (l[i].endtime < cl.time) { - l[i].ent.flags = RF_TRANSLUCENT | RF_BEAM; - VectorCopy(start, l[i].ent.origin); - VectorCopy(end, l[i].ent.oldorigin); - l[i].ent.alpha = 0.30f; - l[i].ent.skinnum = (colors >> ((rand() % 4) * 8)) & 0xff; - l[i].ent.model = null; - l[i].ent.frame = 4; - l[i].endtime = cl.time + 100; - return; - } - } - } - -// ============= -// ROGUE - static void ParseSteam() { - float[] pos = new float[3]; - float[] dir = new float[3]; - int id, i; - int r; - int cnt; - int color; - int magnitude; - cl_sustain_t[] s; - cl_sustain_t free_sustain; - - id = MSG.ReadShort(net_message); // an id of -1 is an instant effect - if (id != -1) // sustains - { - // Com_Printf ("Sustain effect id %d\n", id); - free_sustain = null; - s = cl_sustains; - for (i = 0; i < MAX_SUSTAINS; i++) { - if (s[i].id == 0) { - free_sustain = s[i]; - break; - } - } - if (free_sustain != null) { - s[i].id = id; - s[i].count = MSG.ReadByte(net_message); - MSG.ReadPos(net_message, s[i].org); - MSG.ReadDir(net_message, s[i].dir); - r = MSG.ReadByte(net_message); - s[i].color = r & 0xff; - s[i].magnitude = MSG.ReadShort(net_message); - s[i].endtime = cl.time + MSG.ReadLong(net_message); - s[i].think = new cl_sustain_t.ThinkAdapter() { - void think(cl_sustain_t self) { - CL.ParticleSteamEffect2(self); - } - }; - s[i].thinkinterval = 100; - s[i].nextthink = cl.time; - } else { - // Com_Printf ("No free sustains!\n"); - // FIXME - read the stuff anyway - cnt = MSG.ReadByte(net_message); - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - r = MSG.ReadByte(net_message); - magnitude = MSG.ReadShort(net_message); - magnitude = MSG.ReadLong(net_message); // really interval - } - } else // instant - { - cnt = MSG.ReadByte(net_message); - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - r = MSG.ReadByte(net_message); - magnitude = MSG.ReadShort(net_message); - color = r & 0xff; - CL.ParticleSteamEffect(pos, dir, color, cnt, magnitude); - // S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); - } - } - - static void ParseWidow() { - float[] pos = new float[3]; - int id, i; - cl_sustain_t[] s; - cl_sustain_t free_sustain; - - id = MSG.ReadShort(net_message); - - free_sustain = null; - s = cl_sustains; - for (i = 0; i < MAX_SUSTAINS; i++) { - if (s[i].id == 0) { - free_sustain = s[i]; - break; - } - } - if (free_sustain != null) { - s[i].id = id; - MSG.ReadPos(net_message, s[i].org); - s[i].endtime = cl.time + 2100; - s[i].think = new cl_sustain_t.ThinkAdapter() { - void think(cl_sustain_t self) { - CL.Widowbeamout(self); - } - }; - s[i].thinkinterval = 1; - s[i].nextthink = cl.time; - } else // no free sustains - { - // FIXME - read the stuff anyway - MSG.ReadPos(net_message, pos); - } - } - - static void ParseNuke() { - float[] pos = new float[3]; - int i; - cl_sustain_t[] s; - cl_sustain_t free_sustain; - - free_sustain = null; - s = cl_sustains; - for (i = 0; i < MAX_SUSTAINS; i++) { - if (s[i].id == 0) { - free_sustain = s[i]; - break; - } - } - if (free_sustain != null) { - s[i].id = 21000; - MSG.ReadPos(net_message, s[i].org); - s[i].endtime = cl.time + 1000; - s[i].think = new cl_sustain_t.ThinkAdapter() { - void think(cl_sustain_t self) { - CL.Nukeblast(self); - } - }; - s[i].thinkinterval = 1; - s[i].nextthink = cl.time; - } else // no free sustains - { - // FIXME - read the stuff anyway - MSG.ReadPos(net_message, pos); - } - } - -// ROGUE -// ============= - - - /* - ================= - CL_ParseTEnt - ================= - */ - static int[] splash_color = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8}; - static void ParseTEnt() { - int type; - float[] pos = new float[3]; - float[] pos2 = new float[3]; - float[] dir = new float[3]; - explosion_t ex; - int cnt; - int color; - int r; - int ent; - int magnitude; - - type = MSG.ReadByte(net_message); - - switch (type) { - case TE_BLOOD : // bullet hitting flesh - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - CL.ParticleEffect(pos, dir, 0xe8, 60); - break; - - case TE_GUNSHOT : // bullet hitting wall - case TE_SPARKS : - case TE_BULLET_SPARKS : - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - if (type == TE_GUNSHOT) - CL.ParticleEffect(pos, dir, 0, 40); - else - CL.ParticleEffect(pos, dir, 0xe0, 6); - - if (type != TE_SPARKS) { - CL.SmokeAndFlash(pos); - - // impact sound - cnt = rand() & 15; - if (cnt == 1) - S.StartSound(pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0); - else if (cnt == 2) - S.StartSound(pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0); - else if (cnt == 3) - S.StartSound(pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0); - } - - break; - - case TE_SCREEN_SPARKS : - case TE_SHIELD_SPARKS : - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - if (type == TE_SCREEN_SPARKS) - CL.ParticleEffect(pos, dir, 0xd0, 40); - else - CL.ParticleEffect(pos, dir, 0xb0, 40); - //FIXME : replace or remove this sound - S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); - break; - - case TE_SHOTGUN : // bullet hitting wall - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - CL.ParticleEffect(pos, dir, 0, 20); - CL.SmokeAndFlash(pos); - break; - - case TE_SPLASH : // bullet hitting water - cnt = MSG.ReadByte(net_message); - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - r = MSG.ReadByte(net_message); - if (r > 6) - color = 0x00; - else - color = splash_color[r]; - CL.ParticleEffect(pos, dir, color, cnt); - - if (r == SPLASH_SPARKS) { - r = rand() & 3; - if (r == 0) - S.StartSound(pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0); - else if (r == 1) - S.StartSound(pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0); - else - S.StartSound(pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0); - } - break; - - case TE_LASER_SPARKS : - cnt = MSG.ReadByte(net_message); - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - color = MSG.ReadByte(net_message); - CL.ParticleEffect2(pos, dir, color, cnt); - break; - - // RAFAEL - case TE_BLUEHYPERBLASTER : - MSG.ReadPos(net_message, pos); - MSG.ReadPos(net_message, dir); - CL.BlasterParticles(pos, dir); - break; - - case TE_BLASTER : // blaster hitting wall - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - CL.BlasterParticles(pos, dir); - - ex = CL.AllocExplosion(); - VectorCopy(pos, ex.ent.origin); - ex.ent.angles[0] = (float) (Math.acos(dir[2]) / Math.PI * 180); - // PMM - fixed to correct for pitch of 0 - if (dir[0] != 0.0f) - ex.ent.angles[1] = (float) (Math.atan2(dir[1], dir[0]) / Math.PI * 180); - else if (dir[1] > 0) - ex.ent.angles[1] = 90; - else if (dir[1] < 0) - ex.ent.angles[1] = 270; - else - ex.ent.angles[1] = 0; - - ex.type = ex_misc; - ex.ent.flags = RF_FULLBRIGHT | RF_TRANSLUCENT; - ex.start = cl.frame.servertime - 100; - ex.light = 150; - ex.lightcolor[0] = 1; - ex.lightcolor[1] = 1; - ex.ent.model = cl_mod_explode; - ex.frames = 4; - S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); - break; - - case TE_RAILTRAIL : // railgun effect - MSG.ReadPos(net_message, pos); - MSG.ReadPos(net_message, pos2); - CL.RailTrail(pos, pos2); - S.StartSound(pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0); - break; - - case TE_EXPLOSION2 : - case TE_GRENADE_EXPLOSION : - case TE_GRENADE_EXPLOSION_WATER : - MSG.ReadPos(net_message, pos); - - ex = CL.AllocExplosion(); - VectorCopy(pos, ex.ent.origin); - ex.type = ex_poly; - ex.ent.flags = RF_FULLBRIGHT; - ex.start = cl.frame.servertime - 100; - ex.light = 350; - ex.lightcolor[0] = 1.0f; - ex.lightcolor[1] = 0.5f; - ex.lightcolor[2] = 0.5f; - ex.ent.model = cl_mod_explo4; - ex.frames = 19; - ex.baseframe = 30; - ex.ent.angles[1] = rand() % 360; - CL.ExplosionParticles(pos); - if (type == TE_GRENADE_EXPLOSION_WATER) - S.StartSound(pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0); - else - S.StartSound(pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0); - break; - - // RAFAEL - case TE_PLASMA_EXPLOSION : - MSG.ReadPos(net_message, pos); - ex = CL.AllocExplosion(); - VectorCopy(pos, ex.ent.origin); - ex.type = ex_poly; - ex.ent.flags = RF_FULLBRIGHT; - ex.start = cl.frame.servertime - 100; - ex.light = 350; - ex.lightcolor[0] = 1.0f; - ex.lightcolor[1] = 0.5f; - ex.lightcolor[2] = 0.5f; - ex.ent.angles[1] = rand() % 360; - ex.ent.model = cl_mod_explo4; - if (Globals.rnd.nextFloat() < 0.5) - ex.baseframe = 15; - ex.frames = 15; - CL.ExplosionParticles(pos); - S.StartSound(pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); - break; - - case TE_EXPLOSION1 : - case TE_EXPLOSION1_BIG : // PMM - case TE_ROCKET_EXPLOSION : - case TE_ROCKET_EXPLOSION_WATER : - case TE_EXPLOSION1_NP : // PMM - MSG.ReadPos(net_message, pos); - - ex = CL.AllocExplosion(); - VectorCopy(pos, ex.ent.origin); - ex.type = ex_poly; - ex.ent.flags = RF_FULLBRIGHT; - ex.start = cl.frame.servertime - 100; - ex.light = 350; - ex.lightcolor[0] = 1.0f; - ex.lightcolor[1] = 0.5f; - ex.lightcolor[2] = 0.5f; - ex.ent.angles[1] = rand() % 360; - if (type != TE_EXPLOSION1_BIG) // PMM - ex.ent.model = cl_mod_explo4; // PMM - else - ex.ent.model = cl_mod_explo4_big; - if (Globals.rnd.nextFloat() < 0.5) - ex.baseframe = 15; - ex.frames = 15; - if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP)) // PMM - CL.ExplosionParticles(pos); // PMM - if (type == TE_ROCKET_EXPLOSION_WATER) - S.StartSound(pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0); - else - S.StartSound(pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); - break; - - case TE_BFG_EXPLOSION : - MSG.ReadPos(net_message, pos); - ex = CL.AllocExplosion(); - VectorCopy(pos, ex.ent.origin); - ex.type = ex_poly; - ex.ent.flags = RF_FULLBRIGHT; - ex.start = cl.frame.servertime - 100; - ex.light = 350; - ex.lightcolor[0] = 0.0f; - ex.lightcolor[1] = 1.0f; - ex.lightcolor[2] = 0.0f; - ex.ent.model = cl_mod_bfg_explo; - ex.ent.flags |= RF_TRANSLUCENT; - ex.ent.alpha = 0.30f; - ex.frames = 4; - break; - - case TE_BFG_BIGEXPLOSION : - MSG.ReadPos(net_message, pos); - CL.BFGExplosionParticles(pos); - break; - - case TE_BFG_LASER : - CL.ParseLaser(0xd0d1d2d3); - break; - - case TE_BUBBLETRAIL : - MSG.ReadPos(net_message, pos); - MSG.ReadPos(net_message, pos2); - CL.BubbleTrail(pos, pos2); - break; - - case TE_PARASITE_ATTACK : - case TE_MEDIC_CABLE_ATTACK : - ent = CL.ParseBeam(cl_mod_parasite_segment); - break; - - case TE_BOSSTPORT : // boss teleporting to station - MSG.ReadPos(net_message, pos); - CL.BigTeleportParticles(pos); - S.StartSound(pos, 0, 0, S.RegisterSound("misc/bigtele.wav"), 1, ATTN_NONE, 0); - break; - - case TE_GRAPPLE_CABLE : - ent = CL.ParseBeam2(cl_mod_grapple_cable); - break; - - // RAFAEL - case TE_WELDING_SPARKS : - cnt = MSG.ReadByte(net_message); - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - color = MSG.ReadByte(net_message); - CL.ParticleEffect2(pos, dir, color, cnt); - - ex = CL.AllocExplosion(); - VectorCopy(pos, ex.ent.origin); - ex.type = ex_flash; - // note to self - // we need a better no draw flag - ex.ent.flags = RF_BEAM; - ex.start = cl.frame.servertime - 0.1f; - ex.light = 100 + (rand() % 75); - ex.lightcolor[0] = 1.0f; - ex.lightcolor[1] = 1.0f; - ex.lightcolor[2] = 0.3f; - ex.ent.model = cl_mod_flash; - ex.frames = 2; - break; - - case TE_GREENBLOOD : - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - CL.ParticleEffect2(pos, dir, 0xdf, 30); - break; - - // RAFAEL - case TE_TUNNEL_SPARKS : - cnt = MSG.ReadByte(net_message); - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - color = MSG.ReadByte(net_message); - CL.ParticleEffect3(pos, dir, color, cnt); - break; - - // ============= - // PGM - // PMM -following code integrated for flechette (different color) - case TE_BLASTER2 : // green blaster hitting wall - case TE_FLECHETTE : // flechette - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - - // PMM - if (type == TE_BLASTER2) - CL.BlasterParticles2(pos, dir, 0xd0); - else - CL.BlasterParticles2(pos, dir, 0x6f); // 75 - - ex = CL.AllocExplosion(); - VectorCopy(pos, ex.ent.origin); - ex.ent.angles[0] = (float) (Math.acos(dir[2]) / Math.PI * 180); - // PMM - fixed to correct for pitch of 0 - if (dir[0] != 0.0f) - ex.ent.angles[1] = (float) (Math.atan2(dir[1], dir[0]) / Math.PI * 180); - else if (dir[1] > 0) - ex.ent.angles[1] = 90; - else if (dir[1] < 0) - ex.ent.angles[1] = 270; - else - ex.ent.angles[1] = 0; - - ex.type = ex_misc; - ex.ent.flags = RF_FULLBRIGHT | RF_TRANSLUCENT; - - // PMM - if (type == TE_BLASTER2) - ex.ent.skinnum = 1; - else // flechette - ex.ent.skinnum = 2; - - ex.start = cl.frame.servertime - 100; - ex.light = 150; - // PMM - if (type == TE_BLASTER2) - ex.lightcolor[1] = 1; - else // flechette - { - ex.lightcolor[0] = 0.19f; - ex.lightcolor[1] = 0.41f; - ex.lightcolor[2] = 0.75f; - } - ex.ent.model = cl_mod_explode; - ex.frames = 4; - S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); - break; - - case TE_LIGHTNING : - ent = CL.ParseLightning(cl_mod_lightning); - S.StartSound(null, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0); - break; - - case TE_DEBUGTRAIL : - MSG.ReadPos(net_message, pos); - MSG.ReadPos(net_message, pos2); - CL.DebugTrail(pos, pos2); - break; - - case TE_PLAIN_EXPLOSION : - MSG.ReadPos(net_message, pos); - - ex = CL.AllocExplosion(); - VectorCopy(pos, ex.ent.origin); - ex.type = ex_poly; - ex.ent.flags = RF_FULLBRIGHT; - ex.start = cl.frame.servertime - 100; - ex.light = 350; - ex.lightcolor[0] = 1.0f; - ex.lightcolor[1] = 0.5f; - ex.lightcolor[2] = 0.5f; - ex.ent.angles[1] = rand() % 360; - ex.ent.model = cl_mod_explo4; - if (Globals.rnd.nextFloat() < 0.5) - ex.baseframe = 15; - ex.frames = 15; - if (type == TE_ROCKET_EXPLOSION_WATER) - S.StartSound(pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0); - else - S.StartSound(pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); - break; - - case TE_FLASHLIGHT : - MSG.ReadPos(net_message, pos); - ent = MSG.ReadShort(net_message); - CL.Flashlight(ent, pos); - break; - - case TE_FORCEWALL : - MSG.ReadPos(net_message, pos); - MSG.ReadPos(net_message, pos2); - color = MSG.ReadByte(net_message); - CL.ForceWall(pos, pos2, color); - break; - - case TE_HEATBEAM : - ent = CL.ParsePlayerBeam(cl_mod_heatbeam); - break; - - case TE_MONSTER_HEATBEAM : - ent = CL.ParsePlayerBeam(cl_mod_monster_heatbeam); - break; - - case TE_HEATBEAM_SPARKS : - // cnt = MSG.ReadByte (net_message); - cnt = 50; - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - // r = MSG.ReadByte (net_message); - // magnitude = MSG.ReadShort (net_message); - r = 8; - magnitude = 60; - color = r & 0xff; - CL.ParticleSteamEffect(pos, dir, color, cnt, magnitude); - S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); - break; - - case TE_HEATBEAM_STEAM : - // cnt = MSG.ReadByte (net_message); - cnt = 20; - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - // r = MSG.ReadByte (net_message); - // magnitude = MSG.ReadShort (net_message); - // color = r & 0xff; - color = 0xe0; - magnitude = 60; - CL.ParticleSteamEffect(pos, dir, color, cnt, magnitude); - S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); - break; - - case TE_STEAM : - CL.ParseSteam(); - break; - - case TE_BUBBLETRAIL2 : - // cnt = MSG.ReadByte (net_message); - cnt = 8; - MSG.ReadPos(net_message, pos); - MSG.ReadPos(net_message, pos2); - CL.BubbleTrail2(pos, pos2, cnt); - S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); - break; - - case TE_MOREBLOOD : - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - CL.ParticleEffect(pos, dir, 0xe8, 250); - break; - - case TE_CHAINFIST_SMOKE : - dir[0] = 0; - dir[1] = 0; - dir[2] = 1; - MSG.ReadPos(net_message, pos); - CL.ParticleSmokeEffect(pos, dir, 0, 20, 20); - break; - - case TE_ELECTRIC_SPARKS : - MSG.ReadPos(net_message, pos); - MSG.ReadDir(net_message, dir); - // CL_ParticleEffect (pos, dir, 109, 40); - CL.ParticleEffect(pos, dir, 0x75, 40); - //FIXME : replace or remove this sound - S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); - break; - - case TE_TRACKER_EXPLOSION : - MSG.ReadPos(net_message, pos); - CL.ColorFlash(pos, 0, 150, -1, -1, -1); - CL.ColorExplosionParticles(pos, 0, 1); - // CL_Tracker_Explode (pos); - S.StartSound(pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0); - break; - - case TE_TELEPORT_EFFECT : - case TE_DBALL_GOAL : - MSG.ReadPos(net_message, pos); - CL.TeleportParticles(pos); - break; - - case TE_WIDOWBEAMOUT : - CL.ParseWidow(); - break; - - case TE_NUKEBLAST : - ParseNuke(); - break; - - case TE_WIDOWSPLASH : - MSG.ReadPos(net_message, pos); - CL.WidowSplash(pos); - break; - // PGM - // ============== - - default : - Com.Error(ERR_DROP, "CL_ParseTEnt: bad type"); - } - } - - /* - ================= - CL_AddBeams - ================= - */ - static void AddBeams() { - int i, j; - beam_t[] b; - float[] dist = new float[3]; - float[] org = new float[3]; - float d; - entity_t ent = new entity_t(); - float yaw, pitch; - float forward; - float len, steps; - float model_length; - - // update beams - b = cl_beams; - for (i = 0; i < MAX_BEAMS; i++) { - if (b[i].model == null || b[i].endtime < cl.time) - continue; - - // if coming from the player, update the start position - if (b[i].entity == cl.playernum + 1) // entity 0 is the world - { - VectorCopy(cl.refdef.vieworg, b[i].start); - b[i].start[2] -= 22; // adjust for view height - } - VectorAdd(b[i].start, b[i].offset, org); - - // calculate pitch and yaw - VectorSubtract(b[i].end, org, dist); - - if (dist[1] == 0 && dist[0] == 0) { - yaw = 0; - if (dist[2] > 0) - pitch = 90; - else - pitch = 270; - } else { - // PMM - fixed to correct for pitch of 0 - if (dist[0] != 0.0f) - yaw = (float) (Math.atan2(dist[1], dist[0]) * 180 / Math.PI); - else if (dist[1] > 0) - yaw = 90; - else - yaw = 270; - if (yaw < 0) - yaw += 360; - - forward = (float)Math.sqrt(dist[0] * dist[0] + dist[1] * dist[1]); - pitch = (float) (Math.atan2(dist[2], forward) * -180.0 / Math.PI); - if (pitch < 0) - pitch += 360.0; - } - - // add new entities for the beams - d = VectorNormalize(dist); - - //memset (&ent, 0, sizeof(ent)); - ent = new entity_t(); - if (b[i].model == cl_mod_lightning) { - model_length = 35.0f; - d -= 20.0; // correction so it doesn't end in middle of tesla - } else { - model_length = 30.0f; - } - steps = (float)Math.ceil(d / model_length); - len = (d - model_length) / (steps - 1); - - // PMM - special case for lightning model .. if the real length is shorter than the model, - // flip it around & draw it from the end to the start. This prevents the model from going - // through the tesla mine (instead it goes through the target) - if ((b[i].model == cl_mod_lightning) && (d <= model_length)) { - // Com_Printf ("special case\n"); - VectorCopy(b[i].end, ent.origin); - // offset to push beam outside of tesla model (negative because dist is from end to start - // for this beam) - // for (j=0 ; j<3 ; j++) - // ent.origin[j] -= dist[j]*10.0; - ent.model = b[i].model; - ent.flags = RF_FULLBRIGHT; - ent.angles[0] = pitch; - ent.angles[1] = yaw; - ent.angles[2] = rand() % 360; - V.AddEntity(ent); - return; - } - while (d > 0) { - VectorCopy(org, ent.origin); - ent.model = b[i].model; - if (b[i].model == cl_mod_lightning) { - ent.flags = RF_FULLBRIGHT; - ent.angles[0] = -pitch; - ent.angles[1] = yaw + 180.0f; - ent.angles[2] = rand() % 360; - } else { - ent.angles[0] = pitch; - ent.angles[1] = yaw; - ent.angles[2] = rand() % 360; - } - - // Com_Printf("B: %d . %d\n", b[i].entity, b[i].dest_entity); - V.AddEntity(ent); - - for (j = 0; j < 3; j++) - org[j] += dist[j] * len; - d -= model_length; - } - } - } - - //extern cvar_t *hand; - - /* - ================= - ROGUE - draw player locked beams - CL_AddPlayerBeams - ================= - */ - static void AddPlayerBeams() { - float[] dist = new float[3]; - float[] org = new float[3]; - float d; - entity_t ent = new entity_t(); - float yaw, pitch; - float forward; - float len, steps; - int framenum = 0; - float model_length; - - float hand_multiplier; - frame_t oldframe; - player_state_t ps, ops; - - // PMM - if (hand != null) { - if (hand.value == 2) - hand_multiplier = 0; - else if (hand.value == 1) - hand_multiplier = -1; - else - hand_multiplier = 1; - } else { - hand_multiplier = 1; - } - // PMM - - // update beams - beam_t[] b = cl_playerbeams; - float[] f = new float[3]; - float[] u = new float[3]; - float[] r = new float[3]; - for (int i = 0; i < MAX_BEAMS; i++) { - - if (b[i].model == null || b[i].endtime < cl.time) - continue; - - if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) { - - // if coming from the player, update the start position - if (b[i].entity == cl.playernum + 1) // entity 0 is the world - { - // set up gun position - // code straight out of CL_AddViewWeapon - ps = cl.frame.playerstate; - int j = (cl.frame.serverframe - 1) & UPDATE_MASK; - oldframe = cl.frames[j]; - - if (oldframe.serverframe != cl.frame.serverframe - 1 || !oldframe.valid) - oldframe = cl.frame; // previous frame was dropped or involid - - ops = oldframe.playerstate; - for (j = 0; j < 3; j++) { - b[i].start[j] = - cl.refdef.vieworg[j] - + ops.gunoffset[j] - + cl.lerpfrac * (ps.gunoffset[j] - ops.gunoffset[j]); - } - VectorMA(b[i].start, (hand_multiplier * b[i].offset[0]), cl.v_right, org); - VectorMA(org, b[i].offset[1], cl.v_forward, org); - VectorMA(org, b[i].offset[2], cl.v_up, org); - if ((hand != null) && (hand.value == 2)) { - VectorMA(org, -1, cl.v_up, org); - } - // FIXME - take these out when final - VectorCopy(cl.v_right, r); - VectorCopy(cl.v_forward, f); - VectorCopy(cl.v_up, u); - - } else - VectorCopy(b[i].start, org); - } else { - // if coming from the player, update the start position - if (b[i].entity == cl.playernum + 1) // entity 0 is the world - { - VectorCopy(cl.refdef.vieworg, b[i].start); - b[i].start[2] -= 22; // adjust for view height - } - VectorAdd(b[i].start, b[i].offset, org); - } - - // calculate pitch and yaw - VectorSubtract(b[i].end, org, dist); - - // PMM - if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam) && (b[i].entity == cl.playernum + 1)) { - - len = VectorLength(dist); - VectorScale(f, len, dist); - VectorMA(dist, (hand_multiplier * b[i].offset[0]), r, dist); - VectorMA(dist, b[i].offset[1], f, dist); - VectorMA(dist, b[i].offset[2], u, dist); - if ((hand != null) && (hand.value == 2)) { - VectorMA(org, -1, cl.v_up, org); - } - } - // PMM - - if (dist[1] == 0 && dist[0] == 0) { - yaw = 0; - if (dist[2] > 0) - pitch = 90; - else - pitch = 270; - } else { - // PMM - fixed to correct for pitch of 0 - if (dist[0] != 0.0f) - yaw = (float) (Math.atan2(dist[1], dist[0]) * 180 / Math.PI); - else if (dist[1] > 0) - yaw = 90; - else - yaw = 270; - if (yaw < 0) - yaw += 360; - - forward = (float)Math.sqrt(dist[0] * dist[0] + dist[1] * dist[1]); - pitch = (float) (Math.atan2(dist[2], forward) * -180.0 / Math.PI); - if (pitch < 0) - pitch += 360.0; - } - - if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) { - if (b[i].entity != cl.playernum + 1) { - framenum = 2; - // Com_Printf ("Third person\n"); - ent.angles[0] = -pitch; - ent.angles[1] = yaw + 180.0f; - ent.angles[2] = 0; - // Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b[i].offset[0], b[i].offset[1], b[i].offset[2]); - AngleVectors(ent.angles, f, r, u); - - // if it's a non-origin offset, it's a player, so use the hardcoded player offset - if (VectorCompare(b[i].offset, vec3_origin) == 0) { - VectorMA(org, - (b[i].offset[0]) + 1, r, org); - VectorMA(org, - (b[i].offset[1]), f, org); - VectorMA(org, - (b[i].offset[2]) - 10, u, org); - } else { - // if it's a monster, do the particle effect - CL.MonsterPlasma_Shell(b[i].start); - } - } else { - framenum = 1; - } - } - - // if it's the heatbeam, draw the particle effect - if ((cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam) && (b[i].entity == cl.playernum + 1))) { - CL.Heatbeam(org, dist); - } - - // add new entities for the beams - d = VectorNormalize(dist); - - //memset (&ent, 0, sizeof(ent)); - //ent = new entity_t(); - // this is not required. hoz - - if (b[i].model == cl_mod_heatbeam) { - model_length = 32.0f; - } else if (b[i].model == cl_mod_lightning) { - model_length = 35.0f; - d -= 20.0; // correction so it doesn't end in middle of tesla - } else { - model_length = 30.0f; - } - steps = (float)Math.ceil(d / model_length); - len = (d - model_length) / (steps - 1); - - // PMM - special case for lightning model .. if the real length is shorter than the model, - // flip it around & draw it from the end to the start. This prevents the model from going - // through the tesla mine (instead it goes through the target) - if ((b[i].model == cl_mod_lightning) && (d <= model_length)) { - // Com_Printf ("special case\n"); - VectorCopy(b[i].end, ent.origin); - // offset to push beam outside of tesla model (negative because dist is from end to start - // for this beam) - // for (j=0 ; j<3 ; j++) - // ent.origin[j] -= dist[j]*10.0; - ent.model = b[i].model; - ent.flags = RF_FULLBRIGHT; - ent.angles[0] = pitch; - ent.angles[1] = yaw; - ent.angles[2] = rand() % 360; - V.AddEntity(ent); - return; - } - while (d > 0) { - VectorCopy(org, ent.origin); - ent.model = b[i].model; - if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) { - // ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT; - // ent.alpha = 0.3; - ent.flags = RF_FULLBRIGHT; - ent.angles[0] = -pitch; - ent.angles[1] = yaw + 180.0f; - ent.angles[2] = (cl.time) % 360; - // ent.angles[2] = rand()%360; - ent.frame = framenum; - } else if (b[i].model == cl_mod_lightning) { - ent.flags = RF_FULLBRIGHT; - ent.angles[0] = -pitch; - ent.angles[1] = yaw + 180.0f; - ent.angles[2] = rand() % 360; - } else { - ent.angles[0] = pitch; - ent.angles[1] = yaw; - ent.angles[2] = rand() % 360; - } - - // Com_Printf("B: %d . %d\n", b[i].entity, b[i].dest_entity); - V.AddEntity(ent); - - for (int j = 0; j < 3; j++) - org[j] += dist[j] * len; - d -= model_length; - } - } - } - - /* - ================= - CL_AddExplosions - ================= - */ - static void AddExplosions() { - entity_t ent; - int i; - explosion_t[] ex; - float frac; - int f; - - //memset (&ent, 0, sizeof(ent)); Pointer! - ent = null; - ex = cl_explosions; - for (i = 0; i < MAX_EXPLOSIONS; i++) { - if (ex[i].type == ex_free) - continue; - frac = (cl.time - ex[i].start) / 100.0f; - f = (int)Math.floor(frac); - - ent = ex[i].ent; - - switch (ex[i].type) { - case ex_mflash : - if (f >= ex[i].frames - 1) - ex[i].type = ex_free; - break; - case ex_misc : - if (f >= ex[i].frames - 1) { - ex[i].type = ex_free; - break; - } - ent.alpha = 1.0f - frac / (ex[i].frames - 1); - break; - case ex_flash : - if (f >= 1) { - ex[i].type = ex_free; - break; - } - ent.alpha = 1.0f; - break; - case ex_poly : - if (f >= ex[i].frames - 1) { - ex[i].type = ex_free; - break; - } - - ent.alpha = (16.0f - (float)f) / 16.0f; - - if (f < 10) { - ent.skinnum = (f >> 1); - if (ent.skinnum < 0) - ent.skinnum = 0; - } else { - ent.flags |= RF_TRANSLUCENT; - if (f < 13) - ent.skinnum = 5; - else - ent.skinnum = 6; - } - break; - case ex_poly2 : - if (f >= ex[i].frames - 1) { - ex[i].type = ex_free; - break; - } - - ent.alpha = (5.0f - (float)f) / 5.0f; - ent.skinnum = 0; - ent.flags |= RF_TRANSLUCENT; - break; - } - - if (ex[i].type == ex_free) - continue; - if (ex[i].light != 0.0f) { - V.AddLight( - ent.origin, - ex[i].light * ent.alpha, - ex[i].lightcolor[0], - ex[i].lightcolor[1], - ex[i].lightcolor[2]); - } - - VectorCopy(ent.origin, ent.oldorigin); - - if (f < 0) - f = 0; - ent.frame = ex[i].baseframe + f + 1; - ent.oldframe = ex[i].baseframe + f; - ent.backlerp = 1.0f - cl.lerpfrac; - - V.AddEntity(ent); - } - } - - /* - ================= - CL_AddLasers - ================= - */ - static void AddLasers() { - laser_t[] l; - int i; - - l = cl_lasers; - for (i = 0; i < MAX_LASERS; i++) { - if (l[i].endtime >= cl.time) - V.AddEntity(l[i].ent); - } - } - - /* PMM - CL_Sustains */ - static void ProcessSustain() { - cl_sustain_t[] s; - int i; - - s = cl_sustains; - for (i = 0; i < MAX_SUSTAINS; i++) { - if (s[i].id != 0) - if ((s[i].endtime >= cl.time) && (cl.time >= s[i].nextthink)) { - s[i].think.think(s[i]); - } else if (s[i].endtime < cl.time) - s[i].id = 0; - } - } - - /* - ================= - CL_AddTEnts - ================= - */ - static void AddTEnts() { - CL.AddBeams(); - // PMM - draw plasma beams - CL.AddPlayerBeams(); - CL.AddExplosions(); - CL.AddLasers(); - // PMM - set up sustain - CL.ProcessSustain(); - } -} +public class CL_tent { + + static class explosion_t { + int type; + + entity_t ent = new entity_t(); + + int frames; + + float light; + + float[] lightcolor = new float[3]; + + float start; + + int baseframe; + + void clear() { + lightcolor[0] = lightcolor[1] = lightcolor[2] = light = start = type = frames = baseframe = 0; + ent = new entity_t(); + } + } + + static final int MAX_EXPLOSIONS = 32; + + static explosion_t[] cl_explosions = new explosion_t[MAX_EXPLOSIONS]; + + static final int MAX_BEAMS = 32; + + static beam_t[] cl_beams = new beam_t[MAX_BEAMS]; + + // PMM - added this for player-linked beams. Currently only used by the + // plasma beam + static beam_t[] cl_playerbeams = new beam_t[MAX_BEAMS]; + + static final int MAX_LASERS = 32; + + static laser_t[] cl_lasers = new laser_t[MAX_LASERS]; + + // ROGUE + static final int MAX_SUSTAINS = 32; + + static cl_sustain_t[] cl_sustains = new cl_sustain_t[MAX_SUSTAINS]; + + static class beam_t { + int entity; + + int dest_entity; + + model_t model; + + int endtime; + + float[] offset = new float[3]; + + float[] start = new float[3]; + + float[] end = new float[3]; + + void clear() { + offset[0] = offset[1] = offset[2] = start[0] = start[1] = start[2] = end[0] = end[1] = end[2] = entity = dest_entity = endtime = 0; + model = null; + } + } + + static { + for (int i = 0; i < cl_explosions.length; i++) + cl_explosions[i] = new explosion_t(); + } + static { + for (int i = 0; i < cl_beams.length; i++) + cl_beams[i] = new beam_t(); + for (int i = 0; i < cl_playerbeams.length; i++) + cl_playerbeams[i] = new beam_t(); + } + + static class laser_t { + entity_t ent = new entity_t(); + + int endtime; + + void clear() { + endtime = 0; + ent = new entity_t(); + } + } + + static { + for (int i = 0; i < cl_lasers.length; i++) + cl_lasers[i] = new laser_t(); + } + + static { + for (int i = 0; i < cl_sustains.length; i++) + cl_sustains[i] = new cl_sustain_t(); + } + + static final int ex_free = 0; + + static final int ex_explosion = 1; + + static final int ex_misc = 2; + + static final int ex_flash = 3; + + static final int ex_mflash = 4; + + static final int ex_poly = 5; + + static final int ex_poly2 = 6; + + // ROGUE + + // all are references; + static sfx_t cl_sfx_ric1; + + static sfx_t cl_sfx_ric2; + + static sfx_t cl_sfx_ric3; + + static sfx_t cl_sfx_lashit; + + static sfx_t cl_sfx_spark5; + + static sfx_t cl_sfx_spark6; + + static sfx_t cl_sfx_spark7; + + static sfx_t cl_sfx_railg; + + static sfx_t cl_sfx_rockexp; + + static sfx_t cl_sfx_grenexp; + + static sfx_t cl_sfx_watrexp; + + // RAFAEL + static sfx_t cl_sfx_plasexp; + + static sfx_t cl_sfx_footsteps[] = new sfx_t[4]; + + static model_t cl_mod_explode; + + static model_t cl_mod_smoke; + + static model_t cl_mod_flash; + + static model_t cl_mod_parasite_segment; + + static model_t cl_mod_grapple_cable; + + static model_t cl_mod_parasite_tip; + + static model_t cl_mod_explo4; + + static model_t cl_mod_bfg_explo; + + static model_t cl_mod_powerscreen; + + // RAFAEL + static model_t cl_mod_plasmaexplo; + + // ROGUE + static sfx_t cl_sfx_lightning; + + static sfx_t cl_sfx_disrexp; + + static model_t cl_mod_lightning; + + static model_t cl_mod_heatbeam; + + static model_t cl_mod_monster_heatbeam; + + static model_t cl_mod_explo4_big; + + // ROGUE + /* + * ================= CL_RegisterTEntSounds ================= + */ + static void RegisterTEntSounds() { + int i; + String name; + + // PMM - version stuff + // Com_Printf ("%s\n", ROGUE_VERSION_STRING); + // PMM + cl_sfx_ric1 = S.RegisterSound("world/ric1.wav"); + cl_sfx_ric2 = S.RegisterSound("world/ric2.wav"); + cl_sfx_ric3 = S.RegisterSound("world/ric3.wav"); + cl_sfx_lashit = S.RegisterSound("weapons/lashit.wav"); + cl_sfx_spark5 = S.RegisterSound("world/spark5.wav"); + cl_sfx_spark6 = S.RegisterSound("world/spark6.wav"); + cl_sfx_spark7 = S.RegisterSound("world/spark7.wav"); + cl_sfx_railg = S.RegisterSound("weapons/railgf1a.wav"); + cl_sfx_rockexp = S.RegisterSound("weapons/rocklx1a.wav"); + cl_sfx_grenexp = S.RegisterSound("weapons/grenlx1a.wav"); + cl_sfx_watrexp = S.RegisterSound("weapons/xpld_wat.wav"); + // RAFAEL + // cl_sfx_plasexp = S.RegisterSound ("weapons/plasexpl.wav"); + S.RegisterSound("player/land1.wav"); + + S.RegisterSound("player/fall2.wav"); + S.RegisterSound("player/fall1.wav"); + + for (i = 0; i < 4; i++) { + //Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1); + name = "player/step" + (i + 1) + ".wav"; + cl_sfx_footsteps[i] = S.RegisterSound(name); + } + + // PGM + cl_sfx_lightning = S.RegisterSound("weapons/tesla.wav"); + cl_sfx_disrexp = S.RegisterSound("weapons/disrupthit.wav"); + // version stuff + // sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID); + // if (name[0] == 'w') + // name[0] = 'W'; + // PGM + } + + /* + * ================= CL_RegisterTEntModels ================= + */ + static void RegisterTEntModels() { + cl_mod_explode = Globals.re + .RegisterModel("models/objects/explode/tris.md2"); + cl_mod_smoke = Globals.re + .RegisterModel("models/objects/smoke/tris.md2"); + cl_mod_flash = Globals.re + .RegisterModel("models/objects/flash/tris.md2"); + cl_mod_parasite_segment = Globals.re + .RegisterModel("models/monsters/parasite/segment/tris.md2"); + cl_mod_grapple_cable = Globals.re + .RegisterModel("models/ctf/segment/tris.md2"); + cl_mod_parasite_tip = Globals.re + .RegisterModel("models/monsters/parasite/tip/tris.md2"); + cl_mod_explo4 = Globals.re + .RegisterModel("models/objects/r_explode/tris.md2"); + cl_mod_bfg_explo = Globals.re.RegisterModel("sprites/s_bfg2.sp2"); + cl_mod_powerscreen = Globals.re + .RegisterModel("models/items/armor/effect/tris.md2"); + + Globals.re.RegisterModel("models/objects/laser/tris.md2"); + Globals.re.RegisterModel("models/objects/grenade2/tris.md2"); + Globals.re.RegisterModel("models/weapons/v_machn/tris.md2"); + Globals.re.RegisterModel("models/weapons/v_handgr/tris.md2"); + Globals.re.RegisterModel("models/weapons/v_shotg2/tris.md2"); + Globals.re.RegisterModel("models/objects/gibs/bone/tris.md2"); + Globals.re.RegisterModel("models/objects/gibs/sm_meat/tris.md2"); + Globals.re.RegisterModel("models/objects/gibs/bone2/tris.md2"); + // RAFAEL + // re.RegisterModel ("models/objects/blaser/tris.md2"); + + Globals.re.RegisterPic("w_machinegun"); + Globals.re.RegisterPic("a_bullets"); + Globals.re.RegisterPic("i_health"); + Globals.re.RegisterPic("a_grenades"); + + // ROGUE + cl_mod_explo4_big = Globals.re + .RegisterModel("models/objects/r_explode2/tris.md2"); + cl_mod_lightning = Globals.re + .RegisterModel("models/proj/lightning/tris.md2"); + cl_mod_heatbeam = Globals.re.RegisterModel("models/proj/beam/tris.md2"); + cl_mod_monster_heatbeam = Globals.re + .RegisterModel("models/proj/widowbeam/tris.md2"); + // ROGUE + } + + /* + * ================= CL_ClearTEnts ================= + */ + static void ClearTEnts() { + // memset (cl_beams, 0, sizeof(cl_beams)); + for (int i = 0; i < cl_beams.length; i++) + cl_beams[i].clear(); + // memset (cl_explosions, 0, sizeof(cl_explosions)); + for (int i = 0; i < cl_explosions.length; i++) + cl_explosions[i].clear(); + // memset (cl_lasers, 0, sizeof(cl_lasers)); + for (int i = 0; i < cl_lasers.length; i++) + cl_lasers[i].clear(); + // + // ROGUE + // memset (cl_playerbeams, 0, sizeof(cl_playerbeams)); + for (int i = 0; i < cl_playerbeams.length; i++) + cl_playerbeams[i].clear(); + // memset (cl_sustains, 0, sizeof(cl_sustains)); + for (int i = 0; i < cl_sustains.length; i++) + cl_sustains[i].clear(); + // ROGUE + } + + /* + * ================= CL_AllocExplosion ================= + */ + static explosion_t AllocExplosion() { + int i; + int time; + int index; + + for (i = 0; i < MAX_EXPLOSIONS; i++) { + if (cl_explosions[i].type == ex_free) { + //memset (&cl_explosions[i], 0, sizeof (cl_explosions[i])); + cl_explosions[i].clear(); + return cl_explosions[i]; + } + } + // find the oldest explosion + time = Globals.cl.time; + index = 0; + + for (i = 0; i < MAX_EXPLOSIONS; i++) + if (cl_explosions[i].start < time) { + time = (int) cl_explosions[i].start; + index = i; + } + //memset (&cl_explosions[index], 0, sizeof (cl_explosions[index])); + cl_explosions[index].clear(); + return cl_explosions[index]; + } + + /* + * ================= CL_SmokeAndFlash ================= + */ + static void SmokeAndFlash(float[] origin) { + explosion_t ex; + + ex = AllocExplosion(); + Math3D.VectorCopy(origin, ex.ent.origin); + ex.type = ex_misc; + ex.frames = 4; + ex.ent.flags = Defines.RF_TRANSLUCENT; + ex.start = Globals.cl.frame.servertime - 100; + ex.ent.model = cl_mod_smoke; + + ex = AllocExplosion(); + Math3D.VectorCopy(origin, ex.ent.origin); + ex.type = ex_flash; + ex.ent.flags = Defines.RF_FULLBRIGHT; + ex.frames = 2; + ex.start = Globals.cl.frame.servertime - 100; + ex.ent.model = cl_mod_flash; + } + + /* + * ================= CL_ParseParticles ================= + */ + static void ParseParticles() { + int color, count; + float[] pos = new float[3]; + float[] dir = new float[3]; + + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + + color = MSG.ReadByte(Globals.net_message); + + count = MSG.ReadByte(Globals.net_message); + + CL_fx.ParticleEffect(pos, dir, color, count); + } + + /* + * ================= CL_ParseBeam ================= + */ + static int ParseBeam(model_t model) { + int ent; + float[] start = new float[3]; + float[] end = new float[3]; + beam_t[] b; + int i; + + ent = MSG.ReadShort(Globals.net_message); + + MSG.ReadPos(Globals.net_message, start); + MSG.ReadPos(Globals.net_message, end); + + // override any beam with the same entity + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) + if (b[i].entity == ent) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = Globals.cl.time + 200; + Math3D.VectorCopy(start, b[i].start); + Math3D.VectorCopy(end, b[i].end); + Math3D.VectorClear(b[i].offset); + return ent; + } + + // find a free beam + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].model == null || b[i].endtime < Globals.cl.time) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = Globals.cl.time + 200; + Math3D.VectorCopy(start, b[i].start); + Math3D.VectorCopy(end, b[i].end); + Math3D.VectorClear(b[i].offset); + return ent; + } + } + Com.Printf("beam list overflow!\n"); + return ent; + } + + /* + * ================= CL_ParseBeam2 ================= + */ + static int ParseBeam2(model_t model) { + int ent; + float[] start = new float[3]; + float[] end = new float[3]; + float[] offset = new float[3]; + beam_t[] b; + int i; + + ent = MSG.ReadShort(Globals.net_message); + + MSG.ReadPos(Globals.net_message, start); + MSG.ReadPos(Globals.net_message, end); + MSG.ReadPos(Globals.net_message, offset); + + // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]); + + // override any beam with the same entity + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) + if (b[i].entity == ent) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = Globals.cl.time + 200; + Math3D.VectorCopy(start, b[i].start); + Math3D.VectorCopy(end, b[i].end); + Math3D.VectorCopy(offset, b[i].offset); + return ent; + } + + // find a free beam + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].model == null || b[i].endtime < Globals.cl.time) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = Globals.cl.time + 200; + Math3D.VectorCopy(start, b[i].start); + Math3D.VectorCopy(end, b[i].end); + Math3D.VectorCopy(offset, b[i].offset); + return ent; + } + } + Com.Printf("beam list overflow!\n"); + return ent; + } + + // ROGUE + /* + * ================= CL_ParsePlayerBeam - adds to the cl_playerbeam array + * instead of the cl_beams array ================= + */ + static int ParsePlayerBeam(model_t model) { + int ent; + float[] start = new float[3]; + float[] end = new float[3]; + float[] offset = new float[3]; + beam_t[] b; + int i; + + ent = MSG.ReadShort(Globals.net_message); + + MSG.ReadPos(Globals.net_message, start); + MSG.ReadPos(Globals.net_message, end); + // PMM - network optimization + if (model == cl_mod_heatbeam) + Math3D.VectorSet(offset, 2, 7, -3); + else if (model == cl_mod_monster_heatbeam) { + model = cl_mod_heatbeam; + Math3D.VectorSet(offset, 0, 0, 0); + } else + MSG.ReadPos(Globals.net_message, offset); + + // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]); + + // override any beam with the same entity + // PMM - For player beams, we only want one per player (entity) so.. + b = cl_playerbeams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].entity == ent) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = Globals.cl.time + 200; + Math3D.VectorCopy(start, b[i].start); + Math3D.VectorCopy(end, b[i].end); + Math3D.VectorCopy(offset, b[i].offset); + return ent; + } + } + + // find a free beam + b = cl_playerbeams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].model == null || b[i].endtime < Globals.cl.time) { + b[i].entity = ent; + b[i].model = model; + b[i].endtime = Globals.cl.time + 100; // PMM - this needs to be + // 100 to prevent multiple + // heatbeams + Math3D.VectorCopy(start, b[i].start); + Math3D.VectorCopy(end, b[i].end); + Math3D.VectorCopy(offset, b[i].offset); + return ent; + } + } + Com.Printf("beam list overflow!\n"); + return ent; + } + + // rogue + + /* + * ================= CL_ParseLightning ================= + */ + static int ParseLightning(model_t model) { + int srcEnt, destEnt; + float[] start = new float[3]; + float[] end = new float[3]; + beam_t[] b; + int i; + + srcEnt = MSG.ReadShort(Globals.net_message); + destEnt = MSG.ReadShort(Globals.net_message); + + MSG.ReadPos(Globals.net_message, start); + MSG.ReadPos(Globals.net_message, end); + + // override any beam with the same source AND destination entities + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) + if (b[i].entity == srcEnt && b[i].dest_entity == destEnt) { + // Com_Printf("%d: OVERRIDE %d . %d\n", cl.time, srcEnt, + // destEnt); + b[i].entity = srcEnt; + b[i].dest_entity = destEnt; + b[i].model = model; + b[i].endtime = Globals.cl.time + 200; + Math3D.VectorCopy(start, b[i].start); + Math3D.VectorCopy(end, b[i].end); + Math3D.VectorClear(b[i].offset); + return srcEnt; + } + + // find a free beam + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].model == null || b[i].endtime < Globals.cl.time) { + // Com_Printf("%d: NORMAL %d . %d\n", cl.time, srcEnt, destEnt); + b[i].entity = srcEnt; + b[i].dest_entity = destEnt; + b[i].model = model; + b[i].endtime = Globals.cl.time + 200; + Math3D.VectorCopy(start, b[i].start); + Math3D.VectorCopy(end, b[i].end); + Math3D.VectorClear(b[i].offset); + return srcEnt; + } + } + Com.Printf("beam list overflow!\n"); + return srcEnt; + } + + /* + * ================= CL_ParseLaser ================= + */ + static void ParseLaser(int colors) { + float[] start = new float[3]; + float[] end = new float[3]; + laser_t[] l; + int i; + + MSG.ReadPos(Globals.net_message, start); + MSG.ReadPos(Globals.net_message, end); + + l = cl_lasers; + for (i = 0; i < MAX_LASERS; i++) { + if (l[i].endtime < Globals.cl.time) { + l[i].ent.flags = Defines.RF_TRANSLUCENT | Defines.RF_BEAM; + Math3D.VectorCopy(start, l[i].ent.origin); + Math3D.VectorCopy(end, l[i].ent.oldorigin); + l[i].ent.alpha = 0.30f; + l[i].ent.skinnum = (colors >> ((Lib.rand() % 4) * 8)) & 0xff; + l[i].ent.model = null; + l[i].ent.frame = 4; + l[i].endtime = Globals.cl.time + 100; + return; + } + } + } + + // ============= + // ROGUE + static void ParseSteam() { + float[] pos = new float[3]; + float[] dir = new float[3]; + int id, i; + int r; + int cnt; + int color; + int magnitude; + cl_sustain_t[] s; + cl_sustain_t free_sustain; + + id = MSG.ReadShort(Globals.net_message); // an id of -1 is an instant + // effect + if (id != -1) // sustains + { + // Com_Printf ("Sustain effect id %d\n", id); + free_sustain = null; + s = cl_sustains; + for (i = 0; i < MAX_SUSTAINS; i++) { + if (s[i].id == 0) { + free_sustain = s[i]; + break; + } + } + if (free_sustain != null) { + s[i].id = id; + s[i].count = MSG.ReadByte(Globals.net_message); + MSG.ReadPos(Globals.net_message, s[i].org); + MSG.ReadDir(Globals.net_message, s[i].dir); + r = MSG.ReadByte(Globals.net_message); + s[i].color = r & 0xff; + s[i].magnitude = MSG.ReadShort(Globals.net_message); + s[i].endtime = Globals.cl.time + + MSG.ReadLong(Globals.net_message); + s[i].think = new cl_sustain_t.ThinkAdapter() { + void think(cl_sustain_t self) { + CL_newfx.ParticleSteamEffect2(self); + } + }; + s[i].thinkinterval = 100; + s[i].nextthink = Globals.cl.time; + } else { + // Com_Printf ("No free sustains!\n"); + // FIXME - read the stuff anyway + cnt = MSG.ReadByte(Globals.net_message); + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + r = MSG.ReadByte(Globals.net_message); + magnitude = MSG.ReadShort(Globals.net_message); + magnitude = MSG.ReadLong(Globals.net_message); // really + // interval + } + } else // instant + { + cnt = MSG.ReadByte(Globals.net_message); + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + r = MSG.ReadByte(Globals.net_message); + magnitude = MSG.ReadShort(Globals.net_message); + color = r & 0xff; + CL_newfx.ParticleSteamEffect(pos, dir, color, cnt, magnitude); + // S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + } + } + + static void ParseWidow() { + float[] pos = new float[3]; + int id, i; + cl_sustain_t[] s; + cl_sustain_t free_sustain; + + id = MSG.ReadShort(Globals.net_message); + + free_sustain = null; + s = cl_sustains; + for (i = 0; i < MAX_SUSTAINS; i++) { + if (s[i].id == 0) { + free_sustain = s[i]; + break; + } + } + if (free_sustain != null) { + s[i].id = id; + MSG.ReadPos(Globals.net_message, s[i].org); + s[i].endtime = Globals.cl.time + 2100; + s[i].think = new cl_sustain_t.ThinkAdapter() { + void think(cl_sustain_t self) { + CL_newfx.Widowbeamout(self); + } + }; + s[i].thinkinterval = 1; + s[i].nextthink = Globals.cl.time; + } else // no free sustains + { + // FIXME - read the stuff anyway + MSG.ReadPos(Globals.net_message, pos); + } + } + + static void ParseNuke() { + float[] pos = new float[3]; + int i; + cl_sustain_t[] s; + cl_sustain_t free_sustain; + + free_sustain = null; + s = cl_sustains; + for (i = 0; i < MAX_SUSTAINS; i++) { + if (s[i].id == 0) { + free_sustain = s[i]; + break; + } + } + if (free_sustain != null) { + s[i].id = 21000; + MSG.ReadPos(Globals.net_message, s[i].org); + s[i].endtime = Globals.cl.time + 1000; + s[i].think = new cl_sustain_t.ThinkAdapter() { + void think(cl_sustain_t self) { + CL_newfx.Nukeblast(self); + } + }; + s[i].thinkinterval = 1; + s[i].nextthink = Globals.cl.time; + } else // no free sustains + { + // FIXME - read the stuff anyway + MSG.ReadPos(Globals.net_message, pos); + } + } + + // ROGUE + // ============= + + /* + * ================= CL_ParseTEnt ================= + */ + static int[] splash_color = { 0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8 }; + + static void ParseTEnt() { + int type; + float[] pos = new float[3]; + float[] pos2 = new float[3]; + float[] dir = new float[3]; + explosion_t ex; + int cnt; + int color; + int r; + int ent; + int magnitude; + + type = MSG.ReadByte(Globals.net_message); + + switch (type) { + case Defines.TE_BLOOD: // bullet hitting flesh + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + CL_fx.ParticleEffect(pos, dir, 0xe8, 60); + break; + + case Defines.TE_GUNSHOT: // bullet hitting wall + case Defines.TE_SPARKS: + case Defines.TE_BULLET_SPARKS: + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + if (type == Defines.TE_GUNSHOT) + CL_fx.ParticleEffect(pos, dir, 0, 40); + else + CL_fx.ParticleEffect(pos, dir, 0xe0, 6); + + if (type != Defines.TE_SPARKS) { + SmokeAndFlash(pos); + + // impact sound + cnt = Lib.rand() & 15; + if (cnt == 1) + S.StartSound(pos, 0, 0, cl_sfx_ric1, 1, Defines.ATTN_NORM, + 0); + else if (cnt == 2) + S.StartSound(pos, 0, 0, cl_sfx_ric2, 1, Defines.ATTN_NORM, + 0); + else if (cnt == 3) + S.StartSound(pos, 0, 0, cl_sfx_ric3, 1, Defines.ATTN_NORM, + 0); + } + + break; + + case Defines.TE_SCREEN_SPARKS: + case Defines.TE_SHIELD_SPARKS: + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + if (type == Defines.TE_SCREEN_SPARKS) + CL_fx.ParticleEffect(pos, dir, 0xd0, 40); + else + CL_fx.ParticleEffect(pos, dir, 0xb0, 40); + //FIXME : replace or remove this sound + S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0); + break; + + case Defines.TE_SHOTGUN: // bullet hitting wall + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + CL_fx.ParticleEffect(pos, dir, 0, 20); + SmokeAndFlash(pos); + break; + + case Defines.TE_SPLASH: // bullet hitting water + cnt = MSG.ReadByte(Globals.net_message); + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + r = MSG.ReadByte(Globals.net_message); + if (r > 6) + color = 0x00; + else + color = splash_color[r]; + CL_fx.ParticleEffect(pos, dir, color, cnt); + + if (r == Defines.SPLASH_SPARKS) { + r = Lib.rand() & 3; + if (r == 0) + S.StartSound(pos, 0, 0, cl_sfx_spark5, 1, + Defines.ATTN_STATIC, 0); + else if (r == 1) + S.StartSound(pos, 0, 0, cl_sfx_spark6, 1, + Defines.ATTN_STATIC, 0); + else + S.StartSound(pos, 0, 0, cl_sfx_spark7, 1, + Defines.ATTN_STATIC, 0); + } + break; + + case Defines.TE_LASER_SPARKS: + cnt = MSG.ReadByte(Globals.net_message); + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + color = MSG.ReadByte(Globals.net_message); + CL_fx.ParticleEffect2(pos, dir, color, cnt); + break; + + // RAFAEL + case Defines.TE_BLUEHYPERBLASTER: + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadPos(Globals.net_message, dir); + CL_fx.BlasterParticles(pos, dir); + break; + + case Defines.TE_BLASTER: // blaster hitting wall + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + CL_fx.BlasterParticles(pos, dir); + + ex = AllocExplosion(); + Math3D.VectorCopy(pos, ex.ent.origin); + ex.ent.angles[0] = (float) (Math.acos(dir[2]) / Math.PI * 180); + // PMM - fixed to correct for pitch of 0 + if (dir[0] != 0.0f) + ex.ent.angles[1] = (float) (Math.atan2(dir[1], dir[0]) + / Math.PI * 180); + else if (dir[1] > 0) + ex.ent.angles[1] = 90; + else if (dir[1] < 0) + ex.ent.angles[1] = 270; + else + ex.ent.angles[1] = 0; + + ex.type = ex_misc; + ex.ent.flags = Defines.RF_FULLBRIGHT | Defines.RF_TRANSLUCENT; + ex.start = Globals.cl.frame.servertime - 100; + ex.light = 150; + ex.lightcolor[0] = 1; + ex.lightcolor[1] = 1; + ex.ent.model = cl_mod_explode; + ex.frames = 4; + S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0); + break; + + case Defines.TE_RAILTRAIL: // railgun effect + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadPos(Globals.net_message, pos2); + CL_fx.RailTrail(pos, pos2); + S.StartSound(pos2, 0, 0, cl_sfx_railg, 1, Defines.ATTN_NORM, 0); + break; + + case Defines.TE_EXPLOSION2: + case Defines.TE_GRENADE_EXPLOSION: + case Defines.TE_GRENADE_EXPLOSION_WATER: + MSG.ReadPos(Globals.net_message, pos); + + ex = AllocExplosion(); + Math3D.VectorCopy(pos, ex.ent.origin); + ex.type = ex_poly; + ex.ent.flags = Defines.RF_FULLBRIGHT; + ex.start = Globals.cl.frame.servertime - 100; + ex.light = 350; + ex.lightcolor[0] = 1.0f; + ex.lightcolor[1] = 0.5f; + ex.lightcolor[2] = 0.5f; + ex.ent.model = cl_mod_explo4; + ex.frames = 19; + ex.baseframe = 30; + ex.ent.angles[1] = Lib.rand() % 360; + CL_fx.ExplosionParticles(pos); + if (type == Defines.TE_GRENADE_EXPLOSION_WATER) + S + .StartSound(pos, 0, 0, cl_sfx_watrexp, 1, + Defines.ATTN_NORM, 0); + else + S + .StartSound(pos, 0, 0, cl_sfx_grenexp, 1, + Defines.ATTN_NORM, 0); + break; + + // RAFAEL + case Defines.TE_PLASMA_EXPLOSION: + MSG.ReadPos(Globals.net_message, pos); + ex = AllocExplosion(); + Math3D.VectorCopy(pos, ex.ent.origin); + ex.type = ex_poly; + ex.ent.flags = Defines.RF_FULLBRIGHT; + ex.start = Globals.cl.frame.servertime - 100; + ex.light = 350; + ex.lightcolor[0] = 1.0f; + ex.lightcolor[1] = 0.5f; + ex.lightcolor[2] = 0.5f; + ex.ent.angles[1] = Lib.rand() % 360; + ex.ent.model = cl_mod_explo4; + if (Globals.rnd.nextFloat() < 0.5) + ex.baseframe = 15; + ex.frames = 15; + CL_fx.ExplosionParticles(pos); + S.StartSound(pos, 0, 0, cl_sfx_rockexp, 1, Defines.ATTN_NORM, 0); + break; + + case Defines.TE_EXPLOSION1: + case Defines.TE_EXPLOSION1_BIG: // PMM + case Defines.TE_ROCKET_EXPLOSION: + case Defines.TE_ROCKET_EXPLOSION_WATER: + case Defines.TE_EXPLOSION1_NP: // PMM + MSG.ReadPos(Globals.net_message, pos); + + ex = AllocExplosion(); + Math3D.VectorCopy(pos, ex.ent.origin); + ex.type = ex_poly; + ex.ent.flags = Defines.RF_FULLBRIGHT; + ex.start = Globals.cl.frame.servertime - 100; + ex.light = 350; + ex.lightcolor[0] = 1.0f; + ex.lightcolor[1] = 0.5f; + ex.lightcolor[2] = 0.5f; + ex.ent.angles[1] = Lib.rand() % 360; + if (type != Defines.TE_EXPLOSION1_BIG) // PMM + ex.ent.model = cl_mod_explo4; // PMM + else + ex.ent.model = cl_mod_explo4_big; + if (Globals.rnd.nextFloat() < 0.5) + ex.baseframe = 15; + ex.frames = 15; + if ((type != Defines.TE_EXPLOSION1_BIG) + && (type != Defines.TE_EXPLOSION1_NP)) // PMM + CL_fx.ExplosionParticles(pos); // PMM + if (type == Defines.TE_ROCKET_EXPLOSION_WATER) + S + .StartSound(pos, 0, 0, cl_sfx_watrexp, 1, + Defines.ATTN_NORM, 0); + else + S + .StartSound(pos, 0, 0, cl_sfx_rockexp, 1, + Defines.ATTN_NORM, 0); + break; + + case Defines.TE_BFG_EXPLOSION: + MSG.ReadPos(Globals.net_message, pos); + ex = AllocExplosion(); + Math3D.VectorCopy(pos, ex.ent.origin); + ex.type = ex_poly; + ex.ent.flags = Defines.RF_FULLBRIGHT; + ex.start = Globals.cl.frame.servertime - 100; + ex.light = 350; + ex.lightcolor[0] = 0.0f; + ex.lightcolor[1] = 1.0f; + ex.lightcolor[2] = 0.0f; + ex.ent.model = cl_mod_bfg_explo; + ex.ent.flags |= Defines.RF_TRANSLUCENT; + ex.ent.alpha = 0.30f; + ex.frames = 4; + break; + + case Defines.TE_BFG_BIGEXPLOSION: + MSG.ReadPos(Globals.net_message, pos); + CL_fx.BFGExplosionParticles(pos); + break; + + case Defines.TE_BFG_LASER: + ParseLaser(0xd0d1d2d3); + break; + + case Defines.TE_BUBBLETRAIL: + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadPos(Globals.net_message, pos2); + CL_fx.BubbleTrail(pos, pos2); + break; + + case Defines.TE_PARASITE_ATTACK: + case Defines.TE_MEDIC_CABLE_ATTACK: + ent = ParseBeam(cl_mod_parasite_segment); + break; + + case Defines.TE_BOSSTPORT: // boss teleporting to station + MSG.ReadPos(Globals.net_message, pos); + CL_fx.BigTeleportParticles(pos); + S.StartSound(pos, 0, 0, S.RegisterSound("misc/bigtele.wav"), 1, + Defines.ATTN_NONE, 0); + break; + + case Defines.TE_GRAPPLE_CABLE: + ent = ParseBeam2(cl_mod_grapple_cable); + break; + + // RAFAEL + case Defines.TE_WELDING_SPARKS: + cnt = MSG.ReadByte(Globals.net_message); + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + color = MSG.ReadByte(Globals.net_message); + CL_fx.ParticleEffect2(pos, dir, color, cnt); + + ex = AllocExplosion(); + Math3D.VectorCopy(pos, ex.ent.origin); + ex.type = ex_flash; + // note to self + // we need a better no draw flag + ex.ent.flags = Defines.RF_BEAM; + ex.start = Globals.cl.frame.servertime - 0.1f; + ex.light = 100 + (Lib.rand() % 75); + ex.lightcolor[0] = 1.0f; + ex.lightcolor[1] = 1.0f; + ex.lightcolor[2] = 0.3f; + ex.ent.model = cl_mod_flash; + ex.frames = 2; + break; + + case Defines.TE_GREENBLOOD: + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + CL_fx.ParticleEffect2(pos, dir, 0xdf, 30); + break; + + // RAFAEL + case Defines.TE_TUNNEL_SPARKS: + cnt = MSG.ReadByte(Globals.net_message); + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + color = MSG.ReadByte(Globals.net_message); + CL_fx.ParticleEffect3(pos, dir, color, cnt); + break; + + // ============= + // PGM + // PMM -following code integrated for flechette (different color) + case Defines.TE_BLASTER2: // green blaster hitting wall + case Defines.TE_FLECHETTE: // flechette + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + + // PMM + if (type == Defines.TE_BLASTER2) + CL_newfx.BlasterParticles2(pos, dir, 0xd0); + else + CL_newfx.BlasterParticles2(pos, dir, 0x6f); // 75 + + ex = AllocExplosion(); + Math3D.VectorCopy(pos, ex.ent.origin); + ex.ent.angles[0] = (float) (Math.acos(dir[2]) / Math.PI * 180); + // PMM - fixed to correct for pitch of 0 + if (dir[0] != 0.0f) + ex.ent.angles[1] = (float) (Math.atan2(dir[1], dir[0]) + / Math.PI * 180); + else if (dir[1] > 0) + ex.ent.angles[1] = 90; + else if (dir[1] < 0) + ex.ent.angles[1] = 270; + else + ex.ent.angles[1] = 0; + + ex.type = ex_misc; + ex.ent.flags = Defines.RF_FULLBRIGHT | Defines.RF_TRANSLUCENT; + + // PMM + if (type == Defines.TE_BLASTER2) + ex.ent.skinnum = 1; + else + // flechette + ex.ent.skinnum = 2; + + ex.start = Globals.cl.frame.servertime - 100; + ex.light = 150; + // PMM + if (type == Defines.TE_BLASTER2) + ex.lightcolor[1] = 1; + else // flechette + { + ex.lightcolor[0] = 0.19f; + ex.lightcolor[1] = 0.41f; + ex.lightcolor[2] = 0.75f; + } + ex.ent.model = cl_mod_explode; + ex.frames = 4; + S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0); + break; + + case Defines.TE_LIGHTNING: + ent = ParseLightning(cl_mod_lightning); + S.StartSound(null, ent, Defines.CHAN_WEAPON, cl_sfx_lightning, 1, + Defines.ATTN_NORM, 0); + break; + + case Defines.TE_DEBUGTRAIL: + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadPos(Globals.net_message, pos2); + CL_newfx.DebugTrail(pos, pos2); + break; + + case Defines.TE_PLAIN_EXPLOSION: + MSG.ReadPos(Globals.net_message, pos); + + ex = AllocExplosion(); + Math3D.VectorCopy(pos, ex.ent.origin); + ex.type = ex_poly; + ex.ent.flags = Defines.RF_FULLBRIGHT; + ex.start = Globals.cl.frame.servertime - 100; + ex.light = 350; + ex.lightcolor[0] = 1.0f; + ex.lightcolor[1] = 0.5f; + ex.lightcolor[2] = 0.5f; + ex.ent.angles[1] = Lib.rand() % 360; + ex.ent.model = cl_mod_explo4; + if (Globals.rnd.nextFloat() < 0.5) + ex.baseframe = 15; + ex.frames = 15; + if (type == Defines.TE_ROCKET_EXPLOSION_WATER) + S + .StartSound(pos, 0, 0, cl_sfx_watrexp, 1, + Defines.ATTN_NORM, 0); + else + S + .StartSound(pos, 0, 0, cl_sfx_rockexp, 1, + Defines.ATTN_NORM, 0); + break; + + case Defines.TE_FLASHLIGHT: + MSG.ReadPos(Globals.net_message, pos); + ent = MSG.ReadShort(Globals.net_message); + CL_newfx.Flashlight(ent, pos); + break; + + case Defines.TE_FORCEWALL: + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadPos(Globals.net_message, pos2); + color = MSG.ReadByte(Globals.net_message); + CL_newfx.ForceWall(pos, pos2, color); + break; + + case Defines.TE_HEATBEAM: + ent = ParsePlayerBeam(cl_mod_heatbeam); + break; + + case Defines.TE_MONSTER_HEATBEAM: + ent = ParsePlayerBeam(cl_mod_monster_heatbeam); + break; + + case Defines.TE_HEATBEAM_SPARKS: + // cnt = MSG.ReadByte (net_message); + cnt = 50; + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + // r = MSG.ReadByte (net_message); + // magnitude = MSG.ReadShort (net_message); + r = 8; + magnitude = 60; + color = r & 0xff; + CL_newfx.ParticleSteamEffect(pos, dir, color, cnt, magnitude); + S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0); + break; + + case Defines.TE_HEATBEAM_STEAM: + // cnt = MSG.ReadByte (net_message); + cnt = 20; + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + // r = MSG.ReadByte (net_message); + // magnitude = MSG.ReadShort (net_message); + // color = r & 0xff; + color = 0xe0; + magnitude = 60; + CL_newfx.ParticleSteamEffect(pos, dir, color, cnt, magnitude); + S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0); + break; + + case Defines.TE_STEAM: + ParseSteam(); + break; + + case Defines.TE_BUBBLETRAIL2: + // cnt = MSG.ReadByte (net_message); + cnt = 8; + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadPos(Globals.net_message, pos2); + CL_newfx.BubbleTrail2(pos, pos2, cnt); + S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0); + break; + + case Defines.TE_MOREBLOOD: + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + CL_fx.ParticleEffect(pos, dir, 0xe8, 250); + break; + + case Defines.TE_CHAINFIST_SMOKE: + dir[0] = 0; + dir[1] = 0; + dir[2] = 1; + MSG.ReadPos(Globals.net_message, pos); + CL_newfx.ParticleSmokeEffect(pos, dir, 0, 20, 20); + break; + + case Defines.TE_ELECTRIC_SPARKS: + MSG.ReadPos(Globals.net_message, pos); + MSG.ReadDir(Globals.net_message, dir); + // CL_ParticleEffect (pos, dir, 109, 40); + CL_fx.ParticleEffect(pos, dir, 0x75, 40); + //FIXME : replace or remove this sound + S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, Defines.ATTN_NORM, 0); + break; + + case Defines.TE_TRACKER_EXPLOSION: + MSG.ReadPos(Globals.net_message, pos); + CL_newfx.ColorFlash(pos, 0, 150, -1, -1, -1); + CL_newfx.ColorExplosionParticles(pos, 0, 1); + // CL_Tracker_Explode (pos); + S.StartSound(pos, 0, 0, cl_sfx_disrexp, 1, Defines.ATTN_NORM, 0); + break; + + case Defines.TE_TELEPORT_EFFECT: + case Defines.TE_DBALL_GOAL: + MSG.ReadPos(Globals.net_message, pos); + CL_fx.TeleportParticles(pos); + break; + + case Defines.TE_WIDOWBEAMOUT: + ParseWidow(); + break; + + case Defines.TE_NUKEBLAST: + ParseNuke(); + break; + + case Defines.TE_WIDOWSPLASH: + MSG.ReadPos(Globals.net_message, pos); + CL_newfx.WidowSplash(pos); + break; + // PGM + // ============== + + default: + Com.Error(Defines.ERR_DROP, "CL_ParseTEnt: bad type"); + } + } + + /* + * ================= CL_AddBeams ================= + */ + static void AddBeams() { + int i, j; + beam_t[] b; + float[] dist = new float[3]; + float[] org = new float[3]; + float d; + entity_t ent = new entity_t(); + float yaw, pitch; + float forward; + float len, steps; + float model_length; + + // update beams + b = cl_beams; + for (i = 0; i < MAX_BEAMS; i++) { + if (b[i].model == null || b[i].endtime < Globals.cl.time) + continue; + + // if coming from the player, update the start position + if (b[i].entity == Globals.cl.playernum + 1) // entity 0 is the + // world + { + Math3D.VectorCopy(Globals.cl.refdef.vieworg, b[i].start); + b[i].start[2] -= 22; // adjust for view height + } + Math3D.VectorAdd(b[i].start, b[i].offset, org); + + // calculate pitch and yaw + Math3D.VectorSubtract(b[i].end, org, dist); + + if (dist[1] == 0 && dist[0] == 0) { + yaw = 0; + if (dist[2] > 0) + pitch = 90; + else + pitch = 270; + } else { + // PMM - fixed to correct for pitch of 0 + if (dist[0] != 0.0f) + yaw = (float) (Math.atan2(dist[1], dist[0]) * 180 / Math.PI); + else if (dist[1] > 0) + yaw = 90; + else + yaw = 270; + if (yaw < 0) + yaw += 360; + + forward = (float) Math.sqrt(dist[0] * dist[0] + dist[1] + * dist[1]); + pitch = (float) (Math.atan2(dist[2], forward) * -180.0 / Math.PI); + if (pitch < 0) + pitch += 360.0; + } + + // add new entities for the beams + d = Math3D.VectorNormalize(dist); + + //memset (&ent, 0, sizeof(ent)); + ent = new entity_t(); + if (b[i].model == cl_mod_lightning) { + model_length = 35.0f; + d -= 20.0; // correction so it doesn't end in middle of tesla + } else { + model_length = 30.0f; + } + steps = (float) Math.ceil(d / model_length); + len = (d - model_length) / (steps - 1); + + // PMM - special case for lightning model .. if the real length is + // shorter than the model, + // flip it around & draw it from the end to the start. This prevents + // the model from going + // through the tesla mine (instead it goes through the target) + if ((b[i].model == cl_mod_lightning) && (d <= model_length)) { + // Com_Printf ("special case\n"); + Math3D.VectorCopy(b[i].end, ent.origin); + // offset to push beam outside of tesla model (negative because + // dist is from end to start + // for this beam) + // for (j=0 ; j<3 ; j++) + // ent.origin[j] -= dist[j]*10.0; + ent.model = b[i].model; + ent.flags = Defines.RF_FULLBRIGHT; + ent.angles[0] = pitch; + ent.angles[1] = yaw; + ent.angles[2] = Lib.rand() % 360; + V.AddEntity(ent); + return; + } + while (d > 0) { + Math3D.VectorCopy(org, ent.origin); + ent.model = b[i].model; + if (b[i].model == cl_mod_lightning) { + ent.flags = Defines.RF_FULLBRIGHT; + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0f; + ent.angles[2] = Lib.rand() % 360; + } else { + ent.angles[0] = pitch; + ent.angles[1] = yaw; + ent.angles[2] = Lib.rand() % 360; + } + + // Com_Printf("B: %d . %d\n", b[i].entity, b[i].dest_entity); + V.AddEntity(ent); + + for (j = 0; j < 3; j++) + org[j] += dist[j] * len; + d -= model_length; + } + } + } + + //extern cvar_t *hand; + + /* + * ================= ROGUE - draw player locked beams CL_AddPlayerBeams + * ================= + */ + static void AddPlayerBeams() { + float[] dist = new float[3]; + float[] org = new float[3]; + float d; + entity_t ent = new entity_t(); + float yaw, pitch; + float forward; + float len, steps; + int framenum = 0; + float model_length; + + float hand_multiplier; + frame_t oldframe; + player_state_t ps, ops; + + // PMM + if (Globals.hand != null) { + if (Globals.hand.value == 2) + hand_multiplier = 0; + else if (Globals.hand.value == 1) + hand_multiplier = -1; + else + hand_multiplier = 1; + } else { + hand_multiplier = 1; + } + // PMM + + // update beams + beam_t[] b = cl_playerbeams; + float[] f = new float[3]; + float[] u = new float[3]; + float[] r = new float[3]; + for (int i = 0; i < MAX_BEAMS; i++) { + + if (b[i].model == null || b[i].endtime < Globals.cl.time) + continue; + + if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) { + + // if coming from the player, update the start position + if (b[i].entity == Globals.cl.playernum + 1) // entity 0 is the + // world + { + // set up gun position + // code straight out of CL_AddViewWeapon + ps = Globals.cl.frame.playerstate; + int j = (Globals.cl.frame.serverframe - 1) + & Defines.UPDATE_MASK; + oldframe = Globals.cl.frames[j]; + + if (oldframe.serverframe != Globals.cl.frame.serverframe - 1 + || !oldframe.valid) + oldframe = Globals.cl.frame; // previous frame was + // dropped or involid + + ops = oldframe.playerstate; + for (j = 0; j < 3; j++) { + b[i].start[j] = Globals.cl.refdef.vieworg[j] + + ops.gunoffset[j] + Globals.cl.lerpfrac + * (ps.gunoffset[j] - ops.gunoffset[j]); + } + Math3D.VectorMA(b[i].start, + (hand_multiplier * b[i].offset[0]), + Globals.cl.v_right, org); + Math3D.VectorMA(org, b[i].offset[1], Globals.cl.v_forward, + org); + Math3D.VectorMA(org, b[i].offset[2], Globals.cl.v_up, org); + if ((Globals.hand != null) && (Globals.hand.value == 2)) { + Math3D.VectorMA(org, -1, Globals.cl.v_up, org); + } + // FIXME - take these out when final + Math3D.VectorCopy(Globals.cl.v_right, r); + Math3D.VectorCopy(Globals.cl.v_forward, f); + Math3D.VectorCopy(Globals.cl.v_up, u); + + } else + Math3D.VectorCopy(b[i].start, org); + } else { + // if coming from the player, update the start position + if (b[i].entity == Globals.cl.playernum + 1) // entity 0 is the + // world + { + Math3D.VectorCopy(Globals.cl.refdef.vieworg, b[i].start); + b[i].start[2] -= 22; // adjust for view height + } + Math3D.VectorAdd(b[i].start, b[i].offset, org); + } + + // calculate pitch and yaw + Math3D.VectorSubtract(b[i].end, org, dist); + + // PMM + if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam) + && (b[i].entity == Globals.cl.playernum + 1)) { + + len = Math3D.VectorLength(dist); + Math3D.VectorScale(f, len, dist); + Math3D.VectorMA(dist, (hand_multiplier * b[i].offset[0]), r, + dist); + Math3D.VectorMA(dist, b[i].offset[1], f, dist); + Math3D.VectorMA(dist, b[i].offset[2], u, dist); + if ((Globals.hand != null) && (Globals.hand.value == 2)) { + Math3D.VectorMA(org, -1, Globals.cl.v_up, org); + } + } + // PMM + + if (dist[1] == 0 && dist[0] == 0) { + yaw = 0; + if (dist[2] > 0) + pitch = 90; + else + pitch = 270; + } else { + // PMM - fixed to correct for pitch of 0 + if (dist[0] != 0.0f) + yaw = (float) (Math.atan2(dist[1], dist[0]) * 180 / Math.PI); + else if (dist[1] > 0) + yaw = 90; + else + yaw = 270; + if (yaw < 0) + yaw += 360; + + forward = (float) Math.sqrt(dist[0] * dist[0] + dist[1] + * dist[1]); + pitch = (float) (Math.atan2(dist[2], forward) * -180.0 / Math.PI); + if (pitch < 0) + pitch += 360.0; + } + + if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) { + if (b[i].entity != Globals.cl.playernum + 1) { + framenum = 2; + // Com_Printf ("Third person\n"); + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0f; + ent.angles[2] = 0; + // Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, + // b[i].offset[0], b[i].offset[1], b[i].offset[2]); + Math3D.AngleVectors(ent.angles, f, r, u); + + // if it's a non-origin offset, it's a player, so use the + // hardcoded player offset + if (Math3D.VectorCompare(b[i].offset, Globals.vec3_origin) == 0) { + Math3D.VectorMA(org, -(b[i].offset[0]) + 1, r, org); + Math3D.VectorMA(org, -(b[i].offset[1]), f, org); + Math3D.VectorMA(org, -(b[i].offset[2]) - 10, u, org); + } else { + // if it's a monster, do the particle effect + CL_newfx.MonsterPlasma_Shell(b[i].start); + } + } else { + framenum = 1; + } + } + + // if it's the heatbeam, draw the particle effect + if ((cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam) && (b[i].entity == Globals.cl.playernum + 1))) { + CL_newfx.Heatbeam(org, dist); + } + + // add new entities for the beams + d = Math3D.VectorNormalize(dist); + + //memset (&ent, 0, sizeof(ent)); + //ent = new entity_t(); + // this is not required. hoz + + if (b[i].model == cl_mod_heatbeam) { + model_length = 32.0f; + } else if (b[i].model == cl_mod_lightning) { + model_length = 35.0f; + d -= 20.0; // correction so it doesn't end in middle of tesla + } else { + model_length = 30.0f; + } + steps = (float) Math.ceil(d / model_length); + len = (d - model_length) / (steps - 1); + + // PMM - special case for lightning model .. if the real length is + // shorter than the model, + // flip it around & draw it from the end to the start. This prevents + // the model from going + // through the tesla mine (instead it goes through the target) + if ((b[i].model == cl_mod_lightning) && (d <= model_length)) { + // Com_Printf ("special case\n"); + Math3D.VectorCopy(b[i].end, ent.origin); + // offset to push beam outside of tesla model (negative because + // dist is from end to start + // for this beam) + // for (j=0 ; j<3 ; j++) + // ent.origin[j] -= dist[j]*10.0; + ent.model = b[i].model; + ent.flags = Defines.RF_FULLBRIGHT; + ent.angles[0] = pitch; + ent.angles[1] = yaw; + ent.angles[2] = Lib.rand() % 360; + V.AddEntity(ent); + return; + } + while (d > 0) { + Math3D.VectorCopy(org, ent.origin); + ent.model = b[i].model; + if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) { + // ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT; + // ent.alpha = 0.3; + ent.flags = Defines.RF_FULLBRIGHT; + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0f; + ent.angles[2] = (Globals.cl.time) % 360; + // ent.angles[2] = rand()%360; + ent.frame = framenum; + } else if (b[i].model == cl_mod_lightning) { + ent.flags = Defines.RF_FULLBRIGHT; + ent.angles[0] = -pitch; + ent.angles[1] = yaw + 180.0f; + ent.angles[2] = Lib.rand() % 360; + } else { + ent.angles[0] = pitch; + ent.angles[1] = yaw; + ent.angles[2] = Lib.rand() % 360; + } + + // Com_Printf("B: %d . %d\n", b[i].entity, b[i].dest_entity); + V.AddEntity(ent); + + for (int j = 0; j < 3; j++) + org[j] += dist[j] * len; + d -= model_length; + } + } + } + + /* + * ================= CL_AddExplosions ================= + */ + static void AddExplosions() { + entity_t ent; + int i; + explosion_t[] ex; + float frac; + int f; + + //memset (&ent, 0, sizeof(ent)); Pointer! + ent = null; + ex = cl_explosions; + for (i = 0; i < MAX_EXPLOSIONS; i++) { + if (ex[i].type == ex_free) + continue; + frac = (Globals.cl.time - ex[i].start) / 100.0f; + f = (int) Math.floor(frac); + + ent = ex[i].ent; + + switch (ex[i].type) { + case ex_mflash: + if (f >= ex[i].frames - 1) + ex[i].type = ex_free; + break; + case ex_misc: + if (f >= ex[i].frames - 1) { + ex[i].type = ex_free; + break; + } + ent.alpha = 1.0f - frac / (ex[i].frames - 1); + break; + case ex_flash: + if (f >= 1) { + ex[i].type = ex_free; + break; + } + ent.alpha = 1.0f; + break; + case ex_poly: + if (f >= ex[i].frames - 1) { + ex[i].type = ex_free; + break; + } + + ent.alpha = (16.0f - (float) f) / 16.0f; + + if (f < 10) { + ent.skinnum = (f >> 1); + if (ent.skinnum < 0) + ent.skinnum = 0; + } else { + ent.flags |= Defines.RF_TRANSLUCENT; + if (f < 13) + ent.skinnum = 5; + else + ent.skinnum = 6; + } + break; + case ex_poly2: + if (f >= ex[i].frames - 1) { + ex[i].type = ex_free; + break; + } + + ent.alpha = (5.0f - (float) f) / 5.0f; + ent.skinnum = 0; + ent.flags |= Defines.RF_TRANSLUCENT; + break; + } + + if (ex[i].type == ex_free) + continue; + if (ex[i].light != 0.0f) { + V.AddLight(ent.origin, ex[i].light * ent.alpha, + ex[i].lightcolor[0], ex[i].lightcolor[1], + ex[i].lightcolor[2]); + } + + Math3D.VectorCopy(ent.origin, ent.oldorigin); + + if (f < 0) + f = 0; + ent.frame = ex[i].baseframe + f + 1; + ent.oldframe = ex[i].baseframe + f; + ent.backlerp = 1.0f - Globals.cl.lerpfrac; + + V.AddEntity(ent); + } + } + + /* + * ================= CL_AddLasers ================= + */ + static void AddLasers() { + laser_t[] l; + int i; + + l = cl_lasers; + for (i = 0; i < MAX_LASERS; i++) { + if (l[i].endtime >= Globals.cl.time) + V.AddEntity(l[i].ent); + } + } + + /* PMM - CL_Sustains */ + static void ProcessSustain() { + cl_sustain_t[] s; + int i; + + s = cl_sustains; + for (i = 0; i < MAX_SUSTAINS; i++) { + if (s[i].id != 0) + if ((s[i].endtime >= Globals.cl.time) + && (Globals.cl.time >= s[i].nextthink)) { + s[i].think.think(s[i]); + } else if (s[i].endtime < Globals.cl.time) + s[i].id = 0; + } + } + + /* + * ================= CL_AddTEnts ================= + */ + static void AddTEnts() { + AddBeams(); + // PMM - draw plasma beams + AddPlayerBeams(); + AddExplosions(); + AddLasers(); + // PMM - set up sustain + ProcessSustain(); + } +} \ No newline at end of file diff --git a/src/jake2/client/CL_view.java b/src/jake2/client/CL_view.java index ab9efa7..8a834d9 100644 --- a/src/jake2/client/CL_view.java +++ b/src/jake2/client/CL_view.java @@ -1,174 +1,190 @@ /* - * CL_view.java - * Copyright (C) 2004 + * CL_view.java Copyright (C) 2004 * - * $Id: CL_view.java,v 1.3 2004-07-09 06:50:50 hzi Exp $ + * $Id: CL_view.java,v 1.4 2004-09-22 19:22:07 salomo 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. - -*/ + * 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.client; +import jake2.Defines; +import jake2.Globals; import jake2.qcommon.CM; import jake2.qcommon.Com; import jake2.sys.Sys; import java.util.StringTokenizer; -public class CL_view extends CL_input { - - static int num_cl_weaponmodels; - static String[] cl_weaponmodels = new String[MAX_CLIENTWEAPONMODELS]; - - - /* - ================= - CL_PrepRefresh - - Call before entering a new level, or after changing dlls - ================= - */ - static void PrepRefresh() { - String mapname; - int i; - String name; - float rotate; - float[] axis = new float[3]; - - if ((i=cl.configstrings[CS_MODELS+1].length()) == 0) - return; // no map loaded - - SCR.AddDirtyPoint(0, 0); - SCR.AddDirtyPoint(viddef.width-1, viddef.height-1); - - // let the render dll load the map - mapname = cl.configstrings[CS_MODELS+1].substring(5, i - 4); // skip "maps/" - // cut off ".bsp" - - // register models, pics, and skins - Com.Printf("Map: " + mapname + "\r"); - SCR.UpdateScreen(); - re.BeginRegistration(mapname); - Com.Printf(" \r"); - - // precache status bar pics - Com.Printf("pics\r"); - SCR.UpdateScreen(); - SCR.TouchPics(); - Com.Printf(" \r"); - - CL.RegisterTEntModels(); - - num_cl_weaponmodels = 1; - cl_weaponmodels[0] = "weapon.md2"; - - for (i=1 ; i 37) name = name.substring(0, 36); - - - if (name.charAt(0) != '*') - Com.Printf(name + "\r"); - - SCR.UpdateScreen(); - Sys.SendKeyEvents(); // pump message loop - if (name.charAt(0) == '#') { - // special player weapon model - if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS) { - cl_weaponmodels[num_cl_weaponmodels] = cl.configstrings[CS_MODELS+i].substring(1); - num_cl_weaponmodels++; - } - } else { - cl.model_draw[i] = re.RegisterModel(cl.configstrings[CS_MODELS+i]); - if (name.charAt(0) == '*') - cl.model_clip[i] = CM.InlineModel(cl.configstrings[CS_MODELS+i]); - else - cl.model_clip[i] = null; - } - if (name.charAt(0) != '*') - Com.Printf(" \r"); - } - - Com.Printf("images\r"); - SCR.UpdateScreen(); - for (i=1 ; i 0 ; i++) { - cl.image_precache[i] = re.RegisterPic(cl.configstrings[CS_IMAGES+i]); - Sys.SendKeyEvents(); // pump message loop - } - - Com.Printf(" \r"); - for (i=0 ; i 30) - ping = 30; - SCR.DebugGraph (ping, 0xd0); - } -} +public class CL_view { + + static int num_cl_weaponmodels; + + static String[] cl_weaponmodels = new String[Defines.MAX_CLIENTWEAPONMODELS]; + + /* + * ================= + * + * CL_PrepRefresh + * + * Call before entering a new level, or after changing dlls + * ================= + */ + static void PrepRefresh() { + String mapname; + int i; + String name; + float rotate; + float[] axis = new float[3]; + + if ((i = Globals.cl.configstrings[Defines.CS_MODELS + 1].length()) == 0) + return; // no map loaded + + SCR.AddDirtyPoint(0, 0); + SCR.AddDirtyPoint(Globals.viddef.width - 1, Globals.viddef.height - 1); + + // let the render dll load the map + mapname = Globals.cl.configstrings[Defines.CS_MODELS + 1].substring(5, + i - 4); // skip "maps/" + // cut off ".bsp" + + // register models, pics, and skins + Com.Printf("Map: " + mapname + "\r"); + SCR.UpdateScreen(); + Globals.re.BeginRegistration(mapname); + Com.Printf(" \r"); + + // precache status bar pics + Com.Printf("pics\r"); + SCR.UpdateScreen(); + SCR.TouchPics(); + Com.Printf(" \r"); + + CL_tent.RegisterTEntModels(); + + num_cl_weaponmodels = 1; + cl_weaponmodels[0] = "weapon.md2"; + + for (i = 1; i < Defines.MAX_MODELS + && Globals.cl.configstrings[Defines.CS_MODELS + i].length() != 0; i++) { + name = new String(Globals.cl.configstrings[Defines.CS_MODELS + i]); + if (name.length() > 37) + name = name.substring(0, 36); + + if (name.charAt(0) != '*') + Com.Printf(name + "\r"); + + SCR.UpdateScreen(); + Sys.SendKeyEvents(); // pump message loop + if (name.charAt(0) == '#') { + // special player weapon model + if (num_cl_weaponmodels < Defines.MAX_CLIENTWEAPONMODELS) { + cl_weaponmodels[num_cl_weaponmodels] = Globals.cl.configstrings[Defines.CS_MODELS + + i].substring(1); + num_cl_weaponmodels++; + } + } else { + Globals.cl.model_draw[i] = Globals.re + .RegisterModel(Globals.cl.configstrings[Defines.CS_MODELS + + i]); + if (name.charAt(0) == '*') + Globals.cl.model_clip[i] = CM + .InlineModel(Globals.cl.configstrings[Defines.CS_MODELS + + i]); + else + Globals.cl.model_clip[i] = null; + } + if (name.charAt(0) != '*') + Com.Printf(" \r"); + } + + Com.Printf("images\r"); + SCR.UpdateScreen(); + for (i = 1; i < Defines.MAX_IMAGES + && Globals.cl.configstrings[Defines.CS_IMAGES + i].length() > 0; i++) { + Globals.cl.image_precache[i] = Globals.re + .RegisterPic(Globals.cl.configstrings[Defines.CS_IMAGES + i]); + Sys.SendKeyEvents(); // pump message loop + } + + Com.Printf(" \r"); + for (i = 0; i < Defines.MAX_CLIENTS; i++) { + if (Globals.cl.configstrings[Defines.CS_PLAYERSKINS + i].length() == 0) + continue; + Com.Printf("client " + i + '\r'); + SCR.UpdateScreen(); + Sys.SendKeyEvents(); // pump message loop + CL_parse.ParseClientinfo(i); + Com.Printf(" \r"); + } + + CL_parse.LoadClientinfo(Globals.cl.baseclientinfo, + "unnamed\\male/grunt"); + + // set sky textures and speed + Com.Printf("sky\r"); + SCR.UpdateScreen(); + rotate = Float + .parseFloat(Globals.cl.configstrings[Defines.CS_SKYROTATE]); + StringTokenizer st = new StringTokenizer( + Globals.cl.configstrings[Defines.CS_SKYAXIS]); + axis[0] = Float.parseFloat(st.nextToken()); + axis[1] = Float.parseFloat(st.nextToken()); + axis[2] = Float.parseFloat(st.nextToken()); + Globals.re.SetSky(Globals.cl.configstrings[Defines.CS_SKY], rotate, + axis); + Com.Printf(" \r"); + + // the renderer can now free unneeded stuff + Globals.re.EndRegistration(); + + // clear any lines of console text + Console.ClearNotify(); + + SCR.UpdateScreen(); + Globals.cl.refresh_prepped = true; + Globals.cl.force_refdef = true; // make sure we have a valid refdef + } + + public static void AddNetgraph() { + int i; + int in; + int ping; + + // if using the debuggraph for something else, don't + // add the net lines + if (SCR.scr_debuggraph.value == 0.0f || SCR.scr_timegraph.value == 0.0f) + return; + + for (i = 0; i < Globals.cls.netchan.dropped; i++) + SCR.DebugGraph(30, 0x40); + + for (i = 0; i < Globals.cl.surpressCount; i++) + SCR.DebugGraph(30, 0xdf); + + // see what the latency was on this packet + in = Globals.cls.netchan.incoming_acknowledged + & (Defines.CMD_BACKUP - 1); + ping = (int) (Globals.cls.realtime - Globals.cl.cmd_time[in]); + ping /= 30; + if (ping > 30) + ping = 30; + SCR.DebugGraph(ping, 0xd0); + } +} \ No newline at end of file diff --git a/src/jake2/client/Console.java b/src/jake2/client/Console.java index b37a1f8..65bf253 100644 --- a/src/jake2/client/Console.java +++ b/src/jake2/client/Console.java @@ -2,27 +2,27 @@ * Con.java * Copyright (C) 2003 * - * $Id: Console.java,v 1.4 2004-07-30 06:03:40 hzi Exp $ + * $Id: Console.java,v 1.5 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; import java.io.IOException; @@ -33,574 +33,582 @@ import jake2.Defines; import jake2.Globals; import jake2.game.Cmd; import jake2.qcommon.*; +import jake2.util.Lib; import jake2.util.Vargs; /** * Console */ public final class Console extends Globals { - - public static xcommand_t ToggleConsole_f = new xcommand_t() { - public void execute() { - SCR.EndLoadingPlaque(); // get rid of loading plaque - - if (Globals.cl.attractloop) { - Cbuf.AddText("killserver\n"); - return; - } - - if (Globals.cls.state == Defines.ca_disconnected) { - // start the demo loop again - Cbuf.AddText("d1\n"); - return; - } - - Key.ClearTyping(); - Console.ClearNotify(); - - if (Globals.cls.key_dest == Defines.key_console) { - Menu.ForceMenuOff(); - Cvar.Set("paused", "0"); - } - else { - Menu.ForceMenuOff(); - Globals.cls.key_dest = Defines.key_console; - - if (Cvar.VariableValue("maxclients") == 1 && Globals.server_state!= 0) - Cvar.Set("paused", "1"); - } - } - }; - - public static xcommand_t Clear_f = new xcommand_t() { - public void execute() { - Arrays.fill(Globals.con.text, (byte)' '); - } - }; - public static xcommand_t Dump_f = new xcommand_t() { - public void execute() { - - int l, x; - int line; - RandomAccessFile f; - byte[] buffer = new byte[1024]; - String name; - - if (Cmd.Argc() != 2) { - Com.Printf("usage: condump \n"); - return; - } - - //Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1)); - name = FS.Gamedir() + "/" + Cmd.Argv(1) + ".txt"; - - Com.Printf("Dumped console text to " + name + ".\n"); - FS.CreatePath(name); - f = fopen(name, "rw"); - if (f == null) { - Com.Printf("ERROR: couldn't open.\n"); - return; - } - - // skip empty lines - for (l = con.current - con.totallines + 1; l <= con.current; l++) { - line = (l % con.totallines) * con.linewidth; - for (x = 0; x < con.linewidth; x++) - if (con.text[line + x] != ' ') - break; - if (x != con.linewidth) - break; - } - - // write the remaining lines - buffer[con.linewidth] = 0; - for (; l <= con.current; l++) { - line = (l % con.totallines) * con.linewidth; - //strncpy (buffer, line, con.linewidth); - System.arraycopy(con.text, line, buffer, 0, con.linewidth); - for (x = con.linewidth - 1; x >= 0; x--) { - if (buffer[x] == ' ') - buffer[x] = 0; - else - break; - } - for (x = 0; buffer[x] != 0; x++) - buffer[x] &= 0x7f; - - buffer[x] = '\n'; - // fprintf (f, "%s\n", buffer); - try { - f.write(buffer, 0, x+1); - } catch (IOException e) {} - } - - fclose(f); - - } - }; - - /** - * - */ - public static void Init() { - Globals.con.linewidth = -1; - - CheckResize(); - - Com.Printf("Console initialized.\n"); - - // - // register our commands - // - Globals.con_notifytime = Cvar.Get("con_notifytime", "3", 0); - - Cmd.AddCommand("toggleconsole", ToggleConsole_f); - Cmd.AddCommand("togglechat", ToggleChat_f); - Cmd.AddCommand("messagemode", MessageMode_f); - Cmd.AddCommand("messagemode2", MessageMode2_f); - Cmd.AddCommand("clear", Clear_f); - Cmd.AddCommand("condump", Dump_f); - Globals.con.initialized = true; - } - - /** - * If the line width has changed, reformat the buffer. - */ - public static void CheckResize() { - - int width = (Globals.viddef.width >> 3) - 2; - - if (width == Globals.con.linewidth) - return; - - if (width < 1) { // video hasn't been initialized yet - width = 38; - Globals.con.linewidth = width; - Globals.con.totallines = Defines.CON_TEXTSIZE / Globals.con.linewidth; - Arrays.fill(Globals.con.text, (byte)' '); - } - else { - int oldwidth = Globals.con.linewidth; - Globals.con.linewidth = width; - int oldtotallines = Globals.con.totallines; - Globals.con.totallines = Defines.CON_TEXTSIZE / Globals.con.linewidth; - int numlines = oldtotallines; - - if (Globals.con.totallines < numlines) - numlines = Globals.con.totallines; - - int numchars = oldwidth; - - if (Globals.con.linewidth < numchars) - numchars = Globals.con.linewidth; - - byte[] tbuf = new byte[Defines.CON_TEXTSIZE]; - System.arraycopy(Globals.con.text, 0, tbuf, 0, Defines.CON_TEXTSIZE); - Arrays.fill(Globals.con.text, (byte)' '); - - for (int i=0 ; i con.linewidth) ) - con.x = 0; - - txtpos++; - - if (cr != 0) { - con.current--; - cr = 0; - } - - if (con.x == 0) { - Console.Linefeed(); - // mark time for transparent overlay - if (con.current >= 0) - con.times[con.current % NUM_CON_TIMES] = cls.realtime; - } - - switch (c) { - case '\n': - con.x = 0; - break; - - case '\r': - con.x = 0; - cr = 1; - break; - - default: // display character and advance - y = con.current % con.totallines; - con.text[y*con.linewidth+con.x] = (byte)(c | mask | con.ormask); - con.x++; - if (con.x >= con.linewidth) - con.x = 0; - break; - } - } - } - - /* - ============== - Con_CenteredPrint - ============== - */ - static void CenteredPrint(String text) { - int l = text.length(); - l = (con.linewidth-l)/2; - if (l < 0) l = 0; - - StringBuffer sb = new StringBuffer(1024); - for (int i = 0; i < l; i++) sb.append(' '); - sb.append(text); - sb.append('\n'); - - sb.setLength(1024); - - Console.Print(sb.toString()); - } - - /* - ============================================================================== - - DRAWING - - ============================================================================== - */ - - /* - ================ - Con_DrawInput - - The input line scrolls horizontally if typing goes beyond the right edge - ================ - */ - static void DrawInput() { - int i; - byte[] text; - int start = 0; - - if (cls.key_dest == key_menu) - return; - if (cls.key_dest != key_console && cls.state == ca_active) - return; // don't draw anything (always draw if not active) - - text = key_lines[edit_line]; - - // add the cursor frame - text[key_linepos] = (byte)(10+((int)(cls.realtime>>8)&1)); - - // fill out remainder with spaces - for (i=key_linepos+1 ; i< con.linewidth ; i++) - text[i] = ' '; - - // prestep if horizontally scrolling - if (key_linepos >= con.linewidth) - start += 1 + key_linepos - con.linewidth; - - // draw it -// y = con.vislines-16; - - for (i=0 ; i con_notifytime.value*1000) continue; - - text = (i % con.totallines)*con.linewidth; - - for (x = 0 ; x < con.linewidth ; x++) - re.DrawChar( (x+1)<<3, v, con.text[text+x]); - - v += 8; - } - - if (cls.key_dest == key_message) { - if (chat_team) { - DrawString(8, v, "say_team:"); - skip = 11; - } else { - DrawString (8, v, "say:"); - skip = 5; - } - - s = chat_buffer; - if (chat_bufferlen > (viddef.width>>3)-(skip+1)) - s = s.substring(chat_bufferlen - ((viddef.width>>3)-(skip+1))); - - for (x = 0; x < s.length(); x++) { - re.DrawChar( (x+skip)<<3, v, s.charAt(x)); - } - re.DrawChar( (x+skip)<<3, v, (int)(10+((cls.realtime>>8)&1))); - v += 8; - } - - if (v != 0) { - SCR.AddDirtyPoint(0,0); - SCR.AddDirtyPoint(viddef.width-1, v); - } - } - - /* - ================ - Con_DrawConsole - - Draws the console with the solid background - ================ - */ - static void DrawConsole(float frac) { - int i, j, x, y, n; - int rows; - int text; - int row; - int lines; - String version; - String dlbar; - - lines = (int)(viddef.height * frac); - if (lines <= 0) - return; - - if (lines > viddef.height) - lines = viddef.height; - - // draw the background - re.DrawStretchPic(0, -viddef.height+lines, viddef.width, viddef.height, "conback"); - SCR.AddDirtyPoint(0,0); - SCR.AddDirtyPoint(viddef.width-1,lines-1); - - version = Com.sprintf("v%4.2f", new Vargs(1).add(VERSION)); - for (x=0 ; x<5 ; x++) - re.DrawChar (viddef.width-44+x*8, lines-12, 128 + version.charAt(x)); - - // draw the text - con.vislines = lines; - - rows = (lines-22)>>3; // rows of text to draw - - y = lines - 30; - - // draw from the bottom up - if (con.display != con.current) { - // draw arrows to show the buffer is backscrolled - for (x=0 ; x= con.totallines) - break; // past scrollback wrap point - - int first = (row % con.totallines)*con.linewidth; - - for (x=0 ; x i) { - y = x - i - 11; - int end = text + i - 1;; - dlbar = cls.downloadname.substring(text, end); - dlbar += "..."; - } else { - dlbar = cls.downloadname.substring(text); - } - dlbar += ": "; - dlbar += (char)0x80; - - // where's the dot go? - if (cls.downloadpercent == 0) - n = 0; - else - n = y * cls.downloadpercent / 100; - - StringBuffer sb = new StringBuffer(dlbar); - sb.ensureCapacity(1024); - for (j = 0; j < y; j++) { - if (j == n) - sb.append((char)0x83); - else - sb.append((char)0x81); - } - sb.append((char)0x82); - - dlbar = sb.toString(); - dlbar += Com.sprintf(" %02d%%", new Vargs(1).add(cls.downloadpercent)); - - // draw it - y = con.vislines-12; - for (i = 0; i < dlbar.length(); i++) - re.DrawChar ( (i+1)<<3, y, dlbar.charAt(i)); - } - //ZOID - - // draw the input prompt, user text, and cursor if desired - DrawInput(); - } -} + + public static xcommand_t ToggleConsole_f = new xcommand_t() { + public void execute() { + SCR.EndLoadingPlaque(); // get rid of loading plaque + + if (Globals.cl.attractloop) { + Cbuf.AddText("killserver\n"); + return; + } + + if (Globals.cls.state == Defines.ca_disconnected) { + // start the demo loop again + Cbuf.AddText("d1\n"); + return; + } + + Key.ClearTyping(); + Console.ClearNotify(); + + if (Globals.cls.key_dest == Defines.key_console) { + Menu.ForceMenuOff(); + Cvar.Set("paused", "0"); + } else { + Menu.ForceMenuOff(); + Globals.cls.key_dest = Defines.key_console; + + if (Cvar.VariableValue("maxclients") == 1 + && Globals.server_state != 0) + Cvar.Set("paused", "1"); + } + } + }; + + public static xcommand_t Clear_f = new xcommand_t() { + public void execute() { + Arrays.fill(Globals.con.text, (byte) ' '); + } + }; + + public static xcommand_t Dump_f = new xcommand_t() { + public void execute() { + + int l, x; + int line; + RandomAccessFile f; + byte[] buffer = new byte[1024]; + String name; + + if (Cmd.Argc() != 2) { + Com.Printf("usage: condump \n"); + return; + } + + //Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), + // Cmd_Argv(1)); + name = FS.Gamedir() + "/" + Cmd.Argv(1) + ".txt"; + + Com.Printf("Dumped console text to " + name + ".\n"); + FS.CreatePath(name); + f = Lib.fopen(name, "rw"); + if (f == null) { + Com.Printf("ERROR: couldn't open.\n"); + return; + } + + // skip empty lines + for (l = con.current - con.totallines + 1; l <= con.current; l++) { + line = (l % con.totallines) * con.linewidth; + for (x = 0; x < con.linewidth; x++) + if (con.text[line + x] != ' ') + break; + if (x != con.linewidth) + break; + } + + // write the remaining lines + buffer[con.linewidth] = 0; + for (; l <= con.current; l++) { + line = (l % con.totallines) * con.linewidth; + //strncpy (buffer, line, con.linewidth); + System.arraycopy(con.text, line, buffer, 0, con.linewidth); + for (x = con.linewidth - 1; x >= 0; x--) { + if (buffer[x] == ' ') + buffer[x] = 0; + else + break; + } + for (x = 0; buffer[x] != 0; x++) + buffer[x] &= 0x7f; + + buffer[x] = '\n'; + // fprintf (f, "%s\n", buffer); + try { + f.write(buffer, 0, x + 1); + } catch (IOException e) { + } + } + + Lib.fclose(f); + + } + }; + + /** + * + */ + public static void Init() { + Globals.con.linewidth = -1; + + CheckResize(); + + Com.Printf("Console initialized.\n"); + + // + // register our commands + // + Globals.con_notifytime = Cvar.Get("con_notifytime", "3", 0); + + Cmd.AddCommand("toggleconsole", ToggleConsole_f); + Cmd.AddCommand("togglechat", ToggleChat_f); + Cmd.AddCommand("messagemode", MessageMode_f); + Cmd.AddCommand("messagemode2", MessageMode2_f); + Cmd.AddCommand("clear", Clear_f); + Cmd.AddCommand("condump", Dump_f); + Globals.con.initialized = true; + } + + /** + * If the line width has changed, reformat the buffer. + */ + public static void CheckResize() { + + int width = (Globals.viddef.width >> 3) - 2; + + if (width == Globals.con.linewidth) + return; + + if (width < 1) { // video hasn't been initialized yet + width = 38; + Globals.con.linewidth = width; + Globals.con.totallines = Defines.CON_TEXTSIZE + / Globals.con.linewidth; + Arrays.fill(Globals.con.text, (byte) ' '); + } else { + int oldwidth = Globals.con.linewidth; + Globals.con.linewidth = width; + int oldtotallines = Globals.con.totallines; + Globals.con.totallines = Defines.CON_TEXTSIZE + / Globals.con.linewidth; + int numlines = oldtotallines; + + if (Globals.con.totallines < numlines) + numlines = Globals.con.totallines; + + int numchars = oldwidth; + + if (Globals.con.linewidth < numchars) + numchars = Globals.con.linewidth; + + byte[] tbuf = new byte[Defines.CON_TEXTSIZE]; + System + .arraycopy(Globals.con.text, 0, tbuf, 0, + Defines.CON_TEXTSIZE); + Arrays.fill(Globals.con.text, (byte) ' '); + + for (int i = 0; i < numlines; i++) { + for (int j = 0; j < numchars; j++) { + Globals.con.text[(Globals.con.totallines - 1 - i) + * Globals.con.linewidth + j] = tbuf[((Globals.con.current + - i + oldtotallines) % oldtotallines) + * oldwidth + j]; + } + } + + Console.ClearNotify(); + } + + Globals.con.current = Globals.con.totallines - 1; + Globals.con.display = Globals.con.current; + } + + public static void ClearNotify() { + int i; + for (i = 0; i < Defines.NUM_CON_TIMES; i++) + Globals.con.times[i] = 0; + } + + static void DrawString(int x, int y, String s) { + for (int i = 0; i < s.length(); i++) { + Globals.re.DrawChar(x, y, s.charAt(i)); + x += 8; + } + } + + static void DrawAltString(int x, int y, String s) { + for (int i = 0; i < s.length(); i++) { + Globals.re.DrawChar(x, y, s.charAt(i) ^ 0x80); + x += 8; + } + } + + /* + * ================ Con_ToggleChat_f ================ + */ + static xcommand_t ToggleChat_f = new xcommand_t() { + public void execute() { + Key.ClearTyping(); + + if (cls.key_dest == key_console) { + if (cls.state == ca_active) { + Menu.ForceMenuOff(); + cls.key_dest = key_game; + } + } else + cls.key_dest = key_console; + + ClearNotify(); + } + }; + + /* + * ================ Con_MessageMode_f ================ + */ + static xcommand_t MessageMode_f = new xcommand_t() { + public void execute() { + chat_team = false; + cls.key_dest = key_message; + } + }; + + /* + * ================ Con_MessageMode2_f ================ + */ + static xcommand_t MessageMode2_f = new xcommand_t() { + public void execute() { + chat_team = true; + cls.key_dest = key_message; + } + }; + + /* + * =============== Con_Linefeed =============== + */ + static void Linefeed() { + Globals.con.x = 0; + if (Globals.con.display == Globals.con.current) + Globals.con.display++; + Globals.con.current++; + int i = (Globals.con.current % Globals.con.totallines) + * Globals.con.linewidth; + int e = i + Globals.con.linewidth; + while (i++ < e) + Globals.con.text[i] = ' '; + } + + /* + * ================ Con_Print + * + * Handles cursor positioning, line wrapping, etc All console printing must + * go through this in order to be logged to disk If no console is visible, + * the text will appear at the top of the game window ================ + */ + private static int cr; + + public static void Print(String txt) { + int y; + int c, l; + int mask; + int txtpos = 0; + + if (!con.initialized) + return; + + if (txt.charAt(0) == 1 || txt.charAt(0) == 2) { + mask = 128; // go to colored text + txtpos++; + } else + mask = 0; + + while (txtpos < txt.length()) { + c = txt.charAt(txtpos); + // count word length + for (l = 0; l < con.linewidth && l < (txt.length() - txtpos); l++) + if (txt.charAt(l + txtpos) <= ' ') + break; + + // word wrap + if (l != con.linewidth && (con.x + l > con.linewidth)) + con.x = 0; + + txtpos++; + + if (cr != 0) { + con.current--; + cr = 0; + } + + if (con.x == 0) { + Console.Linefeed(); + // mark time for transparent overlay + if (con.current >= 0) + con.times[con.current % NUM_CON_TIMES] = cls.realtime; + } + + switch (c) { + case '\n': + con.x = 0; + break; + + case '\r': + con.x = 0; + cr = 1; + break; + + default: // display character and advance + y = con.current % con.totallines; + con.text[y * con.linewidth + con.x] = (byte) (c | mask | con.ormask); + con.x++; + if (con.x >= con.linewidth) + con.x = 0; + break; + } + } + } + + /* + * ============== Con_CenteredPrint ============== + */ + static void CenteredPrint(String text) { + int l = text.length(); + l = (con.linewidth - l) / 2; + if (l < 0) + l = 0; + + StringBuffer sb = new StringBuffer(1024); + for (int i = 0; i < l; i++) + sb.append(' '); + sb.append(text); + sb.append('\n'); + + sb.setLength(1024); + + Console.Print(sb.toString()); + } + + /* + * ============================================================================== + * + * DRAWING + * + * ============================================================================== + */ + + /* + * ================ Con_DrawInput + * + * The input line scrolls horizontally if typing goes beyond the right edge + * ================ + */ + static void DrawInput() { + int i; + byte[] text; + int start = 0; + + if (cls.key_dest == key_menu) + return; + if (cls.key_dest != key_console && cls.state == ca_active) + return; // don't draw anything (always draw if not active) + + text = key_lines[edit_line]; + + // add the cursor frame + text[key_linepos] = (byte) (10 + ((int) (cls.realtime >> 8) & 1)); + + // fill out remainder with spaces + for (i = key_linepos + 1; i < con.linewidth; i++) + text[i] = ' '; + + // prestep if horizontally scrolling + if (key_linepos >= con.linewidth) + start += 1 + key_linepos - con.linewidth; + + // draw it + // y = con.vislines-16; + + for (i = 0; i < con.linewidth; i++) + re.DrawChar((i + 1) << 3, con.vislines - 22, text[i]); + + // remove cursor + key_lines[edit_line][key_linepos] = 0; + } + + /* + * ================ Con_DrawNotify + * + * Draws the last few lines of output transparently over the game top + * ================ + */ + static void DrawNotify() { + int x, v; + int text; + int i; + int time; + String s; + int skip; + + v = 0; + for (i = con.current - NUM_CON_TIMES + 1; i <= con.current; i++) { + if (i < 0) + continue; + + time = (int) con.times[i % NUM_CON_TIMES]; + if (time == 0) + continue; + + time = (int) (cls.realtime - time); + if (time > con_notifytime.value * 1000) + continue; + + text = (i % con.totallines) * con.linewidth; + + for (x = 0; x < con.linewidth; x++) + re.DrawChar((x + 1) << 3, v, con.text[text + x]); + + v += 8; + } + + if (cls.key_dest == key_message) { + if (chat_team) { + DrawString(8, v, "say_team:"); + skip = 11; + } else { + DrawString(8, v, "say:"); + skip = 5; + } + + s = chat_buffer; + if (chat_bufferlen > (viddef.width >> 3) - (skip + 1)) + s = s.substring(chat_bufferlen + - ((viddef.width >> 3) - (skip + 1))); + + for (x = 0; x < s.length(); x++) { + re.DrawChar((x + skip) << 3, v, s.charAt(x)); + } + re.DrawChar((x + skip) << 3, v, + (int) (10 + ((cls.realtime >> 8) & 1))); + v += 8; + } + + if (v != 0) { + SCR.AddDirtyPoint(0, 0); + SCR.AddDirtyPoint(viddef.width - 1, v); + } + } + + /* + * ================ Con_DrawConsole + * + * Draws the console with the solid background ================ + */ + static void DrawConsole(float frac) { + int i, j, x, y, n; + int rows; + int text; + int row; + int lines; + String version; + String dlbar; + + lines = (int) (viddef.height * frac); + if (lines <= 0) + return; + + if (lines > viddef.height) + lines = viddef.height; + + // draw the background + re.DrawStretchPic(0, -viddef.height + lines, viddef.width, + viddef.height, "conback"); + SCR.AddDirtyPoint(0, 0); + SCR.AddDirtyPoint(viddef.width - 1, lines - 1); + + version = Com.sprintf("v%4.2f", new Vargs(1).add(VERSION)); + for (x = 0; x < 5; x++) + re.DrawChar(viddef.width - 44 + x * 8, lines - 12, 128 + version + .charAt(x)); + + // draw the text + con.vislines = lines; + + rows = (lines - 22) >> 3; // rows of text to draw + + y = lines - 30; + + // draw from the bottom up + if (con.display != con.current) { + // draw arrows to show the buffer is backscrolled + for (x = 0; x < con.linewidth; x += 4) + re.DrawChar((x + 1) << 3, y, '^'); + + y -= 8; + rows--; + } + + row = con.display; + for (i = 0; i < rows; i++, y -= 8, row--) { + if (row < 0) + break; + if (con.current - row >= con.totallines) + break; // past scrollback wrap point + + int first = (row % con.totallines) * con.linewidth; + + for (x = 0; x < con.linewidth; x++) + re.DrawChar((x + 1) << 3, y, con.text[x + first]); + } + + //ZOID + // draw the download bar + // figure out width + if (cls.download != null) { + if ((text = cls.downloadname.lastIndexOf('/')) != 0) + text++; + else + text = 0; + + x = con.linewidth - ((con.linewidth * 7) / 40); + y = x - (cls.downloadname.length() - text) - 8; + i = con.linewidth / 3; + if (cls.downloadname.length() - text > i) { + y = x - i - 11; + int end = text + i - 1; + ; + dlbar = cls.downloadname.substring(text, end); + dlbar += "..."; + } else { + dlbar = cls.downloadname.substring(text); + } + dlbar += ": "; + dlbar += (char) 0x80; + + // where's the dot go? + if (cls.downloadpercent == 0) + n = 0; + else + n = y * cls.downloadpercent / 100; + + StringBuffer sb = new StringBuffer(dlbar); + sb.ensureCapacity(1024); + for (j = 0; j < y; j++) { + if (j == n) + sb.append((char) 0x83); + else + sb.append((char) 0x81); + } + sb.append((char) 0x82); + + dlbar = sb.toString(); + dlbar += Com.sprintf(" %02d%%", new Vargs(1) + .add(cls.downloadpercent)); + + // draw it + y = con.vislines - 12; + for (i = 0; i < dlbar.length(); i++) + re.DrawChar((i + 1) << 3, y, dlbar.charAt(i)); + } + //ZOID + + // draw the input prompt, user text, and cursor if desired + DrawInput(); + } +} \ No newline at end of file diff --git a/src/jake2/client/M.java b/src/jake2/client/M.java index 3e076a6..2ea0d01 100644 --- a/src/jake2/client/M.java +++ b/src/jake2/client/M.java @@ -2,27 +2,27 @@ * M.java * Copyright (C) 2003 * - * $Id: M.java,v 1.4 2004-07-08 20:56:50 hzi Exp $ + * $Id: M.java,v 1.5 2004-09-22 19:22:07 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; import jake2.Defines; @@ -35,606 +35,529 @@ import jake2.util.Math3D; /** * M */ -public final class M -{ - - public static void M_CheckGround(edict_t ent) - { - float[] point = { 0, 0, 0 }; - trace_t trace; - - if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0) - return; - - if (ent.velocity[2] > 100) - { - ent.groundentity = null; - return; - } - - // if the hull point one-quarter unit down is solid the entity is on ground - point[0] = ent.s.origin[0]; - point[1] = ent.s.origin[1]; - point[2] = ent.s.origin[2] - 0.25f; - - trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, point, ent, Defines.MASK_MONSTERSOLID); - - // check steepness - if (trace.plane.normal[2] < 0.7 && !trace.startsolid) - { - ent.groundentity = null; - return; - } - - // ent.groundentity = trace.ent; - // ent.groundentity_linkcount = trace.ent.linkcount; - // if (!trace.startsolid && !trace.allsolid) - // VectorCopy (trace.endpos, ent.s.origin); - if (!trace.startsolid && !trace.allsolid) - { - Math3D.VectorCopy(trace.endpos, ent.s.origin); - ent.groundentity = trace.ent; - ent.groundentity_linkcount = trace.ent.linkcount; - ent.velocity[2] = 0; - } - } - - public static boolean M_CheckBottom(edict_t ent) - { - float[] mins = { 0, 0, 0 }; - float[] maxs = { 0, 0, 0 }; - float[] start = { 0, 0, 0 }; - float[] stop = { 0, 0, 0 }; - - trace_t trace; - int x, y; - float mid, bottom; - - Math3D.VectorAdd(ent.s.origin, ent.mins, mins); - Math3D.VectorAdd(ent.s.origin, ent.maxs, maxs); - - // if all of the points under the corners are solid world, don't bother - // with the tougher checks - // the corners must be within 16 of the midpoint - start[2] = mins[2] - 1; - for (x = 0; x <= 1; x++) - for (y = 0; y <= 1; y++) - { - start[0] = x != 0 ? maxs[0] : mins[0]; - start[1] = y != 0 ? maxs[1] : mins[1]; - if (GameBase.gi.pointcontents.pointcontents(start) != Defines.CONTENTS_SOLID) - { - GameBase.c_no++; - // - // check it for real... - // - start[2] = mins[2]; - - // the midpoint must be within 16 of the bottom - start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f; - start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f; - stop[2] = start[2] - 2 * GameBase.STEPSIZE; - trace = GameBase.gi.trace(start, GameBase.vec3_origin, GameBase.vec3_origin, stop, ent, Defines.MASK_MONSTERSOLID); - - if (trace.fraction == 1.0) - return false; - mid = bottom = trace.endpos[2]; - - // the corners must be within 16 of the midpoint - for (x = 0; x <= 1; x++) - for (y = 0; y <= 1; y++) - { - start[0] = stop[0] = x != 0 ? maxs[0] : mins[0]; - start[1] = stop[1] = y != 0 ? maxs[1] : mins[1]; - - trace = - GameBase.gi.trace( - start, - GameBase.vec3_origin, - GameBase.vec3_origin, - stop, - ent, - Defines.MASK_MONSTERSOLID); - - if (trace.fraction != 1.0 && trace.endpos[2] > bottom) - bottom = trace.endpos[2]; - if (trace.fraction == 1.0 || mid - trace.endpos[2] > GameBase.STEPSIZE) - return false; - } - - GameBase.c_yes++; - return true; - } - } - - GameBase.c_yes++; - return true; // we got out easy - } - - /* - =============== - M_ChangeYaw - - =============== - */ //ok - public static void M_ChangeYaw(edict_t ent) - { - float ideal; - float current; - float move; - float speed; - - current = Math3D.anglemod(ent.s.angles[Defines.YAW]); - ideal = ent.ideal_yaw; - - if (current == ideal) - return; - - move = ideal - current; - speed = ent.yaw_speed; - if (ideal > current) - { - if (move >= 180) - move = move - 360; - } - else - { - if (move <= -180) - move = move + 360; - } - if (move > 0) - { - if (move > speed) - move = speed; - } - else - { - if (move < -speed) - move = -speed; - } - - ent.s.angles[Defines.YAW] = Math3D.anglemod(current + move); - } - - /* - ====================== - M_MoveToGoal - ====================== - */ // ok - public static void M_MoveToGoal(edict_t ent, float dist) - { - edict_t goal = ent.goalentity; - - if (ent.groundentity == null && (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0) - return; - - // if the next step hits the enemy, return immediately - if (ent.enemy != null && SV.SV_CloseEnough(ent, ent.enemy, dist)) - return; - - // bump around... - if ((Lib.rand() & 3) == 1 || !SV.SV_StepDirection(ent, ent.ideal_yaw, dist)) - { - if (ent.inuse) - SV.SV_NewChaseDir(ent, goal, dist); - } - } - - /* - =============== - M_walkmove - =============== - */ - public static boolean M_walkmove(edict_t ent, float yaw, float dist) - { - float[] move = { 0, 0, 0 }; - - if ((ent.groundentity == null) && (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0) - return false; - - yaw = (float) (yaw * Math.PI * 2 / 360); - - move[0] = (float) Math.cos(yaw) * dist; - move[1] = (float) Math.sin(yaw) * dist; - move[2] = 0; - - return SV.SV_movestep(ent, move, true); - } - - public static void M_CatagorizePosition(edict_t ent) - { - float[] point = { 0, 0, 0 }; - int cont; - - // - // get waterlevel - // - point[0] = ent.s.origin[0]; - point[1] = ent.s.origin[1]; - point[2] = ent.s.origin[2] + ent.mins[2] + 1; - cont = Game.gi.pointcontents.pointcontents(point); - - if (0 == (cont & Defines.MASK_WATER)) - { - ent.waterlevel = 0; - ent.watertype = 0; - return; - } - - ent.watertype = cont; - ent.waterlevel = 1; - point[2] += 26; - cont = GameBase.gi.pointcontents.pointcontents(point); - if (0 == (cont & Defines.MASK_WATER)) - return; - - ent.waterlevel = 2; - point[2] += 22; - cont = GameBase.gi.pointcontents.pointcontents(point); - if (0 != (cont & Defines.MASK_WATER)) - ent.waterlevel = 3; - } - - public static void M_WorldEffects(edict_t ent) - { - int dmg; - - if (ent.health > 0) - { - if (0 == (ent.flags & Defines.FL_SWIM)) - { - if (ent.waterlevel < 3) - { - ent.air_finished = GameBase.level.time + 12; - } - else if (ent.air_finished < GameBase.level.time) - { - // drown! - if (ent.pain_debounce_time < GameBase.level.time) - { - dmg = (int) (2f + 2f * Math.floor(GameBase.level.time - ent.air_finished)); - if (dmg > 15) - dmg = 15; - GameUtil.T_Damage( - ent, - GameBase.g_edicts[0], - GameBase.g_edicts[0], - GameBase.vec3_origin, - ent.s.origin, - GameBase.vec3_origin, - dmg, - 0, - Defines.DAMAGE_NO_ARMOR, - Defines.MOD_WATER); - ent.pain_debounce_time = GameBase.level.time + 1; - } - } - } - else - { - if (ent.waterlevel > 0) - { - ent.air_finished = GameBase.level.time + 9; - } - else if (ent.air_finished < GameBase.level.time) - { - // suffocate! - if (ent.pain_debounce_time < GameBase.level.time) - { - dmg = (int) (2 + 2 * Math.floor(GameBase.level.time - ent.air_finished)); - if (dmg > 15) - dmg = 15; - GameUtil.T_Damage( - ent, - GameBase.g_edicts[0], - GameBase.g_edicts[0], - GameBase.vec3_origin, - ent.s.origin, - GameBase.vec3_origin, - dmg, - 0, - Defines.DAMAGE_NO_ARMOR, - Defines.MOD_WATER); - ent.pain_debounce_time = GameBase.level.time + 1; - } - } - } - } - - if (ent.waterlevel == 0) - { - if ((ent.flags & Defines.FL_INWATER) != 0) - { - GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/watr_out.wav"), 1, Defines.ATTN_NORM, 0); - ent.flags &= ~Defines.FL_INWATER; - } - return; - } - - if ((ent.watertype & Defines.CONTENTS_LAVA) != 0 && 0 == (ent.flags & Defines.FL_IMMUNE_LAVA)) - { - if (ent.damage_debounce_time < GameBase.level.time) - { - ent.damage_debounce_time = GameBase.level.time + 0.2f; - GameUtil.T_Damage( - ent, - GameBase.g_edicts[0], - GameBase.g_edicts[0], - GameBase.vec3_origin, - ent.s.origin, - GameBase.vec3_origin, - 10 * ent.waterlevel, - 0, - 0, - Defines.MOD_LAVA); - } - } - if ((ent.watertype & Defines.CONTENTS_SLIME) != 0 && 0 == (ent.flags & Defines.FL_IMMUNE_SLIME)) - { - if (ent.damage_debounce_time < GameBase.level.time) - { - ent.damage_debounce_time = GameBase.level.time + 1; - GameUtil.T_Damage( - ent, - GameBase.g_edicts[0], - GameBase.g_edicts[0], - GameBase.vec3_origin, - ent.s.origin, - GameBase.vec3_origin, - 4 * ent.waterlevel, - 0, - 0, - Defines.MOD_SLIME); - } - } - - if (0 == (ent.flags & Defines.FL_INWATER)) - { - if (0 == (ent.svflags & Defines.SVF_DEADMONSTER)) - { - if ((ent.watertype & Defines.CONTENTS_LAVA) != 0) - if (Globals.rnd.nextFloat() <= 0.5) - GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/lava1.wav"), 1, Defines.ATTN_NORM, 0); - else - GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/lava2.wav"), 1, Defines.ATTN_NORM, 0); - else if ((ent.watertype & Defines.CONTENTS_SLIME) != 0) - GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/watr_in.wav"), 1, Defines.ATTN_NORM, 0); - else if ((ent.watertype & Defines.CONTENTS_WATER) != 0) - GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/watr_in.wav"), 1, Defines.ATTN_NORM, 0); - } - - ent.flags |= Defines.FL_INWATER; - ent.damage_debounce_time = 0; - } - } - - public static EntThinkAdapter M_droptofloor = new EntThinkAdapter() - { - public boolean think(edict_t ent) - { - float[] end = { 0, 0, 0 }; - trace_t trace; - - ent.s.origin[2] += 1; - Math3D.VectorCopy(ent.s.origin, end); - end[2] -= 256; - - trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID); - - if (trace.fraction == 1 || trace.allsolid) - return true; - - Math3D.VectorCopy(trace.endpos, ent.s.origin); - - GameBase.gi.linkentity(ent); - M.M_CheckGround(ent); - M_CatagorizePosition(ent); - return true; - } - }; - - public static void M_SetEffects(edict_t ent) - { - ent.s.effects &= ~(Defines.EF_COLOR_SHELL | Defines.EF_POWERSCREEN); - ent.s.renderfx &= ~(Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE); - - if ((ent.monsterinfo.aiflags & Defines.AI_RESURRECTING) != 0) - { - ent.s.effects |= Defines.EF_COLOR_SHELL; - ent.s.renderfx |= Defines.RF_SHELL_RED; - } - - if (ent.health <= 0) - return; - - if (ent.powerarmor_time > GameBase.level.time) - { - if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SCREEN) - { - ent.s.effects |= Defines.EF_POWERSCREEN; - } - else if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SHIELD) - { - ent.s.effects |= Defines.EF_COLOR_SHELL; - ent.s.renderfx |= Defines.RF_SHELL_GREEN; - } - } - }; - - //ok - public static void M_MoveFrame(edict_t self) - { - mmove_t move; //ptr - int index; - - move = self.monsterinfo.currentmove; - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - - if ((self.monsterinfo.nextframe != 0) - && (self.monsterinfo.nextframe >= move.firstframe) - && (self.monsterinfo.nextframe <= move.lastframe)) - { - self.s.frame = self.monsterinfo.nextframe; - self.monsterinfo.nextframe = 0; - } - else - { - if (self.s.frame == move.lastframe) - { - if (move.endfunc != null) - { - move.endfunc.think(self); - - // regrab move, endfunc is very likely to change it - move = self.monsterinfo.currentmove; - - // check for death - if ((self.svflags & Defines.SVF_DEADMONSTER) != 0) - return; - } - } - - if (self.s.frame < move.firstframe || self.s.frame > move.lastframe) - { - self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; - self.s.frame = move.firstframe; - } - else - { - if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME)) - { - self.s.frame++; - if (self.s.frame > move.lastframe) - self.s.frame = move.firstframe; - } - } - } - - index = self.s.frame - move.firstframe; - if (move.frame[index].ai != null) - if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME)) - move.frame[index].ai.ai(self, move.frame[index].dist * self.monsterinfo.scale); - else - move.frame[index].ai.ai(self, 0); - - if (move.frame[index].think != null) - move.frame[index].think.think(self); - } - - public static void M_ReactToDamage(edict_t targ, edict_t attacker) - { - if ((null != attacker.client) && 0 != (attacker.svflags & Defines.SVF_MONSTER)) - return; - - if (attacker == targ || attacker == targ.enemy) - return; - - // if we are a good guy monster and our attacker is a player - // or another good guy, do not get mad at them - if (0 != (targ.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) - { - if (attacker.client != null || (attacker.monsterinfo.aiflags & Defines.AI_GOOD_GUY) != 0) - return; - } - - // we now know that we are not both good guys - - // if attacker is a client, get mad at them because he's good and we're not - if (attacker.client != null) - { - targ.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET; - - // this can only happen in coop (both new and old enemies are clients) - // only switch if can't see the current enemy - if (targ.enemy != null && targ.enemy.client != null) - { - if (GameUtil.visible(targ, targ.enemy)) - { - targ.oldenemy = attacker; - return; - } - targ.oldenemy = targ.enemy; - } - targ.enemy = attacker; - if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) - GameUtil.FoundTarget(targ); - return; - } - - // it's the same base (walk/swim/fly) type and a different classname and it's not a tank - // (they spray too much), get mad at them - if (((targ.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == (attacker.flags & (Defines.FL_FLY | Defines.FL_SWIM))) - && (Lib.strcmp(targ.classname, attacker.classname) != 0) - && (Lib.strcmp(attacker.classname, "monster_tank") != 0) - && (Lib.strcmp(attacker.classname, "monster_supertank") != 0) - && (Lib.strcmp(attacker.classname, "monster_makron") != 0) - && (Lib.strcmp(attacker.classname, "monster_jorg") != 0)) - { - if (targ.enemy != null && targ.enemy.client != null) - targ.oldenemy = targ.enemy; - targ.enemy = attacker; - if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) - GameUtil.FoundTarget(targ); - } - // if they *meant* to shoot us, then shoot back - else if (attacker.enemy == targ) - { - if (targ.enemy != null && targ.enemy.client != null) - targ.oldenemy = targ.enemy; - targ.enemy = attacker; - if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) - GameUtil.FoundTarget(targ); - } - // otherwise get mad at whoever they are mad at (help our buddy) unless it is us! - else if (attacker.enemy != null && attacker.enemy != targ) - { - if (targ.enemy != null && targ.enemy.client != null) - targ.oldenemy = targ.enemy; - targ.enemy = attacker.enemy; - if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) - GameUtil.FoundTarget(targ); - } - } - /** Stops the Flies. */ - public static EntThinkAdapter M_FliesOff = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - self.s.effects &= ~Defines.EF_FLIES; - self.s.sound = 0; - return true; - } - }; - /** Starts the Flies as setting the animation flag in the entity. */ - public static EntThinkAdapter M_FliesOn = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if (self.waterlevel != 0) - return true; - - self.s.effects |= Defines.EF_FLIES; - self.s.sound = GameBase.gi.soundindex("infantry/inflies1.wav"); - self.think = M_FliesOff; - self.nextthink = GameBase.level.time + 60; - return true; - } - }; - /** Adds some flies after a random time */ - public static EntThinkAdapter M_FlyCheck = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - - if (self.waterlevel != 0) - return true; - - if (Globals.rnd.nextFloat() > 0.5) - return true; - - self.think = M_FliesOn; - self.nextthink = GameBase.level.time + 5 + 10 * Globals.rnd.nextFloat(); - return true; - } - }; -} +public final class M { + + public static void M_CheckGround(edict_t ent) { + float[] point = { 0, 0, 0 }; + trace_t trace; + + if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0) + return; + + if (ent.velocity[2] > 100) { + ent.groundentity = null; + return; + } + + // if the hull point one-quarter unit down is solid the entity is on + // ground + point[0] = ent.s.origin[0]; + point[1] = ent.s.origin[1]; + point[2] = ent.s.origin[2] - 0.25f; + + trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, point, ent, + Defines.MASK_MONSTERSOLID); + + // check steepness + if (trace.plane.normal[2] < 0.7 && !trace.startsolid) { + ent.groundentity = null; + return; + } + + // ent.groundentity = trace.ent; + // ent.groundentity_linkcount = trace.ent.linkcount; + // if (!trace.startsolid && !trace.allsolid) + // VectorCopy (trace.endpos, ent.s.origin); + if (!trace.startsolid && !trace.allsolid) { + Math3D.VectorCopy(trace.endpos, ent.s.origin); + ent.groundentity = trace.ent; + ent.groundentity_linkcount = trace.ent.linkcount; + ent.velocity[2] = 0; + } + } + + public static boolean M_CheckBottom(edict_t ent) { + float[] mins = { 0, 0, 0 }; + float[] maxs = { 0, 0, 0 }; + float[] start = { 0, 0, 0 }; + float[] stop = { 0, 0, 0 }; + + trace_t trace; + int x, y; + float mid, bottom; + + Math3D.VectorAdd(ent.s.origin, ent.mins, mins); + Math3D.VectorAdd(ent.s.origin, ent.maxs, maxs); + + // if all of the points under the corners are solid world, don't bother + // with the tougher checks + // the corners must be within 16 of the midpoint + start[2] = mins[2] - 1; + for (x = 0; x <= 1; x++) + for (y = 0; y <= 1; y++) { + start[0] = x != 0 ? maxs[0] : mins[0]; + start[1] = y != 0 ? maxs[1] : mins[1]; + if (GameBase.gi.pointcontents.pointcontents(start) != Defines.CONTENTS_SOLID) { + GameBase.c_no++; + // + // check it for real... + // + start[2] = mins[2]; + + // the midpoint must be within 16 of the bottom + start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f; + start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f; + stop[2] = start[2] - 2 * GameBase.STEPSIZE; + trace = GameBase.gi.trace(start, Globals.vec3_origin, + Globals.vec3_origin, stop, ent, + Defines.MASK_MONSTERSOLID); + + if (trace.fraction == 1.0) + return false; + mid = bottom = trace.endpos[2]; + + // the corners must be within 16 of the midpoint + for (x = 0; x <= 1; x++) + for (y = 0; y <= 1; y++) { + start[0] = stop[0] = x != 0 ? maxs[0] : mins[0]; + start[1] = stop[1] = y != 0 ? maxs[1] : mins[1]; + + trace = GameBase.gi.trace(start, + Globals.vec3_origin, Globals.vec3_origin, + stop, ent, Defines.MASK_MONSTERSOLID); + + if (trace.fraction != 1.0 + && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == 1.0 + || mid - trace.endpos[2] > GameBase.STEPSIZE) + return false; + } + + GameBase.c_yes++; + return true; + } + } + + GameBase.c_yes++; + return true; // we got out easy + } + + /* + * =============== M_ChangeYaw + * + * =============== + *///ok + public static void M_ChangeYaw(edict_t ent) { + float ideal; + float current; + float move; + float speed; + + current = Math3D.anglemod(ent.s.angles[Defines.YAW]); + ideal = ent.ideal_yaw; + + if (current == ideal) + return; + + move = ideal - current; + speed = ent.yaw_speed; + if (ideal > current) { + if (move >= 180) + move = move - 360; + } else { + if (move <= -180) + move = move + 360; + } + if (move > 0) { + if (move > speed) + move = speed; + } else { + if (move < -speed) + move = -speed; + } + + ent.s.angles[Defines.YAW] = Math3D.anglemod(current + move); + } + + /* + * ====================== M_MoveToGoal ====================== + */// ok + public static void M_MoveToGoal(edict_t ent, float dist) { + edict_t goal = ent.goalentity; + + if (ent.groundentity == null + && (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0) + return; + + // if the next step hits the enemy, return immediately + if (ent.enemy != null && SV.SV_CloseEnough(ent, ent.enemy, dist)) + return; + + // bump around... + if ((Lib.rand() & 3) == 1 + || !SV.SV_StepDirection(ent, ent.ideal_yaw, dist)) { + if (ent.inuse) + SV.SV_NewChaseDir(ent, goal, dist); + } + } + + /* + * =============== M_walkmove =============== + */ + public static boolean M_walkmove(edict_t ent, float yaw, float dist) { + float[] move = { 0, 0, 0 }; + + if ((ent.groundentity == null) + && (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0) + return false; + + yaw = (float) (yaw * Math.PI * 2 / 360); + + move[0] = (float) Math.cos(yaw) * dist; + move[1] = (float) Math.sin(yaw) * dist; + move[2] = 0; + + return SV.SV_movestep(ent, move, true); + } + + public static void M_CatagorizePosition(edict_t ent) { + float[] point = { 0, 0, 0 }; + int cont; + + // + // get waterlevel + // + point[0] = ent.s.origin[0]; + point[1] = ent.s.origin[1]; + point[2] = ent.s.origin[2] + ent.mins[2] + 1; + cont = GameBase.gi.pointcontents.pointcontents(point); + + if (0 == (cont & Defines.MASK_WATER)) { + ent.waterlevel = 0; + ent.watertype = 0; + return; + } + + ent.watertype = cont; + ent.waterlevel = 1; + point[2] += 26; + cont = GameBase.gi.pointcontents.pointcontents(point); + if (0 == (cont & Defines.MASK_WATER)) + return; + + ent.waterlevel = 2; + point[2] += 22; + cont = GameBase.gi.pointcontents.pointcontents(point); + if (0 != (cont & Defines.MASK_WATER)) + ent.waterlevel = 3; + } + + public static void M_WorldEffects(edict_t ent) { + int dmg; + + if (ent.health > 0) { + if (0 == (ent.flags & Defines.FL_SWIM)) { + if (ent.waterlevel < 3) { + ent.air_finished = GameBase.level.time + 12; + } else if (ent.air_finished < GameBase.level.time) { + // drown! + if (ent.pain_debounce_time < GameBase.level.time) { + dmg = (int) (2f + 2f * Math.floor(GameBase.level.time + - ent.air_finished)); + if (dmg > 15) + dmg = 15; + GameUtil.T_Damage(ent, GameBase.g_edicts[0], + GameBase.g_edicts[0], Globals.vec3_origin, + ent.s.origin, Globals.vec3_origin, dmg, 0, + Defines.DAMAGE_NO_ARMOR, Defines.MOD_WATER); + ent.pain_debounce_time = GameBase.level.time + 1; + } + } + } else { + if (ent.waterlevel > 0) { + ent.air_finished = GameBase.level.time + 9; + } else if (ent.air_finished < GameBase.level.time) { + // suffocate! + if (ent.pain_debounce_time < GameBase.level.time) { + dmg = (int) (2 + 2 * Math.floor(GameBase.level.time + - ent.air_finished)); + if (dmg > 15) + dmg = 15; + GameUtil.T_Damage(ent, GameBase.g_edicts[0], + GameBase.g_edicts[0], Globals.vec3_origin, + ent.s.origin, Globals.vec3_origin, dmg, 0, + Defines.DAMAGE_NO_ARMOR, Defines.MOD_WATER); + ent.pain_debounce_time = GameBase.level.time + 1; + } + } + } + } + + if (ent.waterlevel == 0) { + if ((ent.flags & Defines.FL_INWATER) != 0) { + GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi + .soundindex("player/watr_out.wav"), 1, + Defines.ATTN_NORM, 0); + ent.flags &= ~Defines.FL_INWATER; + } + return; + } + + if ((ent.watertype & Defines.CONTENTS_LAVA) != 0 + && 0 == (ent.flags & Defines.FL_IMMUNE_LAVA)) { + if (ent.damage_debounce_time < GameBase.level.time) { + ent.damage_debounce_time = GameBase.level.time + 0.2f; + GameUtil.T_Damage(ent, GameBase.g_edicts[0], + GameBase.g_edicts[0], Globals.vec3_origin, + ent.s.origin, Globals.vec3_origin, 10 * ent.waterlevel, + 0, 0, Defines.MOD_LAVA); + } + } + if ((ent.watertype & Defines.CONTENTS_SLIME) != 0 + && 0 == (ent.flags & Defines.FL_IMMUNE_SLIME)) { + if (ent.damage_debounce_time < GameBase.level.time) { + ent.damage_debounce_time = GameBase.level.time + 1; + GameUtil.T_Damage(ent, GameBase.g_edicts[0], + GameBase.g_edicts[0], Globals.vec3_origin, + ent.s.origin, Globals.vec3_origin, 4 * ent.waterlevel, + 0, 0, Defines.MOD_SLIME); + } + } + + if (0 == (ent.flags & Defines.FL_INWATER)) { + if (0 == (ent.svflags & Defines.SVF_DEADMONSTER)) { + if ((ent.watertype & Defines.CONTENTS_LAVA) != 0) + if (Globals.rnd.nextFloat() <= 0.5) + GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi + .soundindex("player/lava1.wav"), 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi + .soundindex("player/lava2.wav"), 1, + Defines.ATTN_NORM, 0); + else if ((ent.watertype & Defines.CONTENTS_SLIME) != 0) + GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi + .soundindex("player/watr_in.wav"), 1, + Defines.ATTN_NORM, 0); + else if ((ent.watertype & Defines.CONTENTS_WATER) != 0) + GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi + .soundindex("player/watr_in.wav"), 1, + Defines.ATTN_NORM, 0); + } + + ent.flags |= Defines.FL_INWATER; + ent.damage_debounce_time = 0; + } + } + + public static EntThinkAdapter M_droptofloor = new EntThinkAdapter() { + public boolean think(edict_t ent) { + float[] end = { 0, 0, 0 }; + trace_t trace; + + ent.s.origin[2] += 1; + Math3D.VectorCopy(ent.s.origin, end); + end[2] -= 256; + + trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end, + ent, Defines.MASK_MONSTERSOLID); + + if (trace.fraction == 1 || trace.allsolid) + return true; + + Math3D.VectorCopy(trace.endpos, ent.s.origin); + + GameBase.gi.linkentity(ent); + M.M_CheckGround(ent); + M_CatagorizePosition(ent); + return true; + } + }; + + public static void M_SetEffects(edict_t ent) { + ent.s.effects &= ~(Defines.EF_COLOR_SHELL | Defines.EF_POWERSCREEN); + ent.s.renderfx &= ~(Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE); + + if ((ent.monsterinfo.aiflags & Defines.AI_RESURRECTING) != 0) { + ent.s.effects |= Defines.EF_COLOR_SHELL; + ent.s.renderfx |= Defines.RF_SHELL_RED; + } + + if (ent.health <= 0) + return; + + if (ent.powerarmor_time > GameBase.level.time) { + if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SCREEN) { + ent.s.effects |= Defines.EF_POWERSCREEN; + } else if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SHIELD) { + ent.s.effects |= Defines.EF_COLOR_SHELL; + ent.s.renderfx |= Defines.RF_SHELL_GREEN; + } + } + }; + + //ok + public static void M_MoveFrame(edict_t self) { + mmove_t move; //ptr + int index; + + move = self.monsterinfo.currentmove; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + + if ((self.monsterinfo.nextframe != 0) + && (self.monsterinfo.nextframe >= move.firstframe) + && (self.monsterinfo.nextframe <= move.lastframe)) { + self.s.frame = self.monsterinfo.nextframe; + self.monsterinfo.nextframe = 0; + } else { + if (self.s.frame == move.lastframe) { + if (move.endfunc != null) { + move.endfunc.think(self); + + // regrab move, endfunc is very likely to change it + move = self.monsterinfo.currentmove; + + // check for death + if ((self.svflags & Defines.SVF_DEADMONSTER) != 0) + return; + } + } + + if (self.s.frame < move.firstframe || self.s.frame > move.lastframe) { + self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; + self.s.frame = move.firstframe; + } else { + if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME)) { + self.s.frame++; + if (self.s.frame > move.lastframe) + self.s.frame = move.firstframe; + } + } + } + + index = self.s.frame - move.firstframe; + if (move.frame[index].ai != null) + if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME)) + move.frame[index].ai.ai(self, move.frame[index].dist + * self.monsterinfo.scale); + else + move.frame[index].ai.ai(self, 0); + + if (move.frame[index].think != null) + move.frame[index].think.think(self); + } + + public static void M_ReactToDamage(edict_t targ, edict_t attacker) { + if ((null != attacker.client) + && 0 != (attacker.svflags & Defines.SVF_MONSTER)) + return; + + if (attacker == targ || attacker == targ.enemy) + return; + + // if we are a good guy monster and our attacker is a player + // or another good guy, do not get mad at them + if (0 != (targ.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) { + if (attacker.client != null + || (attacker.monsterinfo.aiflags & Defines.AI_GOOD_GUY) != 0) + return; + } + + // we now know that we are not both good guys + + // if attacker is a client, get mad at them because he's good and we're + // not + if (attacker.client != null) { + targ.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET; + + // this can only happen in coop (both new and old enemies are + // clients) + // only switch if can't see the current enemy + if (targ.enemy != null && targ.enemy.client != null) { + if (GameUtil.visible(targ, targ.enemy)) { + targ.oldenemy = attacker; + return; + } + targ.oldenemy = targ.enemy; + } + targ.enemy = attacker; + if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) + GameUtil.FoundTarget(targ); + return; + } + + // it's the same base (walk/swim/fly) type and a different classname and + // it's not a tank + // (they spray too much), get mad at them + if (((targ.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == (attacker.flags & (Defines.FL_FLY | Defines.FL_SWIM))) + && (Lib.strcmp(targ.classname, attacker.classname) != 0) + && (Lib.strcmp(attacker.classname, "monster_tank") != 0) + && (Lib.strcmp(attacker.classname, "monster_supertank") != 0) + && (Lib.strcmp(attacker.classname, "monster_makron") != 0) + && (Lib.strcmp(attacker.classname, "monster_jorg") != 0)) { + if (targ.enemy != null && targ.enemy.client != null) + targ.oldenemy = targ.enemy; + targ.enemy = attacker; + if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) + GameUtil.FoundTarget(targ); + } + // if they *meant* to shoot us, then shoot back + else if (attacker.enemy == targ) { + if (targ.enemy != null && targ.enemy.client != null) + targ.oldenemy = targ.enemy; + targ.enemy = attacker; + if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) + GameUtil.FoundTarget(targ); + } + // otherwise get mad at whoever they are mad at (help our buddy) unless + // it is us! + else if (attacker.enemy != null && attacker.enemy != targ) { + if (targ.enemy != null && targ.enemy.client != null) + targ.oldenemy = targ.enemy; + targ.enemy = attacker.enemy; + if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED)) + GameUtil.FoundTarget(targ); + } + } + + /** Stops the Flies. */ + public static EntThinkAdapter M_FliesOff = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.s.effects &= ~Defines.EF_FLIES; + self.s.sound = 0; + return true; + } + }; + + /** Starts the Flies as setting the animation flag in the entity. */ + public static EntThinkAdapter M_FliesOn = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (self.waterlevel != 0) + return true; + + self.s.effects |= Defines.EF_FLIES; + self.s.sound = GameBase.gi.soundindex("infantry/inflies1.wav"); + self.think = M_FliesOff; + self.nextthink = GameBase.level.time + 60; + return true; + } + }; + + /** Adds some flies after a random time */ + public static EntThinkAdapter M_FlyCheck = new EntThinkAdapter() { + public boolean think(edict_t self) { + + if (self.waterlevel != 0) + return true; + + if (Globals.rnd.nextFloat() > 0.5) + return true; + + self.think = M_FliesOn; + self.nextthink = GameBase.level.time + 5 + 10 + * Globals.rnd.nextFloat(); + return true; + } + }; +} \ No newline at end of file diff --git a/src/jake2/client/Menu.java b/src/jake2/client/Menu.java index b718b19..50797f5 100644 --- a/src/jake2/client/Menu.java +++ b/src/jake2/client/Menu.java @@ -2,27 +2,27 @@ * Menu.java * Copyright (C) 2004 * - * $Id: Menu.java,v 1.8 2004-09-12 19:52:58 hzi Exp $ + * $Id: Menu.java,v 1.9 2004-09-22 19:22:07 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; import jake2.Globals; @@ -42,4968 +42,4882 @@ import java.util.Comparator; /** * Menu * - * + * */ abstract class keyfunc_t { - abstract String execute(int key); + abstract String execute(int key); } public final class Menu extends Key { - static int m_main_cursor; - static final int NUM_CURSOR_FRAMES= 15; + static int m_main_cursor; - static final String menu_in_sound= "misc/menu1.wav"; - static final String menu_move_sound= "misc/menu2.wav"; - static final String menu_out_sound= "misc/menu3.wav"; + static final int NUM_CURSOR_FRAMES = 15; - static boolean m_entersound; // play after drawing a frame, so caching - // won't disrupt the sound + static final String menu_in_sound = "misc/menu1.wav"; - static xcommand_t m_drawfunc; + static final String menu_move_sound = "misc/menu2.wav"; - static keyfunc_t m_keyfunc; + static final String menu_out_sound = "misc/menu3.wav"; - // ============================================================================= - /* Support Routines */ + static boolean m_entersound; // play after drawing a frame, so caching - public final static int MAX_MENU_DEPTH= 8; + // won't disrupt the sound - public static class menulayer_t { - xcommand_t draw; - keyfunc_t key; - } + static xcommand_t m_drawfunc; - static class menuframework_s { - int x, y; - int cursor; + static keyfunc_t m_keyfunc; - int nitems; - int nslots; - menucommon_s items[]= new menucommon_s[64]; + // ============================================================================= + /* Support Routines */ - String statusbar; + public final static int MAX_MENU_DEPTH = 8; - //void (*cursordraw)( struct _tag_menuframework *m ); - mcallback cursordraw; + public static class menulayer_t { + xcommand_t draw; - } + keyfunc_t key; + } - abstract static class mcallback { - abstract public void execute(Object self); - } + static class menuframework_s { + int x, y; - static class menucommon_s { - int type; - String name= ""; - int x, y; - menuframework_s parent; - int cursor_offset; - int localdata[]= { 0, 0, 0, 0 }; - int flags; - int n= -1; //position in an array. + int cursor; - String statusbar; + int nitems; - mcallback callback; - mcallback statusbarfunc; - mcallback ownerdraw; - mcallback cursordraw; - } + int nslots; - static class menufield_s extends menucommon_s { - //char buffer[80]; - StringBuffer buffer; //allow deletion. + menucommon_s items[] = new menucommon_s[64]; - int cursor; - int length; - int visible_length; - int visible_offset; - } + String statusbar; - static class menuslider_s extends menucommon_s { + //void (*cursordraw)( struct _tag_menuframework *m ); + mcallback cursordraw; - float minvalue; - float maxvalue; - float curvalue; + } - float range; - } + abstract static class mcallback { + abstract public void execute(Object self); + } - static class menulist_s extends menucommon_s { - int curvalue; - String itemnames[]; - } - - static class menuaction_s extends menucommon_s { - - } - - static class menuseparator_s extends menucommon_s { - - } - - public static menulayer_t m_layers[]= new menulayer_t[MAX_MENU_DEPTH]; - public static int m_menudepth; - - static void Banner(String name) { - Dimension dim= new Dimension(); - Globals.re.DrawGetPicSize(dim, name); - - Globals.re.DrawPic(viddef.width / 2 - dim.width / 2, viddef.height / 2 - 110, name); - } - - static void PushMenu(xcommand_t draw, keyfunc_t key) { //, String(*key) (int k) ) { - int i; - - if (Cvar.VariableValue("maxclients") == 1 && Globals.server_state != 0) - Cvar.Set("paused", "1"); - - // if this menu is already present, drop back to that level - // to avoid stacking menus by hotkeys - for (i= 0; i < m_menudepth; i++) - if (m_layers[i].draw == draw && m_layers[i].key == key) { - m_menudepth= i; - } - - if (i == m_menudepth) { - if (m_menudepth >= MAX_MENU_DEPTH) - Com.Error(ERR_FATAL, "PushMenu: MAX_MENU_DEPTH"); - - m_layers[m_menudepth].draw= m_drawfunc; - m_layers[m_menudepth].key= m_keyfunc; - m_menudepth++; - } - - m_drawfunc= draw; - m_keyfunc= key; - - m_entersound= true; - - cls.key_dest= key_menu; - } - - static void ForceMenuOff() { - m_drawfunc= null; - m_keyfunc= null; - cls.key_dest= key_game; - m_menudepth= 0; - Key.ClearStates(); - Cvar.Set("paused", "0"); - } - - static void PopMenu() { - S.StartLocalSound(menu_out_sound); - if (m_menudepth < 1) - Com.Error(ERR_FATAL, "PopMenu: depth < 1"); - m_menudepth--; - - m_drawfunc= m_layers[m_menudepth].draw; - m_keyfunc= m_layers[m_menudepth].key; - - if (0 == m_menudepth) - ForceMenuOff(); - } - - static String Default_MenuKey(menuframework_s m, int key) { - String sound= null; - menucommon_s item; - - if (m != null) { - if ((item= ((menucommon_s) Menu_ItemAtCursor(m))) != null) { - if (item.type == MTYPE_FIELD) { - if (Field_Key((menufield_s) item, key)) - return null; - } - } - } - - switch (key) { - case K_ESCAPE : - PopMenu(); - return menu_out_sound; - case K_KP_UPARROW : - case K_UPARROW : - if (m != null) { - m.cursor--; - Menu_AdjustCursor(m, -1); - sound= menu_move_sound; - } - break; - case K_TAB : - if (m != null) { - m.cursor++; - Menu_AdjustCursor(m, 1); - sound= menu_move_sound; - } - break; - case K_KP_DOWNARROW : - case K_DOWNARROW : - if (m != null) { - m.cursor++; - Menu_AdjustCursor(m, 1); - sound= menu_move_sound; - } - break; - case K_KP_LEFTARROW : - case K_LEFTARROW : - if (m != null) { - Menu_SlideItem(m, -1); - sound= menu_move_sound; - } - break; - case K_KP_RIGHTARROW : - case K_RIGHTARROW : - if (m != null) { - Menu_SlideItem(m, 1); - sound= menu_move_sound; - } - break; - - case K_MOUSE1 : - case K_MOUSE2 : - case K_MOUSE3 : - case K_JOY1 : - case K_JOY2 : - case K_JOY3 : - case K_JOY4 : - /* - case K_AUX1 : - case K_AUX2 : - case K_AUX3 : - case K_AUX4 : - case K_AUX5 : - case K_AUX6 : - case K_AUX7 : - case K_AUX8 : - case K_AUX9 : - case K_AUX10 : - case K_AUX11 : - case K_AUX12 : - case K_AUX13 : - case K_AUX14 : - case K_AUX15 : - case K_AUX16 : - case K_AUX17 : - case K_AUX18 : - case K_AUX19 : - case K_AUX20 : - case K_AUX21 : - case K_AUX22 : - case K_AUX23 : - case K_AUX24 : - case K_AUX25 : - case K_AUX26 : - case K_AUX27 : - case K_AUX28 : - case K_AUX29 : - case K_AUX30 : - case K_AUX31 : - case K_AUX32 : - */ - case K_KP_ENTER : - case K_ENTER : - if (m != null) - Menu_SelectItem(m); - sound= menu_move_sound; - break; - } - - return sound; - } - - /* - ================ - DrawCharacter - - Draws one solid graphics character - cx and cy are in 320*240 coordinates, and will be centered on - higher res screens. - ================ - */ - public static void DrawCharacter(int cx, int cy, int num) { - re.DrawChar(cx + ((viddef.width - 320) >> 1), cy + ((viddef.height - 240) >> 1), num); - } - - public static void Print(int cx, int cy, String str) { - //while (*str) - for (int n= 0; n < str.length(); n++) { - DrawCharacter(cx, cy, str.charAt(n) + 128); - //str++; - cx += 8; - } - } - - public static void PrintWhite(int cx, int cy, String str) { - for (int n= 0; n < str.length(); n++) { - DrawCharacter(cx, cy, str.charAt(n)); - //str++; - cx += 8; - } - } - - public static void DrawPic(int x, int y, String pic) { - re.DrawPic(x + ((viddef.width - 320) >> 1), y + ((viddef.height - 240) >> 1), pic); - } - - /* - ============= - DrawCursor - - Draws an animating cursor with the point at - x,y. The pic will extend to the left of x, - and both above and below y. - ============= - */ - static boolean cached; - static void DrawCursor(int x, int y, int f) { - //char cursorname[80]; - String cursorname; - - assert(f >= 0) : "negative time and cursor bug"; - - f= Math.abs(f); - - if (!cached) { - int i; - - for (i= 0; i < NUM_CURSOR_FRAMES; i++) { - cursorname= "m_cursor" + i; - - re.RegisterPic(cursorname); - } - cached= true; - } - - cursorname= "m_cursor" + f; - re.DrawPic(x, y, cursorname); - } - - public static void DrawTextBox(int x, int y, int width, int lines) { - int cx, cy; - int n; - - // draw left side - cx= x; - cy= y; - DrawCharacter(cx, cy, 1); - - for (n= 0; n < lines; n++) { - cy += 8; - DrawCharacter(cx, cy, 4); - } - DrawCharacter(cx, cy + 8, 7); - - // draw middle - cx += 8; - while (width > 0) { - cy= y; - DrawCharacter(cx, cy, 2); - - for (n= 0; n < lines; n++) { - cy += 8; - DrawCharacter(cx, cy, 5); - } - DrawCharacter(cx, cy + 8, 8); - - width -= 1; - cx += 8; - } - - // draw right side - cy= y; - DrawCharacter(cx, cy, 3); - for (n= 0; n < lines; n++) { - cy += 8; - DrawCharacter(cx, cy, 6); - - } - DrawCharacter(cx, cy + 8, 9); - - } - - /* - ======================================================================= - - MAIN MENU - - ======================================================================= - */ - static final int MAIN_ITEMS= 5; - - static xcommand_t Main_Draw= new xcommand_t() { - public void execute() { - Main_Draw(); - } - }; - static void Main_Draw() { - int i; - int w, h; - int ystart; - int xoffset; - int widest= -1; - int totalheight= 0; - String litname; - String[] names= { "m_main_game", "m_main_multiplayer", "m_main_options", "m_main_video", "m_main_quit" }; - Dimension dim= new Dimension(); - - for (i= 0; i < names.length; i++) { - Globals.re.DrawGetPicSize(dim, names[i]); - w= dim.width; - h= dim.height; - - if (w > widest) - widest= w; - totalheight += (h + 12); - } - - ystart= (Globals.viddef.height / 2 - 110); - xoffset= (Globals.viddef.width - widest + 70) / 2; - - for (i= 0; i < names.length; i++) { - if (i != m_main_cursor) - Globals.re.DrawPic(xoffset, ystart + i * 40 + 13, names[i]); - } - - //strcat(litname, "_sel"); - litname= names[m_main_cursor] + "_sel"; - Globals.re.DrawPic(xoffset, ystart + m_main_cursor * 40 + 13, litname); - - DrawCursor(xoffset - 25, ystart + m_main_cursor * 40 + 11, (int) ((Globals.cls.realtime / 100)) % NUM_CURSOR_FRAMES); - - Globals.re.DrawGetPicSize(dim, "m_main_plaque"); - w= dim.width; - h= dim.height; - Globals.re.DrawPic(xoffset - 30 - w, ystart, "m_main_plaque"); - - Globals.re.DrawPic(xoffset - 30 - w, ystart + h + 5, "m_main_logo"); - } - - static keyfunc_t Main_Key= new keyfunc_t() { - public String execute(int key) { - return Main_Key(key); - } - }; - - static String Main_Key(int key) { - String sound= menu_move_sound; - - switch (key) { - case Key.K_ESCAPE : - PopMenu(); - break; - - case Key.K_KP_DOWNARROW : - case Key.K_DOWNARROW : - if (++m_main_cursor >= MAIN_ITEMS) - m_main_cursor= 0; - return sound; - - case Key.K_KP_UPARROW : - case Key.K_UPARROW : - if (--m_main_cursor < 0) - m_main_cursor= MAIN_ITEMS - 1; - return sound; - - case Key.K_KP_ENTER : - case Key.K_ENTER : - m_entersound= true; - - switch (m_main_cursor) { - case 0 : - Menu_Game_f(); - break; - - case 1 : - Menu_Multiplayer_f(); - break; - - case 2 : - Menu_Options_f(); - break; - - case 3 : - Menu_Video_f(); - break; - - case 4 : - Menu_Quit_f(); - break; - } - } - - return null; - } - - static xcommand_t Menu_Main= new xcommand_t() { - public void execute() { - Menu_Main_f(); - } - }; - - static void Menu_Main_f() { - PushMenu(new xcommand_t() { - public void execute() { - Main_Draw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return Main_Key(key); - } - }); - } - - /* - ======================================================================= - - MULTIPLAYER MENU - - ======================================================================= - */ - static menuframework_s s_multiplayer_menu= new menuframework_s(); - static menuaction_s s_join_network_server_action= new menuaction_s(); - static menuaction_s s_start_network_server_action= new menuaction_s(); - static menuaction_s s_player_setup_action= new menuaction_s(); - - static void Multiplayer_MenuDraw() { - Banner("m_banner_multiplayer"); - - Menu_AdjustCursor(s_multiplayer_menu, 1); - Menu_Draw(s_multiplayer_menu); - } - - static void PlayerSetupFunc(Object unused) { - Menu_PlayerConfig_f(); - } - - static void JoinNetworkServerFunc(Object unused) { - Menu_JoinServer_f(); - } - - static void StartNetworkServerFunc(Object unused) { - Menu_StartServer_f(); - } - - static void Multiplayer_MenuInit() { - s_multiplayer_menu.x= (int) (viddef.width * 0.50f - 64); - s_multiplayer_menu.nitems= 0; - - s_join_network_server_action.type= MTYPE_ACTION; - s_join_network_server_action.flags= QMF_LEFT_JUSTIFY; - s_join_network_server_action.x= 0; - s_join_network_server_action.y= 0; - s_join_network_server_action.name= " join network server"; - s_join_network_server_action.callback= new mcallback() { - public void execute(Object o) { - JoinNetworkServerFunc(o); - }; - }; - - s_start_network_server_action.type= MTYPE_ACTION; - s_start_network_server_action.flags= QMF_LEFT_JUSTIFY; - s_start_network_server_action.x= 0; - s_start_network_server_action.y= 10; - s_start_network_server_action.name= " start network server"; - s_start_network_server_action.callback= new mcallback() { - public void execute(Object o) { - StartNetworkServerFunc(o); - } - }; - - s_player_setup_action.type= MTYPE_ACTION; - s_player_setup_action.flags= QMF_LEFT_JUSTIFY; - s_player_setup_action.x= 0; - s_player_setup_action.y= 20; - s_player_setup_action.name= " player setup"; - s_player_setup_action.callback= new mcallback() { - public void execute(Object o) { - PlayerSetupFunc(o); - } - }; - - Menu_AddItem(s_multiplayer_menu, s_join_network_server_action); - Menu_AddItem(s_multiplayer_menu, s_start_network_server_action); - Menu_AddItem(s_multiplayer_menu, s_player_setup_action); - - Menu_SetStatusBar(s_multiplayer_menu, null); - - Menu_Center(s_multiplayer_menu); - } - - static String Multiplayer_MenuKey(int key) { - return Default_MenuKey(s_multiplayer_menu, key); - } - - static xcommand_t Menu_Multiplayer= new xcommand_t() { - public void execute() { - Menu_Multiplayer_f(); - } - }; - - static void Menu_Multiplayer_f() { - Multiplayer_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - Multiplayer_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return Multiplayer_MenuKey(key); - } - }); - } - - /* - ======================================================================= - - KEYS MENU - - ======================================================================= - */ - static String bindnames[][]= { { "+attack", "attack" }, { - "weapnext", "next weapon" }, { - "+forward", "walk forward" }, { - "+back", "backpedal" }, { - "+left", "turn left" }, { - "+right", "turn right" }, { - "+speed", "run" }, { - "+moveleft", "step left" }, { - "+moveright", "step right" }, { - "+strafe", "sidestep" }, { - "+lookup", "look up" }, { - "+lookdown", "look down" }, { - "centerview", "center view" }, { - "+mlook", "mouse look" }, { - "+klook", "keyboard look" }, { - "+moveup", "up / jump" }, { - "+movedown", "down / crouch" }, { - - "inven", "inventory" }, { - "invuse", "use item" }, { - "invdrop", "drop item" }, { - "invprev", "prev item" }, { - "invnext", "next item" }, { - - "cmd help", "help computer" }, { - null, null } - }; - - int keys_cursor; - static boolean bind_grab; - - static menuframework_s s_keys_menu= new menuframework_s(); - static menuaction_s s_keys_attack_action= new menuaction_s(); - static menuaction_s s_keys_change_weapon_action= new menuaction_s(); - static menuaction_s s_keys_walk_forward_action= new menuaction_s(); - static menuaction_s s_keys_backpedal_action= new menuaction_s(); - static menuaction_s s_keys_turn_left_action= new menuaction_s(); - static menuaction_s s_keys_turn_right_action= new menuaction_s(); - static menuaction_s s_keys_run_action= new menuaction_s(); - static menuaction_s s_keys_step_left_action= new menuaction_s(); - static menuaction_s s_keys_step_right_action= new menuaction_s(); - static menuaction_s s_keys_sidestep_action= new menuaction_s(); - static menuaction_s s_keys_look_up_action= new menuaction_s(); - static menuaction_s s_keys_look_down_action= new menuaction_s(); - static menuaction_s s_keys_center_view_action= new menuaction_s(); - static menuaction_s s_keys_mouse_look_action= new menuaction_s(); - static menuaction_s s_keys_keyboard_look_action= new menuaction_s(); - static menuaction_s s_keys_move_up_action= new menuaction_s(); - static menuaction_s s_keys_move_down_action= new menuaction_s(); - static menuaction_s s_keys_inventory_action= new menuaction_s(); - static menuaction_s s_keys_inv_use_action= new menuaction_s(); - static menuaction_s s_keys_inv_drop_action= new menuaction_s(); - static menuaction_s s_keys_inv_prev_action= new menuaction_s(); - static menuaction_s s_keys_inv_next_action= new menuaction_s(); - - static menuaction_s s_keys_help_computer_action= new menuaction_s(); - - static void UnbindCommand(String command) { - int j; - String b; - - for (j= 0; j < 256; j++) { - b= keybindings[j]; - if (b == null) - continue; - if (b.equals(command)) - Key.SetBinding(j, ""); - } - } - - static void FindKeysForCommand(String command, int twokeys[]) { - int count; - int j; - String b; - - twokeys[0]= twokeys[1]= -1; - count= 0; - - for (j= 0; j < 256; j++) { - b= keybindings[j]; - if (b == null) - continue; - - if (b.equals(command)) { - twokeys[count]= j; - count++; - if (count == 2) - break; - } - } - } - - static void KeyCursorDrawFunc(menuframework_s menu) { - if (bind_grab) - re.DrawChar(menu.x, menu.y + menu.cursor * 9, '='); - else - re.DrawChar(menu.x, menu.y + menu.cursor * 9, 12 + ((int) (Sys.Milliseconds() / 250) & 1)); - } - - static void DrawKeyBindingFunc(Object self) { - int keys[]= { 0, 0 }; - menuaction_s a= (menuaction_s) self; - - FindKeysForCommand(bindnames[a.localdata[0]][0], keys); - - if (keys[0] == -1) { - Menu_DrawString(a.x + a.parent.x + 16, a.y + a.parent.y, "???"); - } - else { - int x; - String name; - - name= Key.KeynumToString(keys[0]); - - Menu_DrawString(a.x + a.parent.x + 16, a.y + a.parent.y, name); - - x= name.length() * 8; - - if (keys[1] != -1) { - Menu_DrawString(a.x + a.parent.x + 24 + x, a.y + a.parent.y, "or"); - Menu_DrawString(a.x + a.parent.x + 48 + x, a.y + a.parent.y, Key.KeynumToString(keys[1])); - } - } - } - - static void KeyBindingFunc(Object self) { - menuaction_s a= (menuaction_s) self; - int keys[]= { 0, 0 }; - - FindKeysForCommand(bindnames[a.localdata[0]][0], keys); - - if (keys[1] != -1) - UnbindCommand(bindnames[a.localdata[0]][0]); - - bind_grab= true; - - Menu_SetStatusBar(s_keys_menu, "press a key or button for this action"); - } - - static void Keys_MenuInit() { - int y= 0; - int i= 0; - - s_keys_menu.x= (int) (viddef.width * 0.50); - s_keys_menu.nitems= 0; - s_keys_menu.cursordraw= new mcallback() { - public void execute(Object o) { - KeyCursorDrawFunc((menuframework_s) o); - } - }; - - s_keys_attack_action.type= MTYPE_ACTION; - s_keys_attack_action.flags= QMF_GRAYED; - s_keys_attack_action.x= 0; - s_keys_attack_action.y= y; - s_keys_attack_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - s_keys_attack_action.localdata[0]= i; - s_keys_attack_action.name= bindnames[s_keys_attack_action.localdata[0]][1]; - - s_keys_change_weapon_action.type= MTYPE_ACTION; - s_keys_change_weapon_action.flags= QMF_GRAYED; - s_keys_change_weapon_action.x= 0; - s_keys_change_weapon_action.y= y += 9; - s_keys_change_weapon_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_change_weapon_action.localdata[0]= ++i; - s_keys_change_weapon_action.name= bindnames[s_keys_change_weapon_action.localdata[0]][1]; - - s_keys_walk_forward_action.type= MTYPE_ACTION; - s_keys_walk_forward_action.flags= QMF_GRAYED; - s_keys_walk_forward_action.x= 0; - s_keys_walk_forward_action.y= y += 9; - s_keys_walk_forward_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - s_keys_walk_forward_action.localdata[0]= ++i; - s_keys_walk_forward_action.name= bindnames[s_keys_walk_forward_action.localdata[0]][1]; - - s_keys_backpedal_action.type= MTYPE_ACTION; - s_keys_backpedal_action.flags= QMF_GRAYED; - s_keys_backpedal_action.x= 0; - s_keys_backpedal_action.y= y += 9; - s_keys_backpedal_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - s_keys_backpedal_action.localdata[0]= ++i; - s_keys_backpedal_action.name= bindnames[s_keys_backpedal_action.localdata[0]][1]; - - s_keys_turn_left_action.type= MTYPE_ACTION; - s_keys_turn_left_action.flags= QMF_GRAYED; - s_keys_turn_left_action.x= 0; - s_keys_turn_left_action.y= y += 9; - s_keys_turn_left_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - s_keys_turn_left_action.localdata[0]= ++i; - s_keys_turn_left_action.name= bindnames[s_keys_turn_left_action.localdata[0]][1]; - - s_keys_turn_right_action.type= MTYPE_ACTION; - s_keys_turn_right_action.flags= QMF_GRAYED; - s_keys_turn_right_action.x= 0; - s_keys_turn_right_action.y= y += 9; - s_keys_turn_right_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - s_keys_turn_right_action.localdata[0]= ++i; - s_keys_turn_right_action.name= bindnames[s_keys_turn_right_action.localdata[0]][1]; - - s_keys_run_action.type= MTYPE_ACTION; - s_keys_run_action.flags= QMF_GRAYED; - s_keys_run_action.x= 0; - s_keys_run_action.y= y += 9; - s_keys_run_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - s_keys_run_action.localdata[0]= ++i; - s_keys_run_action.name= bindnames[s_keys_run_action.localdata[0]][1]; - - s_keys_step_left_action.type= MTYPE_ACTION; - s_keys_step_left_action.flags= QMF_GRAYED; - s_keys_step_left_action.x= 0; - s_keys_step_left_action.y= y += 9; - s_keys_step_left_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - s_keys_step_left_action.localdata[0]= ++i; - s_keys_step_left_action.name= bindnames[s_keys_step_left_action.localdata[0]][1]; - - s_keys_step_right_action.type= MTYPE_ACTION; - s_keys_step_right_action.flags= QMF_GRAYED; - s_keys_step_right_action.x= 0; - s_keys_step_right_action.y= y += 9; - s_keys_step_right_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_step_right_action.localdata[0]= ++i; - s_keys_step_right_action.name= bindnames[s_keys_step_right_action.localdata[0]][1]; - - s_keys_sidestep_action.type= MTYPE_ACTION; - s_keys_sidestep_action.flags= QMF_GRAYED; - s_keys_sidestep_action.x= 0; - s_keys_sidestep_action.y= y += 9; - s_keys_sidestep_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_sidestep_action.localdata[0]= ++i; - s_keys_sidestep_action.name= bindnames[s_keys_sidestep_action.localdata[0]][1]; - - s_keys_look_up_action.type= MTYPE_ACTION; - s_keys_look_up_action.flags= QMF_GRAYED; - s_keys_look_up_action.x= 0; - s_keys_look_up_action.y= y += 9; - s_keys_look_up_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_look_up_action.localdata[0]= ++i; - s_keys_look_up_action.name= bindnames[s_keys_look_up_action.localdata[0]][1]; - - s_keys_look_down_action.type= MTYPE_ACTION; - s_keys_look_down_action.flags= QMF_GRAYED; - s_keys_look_down_action.x= 0; - s_keys_look_down_action.y= y += 9; - s_keys_look_down_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_look_down_action.localdata[0]= ++i; - s_keys_look_down_action.name= bindnames[s_keys_look_down_action.localdata[0]][1]; - - s_keys_center_view_action.type= MTYPE_ACTION; - s_keys_center_view_action.flags= QMF_GRAYED; - s_keys_center_view_action.x= 0; - s_keys_center_view_action.y= y += 9; - s_keys_center_view_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_center_view_action.localdata[0]= ++i; - s_keys_center_view_action.name= bindnames[s_keys_center_view_action.localdata[0]][1]; - - s_keys_mouse_look_action.type= MTYPE_ACTION; - s_keys_mouse_look_action.flags= QMF_GRAYED; - s_keys_mouse_look_action.x= 0; - s_keys_mouse_look_action.y= y += 9; - s_keys_mouse_look_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_mouse_look_action.localdata[0]= ++i; - s_keys_mouse_look_action.name= bindnames[s_keys_mouse_look_action.localdata[0]][1]; - - s_keys_keyboard_look_action.type= MTYPE_ACTION; - s_keys_keyboard_look_action.flags= QMF_GRAYED; - s_keys_keyboard_look_action.x= 0; - s_keys_keyboard_look_action.y= y += 9; - s_keys_keyboard_look_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_keyboard_look_action.localdata[0]= ++i; - s_keys_keyboard_look_action.name= bindnames[s_keys_keyboard_look_action.localdata[0]][1]; - - s_keys_move_up_action.type= MTYPE_ACTION; - s_keys_move_up_action.flags= QMF_GRAYED; - s_keys_move_up_action.x= 0; - s_keys_move_up_action.y= y += 9; - s_keys_move_up_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_move_up_action.localdata[0]= ++i; - s_keys_move_up_action.name= bindnames[s_keys_move_up_action.localdata[0]][1]; - - s_keys_move_down_action.type= MTYPE_ACTION; - s_keys_move_down_action.flags= QMF_GRAYED; - s_keys_move_down_action.x= 0; - s_keys_move_down_action.y= y += 9; - s_keys_move_down_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_move_down_action.localdata[0]= ++i; - s_keys_move_down_action.name= bindnames[s_keys_move_down_action.localdata[0]][1]; - - s_keys_inventory_action.type= MTYPE_ACTION; - s_keys_inventory_action.flags= QMF_GRAYED; - s_keys_inventory_action.x= 0; - s_keys_inventory_action.y= y += 9; - s_keys_inventory_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_inventory_action.localdata[0]= ++i; - s_keys_inventory_action.name= bindnames[s_keys_inventory_action.localdata[0]][1]; - - s_keys_inv_use_action.type= MTYPE_ACTION; - s_keys_inv_use_action.flags= QMF_GRAYED; - s_keys_inv_use_action.x= 0; - s_keys_inv_use_action.y= y += 9; - s_keys_inv_use_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_inv_use_action.localdata[0]= ++i; - s_keys_inv_use_action.name= bindnames[s_keys_inv_use_action.localdata[0]][1]; - - s_keys_inv_drop_action.type= MTYPE_ACTION; - s_keys_inv_drop_action.flags= QMF_GRAYED; - s_keys_inv_drop_action.x= 0; - s_keys_inv_drop_action.y= y += 9; - s_keys_inv_drop_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_inv_drop_action.localdata[0]= ++i; - s_keys_inv_drop_action.name= bindnames[s_keys_inv_drop_action.localdata[0]][1]; - - s_keys_inv_prev_action.type= MTYPE_ACTION; - s_keys_inv_prev_action.flags= QMF_GRAYED; - s_keys_inv_prev_action.x= 0; - s_keys_inv_prev_action.y= y += 9; - s_keys_inv_prev_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_inv_prev_action.localdata[0]= ++i; - s_keys_inv_prev_action.name= bindnames[s_keys_inv_prev_action.localdata[0]][1]; - - s_keys_inv_next_action.type= MTYPE_ACTION; - s_keys_inv_next_action.flags= QMF_GRAYED; - s_keys_inv_next_action.x= 0; - s_keys_inv_next_action.y= y += 9; - s_keys_inv_next_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_inv_next_action.localdata[0]= ++i; - s_keys_inv_next_action.name= bindnames[s_keys_inv_next_action.localdata[0]][1]; - - s_keys_help_computer_action.type= MTYPE_ACTION; - s_keys_help_computer_action.flags= QMF_GRAYED; - s_keys_help_computer_action.x= 0; - s_keys_help_computer_action.y= y += 9; - s_keys_help_computer_action.ownerdraw= new mcallback() { - public void execute(Object o) { - DrawKeyBindingFunc(o); - } - }; - - s_keys_help_computer_action.localdata[0]= ++i; - s_keys_help_computer_action.name= bindnames[s_keys_help_computer_action.localdata[0]][1]; - - Menu_AddItem(s_keys_menu, s_keys_attack_action); - Menu_AddItem(s_keys_menu, s_keys_change_weapon_action); - Menu_AddItem(s_keys_menu, s_keys_walk_forward_action); - Menu_AddItem(s_keys_menu, s_keys_backpedal_action); - Menu_AddItem(s_keys_menu, s_keys_turn_left_action); - Menu_AddItem(s_keys_menu, s_keys_turn_right_action); - Menu_AddItem(s_keys_menu, s_keys_run_action); - Menu_AddItem(s_keys_menu, s_keys_step_left_action); - Menu_AddItem(s_keys_menu, s_keys_step_right_action); - Menu_AddItem(s_keys_menu, s_keys_sidestep_action); - Menu_AddItem(s_keys_menu, s_keys_look_up_action); - Menu_AddItem(s_keys_menu, s_keys_look_down_action); - Menu_AddItem(s_keys_menu, s_keys_center_view_action); - Menu_AddItem(s_keys_menu, s_keys_mouse_look_action); - Menu_AddItem(s_keys_menu, s_keys_keyboard_look_action); - Menu_AddItem(s_keys_menu, s_keys_move_up_action); - Menu_AddItem(s_keys_menu, s_keys_move_down_action); - - Menu_AddItem(s_keys_menu, s_keys_inventory_action); - Menu_AddItem(s_keys_menu, s_keys_inv_use_action); - Menu_AddItem(s_keys_menu, s_keys_inv_drop_action); - Menu_AddItem(s_keys_menu, s_keys_inv_prev_action); - Menu_AddItem(s_keys_menu, s_keys_inv_next_action); - - Menu_AddItem(s_keys_menu, s_keys_help_computer_action); - - Menu_SetStatusBar(s_keys_menu, "enter to change, backspace to clear"); - Menu_Center(s_keys_menu); - } - - static xcommand_t Keys_MenuDraw= new xcommand_t() { - public void execute() { - Keys_MenuDraw_f(); - } - }; - - static void Keys_MenuDraw_f() { - Menu_AdjustCursor(s_keys_menu, 1); - Menu_Draw(s_keys_menu); - } - - static keyfunc_t Keys_MenuKey= new keyfunc_t() { - public String execute(int key) { - return Keys_MenuKey_f(key); - } - }; - static String Keys_MenuKey_f(int key) { - menuaction_s item= (menuaction_s) Menu_ItemAtCursor(s_keys_menu); - - if (bind_grab) { - if (key != K_ESCAPE && key != '`') { - //char cmd[1024]; - String cmd; - - //Com_sprintf(cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item.localdata[0]][0]); - cmd= "bind \"" + Key.KeynumToString(key) + "\" \"" + bindnames[item.localdata[0]][0] + "\""; - Cbuf.InsertText(cmd); - } - - Menu_SetStatusBar(s_keys_menu, "enter to change, backspace to clear"); - bind_grab= false; - return menu_out_sound; - } - - switch (key) { - case K_KP_ENTER : - case K_ENTER : - KeyBindingFunc(item); - return menu_in_sound; - case K_BACKSPACE : // delete bindings - case K_DEL : // delete bindings - case K_KP_DEL : - UnbindCommand(bindnames[item.localdata[0]][0]); - return menu_out_sound; - default : - return Default_MenuKey(s_keys_menu, key); - } - } - - static xcommand_t Menu_Keys= new xcommand_t() { - public void execute() { - Menu_Keys_f(); - } - }; - static void Menu_Keys_f() { - Keys_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - Keys_MenuDraw_f(); - } - }, new keyfunc_t() { - public String execute(int key) { - return Keys_MenuKey_f(key); - } - }); - } - - /* - ======================================================================= - - CONTROLS MENU - - ======================================================================= - */ - static cvar_t win_noalttab; - - static menuframework_s s_options_menu= new menuframework_s(); - static menuaction_s s_options_defaults_action= new menuaction_s(); - static menuaction_s s_options_customize_options_action= new menuaction_s(); - static menuslider_s s_options_sensitivity_slider= new menuslider_s(); - static menulist_s s_options_freelook_box= new menulist_s(); - static menulist_s s_options_noalttab_box= new menulist_s(); - static menulist_s s_options_alwaysrun_box= new menulist_s(); - static menulist_s s_options_invertmouse_box= new menulist_s(); - static menulist_s s_options_lookspring_box= new menulist_s(); - static menulist_s s_options_lookstrafe_box= new menulist_s(); - static menulist_s s_options_crosshair_box= new menulist_s(); - static menuslider_s s_options_sfxvolume_slider= new menuslider_s(); - static menulist_s s_options_joystick_box= new menulist_s(); - static menulist_s s_options_cdvolume_box= new menulist_s(); - static menulist_s s_options_quality_list= new menulist_s(); - //static menulist_s s_options_compatibility_list = new menulist_s(); - static menuaction_s s_options_console_action= new menuaction_s(); - - static void CrosshairFunc(Object unused) { - Cvar.SetValue("crosshair", s_options_crosshair_box.curvalue); - } - - static void JoystickFunc(Object unused) { - Cvar.SetValue("in_joystick", s_options_joystick_box.curvalue); - } - - static void CustomizeControlsFunc(Object unused) { - Menu_Keys_f(); - } - - static void AlwaysRunFunc(Object unused) { - Cvar.SetValue("cl_run", s_options_alwaysrun_box.curvalue); - } - - static void FreeLookFunc(Object unused) { - Cvar.SetValue("freelook", s_options_freelook_box.curvalue); - } - - static void MouseSpeedFunc(Object unused) { - Cvar.SetValue("sensitivity", s_options_sensitivity_slider.curvalue / 2.0F); - } - - static void NoAltTabFunc(Object unused) { - Cvar.SetValue("win_noalttab", s_options_noalttab_box.curvalue); - } - - static float ClampCvar(float min, float max, float value) { - if (value < min) - return min; - if (value > max) - return max; - return value; - } - - static void ControlsSetMenuItemValues() { - s_options_sfxvolume_slider.curvalue= Cvar.VariableValue("s_volume") * 10; - s_options_cdvolume_box.curvalue= 1 - ((int) Cvar.VariableValue("cd_nocd")); - //s_options_quality_list.curvalue = 1 - ((int) Cvar.VariableValue("s_loadas8bit")); - if ("joal".equals(Cvar.VariableString("s_impl"))) { - s_options_quality_list.curvalue= 0; - } - else { - s_options_quality_list.curvalue= 1; - } - - s_options_sensitivity_slider.curvalue= (sensitivity.value) * 2; - - Cvar.SetValue("cl_run", ClampCvar(0, 1, cl_run.value)); - s_options_alwaysrun_box.curvalue= (int) cl_run.value; - - s_options_invertmouse_box.curvalue= m_pitch.value < 0 ? 1 : 0; - - Cvar.SetValue("lookspring", ClampCvar(0, 1, lookspring.value)); - s_options_lookspring_box.curvalue= (int) lookspring.value; - - Cvar.SetValue("lookstrafe", ClampCvar(0, 1, lookstrafe.value)); - s_options_lookstrafe_box.curvalue= (int) lookstrafe.value; - - Cvar.SetValue("freelook", ClampCvar(0, 1, freelook.value)); - s_options_freelook_box.curvalue= (int) freelook.value; - - Cvar.SetValue("crosshair", ClampCvar(0, 3, Globals.crosshair.value)); - s_options_crosshair_box.curvalue= (int) Globals.crosshair.value; - - Cvar.SetValue("in_joystick", ClampCvar(0, 1, in_joystick.value)); - s_options_joystick_box.curvalue= (int) in_joystick.value; - - s_options_noalttab_box.curvalue= (int) win_noalttab.value; - } - - static void ControlsResetDefaultsFunc(Object unused) { - Cbuf.AddText("exec default.cfg\n"); - Cbuf.Execute(); - - ControlsSetMenuItemValues(); - } - - static void InvertMouseFunc(Object unused) { - Cvar.SetValue("m_pitch", -m_pitch.value); - } - - static void LookspringFunc(Object unused) { - Cvar.SetValue("lookspring", 1 - lookspring.value); - } - - static void LookstrafeFunc(Object unused) { - Cvar.SetValue("lookstrafe", 1 - lookstrafe.value); - } - - static void UpdateVolumeFunc(Object unused) { - Cvar.SetValue("s_volume", s_options_sfxvolume_slider.curvalue / 10); - } - - static void UpdateCDVolumeFunc(Object unused) { - Cvar.SetValue("cd_nocd", 1 - s_options_cdvolume_box.curvalue); - } - - static void ConsoleFunc(Object unused) { - /* - ** the proper way to do this is probably to have ToggleConsole_f accept a parameter - */ - - if (cl.attractloop) { - Cbuf.AddText("killserver\n"); - return; - } - - Key.ClearTyping(); - Console.ClearNotify(); - - ForceMenuOff(); - cls.key_dest= key_console; - } - - static void UpdateSoundQualityFunc(Object unused) { - boolean driverNotChanged= false; - if (s_options_quality_list.curvalue != 0) { - // Cvar.SetValue("s_khz", 22); - // Cvar.SetValue("s_loadas8bit", 0); - driverNotChanged= S.getDriverName().equals("dummy"); - Cvar.Set("s_impl", "dummy"); - } - else { - // Cvar.SetValue("s_khz", 11); - // Cvar.SetValue("s_loadas8bit", 1); - driverNotChanged= S.getDriverName().equals("joal"); - Cvar.Set("s_impl", "joal"); - } - - //Cvar.SetValue("s_primary", s_options_compatibility_list.curvalue); - - if (driverNotChanged) { - re.EndFrame(); - return; - } - else { - - DrawTextBox(8, 120 - 48, 36, 3); - Print(16 + 16, 120 - 48 + 8, "Restarting the sound system. This"); - Print(16 + 16, 120 - 48 + 16, "could take up to a minute, so"); - Print(16 + 16, 120 - 48 + 24, "please be patient."); - - // the text box won't show up unless we do a buffer swap - re.EndFrame(); - - CL.Snd_Restart_f.execute(); - } - } - - static String cd_music_items[]= { "disabled", "enabled", null }; - static String soundstate_items[]= { "on", "off", null }; - - static String compatibility_items[]= { "max compatibility", "max performance", null }; - - static String yesno_names[]= { "no", "yes", null }; - - static String crosshair_names[]= { "none", "cross", "dot", "angle", null }; - - static void Options_MenuInit() { - - win_noalttab= Cvar.Get("win_noalttab", "0", CVAR_ARCHIVE); - - /* - ** configure controls menu and menu items - */ - s_options_menu.x= viddef.width / 2; - s_options_menu.y= viddef.height / 2 - 58; - s_options_menu.nitems= 0; - - s_options_sfxvolume_slider.type= MTYPE_SLIDER; - s_options_sfxvolume_slider.x= 0; - s_options_sfxvolume_slider.y= 0; - s_options_sfxvolume_slider.name= "effects volume"; - s_options_sfxvolume_slider.callback= new mcallback() { - public void execute(Object o) { - UpdateVolumeFunc(o); - } - }; - s_options_sfxvolume_slider.minvalue= 0; - s_options_sfxvolume_slider.maxvalue= 10; - s_options_sfxvolume_slider.curvalue= Cvar.VariableValue("s_volume") * 10; - - s_options_cdvolume_box.type= MTYPE_SPINCONTROL; - s_options_cdvolume_box.x= 0; - s_options_cdvolume_box.y= 10; - s_options_cdvolume_box.name= "CD music"; - s_options_cdvolume_box.callback= new mcallback() { - public void execute(Object o) { - UpdateCDVolumeFunc(o); - } - }; - s_options_cdvolume_box.itemnames= cd_music_items; - s_options_cdvolume_box.curvalue= 1 - (int) Cvar.VariableValue("cd_nocd"); - - s_options_quality_list.type= MTYPE_SPINCONTROL; - s_options_quality_list.x= 0; - s_options_quality_list.y= 20; - ; - s_options_quality_list.name= "sound"; - s_options_quality_list.callback= new mcallback() { - public void execute(Object o) { - UpdateSoundQualityFunc(o); - } - }; - s_options_quality_list.itemnames= soundstate_items; - //s_options_quality_list.curvalue = 1 - (int) Cvar.VariableValue("s_loadas8bit"); - - // s_options_compatibility_list.type = MTYPE_SPINCONTROL; - // s_options_compatibility_list.x = 0; - // s_options_compatibility_list.y = 30; - // s_options_compatibility_list.name = "sound compatibility"; - // s_options_compatibility_list.callback = new mcallback() { - // public void execute(Object o) { - // UpdateSoundQualityFunc(o); - // } - // }; - // s_options_compatibility_list.itemnames = compatibility_items; - // s_options_compatibility_list.curvalue = (int) Cvar.VariableValue("s_primary"); - - s_options_sensitivity_slider.type= MTYPE_SLIDER; - s_options_sensitivity_slider.x= 0; - s_options_sensitivity_slider.y= 50; - s_options_sensitivity_slider.name= "mouse speed"; - s_options_sensitivity_slider.callback= new mcallback() { - public void execute(Object o) { - MouseSpeedFunc(o); - } - }; - s_options_sensitivity_slider.minvalue= 2; - s_options_sensitivity_slider.maxvalue= 22; - - s_options_alwaysrun_box.type= MTYPE_SPINCONTROL; - s_options_alwaysrun_box.x= 0; - s_options_alwaysrun_box.y= 60; - s_options_alwaysrun_box.name= "always run"; - s_options_alwaysrun_box.callback= new mcallback() { - public void execute(Object o) { - AlwaysRunFunc(o); - } - }; - s_options_alwaysrun_box.itemnames= yesno_names; - - s_options_invertmouse_box.type= MTYPE_SPINCONTROL; - s_options_invertmouse_box.x= 0; - s_options_invertmouse_box.y= 70; - s_options_invertmouse_box.name= "invert mouse"; - s_options_invertmouse_box.callback= new mcallback() { - public void execute(Object o) { - InvertMouseFunc(o); - } - }; - s_options_invertmouse_box.itemnames= yesno_names; - - s_options_lookspring_box.type= MTYPE_SPINCONTROL; - s_options_lookspring_box.x= 0; - s_options_lookspring_box.y= 80; - s_options_lookspring_box.name= "lookspring"; - s_options_lookspring_box.callback= new mcallback() { - public void execute(Object o) { - LookspringFunc(o); - } - }; - s_options_lookspring_box.itemnames= yesno_names; - - s_options_lookstrafe_box.type= MTYPE_SPINCONTROL; - s_options_lookstrafe_box.x= 0; - s_options_lookstrafe_box.y= 90; - s_options_lookstrafe_box.name= "lookstrafe"; - s_options_lookstrafe_box.callback= new mcallback() { - public void execute(Object o) { - LookstrafeFunc(o); - } - }; - s_options_lookstrafe_box.itemnames= yesno_names; - - s_options_freelook_box.type= MTYPE_SPINCONTROL; - s_options_freelook_box.x= 0; - s_options_freelook_box.y= 100; - s_options_freelook_box.name= "free look"; - s_options_freelook_box.callback= new mcallback() { - public void execute(Object o) { - FreeLookFunc(o); - } - }; - s_options_freelook_box.itemnames= yesno_names; - - s_options_crosshair_box.type= MTYPE_SPINCONTROL; - s_options_crosshair_box.x= 0; - s_options_crosshair_box.y= 110; - s_options_crosshair_box.name= "crosshair"; - s_options_crosshair_box.callback= new mcallback() { - public void execute(Object o) { - CrosshairFunc(o); - } - }; - s_options_crosshair_box.itemnames= crosshair_names; - /* - s_options_noalttab_box.type = MTYPE_SPINCONTROL; - s_options_noalttab_box.x = 0; - s_options_noalttab_box.y = 110; - s_options_noalttab_box.name = "disable alt-tab"; - s_options_noalttab_box.callback = NoAltTabFunc; - s_options_noalttab_box.itemnames = yesno_names; - */ - s_options_joystick_box.type= MTYPE_SPINCONTROL; - s_options_joystick_box.x= 0; - s_options_joystick_box.y= 120; - s_options_joystick_box.name= "use joystick"; - s_options_joystick_box.callback= new mcallback() { - public void execute(Object o) { - JoystickFunc(o); - } - }; - s_options_joystick_box.itemnames= yesno_names; - - s_options_customize_options_action.type= MTYPE_ACTION; - s_options_customize_options_action.x= 0; - s_options_customize_options_action.y= 140; - s_options_customize_options_action.name= "customize controls"; - s_options_customize_options_action.callback= new mcallback() { - public void execute(Object o) { - CustomizeControlsFunc(o); - } - }; - - s_options_defaults_action.type= MTYPE_ACTION; - s_options_defaults_action.x= 0; - s_options_defaults_action.y= 150; - s_options_defaults_action.name= "reset defaults"; - s_options_defaults_action.callback= new mcallback() { - public void execute(Object o) { - ControlsResetDefaultsFunc(o); - } - }; - - s_options_console_action.type= MTYPE_ACTION; - s_options_console_action.x= 0; - s_options_console_action.y= 160; - s_options_console_action.name= "go to console"; - s_options_console_action.callback= new mcallback() { - public void execute(Object o) { - ConsoleFunc(o); - } - }; - - ControlsSetMenuItemValues(); - - Menu_AddItem(s_options_menu, s_options_sfxvolume_slider); - - Menu_AddItem(s_options_menu, s_options_cdvolume_box); - Menu_AddItem(s_options_menu, s_options_quality_list); - // Menu_AddItem(s_options_menu, s_options_compatibility_list); - Menu_AddItem(s_options_menu, s_options_sensitivity_slider); - Menu_AddItem(s_options_menu, s_options_alwaysrun_box); - Menu_AddItem(s_options_menu, s_options_invertmouse_box); - Menu_AddItem(s_options_menu, s_options_lookspring_box); - Menu_AddItem(s_options_menu, s_options_lookstrafe_box); - Menu_AddItem(s_options_menu, s_options_freelook_box); - Menu_AddItem(s_options_menu, s_options_crosshair_box); - // Menu_AddItem(s_options_menu, s_options_joystick_box); - Menu_AddItem(s_options_menu, s_options_customize_options_action); - Menu_AddItem(s_options_menu, s_options_defaults_action); - Menu_AddItem(s_options_menu, s_options_console_action); - } - - static void Options_MenuDraw() { - Banner("m_banner_options"); - Menu_AdjustCursor(s_options_menu, 1); - Menu_Draw(s_options_menu); - } - - static String Options_MenuKey(int key) { - return Default_MenuKey(s_options_menu, key); - } - - static xcommand_t Menu_Options= new xcommand_t() { - public void execute() { - Menu_Options_f(); - } - }; - - static void Menu_Options_f() { - Options_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - Options_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return Options_MenuKey(key); - } - }); - } - - /* - ======================================================================= - - VIDEO MENU - - ======================================================================= - */ - - static xcommand_t Menu_Video= new xcommand_t() { - public void execute() { - Menu_Video_f(); - } - }; - - static void Menu_Video_f() { - VID.MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - VID.MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return VID.MenuKey(key); - } - }); - } - - /* - ============================================================================= - - END GAME MENU - - ============================================================================= - */ - static int credits_start_time; - - static String creditsIndex[]= new String[256]; - static String creditsBuffer; - static String idcredits[]= - { - "+QUAKE II BY ID SOFTWARE", - "", - "+PROGRAMMING", - "John Carmack", - "John Cash", - "Brian Hook", - "", - "+JAVA PORT BY BYTONIC", - "CWEI", - "HOZ", - "RST", - "", - "+ART", - "Adrian Carmack", - "Kevin Cloud", - "Paul Steed", - "", - "+LEVEL DESIGN", - "Tim Willits", - "American McGee", - "Christian Antkow", - "Paul Jaquays", - "Brandon James", - "", - "+BIZ", - "Todd Hollenshead", - "Barrett (Bear) Alexander", - "Donna Jackson", - "", - "", - "+SPECIAL THANKS", - "Ben Donges for beta testing", - "", - "", - "", - "", - "", - "", - "+ADDITIONAL SUPPORT", - "", - "+LINUX PORT AND CTF", - "Dave \"Zoid\" Kirsch", - "", - "+CINEMATIC SEQUENCES", - "Ending Cinematic by Blur Studio - ", - "Venice, CA", - "", - "Environment models for Introduction", - "Cinematic by Karl Dolgener", - "", - "Assistance with environment design", - "by Cliff Iwai", - "", - "+SOUND EFFECTS AND MUSIC", - "Sound Design by Soundelux Media Labs.", - "Music Composed and Produced by", - "Soundelux Media Labs. Special thanks", - "to Bill Brown, Tom Ozanich, Brian", - "Celano, Jeff Eisner, and The Soundelux", - "Players.", - "", - "\"Level Music\" by Sonic Mayhem", - "www.sonicmayhem.com", - "", - "\"Quake II Theme Song\"", - "(C) 1997 Rob Zombie. All Rights", - "Reserved.", - "", - "Track 10 (\"Climb\") by Jer Sypult", - "", - "Voice of computers by", - "Carly Staehlin-Taylor", - "", - "+THANKS TO ACTIVISION", - "+IN PARTICULAR:", - "", - "John Tam", - "Steve Rosenthal", - "Marty Stratton", - "Henk Hartong", - "", - "Quake II(tm) (C)1997 Id Software, Inc.", - "All Rights Reserved. Distributed by", - "Activision, Inc. under license.", - "Quake II(tm), the Id Software name,", - "the \"Q II\"(tm) logo and id(tm)", - "logo are trademarks of Id Software,", - "Inc. Activision(R) is a registered", - "trademark of Activision, Inc. All", - "other trademarks and trade names are", - "properties of their respective owners.", - null }; - static String credits[]= idcredits; - static String xatcredits[]= - { - "+QUAKE II MISSION PACK: THE RECKONING", - "+BY", - "+XATRIX ENTERTAINMENT, INC.", - "", - "+DESIGN AND DIRECTION", - "Drew Markham", - "", - "+PRODUCED BY", - "Greg Goodrich", - "", - "+PROGRAMMING", - "Rafael Paiz", - "", - "+LEVEL DESIGN / ADDITIONAL GAME DESIGN", - "Alex Mayberry", - "", - "+LEVEL DESIGN", - "Mal Blackwell", - "Dan Koppel", - "", - "+ART DIRECTION", - "Michael \"Maxx\" Kaufman", - "", - "+COMPUTER GRAPHICS SUPERVISOR AND", - "+CHARACTER ANIMATION DIRECTION", - "Barry Dempsey", - "", - "+SENIOR ANIMATOR AND MODELER", - "Jason Hoover", - "", - "+CHARACTER ANIMATION AND", - "+MOTION CAPTURE SPECIALIST", - "Amit Doron", - "", - "+ART", - "Claire Praderie-Markham", - "Viktor Antonov", - "Corky Lehmkuhl", - "", - "+INTRODUCTION ANIMATION", - "Dominique Drozdz", - "", - "+ADDITIONAL LEVEL DESIGN", - "Aaron Barber", - "Rhett Baldwin", - "", - "+3D CHARACTER ANIMATION TOOLS", - "Gerry Tyra, SA Technology", - "", - "+ADDITIONAL EDITOR TOOL PROGRAMMING", - "Robert Duffy", - "", - "+ADDITIONAL PROGRAMMING", - "Ryan Feltrin", - "", - "+PRODUCTION COORDINATOR", - "Victoria Sylvester", - "", - "+SOUND DESIGN", - "Gary Bradfield", - "", - "+MUSIC BY", - "Sonic Mayhem", - "", - "", - "", - "+SPECIAL THANKS", - "+TO", - "+OUR FRIENDS AT ID SOFTWARE", - "", - "John Carmack", - "John Cash", - "Brian Hook", - "Adrian Carmack", - "Kevin Cloud", - "Paul Steed", - "Tim Willits", - "Christian Antkow", - "Paul Jaquays", - "Brandon James", - "Todd Hollenshead", - "Barrett (Bear) Alexander", - "Dave \"Zoid\" Kirsch", - "Donna Jackson", - "", - "", - "", - "+THANKS TO ACTIVISION", - "+IN PARTICULAR:", - "", - "Marty Stratton", - "Henk \"The Original Ripper\" Hartong", - "Kevin Kraff", - "Jamey Gottlieb", - "Chris Hepburn", - "", - "+AND THE GAME TESTERS", - "", - "Tim Vanlaw", - "Doug Jacobs", - "Steven Rosenthal", - "David Baker", - "Chris Campbell", - "Aaron Casillas", - "Steve Elwell", - "Derek Johnstone", - "Igor Krinitskiy", - "Samantha Lee", - "Michael Spann", - "Chris Toft", - "Juan Valdes", - "", - "+THANKS TO INTERGRAPH COMPUTER SYTEMS", - "+IN PARTICULAR:", - "", - "Michael T. Nicolaou", - "", - "", - "Quake II Mission Pack: The Reckoning", - "(tm) (C)1998 Id Software, Inc. All", - "Rights Reserved. Developed by Xatrix", - "Entertainment, Inc. for Id Software,", - "Inc. Distributed by Activision Inc.", - "under license. Quake(R) is a", - "registered trademark of Id Software,", - "Inc. Quake II Mission Pack: The", - "Reckoning(tm), Quake II(tm), the Id", - "Software name, the \"Q II\"(tm) logo", - "and id(tm) logo are trademarks of Id", - "Software, Inc. Activision(R) is a", - "registered trademark of Activision,", - "Inc. Xatrix(R) is a registered", - "trademark of Xatrix Entertainment,", - "Inc. All other trademarks and trade", - "names are properties of their", - "respective owners.", - null }; - - static String roguecredits[]= - { - "+QUAKE II MISSION PACK 2: GROUND ZERO", - "+BY", - "+ROGUE ENTERTAINMENT, INC.", - "", - "+PRODUCED BY", - "Jim Molinets", - "", - "+PROGRAMMING", - "Peter Mack", - "Patrick Magruder", - "", - "+LEVEL DESIGN", - "Jim Molinets", - "Cameron Lamprecht", - "Berenger Fish", - "Robert Selitto", - "Steve Tietze", - "Steve Thoms", - "", - "+ART DIRECTION", - "Rich Fleider", - "", - "+ART", - "Rich Fleider", - "Steve Maines", - "Won Choi", - "", - "+ANIMATION SEQUENCES", - "Creat Studios", - "Steve Maines", - "", - "+ADDITIONAL LEVEL DESIGN", - "Rich Fleider", - "Steve Maines", - "Peter Mack", - "", - "+SOUND", - "James Grunke", - "", - "+GROUND ZERO THEME", - "+AND", - "+MUSIC BY", - "Sonic Mayhem", - "", - "+VWEP MODELS", - "Brent \"Hentai\" Dill", - "", - "", - "", - "+SPECIAL THANKS", - "+TO", - "+OUR FRIENDS AT ID SOFTWARE", - "", - "John Carmack", - "John Cash", - "Brian Hook", - "Adrian Carmack", - "Kevin Cloud", - "Paul Steed", - "Tim Willits", - "Christian Antkow", - "Paul Jaquays", - "Brandon James", - "Todd Hollenshead", - "Barrett (Bear) Alexander", - "Katherine Anna Kang", - "Donna Jackson", - "Dave \"Zoid\" Kirsch", - "", - "", - "", - "+THANKS TO ACTIVISION", - "+IN PARTICULAR:", - "", - "Marty Stratton", - "Henk Hartong", - "Mitch Lasky", - "Steve Rosenthal", - "Steve Elwell", - "", - "+AND THE GAME TESTERS", - "", - "The Ranger Clan", - "Dave \"Zoid\" Kirsch", - "Nihilistic Software", - "Robert Duffy", - "", - "And Countless Others", - "", - "", - "", - "Quake II Mission Pack 2: Ground Zero", - "(tm) (C)1998 Id Software, Inc. All", - "Rights Reserved. Developed by Rogue", - "Entertainment, Inc. for Id Software,", - "Inc. Distributed by Activision Inc.", - "under license. Quake(R) is a", - "registered trademark of Id Software,", - "Inc. Quake II Mission Pack 2: Ground", - "Zero(tm), Quake II(tm), the Id", - "Software name, the \"Q II\"(tm) logo", - "and id(tm) logo are trademarks of Id", - "Software, Inc. Activision(R) is a", - "registered trademark of Activision,", - "Inc. Rogue(R) is a registered", - "trademark of Rogue Entertainment,", - "Inc. All other trademarks and trade", - "names are properties of their", - "respective owners.", - null }; - - public static void Credits_MenuDraw() { - int i, y; - - /* - ** draw the credits - */ - for (i= 0, y= (int) (viddef.height - ((cls.realtime - credits_start_time) / 40.0F)); - credits[i] != null && y < viddef.height; - y += 10, i++) { - int j, stringoffset= 0; - boolean bold= false; - - if (y <= -8) - continue; - - if (credits[i].length() > 0 && credits[i].charAt(0) == '+') { - bold= true; - stringoffset= 1; - } - else { - bold= false; - stringoffset= 0; - } - - for (j= 0; j + stringoffset < credits[i].length(); j++) { - int x; - - x= (viddef.width - credits[i].length() * 8 - stringoffset * 8) / 2 + (j + stringoffset) * 8; - - if (bold) - re.DrawChar(x, y, credits[i].charAt(j + stringoffset) + 128); - else - re.DrawChar(x, y, credits[i].charAt(j + stringoffset)); - } - } - - if (y < 0) - credits_start_time= cls.realtime; - } - - public static String Credits_Key(int key) { - switch (key) { - case K_ESCAPE : - if (creditsBuffer != null) - //FS.FreeFile(creditsBuffer); - ; - PopMenu(); - break; - } - - return menu_out_sound; - - } - - static xcommand_t Menu_Credits= new xcommand_t() { - public void execute() { - Menu_Credits_f(); - } - }; - static void Menu_Credits_f() { - int n; - int isdeveloper= 0; - - byte b[]= FS.LoadFile("credits"); - - if (b != null) { - creditsBuffer= new String(b); - String line[]= Lib.linesplit(creditsBuffer); - - for (n= 0; n < line.length; n++) { - creditsIndex[n]= line[n]; - } - - creditsIndex[n]= null; - credits= creditsIndex; - } - else { - isdeveloper= FS.Developer_searchpath(1); - - if (isdeveloper == 1) // xatrix - credits= xatcredits; - else if (isdeveloper == 2) // ROGUE - credits= roguecredits; - else { - credits= idcredits; - } - - } - - credits_start_time= cls.realtime; - PushMenu(new xcommand_t() { - public void execute() { - Credits_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return Credits_Key(key); - } - }); - } - - /* - ============================================================================= - - GAME MENU - - ============================================================================= - */ - - static int m_game_cursor; - - static menuframework_s s_game_menu= new menuframework_s(); - static menuaction_s s_easy_game_action= new menuaction_s(); - static menuaction_s s_medium_game_action= new menuaction_s(); - static menuaction_s s_hard_game_action= new menuaction_s(); - static menuaction_s s_load_game_action= new menuaction_s(); - static menuaction_s s_save_game_action= new menuaction_s(); - static menuaction_s s_credits_action= new menuaction_s(); - static menuseparator_s s_blankline= new menuseparator_s(); - - static void StartGame() { - // disable updates and start the cinematic going - cl.servercount= -1; - ForceMenuOff(); - Cvar.SetValue("deathmatch", 0); - Cvar.SetValue("coop", 0); - - Cvar.SetValue("gamerules", 0); //PGM - - Cbuf.AddText("loading ; killserver ; wait ; newgame\n"); - cls.key_dest= key_game; - } - - static void EasyGameFunc(Object data) { - Cvar.ForceSet("skill", "0"); - StartGame(); - } - - static void MediumGameFunc(Object data) { - Cvar.ForceSet("skill", "1"); - StartGame(); - } - - static void HardGameFunc(Object data) { - Cvar.ForceSet("skill", "2"); - StartGame(); - } - - static void LoadGameFunc(Object unused) { - Menu_LoadGame_f(); - } - - static void SaveGameFunc(Object unused) { - Menu_SaveGame_f(); - } - - static void CreditsFunc(Object unused) { - Menu_Credits_f(); - } - - static String difficulty_names[]= { "easy", "medium", "fuckin shitty hard", null }; - static void Game_MenuInit() { - - s_game_menu.x= (int) (viddef.width * 0.50); - s_game_menu.nitems= 0; - - s_easy_game_action.type= MTYPE_ACTION; - s_easy_game_action.flags= QMF_LEFT_JUSTIFY; - s_easy_game_action.x= 0; - s_easy_game_action.y= 0; - s_easy_game_action.name= "easy"; - s_easy_game_action.callback= new mcallback() { - public void execute(Object o) { - EasyGameFunc(o); - } - }; - - s_medium_game_action.type= MTYPE_ACTION; - s_medium_game_action.flags= QMF_LEFT_JUSTIFY; - s_medium_game_action.x= 0; - s_medium_game_action.y= 10; - s_medium_game_action.name= "medium"; - s_medium_game_action.callback= new mcallback() { - public void execute(Object o) { - MediumGameFunc(o); - } - }; - - s_hard_game_action.type= MTYPE_ACTION; - s_hard_game_action.flags= QMF_LEFT_JUSTIFY; - s_hard_game_action.x= 0; - s_hard_game_action.y= 20; - s_hard_game_action.name= "hard"; - s_hard_game_action.callback= new mcallback() { - public void execute(Object o) { - HardGameFunc(o); - } - }; - - s_blankline.type= MTYPE_SEPARATOR; - - s_load_game_action.type= MTYPE_ACTION; - s_load_game_action.flags= QMF_LEFT_JUSTIFY; - s_load_game_action.x= 0; - s_load_game_action.y= 40; - s_load_game_action.name= "load game"; - s_load_game_action.callback= new mcallback() { - public void execute(Object o) { - LoadGameFunc(o); - } - }; - - s_save_game_action.type= MTYPE_ACTION; - s_save_game_action.flags= QMF_LEFT_JUSTIFY; - s_save_game_action.x= 0; - s_save_game_action.y= 50; - s_save_game_action.name= "save game"; - s_save_game_action.callback= new mcallback() { - public void execute(Object o) { - SaveGameFunc(o); - } - }; - - s_credits_action.type= MTYPE_ACTION; - s_credits_action.flags= QMF_LEFT_JUSTIFY; - s_credits_action.x= 0; - s_credits_action.y= 60; - s_credits_action.name= "credits"; - s_credits_action.callback= new mcallback() { - public void execute(Object o) { - CreditsFunc(o); - } - }; - - Menu_AddItem(s_game_menu, s_easy_game_action); - Menu_AddItem(s_game_menu, s_medium_game_action); - Menu_AddItem(s_game_menu, s_hard_game_action); - Menu_AddItem(s_game_menu, s_blankline); - Menu_AddItem(s_game_menu, s_load_game_action); - Menu_AddItem(s_game_menu, s_save_game_action); - Menu_AddItem(s_game_menu, s_blankline); - Menu_AddItem(s_game_menu, s_credits_action); - - Menu_Center(s_game_menu); - } - - static void Game_MenuDraw() { - Banner("m_banner_game"); - Menu_AdjustCursor(s_game_menu, 1); - Menu_Draw(s_game_menu); - } - - static String Game_MenuKey(int key) { - return Default_MenuKey(s_game_menu, key); - } - - static xcommand_t Menu_Game= new xcommand_t() { - public void execute() { - Menu_Game_f(); - } - }; - - static void Menu_Game_f() { - Game_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - Game_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return Game_MenuKey(key); - } - }); - m_game_cursor= 1; - } - - /* - ============================================================================= - - LOADGAME MENU - - ============================================================================= - */ - - public final static int MAX_SAVEGAMES= 15; - - static menuframework_s s_savegame_menu= new menuframework_s(); - static menuframework_s s_loadgame_menu= new menuframework_s(); - - static menuaction_s s_loadgame_actions[]= new menuaction_s[MAX_SAVEGAMES]; - - static { - for (int n= 0; n < MAX_SAVEGAMES; n++) - s_loadgame_actions[n]= new menuaction_s(); - } - - //String m_savestrings[] = new String [MAX_SAVEGAMES][32]; - static String m_savestrings[]= new String[MAX_SAVEGAMES]; - - static { - for (int n= 0; n < MAX_SAVEGAMES; n++) - m_savestrings[n]= ""; - } - - static boolean m_savevalid[]= new boolean[MAX_SAVEGAMES]; - - /** Search the save dir for saved games and their names. */ - static void Create_Savestrings() { - int i; - QuakeFile f; - String name; - - for (i= 0; i < MAX_SAVEGAMES; i++) { - - m_savestrings[i]= ""; - name= FS.Gamedir() + "/save/save" + i + "/server.ssv"; - - try { - f= new QuakeFile(name, "r"); - if (f == null) { - m_savestrings[i]= ""; - m_savevalid[i]= false; - } - else { - String str= f.readString(); - if (str != null) - m_savestrings[i]= str; - f.close(); - m_savevalid[i]= true; - } - } - catch (Exception e) { - m_savestrings[i]= ""; - m_savevalid[i]= false; - }; - } - } - - static void LoadGameCallback(Object self) { - menuaction_s a= (menuaction_s) self; - - if (m_savevalid[a.localdata[0]]) - Cbuf.AddText("load save" + a.localdata[0] + "\n"); - ForceMenuOff(); - } - - static void LoadGame_MenuInit() { - int i; - - s_loadgame_menu.x= viddef.width / 2 - 120; - s_loadgame_menu.y= viddef.height / 2 - 58; - s_loadgame_menu.nitems= 0; - - Create_Savestrings(); - - for (i= 0; i < MAX_SAVEGAMES; i++) { - s_loadgame_actions[i].name= m_savestrings[i]; - s_loadgame_actions[i].flags= QMF_LEFT_JUSTIFY; - s_loadgame_actions[i].localdata[0]= i; - s_loadgame_actions[i].callback= new mcallback() { - public void execute(Object o) { - LoadGameCallback(o); - } - }; - - s_loadgame_actions[i].x= 0; - s_loadgame_actions[i].y= (i) * 10; - if (i > 0) // separate from autosave - s_loadgame_actions[i].y += 10; - - s_loadgame_actions[i].type= MTYPE_ACTION; - - Menu_AddItem(s_loadgame_menu, s_loadgame_actions[i]); - } - } - - static void LoadGame_MenuDraw() { - Banner("m_banner_load_game"); - // Menu_AdjustCursor( &s_loadgame_menu, 1 ); - Menu_Draw(s_loadgame_menu); - } - - static String LoadGame_MenuKey(int key) { - if (key == K_ESCAPE || key == K_ENTER) { - s_savegame_menu.cursor= s_loadgame_menu.cursor - 1; - if (s_savegame_menu.cursor < 0) - s_savegame_menu.cursor= 0; - } - return Default_MenuKey(s_loadgame_menu, key); - } - - static xcommand_t Menu_LoadGame= new xcommand_t() { - public void execute() { - Menu_LoadGame_f(); - } - }; - static void Menu_LoadGame_f() { - LoadGame_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - LoadGame_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return LoadGame_MenuKey(key); - } - }); - } - - /* - ============================================================================= - - SAVEGAME MENU - - ============================================================================= - */ - //static menuframework_s s_savegame_menu; - static menuaction_s s_savegame_actions[]= new menuaction_s[MAX_SAVEGAMES]; - - static { - for (int n= 0; n < MAX_SAVEGAMES; n++) - s_savegame_actions[n]= new menuaction_s(); - - } - - static void SaveGameCallback(Object self) { - menuaction_s a= (menuaction_s) self; - - Cbuf.AddText("save save" + a.localdata[0] + "\n"); - ForceMenuOff(); - } - - static void SaveGame_MenuDraw() { - Banner("m_banner_save_game"); - Menu_AdjustCursor(s_savegame_menu, 1); - Menu_Draw(s_savegame_menu); - } - - static void SaveGame_MenuInit() { - int i; - - s_savegame_menu.x= viddef.width / 2 - 120; - s_savegame_menu.y= viddef.height / 2 - 58; - s_savegame_menu.nitems= 0; - - Create_Savestrings(); - - // don't include the autosave slot - for (i= 0; i < MAX_SAVEGAMES - 1; i++) { - s_savegame_actions[i].name= m_savestrings[i + 1]; - s_savegame_actions[i].localdata[0]= i + 1; - s_savegame_actions[i].flags= QMF_LEFT_JUSTIFY; - s_savegame_actions[i].callback= new mcallback() { - public void execute(Object o) { - SaveGameCallback(o); - } - }; - - s_savegame_actions[i].x= 0; - s_savegame_actions[i].y= (i) * 10; - - s_savegame_actions[i].type= MTYPE_ACTION; - - Menu_AddItem(s_savegame_menu, s_savegame_actions[i]); - } - } - - static String SaveGame_MenuKey(int key) { - if (key == K_ENTER || key == K_ESCAPE) { - s_loadgame_menu.cursor= s_savegame_menu.cursor - 1; - if (s_loadgame_menu.cursor < 0) - s_loadgame_menu.cursor= 0; - } - return Default_MenuKey(s_savegame_menu, key); - } - - static xcommand_t Menu_SaveGame= new xcommand_t() { - public void execute() { - Menu_SaveGame_f(); - } - }; - - static void Menu_SaveGame_f() { - if (0 == Globals.server_state) - return; // not playing a game - - SaveGame_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - SaveGame_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return SaveGame_MenuKey(key); - } - }); - Create_Savestrings(); - } - - /* - ============================================================================= - - JOIN SERVER MENU - - ============================================================================= - */ - - static menuframework_s s_joinserver_menu= new menuframework_s(); - static menuseparator_s s_joinserver_server_title= new menuseparator_s(); - static menuaction_s s_joinserver_search_action= new menuaction_s(); - static menuaction_s s_joinserver_address_book_action= new menuaction_s(); - - static netadr_t local_server_netadr[]= new netadr_t[MAX_LOCAL_SERVERS]; - static String local_server_names[]= new String[MAX_LOCAL_SERVERS]; //[80]; - static menuaction_s s_joinserver_server_actions[]= new menuaction_s[MAX_LOCAL_SERVERS]; - - // user readable information - // network address - static { - for (int n= 0; n < MAX_LOCAL_SERVERS; n++) { - local_server_netadr[n]= new netadr_t(); - local_server_names[n]= ""; - s_joinserver_server_actions[n]= new menuaction_s(); - s_joinserver_server_actions[n].n= n; - } - } - - static int m_num_servers; - - static void AddToServerList(netadr_t adr, String info) { - int i; - - if (m_num_servers == MAX_LOCAL_SERVERS) - return; - - String x= info.trim(); - - // ignore if duplicated - - for (i= 0; i < m_num_servers; i++) - if (x.equals(local_server_names[i])) - return; - - local_server_netadr[m_num_servers]= adr; - local_server_names[m_num_servers]= x; - m_num_servers++; - } - - static void JoinServerFunc(Object self) { - String buffer; - int index; - - index= ((menucommon_s) self).n; - - if (Q_stricmp(local_server_names[index], NO_SERVER_STRING) == 0) - return; - - if (index >= m_num_servers) - return; - - buffer= "connect " + NET.AdrToString(local_server_netadr[index]) + "\n"; - Cbuf.AddText(buffer); - ForceMenuOff(); - } - - static void AddressBookFunc(Object self) { - Menu_AddressBook_f(); - } - - static void NullCursorDraw(Object self) { - } - - static void SearchLocalGames() { - int i; - - m_num_servers= 0; - for (i= 0; i < MAX_LOCAL_SERVERS; i++) - local_server_names[i]= NO_SERVER_STRING; - - DrawTextBox(8, 120 - 48, 36, 3); - Print(16 + 16, 120 - 48 + 8, "Searching for local servers, this"); - Print(16 + 16, 120 - 48 + 16, "could take up to a minute, so"); - Print(16 + 16, 120 - 48 + 24, "please be patient."); - - // the text box won't show up unless we do a buffer swap - re.EndFrame(); - - // send out info packets - CL.PingServers_f.execute(); - } - - static void SearchLocalGamesFunc(Object self) { - SearchLocalGames(); - } - - static void JoinServer_MenuInit() { - int i; - - s_joinserver_menu.x= (int) (viddef.width * 0.50 - 120); - s_joinserver_menu.nitems= 0; - - s_joinserver_address_book_action.type= MTYPE_ACTION; - s_joinserver_address_book_action.name= "address book"; - s_joinserver_address_book_action.flags= QMF_LEFT_JUSTIFY; - s_joinserver_address_book_action.x= 0; - s_joinserver_address_book_action.y= 0; - s_joinserver_address_book_action.callback= new mcallback() { - public void execute(Object o) { - AddressBookFunc(o); - } - }; - - s_joinserver_search_action.type= MTYPE_ACTION; - s_joinserver_search_action.name= "refresh server list"; - s_joinserver_search_action.flags= QMF_LEFT_JUSTIFY; - s_joinserver_search_action.x= 0; - s_joinserver_search_action.y= 10; - s_joinserver_search_action.callback= new mcallback() { - public void execute(Object o) { - SearchLocalGamesFunc(o); - } - }; - s_joinserver_search_action.statusbar= "search for servers"; - - s_joinserver_server_title.type= MTYPE_SEPARATOR; - s_joinserver_server_title.name= "connect to..."; - s_joinserver_server_title.x= 80; - s_joinserver_server_title.y= 30; - - for (i= 0; i < MAX_LOCAL_SERVERS; i++) { - s_joinserver_server_actions[i].type= MTYPE_ACTION; - local_server_names[i]= NO_SERVER_STRING; - s_joinserver_server_actions[i].name= local_server_names[i]; - s_joinserver_server_actions[i].flags= QMF_LEFT_JUSTIFY; - s_joinserver_server_actions[i].x= 0; - s_joinserver_server_actions[i].y= 40 + i * 10; - s_joinserver_server_actions[i].callback= new mcallback() { - public void execute(Object o) { - JoinServerFunc(o); - } - }; - s_joinserver_server_actions[i].statusbar= "press ENTER to connect"; - } - - Menu_AddItem(s_joinserver_menu, s_joinserver_address_book_action); - Menu_AddItem(s_joinserver_menu, s_joinserver_server_title); - Menu_AddItem(s_joinserver_menu, s_joinserver_search_action); - - for (i= 0; i < 8; i++) - Menu_AddItem(s_joinserver_menu, s_joinserver_server_actions[i]); - - Menu_Center(s_joinserver_menu); - - SearchLocalGames(); - } - - static void JoinServer_MenuDraw() { - Banner("m_banner_join_server"); - Menu_Draw(s_joinserver_menu); - } - - static String JoinServer_MenuKey(int key) { - return Default_MenuKey(s_joinserver_menu, key); - } - - static xcommand_t Menu_JoinServer= new xcommand_t() { - public void execute() { - Menu_JoinServer_f(); - } - }; - static void Menu_JoinServer_f() { - JoinServer_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - JoinServer_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return JoinServer_MenuKey(key); - } - }); - } - - /* - ============================================================================= - - START SERVER MENU - - ============================================================================= - */ - static menuframework_s s_startserver_menu= new menuframework_s(); - static String mapnames[]; - static int nummaps; - - static menuaction_s s_startserver_start_action= new menuaction_s(); - static menuaction_s s_startserver_dmoptions_action= new menuaction_s(); - static menufield_s s_timelimit_field= new menufield_s(); - static menufield_s s_fraglimit_field= new menufield_s(); - static menufield_s s_maxclients_field= new menufield_s(); - static menufield_s s_hostname_field= new menufield_s(); - static menulist_s s_startmap_list= new menulist_s(); - static menulist_s s_rules_box= new menulist_s(); - - static void DMOptionsFunc(Object self) { - if (s_rules_box.curvalue == 1) - return; - Menu_DMOptions_f(); - } - - static void RulesChangeFunc(Object self) { - // DM - if (s_rules_box.curvalue == 0) { - s_maxclients_field.statusbar= null; - s_startserver_dmoptions_action.statusbar= null; - } - else if (s_rules_box.curvalue == 1) - // coop // PGM - { - s_maxclients_field.statusbar= "4 maximum for cooperative"; - if (atoi(s_maxclients_field.buffer.toString()) > 4) - s_maxclients_field.buffer= new StringBuffer("4"); - s_startserver_dmoptions_action.statusbar= "N/A for cooperative"; - } - // ===== - // PGM - // ROGUE GAMES - else if (FS.Developer_searchpath(2) == 2) { - if (s_rules_box.curvalue == 2) // tag - { - s_maxclients_field.statusbar= null; - s_startserver_dmoptions_action.statusbar= null; - } - /* - else if(s_rules_box.curvalue == 3) // deathball - { - s_maxclients_field.statusbar = null; - s_startserver_dmoptions_action.statusbar = null; - } - */ - } - // PGM - // ===== - } - - static void StartServerActionFunc(Object self) { - //char startmap[1024]; - String startmap; - int timelimit; - int fraglimit; - int maxclients; - String spot; - - //strcpy(startmap, strchr(mapnames[s_startmap_list.curvalue], '\n') + 1); - String x= mapnames[s_startmap_list.curvalue]; - - int pos= x.indexOf('\n'); - if (pos == -1) - startmap= x; - else - startmap= x.substring(pos + 1, x.length()); - - maxclients= atoi(s_maxclients_field.buffer.toString()); - timelimit= atoi(s_timelimit_field.buffer.toString()); - fraglimit= atoi(s_fraglimit_field.buffer.toString()); - - Cvar.SetValue("maxclients", ClampCvar(0, maxclients, maxclients)); - Cvar.SetValue("timelimit", ClampCvar(0, timelimit, timelimit)); - Cvar.SetValue("fraglimit", ClampCvar(0, fraglimit, fraglimit)); - Cvar.Set("hostname", s_hostname_field.buffer.toString()); - // Cvar.SetValue ("deathmatch", !s_rules_box.curvalue ); - // Cvar.SetValue ("coop", s_rules_box.curvalue ); - - // PGM - if ((s_rules_box.curvalue < 2) || (FS.Developer_searchpath(2) != 2)) { - Cvar.SetValue("deathmatch", 1 - (int) (s_rules_box.curvalue)); - Cvar.SetValue("coop", s_rules_box.curvalue); - Cvar.SetValue("gamerules", 0); - } - else { - Cvar.SetValue("deathmatch", 1); - // deathmatch is always true for rogue games, right? - Cvar.SetValue("coop", 0); - // FIXME - this might need to depend on which game we're running - Cvar.SetValue("gamerules", s_rules_box.curvalue); - } - // PGM - - spot= null; - if (s_rules_box.curvalue == 1) // PGM - { - if (Q_stricmp(startmap, "bunk1") == 0) - spot= "start"; - else if (Q_stricmp(startmap, "mintro") == 0) - spot= "start"; - else if (Q_stricmp(startmap, "fact1") == 0) - spot= "start"; - else if (Q_stricmp(startmap, "power1") == 0) - spot= "pstart"; - else if (Q_stricmp(startmap, "biggun") == 0) - spot= "bstart"; - else if (Q_stricmp(startmap, "hangar1") == 0) - spot= "unitstart"; - else if (Q_stricmp(startmap, "city1") == 0) - spot= "unitstart"; - else if (Q_stricmp(startmap, "boss1") == 0) - spot= "bosstart"; - } - - if (spot != null) { - if (Globals.server_state != 0) - Cbuf.AddText("disconnect\n"); - Cbuf.AddText("gamemap \"*" + startmap + "$" + spot + "\"\n"); - } - else { - Cbuf.AddText("map " + startmap + "\n"); - } - - ForceMenuOff(); - } - - static String dm_coop_names[]= { "deathmatch", "cooperative", null }; - static String dm_coop_names_rogue[]= { "deathmatch", "cooperative", "tag", - // "deathball", - null }; - - static void StartServer_MenuInit() { - - // ======= - // PGM - // ======= - - byte[] buffer= null; - String mapsname; - String s; - int i; - RandomAccessFile fp; - - /* - ** load the list of map names - */ - mapsname= FS.Gamedir() + "/maps.lst"; - - if ((fp= fopen(mapsname, "r")) == null) { - buffer= FS.LoadFile("maps.lst"); - if (buffer == null) - //if ((length = FS_LoadFile("maps.lst", (Object *) & buffer)) == -1) - Com.Error(ERR_DROP, "couldn't find maps.lst\n"); - } - else { - try { - int len= (int) fp.length(); - buffer= new byte[len]; - fp.readFully(buffer); - } - catch (Exception e) { - Com.Error(ERR_DROP, "couldn't load maps.lst\n"); - } - } - - s= new String(buffer); - String lines[]= Lib.linesplit(s); - - nummaps= lines.length; - - if (nummaps == 0) - Com.Error(ERR_DROP, "no maps in maps.lst\n"); - - mapnames= new String[nummaps + 1]; - - for (i= 0; i < nummaps; i++) { - String shortname, longname, scratch; - - Com.ParseHelp ph= new Com.ParseHelp(lines[i]); - - shortname= Com.Parse(ph).toUpperCase(); - longname= Com.Parse(ph); - scratch= longname + "\n" + shortname; - mapnames[i]= scratch; - } - mapnames[nummaps]= null; - - if (fp != null) { - fclose(fp); - fp= null; - - } - else { - FS.FreeFile(buffer); - } - - /* - ** initialize the menu stuff - */ - s_startserver_menu.x= (int) (viddef.width * 0.50); - s_startserver_menu.nitems= 0; - - s_startmap_list.type= MTYPE_SPINCONTROL; - s_startmap_list.x= 0; - s_startmap_list.y= 0; - s_startmap_list.name= "initial map"; - s_startmap_list.itemnames= mapnames; - - s_rules_box.type= MTYPE_SPINCONTROL; - s_rules_box.x= 0; - s_rules_box.y= 20; - s_rules_box.name= "rules"; - - // PGM - rogue games only available with rogue DLL. - if (FS.Developer_searchpath(2) == 2) - s_rules_box.itemnames= dm_coop_names_rogue; - else - s_rules_box.itemnames= dm_coop_names; - // PGM - - if (Cvar.VariableValue("coop") != 0) - s_rules_box.curvalue= 1; - else - s_rules_box.curvalue= 0; - s_rules_box.callback= new mcallback() { - public void execute(Object o) { - RulesChangeFunc(o); - } - }; - - s_timelimit_field.type= MTYPE_FIELD; - s_timelimit_field.name= "time limit"; - s_timelimit_field.flags= QMF_NUMBERSONLY; - s_timelimit_field.x= 0; - s_timelimit_field.y= 36; - s_timelimit_field.statusbar= "0 = no limit"; - s_timelimit_field.length= 3; - s_timelimit_field.visible_length= 3; - s_timelimit_field.buffer= new StringBuffer(Cvar.VariableString("timelimit")); - - s_fraglimit_field.type= MTYPE_FIELD; - s_fraglimit_field.name= "frag limit"; - s_fraglimit_field.flags= QMF_NUMBERSONLY; - s_fraglimit_field.x= 0; - s_fraglimit_field.y= 54; - s_fraglimit_field.statusbar= "0 = no limit"; - s_fraglimit_field.length= 3; - s_fraglimit_field.visible_length= 3; - s_fraglimit_field.buffer= new StringBuffer(Cvar.VariableString("fraglimit")); - - /* - ** maxclients determines the maximum number of players that can join - ** the game. If maxclients is only "1" then we should default the menu - ** option to 8 players, otherwise use whatever its current value is. - ** Clamping will be done when the server is actually started. - */ - s_maxclients_field.type= MTYPE_FIELD; - s_maxclients_field.name= "max players"; - s_maxclients_field.flags= QMF_NUMBERSONLY; - s_maxclients_field.x= 0; - s_maxclients_field.y= 72; - s_maxclients_field.statusbar= null; - s_maxclients_field.length= 3; - s_maxclients_field.visible_length= 3; - if (Cvar.VariableValue("maxclients") == 1) - s_maxclients_field.buffer= new StringBuffer("8"); - else - s_maxclients_field.buffer= new StringBuffer(Cvar.VariableString("maxclients")); - - s_hostname_field.type= MTYPE_FIELD; - s_hostname_field.name= "hostname"; - s_hostname_field.flags= 0; - s_hostname_field.x= 0; - s_hostname_field.y= 90; - s_hostname_field.statusbar= null; - s_hostname_field.length= 12; - s_hostname_field.visible_length= 12; - s_hostname_field.buffer= new StringBuffer(Cvar.VariableString("hostname")); - s_hostname_field.cursor= s_hostname_field.buffer.length(); - - s_startserver_dmoptions_action.type= MTYPE_ACTION; - s_startserver_dmoptions_action.name= " deathmatch flags"; - s_startserver_dmoptions_action.flags= QMF_LEFT_JUSTIFY; - s_startserver_dmoptions_action.x= 24; - s_startserver_dmoptions_action.y= 108; - s_startserver_dmoptions_action.statusbar= null; - s_startserver_dmoptions_action.callback= new mcallback() { - public void execute(Object o) { - DMOptionsFunc(o); - } - }; - - s_startserver_start_action.type= MTYPE_ACTION; - s_startserver_start_action.name= " begin"; - s_startserver_start_action.flags= QMF_LEFT_JUSTIFY; - s_startserver_start_action.x= 24; - s_startserver_start_action.y= 128; - s_startserver_start_action.callback= new mcallback() { - public void execute(Object o) { - StartServerActionFunc(o); - } - }; - - Menu_AddItem(s_startserver_menu, s_startmap_list); - Menu_AddItem(s_startserver_menu, s_rules_box); - Menu_AddItem(s_startserver_menu, s_timelimit_field); - Menu_AddItem(s_startserver_menu, s_fraglimit_field); - Menu_AddItem(s_startserver_menu, s_maxclients_field); - Menu_AddItem(s_startserver_menu, s_hostname_field); - Menu_AddItem(s_startserver_menu, s_startserver_dmoptions_action); - Menu_AddItem(s_startserver_menu, s_startserver_start_action); - - Menu_Center(s_startserver_menu); - - // call this now to set proper inital state - RulesChangeFunc(null); - } - - static void StartServer_MenuDraw() { - Menu_Draw(s_startserver_menu); - } - - static String StartServer_MenuKey(int key) { - if (key == K_ESCAPE) { - if (mapnames != null) { - int i; - - for (i= 0; i < nummaps; i++) - mapnames[i]= null; - - } - mapnames= null; - nummaps= 0; - } - - return Default_MenuKey(s_startserver_menu, key); - } - - static xcommand_t Menu_StartServer= new xcommand_t() { - public void execute() { - Menu_StartServer_f(); - } - }; - static void Menu_StartServer_f() { - StartServer_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - StartServer_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return StartServer_MenuKey(key); - } - }); - } - - /* - ============================================================================= - - DMOPTIONS BOOK MENU - - ============================================================================= - */ - static String dmoptions_statusbar; //[128]; - - static menuframework_s s_dmoptions_menu= new menuframework_s(); - - static menulist_s s_friendlyfire_box= new menulist_s(); - static menulist_s s_falls_box= new menulist_s(); - static menulist_s s_weapons_stay_box= new menulist_s(); - static menulist_s s_instant_powerups_box= new menulist_s(); - static menulist_s s_powerups_box= new menulist_s(); - static menulist_s s_health_box= new menulist_s(); - static menulist_s s_spawn_farthest_box= new menulist_s(); - static menulist_s s_teamplay_box= new menulist_s(); - static menulist_s s_samelevel_box= new menulist_s(); - static menulist_s s_force_respawn_box= new menulist_s(); - static menulist_s s_armor_box= new menulist_s(); - static menulist_s s_allow_exit_box= new menulist_s(); - static menulist_s s_infinite_ammo_box= new menulist_s(); - static menulist_s s_fixed_fov_box= new menulist_s(); - static menulist_s s_quad_drop_box= new menulist_s(); - - // ROGUE - static menulist_s s_no_mines_box= new menulist_s(); - static menulist_s s_no_nukes_box= new menulist_s(); - static menulist_s s_stack_double_box= new menulist_s(); - static menulist_s s_no_spheres_box= new menulist_s(); - // ROGUE - - static void setvalue(int flags) { - Cvar.SetValue("dmflags", flags); - dmoptions_statusbar= "dmflags = " + flags; - } - - static void DMFlagCallback(Object self) { - menulist_s f= (menulist_s) self; - int flags; - int bit= 0; - - flags= (int) Cvar.VariableValue("dmflags"); - - if (f == s_friendlyfire_box) { - if (f.curvalue != 0) - flags &= ~DF_NO_FRIENDLY_FIRE; - else - flags |= DF_NO_FRIENDLY_FIRE; - setvalue(flags); - return; - } - else if (f == s_falls_box) { - if (f.curvalue != 0) - flags &= ~DF_NO_FALLING; - else - flags |= DF_NO_FALLING; - setvalue(flags); - return; - } - else if (f == s_weapons_stay_box) { - bit= DF_WEAPONS_STAY; - } - else if (f == s_instant_powerups_box) { - bit= DF_INSTANT_ITEMS; - } - else if (f == s_allow_exit_box) { - bit= DF_ALLOW_EXIT; - } - else if (f == s_powerups_box) { - if (f.curvalue != 0) - flags &= ~DF_NO_ITEMS; - else - flags |= DF_NO_ITEMS; - setvalue(flags); - return; - } - else if (f == s_health_box) { - if (f.curvalue != 0) - flags &= ~DF_NO_HEALTH; - else - flags |= DF_NO_HEALTH; - setvalue(flags); - return; - } - else if (f == s_spawn_farthest_box) { - bit= DF_SPAWN_FARTHEST; - } - else if (f == s_teamplay_box) { - if (f.curvalue == 1) { - flags |= DF_SKINTEAMS; - flags &= ~DF_MODELTEAMS; - } - else if (f.curvalue == 2) { - flags |= DF_MODELTEAMS; - flags &= ~DF_SKINTEAMS; - } - else { - flags &= ~(DF_MODELTEAMS | DF_SKINTEAMS); - } - - setvalue(flags); - return; - } - else if (f == s_samelevel_box) { - bit= DF_SAME_LEVEL; - } - else if (f == s_force_respawn_box) { - bit= DF_FORCE_RESPAWN; - } - else if (f == s_armor_box) { - if (f.curvalue != 0) - flags &= ~DF_NO_ARMOR; - else - flags |= DF_NO_ARMOR; - setvalue(flags); - return; - } - else if (f == s_infinite_ammo_box) { - bit= DF_INFINITE_AMMO; - } - else if (f == s_fixed_fov_box) { - bit= DF_FIXED_FOV; - } - else if (f == s_quad_drop_box) { - bit= DF_QUAD_DROP; - } - - // ======= - // ROGUE - else if (FS.Developer_searchpath(2) == 2) { - if (f == s_no_mines_box) { - bit= DF_NO_MINES; - } - else if (f == s_no_nukes_box) { - bit= DF_NO_NUKES; - } - else if (f == s_stack_double_box) { - bit= DF_NO_STACK_DOUBLE; - } - else if (f == s_no_spheres_box) { - bit= DF_NO_SPHERES; - } - } - // ROGUE - // ======= - - if (f != null) { - if (f.curvalue == 0) - flags &= ~bit; - else - flags |= bit; - } - - Cvar.SetValue("dmflags", flags); - - dmoptions_statusbar= "dmflags = " + flags; - - } - - //static String yes_no_names[] = { "no", "yes", 0 }; - static String teamplay_names[]= { "disabled", "by skin", "by model", null }; - - static void DMOptions_MenuInit() { - - int dmflags= (int) Cvar.VariableValue("dmflags"); - int y= 0; - - s_dmoptions_menu.x= (int) (viddef.width * 0.50); - s_dmoptions_menu.nitems= 0; - - s_falls_box.type= MTYPE_SPINCONTROL; - s_falls_box.x= 0; - s_falls_box.y= y; - s_falls_box.name= "falling damage"; - s_falls_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_falls_box.itemnames= yes_no_names; - s_falls_box.curvalue= (dmflags & DF_NO_FALLING) == 0 ? 1 : 0; - - s_weapons_stay_box.type= MTYPE_SPINCONTROL; - s_weapons_stay_box.x= 0; - s_weapons_stay_box.y= y += 10; - s_weapons_stay_box.name= "weapons stay"; - s_weapons_stay_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_weapons_stay_box.itemnames= yes_no_names; - s_weapons_stay_box.curvalue= (dmflags & DF_WEAPONS_STAY) != 0 ? 1 : 0; - - s_instant_powerups_box.type= MTYPE_SPINCONTROL; - s_instant_powerups_box.x= 0; - s_instant_powerups_box.y= y += 10; - s_instant_powerups_box.name= "instant powerups"; - s_instant_powerups_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_instant_powerups_box.itemnames= yes_no_names; - s_instant_powerups_box.curvalue= (dmflags & DF_INSTANT_ITEMS) != 0 ? 1 : 0; - - s_powerups_box.type= MTYPE_SPINCONTROL; - s_powerups_box.x= 0; - s_powerups_box.y= y += 10; - s_powerups_box.name= "allow powerups"; - s_powerups_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_powerups_box.itemnames= yes_no_names; - s_powerups_box.curvalue= (dmflags & DF_NO_ITEMS) == 0 ? 1 : 0; - - s_health_box.type= MTYPE_SPINCONTROL; - s_health_box.x= 0; - s_health_box.y= y += 10; - s_health_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_health_box.name= "allow health"; - s_health_box.itemnames= yes_no_names; - s_health_box.curvalue= (dmflags & DF_NO_HEALTH) == 0 ? 1 : 0; - - s_armor_box.type= MTYPE_SPINCONTROL; - s_armor_box.x= 0; - s_armor_box.y= y += 10; - s_armor_box.name= "allow armor"; - s_armor_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_armor_box.itemnames= yes_no_names; - s_armor_box.curvalue= (dmflags & DF_NO_ARMOR) == 0 ? 1 : 0; - - s_spawn_farthest_box.type= MTYPE_SPINCONTROL; - s_spawn_farthest_box.x= 0; - s_spawn_farthest_box.y= y += 10; - s_spawn_farthest_box.name= "spawn farthest"; - s_spawn_farthest_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_spawn_farthest_box.itemnames= yes_no_names; - s_spawn_farthest_box.curvalue= (dmflags & DF_SPAWN_FARTHEST) != 0 ? 1 : 0; - - s_samelevel_box.type= MTYPE_SPINCONTROL; - s_samelevel_box.x= 0; - s_samelevel_box.y= y += 10; - s_samelevel_box.name= "same map"; - s_samelevel_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_samelevel_box.itemnames= yes_no_names; - s_samelevel_box.curvalue= (dmflags & DF_SAME_LEVEL) != 0 ? 1 : 0; - - s_force_respawn_box.type= MTYPE_SPINCONTROL; - s_force_respawn_box.x= 0; - s_force_respawn_box.y= y += 10; - s_force_respawn_box.name= "force respawn"; - s_force_respawn_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_force_respawn_box.itemnames= yes_no_names; - s_force_respawn_box.curvalue= (dmflags & DF_FORCE_RESPAWN) != 0 ? 1 : 0; - - s_teamplay_box.type= MTYPE_SPINCONTROL; - s_teamplay_box.x= 0; - s_teamplay_box.y= y += 10; - s_teamplay_box.name= "teamplay"; - s_teamplay_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_teamplay_box.itemnames= teamplay_names; - - s_allow_exit_box.type= MTYPE_SPINCONTROL; - s_allow_exit_box.x= 0; - s_allow_exit_box.y= y += 10; - s_allow_exit_box.name= "allow exit"; - s_allow_exit_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_allow_exit_box.itemnames= yes_no_names; - s_allow_exit_box.curvalue= (dmflags & DF_ALLOW_EXIT) != 0 ? 1 : 0; - - s_infinite_ammo_box.type= MTYPE_SPINCONTROL; - s_infinite_ammo_box.x= 0; - s_infinite_ammo_box.y= y += 10; - s_infinite_ammo_box.name= "infinite ammo"; - s_infinite_ammo_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_infinite_ammo_box.itemnames= yes_no_names; - s_infinite_ammo_box.curvalue= (dmflags & DF_INFINITE_AMMO) != 0 ? 1 : 0; - - s_fixed_fov_box.type= MTYPE_SPINCONTROL; - s_fixed_fov_box.x= 0; - s_fixed_fov_box.y= y += 10; - s_fixed_fov_box.name= "fixed FOV"; - s_fixed_fov_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_fixed_fov_box.itemnames= yes_no_names; - s_fixed_fov_box.curvalue= (dmflags & DF_FIXED_FOV) != 0 ? 1 : 0; - - s_quad_drop_box.type= MTYPE_SPINCONTROL; - s_quad_drop_box.x= 0; - s_quad_drop_box.y= y += 10; - s_quad_drop_box.name= "quad drop"; - s_quad_drop_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_quad_drop_box.itemnames= yes_no_names; - s_quad_drop_box.curvalue= (dmflags & DF_QUAD_DROP) != 0 ? 1 : 0; - - s_friendlyfire_box.type= MTYPE_SPINCONTROL; - s_friendlyfire_box.x= 0; - s_friendlyfire_box.y= y += 10; - s_friendlyfire_box.name= "friendly fire"; - s_friendlyfire_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_friendlyfire_box.itemnames= yes_no_names; - s_friendlyfire_box.curvalue= (dmflags & DF_NO_FRIENDLY_FIRE) == 0 ? 1 : 0; - - // ============ - // ROGUE - if (FS.Developer_searchpath(2) == 2) { - s_no_mines_box.type= MTYPE_SPINCONTROL; - s_no_mines_box.x= 0; - s_no_mines_box.y= y += 10; - s_no_mines_box.name= "remove mines"; - s_no_mines_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_no_mines_box.itemnames= yes_no_names; - s_no_mines_box.curvalue= (dmflags & DF_NO_MINES) != 0 ? 1 : 0; - - s_no_nukes_box.type= MTYPE_SPINCONTROL; - s_no_nukes_box.x= 0; - s_no_nukes_box.y= y += 10; - s_no_nukes_box.name= "remove nukes"; - s_no_nukes_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_no_nukes_box.itemnames= yes_no_names; - s_no_nukes_box.curvalue= (dmflags & DF_NO_NUKES) != 0 ? 1 : 0; - - s_stack_double_box.type= MTYPE_SPINCONTROL; - s_stack_double_box.x= 0; - s_stack_double_box.y= y += 10; - s_stack_double_box.name= "2x/4x stacking off"; - s_stack_double_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_stack_double_box.itemnames= yes_no_names; - s_stack_double_box.curvalue= (dmflags & DF_NO_STACK_DOUBLE); - - s_no_spheres_box.type= MTYPE_SPINCONTROL; - s_no_spheres_box.x= 0; - s_no_spheres_box.y= y += 10; - s_no_spheres_box.name= "remove spheres"; - s_no_spheres_box.callback= new mcallback() { - public void execute(Object o) { - DMFlagCallback(o); - } - }; - s_no_spheres_box.itemnames= yes_no_names; - s_no_spheres_box.curvalue= (dmflags & DF_NO_SPHERES) != 0 ? 1 : 0; - - } - // ROGUE - // ============ - - Menu_AddItem(s_dmoptions_menu, s_falls_box); - Menu_AddItem(s_dmoptions_menu, s_weapons_stay_box); - Menu_AddItem(s_dmoptions_menu, s_instant_powerups_box); - Menu_AddItem(s_dmoptions_menu, s_powerups_box); - Menu_AddItem(s_dmoptions_menu, s_health_box); - Menu_AddItem(s_dmoptions_menu, s_armor_box); - Menu_AddItem(s_dmoptions_menu, s_spawn_farthest_box); - Menu_AddItem(s_dmoptions_menu, s_samelevel_box); - Menu_AddItem(s_dmoptions_menu, s_force_respawn_box); - Menu_AddItem(s_dmoptions_menu, s_teamplay_box); - Menu_AddItem(s_dmoptions_menu, s_allow_exit_box); - Menu_AddItem(s_dmoptions_menu, s_infinite_ammo_box); - Menu_AddItem(s_dmoptions_menu, s_fixed_fov_box); - Menu_AddItem(s_dmoptions_menu, s_quad_drop_box); - Menu_AddItem(s_dmoptions_menu, s_friendlyfire_box); - - // ======= - // ROGUE - if (FS.Developer_searchpath(2) == 2) { - Menu_AddItem(s_dmoptions_menu, s_no_mines_box); - Menu_AddItem(s_dmoptions_menu, s_no_nukes_box); - Menu_AddItem(s_dmoptions_menu, s_stack_double_box); - Menu_AddItem(s_dmoptions_menu, s_no_spheres_box); - } - // ROGUE - // ======= - - Menu_Center(s_dmoptions_menu); - - // set the original dmflags statusbar - DMFlagCallback(null); - Menu_SetStatusBar(s_dmoptions_menu, dmoptions_statusbar); - } - - static void DMOptions_MenuDraw() { - Menu_Draw(s_dmoptions_menu); - } - - static String DMOptions_MenuKey(int key) { - return Default_MenuKey(s_dmoptions_menu, key); - } - - static xcommand_t Menu_DMOptions= new xcommand_t() { - public void execute() { - Menu_DMOptions_f(); - } - }; - static void Menu_DMOptions_f() { - DMOptions_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - DMOptions_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return DMOptions_MenuKey(key); - } - }); - } - - /* - ============================================================================= - - DOWNLOADOPTIONS BOOK MENU - - ============================================================================= - */ - static menuframework_s s_downloadoptions_menu= new menuframework_s(); - - static menuseparator_s s_download_title= new menuseparator_s(); - static menulist_s s_allow_download_box= new menulist_s(); - static menulist_s s_allow_download_maps_box= new menulist_s(); - static menulist_s s_allow_download_models_box= new menulist_s(); - static menulist_s s_allow_download_players_box= new menulist_s(); - static menulist_s s_allow_download_sounds_box= new menulist_s(); - - static void DownloadCallback(Object self) { - menulist_s f= (menulist_s) self; - - if (f == s_allow_download_box) { - Cvar.SetValue("allow_download", f.curvalue); - } - - else if (f == s_allow_download_maps_box) { - Cvar.SetValue("allow_download_maps", f.curvalue); - } - - else if (f == s_allow_download_models_box) { - Cvar.SetValue("allow_download_models", f.curvalue); - } - - else if (f == s_allow_download_players_box) { - Cvar.SetValue("allow_download_players", f.curvalue); - } - - else if (f == s_allow_download_sounds_box) { - Cvar.SetValue("allow_download_sounds", f.curvalue); - } - } - - static String yes_no_names[]= { "no", "yes", null }; - static void DownloadOptions_MenuInit() { - - int y= 0; - - s_downloadoptions_menu.x= (int) (viddef.width * 0.50); - s_downloadoptions_menu.nitems= 0; - - s_download_title.type= MTYPE_SEPARATOR; - s_download_title.name= "Download Options"; - s_download_title.x= 48; - s_download_title.y= y; - - s_allow_download_box.type= MTYPE_SPINCONTROL; - s_allow_download_box.x= 0; - s_allow_download_box.y= y += 20; - s_allow_download_box.name= "allow downloading"; - s_allow_download_box.callback= new mcallback() { - public void execute(Object o) { - DownloadCallback(o); - } - }; - s_allow_download_box.itemnames= yes_no_names; - s_allow_download_box.curvalue= (Cvar.VariableValue("allow_download") != 0) ? 1 : 0; - - s_allow_download_maps_box.type= MTYPE_SPINCONTROL; - s_allow_download_maps_box.x= 0; - s_allow_download_maps_box.y= y += 20; - s_allow_download_maps_box.name= "maps"; - s_allow_download_maps_box.callback= new mcallback() { - public void execute(Object o) { - DownloadCallback(o); - } - }; - s_allow_download_maps_box.itemnames= yes_no_names; - s_allow_download_maps_box.curvalue= (Cvar.VariableValue("allow_download_maps") != 0) ? 1 : 0; - - s_allow_download_players_box.type= MTYPE_SPINCONTROL; - s_allow_download_players_box.x= 0; - s_allow_download_players_box.y= y += 10; - s_allow_download_players_box.name= "player models/skins"; - s_allow_download_players_box.callback= new mcallback() { - public void execute(Object o) { - DownloadCallback(o); - } - }; - s_allow_download_players_box.itemnames= yes_no_names; - s_allow_download_players_box.curvalue= (Cvar.VariableValue("allow_download_players") != 0) ? 1 : 0; - - s_allow_download_models_box.type= MTYPE_SPINCONTROL; - s_allow_download_models_box.x= 0; - s_allow_download_models_box.y= y += 10; - s_allow_download_models_box.name= "models"; - s_allow_download_models_box.callback= new mcallback() { - public void execute(Object o) { - DownloadCallback(o); - } - }; - s_allow_download_models_box.itemnames= yes_no_names; - s_allow_download_models_box.curvalue= (Cvar.VariableValue("allow_download_models") != 0) ? 1 : 0; - - s_allow_download_sounds_box.type= MTYPE_SPINCONTROL; - s_allow_download_sounds_box.x= 0; - s_allow_download_sounds_box.y= y += 10; - s_allow_download_sounds_box.name= "sounds"; - s_allow_download_sounds_box.callback= new mcallback() { - public void execute(Object o) { - DownloadCallback(o); - } - }; - s_allow_download_sounds_box.itemnames= yes_no_names; - s_allow_download_sounds_box.curvalue= (Cvar.VariableValue("allow_download_sounds") != 0) ? 1 : 0; - - Menu_AddItem(s_downloadoptions_menu, s_download_title); - Menu_AddItem(s_downloadoptions_menu, s_allow_download_box); - Menu_AddItem(s_downloadoptions_menu, s_allow_download_maps_box); - Menu_AddItem(s_downloadoptions_menu, s_allow_download_players_box); - Menu_AddItem(s_downloadoptions_menu, s_allow_download_models_box); - Menu_AddItem(s_downloadoptions_menu, s_allow_download_sounds_box); - - Menu_Center(s_downloadoptions_menu); - - // skip over title - if (s_downloadoptions_menu.cursor == 0) - s_downloadoptions_menu.cursor= 1; - } - - static void DownloadOptions_MenuDraw() { - Menu_Draw(s_downloadoptions_menu); - } - - static String DownloadOptions_MenuKey(int key) { - return Default_MenuKey(s_downloadoptions_menu, key); - } - - static xcommand_t Menu_DownloadOptions= new xcommand_t() { - public void execute() { - Menu_DownloadOptions_f(); - } - }; - static void Menu_DownloadOptions_f() { - DownloadOptions_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - DownloadOptions_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return DownloadOptions_MenuKey(key); - } - }); - } - /* - ============================================================================= - - ADDRESS BOOK MENU - - ============================================================================= - */ - - static menuframework_s s_addressbook_menu= new menuframework_s(); - static menufield_s s_addressbook_fields[]= new menufield_s[NUM_ADDRESSBOOK_ENTRIES]; - static { - for (int n= 0; n < NUM_ADDRESSBOOK_ENTRIES; n++) - s_addressbook_fields[n]= new menufield_s(); - } - - static void AddressBook_MenuInit() { - int i; - - s_addressbook_menu.x= viddef.width / 2 - 142; - s_addressbook_menu.y= viddef.height / 2 - 58; - s_addressbook_menu.nitems= 0; - - for (i= 0; i < NUM_ADDRESSBOOK_ENTRIES; i++) { - cvar_t adr; - //char buffer[20]; - String buffer; - - //Com_sprintf(buffer, sizeof(buffer), "adr%d", i); - buffer= "adr" + i; - - adr= Cvar.Get(buffer, "", CVAR_ARCHIVE); - - s_addressbook_fields[i].type= MTYPE_FIELD; - s_addressbook_fields[i].name= null; - s_addressbook_fields[i].callback= null; - s_addressbook_fields[i].x= 0; - s_addressbook_fields[i].y= i * 18 + 0; - s_addressbook_fields[i].localdata[0]= i; - s_addressbook_fields[i].cursor= 0; - s_addressbook_fields[i].length= 60; - s_addressbook_fields[i].visible_length= 30; - - s_addressbook_fields[i].buffer= new StringBuffer(adr.string); - - Menu_AddItem(s_addressbook_menu, s_addressbook_fields[i]); - } - } - - static keyfunc_t AddressBook_MenuKey= new keyfunc_t() { - public String execute(int key) { - return AddressBook_MenuKey_f(key); - } - }; - - static String AddressBook_MenuKey_f(int key) { - if (key == K_ESCAPE) { - int index; - //char buffer[20]; - String buffer; - - for (index= 0; index < NUM_ADDRESSBOOK_ENTRIES; index++) { - buffer= "adr" + index; - //Com_sprintf(buffer, sizeof(buffer), "adr%d", index); - Cvar.Set(buffer, s_addressbook_fields[index].buffer.toString()); - } - } - return Default_MenuKey(s_addressbook_menu, key); - } - - static xcommand_t AddressBook_MenuDraw= new xcommand_t() { - public void execute() { - AddressBook_MenuDraw_f(); - } - }; - static void AddressBook_MenuDraw_f() { - Banner("m_banner_addressbook"); - Menu_Draw(s_addressbook_menu); - } - - static xcommand_t Menu_AddressBook= new xcommand_t() { - public void execute() { - Menu_AddressBook_f(); - } - }; - static void Menu_AddressBook_f() { - AddressBook_MenuInit(); - PushMenu(new xcommand_t() { - public void execute() { - AddressBook_MenuDraw_f(); - } - }, new keyfunc_t() { - public String execute(int key) { - return AddressBook_MenuKey_f(key); - } - }); - } - /* - ============================================================================= - - PLAYER CONFIG MENU - - ============================================================================= - */ - static menuframework_s s_player_config_menu= new menuframework_s(); - static menufield_s s_player_name_field= new menufield_s(); - static menulist_s s_player_model_box= new menulist_s(); - static menulist_s s_player_skin_box= new menulist_s(); - static menulist_s s_player_handedness_box= new menulist_s(); - static menulist_s s_player_rate_box= new menulist_s(); - static menuseparator_s s_player_skin_title= new menuseparator_s(); - static menuseparator_s s_player_model_title= new menuseparator_s(); - static menuseparator_s s_player_hand_title= new menuseparator_s(); - static menuseparator_s s_player_rate_title= new menuseparator_s(); - static menuaction_s s_player_download_action= new menuaction_s(); - - static class playermodelinfo_s { - int nskins; - String skindisplaynames[]; - //char displayname[MAX_DISPLAYNAME]; - String displayname; - //char directory[MAX_QPATH]; - String directory; - }; - - static playermodelinfo_s s_pmi[]= new playermodelinfo_s[MAX_PLAYERMODELS]; - static String s_pmnames[]= new String[MAX_PLAYERMODELS]; - static int s_numplayermodels; - - static int rate_tbl[]= { 2500, 3200, 5000, 10000, 25000, 0 }; - static String rate_names[]= { "28.8 Modem", "33.6 Modem", "Single ISDN", "Dual ISDN/Cable", "T1/LAN", "User defined", null }; - - static void DownloadOptionsFunc(Object self) { - Menu_DownloadOptions_f(); - } - - static void HandednessCallback(Object unused) { - Cvar.SetValue("hand", s_player_handedness_box.curvalue); - } - - static void RateCallback(Object unused) { - if (s_player_rate_box.curvalue != rate_tbl.length - 1) //sizeof(rate_tbl) / sizeof(* rate_tbl) - 1) - Cvar.SetValue("rate", rate_tbl[s_player_rate_box.curvalue]); - } - - static void ModelCallback(Object unused) { - s_player_skin_box.itemnames= s_pmi[s_player_model_box.curvalue].skindisplaynames; - s_player_skin_box.curvalue= 0; - } - - static boolean IconOfSkinExists(String skin, String pcxfiles[], int npcxfiles) { - int i; - //char scratch[1024]; - String scratch; - - //strcpy(scratch, skin); - scratch= skin; - int pos= scratch.lastIndexOf('.'); - if (pos != -1) - scratch= scratch.substring(0, pos) + "_i.pcx"; - - else - scratch += "_i.pcx"; - - for (i= 0; i < npcxfiles; i++) { - if (strcmp(pcxfiles[i], scratch) == 0) - return true; - } - - return false; - } - - static boolean PlayerConfig_ScanDirectories() { - //char findname[1024]; - String findname; - //char scratch[1024]; - String scratch; - - int ndirs= 0, npms= 0; - int a, b, c; - String dirnames[]; - - String path= null; - - int i; - - //extern String * FS_ListFiles(String , int *, unsigned, unsigned); - - s_numplayermodels= 0; - - /* - ** get a list of directories - */ - do { - path= FS.NextPath(path); - findname= path + "/players/*.*"; - - if ((dirnames= FS.ListFiles(findname, 0, SFF_SUBDIR)) != null) { - ndirs= dirnames.length; - break; - } - } - while (path != null); - - if (dirnames == null) - return false; - - /* - ** go through the subdirectories - */ - npms= ndirs; - if (npms > MAX_PLAYERMODELS) - npms= MAX_PLAYERMODELS; - - for (i= 0; i < npms; i++) { - int k, s; - //String a, b, c; - String pcxnames[]; - String skinnames[]; - int npcxfiles; - int nskins= 0; - - if (dirnames[i] == null) - continue; - - // verify the existence of tris.md2 - scratch= dirnames[i]; - scratch += "/tris.md2"; - if (Sys.FindFirst(scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM) == null) { - //free(dirnames[i]); - dirnames[i]= null; - Sys.FindClose(); - continue; - } - Sys.FindClose(); - - // verify the existence of at least one pcx skin - scratch= dirnames[i] + "/*.pcx"; - pcxnames= FS.ListFiles(scratch, 0, 0); - npcxfiles= pcxnames.length; - - if (pcxnames == null) { - - dirnames[i]= null; - continue; - } - - // count valid skins, which consist of a skin with a matching "_i" icon - for (k= 0; k < npcxfiles - 1; k++) { - if (!pcxnames[k].endsWith("_i.pcx")) { - //if (!strstr(pcxnames[k], "_i.pcx")) { - if (IconOfSkinExists(pcxnames[k], pcxnames, npcxfiles - 1)) { - nskins++; - } - } - } - if (nskins == 0) - continue; - - skinnames= new String[nskins + 1]; //malloc(sizeof(String) * (nskins + 1)); - //memset(skinnames, 0, sizeof(String) * (nskins + 1)); - - // copy the valid skins - for (s= 0, k= 0; k < npcxfiles - 1; k++) { - - if (pcxnames[k].indexOf("_i.pcx") < 0) { - if (IconOfSkinExists(pcxnames[k], pcxnames, npcxfiles - 1)) { - a= pcxnames[k].lastIndexOf('/'); - b= pcxnames[k].lastIndexOf('\\'); - - if (a > b) - c= a; - else - c= b; - - scratch= pcxnames[k].substring(c + 1, pcxnames[k].length()); - int pos= scratch.lastIndexOf('.'); - if (pos != -1) - scratch= scratch.substring(0, pos); - - skinnames[s]= scratch; - s++; - } - } - } - - // at this point we have a valid player model - if (s_pmi[s_numplayermodels] == null) - s_pmi[s_numplayermodels]= new playermodelinfo_s(); - - s_pmi[s_numplayermodels].nskins= nskins; - s_pmi[s_numplayermodels].skindisplaynames= skinnames; - - // make short name for the model - a= dirnames[i].lastIndexOf('/'); - b= dirnames[i].lastIndexOf('\\'); - - if (a > b) - c= a; - else - c= b; - - s_pmi[s_numplayermodels].displayname= dirnames[i].substring(c + 1); - s_pmi[s_numplayermodels].directory= dirnames[i].substring(c + 1); - - s_numplayermodels++; - } - - return true; - - } - - static int pmicmpfnc(Object _a, Object _b) { - playermodelinfo_s a= (playermodelinfo_s) _a; - playermodelinfo_s b= (playermodelinfo_s) _b; - - /* - ** sort by male, female, then alphabetical - */ - if (strcmp(a.directory, "male") == 0) - return -1; - else if (strcmp(b.directory, "male") == 0) - return 1; - - if (strcmp(a.directory, "female") == 0) - return -1; - else if (strcmp(b.directory, "female") == 0) - return 1; - - return strcmp(a.directory, b.directory); - } - - static String handedness[]= { "right", "left", "center", null }; - - static boolean PlayerConfig_MenuInit() { - /* - extern cvar_t * name; - extern cvar_t * team; - extern cvar_t * skin; - */ - //har currentdirectory[1024]; - String currentdirectory; - //char currentskin[1024]; - String currentskin; - - int i= 0; - - int currentdirectoryindex= 0; - int currentskinindex= 0; - - cvar_t hand= Cvar.Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE); - - PlayerConfig_ScanDirectories(); - - if (s_numplayermodels == 0) - return false; - - if (hand.value < 0 || hand.value > 2) - Cvar.SetValue("hand", 0); - - currentdirectory= skin.string; - - if (currentdirectory.lastIndexOf('/') != -1) { - currentskin= rightFrom(currentdirectory, '/'); - currentdirectory= leftFrom(currentdirectory, '/'); - } - else if (currentdirectory.lastIndexOf('\\') != -1) { - currentskin= rightFrom(currentdirectory, '\\'); - currentdirectory= leftFrom(currentdirectory, '\\'); - } - else { - currentdirectory= "male"; - currentskin= "grunt"; - } - - //qsort(s_pmi, s_numplayermodels, sizeof(s_pmi[0]), pmicmpfnc); - Arrays.sort(s_pmi, 0, s_numplayermodels, new Comparator() { - public int compare(Object o1, Object o2) { - return pmicmpfnc(o1, o2); - } - }); - - //memset(s_pmnames, 0, sizeof(s_pmnames)); - s_pmnames= new String[MAX_PLAYERMODELS]; - - for (i= 0; i < s_numplayermodels; i++) { - s_pmnames[i]= s_pmi[i].displayname; - if (Q_stricmp(s_pmi[i].directory, currentdirectory) == 0) { - int j; - - currentdirectoryindex= i; - - for (j= 0; j < s_pmi[i].nskins; j++) { - if (Q_stricmp(s_pmi[i].skindisplaynames[j], currentskin) == 0) { - currentskinindex= j; - break; - } - } - } - } - - s_player_config_menu.x= viddef.width / 2 - 95; - s_player_config_menu.y= viddef.height / 2 - 97; - s_player_config_menu.nitems= 0; - - s_player_name_field.type= MTYPE_FIELD; - s_player_name_field.name= "name"; - s_player_name_field.callback= null; - s_player_name_field.x= 0; - s_player_name_field.y= 0; - s_player_name_field.length= 20; - s_player_name_field.visible_length= 20; - s_player_name_field.buffer= new StringBuffer(name.string); - s_player_name_field.cursor= name.string.length(); - - s_player_model_title.type= MTYPE_SEPARATOR; - s_player_model_title.name= "model"; - s_player_model_title.x= -8; - s_player_model_title.y= 60; - - s_player_model_box.type= MTYPE_SPINCONTROL; - s_player_model_box.x= -56; - s_player_model_box.y= 70; - s_player_model_box.callback= new mcallback() { - public void execute(Object o) { - ModelCallback(o); - } - }; - s_player_model_box.cursor_offset= -48; - s_player_model_box.curvalue= currentdirectoryindex; - s_player_model_box.itemnames= s_pmnames; - - s_player_skin_title.type= MTYPE_SEPARATOR; - s_player_skin_title.name= "skin"; - s_player_skin_title.x= -16; - s_player_skin_title.y= 84; - - s_player_skin_box.type= MTYPE_SPINCONTROL; - s_player_skin_box.x= -56; - s_player_skin_box.y= 94; - s_player_skin_box.name= null; - s_player_skin_box.callback= null; - s_player_skin_box.cursor_offset= -48; - s_player_skin_box.curvalue= currentskinindex; - s_player_skin_box.itemnames= s_pmi[currentdirectoryindex].skindisplaynames; - - s_player_hand_title.type= MTYPE_SEPARATOR; - s_player_hand_title.name= "handedness"; - s_player_hand_title.x= 32; - s_player_hand_title.y= 108; - - s_player_handedness_box.type= MTYPE_SPINCONTROL; - s_player_handedness_box.x= -56; - s_player_handedness_box.y= 118; - s_player_handedness_box.name= null; - s_player_handedness_box.cursor_offset= -48; - s_player_handedness_box.callback= new mcallback() { - public void execute(Object o) { - HandednessCallback(o); - } - }; - s_player_handedness_box.curvalue= (int) Cvar.VariableValue("hand"); - s_player_handedness_box.itemnames= handedness; - - for (i= 0; i < rate_tbl.length - 1; i++) - if (Cvar.VariableValue("rate") == rate_tbl[i]) - break; - - s_player_rate_title.type= MTYPE_SEPARATOR; - s_player_rate_title.name= "connect speed"; - s_player_rate_title.x= 56; - s_player_rate_title.y= 156; - - s_player_rate_box.type= MTYPE_SPINCONTROL; - s_player_rate_box.x= -56; - s_player_rate_box.y= 166; - s_player_rate_box.name= null; - s_player_rate_box.cursor_offset= -48; - s_player_rate_box.callback= new mcallback() { - public void execute(Object o) { - RateCallback(o); - } - }; - s_player_rate_box.curvalue= i; - s_player_rate_box.itemnames= rate_names; - - s_player_download_action.type= MTYPE_ACTION; - s_player_download_action.name= "download options"; - s_player_download_action.flags= QMF_LEFT_JUSTIFY; - s_player_download_action.x= -24; - s_player_download_action.y= 186; - s_player_download_action.statusbar= null; - s_player_download_action.callback= new mcallback() { - public void execute(Object o) { - DownloadOptionsFunc(o); - } - }; - - Menu_AddItem(s_player_config_menu, s_player_name_field); - Menu_AddItem(s_player_config_menu, s_player_model_title); - Menu_AddItem(s_player_config_menu, s_player_model_box); - if (s_player_skin_box.itemnames != null) { - Menu_AddItem(s_player_config_menu, s_player_skin_title); - Menu_AddItem(s_player_config_menu, s_player_skin_box); - } - Menu_AddItem(s_player_config_menu, s_player_hand_title); - Menu_AddItem(s_player_config_menu, s_player_handedness_box); - Menu_AddItem(s_player_config_menu, s_player_rate_title); - Menu_AddItem(s_player_config_menu, s_player_rate_box); - Menu_AddItem(s_player_config_menu, s_player_download_action); - - return true; - } - - static int yaw; - - static void PlayerConfig_MenuDraw() { - - refdef_t refdef= new refdef_t(); - //char scratch[MAX_QPATH]; - String scratch; - - //memset(refdef, 0, sizeof(refdef)); - - refdef.x= viddef.width / 2; - refdef.y= viddef.height / 2 - 72; - refdef.width= 144; - refdef.height= 168; - refdef.fov_x= 40; - refdef.fov_y= Math3D.CalcFov(refdef.fov_x, refdef.width, refdef.height); - refdef.time= cls.realtime * 0.001f; - - if (s_pmi[s_player_model_box.curvalue].skindisplaynames != null) { - - int maxframe= 29; - entity_t entity= new entity_t(); - - //memset(entity, 0, sizeof(entity)); - - scratch= "players/" + s_pmi[s_player_model_box.curvalue].directory + "/tris.md2"; - - entity.model= re.RegisterModel(scratch); - - scratch= - "players/" - + s_pmi[s_player_model_box.curvalue].directory - + "/" - + s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] - + ".pcx"; - - entity.skin= re.RegisterSkin(scratch); - entity.flags= RF_FULLBRIGHT; - entity.origin[0]= 80; - entity.origin[1]= 0; - entity.origin[2]= 0; - VectorCopy(entity.origin, entity.oldorigin); - entity.frame= 0; - entity.oldframe= 0; - entity.backlerp= 0.0f; - entity.angles[1]= yaw++; - if (++yaw > 360) - yaw -= 360; - - refdef.areabits= null; - refdef.num_entities= 1; - refdef.entities= new entity_t[] { entity }; - refdef.lightstyles= null; - refdef.rdflags= RDF_NOWORLDMODEL; - - Menu_Draw(s_player_config_menu); - - DrawTextBox( - (int) ((refdef.x) * (320.0F / viddef.width) - 8), - (int) ((viddef.height / 2) * (240.0F / viddef.height) - 77), - refdef.width / 8, - refdef.height / 8); - refdef.height += 4; - - re.RenderFrame(refdef); - - scratch= - "/players/" - + s_pmi[s_player_model_box.curvalue].directory - + "/" - + s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] - + "_i.pcx"; - - re.DrawPic(s_player_config_menu.x - 40, refdef.y, scratch); - } - } - - static String PlayerConfig_MenuKey(int key) { - int i; - - if (key == K_ESCAPE) { - //char scratch[1024]; - String scratch; - - Cvar.Set("name", s_player_name_field.buffer.toString()); - - scratch= - s_pmi[s_player_model_box.curvalue].directory - + "/" - + s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue]; - - Cvar.Set("skin", scratch); - - for (i= 0; i < s_numplayermodels; i++) { - int j; - - for (j= 0; j < s_pmi[i].nskins; j++) { - if (s_pmi[i].skindisplaynames[j] != null) - s_pmi[i].skindisplaynames[j]= null; - } - s_pmi[i].skindisplaynames= null; - s_pmi[i].nskins= 0; - } - } - return Default_MenuKey(s_player_config_menu, key); - } - - static xcommand_t Menu_PlayerConfig= new xcommand_t() { - public void execute() { - Menu_PlayerConfig_f(); - } - }; - static void Menu_PlayerConfig_f() { - if (!PlayerConfig_MenuInit()) { - Menu_SetStatusBar(s_multiplayer_menu, "No valid player models found"); - return; - } - Menu_SetStatusBar(s_multiplayer_menu, null); - PushMenu(new xcommand_t() { - public void execute() { - PlayerConfig_MenuDraw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return PlayerConfig_MenuKey(key); - } - }); - } - - /* - ======================================================================= - - QUIT MENU - - ======================================================================= - */ - - static String Quit_Key(int key) { - switch (key) { - case K_ESCAPE : - case 'n' : - case 'N' : - PopMenu(); - break; - - case 'Y' : - case 'y' : - cls.key_dest= key_console; - CL.Quit_f.execute(); - break; - - default : - break; - } - - return null; - - } - - static void Quit_Draw() { - int w, h; - Dimension d= new Dimension(); - re.DrawGetPicSize(d, "quit"); - w= d.width; - h= d.height; - re.DrawPic((viddef.width - w) / 2, (viddef.height - h) / 2, "quit"); - } - - static xcommand_t Menu_Quit= new xcommand_t() { - public void execute() { - Menu_Quit_f(); - } - }; - - static void Menu_Quit_f() { - PushMenu(new xcommand_t() { - public void execute() { - Quit_Draw(); - } - }, new keyfunc_t() { - public String execute(int key) { - return Quit_Key(key); - } - }); - } - - // ============================================================================= - /* Menu Subsystem */ - - /** - * Init - */ - public static void Init() { - Cmd.AddCommand("menu_main", Menu_Main); - Cmd.AddCommand("menu_game", Menu_Game); - Cmd.AddCommand("menu_loadgame", Menu_LoadGame); - Cmd.AddCommand("menu_savegame", Menu_SaveGame); - Cmd.AddCommand("menu_joinserver", Menu_JoinServer); - Cmd.AddCommand("menu_addressbook", Menu_AddressBook); - Cmd.AddCommand("menu_startserver", Menu_StartServer); - Cmd.AddCommand("menu_dmoptions", Menu_DMOptions); - Cmd.AddCommand("menu_playerconfig", Menu_PlayerConfig); - Cmd.AddCommand("menu_downloadoptions", Menu_DownloadOptions); - Cmd.AddCommand("menu_credits", Menu_Credits); - Cmd.AddCommand("menu_multiplayer", Menu_Multiplayer); - Cmd.AddCommand("menu_video", Menu_Video); - Cmd.AddCommand("menu_options", Menu_Options); - Cmd.AddCommand("menu_keys", Menu_Keys); - Cmd.AddCommand("menu_quit", Menu_Quit); - - for (int i= 0; i < m_layers.length; i++) { - m_layers[i]= new menulayer_t(); - } - } - - /* - ================= - Draw - ================= - */ - static void Draw() { - if (cls.key_dest != key_menu) - return; - - // repaint everything next frame - SCR.DirtyScreen(); - - // dim everything behind it down - if (cl.cinematictime > 0) - re.DrawFill(0, 0, viddef.width, viddef.height, 0); - else - re.DrawFadeScreen(); - - m_drawfunc.execute(); - - // delay playing the enter sound until after the - // menu has been drawn, to avoid delay while - // caching images - if (m_entersound) { - S.StartLocalSound(menu_in_sound); - m_entersound= false; - } - } - - /* - ================= - Keydown - ================= - */ - static void Keydown(int key) { - String s; - - if (m_keyfunc != null) - if ((s= m_keyfunc.execute(key)) != null) - S.StartLocalSound(s); - } - - public static void Action_DoEnter(menuaction_s a) { - if (a.callback != null) - a.callback.execute(a); - } - - public static void Action_Draw(menuaction_s a) { - if ((a.flags & QMF_LEFT_JUSTIFY) != 0) { - if ((a.flags & QMF_GRAYED) != 0) - Menu_DrawStringDark(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + a.parent.y, a.name); - else - Menu_DrawString(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + a.parent.y, a.name); - } - else { - if ((a.flags & QMF_GRAYED) != 0) - Menu_DrawStringR2LDark(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + a.parent.y, a.name); - else - Menu_DrawStringR2L(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + a.parent.y, a.name); - } - if (a.ownerdraw != null) - a.ownerdraw.execute(a); - } - - public static boolean Field_DoEnter(menufield_s f) { - if (f.callback != null) { - f.callback.execute(f); - return true; - } - return false; - } - - public static void Field_Draw(menufield_s f) { - int i; - String tempbuffer; - //[128] = ""; - - if (f.name != null) - Menu_DrawStringR2LDark(f.x + f.parent.x + LCOLUMN_OFFSET, f.y + f.parent.y, f.name); - - //strncpy(tempbuffer, f.buffer + f.visible_offset, f.visible_length); - String s= f.buffer.toString(); - tempbuffer= s.substring(f.visible_offset, s.length()); - re.DrawChar(f.x + f.parent.x + 16, f.y + f.parent.y - 4, 18); - re.DrawChar(f.x + f.parent.x + 16, f.y + f.parent.y + 4, 24); - - re.DrawChar(f.x + f.parent.x + 24 + f.visible_length * 8, f.y + f.parent.y - 4, 20); - re.DrawChar(f.x + f.parent.x + 24 + f.visible_length * 8, f.y + f.parent.y + 4, 26); - - for (i= 0; i < f.visible_length; i++) { - re.DrawChar(f.x + f.parent.x + 24 + i * 8, f.y + f.parent.y - 4, 19); - re.DrawChar(f.x + f.parent.x + 24 + i * 8, f.y + f.parent.y + 4, 25); - } - - Menu_DrawString(f.x + f.parent.x + 24, f.y + f.parent.y, tempbuffer); - - if (Menu_ItemAtCursor(f.parent) == f) { - int offset; - - if (f.visible_offset != 0) - offset= f.visible_length; - else - offset= f.cursor; - - if ((((int) (Sys.Milliseconds() / 250)) & 1) != 0) { - re.DrawChar(f.x + f.parent.x + (offset + 2) * 8 + 8, f.y + f.parent.y, 11); - } - else { - re.DrawChar(f.x + f.parent.x + (offset + 2) * 8 + 8, f.y + f.parent.y, ' '); - } - } - } - - public static boolean Field_Key(menufield_s f, int k) { - char key= (char) k; - - switch (key) { - case K_KP_SLASH : - key= '/'; - break; - case K_KP_MINUS : - key= '-'; - break; - case K_KP_PLUS : - key= '+'; - break; - case K_KP_HOME : - key= '7'; - break; - case K_KP_UPARROW : - key= '8'; - break; - case K_KP_PGUP : - key= '9'; - break; - case K_KP_LEFTARROW : - key= '4'; - break; - case K_KP_5 : - key= '5'; - break; - case K_KP_RIGHTARROW : - key= '6'; - break; - case K_KP_END : - key= '1'; - break; - case K_KP_DOWNARROW : - key= '2'; - break; - case K_KP_PGDN : - key= '3'; - break; - case K_KP_INS : - key= '0'; - break; - case K_KP_DEL : - key= '.'; - break; - } - - if (key > 127) { - switch (key) { - case K_DEL : - default : - return false; - } - } - - /* - ** support pasting from the clipboard - */ - if ((Character.toUpperCase(key) == 'V' && keydown[K_CTRL]) || (((key == K_INS) || (key == K_KP_INS)) && keydown[K_SHIFT])) { - String cbd; - - if ((cbd= Sys.GetClipboardData()) != null) { - //strtok(cbd, "\n\r\b"); - String lines[]= Lib.linesplit(cbd); - if (lines.length > 0 && lines[0].length() != 0) { - //strncpy(f.buffer, cbd, f.length - 1); - f.buffer= new StringBuffer(lines[0]); - f.cursor= f.buffer.length(); - - f.visible_offset= f.cursor - f.visible_length; - - if (f.visible_offset < 0) - f.visible_offset= 0; - } - } - return true; - } - - switch (key) { - case K_KP_LEFTARROW : - case K_LEFTARROW : - case K_BACKSPACE : - if (f.cursor > 0) { - f.buffer.deleteCharAt(f.cursor - 1); - //memmove(f.buffer[f.cursor - 1], f.buffer[f.cursor], strlen(& f.buffer[f.cursor]) + 1); - f.cursor--; - - if (f.visible_offset != 0) { - f.visible_offset--; - } - } - break; - - case K_KP_DEL : - case K_DEL : - //memmove(& f.buffer[f.cursor], & f.buffer[f.cursor + 1], strlen(& f.buffer[f.cursor + 1]) + 1); - f.buffer.deleteCharAt(f.cursor); - break; - - case K_KP_ENTER : - case K_ENTER : - case K_ESCAPE : - case K_TAB : - return false; - - case K_SPACE : - default : - if (!Character.isDigit(key) && (f.flags & QMF_NUMBERSONLY) != 0) - return false; - - if (f.cursor < f.length) { - f.buffer.append(key); - f.cursor++; - - if (f.cursor > f.visible_length) { - f.visible_offset++; - } - } - } - - return true; - } - - public static void Menu_AddItem(menuframework_s menu, menucommon_s item) { - if (menu.nitems == 0) - menu.nslots= 0; - - if (menu.nitems < MAXMENUITEMS) { - menu.items[menu.nitems]= item; - ((menucommon_s) menu.items[menu.nitems]).parent= menu; - menu.nitems++; - } - - menu.nslots= Menu_TallySlots(menu); - } - - /* - ** Menu_AdjustCursor - ** - ** This function takes the given menu, the direction, and attempts - ** to adjust the menu's cursor so that it's at the next available - ** slot. - */ - public static void Menu_AdjustCursor(menuframework_s m, int dir) { - menucommon_s citem; - - /* - ** see if it's in a valid spot - */ - if (m.cursor >= 0 && m.cursor < m.nitems) { - if ((citem= Menu_ItemAtCursor(m)) != null) { - if (citem.type != MTYPE_SEPARATOR) - return; - } - } - - /* - ** it's not in a valid spot, so crawl in the direction indicated until we - ** find a valid spot - */ - if (dir == 1) { - while (true) { - citem= Menu_ItemAtCursor(m); - if (citem != null) - if (citem.type != MTYPE_SEPARATOR) - break; - m.cursor += dir; - if (m.cursor >= m.nitems) - m.cursor= 0; - } - } - else { - while (true) { - citem= Menu_ItemAtCursor(m); - if (citem != null) - if (citem.type != MTYPE_SEPARATOR) - break; - m.cursor += dir; - if (m.cursor < 0) - m.cursor= m.nitems - 1; - } - } - } - - public static void Menu_Center(menuframework_s menu) { - int height; - - height= ((menucommon_s) menu.items[menu.nitems - 1]).y; - height += 10; - - menu.y= (viddef.height - height) / 2; - } - - public static void Menu_Draw(menuframework_s menu) { - int i; - menucommon_s item; - - /* - ** draw contents - */ - for (i= 0; i < menu.nitems; i++) { - switch (((menucommon_s) menu.items[i]).type) { - case MTYPE_FIELD : - Field_Draw((menufield_s) menu.items[i]); - break; - case MTYPE_SLIDER : - Slider_Draw((menuslider_s) menu.items[i]); - break; - case MTYPE_LIST : - MenuList_Draw((menulist_s) menu.items[i]); - break; - case MTYPE_SPINCONTROL : - SpinControl_Draw((menulist_s) menu.items[i]); - break; - case MTYPE_ACTION : - Action_Draw((menuaction_s) menu.items[i]); - break; - case MTYPE_SEPARATOR : - Separator_Draw((menuseparator_s) menu.items[i]); - break; - } - } - - item= Menu_ItemAtCursor(menu); - - if (item != null && item.cursordraw != null) { - item.cursordraw.execute(item); - } - else if (menu.cursordraw != null) { - menu.cursordraw.execute(menu); - } - else if (item != null && item.type != MTYPE_FIELD) { - if ((item.flags & QMF_LEFT_JUSTIFY) != 0) { - re.DrawChar(menu.x + item.x - 24 + item.cursor_offset, menu.y + item.y, 12 + ((int) (Sys.Milliseconds() / 250) & 1)); - } - else { - re.DrawChar(menu.x + item.cursor_offset, menu.y + item.y, 12 + ((int) (Sys.Milliseconds() / 250) & 1)); - } - } - - if (item != null) { - if (item.statusbarfunc != null) - item.statusbarfunc.execute(item); - else if (item.statusbar != null) - Menu_DrawStatusBar(item.statusbar); - else - Menu_DrawStatusBar(menu.statusbar); - - } - else { - Menu_DrawStatusBar(menu.statusbar); - } - } - - public static void Menu_DrawStatusBar(String string) { - if (string != null) { - int l= string.length(); - int maxrow= viddef.height / 8; - int maxcol= viddef.width / 8; - int col= maxcol / 2 - l / 2; - - re.DrawFill(0, viddef.height - 8, viddef.width, 8, 4); - Menu_DrawString(col * 8, viddef.height - 8, string); - } - else { - re.DrawFill(0, viddef.height - 8, viddef.width, 8, 0); - } - } - - public static void Menu_DrawString(int x, int y, String string) { - int i; - - for (i= 0; i < string.length(); i++) { - re.DrawChar((x + i * 8), y, string.charAt(i)); - } - } - - public static void Menu_DrawStringDark(int x, int y, String string) { - int i; - - for (i= 0; i < string.length(); i++) { - re.DrawChar((x + i * 8), y, string.charAt(i) + 128); - } - } - - public static void Menu_DrawStringR2L(int x, int y, String string) { - int i; - - int l= string.length(); - for (i= 0; i < l; i++) { - re.DrawChar((x - i * 8), y, string.charAt(l - i - 1)); - } - } - - public static void Menu_DrawStringR2LDark(int x, int y, String string) { - int i; - - int l= string.length(); - for (i= 0; i < l; i++) { - re.DrawChar((x - i * 8), y, string.charAt(l - i - 1) + 128); - } - } - - public static menucommon_s Menu_ItemAtCursor(menuframework_s m) { - if (m.cursor < 0 || m.cursor >= m.nitems) - return null; - - return (menucommon_s) m.items[m.cursor]; - } - - static boolean Menu_SelectItem(menuframework_s s) { - menucommon_s item= Menu_ItemAtCursor(s); - - if (item != null) { - switch (item.type) { - case MTYPE_FIELD : - return Field_DoEnter((menufield_s) item); - case MTYPE_ACTION : - Action_DoEnter((menuaction_s) item); - return true; - case MTYPE_LIST : - // Menulist_DoEnter( ( menulist_s ) item ); - return false; - case MTYPE_SPINCONTROL : - // SpinControl_DoEnter( ( menulist_s ) item ); - return false; - } - } - return false; - } - - public static void Menu_SetStatusBar(menuframework_s m, String string) { - m.statusbar= string; - } - - public static void Menu_SlideItem(menuframework_s s, int dir) { - menucommon_s item= (menucommon_s) Menu_ItemAtCursor(s); - - if (item != null) { - switch (item.type) { - case MTYPE_SLIDER : - Slider_DoSlide((menuslider_s) item, dir); - break; - case MTYPE_SPINCONTROL : - SpinControl_DoSlide((menulist_s) item, dir); - break; - } - } - } - - public static int Menu_TallySlots(menuframework_s menu) { - int i; - int total= 0; - - for (i= 0; i < menu.nitems; i++) { - if (((menucommon_s) menu.items[i]).type == MTYPE_LIST) { - int nitems= 0; - String n[]= ((menulist_s) menu.items[i]).itemnames; - - while (n[nitems] != null) - nitems++; - - total += nitems; - } - else { - total++; - } - } - - return total; - } - - public static void Menulist_DoEnter(menulist_s l) { - int start; - - start= l.y / 10 + 1; - - l.curvalue= l.parent.cursor - start; - - if (l.callback != null) - l.callback.execute(l); - } - - public static void MenuList_Draw(menulist_s l) { - String n[]; - int y= 0; - - Menu_DrawStringR2LDark(l.x + l.parent.x + LCOLUMN_OFFSET, l.y + l.parent.y, l.name); - - n= l.itemnames; - - re.DrawFill(l.x - 112 + l.parent.x, l.parent.y + l.y + l.curvalue * 10 + 10, 128, 10, 16); - int i= 0; - - while (n[i] != null) { - Menu_DrawStringR2LDark(l.x + l.parent.x + LCOLUMN_OFFSET, l.y + l.parent.y + y + 10, n[i]); - - i++; - y += 10; - } - } - - public static void Separator_Draw(menuseparator_s s) { - if (s.name != null) - Menu_DrawStringR2LDark(s.x + s.parent.x, s.y + s.parent.y, s.name); - } - - public static void Slider_DoSlide(menuslider_s s, int dir) { - s.curvalue += dir; - - if (s.curvalue > s.maxvalue) - s.curvalue= s.maxvalue; - else if (s.curvalue < s.minvalue) - s.curvalue= s.minvalue; - - if (s.callback != null) - s.callback.execute(s); - } - - public static final int SLIDER_RANGE= 10; - - public static void Slider_Draw(menuslider_s s) { - int i; - - Menu_DrawStringR2LDark(s.x + s.parent.x + LCOLUMN_OFFSET, s.y + s.parent.y, s.name); - - s.range= (s.curvalue - s.minvalue) / (float) (s.maxvalue - s.minvalue); - - if (s.range < 0) - s.range= 0; - if (s.range > 1) - s.range= 1; - re.DrawChar(s.x + s.parent.x + RCOLUMN_OFFSET, s.y + s.parent.y, 128); - for (i= 0; i < SLIDER_RANGE; i++) - re.DrawChar(RCOLUMN_OFFSET + s.x + i * 8 + s.parent.x + 8, s.y + s.parent.y, 129); - re.DrawChar(RCOLUMN_OFFSET + s.x + i * 8 + s.parent.x + 8, s.y + s.parent.y, 130); - re.DrawChar((int) (8 + RCOLUMN_OFFSET + s.parent.x + s.x + (SLIDER_RANGE - 1) * 8 * s.range), s.y + s.parent.y, 131); - } - - public static void SpinControl_DoEnter(menulist_s s) { - s.curvalue++; - if (s.itemnames[s.curvalue] == null) - s.curvalue= 0; + static class menucommon_s { + int type; - if (s.callback != null) - s.callback.execute(s); - } + String name = ""; - public static void SpinControl_DoSlide(menulist_s s, int dir) { - s.curvalue += dir; + int x, y; - if (s.curvalue < 0) - s.curvalue= 0; - else if (s.itemnames[s.curvalue] == null) - s.curvalue--; + menuframework_s parent; - if (s.callback != null) - s.callback.execute(s); - } + int cursor_offset; - public static void SpinControl_Draw(menulist_s s) { - //char buffer[100]; - String buffer; + int localdata[] = { 0, 0, 0, 0 }; - if (s.name != null) { - Menu_DrawStringR2LDark(s.x + s.parent.x + LCOLUMN_OFFSET, s.y + s.parent.y, s.name); - } + int flags; - if (s.itemnames[s.curvalue].indexOf('\n') == -1) { - Menu_DrawString(RCOLUMN_OFFSET + s.x + s.parent.x, s.y + s.parent.y, s.itemnames[s.curvalue]); - } - else { - String line1, line2; - line1= Lib.leftFrom(s.itemnames[s.curvalue], '\n'); - Menu_DrawString(RCOLUMN_OFFSET + s.x + s.parent.x, s.y + s.parent.y, line1); + int n = -1; //position in an array. - line2= Lib.rightFrom(s.itemnames[s.curvalue], '\n'); + String statusbar; - int pos= line2.indexOf('\n'); - if (pos != -1) - line2= line2.substring(0, pos); + mcallback callback; - Menu_DrawString(RCOLUMN_OFFSET + s.x + s.parent.x, s.y + s.parent.y + 10, line2); - } - } -} + mcallback statusbarfunc; + + mcallback ownerdraw; + + mcallback cursordraw; + } + + static class menufield_s extends menucommon_s { + //char buffer[80]; + StringBuffer buffer; //allow deletion. + + int cursor; + + int length; + + int visible_length; + + int visible_offset; + } + + static class menuslider_s extends menucommon_s { + + float minvalue; + + float maxvalue; + + float curvalue; + + float range; + } + + static class menulist_s extends menucommon_s { + int curvalue; + + String itemnames[]; + } + + static class menuaction_s extends menucommon_s { + + } + + static class menuseparator_s extends menucommon_s { + + } + + public static menulayer_t m_layers[] = new menulayer_t[MAX_MENU_DEPTH]; + + public static int m_menudepth; + + static void Banner(String name) { + Dimension dim = new Dimension(); + Globals.re.DrawGetPicSize(dim, name); + + Globals.re.DrawPic(viddef.width / 2 - dim.width / 2, + viddef.height / 2 - 110, name); + } + + static void PushMenu(xcommand_t draw, keyfunc_t key) { //, String(*key) + // (int k) ) { + int i; + + if (Cvar.VariableValue("maxclients") == 1 && Globals.server_state != 0) + Cvar.Set("paused", "1"); + + // if this menu is already present, drop back to that level + // to avoid stacking menus by hotkeys + for (i = 0; i < m_menudepth; i++) + if (m_layers[i].draw == draw && m_layers[i].key == key) { + m_menudepth = i; + } + + if (i == m_menudepth) { + if (m_menudepth >= MAX_MENU_DEPTH) + Com.Error(ERR_FATAL, "PushMenu: MAX_MENU_DEPTH"); + + m_layers[m_menudepth].draw = m_drawfunc; + m_layers[m_menudepth].key = m_keyfunc; + m_menudepth++; + } + + m_drawfunc = draw; + m_keyfunc = key; + + m_entersound = true; + + cls.key_dest = key_menu; + } + + static void ForceMenuOff() { + m_drawfunc = null; + m_keyfunc = null; + cls.key_dest = key_game; + m_menudepth = 0; + Key.ClearStates(); + Cvar.Set("paused", "0"); + } + + static void PopMenu() { + S.StartLocalSound(menu_out_sound); + if (m_menudepth < 1) + Com.Error(ERR_FATAL, "PopMenu: depth < 1"); + m_menudepth--; + + m_drawfunc = m_layers[m_menudepth].draw; + m_keyfunc = m_layers[m_menudepth].key; + + if (0 == m_menudepth) + ForceMenuOff(); + } + + static String Default_MenuKey(menuframework_s m, int key) { + String sound = null; + menucommon_s item; + + if (m != null) { + if ((item = ((menucommon_s) Menu_ItemAtCursor(m))) != null) { + if (item.type == MTYPE_FIELD) { + if (Field_Key((menufield_s) item, key)) + return null; + } + } + } + + switch (key) { + case K_ESCAPE: + PopMenu(); + return menu_out_sound; + case K_KP_UPARROW: + case K_UPARROW: + if (m != null) { + m.cursor--; + Menu_AdjustCursor(m, -1); + sound = menu_move_sound; + } + break; + case K_TAB: + if (m != null) { + m.cursor++; + Menu_AdjustCursor(m, 1); + sound = menu_move_sound; + } + break; + case K_KP_DOWNARROW: + case K_DOWNARROW: + if (m != null) { + m.cursor++; + Menu_AdjustCursor(m, 1); + sound = menu_move_sound; + } + break; + case K_KP_LEFTARROW: + case K_LEFTARROW: + if (m != null) { + Menu_SlideItem(m, -1); + sound = menu_move_sound; + } + break; + case K_KP_RIGHTARROW: + case K_RIGHTARROW: + if (m != null) { + Menu_SlideItem(m, 1); + sound = menu_move_sound; + } + break; + + case K_MOUSE1: + case K_MOUSE2: + case K_MOUSE3: + case K_JOY1: + case K_JOY2: + case K_JOY3: + case K_JOY4: + /* + * case K_AUX1 : case K_AUX2 : case K_AUX3 : case K_AUX4 : case K_AUX5 : + * case K_AUX6 : case K_AUX7 : case K_AUX8 : case K_AUX9 : case K_AUX10 : + * case K_AUX11 : case K_AUX12 : case K_AUX13 : case K_AUX14 : case + * K_AUX15 : case K_AUX16 : case K_AUX17 : case K_AUX18 : case K_AUX19 : + * case K_AUX20 : case K_AUX21 : case K_AUX22 : case K_AUX23 : case + * K_AUX24 : case K_AUX25 : case K_AUX26 : case K_AUX27 : case K_AUX28 : + * case K_AUX29 : case K_AUX30 : case K_AUX31 : case K_AUX32 : + */ + case K_KP_ENTER: + case K_ENTER: + if (m != null) + Menu_SelectItem(m); + sound = menu_move_sound; + break; + } + + return sound; + } + + /* + * ================ DrawCharacter + * + * Draws one solid graphics character cx and cy are in 320*240 coordinates, + * and will be centered on higher res screens. ================ + */ + public static void DrawCharacter(int cx, int cy, int num) { + re.DrawChar(cx + ((viddef.width - 320) >> 1), cy + + ((viddef.height - 240) >> 1), num); + } + + public static void Print(int cx, int cy, String str) { + //while (*str) + for (int n = 0; n < str.length(); n++) { + DrawCharacter(cx, cy, str.charAt(n) + 128); + //str++; + cx += 8; + } + } + + public static void PrintWhite(int cx, int cy, String str) { + for (int n = 0; n < str.length(); n++) { + DrawCharacter(cx, cy, str.charAt(n)); + //str++; + cx += 8; + } + } + + public static void DrawPic(int x, int y, String pic) { + re.DrawPic(x + ((viddef.width - 320) >> 1), y + + ((viddef.height - 240) >> 1), pic); + } + + /* + * ============= DrawCursor + * + * Draws an animating cursor with the point at x,y. The pic will extend to + * the left of x, and both above and below y. ============= + */ + static boolean cached; + + static void DrawCursor(int x, int y, int f) { + //char cursorname[80]; + String cursorname; + + assert (f >= 0) : "negative time and cursor bug"; + + f = Math.abs(f); + + if (!cached) { + int i; + + for (i = 0; i < NUM_CURSOR_FRAMES; i++) { + cursorname = "m_cursor" + i; + + re.RegisterPic(cursorname); + } + cached = true; + } + + cursorname = "m_cursor" + f; + re.DrawPic(x, y, cursorname); + } + + public static void DrawTextBox(int x, int y, int width, int lines) { + int cx, cy; + int n; + + // draw left side + cx = x; + cy = y; + DrawCharacter(cx, cy, 1); + + for (n = 0; n < lines; n++) { + cy += 8; + DrawCharacter(cx, cy, 4); + } + DrawCharacter(cx, cy + 8, 7); + + // draw middle + cx += 8; + while (width > 0) { + cy = y; + DrawCharacter(cx, cy, 2); + + for (n = 0; n < lines; n++) { + cy += 8; + DrawCharacter(cx, cy, 5); + } + DrawCharacter(cx, cy + 8, 8); + + width -= 1; + cx += 8; + } + + // draw right side + cy = y; + DrawCharacter(cx, cy, 3); + for (n = 0; n < lines; n++) { + cy += 8; + DrawCharacter(cx, cy, 6); + + } + DrawCharacter(cx, cy + 8, 9); + + } + + /* + * ======================================================================= + * + * MAIN MENU + * + * ======================================================================= + */ + static final int MAIN_ITEMS = 5; + + static xcommand_t Main_Draw = new xcommand_t() { + public void execute() { + Main_Draw(); + } + }; + + static void Main_Draw() { + int i; + int w, h; + int ystart; + int xoffset; + int widest = -1; + int totalheight = 0; + String litname; + String[] names = { "m_main_game", "m_main_multiplayer", + "m_main_options", "m_main_video", "m_main_quit" }; + Dimension dim = new Dimension(); + + for (i = 0; i < names.length; i++) { + Globals.re.DrawGetPicSize(dim, names[i]); + w = dim.width; + h = dim.height; + + if (w > widest) + widest = w; + totalheight += (h + 12); + } + + ystart = (Globals.viddef.height / 2 - 110); + xoffset = (Globals.viddef.width - widest + 70) / 2; + + for (i = 0; i < names.length; i++) { + if (i != m_main_cursor) + Globals.re.DrawPic(xoffset, ystart + i * 40 + 13, names[i]); + } + + //strcat(litname, "_sel"); + litname = names[m_main_cursor] + "_sel"; + Globals.re.DrawPic(xoffset, ystart + m_main_cursor * 40 + 13, litname); + + DrawCursor(xoffset - 25, ystart + m_main_cursor * 40 + 11, + (int) ((Globals.cls.realtime / 100)) % NUM_CURSOR_FRAMES); + + Globals.re.DrawGetPicSize(dim, "m_main_plaque"); + w = dim.width; + h = dim.height; + Globals.re.DrawPic(xoffset - 30 - w, ystart, "m_main_plaque"); + + Globals.re.DrawPic(xoffset - 30 - w, ystart + h + 5, "m_main_logo"); + } + + static keyfunc_t Main_Key = new keyfunc_t() { + public String execute(int key) { + return Main_Key(key); + } + }; + + static String Main_Key(int key) { + String sound = menu_move_sound; + + switch (key) { + case Key.K_ESCAPE: + PopMenu(); + break; + + case Key.K_KP_DOWNARROW: + case Key.K_DOWNARROW: + if (++m_main_cursor >= MAIN_ITEMS) + m_main_cursor = 0; + return sound; + + case Key.K_KP_UPARROW: + case Key.K_UPARROW: + if (--m_main_cursor < 0) + m_main_cursor = MAIN_ITEMS - 1; + return sound; + + case Key.K_KP_ENTER: + case Key.K_ENTER: + m_entersound = true; + + switch (m_main_cursor) { + case 0: + Menu_Game_f(); + break; + + case 1: + Menu_Multiplayer_f(); + break; + + case 2: + Menu_Options_f(); + break; + + case 3: + Menu_Video_f(); + break; + + case 4: + Menu_Quit_f(); + break; + } + } + + return null; + } + + static xcommand_t Menu_Main = new xcommand_t() { + public void execute() { + Menu_Main_f(); + } + }; + + static void Menu_Main_f() { + PushMenu(new xcommand_t() { + public void execute() { + Main_Draw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return Main_Key(key); + } + }); + } + + /* + * ======================================================================= + * + * MULTIPLAYER MENU + * + * ======================================================================= + */ + static menuframework_s s_multiplayer_menu = new menuframework_s(); + + static menuaction_s s_join_network_server_action = new menuaction_s(); + + static menuaction_s s_start_network_server_action = new menuaction_s(); + + static menuaction_s s_player_setup_action = new menuaction_s(); + + static void Multiplayer_MenuDraw() { + Banner("m_banner_multiplayer"); + + Menu_AdjustCursor(s_multiplayer_menu, 1); + Menu_Draw(s_multiplayer_menu); + } + + static void PlayerSetupFunc(Object unused) { + Menu_PlayerConfig_f(); + } + + static void JoinNetworkServerFunc(Object unused) { + Menu_JoinServer_f(); + } + + static void StartNetworkServerFunc(Object unused) { + Menu_StartServer_f(); + } + + static void Multiplayer_MenuInit() { + s_multiplayer_menu.x = (int) (viddef.width * 0.50f - 64); + s_multiplayer_menu.nitems = 0; + + s_join_network_server_action.type = MTYPE_ACTION; + s_join_network_server_action.flags = QMF_LEFT_JUSTIFY; + s_join_network_server_action.x = 0; + s_join_network_server_action.y = 0; + s_join_network_server_action.name = " join network server"; + s_join_network_server_action.callback = new mcallback() { + public void execute(Object o) { + JoinNetworkServerFunc(o); + }; + }; + + s_start_network_server_action.type = MTYPE_ACTION; + s_start_network_server_action.flags = QMF_LEFT_JUSTIFY; + s_start_network_server_action.x = 0; + s_start_network_server_action.y = 10; + s_start_network_server_action.name = " start network server"; + s_start_network_server_action.callback = new mcallback() { + public void execute(Object o) { + StartNetworkServerFunc(o); + } + }; + + s_player_setup_action.type = MTYPE_ACTION; + s_player_setup_action.flags = QMF_LEFT_JUSTIFY; + s_player_setup_action.x = 0; + s_player_setup_action.y = 20; + s_player_setup_action.name = " player setup"; + s_player_setup_action.callback = new mcallback() { + public void execute(Object o) { + PlayerSetupFunc(o); + } + }; + + Menu_AddItem(s_multiplayer_menu, s_join_network_server_action); + Menu_AddItem(s_multiplayer_menu, s_start_network_server_action); + Menu_AddItem(s_multiplayer_menu, s_player_setup_action); + + Menu_SetStatusBar(s_multiplayer_menu, null); + + Menu_Center(s_multiplayer_menu); + } + + static String Multiplayer_MenuKey(int key) { + return Default_MenuKey(s_multiplayer_menu, key); + } + + static xcommand_t Menu_Multiplayer = new xcommand_t() { + public void execute() { + Menu_Multiplayer_f(); + } + }; + + static void Menu_Multiplayer_f() { + Multiplayer_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + Multiplayer_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return Multiplayer_MenuKey(key); + } + }); + } + + /* + * ======================================================================= + * + * KEYS MENU + * + * ======================================================================= + */ + static String bindnames[][] = { { "+attack", "attack" }, + { "weapnext", "next weapon" }, { "+forward", "walk forward" }, + { "+back", "backpedal" }, { "+left", "turn left" }, + { "+right", "turn right" }, { "+speed", "run" }, + { "+moveleft", "step left" }, { "+moveright", "step right" }, + { "+strafe", "sidestep" }, { "+lookup", "look up" }, + { "+lookdown", "look down" }, { "centerview", "center view" }, + { "+mlook", "mouse look" }, { "+klook", "keyboard look" }, + { "+moveup", "up / jump" }, { "+movedown", "down / crouch" }, { + + "inven", "inventory" }, { "invuse", "use item" }, + { "invdrop", "drop item" }, { "invprev", "prev item" }, + { "invnext", "next item" }, { + + "cmd help", "help computer" }, { null, null } }; + + int keys_cursor; + + static boolean bind_grab; + + static menuframework_s s_keys_menu = new menuframework_s(); + + static menuaction_s s_keys_attack_action = new menuaction_s(); + + static menuaction_s s_keys_change_weapon_action = new menuaction_s(); + + static menuaction_s s_keys_walk_forward_action = new menuaction_s(); + + static menuaction_s s_keys_backpedal_action = new menuaction_s(); + + static menuaction_s s_keys_turn_left_action = new menuaction_s(); + + static menuaction_s s_keys_turn_right_action = new menuaction_s(); + + static menuaction_s s_keys_run_action = new menuaction_s(); + + static menuaction_s s_keys_step_left_action = new menuaction_s(); + + static menuaction_s s_keys_step_right_action = new menuaction_s(); + + static menuaction_s s_keys_sidestep_action = new menuaction_s(); + + static menuaction_s s_keys_look_up_action = new menuaction_s(); + + static menuaction_s s_keys_look_down_action = new menuaction_s(); + + static menuaction_s s_keys_center_view_action = new menuaction_s(); + + static menuaction_s s_keys_mouse_look_action = new menuaction_s(); + + static menuaction_s s_keys_keyboard_look_action = new menuaction_s(); + + static menuaction_s s_keys_move_up_action = new menuaction_s(); + + static menuaction_s s_keys_move_down_action = new menuaction_s(); + + static menuaction_s s_keys_inventory_action = new menuaction_s(); + + static menuaction_s s_keys_inv_use_action = new menuaction_s(); + + static menuaction_s s_keys_inv_drop_action = new menuaction_s(); + + static menuaction_s s_keys_inv_prev_action = new menuaction_s(); + + static menuaction_s s_keys_inv_next_action = new menuaction_s(); + + static menuaction_s s_keys_help_computer_action = new menuaction_s(); + + static void UnbindCommand(String command) { + int j; + String b; + + for (j = 0; j < 256; j++) { + b = keybindings[j]; + if (b == null) + continue; + if (b.equals(command)) + Key.SetBinding(j, ""); + } + } + + static void FindKeysForCommand(String command, int twokeys[]) { + int count; + int j; + String b; + + twokeys[0] = twokeys[1] = -1; + count = 0; + + for (j = 0; j < 256; j++) { + b = keybindings[j]; + if (b == null) + continue; + + if (b.equals(command)) { + twokeys[count] = j; + count++; + if (count == 2) + break; + } + } + } + + static void KeyCursorDrawFunc(menuframework_s menu) { + if (bind_grab) + re.DrawChar(menu.x, menu.y + menu.cursor * 9, '='); + else + re.DrawChar(menu.x, menu.y + menu.cursor * 9, 12 + ((int) (Sys + .Milliseconds() / 250) & 1)); + } + + static void DrawKeyBindingFunc(Object self) { + int keys[] = { 0, 0 }; + menuaction_s a = (menuaction_s) self; + + FindKeysForCommand(bindnames[a.localdata[0]][0], keys); + + if (keys[0] == -1) { + Menu_DrawString(a.x + a.parent.x + 16, a.y + a.parent.y, "???"); + } else { + int x; + String name; + + name = Key.KeynumToString(keys[0]); + + Menu_DrawString(a.x + a.parent.x + 16, a.y + a.parent.y, name); + + x = name.length() * 8; + + if (keys[1] != -1) { + Menu_DrawString(a.x + a.parent.x + 24 + x, a.y + a.parent.y, + "or"); + Menu_DrawString(a.x + a.parent.x + 48 + x, a.y + a.parent.y, + Key.KeynumToString(keys[1])); + } + } + } + + static void KeyBindingFunc(Object self) { + menuaction_s a = (menuaction_s) self; + int keys[] = { 0, 0 }; + + FindKeysForCommand(bindnames[a.localdata[0]][0], keys); + + if (keys[1] != -1) + UnbindCommand(bindnames[a.localdata[0]][0]); + + bind_grab = true; + + Menu_SetStatusBar(s_keys_menu, "press a key or button for this action"); + } + + static void Keys_MenuInit() { + int y = 0; + int i = 0; + + s_keys_menu.x = (int) (viddef.width * 0.50); + s_keys_menu.nitems = 0; + s_keys_menu.cursordraw = new mcallback() { + public void execute(Object o) { + KeyCursorDrawFunc((menuframework_s) o); + } + }; + + s_keys_attack_action.type = MTYPE_ACTION; + s_keys_attack_action.flags = QMF_GRAYED; + s_keys_attack_action.x = 0; + s_keys_attack_action.y = y; + s_keys_attack_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + s_keys_attack_action.localdata[0] = i; + s_keys_attack_action.name = bindnames[s_keys_attack_action.localdata[0]][1]; + + s_keys_change_weapon_action.type = MTYPE_ACTION; + s_keys_change_weapon_action.flags = QMF_GRAYED; + s_keys_change_weapon_action.x = 0; + s_keys_change_weapon_action.y = y += 9; + s_keys_change_weapon_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_change_weapon_action.localdata[0] = ++i; + s_keys_change_weapon_action.name = bindnames[s_keys_change_weapon_action.localdata[0]][1]; + + s_keys_walk_forward_action.type = MTYPE_ACTION; + s_keys_walk_forward_action.flags = QMF_GRAYED; + s_keys_walk_forward_action.x = 0; + s_keys_walk_forward_action.y = y += 9; + s_keys_walk_forward_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + s_keys_walk_forward_action.localdata[0] = ++i; + s_keys_walk_forward_action.name = bindnames[s_keys_walk_forward_action.localdata[0]][1]; + + s_keys_backpedal_action.type = MTYPE_ACTION; + s_keys_backpedal_action.flags = QMF_GRAYED; + s_keys_backpedal_action.x = 0; + s_keys_backpedal_action.y = y += 9; + s_keys_backpedal_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + s_keys_backpedal_action.localdata[0] = ++i; + s_keys_backpedal_action.name = bindnames[s_keys_backpedal_action.localdata[0]][1]; + + s_keys_turn_left_action.type = MTYPE_ACTION; + s_keys_turn_left_action.flags = QMF_GRAYED; + s_keys_turn_left_action.x = 0; + s_keys_turn_left_action.y = y += 9; + s_keys_turn_left_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + s_keys_turn_left_action.localdata[0] = ++i; + s_keys_turn_left_action.name = bindnames[s_keys_turn_left_action.localdata[0]][1]; + + s_keys_turn_right_action.type = MTYPE_ACTION; + s_keys_turn_right_action.flags = QMF_GRAYED; + s_keys_turn_right_action.x = 0; + s_keys_turn_right_action.y = y += 9; + s_keys_turn_right_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + s_keys_turn_right_action.localdata[0] = ++i; + s_keys_turn_right_action.name = bindnames[s_keys_turn_right_action.localdata[0]][1]; + + s_keys_run_action.type = MTYPE_ACTION; + s_keys_run_action.flags = QMF_GRAYED; + s_keys_run_action.x = 0; + s_keys_run_action.y = y += 9; + s_keys_run_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + s_keys_run_action.localdata[0] = ++i; + s_keys_run_action.name = bindnames[s_keys_run_action.localdata[0]][1]; + + s_keys_step_left_action.type = MTYPE_ACTION; + s_keys_step_left_action.flags = QMF_GRAYED; + s_keys_step_left_action.x = 0; + s_keys_step_left_action.y = y += 9; + s_keys_step_left_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + s_keys_step_left_action.localdata[0] = ++i; + s_keys_step_left_action.name = bindnames[s_keys_step_left_action.localdata[0]][1]; + + s_keys_step_right_action.type = MTYPE_ACTION; + s_keys_step_right_action.flags = QMF_GRAYED; + s_keys_step_right_action.x = 0; + s_keys_step_right_action.y = y += 9; + s_keys_step_right_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_step_right_action.localdata[0] = ++i; + s_keys_step_right_action.name = bindnames[s_keys_step_right_action.localdata[0]][1]; + + s_keys_sidestep_action.type = MTYPE_ACTION; + s_keys_sidestep_action.flags = QMF_GRAYED; + s_keys_sidestep_action.x = 0; + s_keys_sidestep_action.y = y += 9; + s_keys_sidestep_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_sidestep_action.localdata[0] = ++i; + s_keys_sidestep_action.name = bindnames[s_keys_sidestep_action.localdata[0]][1]; + + s_keys_look_up_action.type = MTYPE_ACTION; + s_keys_look_up_action.flags = QMF_GRAYED; + s_keys_look_up_action.x = 0; + s_keys_look_up_action.y = y += 9; + s_keys_look_up_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_look_up_action.localdata[0] = ++i; + s_keys_look_up_action.name = bindnames[s_keys_look_up_action.localdata[0]][1]; + + s_keys_look_down_action.type = MTYPE_ACTION; + s_keys_look_down_action.flags = QMF_GRAYED; + s_keys_look_down_action.x = 0; + s_keys_look_down_action.y = y += 9; + s_keys_look_down_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_look_down_action.localdata[0] = ++i; + s_keys_look_down_action.name = bindnames[s_keys_look_down_action.localdata[0]][1]; + + s_keys_center_view_action.type = MTYPE_ACTION; + s_keys_center_view_action.flags = QMF_GRAYED; + s_keys_center_view_action.x = 0; + s_keys_center_view_action.y = y += 9; + s_keys_center_view_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_center_view_action.localdata[0] = ++i; + s_keys_center_view_action.name = bindnames[s_keys_center_view_action.localdata[0]][1]; + + s_keys_mouse_look_action.type = MTYPE_ACTION; + s_keys_mouse_look_action.flags = QMF_GRAYED; + s_keys_mouse_look_action.x = 0; + s_keys_mouse_look_action.y = y += 9; + s_keys_mouse_look_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_mouse_look_action.localdata[0] = ++i; + s_keys_mouse_look_action.name = bindnames[s_keys_mouse_look_action.localdata[0]][1]; + + s_keys_keyboard_look_action.type = MTYPE_ACTION; + s_keys_keyboard_look_action.flags = QMF_GRAYED; + s_keys_keyboard_look_action.x = 0; + s_keys_keyboard_look_action.y = y += 9; + s_keys_keyboard_look_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_keyboard_look_action.localdata[0] = ++i; + s_keys_keyboard_look_action.name = bindnames[s_keys_keyboard_look_action.localdata[0]][1]; + + s_keys_move_up_action.type = MTYPE_ACTION; + s_keys_move_up_action.flags = QMF_GRAYED; + s_keys_move_up_action.x = 0; + s_keys_move_up_action.y = y += 9; + s_keys_move_up_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_move_up_action.localdata[0] = ++i; + s_keys_move_up_action.name = bindnames[s_keys_move_up_action.localdata[0]][1]; + + s_keys_move_down_action.type = MTYPE_ACTION; + s_keys_move_down_action.flags = QMF_GRAYED; + s_keys_move_down_action.x = 0; + s_keys_move_down_action.y = y += 9; + s_keys_move_down_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_move_down_action.localdata[0] = ++i; + s_keys_move_down_action.name = bindnames[s_keys_move_down_action.localdata[0]][1]; + + s_keys_inventory_action.type = MTYPE_ACTION; + s_keys_inventory_action.flags = QMF_GRAYED; + s_keys_inventory_action.x = 0; + s_keys_inventory_action.y = y += 9; + s_keys_inventory_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_inventory_action.localdata[0] = ++i; + s_keys_inventory_action.name = bindnames[s_keys_inventory_action.localdata[0]][1]; + + s_keys_inv_use_action.type = MTYPE_ACTION; + s_keys_inv_use_action.flags = QMF_GRAYED; + s_keys_inv_use_action.x = 0; + s_keys_inv_use_action.y = y += 9; + s_keys_inv_use_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_inv_use_action.localdata[0] = ++i; + s_keys_inv_use_action.name = bindnames[s_keys_inv_use_action.localdata[0]][1]; + + s_keys_inv_drop_action.type = MTYPE_ACTION; + s_keys_inv_drop_action.flags = QMF_GRAYED; + s_keys_inv_drop_action.x = 0; + s_keys_inv_drop_action.y = y += 9; + s_keys_inv_drop_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_inv_drop_action.localdata[0] = ++i; + s_keys_inv_drop_action.name = bindnames[s_keys_inv_drop_action.localdata[0]][1]; + + s_keys_inv_prev_action.type = MTYPE_ACTION; + s_keys_inv_prev_action.flags = QMF_GRAYED; + s_keys_inv_prev_action.x = 0; + s_keys_inv_prev_action.y = y += 9; + s_keys_inv_prev_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_inv_prev_action.localdata[0] = ++i; + s_keys_inv_prev_action.name = bindnames[s_keys_inv_prev_action.localdata[0]][1]; + + s_keys_inv_next_action.type = MTYPE_ACTION; + s_keys_inv_next_action.flags = QMF_GRAYED; + s_keys_inv_next_action.x = 0; + s_keys_inv_next_action.y = y += 9; + s_keys_inv_next_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_inv_next_action.localdata[0] = ++i; + s_keys_inv_next_action.name = bindnames[s_keys_inv_next_action.localdata[0]][1]; + + s_keys_help_computer_action.type = MTYPE_ACTION; + s_keys_help_computer_action.flags = QMF_GRAYED; + s_keys_help_computer_action.x = 0; + s_keys_help_computer_action.y = y += 9; + s_keys_help_computer_action.ownerdraw = new mcallback() { + public void execute(Object o) { + DrawKeyBindingFunc(o); + } + }; + + s_keys_help_computer_action.localdata[0] = ++i; + s_keys_help_computer_action.name = bindnames[s_keys_help_computer_action.localdata[0]][1]; + + Menu_AddItem(s_keys_menu, s_keys_attack_action); + Menu_AddItem(s_keys_menu, s_keys_change_weapon_action); + Menu_AddItem(s_keys_menu, s_keys_walk_forward_action); + Menu_AddItem(s_keys_menu, s_keys_backpedal_action); + Menu_AddItem(s_keys_menu, s_keys_turn_left_action); + Menu_AddItem(s_keys_menu, s_keys_turn_right_action); + Menu_AddItem(s_keys_menu, s_keys_run_action); + Menu_AddItem(s_keys_menu, s_keys_step_left_action); + Menu_AddItem(s_keys_menu, s_keys_step_right_action); + Menu_AddItem(s_keys_menu, s_keys_sidestep_action); + Menu_AddItem(s_keys_menu, s_keys_look_up_action); + Menu_AddItem(s_keys_menu, s_keys_look_down_action); + Menu_AddItem(s_keys_menu, s_keys_center_view_action); + Menu_AddItem(s_keys_menu, s_keys_mouse_look_action); + Menu_AddItem(s_keys_menu, s_keys_keyboard_look_action); + Menu_AddItem(s_keys_menu, s_keys_move_up_action); + Menu_AddItem(s_keys_menu, s_keys_move_down_action); + + Menu_AddItem(s_keys_menu, s_keys_inventory_action); + Menu_AddItem(s_keys_menu, s_keys_inv_use_action); + Menu_AddItem(s_keys_menu, s_keys_inv_drop_action); + Menu_AddItem(s_keys_menu, s_keys_inv_prev_action); + Menu_AddItem(s_keys_menu, s_keys_inv_next_action); + + Menu_AddItem(s_keys_menu, s_keys_help_computer_action); + + Menu_SetStatusBar(s_keys_menu, "enter to change, backspace to clear"); + Menu_Center(s_keys_menu); + } + + static xcommand_t Keys_MenuDraw = new xcommand_t() { + public void execute() { + Keys_MenuDraw_f(); + } + }; + + static void Keys_MenuDraw_f() { + Menu_AdjustCursor(s_keys_menu, 1); + Menu_Draw(s_keys_menu); + } + + static keyfunc_t Keys_MenuKey = new keyfunc_t() { + public String execute(int key) { + return Keys_MenuKey_f(key); + } + }; + + static String Keys_MenuKey_f(int key) { + menuaction_s item = (menuaction_s) Menu_ItemAtCursor(s_keys_menu); + + if (bind_grab) { + if (key != K_ESCAPE && key != '`') { + //char cmd[1024]; + String cmd; + + //Com_sprintf(cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", + // Key_KeynumToString(key), bindnames[item.localdata[0]][0]); + cmd = "bind \"" + Key.KeynumToString(key) + "\" \"" + + bindnames[item.localdata[0]][0] + "\""; + Cbuf.InsertText(cmd); + } + + Menu_SetStatusBar(s_keys_menu, + "enter to change, backspace to clear"); + bind_grab = false; + return menu_out_sound; + } + + switch (key) { + case K_KP_ENTER: + case K_ENTER: + KeyBindingFunc(item); + return menu_in_sound; + case K_BACKSPACE: // delete bindings + case K_DEL: // delete bindings + case K_KP_DEL: + UnbindCommand(bindnames[item.localdata[0]][0]); + return menu_out_sound; + default: + return Default_MenuKey(s_keys_menu, key); + } + } + + static xcommand_t Menu_Keys = new xcommand_t() { + public void execute() { + Menu_Keys_f(); + } + }; + + static void Menu_Keys_f() { + Keys_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + Keys_MenuDraw_f(); + } + }, new keyfunc_t() { + public String execute(int key) { + return Keys_MenuKey_f(key); + } + }); + } + + /* + * ======================================================================= + * + * CONTROLS MENU + * + * ======================================================================= + */ + static cvar_t win_noalttab; + + static menuframework_s s_options_menu = new menuframework_s(); + + static menuaction_s s_options_defaults_action = new menuaction_s(); + + static menuaction_s s_options_customize_options_action = new menuaction_s(); + + static menuslider_s s_options_sensitivity_slider = new menuslider_s(); + + static menulist_s s_options_freelook_box = new menulist_s(); + + static menulist_s s_options_noalttab_box = new menulist_s(); + + static menulist_s s_options_alwaysrun_box = new menulist_s(); + + static menulist_s s_options_invertmouse_box = new menulist_s(); + + static menulist_s s_options_lookspring_box = new menulist_s(); + + static menulist_s s_options_lookstrafe_box = new menulist_s(); + + static menulist_s s_options_crosshair_box = new menulist_s(); + + static menuslider_s s_options_sfxvolume_slider = new menuslider_s(); + + static menulist_s s_options_joystick_box = new menulist_s(); + + static menulist_s s_options_cdvolume_box = new menulist_s(); + + static menulist_s s_options_quality_list = new menulist_s(); + + //static menulist_s s_options_compatibility_list = new menulist_s(); + static menuaction_s s_options_console_action = new menuaction_s(); + + static void CrosshairFunc(Object unused) { + Cvar.SetValue("crosshair", s_options_crosshair_box.curvalue); + } + + static void JoystickFunc(Object unused) { + Cvar.SetValue("in_joystick", s_options_joystick_box.curvalue); + } + + static void CustomizeControlsFunc(Object unused) { + Menu_Keys_f(); + } + + static void AlwaysRunFunc(Object unused) { + Cvar.SetValue("cl_run", s_options_alwaysrun_box.curvalue); + } + + static void FreeLookFunc(Object unused) { + Cvar.SetValue("freelook", s_options_freelook_box.curvalue); + } + + static void MouseSpeedFunc(Object unused) { + Cvar.SetValue("sensitivity", + s_options_sensitivity_slider.curvalue / 2.0F); + } + + static void NoAltTabFunc(Object unused) { + Cvar.SetValue("win_noalttab", s_options_noalttab_box.curvalue); + } + + static float ClampCvar(float min, float max, float value) { + if (value < min) + return min; + if (value > max) + return max; + return value; + } + + static void ControlsSetMenuItemValues() { + s_options_sfxvolume_slider.curvalue = Cvar.VariableValue("s_volume") * 10; + s_options_cdvolume_box.curvalue = 1 - ((int) Cvar + .VariableValue("cd_nocd")); + //s_options_quality_list.curvalue = 1 - ((int) + // Cvar.VariableValue("s_loadas8bit")); + if ("joal".equals(Cvar.VariableString("s_impl"))) { + s_options_quality_list.curvalue = 0; + } else { + s_options_quality_list.curvalue = 1; + } + + s_options_sensitivity_slider.curvalue = (sensitivity.value) * 2; + + Cvar.SetValue("cl_run", ClampCvar(0, 1, cl_run.value)); + s_options_alwaysrun_box.curvalue = (int) cl_run.value; + + s_options_invertmouse_box.curvalue = m_pitch.value < 0 ? 1 : 0; + + Cvar.SetValue("lookspring", ClampCvar(0, 1, lookspring.value)); + s_options_lookspring_box.curvalue = (int) lookspring.value; + + Cvar.SetValue("lookstrafe", ClampCvar(0, 1, lookstrafe.value)); + s_options_lookstrafe_box.curvalue = (int) lookstrafe.value; + + Cvar.SetValue("freelook", ClampCvar(0, 1, freelook.value)); + s_options_freelook_box.curvalue = (int) freelook.value; + + Cvar.SetValue("crosshair", ClampCvar(0, 3, Globals.crosshair.value)); + s_options_crosshair_box.curvalue = (int) Globals.crosshair.value; + + Cvar.SetValue("in_joystick", ClampCvar(0, 1, in_joystick.value)); + s_options_joystick_box.curvalue = (int) in_joystick.value; + + s_options_noalttab_box.curvalue = (int) win_noalttab.value; + } + + static void ControlsResetDefaultsFunc(Object unused) { + Cbuf.AddText("exec default.cfg\n"); + Cbuf.Execute(); + + ControlsSetMenuItemValues(); + } + + static void InvertMouseFunc(Object unused) { + Cvar.SetValue("m_pitch", -m_pitch.value); + } + + static void LookspringFunc(Object unused) { + Cvar.SetValue("lookspring", 1 - lookspring.value); + } + + static void LookstrafeFunc(Object unused) { + Cvar.SetValue("lookstrafe", 1 - lookstrafe.value); + } + + static void UpdateVolumeFunc(Object unused) { + Cvar.SetValue("s_volume", s_options_sfxvolume_slider.curvalue / 10); + } + + static void UpdateCDVolumeFunc(Object unused) { + Cvar.SetValue("cd_nocd", 1 - s_options_cdvolume_box.curvalue); + } + + static void ConsoleFunc(Object unused) { + /* + * * the proper way to do this is probably to have ToggleConsole_f + * accept a parameter + */ + + if (cl.attractloop) { + Cbuf.AddText("killserver\n"); + return; + } + + Key.ClearTyping(); + Console.ClearNotify(); + + ForceMenuOff(); + cls.key_dest = key_console; + } + + static void UpdateSoundQualityFunc(Object unused) { + boolean driverNotChanged = false; + if (s_options_quality_list.curvalue != 0) { + // Cvar.SetValue("s_khz", 22); + // Cvar.SetValue("s_loadas8bit", 0); + driverNotChanged = S.getDriverName().equals("dummy"); + Cvar.Set("s_impl", "dummy"); + } else { + // Cvar.SetValue("s_khz", 11); + // Cvar.SetValue("s_loadas8bit", 1); + driverNotChanged = S.getDriverName().equals("joal"); + Cvar.Set("s_impl", "joal"); + } + + //Cvar.SetValue("s_primary", s_options_compatibility_list.curvalue); + + if (driverNotChanged) { + re.EndFrame(); + return; + } else { + + DrawTextBox(8, 120 - 48, 36, 3); + Print(16 + 16, 120 - 48 + 8, "Restarting the sound system. This"); + Print(16 + 16, 120 - 48 + 16, "could take up to a minute, so"); + Print(16 + 16, 120 - 48 + 24, "please be patient."); + + // the text box won't show up unless we do a buffer swap + re.EndFrame(); + + CL.Snd_Restart_f.execute(); + } + } + + static String cd_music_items[] = { "disabled", "enabled", null }; + + static String soundstate_items[] = { "on", "off", null }; + + static String compatibility_items[] = { "max compatibility", + "max performance", null }; + + static String yesno_names[] = { "no", "yes", null }; + + static String crosshair_names[] = { "none", "cross", "dot", "angle", null }; + + static void Options_MenuInit() { + + win_noalttab = Cvar.Get("win_noalttab", "0", CVAR_ARCHIVE); + + /* + * * configure controls menu and menu items + */ + s_options_menu.x = viddef.width / 2; + s_options_menu.y = viddef.height / 2 - 58; + s_options_menu.nitems = 0; + + s_options_sfxvolume_slider.type = MTYPE_SLIDER; + s_options_sfxvolume_slider.x = 0; + s_options_sfxvolume_slider.y = 0; + s_options_sfxvolume_slider.name = "effects volume"; + s_options_sfxvolume_slider.callback = new mcallback() { + public void execute(Object o) { + UpdateVolumeFunc(o); + } + }; + s_options_sfxvolume_slider.minvalue = 0; + s_options_sfxvolume_slider.maxvalue = 10; + s_options_sfxvolume_slider.curvalue = Cvar.VariableValue("s_volume") * 10; + + s_options_cdvolume_box.type = MTYPE_SPINCONTROL; + s_options_cdvolume_box.x = 0; + s_options_cdvolume_box.y = 10; + s_options_cdvolume_box.name = "CD music"; + s_options_cdvolume_box.callback = new mcallback() { + public void execute(Object o) { + UpdateCDVolumeFunc(o); + } + }; + s_options_cdvolume_box.itemnames = cd_music_items; + s_options_cdvolume_box.curvalue = 1 - (int) Cvar + .VariableValue("cd_nocd"); + + s_options_quality_list.type = MTYPE_SPINCONTROL; + s_options_quality_list.x = 0; + s_options_quality_list.y = 20; + ; + s_options_quality_list.name = "sound"; + s_options_quality_list.callback = new mcallback() { + public void execute(Object o) { + UpdateSoundQualityFunc(o); + } + }; + s_options_quality_list.itemnames = soundstate_items; + //s_options_quality_list.curvalue = 1 - (int) + // Cvar.VariableValue("s_loadas8bit"); + + // s_options_compatibility_list.type = MTYPE_SPINCONTROL; + // s_options_compatibility_list.x = 0; + // s_options_compatibility_list.y = 30; + // s_options_compatibility_list.name = "sound compatibility"; + // s_options_compatibility_list.callback = new mcallback() { + // public void execute(Object o) { + // UpdateSoundQualityFunc(o); + // } + // }; + // s_options_compatibility_list.itemnames = compatibility_items; + // s_options_compatibility_list.curvalue = (int) + // Cvar.VariableValue("s_primary"); + + s_options_sensitivity_slider.type = MTYPE_SLIDER; + s_options_sensitivity_slider.x = 0; + s_options_sensitivity_slider.y = 50; + s_options_sensitivity_slider.name = "mouse speed"; + s_options_sensitivity_slider.callback = new mcallback() { + public void execute(Object o) { + MouseSpeedFunc(o); + } + }; + s_options_sensitivity_slider.minvalue = 2; + s_options_sensitivity_slider.maxvalue = 22; + + s_options_alwaysrun_box.type = MTYPE_SPINCONTROL; + s_options_alwaysrun_box.x = 0; + s_options_alwaysrun_box.y = 60; + s_options_alwaysrun_box.name = "always run"; + s_options_alwaysrun_box.callback = new mcallback() { + public void execute(Object o) { + AlwaysRunFunc(o); + } + }; + s_options_alwaysrun_box.itemnames = yesno_names; + + s_options_invertmouse_box.type = MTYPE_SPINCONTROL; + s_options_invertmouse_box.x = 0; + s_options_invertmouse_box.y = 70; + s_options_invertmouse_box.name = "invert mouse"; + s_options_invertmouse_box.callback = new mcallback() { + public void execute(Object o) { + InvertMouseFunc(o); + } + }; + s_options_invertmouse_box.itemnames = yesno_names; + + s_options_lookspring_box.type = MTYPE_SPINCONTROL; + s_options_lookspring_box.x = 0; + s_options_lookspring_box.y = 80; + s_options_lookspring_box.name = "lookspring"; + s_options_lookspring_box.callback = new mcallback() { + public void execute(Object o) { + LookspringFunc(o); + } + }; + s_options_lookspring_box.itemnames = yesno_names; + + s_options_lookstrafe_box.type = MTYPE_SPINCONTROL; + s_options_lookstrafe_box.x = 0; + s_options_lookstrafe_box.y = 90; + s_options_lookstrafe_box.name = "lookstrafe"; + s_options_lookstrafe_box.callback = new mcallback() { + public void execute(Object o) { + LookstrafeFunc(o); + } + }; + s_options_lookstrafe_box.itemnames = yesno_names; + + s_options_freelook_box.type = MTYPE_SPINCONTROL; + s_options_freelook_box.x = 0; + s_options_freelook_box.y = 100; + s_options_freelook_box.name = "free look"; + s_options_freelook_box.callback = new mcallback() { + public void execute(Object o) { + FreeLookFunc(o); + } + }; + s_options_freelook_box.itemnames = yesno_names; + + s_options_crosshair_box.type = MTYPE_SPINCONTROL; + s_options_crosshair_box.x = 0; + s_options_crosshair_box.y = 110; + s_options_crosshair_box.name = "crosshair"; + s_options_crosshair_box.callback = new mcallback() { + public void execute(Object o) { + CrosshairFunc(o); + } + }; + s_options_crosshair_box.itemnames = crosshair_names; + /* + * s_options_noalttab_box.type = MTYPE_SPINCONTROL; + * s_options_noalttab_box.x = 0; s_options_noalttab_box.y = 110; + * s_options_noalttab_box.name = "disable alt-tab"; + * s_options_noalttab_box.callback = NoAltTabFunc; + * s_options_noalttab_box.itemnames = yesno_names; + */ + s_options_joystick_box.type = MTYPE_SPINCONTROL; + s_options_joystick_box.x = 0; + s_options_joystick_box.y = 120; + s_options_joystick_box.name = "use joystick"; + s_options_joystick_box.callback = new mcallback() { + public void execute(Object o) { + JoystickFunc(o); + } + }; + s_options_joystick_box.itemnames = yesno_names; + + s_options_customize_options_action.type = MTYPE_ACTION; + s_options_customize_options_action.x = 0; + s_options_customize_options_action.y = 140; + s_options_customize_options_action.name = "customize controls"; + s_options_customize_options_action.callback = new mcallback() { + public void execute(Object o) { + CustomizeControlsFunc(o); + } + }; + + s_options_defaults_action.type = MTYPE_ACTION; + s_options_defaults_action.x = 0; + s_options_defaults_action.y = 150; + s_options_defaults_action.name = "reset defaults"; + s_options_defaults_action.callback = new mcallback() { + public void execute(Object o) { + ControlsResetDefaultsFunc(o); + } + }; + + s_options_console_action.type = MTYPE_ACTION; + s_options_console_action.x = 0; + s_options_console_action.y = 160; + s_options_console_action.name = "go to console"; + s_options_console_action.callback = new mcallback() { + public void execute(Object o) { + ConsoleFunc(o); + } + }; + + ControlsSetMenuItemValues(); + + Menu_AddItem(s_options_menu, s_options_sfxvolume_slider); + + Menu_AddItem(s_options_menu, s_options_cdvolume_box); + Menu_AddItem(s_options_menu, s_options_quality_list); + // Menu_AddItem(s_options_menu, s_options_compatibility_list); + Menu_AddItem(s_options_menu, s_options_sensitivity_slider); + Menu_AddItem(s_options_menu, s_options_alwaysrun_box); + Menu_AddItem(s_options_menu, s_options_invertmouse_box); + Menu_AddItem(s_options_menu, s_options_lookspring_box); + Menu_AddItem(s_options_menu, s_options_lookstrafe_box); + Menu_AddItem(s_options_menu, s_options_freelook_box); + Menu_AddItem(s_options_menu, s_options_crosshair_box); + // Menu_AddItem(s_options_menu, s_options_joystick_box); + Menu_AddItem(s_options_menu, s_options_customize_options_action); + Menu_AddItem(s_options_menu, s_options_defaults_action); + Menu_AddItem(s_options_menu, s_options_console_action); + } + + static void Options_MenuDraw() { + Banner("m_banner_options"); + Menu_AdjustCursor(s_options_menu, 1); + Menu_Draw(s_options_menu); + } + + static String Options_MenuKey(int key) { + return Default_MenuKey(s_options_menu, key); + } + + static xcommand_t Menu_Options = new xcommand_t() { + public void execute() { + Menu_Options_f(); + } + }; + + static void Menu_Options_f() { + Options_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + Options_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return Options_MenuKey(key); + } + }); + } + + /* + * ======================================================================= + * + * VIDEO MENU + * + * ======================================================================= + */ + + static xcommand_t Menu_Video = new xcommand_t() { + public void execute() { + Menu_Video_f(); + } + }; + + static void Menu_Video_f() { + VID.MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + VID.MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return VID.MenuKey(key); + } + }); + } + + /* + * ============================================================================= + * + * END GAME MENU + * + * ============================================================================= + */ + static int credits_start_time; + + static String creditsIndex[] = new String[256]; + + static String creditsBuffer; + + static String idcredits[] = { "+QUAKE II BY ID SOFTWARE", "", + "+PROGRAMMING", "John Carmack", "John Cash", "Brian Hook", "", + "+JAVA PORT BY BYTONIC", "CWEI", "HOZ", "RST", "", "+ART", + "Adrian Carmack", "Kevin Cloud", "Paul Steed", "", "+LEVEL DESIGN", + "Tim Willits", "American McGee", "Christian Antkow", + "Paul Jaquays", "Brandon James", "", "+BIZ", "Todd Hollenshead", + "Barrett (Bear) Alexander", "Donna Jackson", "", "", + "+SPECIAL THANKS", "Ben Donges for beta testing", "", "", "", "", + "", "", "+ADDITIONAL SUPPORT", "", "+LINUX PORT AND CTF", + "Dave \"Zoid\" Kirsch", "", "+CINEMATIC SEQUENCES", + "Ending Cinematic by Blur Studio - ", "Venice, CA", "", + "Environment models for Introduction", + "Cinematic by Karl Dolgener", "", + "Assistance with environment design", "by Cliff Iwai", "", + "+SOUND EFFECTS AND MUSIC", + "Sound Design by Soundelux Media Labs.", + "Music Composed and Produced by", + "Soundelux Media Labs. Special thanks", + "to Bill Brown, Tom Ozanich, Brian", + "Celano, Jeff Eisner, and The Soundelux", "Players.", "", + "\"Level Music\" by Sonic Mayhem", "www.sonicmayhem.com", "", + "\"Quake II Theme Song\"", "(C) 1997 Rob Zombie. All Rights", + "Reserved.", "", "Track 10 (\"Climb\") by Jer Sypult", "", + "Voice of computers by", "Carly Staehlin-Taylor", "", + "+THANKS TO ACTIVISION", "+IN PARTICULAR:", "", "John Tam", + "Steve Rosenthal", "Marty Stratton", "Henk Hartong", "", + "Quake II(tm) (C)1997 Id Software, Inc.", + "All Rights Reserved. Distributed by", + "Activision, Inc. under license.", + "Quake II(tm), the Id Software name,", + "the \"Q II\"(tm) logo and id(tm)", + "logo are trademarks of Id Software,", + "Inc. Activision(R) is a registered", + "trademark of Activision, Inc. All", + "other trademarks and trade names are", + "properties of their respective owners.", null }; + + static String credits[] = idcredits; + + static String xatcredits[] = { "+QUAKE II MISSION PACK: THE RECKONING", + "+BY", "+XATRIX ENTERTAINMENT, INC.", "", "+DESIGN AND DIRECTION", + "Drew Markham", "", "+PRODUCED BY", "Greg Goodrich", "", + "+PROGRAMMING", "Rafael Paiz", "", + "+LEVEL DESIGN / ADDITIONAL GAME DESIGN", "Alex Mayberry", "", + "+LEVEL DESIGN", "Mal Blackwell", "Dan Koppel", "", + "+ART DIRECTION", "Michael \"Maxx\" Kaufman", "", + "+COMPUTER GRAPHICS SUPERVISOR AND", + "+CHARACTER ANIMATION DIRECTION", "Barry Dempsey", "", + "+SENIOR ANIMATOR AND MODELER", "Jason Hoover", "", + "+CHARACTER ANIMATION AND", "+MOTION CAPTURE SPECIALIST", + "Amit Doron", "", "+ART", "Claire Praderie-Markham", + "Viktor Antonov", "Corky Lehmkuhl", "", "+INTRODUCTION ANIMATION", + "Dominique Drozdz", "", "+ADDITIONAL LEVEL DESIGN", "Aaron Barber", + "Rhett Baldwin", "", "+3D CHARACTER ANIMATION TOOLS", + "Gerry Tyra, SA Technology", "", + "+ADDITIONAL EDITOR TOOL PROGRAMMING", "Robert Duffy", "", + "+ADDITIONAL PROGRAMMING", "Ryan Feltrin", "", + "+PRODUCTION COORDINATOR", "Victoria Sylvester", "", + "+SOUND DESIGN", "Gary Bradfield", "", "+MUSIC BY", "Sonic Mayhem", + "", "", "", "+SPECIAL THANKS", "+TO", + "+OUR FRIENDS AT ID SOFTWARE", "", "John Carmack", "John Cash", + "Brian Hook", "Adrian Carmack", "Kevin Cloud", "Paul Steed", + "Tim Willits", "Christian Antkow", "Paul Jaquays", "Brandon James", + "Todd Hollenshead", "Barrett (Bear) Alexander", + "Dave \"Zoid\" Kirsch", "Donna Jackson", "", "", "", + "+THANKS TO ACTIVISION", "+IN PARTICULAR:", "", "Marty Stratton", + "Henk \"The Original Ripper\" Hartong", "Kevin Kraff", + "Jamey Gottlieb", "Chris Hepburn", "", "+AND THE GAME TESTERS", "", + "Tim Vanlaw", "Doug Jacobs", "Steven Rosenthal", "David Baker", + "Chris Campbell", "Aaron Casillas", "Steve Elwell", + "Derek Johnstone", "Igor Krinitskiy", "Samantha Lee", + "Michael Spann", "Chris Toft", "Juan Valdes", "", + "+THANKS TO INTERGRAPH COMPUTER SYTEMS", "+IN PARTICULAR:", "", + "Michael T. Nicolaou", "", "", + "Quake II Mission Pack: The Reckoning", + "(tm) (C)1998 Id Software, Inc. All", + "Rights Reserved. Developed by Xatrix", + "Entertainment, Inc. for Id Software,", + "Inc. Distributed by Activision Inc.", + "under license. Quake(R) is a", + "registered trademark of Id Software,", + "Inc. Quake II Mission Pack: The", + "Reckoning(tm), Quake II(tm), the Id", + "Software name, the \"Q II\"(tm) logo", + "and id(tm) logo are trademarks of Id", + "Software, Inc. Activision(R) is a", + "registered trademark of Activision,", + "Inc. Xatrix(R) is a registered", + "trademark of Xatrix Entertainment,", + "Inc. All other trademarks and trade", + "names are properties of their", "respective owners.", null }; + + static String roguecredits[] = { "+QUAKE II MISSION PACK 2: GROUND ZERO", + "+BY", "+ROGUE ENTERTAINMENT, INC.", "", "+PRODUCED BY", + "Jim Molinets", "", "+PROGRAMMING", "Peter Mack", + "Patrick Magruder", "", "+LEVEL DESIGN", "Jim Molinets", + "Cameron Lamprecht", "Berenger Fish", "Robert Selitto", + "Steve Tietze", "Steve Thoms", "", "+ART DIRECTION", + "Rich Fleider", "", "+ART", "Rich Fleider", "Steve Maines", + "Won Choi", "", "+ANIMATION SEQUENCES", "Creat Studios", + "Steve Maines", "", "+ADDITIONAL LEVEL DESIGN", "Rich Fleider", + "Steve Maines", "Peter Mack", "", "+SOUND", "James Grunke", "", + "+GROUND ZERO THEME", "+AND", "+MUSIC BY", "Sonic Mayhem", "", + "+VWEP MODELS", "Brent \"Hentai\" Dill", "", "", "", + "+SPECIAL THANKS", "+TO", "+OUR FRIENDS AT ID SOFTWARE", "", + "John Carmack", "John Cash", "Brian Hook", "Adrian Carmack", + "Kevin Cloud", "Paul Steed", "Tim Willits", "Christian Antkow", + "Paul Jaquays", "Brandon James", "Todd Hollenshead", + "Barrett (Bear) Alexander", "Katherine Anna Kang", "Donna Jackson", + "Dave \"Zoid\" Kirsch", "", "", "", "+THANKS TO ACTIVISION", + "+IN PARTICULAR:", "", "Marty Stratton", "Henk Hartong", + "Mitch Lasky", "Steve Rosenthal", "Steve Elwell", "", + "+AND THE GAME TESTERS", "", "The Ranger Clan", + "Dave \"Zoid\" Kirsch", "Nihilistic Software", "Robert Duffy", "", + "And Countless Others", "", "", "", + "Quake II Mission Pack 2: Ground Zero", + "(tm) (C)1998 Id Software, Inc. All", + "Rights Reserved. Developed by Rogue", + "Entertainment, Inc. for Id Software,", + "Inc. Distributed by Activision Inc.", + "under license. Quake(R) is a", + "registered trademark of Id Software,", + "Inc. Quake II Mission Pack 2: Ground", + "Zero(tm), Quake II(tm), the Id", + "Software name, the \"Q II\"(tm) logo", + "and id(tm) logo are trademarks of Id", + "Software, Inc. Activision(R) is a", + "registered trademark of Activision,", + "Inc. Rogue(R) is a registered", + "trademark of Rogue Entertainment,", + "Inc. All other trademarks and trade", + "names are properties of their", "respective owners.", null }; + + public static void Credits_MenuDraw() { + int i, y; + + /* + * * draw the credits + */ + for (i = 0, y = (int) (viddef.height - ((cls.realtime - credits_start_time) / 40.0F)); credits[i] != null + && y < viddef.height; y += 10, i++) { + int j, stringoffset = 0; + boolean bold = false; + + if (y <= -8) + continue; + + if (credits[i].length() > 0 && credits[i].charAt(0) == '+') { + bold = true; + stringoffset = 1; + } else { + bold = false; + stringoffset = 0; + } + + for (j = 0; j + stringoffset < credits[i].length(); j++) { + int x; + + x = (viddef.width - credits[i].length() * 8 - stringoffset * 8) + / 2 + (j + stringoffset) * 8; + + if (bold) + re + .DrawChar(x, y, + credits[i].charAt(j + stringoffset) + 128); + else + re.DrawChar(x, y, credits[i].charAt(j + stringoffset)); + } + } + + if (y < 0) + credits_start_time = cls.realtime; + } + + public static String Credits_Key(int key) { + switch (key) { + case K_ESCAPE: + if (creditsBuffer != null) + //FS.FreeFile(creditsBuffer); + ; + PopMenu(); + break; + } + + return menu_out_sound; + + } + + static xcommand_t Menu_Credits = new xcommand_t() { + public void execute() { + Menu_Credits_f(); + } + }; + + static void Menu_Credits_f() { + int n; + int isdeveloper = 0; + + byte b[] = FS.LoadFile("credits"); + + if (b != null) { + creditsBuffer = new String(b); + String line[] = Lib.linesplit(creditsBuffer); + + for (n = 0; n < line.length; n++) { + creditsIndex[n] = line[n]; + } + + creditsIndex[n] = null; + credits = creditsIndex; + } else { + isdeveloper = FS.Developer_searchpath(1); + + if (isdeveloper == 1) // xatrix + credits = xatcredits; + else if (isdeveloper == 2) // ROGUE + credits = roguecredits; + else { + credits = idcredits; + } + + } + + credits_start_time = cls.realtime; + PushMenu(new xcommand_t() { + public void execute() { + Credits_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return Credits_Key(key); + } + }); + } + + /* + * ============================================================================= + * + * GAME MENU + * + * ============================================================================= + */ + + static int m_game_cursor; + + static menuframework_s s_game_menu = new menuframework_s(); + + static menuaction_s s_easy_game_action = new menuaction_s(); + + static menuaction_s s_medium_game_action = new menuaction_s(); + + static menuaction_s s_hard_game_action = new menuaction_s(); + + static menuaction_s s_load_game_action = new menuaction_s(); + + static menuaction_s s_save_game_action = new menuaction_s(); + + static menuaction_s s_credits_action = new menuaction_s(); + + static menuseparator_s s_blankline = new menuseparator_s(); + + static void StartGame() { + // disable updates and start the cinematic going + cl.servercount = -1; + ForceMenuOff(); + Cvar.SetValue("deathmatch", 0); + Cvar.SetValue("coop", 0); + + Cvar.SetValue("gamerules", 0); //PGM + + Cbuf.AddText("loading ; killserver ; wait ; newgame\n"); + cls.key_dest = key_game; + } + + static void EasyGameFunc(Object data) { + Cvar.ForceSet("skill", "0"); + StartGame(); + } + + static void MediumGameFunc(Object data) { + Cvar.ForceSet("skill", "1"); + StartGame(); + } + + static void HardGameFunc(Object data) { + Cvar.ForceSet("skill", "2"); + StartGame(); + } + + static void LoadGameFunc(Object unused) { + Menu_LoadGame_f(); + } + + static void SaveGameFunc(Object unused) { + Menu_SaveGame_f(); + } + + static void CreditsFunc(Object unused) { + Menu_Credits_f(); + } + + static String difficulty_names[] = { "easy", "medium", + "fuckin shitty hard", null }; + + static void Game_MenuInit() { + + s_game_menu.x = (int) (viddef.width * 0.50); + s_game_menu.nitems = 0; + + s_easy_game_action.type = MTYPE_ACTION; + s_easy_game_action.flags = QMF_LEFT_JUSTIFY; + s_easy_game_action.x = 0; + s_easy_game_action.y = 0; + s_easy_game_action.name = "easy"; + s_easy_game_action.callback = new mcallback() { + public void execute(Object o) { + EasyGameFunc(o); + } + }; + + s_medium_game_action.type = MTYPE_ACTION; + s_medium_game_action.flags = QMF_LEFT_JUSTIFY; + s_medium_game_action.x = 0; + s_medium_game_action.y = 10; + s_medium_game_action.name = "medium"; + s_medium_game_action.callback = new mcallback() { + public void execute(Object o) { + MediumGameFunc(o); + } + }; + + s_hard_game_action.type = MTYPE_ACTION; + s_hard_game_action.flags = QMF_LEFT_JUSTIFY; + s_hard_game_action.x = 0; + s_hard_game_action.y = 20; + s_hard_game_action.name = "hard"; + s_hard_game_action.callback = new mcallback() { + public void execute(Object o) { + HardGameFunc(o); + } + }; + + s_blankline.type = MTYPE_SEPARATOR; + + s_load_game_action.type = MTYPE_ACTION; + s_load_game_action.flags = QMF_LEFT_JUSTIFY; + s_load_game_action.x = 0; + s_load_game_action.y = 40; + s_load_game_action.name = "load game"; + s_load_game_action.callback = new mcallback() { + public void execute(Object o) { + LoadGameFunc(o); + } + }; + + s_save_game_action.type = MTYPE_ACTION; + s_save_game_action.flags = QMF_LEFT_JUSTIFY; + s_save_game_action.x = 0; + s_save_game_action.y = 50; + s_save_game_action.name = "save game"; + s_save_game_action.callback = new mcallback() { + public void execute(Object o) { + SaveGameFunc(o); + } + }; + + s_credits_action.type = MTYPE_ACTION; + s_credits_action.flags = QMF_LEFT_JUSTIFY; + s_credits_action.x = 0; + s_credits_action.y = 60; + s_credits_action.name = "credits"; + s_credits_action.callback = new mcallback() { + public void execute(Object o) { + CreditsFunc(o); + } + }; + + Menu_AddItem(s_game_menu, s_easy_game_action); + Menu_AddItem(s_game_menu, s_medium_game_action); + Menu_AddItem(s_game_menu, s_hard_game_action); + Menu_AddItem(s_game_menu, s_blankline); + Menu_AddItem(s_game_menu, s_load_game_action); + Menu_AddItem(s_game_menu, s_save_game_action); + Menu_AddItem(s_game_menu, s_blankline); + Menu_AddItem(s_game_menu, s_credits_action); + + Menu_Center(s_game_menu); + } + + static void Game_MenuDraw() { + Banner("m_banner_game"); + Menu_AdjustCursor(s_game_menu, 1); + Menu_Draw(s_game_menu); + } + + static String Game_MenuKey(int key) { + return Default_MenuKey(s_game_menu, key); + } + + static xcommand_t Menu_Game = new xcommand_t() { + public void execute() { + Menu_Game_f(); + } + }; + + static void Menu_Game_f() { + Game_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + Game_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return Game_MenuKey(key); + } + }); + m_game_cursor = 1; + } + + /* + * ============================================================================= + * + * LOADGAME MENU + * + * ============================================================================= + */ + + public final static int MAX_SAVEGAMES = 15; + + static menuframework_s s_savegame_menu = new menuframework_s(); + + static menuframework_s s_loadgame_menu = new menuframework_s(); + + static menuaction_s s_loadgame_actions[] = new menuaction_s[MAX_SAVEGAMES]; + + static { + for (int n = 0; n < MAX_SAVEGAMES; n++) + s_loadgame_actions[n] = new menuaction_s(); + } + + //String m_savestrings[] = new String [MAX_SAVEGAMES][32]; + static String m_savestrings[] = new String[MAX_SAVEGAMES]; + + static { + for (int n = 0; n < MAX_SAVEGAMES; n++) + m_savestrings[n] = ""; + } + + static boolean m_savevalid[] = new boolean[MAX_SAVEGAMES]; + + /** Search the save dir for saved games and their names. */ + static void Create_Savestrings() { + int i; + QuakeFile f; + String name; + + for (i = 0; i < MAX_SAVEGAMES; i++) { + + m_savestrings[i] = ""; + name = FS.Gamedir() + "/save/save" + i + "/server.ssv"; + + try { + f = new QuakeFile(name, "r"); + if (f == null) { + m_savestrings[i] = ""; + m_savevalid[i] = false; + } else { + String str = f.readString(); + if (str != null) + m_savestrings[i] = str; + f.close(); + m_savevalid[i] = true; + } + } catch (Exception e) { + m_savestrings[i] = ""; + m_savevalid[i] = false; + } + ; + } + } + + static void LoadGameCallback(Object self) { + menuaction_s a = (menuaction_s) self; + + if (m_savevalid[a.localdata[0]]) + Cbuf.AddText("load save" + a.localdata[0] + "\n"); + ForceMenuOff(); + } + + static void LoadGame_MenuInit() { + int i; + + s_loadgame_menu.x = viddef.width / 2 - 120; + s_loadgame_menu.y = viddef.height / 2 - 58; + s_loadgame_menu.nitems = 0; + + Create_Savestrings(); + + for (i = 0; i < MAX_SAVEGAMES; i++) { + s_loadgame_actions[i].name = m_savestrings[i]; + s_loadgame_actions[i].flags = QMF_LEFT_JUSTIFY; + s_loadgame_actions[i].localdata[0] = i; + s_loadgame_actions[i].callback = new mcallback() { + public void execute(Object o) { + LoadGameCallback(o); + } + }; + + s_loadgame_actions[i].x = 0; + s_loadgame_actions[i].y = (i) * 10; + if (i > 0) // separate from autosave + s_loadgame_actions[i].y += 10; + + s_loadgame_actions[i].type = MTYPE_ACTION; + + Menu_AddItem(s_loadgame_menu, s_loadgame_actions[i]); + } + } + + static void LoadGame_MenuDraw() { + Banner("m_banner_load_game"); + // Menu_AdjustCursor( &s_loadgame_menu, 1 ); + Menu_Draw(s_loadgame_menu); + } + + static String LoadGame_MenuKey(int key) { + if (key == K_ESCAPE || key == K_ENTER) { + s_savegame_menu.cursor = s_loadgame_menu.cursor - 1; + if (s_savegame_menu.cursor < 0) + s_savegame_menu.cursor = 0; + } + return Default_MenuKey(s_loadgame_menu, key); + } + + static xcommand_t Menu_LoadGame = new xcommand_t() { + public void execute() { + Menu_LoadGame_f(); + } + }; + + static void Menu_LoadGame_f() { + LoadGame_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + LoadGame_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return LoadGame_MenuKey(key); + } + }); + } + + /* + * ============================================================================= + * + * SAVEGAME MENU + * + * ============================================================================= + */ + //static menuframework_s s_savegame_menu; + static menuaction_s s_savegame_actions[] = new menuaction_s[MAX_SAVEGAMES]; + + static { + for (int n = 0; n < MAX_SAVEGAMES; n++) + s_savegame_actions[n] = new menuaction_s(); + + } + + static void SaveGameCallback(Object self) { + menuaction_s a = (menuaction_s) self; + + Cbuf.AddText("save save" + a.localdata[0] + "\n"); + ForceMenuOff(); + } + + static void SaveGame_MenuDraw() { + Banner("m_banner_save_game"); + Menu_AdjustCursor(s_savegame_menu, 1); + Menu_Draw(s_savegame_menu); + } + + static void SaveGame_MenuInit() { + int i; + + s_savegame_menu.x = viddef.width / 2 - 120; + s_savegame_menu.y = viddef.height / 2 - 58; + s_savegame_menu.nitems = 0; + + Create_Savestrings(); + + // don't include the autosave slot + for (i = 0; i < MAX_SAVEGAMES - 1; i++) { + s_savegame_actions[i].name = m_savestrings[i + 1]; + s_savegame_actions[i].localdata[0] = i + 1; + s_savegame_actions[i].flags = QMF_LEFT_JUSTIFY; + s_savegame_actions[i].callback = new mcallback() { + public void execute(Object o) { + SaveGameCallback(o); + } + }; + + s_savegame_actions[i].x = 0; + s_savegame_actions[i].y = (i) * 10; + + s_savegame_actions[i].type = MTYPE_ACTION; + + Menu_AddItem(s_savegame_menu, s_savegame_actions[i]); + } + } + + static String SaveGame_MenuKey(int key) { + if (key == K_ENTER || key == K_ESCAPE) { + s_loadgame_menu.cursor = s_savegame_menu.cursor - 1; + if (s_loadgame_menu.cursor < 0) + s_loadgame_menu.cursor = 0; + } + return Default_MenuKey(s_savegame_menu, key); + } + + static xcommand_t Menu_SaveGame = new xcommand_t() { + public void execute() { + Menu_SaveGame_f(); + } + }; + + static void Menu_SaveGame_f() { + if (0 == Globals.server_state) + return; // not playing a game + + SaveGame_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + SaveGame_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return SaveGame_MenuKey(key); + } + }); + Create_Savestrings(); + } + + /* + * ============================================================================= + * + * JOIN SERVER MENU + * + * ============================================================================= + */ + + static menuframework_s s_joinserver_menu = new menuframework_s(); + + static menuseparator_s s_joinserver_server_title = new menuseparator_s(); + + static menuaction_s s_joinserver_search_action = new menuaction_s(); + + static menuaction_s s_joinserver_address_book_action = new menuaction_s(); + + static netadr_t local_server_netadr[] = new netadr_t[MAX_LOCAL_SERVERS]; + + static String local_server_names[] = new String[MAX_LOCAL_SERVERS]; //[80]; + + static menuaction_s s_joinserver_server_actions[] = new menuaction_s[MAX_LOCAL_SERVERS]; + + // user readable information + // network address + static { + for (int n = 0; n < MAX_LOCAL_SERVERS; n++) { + local_server_netadr[n] = new netadr_t(); + local_server_names[n] = ""; + s_joinserver_server_actions[n] = new menuaction_s(); + s_joinserver_server_actions[n].n = n; + } + } + + static int m_num_servers; + + static void AddToServerList(netadr_t adr, String info) { + int i; + + if (m_num_servers == MAX_LOCAL_SERVERS) + return; + + String x = info.trim(); + + // ignore if duplicated + + for (i = 0; i < m_num_servers; i++) + if (x.equals(local_server_names[i])) + return; + + local_server_netadr[m_num_servers] = adr; + local_server_names[m_num_servers] = x; + m_num_servers++; + } + + static void JoinServerFunc(Object self) { + String buffer; + int index; + + index = ((menucommon_s) self).n; + + if (Lib.Q_stricmp(local_server_names[index], NO_SERVER_STRING) == 0) + return; + + if (index >= m_num_servers) + return; + + buffer = "connect " + NET.AdrToString(local_server_netadr[index]) + + "\n"; + Cbuf.AddText(buffer); + ForceMenuOff(); + } + + static void AddressBookFunc(Object self) { + Menu_AddressBook_f(); + } + + static void NullCursorDraw(Object self) { + } + + static void SearchLocalGames() { + int i; + + m_num_servers = 0; + for (i = 0; i < MAX_LOCAL_SERVERS; i++) + local_server_names[i] = NO_SERVER_STRING; + + DrawTextBox(8, 120 - 48, 36, 3); + Print(16 + 16, 120 - 48 + 8, "Searching for local servers, this"); + Print(16 + 16, 120 - 48 + 16, "could take up to a minute, so"); + Print(16 + 16, 120 - 48 + 24, "please be patient."); + + // the text box won't show up unless we do a buffer swap + re.EndFrame(); + + // send out info packets + CL.PingServers_f.execute(); + } + + static void SearchLocalGamesFunc(Object self) { + SearchLocalGames(); + } + + static void JoinServer_MenuInit() { + int i; + + s_joinserver_menu.x = (int) (viddef.width * 0.50 - 120); + s_joinserver_menu.nitems = 0; + + s_joinserver_address_book_action.type = MTYPE_ACTION; + s_joinserver_address_book_action.name = "address book"; + s_joinserver_address_book_action.flags = QMF_LEFT_JUSTIFY; + s_joinserver_address_book_action.x = 0; + s_joinserver_address_book_action.y = 0; + s_joinserver_address_book_action.callback = new mcallback() { + public void execute(Object o) { + AddressBookFunc(o); + } + }; + + s_joinserver_search_action.type = MTYPE_ACTION; + s_joinserver_search_action.name = "refresh server list"; + s_joinserver_search_action.flags = QMF_LEFT_JUSTIFY; + s_joinserver_search_action.x = 0; + s_joinserver_search_action.y = 10; + s_joinserver_search_action.callback = new mcallback() { + public void execute(Object o) { + SearchLocalGamesFunc(o); + } + }; + s_joinserver_search_action.statusbar = "search for servers"; + + s_joinserver_server_title.type = MTYPE_SEPARATOR; + s_joinserver_server_title.name = "connect to..."; + s_joinserver_server_title.x = 80; + s_joinserver_server_title.y = 30; + + for (i = 0; i < MAX_LOCAL_SERVERS; i++) { + s_joinserver_server_actions[i].type = MTYPE_ACTION; + local_server_names[i] = NO_SERVER_STRING; + s_joinserver_server_actions[i].name = local_server_names[i]; + s_joinserver_server_actions[i].flags = QMF_LEFT_JUSTIFY; + s_joinserver_server_actions[i].x = 0; + s_joinserver_server_actions[i].y = 40 + i * 10; + s_joinserver_server_actions[i].callback = new mcallback() { + public void execute(Object o) { + JoinServerFunc(o); + } + }; + s_joinserver_server_actions[i].statusbar = "press ENTER to connect"; + } + + Menu_AddItem(s_joinserver_menu, s_joinserver_address_book_action); + Menu_AddItem(s_joinserver_menu, s_joinserver_server_title); + Menu_AddItem(s_joinserver_menu, s_joinserver_search_action); + + for (i = 0; i < 8; i++) + Menu_AddItem(s_joinserver_menu, s_joinserver_server_actions[i]); + + Menu_Center(s_joinserver_menu); + + SearchLocalGames(); + } + + static void JoinServer_MenuDraw() { + Banner("m_banner_join_server"); + Menu_Draw(s_joinserver_menu); + } + + static String JoinServer_MenuKey(int key) { + return Default_MenuKey(s_joinserver_menu, key); + } + + static xcommand_t Menu_JoinServer = new xcommand_t() { + public void execute() { + Menu_JoinServer_f(); + } + }; + + static void Menu_JoinServer_f() { + JoinServer_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + JoinServer_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return JoinServer_MenuKey(key); + } + }); + } + + /* + * ============================================================================= + * + * START SERVER MENU + * + * ============================================================================= + */ + static menuframework_s s_startserver_menu = new menuframework_s(); + + static String mapnames[]; + + static int nummaps; + + static menuaction_s s_startserver_start_action = new menuaction_s(); + + static menuaction_s s_startserver_dmoptions_action = new menuaction_s(); + + static menufield_s s_timelimit_field = new menufield_s(); + + static menufield_s s_fraglimit_field = new menufield_s(); + + static menufield_s s_maxclients_field = new menufield_s(); + + static menufield_s s_hostname_field = new menufield_s(); + + static menulist_s s_startmap_list = new menulist_s(); + + static menulist_s s_rules_box = new menulist_s(); + + static void DMOptionsFunc(Object self) { + if (s_rules_box.curvalue == 1) + return; + Menu_DMOptions_f(); + } + + static void RulesChangeFunc(Object self) { + // DM + if (s_rules_box.curvalue == 0) { + s_maxclients_field.statusbar = null; + s_startserver_dmoptions_action.statusbar = null; + } else if (s_rules_box.curvalue == 1) + // coop // PGM + { + s_maxclients_field.statusbar = "4 maximum for cooperative"; + if (Lib.atoi(s_maxclients_field.buffer.toString()) > 4) + s_maxclients_field.buffer = new StringBuffer("4"); + s_startserver_dmoptions_action.statusbar = "N/A for cooperative"; + } + // ===== + // PGM + // ROGUE GAMES + else if (FS.Developer_searchpath(2) == 2) { + if (s_rules_box.curvalue == 2) // tag + { + s_maxclients_field.statusbar = null; + s_startserver_dmoptions_action.statusbar = null; + } + /* + * else if(s_rules_box.curvalue == 3) // deathball { + * s_maxclients_field.statusbar = null; + * s_startserver_dmoptions_action.statusbar = null; } + */ + } + // PGM + // ===== + } + + static void StartServerActionFunc(Object self) { + //char startmap[1024]; + String startmap; + int timelimit; + int fraglimit; + int maxclients; + String spot; + + //strcpy(startmap, strchr(mapnames[s_startmap_list.curvalue], '\n') + + // 1); + String x = mapnames[s_startmap_list.curvalue]; + + int pos = x.indexOf('\n'); + if (pos == -1) + startmap = x; + else + startmap = x.substring(pos + 1, x.length()); + + maxclients = Lib.atoi(s_maxclients_field.buffer.toString()); + timelimit = Lib.atoi(s_timelimit_field.buffer.toString()); + fraglimit = Lib.atoi(s_fraglimit_field.buffer.toString()); + + Cvar.SetValue("maxclients", ClampCvar(0, maxclients, maxclients)); + Cvar.SetValue("timelimit", ClampCvar(0, timelimit, timelimit)); + Cvar.SetValue("fraglimit", ClampCvar(0, fraglimit, fraglimit)); + Cvar.Set("hostname", s_hostname_field.buffer.toString()); + // Cvar.SetValue ("deathmatch", !s_rules_box.curvalue ); + // Cvar.SetValue ("coop", s_rules_box.curvalue ); + + // PGM + if ((s_rules_box.curvalue < 2) || (FS.Developer_searchpath(2) != 2)) { + Cvar.SetValue("deathmatch", 1 - (int) (s_rules_box.curvalue)); + Cvar.SetValue("coop", s_rules_box.curvalue); + Cvar.SetValue("gamerules", 0); + } else { + Cvar.SetValue("deathmatch", 1); + // deathmatch is always true for rogue games, right? + Cvar.SetValue("coop", 0); + // FIXME - this might need to depend on which game we're running + Cvar.SetValue("gamerules", s_rules_box.curvalue); + } + // PGM + + spot = null; + if (s_rules_box.curvalue == 1) // PGM + { + if (Lib.Q_stricmp(startmap, "bunk1") == 0) + spot = "start"; + else if (Lib.Q_stricmp(startmap, "mintro") == 0) + spot = "start"; + else if (Lib.Q_stricmp(startmap, "fact1") == 0) + spot = "start"; + else if (Lib.Q_stricmp(startmap, "power1") == 0) + spot = "pstart"; + else if (Lib.Q_stricmp(startmap, "biggun") == 0) + spot = "bstart"; + else if (Lib.Q_stricmp(startmap, "hangar1") == 0) + spot = "unitstart"; + else if (Lib.Q_stricmp(startmap, "city1") == 0) + spot = "unitstart"; + else if (Lib.Q_stricmp(startmap, "boss1") == 0) + spot = "bosstart"; + } + + if (spot != null) { + if (Globals.server_state != 0) + Cbuf.AddText("disconnect\n"); + Cbuf.AddText("gamemap \"*" + startmap + "$" + spot + "\"\n"); + } else { + Cbuf.AddText("map " + startmap + "\n"); + } + + ForceMenuOff(); + } + + static String dm_coop_names[] = { "deathmatch", "cooperative", null }; + + static String dm_coop_names_rogue[] = { "deathmatch", "cooperative", "tag", + // "deathball", + null }; + + static void StartServer_MenuInit() { + + // ======= + // PGM + // ======= + + byte[] buffer = null; + String mapsname; + String s; + int i; + RandomAccessFile fp; + + /* + * * load the list of map names + */ + mapsname = FS.Gamedir() + "/maps.lst"; + + if ((fp = Lib.fopen(mapsname, "r")) == null) { + buffer = FS.LoadFile("maps.lst"); + if (buffer == null) + //if ((length = FS_LoadFile("maps.lst", (Object *) & buffer)) + // == -1) + Com.Error(ERR_DROP, "couldn't find maps.lst\n"); + } else { + try { + int len = (int) fp.length(); + buffer = new byte[len]; + fp.readFully(buffer); + } catch (Exception e) { + Com.Error(ERR_DROP, "couldn't load maps.lst\n"); + } + } + + s = new String(buffer); + String lines[] = Lib.linesplit(s); + + nummaps = lines.length; + + if (nummaps == 0) + Com.Error(ERR_DROP, "no maps in maps.lst\n"); + + mapnames = new String[nummaps + 1]; + + for (i = 0; i < nummaps; i++) { + String shortname, longname, scratch; + + Com.ParseHelp ph = new Com.ParseHelp(lines[i]); + + shortname = Com.Parse(ph).toUpperCase(); + longname = Com.Parse(ph); + scratch = longname + "\n" + shortname; + mapnames[i] = scratch; + } + mapnames[nummaps] = null; + + if (fp != null) { + Lib.fclose(fp); + fp = null; + + } else { + FS.FreeFile(buffer); + } + + /* + * * initialize the menu stuff + */ + s_startserver_menu.x = (int) (viddef.width * 0.50); + s_startserver_menu.nitems = 0; + + s_startmap_list.type = MTYPE_SPINCONTROL; + s_startmap_list.x = 0; + s_startmap_list.y = 0; + s_startmap_list.name = "initial map"; + s_startmap_list.itemnames = mapnames; + + s_rules_box.type = MTYPE_SPINCONTROL; + s_rules_box.x = 0; + s_rules_box.y = 20; + s_rules_box.name = "rules"; + + // PGM - rogue games only available with rogue DLL. + if (FS.Developer_searchpath(2) == 2) + s_rules_box.itemnames = dm_coop_names_rogue; + else + s_rules_box.itemnames = dm_coop_names; + // PGM + + if (Cvar.VariableValue("coop") != 0) + s_rules_box.curvalue = 1; + else + s_rules_box.curvalue = 0; + s_rules_box.callback = new mcallback() { + public void execute(Object o) { + RulesChangeFunc(o); + } + }; + + s_timelimit_field.type = MTYPE_FIELD; + s_timelimit_field.name = "time limit"; + s_timelimit_field.flags = QMF_NUMBERSONLY; + s_timelimit_field.x = 0; + s_timelimit_field.y = 36; + s_timelimit_field.statusbar = "0 = no limit"; + s_timelimit_field.length = 3; + s_timelimit_field.visible_length = 3; + s_timelimit_field.buffer = new StringBuffer(Cvar + .VariableString("timelimit")); + + s_fraglimit_field.type = MTYPE_FIELD; + s_fraglimit_field.name = "frag limit"; + s_fraglimit_field.flags = QMF_NUMBERSONLY; + s_fraglimit_field.x = 0; + s_fraglimit_field.y = 54; + s_fraglimit_field.statusbar = "0 = no limit"; + s_fraglimit_field.length = 3; + s_fraglimit_field.visible_length = 3; + s_fraglimit_field.buffer = new StringBuffer(Cvar + .VariableString("fraglimit")); + + /* + * * maxclients determines the maximum number of players that can join * + * the game. If maxclients is only "1" then we should default the menu * + * option to 8 players, otherwise use whatever its current value is. * + * Clamping will be done when the server is actually started. + */ + s_maxclients_field.type = MTYPE_FIELD; + s_maxclients_field.name = "max players"; + s_maxclients_field.flags = QMF_NUMBERSONLY; + s_maxclients_field.x = 0; + s_maxclients_field.y = 72; + s_maxclients_field.statusbar = null; + s_maxclients_field.length = 3; + s_maxclients_field.visible_length = 3; + if (Cvar.VariableValue("maxclients") == 1) + s_maxclients_field.buffer = new StringBuffer("8"); + else + s_maxclients_field.buffer = new StringBuffer(Cvar + .VariableString("maxclients")); + + s_hostname_field.type = MTYPE_FIELD; + s_hostname_field.name = "hostname"; + s_hostname_field.flags = 0; + s_hostname_field.x = 0; + s_hostname_field.y = 90; + s_hostname_field.statusbar = null; + s_hostname_field.length = 12; + s_hostname_field.visible_length = 12; + s_hostname_field.buffer = new StringBuffer(Cvar + .VariableString("hostname")); + s_hostname_field.cursor = s_hostname_field.buffer.length(); + + s_startserver_dmoptions_action.type = MTYPE_ACTION; + s_startserver_dmoptions_action.name = " deathmatch flags"; + s_startserver_dmoptions_action.flags = QMF_LEFT_JUSTIFY; + s_startserver_dmoptions_action.x = 24; + s_startserver_dmoptions_action.y = 108; + s_startserver_dmoptions_action.statusbar = null; + s_startserver_dmoptions_action.callback = new mcallback() { + public void execute(Object o) { + DMOptionsFunc(o); + } + }; + + s_startserver_start_action.type = MTYPE_ACTION; + s_startserver_start_action.name = " begin"; + s_startserver_start_action.flags = QMF_LEFT_JUSTIFY; + s_startserver_start_action.x = 24; + s_startserver_start_action.y = 128; + s_startserver_start_action.callback = new mcallback() { + public void execute(Object o) { + StartServerActionFunc(o); + } + }; + + Menu_AddItem(s_startserver_menu, s_startmap_list); + Menu_AddItem(s_startserver_menu, s_rules_box); + Menu_AddItem(s_startserver_menu, s_timelimit_field); + Menu_AddItem(s_startserver_menu, s_fraglimit_field); + Menu_AddItem(s_startserver_menu, s_maxclients_field); + Menu_AddItem(s_startserver_menu, s_hostname_field); + Menu_AddItem(s_startserver_menu, s_startserver_dmoptions_action); + Menu_AddItem(s_startserver_menu, s_startserver_start_action); + + Menu_Center(s_startserver_menu); + + // call this now to set proper inital state + RulesChangeFunc(null); + } + + static void StartServer_MenuDraw() { + Menu_Draw(s_startserver_menu); + } + + static String StartServer_MenuKey(int key) { + if (key == K_ESCAPE) { + if (mapnames != null) { + int i; + + for (i = 0; i < nummaps; i++) + mapnames[i] = null; + + } + mapnames = null; + nummaps = 0; + } + + return Default_MenuKey(s_startserver_menu, key); + } + + static xcommand_t Menu_StartServer = new xcommand_t() { + public void execute() { + Menu_StartServer_f(); + } + }; + + static void Menu_StartServer_f() { + StartServer_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + StartServer_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return StartServer_MenuKey(key); + } + }); + } + + /* + * ============================================================================= + * + * DMOPTIONS BOOK MENU + * + * ============================================================================= + */ + static String dmoptions_statusbar; //[128]; + + static menuframework_s s_dmoptions_menu = new menuframework_s(); + + static menulist_s s_friendlyfire_box = new menulist_s(); + + static menulist_s s_falls_box = new menulist_s(); + + static menulist_s s_weapons_stay_box = new menulist_s(); + + static menulist_s s_instant_powerups_box = new menulist_s(); + + static menulist_s s_powerups_box = new menulist_s(); + + static menulist_s s_health_box = new menulist_s(); + + static menulist_s s_spawn_farthest_box = new menulist_s(); + + static menulist_s s_teamplay_box = new menulist_s(); + + static menulist_s s_samelevel_box = new menulist_s(); + + static menulist_s s_force_respawn_box = new menulist_s(); + + static menulist_s s_armor_box = new menulist_s(); + + static menulist_s s_allow_exit_box = new menulist_s(); + + static menulist_s s_infinite_ammo_box = new menulist_s(); + + static menulist_s s_fixed_fov_box = new menulist_s(); + + static menulist_s s_quad_drop_box = new menulist_s(); + + // ROGUE + static menulist_s s_no_mines_box = new menulist_s(); + + static menulist_s s_no_nukes_box = new menulist_s(); + + static menulist_s s_stack_double_box = new menulist_s(); + + static menulist_s s_no_spheres_box = new menulist_s(); + + // ROGUE + + static void setvalue(int flags) { + Cvar.SetValue("dmflags", flags); + dmoptions_statusbar = "dmflags = " + flags; + } + + static void DMFlagCallback(Object self) { + menulist_s f = (menulist_s) self; + int flags; + int bit = 0; + + flags = (int) Cvar.VariableValue("dmflags"); + + if (f == s_friendlyfire_box) { + if (f.curvalue != 0) + flags &= ~DF_NO_FRIENDLY_FIRE; + else + flags |= DF_NO_FRIENDLY_FIRE; + setvalue(flags); + return; + } else if (f == s_falls_box) { + if (f.curvalue != 0) + flags &= ~DF_NO_FALLING; + else + flags |= DF_NO_FALLING; + setvalue(flags); + return; + } else if (f == s_weapons_stay_box) { + bit = DF_WEAPONS_STAY; + } else if (f == s_instant_powerups_box) { + bit = DF_INSTANT_ITEMS; + } else if (f == s_allow_exit_box) { + bit = DF_ALLOW_EXIT; + } else if (f == s_powerups_box) { + if (f.curvalue != 0) + flags &= ~DF_NO_ITEMS; + else + flags |= DF_NO_ITEMS; + setvalue(flags); + return; + } else if (f == s_health_box) { + if (f.curvalue != 0) + flags &= ~DF_NO_HEALTH; + else + flags |= DF_NO_HEALTH; + setvalue(flags); + return; + } else if (f == s_spawn_farthest_box) { + bit = DF_SPAWN_FARTHEST; + } else if (f == s_teamplay_box) { + if (f.curvalue == 1) { + flags |= DF_SKINTEAMS; + flags &= ~DF_MODELTEAMS; + } else if (f.curvalue == 2) { + flags |= DF_MODELTEAMS; + flags &= ~DF_SKINTEAMS; + } else { + flags &= ~(DF_MODELTEAMS | DF_SKINTEAMS); + } + + setvalue(flags); + return; + } else if (f == s_samelevel_box) { + bit = DF_SAME_LEVEL; + } else if (f == s_force_respawn_box) { + bit = DF_FORCE_RESPAWN; + } else if (f == s_armor_box) { + if (f.curvalue != 0) + flags &= ~DF_NO_ARMOR; + else + flags |= DF_NO_ARMOR; + setvalue(flags); + return; + } else if (f == s_infinite_ammo_box) { + bit = DF_INFINITE_AMMO; + } else if (f == s_fixed_fov_box) { + bit = DF_FIXED_FOV; + } else if (f == s_quad_drop_box) { + bit = DF_QUAD_DROP; + } + + // ======= + // ROGUE + else if (FS.Developer_searchpath(2) == 2) { + if (f == s_no_mines_box) { + bit = DF_NO_MINES; + } else if (f == s_no_nukes_box) { + bit = DF_NO_NUKES; + } else if (f == s_stack_double_box) { + bit = DF_NO_STACK_DOUBLE; + } else if (f == s_no_spheres_box) { + bit = DF_NO_SPHERES; + } + } + // ROGUE + // ======= + + if (f != null) { + if (f.curvalue == 0) + flags &= ~bit; + else + flags |= bit; + } + + Cvar.SetValue("dmflags", flags); + + dmoptions_statusbar = "dmflags = " + flags; + + } + + //static String yes_no_names[] = { "no", "yes", 0 }; + static String teamplay_names[] = { "disabled", "by skin", "by model", null }; + + static void DMOptions_MenuInit() { + + int dmflags = (int) Cvar.VariableValue("dmflags"); + int y = 0; + + s_dmoptions_menu.x = (int) (viddef.width * 0.50); + s_dmoptions_menu.nitems = 0; + + s_falls_box.type = MTYPE_SPINCONTROL; + s_falls_box.x = 0; + s_falls_box.y = y; + s_falls_box.name = "falling damage"; + s_falls_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_falls_box.itemnames = yes_no_names; + s_falls_box.curvalue = (dmflags & DF_NO_FALLING) == 0 ? 1 : 0; + + s_weapons_stay_box.type = MTYPE_SPINCONTROL; + s_weapons_stay_box.x = 0; + s_weapons_stay_box.y = y += 10; + s_weapons_stay_box.name = "weapons stay"; + s_weapons_stay_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_weapons_stay_box.itemnames = yes_no_names; + s_weapons_stay_box.curvalue = (dmflags & DF_WEAPONS_STAY) != 0 ? 1 : 0; + + s_instant_powerups_box.type = MTYPE_SPINCONTROL; + s_instant_powerups_box.x = 0; + s_instant_powerups_box.y = y += 10; + s_instant_powerups_box.name = "instant powerups"; + s_instant_powerups_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_instant_powerups_box.itemnames = yes_no_names; + s_instant_powerups_box.curvalue = (dmflags & DF_INSTANT_ITEMS) != 0 ? 1 + : 0; + + s_powerups_box.type = MTYPE_SPINCONTROL; + s_powerups_box.x = 0; + s_powerups_box.y = y += 10; + s_powerups_box.name = "allow powerups"; + s_powerups_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_powerups_box.itemnames = yes_no_names; + s_powerups_box.curvalue = (dmflags & DF_NO_ITEMS) == 0 ? 1 : 0; + + s_health_box.type = MTYPE_SPINCONTROL; + s_health_box.x = 0; + s_health_box.y = y += 10; + s_health_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_health_box.name = "allow health"; + s_health_box.itemnames = yes_no_names; + s_health_box.curvalue = (dmflags & DF_NO_HEALTH) == 0 ? 1 : 0; + + s_armor_box.type = MTYPE_SPINCONTROL; + s_armor_box.x = 0; + s_armor_box.y = y += 10; + s_armor_box.name = "allow armor"; + s_armor_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_armor_box.itemnames = yes_no_names; + s_armor_box.curvalue = (dmflags & DF_NO_ARMOR) == 0 ? 1 : 0; + + s_spawn_farthest_box.type = MTYPE_SPINCONTROL; + s_spawn_farthest_box.x = 0; + s_spawn_farthest_box.y = y += 10; + s_spawn_farthest_box.name = "spawn farthest"; + s_spawn_farthest_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_spawn_farthest_box.itemnames = yes_no_names; + s_spawn_farthest_box.curvalue = (dmflags & DF_SPAWN_FARTHEST) != 0 ? 1 + : 0; + + s_samelevel_box.type = MTYPE_SPINCONTROL; + s_samelevel_box.x = 0; + s_samelevel_box.y = y += 10; + s_samelevel_box.name = "same map"; + s_samelevel_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_samelevel_box.itemnames = yes_no_names; + s_samelevel_box.curvalue = (dmflags & DF_SAME_LEVEL) != 0 ? 1 : 0; + + s_force_respawn_box.type = MTYPE_SPINCONTROL; + s_force_respawn_box.x = 0; + s_force_respawn_box.y = y += 10; + s_force_respawn_box.name = "force respawn"; + s_force_respawn_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_force_respawn_box.itemnames = yes_no_names; + s_force_respawn_box.curvalue = (dmflags & DF_FORCE_RESPAWN) != 0 ? 1 + : 0; + + s_teamplay_box.type = MTYPE_SPINCONTROL; + s_teamplay_box.x = 0; + s_teamplay_box.y = y += 10; + s_teamplay_box.name = "teamplay"; + s_teamplay_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_teamplay_box.itemnames = teamplay_names; + + s_allow_exit_box.type = MTYPE_SPINCONTROL; + s_allow_exit_box.x = 0; + s_allow_exit_box.y = y += 10; + s_allow_exit_box.name = "allow exit"; + s_allow_exit_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_allow_exit_box.itemnames = yes_no_names; + s_allow_exit_box.curvalue = (dmflags & DF_ALLOW_EXIT) != 0 ? 1 : 0; + + s_infinite_ammo_box.type = MTYPE_SPINCONTROL; + s_infinite_ammo_box.x = 0; + s_infinite_ammo_box.y = y += 10; + s_infinite_ammo_box.name = "infinite ammo"; + s_infinite_ammo_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_infinite_ammo_box.itemnames = yes_no_names; + s_infinite_ammo_box.curvalue = (dmflags & DF_INFINITE_AMMO) != 0 ? 1 + : 0; + + s_fixed_fov_box.type = MTYPE_SPINCONTROL; + s_fixed_fov_box.x = 0; + s_fixed_fov_box.y = y += 10; + s_fixed_fov_box.name = "fixed FOV"; + s_fixed_fov_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_fixed_fov_box.itemnames = yes_no_names; + s_fixed_fov_box.curvalue = (dmflags & DF_FIXED_FOV) != 0 ? 1 : 0; + + s_quad_drop_box.type = MTYPE_SPINCONTROL; + s_quad_drop_box.x = 0; + s_quad_drop_box.y = y += 10; + s_quad_drop_box.name = "quad drop"; + s_quad_drop_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_quad_drop_box.itemnames = yes_no_names; + s_quad_drop_box.curvalue = (dmflags & DF_QUAD_DROP) != 0 ? 1 : 0; + + s_friendlyfire_box.type = MTYPE_SPINCONTROL; + s_friendlyfire_box.x = 0; + s_friendlyfire_box.y = y += 10; + s_friendlyfire_box.name = "friendly fire"; + s_friendlyfire_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_friendlyfire_box.itemnames = yes_no_names; + s_friendlyfire_box.curvalue = (dmflags & DF_NO_FRIENDLY_FIRE) == 0 ? 1 + : 0; + + // ============ + // ROGUE + if (FS.Developer_searchpath(2) == 2) { + s_no_mines_box.type = MTYPE_SPINCONTROL; + s_no_mines_box.x = 0; + s_no_mines_box.y = y += 10; + s_no_mines_box.name = "remove mines"; + s_no_mines_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_no_mines_box.itemnames = yes_no_names; + s_no_mines_box.curvalue = (dmflags & DF_NO_MINES) != 0 ? 1 : 0; + + s_no_nukes_box.type = MTYPE_SPINCONTROL; + s_no_nukes_box.x = 0; + s_no_nukes_box.y = y += 10; + s_no_nukes_box.name = "remove nukes"; + s_no_nukes_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_no_nukes_box.itemnames = yes_no_names; + s_no_nukes_box.curvalue = (dmflags & DF_NO_NUKES) != 0 ? 1 : 0; + + s_stack_double_box.type = MTYPE_SPINCONTROL; + s_stack_double_box.x = 0; + s_stack_double_box.y = y += 10; + s_stack_double_box.name = "2x/4x stacking off"; + s_stack_double_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_stack_double_box.itemnames = yes_no_names; + s_stack_double_box.curvalue = (dmflags & DF_NO_STACK_DOUBLE); + + s_no_spheres_box.type = MTYPE_SPINCONTROL; + s_no_spheres_box.x = 0; + s_no_spheres_box.y = y += 10; + s_no_spheres_box.name = "remove spheres"; + s_no_spheres_box.callback = new mcallback() { + public void execute(Object o) { + DMFlagCallback(o); + } + }; + s_no_spheres_box.itemnames = yes_no_names; + s_no_spheres_box.curvalue = (dmflags & DF_NO_SPHERES) != 0 ? 1 : 0; + + } + // ROGUE + // ============ + + Menu_AddItem(s_dmoptions_menu, s_falls_box); + Menu_AddItem(s_dmoptions_menu, s_weapons_stay_box); + Menu_AddItem(s_dmoptions_menu, s_instant_powerups_box); + Menu_AddItem(s_dmoptions_menu, s_powerups_box); + Menu_AddItem(s_dmoptions_menu, s_health_box); + Menu_AddItem(s_dmoptions_menu, s_armor_box); + Menu_AddItem(s_dmoptions_menu, s_spawn_farthest_box); + Menu_AddItem(s_dmoptions_menu, s_samelevel_box); + Menu_AddItem(s_dmoptions_menu, s_force_respawn_box); + Menu_AddItem(s_dmoptions_menu, s_teamplay_box); + Menu_AddItem(s_dmoptions_menu, s_allow_exit_box); + Menu_AddItem(s_dmoptions_menu, s_infinite_ammo_box); + Menu_AddItem(s_dmoptions_menu, s_fixed_fov_box); + Menu_AddItem(s_dmoptions_menu, s_quad_drop_box); + Menu_AddItem(s_dmoptions_menu, s_friendlyfire_box); + + // ======= + // ROGUE + if (FS.Developer_searchpath(2) == 2) { + Menu_AddItem(s_dmoptions_menu, s_no_mines_box); + Menu_AddItem(s_dmoptions_menu, s_no_nukes_box); + Menu_AddItem(s_dmoptions_menu, s_stack_double_box); + Menu_AddItem(s_dmoptions_menu, s_no_spheres_box); + } + // ROGUE + // ======= + + Menu_Center(s_dmoptions_menu); + + // set the original dmflags statusbar + DMFlagCallback(null); + Menu_SetStatusBar(s_dmoptions_menu, dmoptions_statusbar); + } + + static void DMOptions_MenuDraw() { + Menu_Draw(s_dmoptions_menu); + } + + static String DMOptions_MenuKey(int key) { + return Default_MenuKey(s_dmoptions_menu, key); + } + + static xcommand_t Menu_DMOptions = new xcommand_t() { + public void execute() { + Menu_DMOptions_f(); + } + }; + + static void Menu_DMOptions_f() { + DMOptions_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + DMOptions_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return DMOptions_MenuKey(key); + } + }); + } + + /* + * ============================================================================= + * + * DOWNLOADOPTIONS BOOK MENU + * + * ============================================================================= + */ + static menuframework_s s_downloadoptions_menu = new menuframework_s(); + + static menuseparator_s s_download_title = new menuseparator_s(); + + static menulist_s s_allow_download_box = new menulist_s(); + + static menulist_s s_allow_download_maps_box = new menulist_s(); + + static menulist_s s_allow_download_models_box = new menulist_s(); + + static menulist_s s_allow_download_players_box = new menulist_s(); + + static menulist_s s_allow_download_sounds_box = new menulist_s(); + + static void DownloadCallback(Object self) { + menulist_s f = (menulist_s) self; + + if (f == s_allow_download_box) { + Cvar.SetValue("allow_download", f.curvalue); + } + + else if (f == s_allow_download_maps_box) { + Cvar.SetValue("allow_download_maps", f.curvalue); + } + + else if (f == s_allow_download_models_box) { + Cvar.SetValue("allow_download_models", f.curvalue); + } + + else if (f == s_allow_download_players_box) { + Cvar.SetValue("allow_download_players", f.curvalue); + } + + else if (f == s_allow_download_sounds_box) { + Cvar.SetValue("allow_download_sounds", f.curvalue); + } + } + + static String yes_no_names[] = { "no", "yes", null }; + + static void DownloadOptions_MenuInit() { + + int y = 0; + + s_downloadoptions_menu.x = (int) (viddef.width * 0.50); + s_downloadoptions_menu.nitems = 0; + + s_download_title.type = MTYPE_SEPARATOR; + s_download_title.name = "Download Options"; + s_download_title.x = 48; + s_download_title.y = y; + + s_allow_download_box.type = MTYPE_SPINCONTROL; + s_allow_download_box.x = 0; + s_allow_download_box.y = y += 20; + s_allow_download_box.name = "allow downloading"; + s_allow_download_box.callback = new mcallback() { + public void execute(Object o) { + DownloadCallback(o); + } + }; + s_allow_download_box.itemnames = yes_no_names; + s_allow_download_box.curvalue = (Cvar.VariableValue("allow_download") != 0) ? 1 + : 0; + + s_allow_download_maps_box.type = MTYPE_SPINCONTROL; + s_allow_download_maps_box.x = 0; + s_allow_download_maps_box.y = y += 20; + s_allow_download_maps_box.name = "maps"; + s_allow_download_maps_box.callback = new mcallback() { + public void execute(Object o) { + DownloadCallback(o); + } + }; + s_allow_download_maps_box.itemnames = yes_no_names; + s_allow_download_maps_box.curvalue = (Cvar + .VariableValue("allow_download_maps") != 0) ? 1 : 0; + + s_allow_download_players_box.type = MTYPE_SPINCONTROL; + s_allow_download_players_box.x = 0; + s_allow_download_players_box.y = y += 10; + s_allow_download_players_box.name = "player models/skins"; + s_allow_download_players_box.callback = new mcallback() { + public void execute(Object o) { + DownloadCallback(o); + } + }; + s_allow_download_players_box.itemnames = yes_no_names; + s_allow_download_players_box.curvalue = (Cvar + .VariableValue("allow_download_players") != 0) ? 1 : 0; + + s_allow_download_models_box.type = MTYPE_SPINCONTROL; + s_allow_download_models_box.x = 0; + s_allow_download_models_box.y = y += 10; + s_allow_download_models_box.name = "models"; + s_allow_download_models_box.callback = new mcallback() { + public void execute(Object o) { + DownloadCallback(o); + } + }; + s_allow_download_models_box.itemnames = yes_no_names; + s_allow_download_models_box.curvalue = (Cvar + .VariableValue("allow_download_models") != 0) ? 1 : 0; + + s_allow_download_sounds_box.type = MTYPE_SPINCONTROL; + s_allow_download_sounds_box.x = 0; + s_allow_download_sounds_box.y = y += 10; + s_allow_download_sounds_box.name = "sounds"; + s_allow_download_sounds_box.callback = new mcallback() { + public void execute(Object o) { + DownloadCallback(o); + } + }; + s_allow_download_sounds_box.itemnames = yes_no_names; + s_allow_download_sounds_box.curvalue = (Cvar + .VariableValue("allow_download_sounds") != 0) ? 1 : 0; + + Menu_AddItem(s_downloadoptions_menu, s_download_title); + Menu_AddItem(s_downloadoptions_menu, s_allow_download_box); + Menu_AddItem(s_downloadoptions_menu, s_allow_download_maps_box); + Menu_AddItem(s_downloadoptions_menu, s_allow_download_players_box); + Menu_AddItem(s_downloadoptions_menu, s_allow_download_models_box); + Menu_AddItem(s_downloadoptions_menu, s_allow_download_sounds_box); + + Menu_Center(s_downloadoptions_menu); + + // skip over title + if (s_downloadoptions_menu.cursor == 0) + s_downloadoptions_menu.cursor = 1; + } + + static void DownloadOptions_MenuDraw() { + Menu_Draw(s_downloadoptions_menu); + } + + static String DownloadOptions_MenuKey(int key) { + return Default_MenuKey(s_downloadoptions_menu, key); + } + + static xcommand_t Menu_DownloadOptions = new xcommand_t() { + public void execute() { + Menu_DownloadOptions_f(); + } + }; + + static void Menu_DownloadOptions_f() { + DownloadOptions_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + DownloadOptions_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return DownloadOptions_MenuKey(key); + } + }); + } + + /* + * ============================================================================= + * + * ADDRESS BOOK MENU + * + * ============================================================================= + */ + + static menuframework_s s_addressbook_menu = new menuframework_s(); + + static menufield_s s_addressbook_fields[] = new menufield_s[NUM_ADDRESSBOOK_ENTRIES]; + static { + for (int n = 0; n < NUM_ADDRESSBOOK_ENTRIES; n++) + s_addressbook_fields[n] = new menufield_s(); + } + + static void AddressBook_MenuInit() { + int i; + + s_addressbook_menu.x = viddef.width / 2 - 142; + s_addressbook_menu.y = viddef.height / 2 - 58; + s_addressbook_menu.nitems = 0; + + for (i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++) { + cvar_t adr; + //char buffer[20]; + String buffer; + + //Com_sprintf(buffer, sizeof(buffer), "adr%d", i); + buffer = "adr" + i; + + adr = Cvar.Get(buffer, "", CVAR_ARCHIVE); + + s_addressbook_fields[i].type = MTYPE_FIELD; + s_addressbook_fields[i].name = null; + s_addressbook_fields[i].callback = null; + s_addressbook_fields[i].x = 0; + s_addressbook_fields[i].y = i * 18 + 0; + s_addressbook_fields[i].localdata[0] = i; + s_addressbook_fields[i].cursor = 0; + s_addressbook_fields[i].length = 60; + s_addressbook_fields[i].visible_length = 30; + + s_addressbook_fields[i].buffer = new StringBuffer(adr.string); + + Menu_AddItem(s_addressbook_menu, s_addressbook_fields[i]); + } + } + + static keyfunc_t AddressBook_MenuKey = new keyfunc_t() { + public String execute(int key) { + return AddressBook_MenuKey_f(key); + } + }; + + static String AddressBook_MenuKey_f(int key) { + if (key == K_ESCAPE) { + int index; + //char buffer[20]; + String buffer; + + for (index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++) { + buffer = "adr" + index; + //Com_sprintf(buffer, sizeof(buffer), "adr%d", index); + Cvar.Set(buffer, s_addressbook_fields[index].buffer.toString()); + } + } + return Default_MenuKey(s_addressbook_menu, key); + } + + static xcommand_t AddressBook_MenuDraw = new xcommand_t() { + public void execute() { + AddressBook_MenuDraw_f(); + } + }; + + static void AddressBook_MenuDraw_f() { + Banner("m_banner_addressbook"); + Menu_Draw(s_addressbook_menu); + } + + static xcommand_t Menu_AddressBook = new xcommand_t() { + public void execute() { + Menu_AddressBook_f(); + } + }; + + static void Menu_AddressBook_f() { + AddressBook_MenuInit(); + PushMenu(new xcommand_t() { + public void execute() { + AddressBook_MenuDraw_f(); + } + }, new keyfunc_t() { + public String execute(int key) { + return AddressBook_MenuKey_f(key); + } + }); + } + + /* + * ============================================================================= + * + * PLAYER CONFIG MENU + * + * ============================================================================= + */ + static menuframework_s s_player_config_menu = new menuframework_s(); + + static menufield_s s_player_name_field = new menufield_s(); + + static menulist_s s_player_model_box = new menulist_s(); + + static menulist_s s_player_skin_box = new menulist_s(); + + static menulist_s s_player_handedness_box = new menulist_s(); + + static menulist_s s_player_rate_box = new menulist_s(); + + static menuseparator_s s_player_skin_title = new menuseparator_s(); + + static menuseparator_s s_player_model_title = new menuseparator_s(); + + static menuseparator_s s_player_hand_title = new menuseparator_s(); + + static menuseparator_s s_player_rate_title = new menuseparator_s(); + + static menuaction_s s_player_download_action = new menuaction_s(); + + static class playermodelinfo_s { + int nskins; + + String skindisplaynames[]; + + //char displayname[MAX_DISPLAYNAME]; + String displayname; + + //char directory[MAX_QPATH]; + String directory; + }; + + static playermodelinfo_s s_pmi[] = new playermodelinfo_s[MAX_PLAYERMODELS]; + + static String s_pmnames[] = new String[MAX_PLAYERMODELS]; + + static int s_numplayermodels; + + static int rate_tbl[] = { 2500, 3200, 5000, 10000, 25000, 0 }; + + static String rate_names[] = { "28.8 Modem", "33.6 Modem", "Single ISDN", + "Dual ISDN/Cable", "T1/LAN", "User defined", null }; + + static void DownloadOptionsFunc(Object self) { + Menu_DownloadOptions_f(); + } + + static void HandednessCallback(Object unused) { + Cvar.SetValue("hand", s_player_handedness_box.curvalue); + } + + static void RateCallback(Object unused) { + if (s_player_rate_box.curvalue != rate_tbl.length - 1) //sizeof(rate_tbl) + // / sizeof(* + // rate_tbl) - 1) + Cvar.SetValue("rate", rate_tbl[s_player_rate_box.curvalue]); + } + + static void ModelCallback(Object unused) { + s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames; + s_player_skin_box.curvalue = 0; + } + + static boolean IconOfSkinExists(String skin, String pcxfiles[], + int npcxfiles) { + int i; + //char scratch[1024]; + String scratch; + + //strcpy(scratch, skin); + scratch = skin; + int pos = scratch.lastIndexOf('.'); + if (pos != -1) + scratch = scratch.substring(0, pos) + "_i.pcx"; + + else + scratch += "_i.pcx"; + + for (i = 0; i < npcxfiles; i++) { + if (Lib.strcmp(pcxfiles[i], scratch) == 0) + return true; + } + + return false; + } + + static boolean PlayerConfig_ScanDirectories() { + //char findname[1024]; + String findname; + //char scratch[1024]; + String scratch; + + int ndirs = 0, npms = 0; + int a, b, c; + String dirnames[]; + + String path = null; + + int i; + + //extern String * FS_ListFiles(String , int *, unsigned, unsigned); + + s_numplayermodels = 0; + + /* + * * get a list of directories + */ + do { + path = FS.NextPath(path); + findname = path + "/players/*.*"; + + if ((dirnames = FS.ListFiles(findname, 0, SFF_SUBDIR)) != null) { + ndirs = dirnames.length; + break; + } + } while (path != null); + + if (dirnames == null) + return false; + + /* + * * go through the subdirectories + */ + npms = ndirs; + if (npms > MAX_PLAYERMODELS) + npms = MAX_PLAYERMODELS; + + for (i = 0; i < npms; i++) { + int k, s; + //String a, b, c; + String pcxnames[]; + String skinnames[]; + int npcxfiles; + int nskins = 0; + + if (dirnames[i] == null) + continue; + + // verify the existence of tris.md2 + scratch = dirnames[i]; + scratch += "/tris.md2"; + if (Sys.FindFirst(scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM) == null) { + //free(dirnames[i]); + dirnames[i] = null; + Sys.FindClose(); + continue; + } + Sys.FindClose(); + + // verify the existence of at least one pcx skin + scratch = dirnames[i] + "/*.pcx"; + pcxnames = FS.ListFiles(scratch, 0, 0); + npcxfiles = pcxnames.length; + + if (pcxnames == null) { + + dirnames[i] = null; + continue; + } + + // count valid skins, which consist of a skin with a matching "_i" + // icon + for (k = 0; k < npcxfiles - 1; k++) { + if (!pcxnames[k].endsWith("_i.pcx")) { + //if (!strstr(pcxnames[k], "_i.pcx")) { + if (IconOfSkinExists(pcxnames[k], pcxnames, npcxfiles - 1)) { + nskins++; + } + } + } + if (nskins == 0) + continue; + + skinnames = new String[nskins + 1]; //malloc(sizeof(String) * + // (nskins + 1)); + //memset(skinnames, 0, sizeof(String) * (nskins + 1)); + + // copy the valid skins + for (s = 0, k = 0; k < npcxfiles - 1; k++) { + + if (pcxnames[k].indexOf("_i.pcx") < 0) { + if (IconOfSkinExists(pcxnames[k], pcxnames, npcxfiles - 1)) { + a = pcxnames[k].lastIndexOf('/'); + b = pcxnames[k].lastIndexOf('\\'); + + if (a > b) + c = a; + else + c = b; + + scratch = pcxnames[k].substring(c + 1, pcxnames[k] + .length()); + int pos = scratch.lastIndexOf('.'); + if (pos != -1) + scratch = scratch.substring(0, pos); + + skinnames[s] = scratch; + s++; + } + } + } + + // at this point we have a valid player model + if (s_pmi[s_numplayermodels] == null) + s_pmi[s_numplayermodels] = new playermodelinfo_s(); + + s_pmi[s_numplayermodels].nskins = nskins; + s_pmi[s_numplayermodels].skindisplaynames = skinnames; + + // make short name for the model + a = dirnames[i].lastIndexOf('/'); + b = dirnames[i].lastIndexOf('\\'); + + if (a > b) + c = a; + else + c = b; + + s_pmi[s_numplayermodels].displayname = dirnames[i].substring(c + 1); + s_pmi[s_numplayermodels].directory = dirnames[i].substring(c + 1); + + s_numplayermodels++; + } + + return true; + + } + + static int pmicmpfnc(Object _a, Object _b) { + playermodelinfo_s a = (playermodelinfo_s) _a; + playermodelinfo_s b = (playermodelinfo_s) _b; + + /* + * * sort by male, female, then alphabetical + */ + if (Lib.strcmp(a.directory, "male") == 0) + return -1; + else if (Lib.strcmp(b.directory, "male") == 0) + return 1; + + if (Lib.strcmp(a.directory, "female") == 0) + return -1; + else if (Lib.strcmp(b.directory, "female") == 0) + return 1; + + return Lib.strcmp(a.directory, b.directory); + } + + static String handedness[] = { "right", "left", "center", null }; + + static boolean PlayerConfig_MenuInit() { + /* + * extern cvar_t * name; extern cvar_t * team; extern cvar_t * skin; + */ + //har currentdirectory[1024]; + String currentdirectory; + //char currentskin[1024]; + String currentskin; + + int i = 0; + + int currentdirectoryindex = 0; + int currentskinindex = 0; + + cvar_t hand = Cvar.Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE); + + PlayerConfig_ScanDirectories(); + + if (s_numplayermodels == 0) + return false; + + if (hand.value < 0 || hand.value > 2) + Cvar.SetValue("hand", 0); + + currentdirectory = skin.string; + + if (currentdirectory.lastIndexOf('/') != -1) { + currentskin = Lib.rightFrom(currentdirectory, '/'); + currentdirectory = Lib.leftFrom(currentdirectory, '/'); + } else if (currentdirectory.lastIndexOf('\\') != -1) { + currentskin = Lib.rightFrom(currentdirectory, '\\'); + currentdirectory = Lib.leftFrom(currentdirectory, '\\'); + } else { + currentdirectory = "male"; + currentskin = "grunt"; + } + + //qsort(s_pmi, s_numplayermodels, sizeof(s_pmi[0]), pmicmpfnc); + Arrays.sort(s_pmi, 0, s_numplayermodels, new Comparator() { + public int compare(Object o1, Object o2) { + return pmicmpfnc(o1, o2); + } + }); + + //memset(s_pmnames, 0, sizeof(s_pmnames)); + s_pmnames = new String[MAX_PLAYERMODELS]; + + for (i = 0; i < s_numplayermodels; i++) { + s_pmnames[i] = s_pmi[i].displayname; + if (Lib.Q_stricmp(s_pmi[i].directory, currentdirectory) == 0) { + int j; + + currentdirectoryindex = i; + + for (j = 0; j < s_pmi[i].nskins; j++) { + if (Lib + .Q_stricmp(s_pmi[i].skindisplaynames[j], + currentskin) == 0) { + currentskinindex = j; + break; + } + } + } + } + + s_player_config_menu.x = viddef.width / 2 - 95; + s_player_config_menu.y = viddef.height / 2 - 97; + s_player_config_menu.nitems = 0; + + s_player_name_field.type = MTYPE_FIELD; + s_player_name_field.name = "name"; + s_player_name_field.callback = null; + s_player_name_field.x = 0; + s_player_name_field.y = 0; + s_player_name_field.length = 20; + s_player_name_field.visible_length = 20; + s_player_name_field.buffer = new StringBuffer(name.string); + s_player_name_field.cursor = name.string.length(); + + s_player_model_title.type = MTYPE_SEPARATOR; + s_player_model_title.name = "model"; + s_player_model_title.x = -8; + s_player_model_title.y = 60; + + s_player_model_box.type = MTYPE_SPINCONTROL; + s_player_model_box.x = -56; + s_player_model_box.y = 70; + s_player_model_box.callback = new mcallback() { + public void execute(Object o) { + ModelCallback(o); + } + }; + s_player_model_box.cursor_offset = -48; + s_player_model_box.curvalue = currentdirectoryindex; + s_player_model_box.itemnames = s_pmnames; + + s_player_skin_title.type = MTYPE_SEPARATOR; + s_player_skin_title.name = "skin"; + s_player_skin_title.x = -16; + s_player_skin_title.y = 84; + + s_player_skin_box.type = MTYPE_SPINCONTROL; + s_player_skin_box.x = -56; + s_player_skin_box.y = 94; + s_player_skin_box.name = null; + s_player_skin_box.callback = null; + s_player_skin_box.cursor_offset = -48; + s_player_skin_box.curvalue = currentskinindex; + s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames; + + s_player_hand_title.type = MTYPE_SEPARATOR; + s_player_hand_title.name = "handedness"; + s_player_hand_title.x = 32; + s_player_hand_title.y = 108; + + s_player_handedness_box.type = MTYPE_SPINCONTROL; + s_player_handedness_box.x = -56; + s_player_handedness_box.y = 118; + s_player_handedness_box.name = null; + s_player_handedness_box.cursor_offset = -48; + s_player_handedness_box.callback = new mcallback() { + public void execute(Object o) { + HandednessCallback(o); + } + }; + s_player_handedness_box.curvalue = (int) Cvar.VariableValue("hand"); + s_player_handedness_box.itemnames = handedness; + + for (i = 0; i < rate_tbl.length - 1; i++) + if (Cvar.VariableValue("rate") == rate_tbl[i]) + break; + + s_player_rate_title.type = MTYPE_SEPARATOR; + s_player_rate_title.name = "connect speed"; + s_player_rate_title.x = 56; + s_player_rate_title.y = 156; + + s_player_rate_box.type = MTYPE_SPINCONTROL; + s_player_rate_box.x = -56; + s_player_rate_box.y = 166; + s_player_rate_box.name = null; + s_player_rate_box.cursor_offset = -48; + s_player_rate_box.callback = new mcallback() { + public void execute(Object o) { + RateCallback(o); + } + }; + s_player_rate_box.curvalue = i; + s_player_rate_box.itemnames = rate_names; + + s_player_download_action.type = MTYPE_ACTION; + s_player_download_action.name = "download options"; + s_player_download_action.flags = QMF_LEFT_JUSTIFY; + s_player_download_action.x = -24; + s_player_download_action.y = 186; + s_player_download_action.statusbar = null; + s_player_download_action.callback = new mcallback() { + public void execute(Object o) { + DownloadOptionsFunc(o); + } + }; + + Menu_AddItem(s_player_config_menu, s_player_name_field); + Menu_AddItem(s_player_config_menu, s_player_model_title); + Menu_AddItem(s_player_config_menu, s_player_model_box); + if (s_player_skin_box.itemnames != null) { + Menu_AddItem(s_player_config_menu, s_player_skin_title); + Menu_AddItem(s_player_config_menu, s_player_skin_box); + } + Menu_AddItem(s_player_config_menu, s_player_hand_title); + Menu_AddItem(s_player_config_menu, s_player_handedness_box); + Menu_AddItem(s_player_config_menu, s_player_rate_title); + Menu_AddItem(s_player_config_menu, s_player_rate_box); + Menu_AddItem(s_player_config_menu, s_player_download_action); + + return true; + } + + static int yaw; + + static void PlayerConfig_MenuDraw() { + + refdef_t refdef = new refdef_t(); + //char scratch[MAX_QPATH]; + String scratch; + + //memset(refdef, 0, sizeof(refdef)); + + refdef.x = viddef.width / 2; + refdef.y = viddef.height / 2 - 72; + refdef.width = 144; + refdef.height = 168; + refdef.fov_x = 40; + refdef.fov_y = Math3D + .CalcFov(refdef.fov_x, refdef.width, refdef.height); + refdef.time = cls.realtime * 0.001f; + + if (s_pmi[s_player_model_box.curvalue].skindisplaynames != null) { + + int maxframe = 29; + entity_t entity = new entity_t(); + + //memset(entity, 0, sizeof(entity)); + + scratch = "players/" + s_pmi[s_player_model_box.curvalue].directory + + "/tris.md2"; + + entity.model = re.RegisterModel(scratch); + + scratch = "players/" + + s_pmi[s_player_model_box.curvalue].directory + + "/" + + s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] + + ".pcx"; + + entity.skin = re.RegisterSkin(scratch); + entity.flags = RF_FULLBRIGHT; + entity.origin[0] = 80; + entity.origin[1] = 0; + entity.origin[2] = 0; + Math3D.VectorCopy(entity.origin, entity.oldorigin); + entity.frame = 0; + entity.oldframe = 0; + entity.backlerp = 0.0f; + entity.angles[1] = yaw++; + if (++yaw > 360) + yaw -= 360; + + refdef.areabits = null; + refdef.num_entities = 1; + refdef.entities = new entity_t[] { entity }; + refdef.lightstyles = null; + refdef.rdflags = RDF_NOWORLDMODEL; + + Menu_Draw(s_player_config_menu); + + DrawTextBox( + (int) ((refdef.x) * (320.0F / viddef.width) - 8), + (int) ((viddef.height / 2) * (240.0F / viddef.height) - 77), + refdef.width / 8, refdef.height / 8); + refdef.height += 4; + + re.RenderFrame(refdef); + + scratch = "/players/" + + s_pmi[s_player_model_box.curvalue].directory + + "/" + + s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] + + "_i.pcx"; + + re.DrawPic(s_player_config_menu.x - 40, refdef.y, scratch); + } + } + + static String PlayerConfig_MenuKey(int key) { + int i; + + if (key == K_ESCAPE) { + //char scratch[1024]; + String scratch; + + Cvar.Set("name", s_player_name_field.buffer.toString()); + + scratch = s_pmi[s_player_model_box.curvalue].directory + + "/" + + s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue]; + + Cvar.Set("skin", scratch); + + for (i = 0; i < s_numplayermodels; i++) { + int j; + + for (j = 0; j < s_pmi[i].nskins; j++) { + if (s_pmi[i].skindisplaynames[j] != null) + s_pmi[i].skindisplaynames[j] = null; + } + s_pmi[i].skindisplaynames = null; + s_pmi[i].nskins = 0; + } + } + return Default_MenuKey(s_player_config_menu, key); + } + + static xcommand_t Menu_PlayerConfig = new xcommand_t() { + public void execute() { + Menu_PlayerConfig_f(); + } + }; + + static void Menu_PlayerConfig_f() { + if (!PlayerConfig_MenuInit()) { + Menu_SetStatusBar(s_multiplayer_menu, + "No valid player models found"); + return; + } + Menu_SetStatusBar(s_multiplayer_menu, null); + PushMenu(new xcommand_t() { + public void execute() { + PlayerConfig_MenuDraw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return PlayerConfig_MenuKey(key); + } + }); + } + + /* + * ======================================================================= + * + * QUIT MENU + * + * ======================================================================= + */ + + static String Quit_Key(int key) { + switch (key) { + case K_ESCAPE: + case 'n': + case 'N': + PopMenu(); + break; + + case 'Y': + case 'y': + cls.key_dest = key_console; + CL.Quit_f.execute(); + break; + + default: + break; + } + + return null; + + } + + static void Quit_Draw() { + int w, h; + Dimension d = new Dimension(); + re.DrawGetPicSize(d, "quit"); + w = d.width; + h = d.height; + re.DrawPic((viddef.width - w) / 2, (viddef.height - h) / 2, "quit"); + } + + static xcommand_t Menu_Quit = new xcommand_t() { + public void execute() { + Menu_Quit_f(); + } + }; + + static void Menu_Quit_f() { + PushMenu(new xcommand_t() { + public void execute() { + Quit_Draw(); + } + }, new keyfunc_t() { + public String execute(int key) { + return Quit_Key(key); + } + }); + } + + // ============================================================================= + /* Menu Subsystem */ + + /** + * Init + */ + public static void Init() { + Cmd.AddCommand("menu_main", Menu_Main); + Cmd.AddCommand("menu_game", Menu_Game); + Cmd.AddCommand("menu_loadgame", Menu_LoadGame); + Cmd.AddCommand("menu_savegame", Menu_SaveGame); + Cmd.AddCommand("menu_joinserver", Menu_JoinServer); + Cmd.AddCommand("menu_addressbook", Menu_AddressBook); + Cmd.AddCommand("menu_startserver", Menu_StartServer); + Cmd.AddCommand("menu_dmoptions", Menu_DMOptions); + Cmd.AddCommand("menu_playerconfig", Menu_PlayerConfig); + Cmd.AddCommand("menu_downloadoptions", Menu_DownloadOptions); + Cmd.AddCommand("menu_credits", Menu_Credits); + Cmd.AddCommand("menu_multiplayer", Menu_Multiplayer); + Cmd.AddCommand("menu_video", Menu_Video); + Cmd.AddCommand("menu_options", Menu_Options); + Cmd.AddCommand("menu_keys", Menu_Keys); + Cmd.AddCommand("menu_quit", Menu_Quit); + + for (int i = 0; i < m_layers.length; i++) { + m_layers[i] = new menulayer_t(); + } + } + + /* + * ================= Draw ================= + */ + static void Draw() { + if (cls.key_dest != key_menu) + return; + + // repaint everything next frame + SCR.DirtyScreen(); + + // dim everything behind it down + if (cl.cinematictime > 0) + re.DrawFill(0, 0, viddef.width, viddef.height, 0); + else + re.DrawFadeScreen(); + + m_drawfunc.execute(); + + // delay playing the enter sound until after the + // menu has been drawn, to avoid delay while + // caching images + if (m_entersound) { + S.StartLocalSound(menu_in_sound); + m_entersound = false; + } + } + + /* + * ================= Keydown ================= + */ + static void Keydown(int key) { + String s; + + if (m_keyfunc != null) + if ((s = m_keyfunc.execute(key)) != null) + S.StartLocalSound(s); + } + + public static void Action_DoEnter(menuaction_s a) { + if (a.callback != null) + a.callback.execute(a); + } + + public static void Action_Draw(menuaction_s a) { + if ((a.flags & QMF_LEFT_JUSTIFY) != 0) { + if ((a.flags & QMF_GRAYED) != 0) + Menu_DrawStringDark(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + + a.parent.y, a.name); + else + Menu_DrawString(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + + a.parent.y, a.name); + } else { + if ((a.flags & QMF_GRAYED) != 0) + Menu_DrawStringR2LDark(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + + a.parent.y, a.name); + else + Menu_DrawStringR2L(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + + a.parent.y, a.name); + } + if (a.ownerdraw != null) + a.ownerdraw.execute(a); + } + + public static boolean Field_DoEnter(menufield_s f) { + if (f.callback != null) { + f.callback.execute(f); + return true; + } + return false; + } + + public static void Field_Draw(menufield_s f) { + int i; + String tempbuffer; + //[128] = ""; + + if (f.name != null) + Menu_DrawStringR2LDark(f.x + f.parent.x + LCOLUMN_OFFSET, f.y + + f.parent.y, f.name); + + //strncpy(tempbuffer, f.buffer + f.visible_offset, f.visible_length); + String s = f.buffer.toString(); + tempbuffer = s.substring(f.visible_offset, s.length()); + re.DrawChar(f.x + f.parent.x + 16, f.y + f.parent.y - 4, 18); + re.DrawChar(f.x + f.parent.x + 16, f.y + f.parent.y + 4, 24); + + re.DrawChar(f.x + f.parent.x + 24 + f.visible_length * 8, f.y + + f.parent.y - 4, 20); + re.DrawChar(f.x + f.parent.x + 24 + f.visible_length * 8, f.y + + f.parent.y + 4, 26); + + for (i = 0; i < f.visible_length; i++) { + re + .DrawChar(f.x + f.parent.x + 24 + i * 8, f.y + f.parent.y + - 4, 19); + re + .DrawChar(f.x + f.parent.x + 24 + i * 8, f.y + f.parent.y + + 4, 25); + } + + Menu_DrawString(f.x + f.parent.x + 24, f.y + f.parent.y, tempbuffer); + + if (Menu_ItemAtCursor(f.parent) == f) { + int offset; + + if (f.visible_offset != 0) + offset = f.visible_length; + else + offset = f.cursor; + + if ((((int) (Sys.Milliseconds() / 250)) & 1) != 0) { + re.DrawChar(f.x + f.parent.x + (offset + 2) * 8 + 8, f.y + + f.parent.y, 11); + } else { + re.DrawChar(f.x + f.parent.x + (offset + 2) * 8 + 8, f.y + + f.parent.y, ' '); + } + } + } + + public static boolean Field_Key(menufield_s f, int k) { + char key = (char) k; + + switch (key) { + case K_KP_SLASH: + key = '/'; + break; + case K_KP_MINUS: + key = '-'; + break; + case K_KP_PLUS: + key = '+'; + break; + case K_KP_HOME: + key = '7'; + break; + case K_KP_UPARROW: + key = '8'; + break; + case K_KP_PGUP: + key = '9'; + break; + case K_KP_LEFTARROW: + key = '4'; + break; + case K_KP_5: + key = '5'; + break; + case K_KP_RIGHTARROW: + key = '6'; + break; + case K_KP_END: + key = '1'; + break; + case K_KP_DOWNARROW: + key = '2'; + break; + case K_KP_PGDN: + key = '3'; + break; + case K_KP_INS: + key = '0'; + break; + case K_KP_DEL: + key = '.'; + break; + } + + if (key > 127) { + switch (key) { + case K_DEL: + default: + return false; + } + } + + /* + * * support pasting from the clipboard + */ + if ((Character.toUpperCase(key) == 'V' && keydown[K_CTRL]) + || (((key == K_INS) || (key == K_KP_INS)) && keydown[K_SHIFT])) { + String cbd; + + if ((cbd = Sys.GetClipboardData()) != null) { + //strtok(cbd, "\n\r\b"); + String lines[] = Lib.linesplit(cbd); + if (lines.length > 0 && lines[0].length() != 0) { + //strncpy(f.buffer, cbd, f.length - 1); + f.buffer = new StringBuffer(lines[0]); + f.cursor = f.buffer.length(); + + f.visible_offset = f.cursor - f.visible_length; + + if (f.visible_offset < 0) + f.visible_offset = 0; + } + } + return true; + } + + switch (key) { + case K_KP_LEFTARROW: + case K_LEFTARROW: + case K_BACKSPACE: + if (f.cursor > 0) { + f.buffer.deleteCharAt(f.cursor - 1); + //memmove(f.buffer[f.cursor - 1], f.buffer[f.cursor], strlen(& + // f.buffer[f.cursor]) + 1); + f.cursor--; + + if (f.visible_offset != 0) { + f.visible_offset--; + } + } + break; + + case K_KP_DEL: + case K_DEL: + //memmove(& f.buffer[f.cursor], & f.buffer[f.cursor + 1], strlen(& + // f.buffer[f.cursor + 1]) + 1); + f.buffer.deleteCharAt(f.cursor); + break; + + case K_KP_ENTER: + case K_ENTER: + case K_ESCAPE: + case K_TAB: + return false; + + case K_SPACE: + default: + if (!Character.isDigit(key) && (f.flags & QMF_NUMBERSONLY) != 0) + return false; + + if (f.cursor < f.length) { + f.buffer.append(key); + f.cursor++; + + if (f.cursor > f.visible_length) { + f.visible_offset++; + } + } + } + + return true; + } + + public static void Menu_AddItem(menuframework_s menu, menucommon_s item) { + if (menu.nitems == 0) + menu.nslots = 0; + + if (menu.nitems < MAXMENUITEMS) { + menu.items[menu.nitems] = item; + ((menucommon_s) menu.items[menu.nitems]).parent = menu; + menu.nitems++; + } + + menu.nslots = Menu_TallySlots(menu); + } + + /* + * * Menu_AdjustCursor * * This function takes the given menu, the + * direction, and attempts * to adjust the menu's cursor so that it's at the + * next available * slot. + */ + public static void Menu_AdjustCursor(menuframework_s m, int dir) { + menucommon_s citem; + + /* + * * see if it's in a valid spot + */ + if (m.cursor >= 0 && m.cursor < m.nitems) { + if ((citem = Menu_ItemAtCursor(m)) != null) { + if (citem.type != MTYPE_SEPARATOR) + return; + } + } + + /* + * * it's not in a valid spot, so crawl in the direction indicated until + * we * find a valid spot + */ + if (dir == 1) { + while (true) { + citem = Menu_ItemAtCursor(m); + if (citem != null) + if (citem.type != MTYPE_SEPARATOR) + break; + m.cursor += dir; + if (m.cursor >= m.nitems) + m.cursor = 0; + } + } else { + while (true) { + citem = Menu_ItemAtCursor(m); + if (citem != null) + if (citem.type != MTYPE_SEPARATOR) + break; + m.cursor += dir; + if (m.cursor < 0) + m.cursor = m.nitems - 1; + } + } + } + + public static void Menu_Center(menuframework_s menu) { + int height; + + height = ((menucommon_s) menu.items[menu.nitems - 1]).y; + height += 10; + + menu.y = (viddef.height - height) / 2; + } + + public static void Menu_Draw(menuframework_s menu) { + int i; + menucommon_s item; + + /* + * * draw contents + */ + for (i = 0; i < menu.nitems; i++) { + switch (((menucommon_s) menu.items[i]).type) { + case MTYPE_FIELD: + Field_Draw((menufield_s) menu.items[i]); + break; + case MTYPE_SLIDER: + Slider_Draw((menuslider_s) menu.items[i]); + break; + case MTYPE_LIST: + MenuList_Draw((menulist_s) menu.items[i]); + break; + case MTYPE_SPINCONTROL: + SpinControl_Draw((menulist_s) menu.items[i]); + break; + case MTYPE_ACTION: + Action_Draw((menuaction_s) menu.items[i]); + break; + case MTYPE_SEPARATOR: + Separator_Draw((menuseparator_s) menu.items[i]); + break; + } + } + + item = Menu_ItemAtCursor(menu); + + if (item != null && item.cursordraw != null) { + item.cursordraw.execute(item); + } else if (menu.cursordraw != null) { + menu.cursordraw.execute(menu); + } else if (item != null && item.type != MTYPE_FIELD) { + if ((item.flags & QMF_LEFT_JUSTIFY) != 0) { + re.DrawChar(menu.x + item.x - 24 + item.cursor_offset, menu.y + + item.y, 12 + ((int) (Sys.Milliseconds() / 250) & 1)); + } else { + re.DrawChar(menu.x + item.cursor_offset, menu.y + item.y, + 12 + ((int) (Sys.Milliseconds() / 250) & 1)); + } + } + + if (item != null) { + if (item.statusbarfunc != null) + item.statusbarfunc.execute(item); + else if (item.statusbar != null) + Menu_DrawStatusBar(item.statusbar); + else + Menu_DrawStatusBar(menu.statusbar); + + } else { + Menu_DrawStatusBar(menu.statusbar); + } + } + + public static void Menu_DrawStatusBar(String string) { + if (string != null) { + int l = string.length(); + int maxrow = viddef.height / 8; + int maxcol = viddef.width / 8; + int col = maxcol / 2 - l / 2; + + re.DrawFill(0, viddef.height - 8, viddef.width, 8, 4); + Menu_DrawString(col * 8, viddef.height - 8, string); + } else { + re.DrawFill(0, viddef.height - 8, viddef.width, 8, 0); + } + } + + public static void Menu_DrawString(int x, int y, String string) { + int i; + + for (i = 0; i < string.length(); i++) { + re.DrawChar((x + i * 8), y, string.charAt(i)); + } + } + + public static void Menu_DrawStringDark(int x, int y, String string) { + int i; + + for (i = 0; i < string.length(); i++) { + re.DrawChar((x + i * 8), y, string.charAt(i) + 128); + } + } + + public static void Menu_DrawStringR2L(int x, int y, String string) { + int i; + + int l = string.length(); + for (i = 0; i < l; i++) { + re.DrawChar((x - i * 8), y, string.charAt(l - i - 1)); + } + } + + public static void Menu_DrawStringR2LDark(int x, int y, String string) { + int i; + + int l = string.length(); + for (i = 0; i < l; i++) { + re.DrawChar((x - i * 8), y, string.charAt(l - i - 1) + 128); + } + } + + public static menucommon_s Menu_ItemAtCursor(menuframework_s m) { + if (m.cursor < 0 || m.cursor >= m.nitems) + return null; + + return (menucommon_s) m.items[m.cursor]; + } + + static boolean Menu_SelectItem(menuframework_s s) { + menucommon_s item = Menu_ItemAtCursor(s); + + if (item != null) { + switch (item.type) { + case MTYPE_FIELD: + return Field_DoEnter((menufield_s) item); + case MTYPE_ACTION: + Action_DoEnter((menuaction_s) item); + return true; + case MTYPE_LIST: + // Menulist_DoEnter( ( menulist_s ) item ); + return false; + case MTYPE_SPINCONTROL: + // SpinControl_DoEnter( ( menulist_s ) item ); + return false; + } + } + return false; + } + + public static void Menu_SetStatusBar(menuframework_s m, String string) { + m.statusbar = string; + } + + public static void Menu_SlideItem(menuframework_s s, int dir) { + menucommon_s item = (menucommon_s) Menu_ItemAtCursor(s); + + if (item != null) { + switch (item.type) { + case MTYPE_SLIDER: + Slider_DoSlide((menuslider_s) item, dir); + break; + case MTYPE_SPINCONTROL: + SpinControl_DoSlide((menulist_s) item, dir); + break; + } + } + } + + public static int Menu_TallySlots(menuframework_s menu) { + int i; + int total = 0; + + for (i = 0; i < menu.nitems; i++) { + if (((menucommon_s) menu.items[i]).type == MTYPE_LIST) { + int nitems = 0; + String n[] = ((menulist_s) menu.items[i]).itemnames; + + while (n[nitems] != null) + nitems++; + + total += nitems; + } else { + total++; + } + } + + return total; + } + + public static void Menulist_DoEnter(menulist_s l) { + int start; + + start = l.y / 10 + 1; + + l.curvalue = l.parent.cursor - start; + + if (l.callback != null) + l.callback.execute(l); + } + + public static void MenuList_Draw(menulist_s l) { + String n[]; + int y = 0; + + Menu_DrawStringR2LDark(l.x + l.parent.x + LCOLUMN_OFFSET, l.y + + l.parent.y, l.name); + + n = l.itemnames; + + re.DrawFill(l.x - 112 + l.parent.x, l.parent.y + l.y + l.curvalue * 10 + + 10, 128, 10, 16); + int i = 0; + + while (n[i] != null) { + Menu_DrawStringR2LDark(l.x + l.parent.x + LCOLUMN_OFFSET, l.y + + l.parent.y + y + 10, n[i]); + + i++; + y += 10; + } + } + + public static void Separator_Draw(menuseparator_s s) { + if (s.name != null) + Menu_DrawStringR2LDark(s.x + s.parent.x, s.y + s.parent.y, s.name); + } + + public static void Slider_DoSlide(menuslider_s s, int dir) { + s.curvalue += dir; + + if (s.curvalue > s.maxvalue) + s.curvalue = s.maxvalue; + else if (s.curvalue < s.minvalue) + s.curvalue = s.minvalue; + + if (s.callback != null) + s.callback.execute(s); + } + + public static final int SLIDER_RANGE = 10; + + public static void Slider_Draw(menuslider_s s) { + int i; + + Menu_DrawStringR2LDark(s.x + s.parent.x + LCOLUMN_OFFSET, s.y + + s.parent.y, s.name); + + s.range = (s.curvalue - s.minvalue) / (float) (s.maxvalue - s.minvalue); + + if (s.range < 0) + s.range = 0; + if (s.range > 1) + s.range = 1; + re.DrawChar(s.x + s.parent.x + RCOLUMN_OFFSET, s.y + s.parent.y, 128); + for (i = 0; i < SLIDER_RANGE; i++) + re.DrawChar(RCOLUMN_OFFSET + s.x + i * 8 + s.parent.x + 8, s.y + + s.parent.y, 129); + re.DrawChar(RCOLUMN_OFFSET + s.x + i * 8 + s.parent.x + 8, s.y + + s.parent.y, 130); + re + .DrawChar( + (int) (8 + RCOLUMN_OFFSET + s.parent.x + s.x + (SLIDER_RANGE - 1) + * 8 * s.range), s.y + s.parent.y, 131); + } + + public static void SpinControl_DoEnter(menulist_s s) { + s.curvalue++; + if (s.itemnames[s.curvalue] == null) + s.curvalue = 0; + + if (s.callback != null) + s.callback.execute(s); + } + + public static void SpinControl_DoSlide(menulist_s s, int dir) { + s.curvalue += dir; + + if (s.curvalue < 0) + s.curvalue = 0; + else if (s.itemnames[s.curvalue] == null) + s.curvalue--; + + if (s.callback != null) + s.callback.execute(s); + } + + public static void SpinControl_Draw(menulist_s s) { + //char buffer[100]; + String buffer; + + if (s.name != null) { + Menu_DrawStringR2LDark(s.x + s.parent.x + LCOLUMN_OFFSET, s.y + + s.parent.y, s.name); + } + + if (s.itemnames[s.curvalue].indexOf('\n') == -1) { + Menu_DrawString(RCOLUMN_OFFSET + s.x + s.parent.x, + s.y + s.parent.y, s.itemnames[s.curvalue]); + } else { + String line1, line2; + line1 = Lib.leftFrom(s.itemnames[s.curvalue], '\n'); + Menu_DrawString(RCOLUMN_OFFSET + s.x + s.parent.x, + s.y + s.parent.y, line1); + + line2 = Lib.rightFrom(s.itemnames[s.curvalue], '\n'); + + int pos = line2.indexOf('\n'); + if (pos != -1) + line2 = line2.substring(0, pos); + + Menu_DrawString(RCOLUMN_OFFSET + s.x + s.parent.x, s.y + s.parent.y + + 10, line2); + } + } +} \ No newline at end of file diff --git a/src/jake2/client/SCR.java b/src/jake2/client/SCR.java index f92adcc..9ff5021 100644 --- a/src/jake2/client/SCR.java +++ b/src/jake2/client/SCR.java @@ -2,27 +2,27 @@ * SCR.java * Copyright (C) 2003 * - * $Id: SCR.java,v 1.7 2004-08-27 21:07:01 hzi Exp $ + * $Id: SCR.java,v 1.8 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; @@ -32,6 +32,7 @@ import jake2.game.cvar_t; import jake2.qcommon.*; import jake2.sound.*; import jake2.sys.Sys; +import jake2.util.Lib; import jake2.util.Vargs; import java.awt.Dimension; @@ -41,1971 +42,1954 @@ import java.awt.Dimension; */ public final class SCR extends Globals { - // cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc - - static String[][] sb_nums= - { { "num_0", "num_1", "num_2", "num_3", "num_4", "num_5", "num_6", "num_7", "num_8", "num_9", "num_minus" }, { - "anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5", "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus" } - }; - - /* - full screen console - put up loading plaque - blanked background with loading plaque - blanked background with menu - cinematics - full screen image for quit and victory - - end of unit intermissions - */ - - static float scr_con_current; // aproaches scr_conlines at scr_conspeed - static float scr_conlines; // 0.0 to 1.0 lines of console to display - - static boolean scr_initialized; // ready to draw - - static int scr_draw_loading; - - // scr_vrect ist in Globals definiert - // position of render window on screen - - static cvar_t scr_viewsize; - static cvar_t scr_conspeed; - static cvar_t scr_centertime; - static cvar_t scr_showturtle; - static cvar_t scr_showpause; - static cvar_t scr_printspeed; - - static cvar_t scr_netgraph; - static cvar_t scr_timegraph; - static cvar_t scr_debuggraph; - static cvar_t scr_graphheight; - static cvar_t scr_graphscale; - static cvar_t scr_graphshift; - static cvar_t scr_drawall; - public static cvar_t fps; - - static dirty_t scr_dirty= new dirty_t(); - static dirty_t[] scr_old_dirty= { new dirty_t(), new dirty_t()}; - - static String crosshair_pic; - static int crosshair_width, crosshair_height; - - static class dirty_t { - int x1; - int x2; - int y1; - int y2; - - void set(dirty_t src) { - x1= src.x1; - x2= src.x2; - y1= src.y1; - y2= src.y2; - } - - void clear() { - x1= x2= y1= y2= 0; - } - } - - /* - =============================================================================== - - BAR GRAPHS - - =============================================================================== - */ - - // typedef struct - // { - // float value; - // int color; - // } graphsamp_t; - static class graphsamp_t { - float value; - int color; - } - static int current; - static graphsamp_t[] values= new graphsamp_t[1024]; - - static { - for (int n= 0; n < 1024; n++) - values[n]= new graphsamp_t(); - } - - /* - ============== - SCR_DebugGraph - ============== - */ - public static void DebugGraph(float value, int color) { - values[current & 1023].value= value; - values[current & 1023].color= color; - current++; - } - - /* - ============== - SCR_DrawDebugGraph - ============== - */ - static void DrawDebugGraph() { - int a, x, y, w, i, h; - float v; - int color; - - // draw the graph - - w= scr_vrect.width; - - x= scr_vrect.x; - y= scr_vrect.y + scr_vrect.height; - re.DrawFill(x, (int) (y - scr_graphheight.value), w, (int) scr_graphheight.value, 8); - - for (a= 0; a < w; a++) { - i= (current - 1 - a + 1024) & 1023; - v= values[i].value; - color= values[i].color; - v= v * scr_graphscale.value + scr_graphshift.value; - - if (v < 0) - v += scr_graphheight.value * (1 + (int) (-v / scr_graphheight.value)); - h= (int) v % (int) scr_graphheight.value; - re.DrawFill(x + w - 1 - a, y - h, 1, h, color); - } - } - - /* - =============================================================================== - - CENTER PRINTING - - =============================================================================== - */ - - // char scr_centerstring[1024]; - static String scr_centerstring; - static float scr_centertime_start; // for slow victory printing - static float scr_centertime_off; - static int scr_center_lines; - static int scr_erase_center; - - /* - ============== - SCR_CenterPrint - - Called for important messages that should stay in the center of the screen - for a few moments - ============== - */ - static void CenterPrint(String str) { - //char *s; - int s; - StringBuffer line= new StringBuffer(64); - int i, j, l; - - //strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1); - scr_centerstring= str; - scr_centertime_off= scr_centertime.value; - scr_centertime_start= cl.time; - - // count the number of lines for centering - scr_center_lines= 1; - s= 0; - while (s < str.length()) { - if (str.charAt(s) == '\n') - scr_center_lines++; - s++; - } - - // echo it to the console - Com.Printf( - "\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); - - s= 0; - - if (str.length() != 0) { - do { - // scan the width of the line - - for (l= 0; l < 40 && (l + s) < str.length(); l++) - if (str.charAt(s + l) == '\n' || str.charAt(s + l) == 0) - break; - for (i= 0; i < (40 - l) / 2; i++) - line.append(' '); - - for (j= 0; j < l; j++) { - line.append(str.charAt(s + j)); - } - - line.append('\n'); - - Com.Printf(line.toString()); - - while (s < str.length() && str.charAt(s) != '\n') - s++; - - if (s == str.length()) - break; - s++; // skip the \n - } - while (true); - } - Com.Printf( - "\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); - Console.ClearNotify(); - } - - static void DrawCenterString() { - String cs= scr_centerstring + "\0"; - int start; - int l; - int j; - int x, y; - int remaining; - - if (cs == null) - return; - if (cs.length() == 0) - return; - - // the finale prints the characters one at a time - remaining= 9999; - - scr_erase_center= 0; - start= 0; - - if (scr_center_lines <= 4) - y= (int) (viddef.height * 0.35); - else - y= 48; - - do { - // scan the width of the line - for (l= 0; l < 40; l++) - if (start + l == cs.length() - 1 || cs.charAt(start + l) == '\n') - break; - x= (viddef.width - l * 8) / 2; - SCR.AddDirtyPoint(x, y); - for (j= 0; j < l; j++, x += 8) { - re.DrawChar(x, y, cs.charAt(start + j)); - if (remaining == 0) - return; - remaining--; - } - SCR.AddDirtyPoint(x, y + 8); - - y += 8; - - while (start < cs.length() && cs.charAt(start) != '\n') - start++; - - if (start == cs.length()) - break; - start++; // skip the \n - } - while (true); - } - - static void CheckDrawCenterString() { - scr_centertime_off -= cls.frametime; - - if (scr_centertime_off <= 0) - return; - - DrawCenterString(); - } - - // ============================================================================= - - /* - ================= - SCR_CalcVrect - - Sets scr_vrect, the coordinates of the rendered window - ================= - */ - static void CalcVrect() { - int size; - - // bound viewsize - if (scr_viewsize.value < 40) - Cvar.Set("viewsize", "40"); - if (scr_viewsize.value > 100) - Cvar.Set("viewsize", "100"); - - size= (int) scr_viewsize.value; - - scr_vrect.width= viddef.width * size / 100; - scr_vrect.width &= ~7; - - scr_vrect.height= viddef.height * size / 100; - scr_vrect.height &= ~1; - - scr_vrect.x= (viddef.width - scr_vrect.width) / 2; - scr_vrect.y= (viddef.height - scr_vrect.height) / 2; - } - - /* - ================= - SCR_SizeUp_f - - Keybinding command - ================= - */ - static void SizeUp_f() { - Cvar.SetValue("viewsize", scr_viewsize.value + 10); - } - - /* - ================= - SCR_SizeDown_f - - Keybinding command - ================= - */ - static void SizeDown_f() { - Cvar.SetValue("viewsize", scr_viewsize.value - 10); - } - - /* - ================= - SCR_Sky_f - - Set a specific sky and rotation speed - ================= - */ - static void Sky_f() { - float rotate; - float[] axis= { 0, 0, 0 }; - - if (Cmd.Argc() < 2) { - Com.Printf("Usage: sky \n"); - return; - } - if (Cmd.Argc() > 2) - rotate= Float.parseFloat(Cmd.Argv(2)); - else - rotate= 0; - if (Cmd.Argc() == 6) { - axis[0]= Float.parseFloat(Cmd.Argv(3)); - axis[1]= Float.parseFloat(Cmd.Argv(4)); - axis[2]= Float.parseFloat(Cmd.Argv(5)); - } - else { - axis[0]= 0; - axis[1]= 0; - axis[2]= 1; - } - - re.SetSky(Cmd.Argv(1), rotate, axis); - } - - // ============================================================================ - - /* - ================== - SCR_Init - ================== - */ - static void Init() { - scr_viewsize= Cvar.Get("viewsize", "100", CVAR_ARCHIVE); - scr_conspeed= Cvar.Get("scr_conspeed", "3", 0); - scr_showturtle= Cvar.Get("scr_showturtle", "0", 0); - scr_showpause= Cvar.Get("scr_showpause", "1", 0); - scr_centertime= Cvar.Get("scr_centertime", "2.5", 0); - scr_printspeed= Cvar.Get("scr_printspeed", "8", 0); - scr_netgraph= Cvar.Get("netgraph", "1", 0); - scr_timegraph= Cvar.Get("timegraph", "1", 0); - scr_debuggraph= Cvar.Get("debuggraph", "1", 0); - scr_graphheight= Cvar.Get("graphheight", "32", 0); - scr_graphscale= Cvar.Get("graphscale", "1", 0); - scr_graphshift= Cvar.Get("graphshift", "0", 0); - scr_drawall= Cvar.Get("scr_drawall", "1", 0); - fps= Cvar.Get("fps", "0", 0); - - // - // register our commands - // - Cmd.AddCommand("timerefresh", new xcommand_t() { - public void execute() { - TimeRefresh_f(); - } - }); - Cmd.AddCommand("loading", new xcommand_t() { - public void execute() { - Loading_f(); - } - }); - Cmd.AddCommand("sizeup", new xcommand_t() { - public void execute() { - SizeUp_f(); - } - }); - Cmd.AddCommand("sizedown", new xcommand_t() { - public void execute() { - SizeDown_f(); - } - }); - Cmd.AddCommand("sky", new xcommand_t() { - public void execute() { - Sky_f(); - } - }); - - scr_initialized= true; - } - - /* - ============== - SCR_DrawNet - ============== - */ - static void DrawNet() { - if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged < CMD_BACKUP - 1) - return; - - re.DrawPic(scr_vrect.x + 64, scr_vrect.y, "net"); - } - - /* - ============== - SCR_DrawPause - ============== - */ - static void DrawPause() { - Dimension dim= new Dimension(); - - if (scr_showpause.value == 0) // turn off for screenshots - return; - - if (cl_paused.value == 0) - return; - - re.DrawGetPicSize(dim, "pause"); - re.DrawPic((viddef.width - dim.width) / 2, viddef.height / 2 + 8, "pause"); - } - - /* - ============== - SCR_DrawLoading - ============== - */ - static void DrawLoading() { - Dimension dim= new Dimension(); - - if (scr_draw_loading == 0) - return; - - scr_draw_loading= 0; - re.DrawGetPicSize(dim, "loading"); - re.DrawPic((viddef.width - dim.width) / 2, (viddef.height - dim.height) / 2, "loading"); - } - - // ============================================================================= - - /* - ================== - SCR_RunConsole - - Scroll it up or down - ================== - */ - static void RunConsole() { - // decide on the height of the console - if (cls.key_dest == key_console) - scr_conlines= 0.5f; // half screen - else - scr_conlines= 0; // none visible - - if (scr_conlines < scr_con_current) { - scr_con_current -= scr_conspeed.value * cls.frametime; - if (scr_conlines > scr_con_current) - scr_con_current= scr_conlines; - - } - else if (scr_conlines > scr_con_current) { - scr_con_current += scr_conspeed.value * cls.frametime; - if (scr_conlines < scr_con_current) - scr_con_current= scr_conlines; - } - } - - /* - ================== - SCR_DrawConsole - ================== - */ - static void DrawConsole() { - Console.CheckResize(); - - if (cls.state == ca_disconnected || cls.state == ca_connecting) { // forced full screen console - Console.DrawConsole(1.0f); - return; - } - - if (cls.state != ca_active || !cl.refresh_prepped) { // connected, but can't render - Console.DrawConsole(0.5f); - re.DrawFill(0, viddef.height / 2, viddef.width, viddef.height / 2, 0); - return; - } - - if (scr_con_current != 0) { - Console.DrawConsole(scr_con_current); - } - else { - if (cls.key_dest == key_game || cls.key_dest == key_message) - Console.DrawNotify(); // only draw notify in game - } - } - - // ============================================================================= - - /* - ================ - SCR_BeginLoadingPlaque - ================ - */ - public static void BeginLoadingPlaque() { - S.StopAllSounds(); - cl.sound_prepped= false; // don't play ambients - - if (cls.disable_screen != 0) - return; - if (developer.value != 0) - return; - if (cls.state == ca_disconnected) - return; // if at console, don't bring up the plaque - if (cls.key_dest == key_console) - return; - if (cl.cinematictime > 0) - scr_draw_loading= 2; // clear to balack first - else - scr_draw_loading= 1; - - UpdateScreen(); - cls.disable_screen= Sys.Milliseconds(); - cls.disable_servercount= cl.servercount; - } - - /* - ================ - SCR_EndLoadingPlaque - ================ - */ - public static void EndLoadingPlaque() { - cls.disable_screen= 0; - Console.ClearNotify(); - } - - /* - ================ - SCR_Loading_f - ================ - */ - static void Loading_f() { - BeginLoadingPlaque(); - } - - /* - ================ - SCR_TimeRefresh_f - ================ - */ - static void TimeRefresh_f() { - int i; - int start, stop; - float time; - - if (cls.state != ca_active) - return; - - start= Sys.Milliseconds(); - - if (Cmd.Argc() == 2) { // run without page flipping - re.BeginFrame(0); - for (i= 0; i < 128; i++) { - cl.refdef.viewangles[1]= i / 128.0f * 360.0f; - re.RenderFrame(cl.refdef); - } - re.EndFrame(); - } - else { - for (i= 0; i < 128; i++) { - cl.refdef.viewangles[1]= i / 128.0f * 360.0f; - - re.BeginFrame(0); - re.RenderFrame(cl.refdef); - re.EndFrame(); - } - } - - stop= Sys.Milliseconds(); - time= (stop - start) / 1000.0f; - Com.Printf("%f seconds (%f fps)\n", new Vargs(2).add(time).add(128.0f / time)); - } - - static void DirtyScreen() { - AddDirtyPoint(0, 0); - AddDirtyPoint(viddef.width - 1, viddef.height - 1); - } - - /* - ============== - SCR_TileClear - - Clear any parts of the tiled background that were drawn on last frame - ============== - */ - - static dirty_t clear= new dirty_t(); - - static void TileClear() { - int i; - int top, bottom, left, right; - clear.clear(); - - if (scr_drawall.value != 0) - DirtyScreen(); // for power vr or broken page flippers... - - if (scr_con_current == 1.0f) - return; // full screen console - if (scr_viewsize.value == 100) - return; // full screen rendering - if (cl.cinematictime > 0) - return; // full screen cinematic - - // erase rect will be the union of the past three frames - // so tripple buffering works properly - clear.set(scr_dirty); - for (i= 0; i < 2; i++) { - if (scr_old_dirty[i].x1 < clear.x1) - clear.x1= scr_old_dirty[i].x1; - if (scr_old_dirty[i].x2 > clear.x2) - clear.x2= scr_old_dirty[i].x2; - if (scr_old_dirty[i].y1 < clear.y1) - clear.y1= scr_old_dirty[i].y1; - if (scr_old_dirty[i].y2 > clear.y2) - clear.y2= scr_old_dirty[i].y2; - } - - scr_old_dirty[1].set(scr_old_dirty[0]); - scr_old_dirty[0].set(scr_dirty); - - scr_dirty.x1= 9999; - scr_dirty.x2= -9999; - scr_dirty.y1= 9999; - scr_dirty.y2= -9999; - - // don't bother with anything convered by the console) - top= (int) (scr_con_current * viddef.height); - if (top >= clear.y1) - clear.y1= top; - - if (clear.y2 <= clear.y1) - return; // nothing disturbed - - top= scr_vrect.y; - bottom= top + scr_vrect.height - 1; - left= scr_vrect.x; - right= left + scr_vrect.width - 1; - - if (clear.y1 < top) { // clear above view screen - i= clear.y2 < top - 1 ? clear.y2 : top - 1; - re.DrawTileClear(clear.x1, clear.y1, clear.x2 - clear.x1 + 1, i - clear.y1 + 1, "backtile"); - clear.y1= top; - } - if (clear.y2 > bottom) { // clear below view screen - i= clear.y1 > bottom + 1 ? clear.y1 : bottom + 1; - re.DrawTileClear(clear.x1, i, clear.x2 - clear.x1 + 1, clear.y2 - i + 1, "backtile"); - clear.y2= bottom; - } - if (clear.x1 < left) { // clear left of view screen - i= clear.x2 < left - 1 ? clear.x2 : left - 1; - re.DrawTileClear(clear.x1, clear.y1, i - clear.x1 + 1, clear.y2 - clear.y1 + 1, "backtile"); - clear.x1= left; - } - if (clear.x2 > right) { // clear left of view screen - i= clear.x1 > right + 1 ? clear.x1 : right + 1; - re.DrawTileClear(i, clear.y1, clear.x2 - i + 1, clear.y2 - clear.y1 + 1, "backtile"); - clear.x2= right; - } - - } - - // =============================================================== - - static final int STAT_MINUS= 10; // num frame for '-' stats digit - - static final int ICON_WIDTH= 24; - static final int ICON_HEIGHT= 24; - static final int CHAR_WIDTH= 16; - static final int ICON_SPACE= 8; - - /* - ================ - SizeHUDString - - Allow embedded \n in the string - ================ - */ - static void SizeHUDString(String string, Dimension dim) { - int lines, width, current; - - lines= 1; - width= 0; - - current= 0; - for (int i= 0; i < string.length(); i++) { - if (string.charAt(i) == '\n') { - lines++; - current= 0; - } - else { - current++; - if (current > width) - width= current; - } - - } - - dim.width= width * 8; - dim.height= lines * 8; - } - - static void DrawHUDString(String string, int x, int y, int centerwidth, int xor) { - int margin; - //char line[1024]; - StringBuffer line= new StringBuffer(1024); - int i; - - margin= x; - - for (int l= 0; l < string.length();) { - // scan out one line of text from the string - line= new StringBuffer(1024); - while (l < string.length() && string.charAt(l) != '\n') { - line.append(string.charAt(l)); - l++; - } - - if (centerwidth != 0) - x= margin + (centerwidth - line.length() * 8) / 2; - else - x= margin; - for (i= 0; i < line.length(); i++) { - re.DrawChar(x, y, line.charAt(i) ^ xor); - x += 8; - } - if (l < string.length()) { - l++; // skip the \n - x= margin; - y += 8; - } - } - } - - /* - ============== - SCR_DrawField - ============== - */ - static void DrawField(int x, int y, int color, int width, int value) { - char ptr; - String num; - int l; - int frame; - - if (width < 1) - return; - - // draw number string - if (width > 5) - width= 5; - - AddDirtyPoint(x, y); - AddDirtyPoint(x + width * CHAR_WIDTH + 2, y + 23); - - num= "" + value; - l= num.length(); - if (l > width) - l= width; - x += 2 + CHAR_WIDTH * (width - l); - - ptr= num.charAt(0); - - for (int i= 0; i < l; i++) { - ptr= num.charAt(i); - if (ptr == '-') - frame= STAT_MINUS; - else - frame= ptr - '0'; - - re.DrawPic(x, y, sb_nums[color][frame]); - x += CHAR_WIDTH; - } - } - - /* - =============== - SCR_TouchPics - - Allows rendering code to cache all needed sbar graphics - =============== - */ - static void TouchPics() { - int i, j; - - for (i= 0; i < 2; i++) - for (j= 0; j < 11; j++) - re.RegisterPic(sb_nums[i][j]); - - if (crosshair.value != 0.0f) { - if (crosshair.value > 3.0f || crosshair.value < 0.0f) - crosshair.value= 3.0f; - - crosshair_pic= "ch" + (int) crosshair.value; - Dimension dim= new Dimension(); - re.DrawGetPicSize(dim, crosshair_pic); - crosshair_width= dim.width; - crosshair_height= dim.height; - if (crosshair_width == 0) - crosshair_pic= ""; - } - } - - /* - ================ - SCR_ExecuteLayoutString - - ================ - */ - static void ExecuteLayoutString(String s) { - int x, y; - int value; - String token; - int width; - int index; - clientinfo_t ci; - - if (cls.state != ca_active || !cl.refresh_prepped) - return; - - // if (!s[0]) - if (s == null || s.length() == 0) - return; - - x= 0; - y= 0; - width= 3; - - Com.ParseHelp ph= new Com.ParseHelp(s); - - while (!ph.isEof()) { - token= Com.Parse(ph); - if (token.equals("xl")) { - token= Com.Parse(ph); - x= atoi(token); - continue; - } - if (token.equals("xr")) { - token= Com.Parse(ph); - x= viddef.width + atoi(token); - continue; - } - if (token.equals("xv")) { - token= Com.Parse(ph); - x= viddef.width / 2 - 160 + atoi(token); - continue; - } - - if (token.equals("yt")) { - token= Com.Parse(ph); - y= atoi(token); - continue; - } - if (token.equals("yb")) { - token= Com.Parse(ph); - y= viddef.height + atoi(token); - continue; - } - if (token.equals("yv")) { - token= Com.Parse(ph); - y= viddef.height / 2 - 120 + atoi(token); - continue; - } - - if (token.equals("pic")) { // draw a pic from a stat number - token= Com.Parse(ph); - value= cl.frame.playerstate.stats[atoi(token)]; - if (value >= MAX_IMAGES) - Com.Error(ERR_DROP, "Pic >= MAX_IMAGES"); - if (cl.configstrings[CS_IMAGES + value] != null) { - AddDirtyPoint(x, y); - AddDirtyPoint(x + 23, y + 23); - re.DrawPic(x, y, cl.configstrings[CS_IMAGES + value]); - } - continue; - } - - if (token.equals("client")) { // draw a deathmatch client block - int score, ping, time; - - token= Com.Parse(ph); - x= viddef.width / 2 - 160 + atoi(token); - token= Com.Parse(ph); - y= viddef.height / 2 - 120 + atoi(token); - AddDirtyPoint(x, y); - AddDirtyPoint(x + 159, y + 31); - - token= Com.Parse(ph); - value= atoi(token); - if (value >= MAX_CLIENTS || value < 0) - Com.Error(ERR_DROP, "client >= MAX_CLIENTS"); - ci= cl.clientinfo[value]; - - token= Com.Parse(ph); - score= atoi(token); - - token= Com.Parse(ph); - ping= atoi(token); - - token= Com.Parse(ph); - time= atoi(token); - - Console.DrawAltString(x + 32, y, ci.name); - Console.DrawString(x + 32, y + 8, "Score: "); - Console.DrawAltString(x + 32 + 7 * 8, y + 8, "" + score); - Console.DrawString(x + 32, y + 16, "Ping: " + ping); - Console.DrawString(x + 32, y + 24, "Time: " + time); - - if (ci.icon == null) - ci= cl.baseclientinfo; - re.DrawPic(x, y, ci.iconname); - continue; - } - - if (token.equals("ctf")) { // draw a ctf client block - int score, ping; - - token= Com.Parse(ph); - x= viddef.width / 2 - 160 + atoi(token); - token= Com.Parse(ph); - y= viddef.height / 2 - 120 + atoi(token); - AddDirtyPoint(x, y); - AddDirtyPoint(x + 159, y + 31); - - token= Com.Parse(ph); - value= atoi(token); - if (value >= MAX_CLIENTS || value < 0) - Com.Error(ERR_DROP, "client >= MAX_CLIENTS"); - ci= cl.clientinfo[value]; - - token= Com.Parse(ph); - score= atoi(token); - - token= Com.Parse(ph); - ping= atoi(token); - if (ping > 999) - ping= 999; - - // sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name); - String block= Com.sprintf("%3d %3d %-12.12s", new Vargs(3).add(score).add(ping).add(ci.name)); - - if (value == cl.playernum) - Console.DrawAltString(x, y, block); - else - Console.DrawString(x, y, block); - continue; - } - - if (token.equals("picn")) { // draw a pic from a name - token= Com.Parse(ph); - AddDirtyPoint(x, y); - AddDirtyPoint(x + 23, y + 23); - re.DrawPic(x, y, token); - continue; - } - - if (token.equals("num")) { // draw a number - token= Com.Parse(ph); - width= atoi(token); - token= Com.Parse(ph); - value= cl.frame.playerstate.stats[atoi(token)]; - DrawField(x, y, 0, width, value); - continue; - } - - if (token.equals("hnum")) { // health number - int color; - - width= 3; - value= cl.frame.playerstate.stats[STAT_HEALTH]; - if (value > 25) - color= 0; // green - else if (value > 0) - color= (cl.frame.serverframe >> 2) & 1; // flash - else - color= 1; - - if ((cl.frame.playerstate.stats[STAT_FLASHES] & 1) != 0) - re.DrawPic(x, y, "field_3"); - - DrawField(x, y, color, width, value); - continue; - } - - if (token.equals("anum")) { // ammo number - int color; - - width= 3; - value= cl.frame.playerstate.stats[STAT_AMMO]; - if (value > 5) - color= 0; // green - else if (value >= 0) - color= (cl.frame.serverframe >> 2) & 1; // flash - else - continue; // negative number = don't show - - if ((cl.frame.playerstate.stats[STAT_FLASHES] & 4) != 0) - re.DrawPic(x, y, "field_3"); - - DrawField(x, y, color, width, value); - continue; - } - - if (token.equals("rnum")) { // armor number - int color; - - width= 3; - value= cl.frame.playerstate.stats[STAT_ARMOR]; - if (value < 1) - continue; - - color= 0; // green - - if ((cl.frame.playerstate.stats[STAT_FLASHES] & 2) != 0) - re.DrawPic(x, y, "field_3"); - - DrawField(x, y, color, width, value); - continue; - } - - if (token.equals("stat_string")) { - token= Com.Parse(ph); - index= atoi(token); - if (index < 0 || index >= MAX_CONFIGSTRINGS) - Com.Error(ERR_DROP, "Bad stat_string index"); - index= cl.frame.playerstate.stats[index]; - if (index < 0 || index >= MAX_CONFIGSTRINGS) - Com.Error(ERR_DROP, "Bad stat_string index"); - Console.DrawString(x, y, cl.configstrings[index]); - continue; - } - - if (token.equals("cstring")) { - token= Com.Parse(ph); - DrawHUDString(token, x, y, 320, 0); - continue; - } - - if (token.equals("string")) { - token= Com.Parse(ph); - Console.DrawString(x, y, token); - continue; - } - - if (token.equals("cstring2")) { - token= Com.Parse(ph); - DrawHUDString(token, x, y, 320, 0x80); - continue; - } - - if (token.equals("string2")) { - token= Com.Parse(ph); - Console.DrawAltString(x, y, token); - continue; - } - - if (token.equals("if")) { // draw a number - token= Com.Parse(ph); - value= cl.frame.playerstate.stats[atoi(token)]; - if (value == 0) { // skip to endif - // while (s && strcmp(token, "endif") ) - // { - // token = Com.Parse(ph); - // } - - while (!ph.isEof() && !(token= Com.Parse(ph)).equals("endif")); - - } - - continue; - } - - } - } - - /* - ================ - SCR_DrawStats - - The status bar is a small layout program that - is based on the stats array - ================ - */ - static void DrawStats() { - //TODO: - SCR.ExecuteLayoutString(cl.configstrings[CS_STATUSBAR]); - } - - /* - ================ - SCR_DrawLayout - - ================ - */ - static final int STAT_LAYOUTS= 13; - - static void DrawLayout() { - if (cl.frame.playerstate.stats[STAT_LAYOUTS] != 0) - SCR.ExecuteLayoutString(cl.layout); - } - - // ======================================================= - - /* - ================== - SCR_UpdateScreen - - This is called every frame, and can also be called explicitly to flush - text to the screen. - ================== - */ - static void UpdateScreen2() { - int numframes; - int i; - float[] separation= { 0, 0 }; - - // if the screen is disabled (loading plaque is up, or vid mode changing) - // do nothing at all - if (cls.disable_screen != 0) { - if (Sys.Milliseconds() - cls.disable_screen > 120000) { - cls.disable_screen= 0; - Com.Printf("Loading plaque timed out.\n"); - } - return; - } - - if (!scr_initialized || !con.initialized) - return; // not initialized yet - - /* - ** range check cl_camera_separation so we don't inadvertently fry someone's - ** brain - */ - if (cl_stereo_separation.value > 1.0) - Cvar.SetValue("cl_stereo_separation", 1.0f); - else if (cl_stereo_separation.value < 0) - Cvar.SetValue("cl_stereo_separation", 0.0f); - - if (cl_stereo.value != 0) { - numframes= 2; - separation[0]= -cl_stereo_separation.value / 2; - separation[1]= cl_stereo_separation.value / 2; - } - else { - separation[0]= 0; - separation[1]= 0; - numframes= 1; - } - - for (i= 0; i < numframes; i++) { - re.BeginFrame(separation[i]); - - if (scr_draw_loading == 2) { // loading plaque over black screen - Dimension dim= new Dimension(); - - re.CinematicSetPalette(null); - scr_draw_loading= 0; // false - re.DrawGetPicSize(dim, "loading"); - re.DrawPic((viddef.width - dim.width) / 2, (viddef.height - dim.height) / 2, "loading"); - } - // if a cinematic is supposed to be running, handle menus - // and console specially - else if (cl.cinematictime > 0) { - if (cls.key_dest == key_menu) { - if (cl.cinematicpalette_active) { - re.CinematicSetPalette(null); - cl.cinematicpalette_active= false; - } - Menu.Draw(); - } - else if (cls.key_dest == key_console) { - if (cl.cinematicpalette_active) { - re.CinematicSetPalette(null); - cl.cinematicpalette_active= false; - } - DrawConsole(); - } - else { - // TODO impl: cl_cin.c for cinematics - DrawCinematic(); - } - } - else { - // make sure the game palette is active - if (cl.cinematicpalette_active) { - re.CinematicSetPalette(null); - cl.cinematicpalette_active= false; - } - - // do 3D refresh drawing, and then update the screen - CalcVrect(); - - // clear any dirty part of the background - TileClear(); - - V.RenderView(separation[i]); - - DrawStats(); - - if ((cl.frame.playerstate.stats[STAT_LAYOUTS] & 1) != 0) - DrawLayout(); - if ((cl.frame.playerstate.stats[STAT_LAYOUTS] & 2) != 0) - CL.DrawInventory(); - - DrawNet(); - CheckDrawCenterString(); - DrawFPS(); - - // - // if (scr_timegraph->value) - // SCR_DebugGraph (cls.frametime*300, 0); - // - // if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value) - // SCR_DrawDebugGraph (); - // - DrawPause(); - DrawConsole(); - Menu.Draw(); - DrawLoading(); - } - } - - Globals.re.EndFrame(); - } - - /* - ================= - SCR_DrawCrosshair - ================= - */ - static void DrawCrosshair() { - if (crosshair.value == 0.0f) - return; - - if (crosshair.modified) { - crosshair.modified= false; - SCR.TouchPics(); - } - - if (crosshair_pic.length() == 0) - return; - - re.DrawPic( - scr_vrect.x + ((scr_vrect.width - crosshair_width) >> 1), - scr_vrect.y + ((scr_vrect.height - crosshair_height) >> 1), - crosshair_pic); - } - - private static xcommand_t updateScreenCallback= new xcommand_t() { - public void execute() { - UpdateScreen2(); - } - }; - - // wird anstelle von der richtigen UpdateScreen benoetigt - public static void UpdateScreen() { - Globals.re.updateScreen(updateScreenCallback); - } - - /* - ================= - SCR_AddDirtyPoint - ================= - */ - static void AddDirtyPoint(int x, int y) { - if (x < scr_dirty.x1) - scr_dirty.x1= x; - if (x > scr_dirty.x2) - scr_dirty.x2= x; - if (y < scr_dirty.y1) - scr_dirty.y1= y; - if (y > scr_dirty.y2) - scr_dirty.y2= y; - } - - private static int lastframes= 0; - private static int lasttime= 0; - private static String fpsvalue= ""; - - static void DrawFPS() { - if (fps.value > 0.0f) { - if (fps.modified) { - fps.modified= false; - Cvar.SetValue("cl_maxfps", 1000); - } - - int diff= cls.realtime - lasttime; - if (diff > (int) (fps.value * 1000)) { - fpsvalue= (cls.framecount - lastframes) * 100000 / diff / 100.0f + " fps"; - lastframes= cls.framecount; - lasttime= cls.realtime; - } - int x= viddef.width - 8 * fpsvalue.length() - 2; - for (int i= 0; i < fpsvalue.length(); i++) { - re.DrawChar(x, 2, fpsvalue.charAt(i)); - x += 8; - } - } - else if (fps.modified) { - fps.modified= false; - Cvar.SetValue("cl_maxfps", 90); - } - } - - /* - ================================================================= - - cl_cin.c - - Play Cinematics - - ================================================================= - */ - - // typedef struct - // { - // byte *data; - // int count; - // } cblock_t; - // - // typedef struct - // { - // qboolean restart_sound; - // int s_rate; - // int s_width; - // int s_channels; - // - // int width; - // int height; - // byte *pic; - // byte *pic_pending; - // - // // order 1 huffman stuff - // int *hnodes1; // [256][256][2]; - // int numhnodes1[256]; - // - // int h_used[512]; - // int h_count[512]; - // } cinematics_t; - // - // cinematics_t cin; - // - // /* - // ================================================================= - // - // PCX LOADING - // - // ================================================================= - // */ - // - // - // /* - // ============== - // SCR_LoadPCX - // ============== - // */ - // void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height) - // { - // byte *raw; - // pcx_t *pcx; - // int x, y; - // int len; - // int dataByte, runLength; - // byte *out, *pix; - // - // *pic = NULL; - // - // // - // // load the file - // // - // len = FS_LoadFile (filename, (void **)&raw); - // if (!raw) - // return; // Com_Printf ("Bad pcx file %s\n", filename); - // - // // - // // parse the PCX file - // // - // pcx = (pcx_t *)raw; - // raw = &pcx->data; - // - // if (pcx->manufacturer != 0x0a - // || pcx->version != 5 - // || pcx->encoding != 1 - // || pcx->bits_per_pixel != 8 - // || pcx->xmax >= 640 - // || pcx->ymax >= 480) - // { - // Com_Printf ("Bad pcx file %s\n", filename); - // return; - // } - // - // out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); - // - // *pic = out; - // - // pix = out; - // - // if (palette) - // { - // *palette = Z_Malloc(768); - // memcpy (*palette, (byte *)pcx + len - 768, 768); - // } - // - // if (width) - // *width = pcx->xmax+1; - // if (height) - // *height = pcx->ymax+1; - // - // for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) - // { - // for (x=0 ; x<=pcx->xmax ; ) - // { - // dataByte = *raw++; - // - // if((dataByte & 0xC0) == 0xC0) - // { - // runLength = dataByte & 0x3F; - // dataByte = *raw++; - // } - // else - // runLength = 1; - // - // while(runLength-- > 0) - // pix[x++] = dataByte; - // } - // - // } - // - // if ( raw - (byte *)pcx > len) - // { - // Com_Printf ("PCX file %s was malformed", filename); - // Z_Free (*pic); - // *pic = NULL; - // } - // - // FS_FreeFile (pcx); - // } - // - // ============================================================= - - /* - ================== - SCR_StopCinematic - ================== - */ - static void StopCinematic() { - cl.cinematictime= 0; // done - // if (cin.pic) - // { - // Z_Free (cin.pic); - // cin.pic = NULL; - // } - // if (cin.pic_pending) - // { - // Z_Free (cin.pic_pending); - // cin.pic_pending = NULL; - // } - if (cl.cinematicpalette_active) { - re.CinematicSetPalette(null); - cl.cinematicpalette_active= false; - } - // if (cl.cinematic_file) - // { - // fclose (cl.cinematic_file); - // cl.cinematic_file = NULL; - // } - // if (cin.hnodes1) - // { - // Z_Free (cin.hnodes1); - // cin.hnodes1 = NULL; - // } - // - // // switch back down to 11 khz sound if necessary - // if (cin.restart_sound) - // { - // cin.restart_sound = false; - // CL_Snd_Restart_f (); - // } - // - } - - /* - ==================== - SCR_FinishCinematic - - Called when either the cinematic completes, or it is aborted - ==================== - */ - static void FinishCinematic() { - // tell the server to advance to the next map / cinematic - MSG.WriteByte(cls.netchan.message, clc_stringcmd); - SZ.Print(cls.netchan.message, "nextserver " + cl.servercount + '\n'); - } - - // ========================================================================== - - // /* - // ================== - // SmallestNode1 - // ================== - // */ - // int SmallestNode1 (int numhnodes) - // { - // int i; - // int best, bestnode; - // - // best = 99999999; - // bestnode = -1; - // for (i=0 ; i>=1; - // //----------- - // if (nodenum < 256) - // { - // hnodes = hnodesbase + (nodenum<<9); - // *out_p++ = nodenum; - // if (!--count) - // break; - // nodenum = cin.numhnodes1[nodenum]; - // } - // nodenum = hnodes[nodenum*2 + (inbyte&1)]; - // inbyte >>=1; - // //----------- - // if (nodenum < 256) - // { - // hnodes = hnodesbase + (nodenum<<9); - // *out_p++ = nodenum; - // if (!--count) - // break; - // nodenum = cin.numhnodes1[nodenum]; - // } - // nodenum = hnodes[nodenum*2 + (inbyte&1)]; - // inbyte >>=1; - // //----------- - // if (nodenum < 256) - // { - // hnodes = hnodesbase + (nodenum<<9); - // *out_p++ = nodenum; - // if (!--count) - // break; - // nodenum = cin.numhnodes1[nodenum]; - // } - // nodenum = hnodes[nodenum*2 + (inbyte&1)]; - // inbyte >>=1; - // //----------- - // if (nodenum < 256) - // { - // hnodes = hnodesbase + (nodenum<<9); - // *out_p++ = nodenum; - // if (!--count) - // break; - // nodenum = cin.numhnodes1[nodenum]; - // } - // nodenum = hnodes[nodenum*2 + (inbyte&1)]; - // inbyte >>=1; - // //----------- - // if (nodenum < 256) - // { - // hnodes = hnodesbase + (nodenum<<9); - // *out_p++ = nodenum; - // if (!--count) - // break; - // nodenum = cin.numhnodes1[nodenum]; - // } - // nodenum = hnodes[nodenum*2 + (inbyte&1)]; - // inbyte >>=1; - // //----------- - // if (nodenum < 256) - // { - // hnodes = hnodesbase + (nodenum<<9); - // *out_p++ = nodenum; - // if (!--count) - // break; - // nodenum = cin.numhnodes1[nodenum]; - // } - // nodenum = hnodes[nodenum*2 + (inbyte&1)]; - // inbyte >>=1; - // //----------- - // if (nodenum < 256) - // { - // hnodes = hnodesbase + (nodenum<<9); - // *out_p++ = nodenum; - // if (!--count) - // break; - // nodenum = cin.numhnodes1[nodenum]; - // } - // nodenum = hnodes[nodenum*2 + (inbyte&1)]; - // inbyte >>=1; - // } - // - // if (input - in.data != in.count && input - in.data != in.count+1) - // { - // Com_Printf ("Decompression overread by %i", (input - in.data) - in.count); - // } - // out.count = out_p - out.data; - // - // return out; - // } - // - // /* - // ================== - // SCR_ReadNextFrame - // ================== - // */ - // byte *SCR_ReadNextFrame (void) - // { - // int r; - // int command; - // byte samples[22050/14*4]; - // byte compressed[0x20000]; - // int size; - // byte *pic; - // cblock_t in, huf1; - // int start, end, count; - // - // // read the next frame - // r = fread (&command, 4, 1, cl.cinematic_file); - // if (r == 0) // we'll give it one more chance - // r = fread (&command, 4, 1, cl.cinematic_file); - // - // if (r != 1) - // return NULL; - // command = LittleLong(command); - // if (command == 2) - // return NULL; // last frame marker - // - // if (command == 1) - // { // read palette - // FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file); - // cl.cinematicpalette_active=0; // dubious.... exposes an edge case - // } - // - // // decompress the next frame - // FS_Read (&size, 4, cl.cinematic_file); - // size = LittleLong(size); - // if (size > sizeof(compressed) || size < 1) - // Com_Error (ERR_DROP, "Bad compressed frame size"); - // FS_Read (compressed, size, cl.cinematic_file); - // - // // read sound - // start = cl.cinematicframe*cin.s_rate/14; - // end = (cl.cinematicframe+1)*cin.s_rate/14; - // count = end - start; - // - // FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file); - // - // S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples); - // - // in.data = compressed; - // in.count = size; - // - // huf1 = Huff1Decompress (in); - // - // pic = huf1.data; - // - // cl.cinematicframe++; - // - // return pic; - // } - // - // - /* - ================== - SCR_RunCinematic - - ================== - */ - static void RunCinematic() { - int frame; - - if (cl.cinematictime <= 0) { - StopCinematic(); - return; - } - - // if (cl.cinematicframe == -1) - // return; // static image - // - // if (cls.key_dest != key_game) - // { // pause if menu or console is up - // cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14; - // return; - // } - // - // frame = (cls.realtime - cl.cinematictime)*14.0/1000; - // if (frame <= cl.cinematicframe) - // return; - // if (frame > cl.cinematicframe+1) - // { - // Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1); - // cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14; - // } - // if (cin.pic) - // Z_Free (cin.pic); - // cin.pic = cin.pic_pending; - // cin.pic_pending = NULL; - // cin.pic_pending = SCR_ReadNextFrame (); - // if (!cin.pic_pending) - // { - // SCR_StopCinematic (); - // SCR_FinishCinematic (); - // cl.cinematictime = 1; // hack to get the black screen behind loading - // SCR_BeginLoadingPlaque (); - // cl.cinematictime = 0; - // return; - // } - } - - /* - ================== - SCR_DrawCinematic - - Returns true if a cinematic is active, meaning the view rendering - should be skipped - ================== - */ - static boolean DrawCinematic() { - // if (cl.cinematictime <= 0) - // { - return false; - // } - // - // if (cls.key_dest == key_menu) - // { // blank screen and pause if menu is up - // re.CinematicSetPalette(NULL); - // cl.cinematicpalette_active = false; - // return true; - // } - // - // if (!cl.cinematicpalette_active) - // { - // re.CinematicSetPalette(cl.cinematicpalette); - // cl.cinematicpalette_active = true; - // } - // - // if (!cin.pic) - // return true; - // - // re.DrawStretchRaw (0, 0, viddef.width, viddef.height, - // cin.width, cin.height, cin.pic); - // - // return true; - } - - /* - ================== - SCR_PlayCinematic - - ================== - */ - static void PlayCinematic(String arg) { - // int width, height; - // byte *palette; - // char name[MAX_OSPATH], *dot; - // int old_khz; - // - // // make sure CD isn't playing music - //CDAudio.Stop(); - - cl.cinematicframe= 0; - // dot = strstr (arg, "."); - // if (dot && !strcmp (dot, ".pcx")) - // { // static pcx image - // Com_sprintf (name, sizeof(name), "pics/%s", arg); - // SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height); - // cl.cinematicframe = -1; - // cl.cinematictime = 1; - // SCR_EndLoadingPlaque (); - // cls.state = ca_active; - // if (!cin.pic) - // { - // Com_Printf ("%s not found.\n", name); - // cl.cinematictime = 0; - // } - // else - // { - // memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette)); - // Z_Free (palette); - // } - // return; - // } - // - // Com_sprintf (name, sizeof(name), "video/%s", arg); - // FS_FOpenFile (name, &cl.cinematic_file); - // if (!cl.cinematic_file) - // { - // Com_Error (ERR_DROP, "Cinematic %s not found.\n", name); - FinishCinematic(); - cl.cinematictime= 0; // done - return; - // } - // - // SCR_EndLoadingPlaque (); - // - // cls.state = ca_active; - // - // FS_Read (&width, 4, cl.cinematic_file); - // FS_Read (&height, 4, cl.cinematic_file); - // cin.width = LittleLong(width); - // cin.height = LittleLong(height); - // - // FS_Read (&cin.s_rate, 4, cl.cinematic_file); - // cin.s_rate = LittleLong(cin.s_rate); - // FS_Read (&cin.s_width, 4, cl.cinematic_file); - // cin.s_width = LittleLong(cin.s_width); - // FS_Read (&cin.s_channels, 4, cl.cinematic_file); - // cin.s_channels = LittleLong(cin.s_channels); - // - // Huff1TableInit (); - // - // // switch up to 22 khz sound if necessary - // old_khz = Cvar_VariableValue ("s_khz"); - // if (old_khz != cin.s_rate/1000) - // { - // cin.restart_sound = true; - // Cvar_SetValue ("s_khz", cin.s_rate/1000); - // CL_Snd_Restart_f (); - // Cvar_SetValue ("s_khz", old_khz); - // } - // - // cl.cinematicframe = 0; - // cin.pic = SCR_ReadNextFrame (); - // cl.cinematictime = Sys_Milliseconds (); - } + // cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc + + static String[][] sb_nums = { + { "num_0", "num_1", "num_2", "num_3", "num_4", "num_5", "num_6", + "num_7", "num_8", "num_9", "num_minus" }, + { "anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5", + "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus" } }; + + /* + * full screen console put up loading plaque blanked background with loading + * plaque blanked background with menu cinematics full screen image for quit + * and victory + * + * end of unit intermissions + */ + + static float scr_con_current; // aproaches scr_conlines at scr_conspeed + + static float scr_conlines; // 0.0 to 1.0 lines of console to display + + static boolean scr_initialized; // ready to draw + + static int scr_draw_loading; + + // scr_vrect ist in Globals definiert + // position of render window on screen + + static cvar_t scr_viewsize; + + static cvar_t scr_conspeed; + + static cvar_t scr_centertime; + + static cvar_t scr_showturtle; + + static cvar_t scr_showpause; + + static cvar_t scr_printspeed; + + static cvar_t scr_netgraph; + + static cvar_t scr_timegraph; + + static cvar_t scr_debuggraph; + + static cvar_t scr_graphheight; + + static cvar_t scr_graphscale; + + static cvar_t scr_graphshift; + + static cvar_t scr_drawall; + + public static cvar_t fps; + + static dirty_t scr_dirty = new dirty_t(); + + static dirty_t[] scr_old_dirty = { new dirty_t(), new dirty_t() }; + + static String crosshair_pic; + + static int crosshair_width, crosshair_height; + + static class dirty_t { + int x1; + + int x2; + + int y1; + + int y2; + + void set(dirty_t src) { + x1 = src.x1; + x2 = src.x2; + y1 = src.y1; + y2 = src.y2; + } + + void clear() { + x1 = x2 = y1 = y2 = 0; + } + } + + /* + * =============================================================================== + * + * BAR GRAPHS + * + * =============================================================================== + */ + + // typedef struct + // { + // float value; + // int color; + // } graphsamp_t; + static class graphsamp_t { + float value; + + int color; + } + + static int current; + + static graphsamp_t[] values = new graphsamp_t[1024]; + + static { + for (int n = 0; n < 1024; n++) + values[n] = new graphsamp_t(); + } + + /* + * ============== SCR_DebugGraph ============== + */ + public static void DebugGraph(float value, int color) { + values[current & 1023].value = value; + values[current & 1023].color = color; + current++; + } + + /* + * ============== SCR_DrawDebugGraph ============== + */ + static void DrawDebugGraph() { + int a, x, y, w, i, h; + float v; + int color; + + // draw the graph + + w = scr_vrect.width; + + x = scr_vrect.x; + y = scr_vrect.y + scr_vrect.height; + re.DrawFill(x, (int) (y - scr_graphheight.value), w, + (int) scr_graphheight.value, 8); + + for (a = 0; a < w; a++) { + i = (current - 1 - a + 1024) & 1023; + v = values[i].value; + color = values[i].color; + v = v * scr_graphscale.value + scr_graphshift.value; + + if (v < 0) + v += scr_graphheight.value + * (1 + (int) (-v / scr_graphheight.value)); + h = (int) v % (int) scr_graphheight.value; + re.DrawFill(x + w - 1 - a, y - h, 1, h, color); + } + } + + /* + * =============================================================================== + * + * CENTER PRINTING + * + * =============================================================================== + */ + + // char scr_centerstring[1024]; + static String scr_centerstring; + + static float scr_centertime_start; // for slow victory printing + + static float scr_centertime_off; + + static int scr_center_lines; + + static int scr_erase_center; + + /* + * ============== SCR_CenterPrint + * + * Called for important messages that should stay in the center of the + * screen for a few moments ============== + */ + static void CenterPrint(String str) { + //char *s; + int s; + StringBuffer line = new StringBuffer(64); + int i, j, l; + + //strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1); + scr_centerstring = str; + scr_centertime_off = scr_centertime.value; + scr_centertime_start = cl.time; + + // count the number of lines for centering + scr_center_lines = 1; + s = 0; + while (s < str.length()) { + if (str.charAt(s) == '\n') + scr_center_lines++; + s++; + } + + // echo it to the console + Com + .Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); + + s = 0; + + if (str.length() != 0) { + do { + // scan the width of the line + + for (l = 0; l < 40 && (l + s) < str.length(); l++) + if (str.charAt(s + l) == '\n' || str.charAt(s + l) == 0) + break; + for (i = 0; i < (40 - l) / 2; i++) + line.append(' '); + + for (j = 0; j < l; j++) { + line.append(str.charAt(s + j)); + } + + line.append('\n'); + + Com.Printf(line.toString()); + + while (s < str.length() && str.charAt(s) != '\n') + s++; + + if (s == str.length()) + break; + s++; // skip the \n + } while (true); + } + Com + .Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); + Console.ClearNotify(); + } + + static void DrawCenterString() { + String cs = scr_centerstring + "\0"; + int start; + int l; + int j; + int x, y; + int remaining; + + if (cs == null) + return; + if (cs.length() == 0) + return; + + // the finale prints the characters one at a time + remaining = 9999; + + scr_erase_center = 0; + start = 0; + + if (scr_center_lines <= 4) + y = (int) (viddef.height * 0.35); + else + y = 48; + + do { + // scan the width of the line + for (l = 0; l < 40; l++) + if (start + l == cs.length() - 1 + || cs.charAt(start + l) == '\n') + break; + x = (viddef.width - l * 8) / 2; + SCR.AddDirtyPoint(x, y); + for (j = 0; j < l; j++, x += 8) { + re.DrawChar(x, y, cs.charAt(start + j)); + if (remaining == 0) + return; + remaining--; + } + SCR.AddDirtyPoint(x, y + 8); + + y += 8; + + while (start < cs.length() && cs.charAt(start) != '\n') + start++; + + if (start == cs.length()) + break; + start++; // skip the \n + } while (true); + } + + static void CheckDrawCenterString() { + scr_centertime_off -= cls.frametime; + + if (scr_centertime_off <= 0) + return; + + DrawCenterString(); + } + + // ============================================================================= + + /* + * ================= SCR_CalcVrect + * + * Sets scr_vrect, the coordinates of the rendered window ================= + */ + static void CalcVrect() { + int size; + + // bound viewsize + if (scr_viewsize.value < 40) + Cvar.Set("viewsize", "40"); + if (scr_viewsize.value > 100) + Cvar.Set("viewsize", "100"); + + size = (int) scr_viewsize.value; + + scr_vrect.width = viddef.width * size / 100; + scr_vrect.width &= ~7; + + scr_vrect.height = viddef.height * size / 100; + scr_vrect.height &= ~1; + + scr_vrect.x = (viddef.width - scr_vrect.width) / 2; + scr_vrect.y = (viddef.height - scr_vrect.height) / 2; + } + + /* + * ================= SCR_SizeUp_f + * + * Keybinding command ================= + */ + static void SizeUp_f() { + Cvar.SetValue("viewsize", scr_viewsize.value + 10); + } + + /* + * ================= SCR_SizeDown_f + * + * Keybinding command ================= + */ + static void SizeDown_f() { + Cvar.SetValue("viewsize", scr_viewsize.value - 10); + } + + /* + * ================= SCR_Sky_f + * + * Set a specific sky and rotation speed ================= + */ + static void Sky_f() { + float rotate; + float[] axis = { 0, 0, 0 }; + + if (Cmd.Argc() < 2) { + Com.Printf("Usage: sky \n"); + return; + } + if (Cmd.Argc() > 2) + rotate = Float.parseFloat(Cmd.Argv(2)); + else + rotate = 0; + if (Cmd.Argc() == 6) { + axis[0] = Float.parseFloat(Cmd.Argv(3)); + axis[1] = Float.parseFloat(Cmd.Argv(4)); + axis[2] = Float.parseFloat(Cmd.Argv(5)); + } else { + axis[0] = 0; + axis[1] = 0; + axis[2] = 1; + } + + re.SetSky(Cmd.Argv(1), rotate, axis); + } + + // ============================================================================ + + /* + * ================== SCR_Init ================== + */ + static void Init() { + scr_viewsize = Cvar.Get("viewsize", "100", CVAR_ARCHIVE); + scr_conspeed = Cvar.Get("scr_conspeed", "3", 0); + scr_showturtle = Cvar.Get("scr_showturtle", "0", 0); + scr_showpause = Cvar.Get("scr_showpause", "1", 0); + scr_centertime = Cvar.Get("scr_centertime", "2.5", 0); + scr_printspeed = Cvar.Get("scr_printspeed", "8", 0); + scr_netgraph = Cvar.Get("netgraph", "1", 0); + scr_timegraph = Cvar.Get("timegraph", "1", 0); + scr_debuggraph = Cvar.Get("debuggraph", "1", 0); + scr_graphheight = Cvar.Get("graphheight", "32", 0); + scr_graphscale = Cvar.Get("graphscale", "1", 0); + scr_graphshift = Cvar.Get("graphshift", "0", 0); + scr_drawall = Cvar.Get("scr_drawall", "1", 0); + fps = Cvar.Get("fps", "0", 0); + + // + // register our commands + // + Cmd.AddCommand("timerefresh", new xcommand_t() { + public void execute() { + TimeRefresh_f(); + } + }); + Cmd.AddCommand("loading", new xcommand_t() { + public void execute() { + Loading_f(); + } + }); + Cmd.AddCommand("sizeup", new xcommand_t() { + public void execute() { + SizeUp_f(); + } + }); + Cmd.AddCommand("sizedown", new xcommand_t() { + public void execute() { + SizeDown_f(); + } + }); + Cmd.AddCommand("sky", new xcommand_t() { + public void execute() { + Sky_f(); + } + }); + + scr_initialized = true; + } + + /* + * ============== SCR_DrawNet ============== + */ + static void DrawNet() { + if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged < CMD_BACKUP - 1) + return; + + re.DrawPic(scr_vrect.x + 64, scr_vrect.y, "net"); + } + + /* + * ============== SCR_DrawPause ============== + */ + static void DrawPause() { + Dimension dim = new Dimension(); + + if (scr_showpause.value == 0) // turn off for screenshots + return; + + if (cl_paused.value == 0) + return; + + re.DrawGetPicSize(dim, "pause"); + re.DrawPic((viddef.width - dim.width) / 2, viddef.height / 2 + 8, + "pause"); + } + + /* + * ============== SCR_DrawLoading ============== + */ + static void DrawLoading() { + Dimension dim = new Dimension(); + + if (scr_draw_loading == 0) + return; + + scr_draw_loading = 0; + re.DrawGetPicSize(dim, "loading"); + re.DrawPic((viddef.width - dim.width) / 2, + (viddef.height - dim.height) / 2, "loading"); + } + + // ============================================================================= + + /* + * ================== SCR_RunConsole + * + * Scroll it up or down ================== + */ + static void RunConsole() { + // decide on the height of the console + if (cls.key_dest == key_console) + scr_conlines = 0.5f; // half screen + else + scr_conlines = 0; // none visible + + if (scr_conlines < scr_con_current) { + scr_con_current -= scr_conspeed.value * cls.frametime; + if (scr_conlines > scr_con_current) + scr_con_current = scr_conlines; + + } else if (scr_conlines > scr_con_current) { + scr_con_current += scr_conspeed.value * cls.frametime; + if (scr_conlines < scr_con_current) + scr_con_current = scr_conlines; + } + } + + /* + * ================== SCR_DrawConsole ================== + */ + static void DrawConsole() { + Console.CheckResize(); + + if (cls.state == ca_disconnected || cls.state == ca_connecting) { // forced + // full + // screen + // console + Console.DrawConsole(1.0f); + return; + } + + if (cls.state != ca_active || !cl.refresh_prepped) { // connected, but + // can't render + Console.DrawConsole(0.5f); + re.DrawFill(0, viddef.height / 2, viddef.width, viddef.height / 2, + 0); + return; + } + + if (scr_con_current != 0) { + Console.DrawConsole(scr_con_current); + } else { + if (cls.key_dest == key_game || cls.key_dest == key_message) + Console.DrawNotify(); // only draw notify in game + } + } + + // ============================================================================= + + /* + * ================ SCR_BeginLoadingPlaque ================ + */ + public static void BeginLoadingPlaque() { + S.StopAllSounds(); + cl.sound_prepped = false; // don't play ambients + + if (cls.disable_screen != 0) + return; + if (developer.value != 0) + return; + if (cls.state == ca_disconnected) + return; // if at console, don't bring up the plaque + if (cls.key_dest == key_console) + return; + if (cl.cinematictime > 0) + scr_draw_loading = 2; // clear to balack first + else + scr_draw_loading = 1; + + UpdateScreen(); + cls.disable_screen = Sys.Milliseconds(); + cls.disable_servercount = cl.servercount; + } + + /* + * ================ SCR_EndLoadingPlaque ================ + */ + public static void EndLoadingPlaque() { + cls.disable_screen = 0; + Console.ClearNotify(); + } + + /* + * ================ SCR_Loading_f ================ + */ + static void Loading_f() { + BeginLoadingPlaque(); + } + + /* + * ================ SCR_TimeRefresh_f ================ + */ + static void TimeRefresh_f() { + int i; + int start, stop; + float time; + + if (cls.state != ca_active) + return; + + start = Sys.Milliseconds(); + + if (Cmd.Argc() == 2) { // run without page flipping + re.BeginFrame(0); + for (i = 0; i < 128; i++) { + cl.refdef.viewangles[1] = i / 128.0f * 360.0f; + re.RenderFrame(cl.refdef); + } + re.EndFrame(); + } else { + for (i = 0; i < 128; i++) { + cl.refdef.viewangles[1] = i / 128.0f * 360.0f; + + re.BeginFrame(0); + re.RenderFrame(cl.refdef); + re.EndFrame(); + } + } + + stop = Sys.Milliseconds(); + time = (stop - start) / 1000.0f; + Com.Printf("%f seconds (%f fps)\n", new Vargs(2).add(time).add( + 128.0f / time)); + } + + static void DirtyScreen() { + AddDirtyPoint(0, 0); + AddDirtyPoint(viddef.width - 1, viddef.height - 1); + } + + /* + * ============== SCR_TileClear + * + * Clear any parts of the tiled background that were drawn on last frame + * ============== + */ + + static dirty_t clear = new dirty_t(); + + static void TileClear() { + int i; + int top, bottom, left, right; + clear.clear(); + + if (scr_drawall.value != 0) + DirtyScreen(); // for power vr or broken page flippers... + + if (scr_con_current == 1.0f) + return; // full screen console + if (scr_viewsize.value == 100) + return; // full screen rendering + if (cl.cinematictime > 0) + return; // full screen cinematic + + // erase rect will be the union of the past three frames + // so tripple buffering works properly + clear.set(scr_dirty); + for (i = 0; i < 2; i++) { + if (scr_old_dirty[i].x1 < clear.x1) + clear.x1 = scr_old_dirty[i].x1; + if (scr_old_dirty[i].x2 > clear.x2) + clear.x2 = scr_old_dirty[i].x2; + if (scr_old_dirty[i].y1 < clear.y1) + clear.y1 = scr_old_dirty[i].y1; + if (scr_old_dirty[i].y2 > clear.y2) + clear.y2 = scr_old_dirty[i].y2; + } + + scr_old_dirty[1].set(scr_old_dirty[0]); + scr_old_dirty[0].set(scr_dirty); + + scr_dirty.x1 = 9999; + scr_dirty.x2 = -9999; + scr_dirty.y1 = 9999; + scr_dirty.y2 = -9999; + + // don't bother with anything convered by the console) + top = (int) (scr_con_current * viddef.height); + if (top >= clear.y1) + clear.y1 = top; + + if (clear.y2 <= clear.y1) + return; // nothing disturbed + + top = scr_vrect.y; + bottom = top + scr_vrect.height - 1; + left = scr_vrect.x; + right = left + scr_vrect.width - 1; + + if (clear.y1 < top) { // clear above view screen + i = clear.y2 < top - 1 ? clear.y2 : top - 1; + re.DrawTileClear(clear.x1, clear.y1, clear.x2 - clear.x1 + 1, i + - clear.y1 + 1, "backtile"); + clear.y1 = top; + } + if (clear.y2 > bottom) { // clear below view screen + i = clear.y1 > bottom + 1 ? clear.y1 : bottom + 1; + re.DrawTileClear(clear.x1, i, clear.x2 - clear.x1 + 1, clear.y2 - i + + 1, "backtile"); + clear.y2 = bottom; + } + if (clear.x1 < left) { // clear left of view screen + i = clear.x2 < left - 1 ? clear.x2 : left - 1; + re.DrawTileClear(clear.x1, clear.y1, i - clear.x1 + 1, clear.y2 + - clear.y1 + 1, "backtile"); + clear.x1 = left; + } + if (clear.x2 > right) { // clear left of view screen + i = clear.x1 > right + 1 ? clear.x1 : right + 1; + re.DrawTileClear(i, clear.y1, clear.x2 - i + 1, clear.y2 - clear.y1 + + 1, "backtile"); + clear.x2 = right; + } + + } + + // =============================================================== + + static final int STAT_MINUS = 10; // num frame for '-' stats digit + + static final int ICON_WIDTH = 24; + + static final int ICON_HEIGHT = 24; + + static final int CHAR_WIDTH = 16; + + static final int ICON_SPACE = 8; + + /* + * ================ SizeHUDString + * + * Allow embedded \n in the string ================ + */ + static void SizeHUDString(String string, Dimension dim) { + int lines, width, current; + + lines = 1; + width = 0; + + current = 0; + for (int i = 0; i < string.length(); i++) { + if (string.charAt(i) == '\n') { + lines++; + current = 0; + } else { + current++; + if (current > width) + width = current; + } + + } + + dim.width = width * 8; + dim.height = lines * 8; + } + + static void DrawHUDString(String string, int x, int y, int centerwidth, + int xor) { + int margin; + //char line[1024]; + StringBuffer line = new StringBuffer(1024); + int i; + + margin = x; + + for (int l = 0; l < string.length();) { + // scan out one line of text from the string + line = new StringBuffer(1024); + while (l < string.length() && string.charAt(l) != '\n') { + line.append(string.charAt(l)); + l++; + } + + if (centerwidth != 0) + x = margin + (centerwidth - line.length() * 8) / 2; + else + x = margin; + for (i = 0; i < line.length(); i++) { + re.DrawChar(x, y, line.charAt(i) ^ xor); + x += 8; + } + if (l < string.length()) { + l++; // skip the \n + x = margin; + y += 8; + } + } + } + + /* + * ============== SCR_DrawField ============== + */ + static void DrawField(int x, int y, int color, int width, int value) { + char ptr; + String num; + int l; + int frame; + + if (width < 1) + return; + + // draw number string + if (width > 5) + width = 5; + + AddDirtyPoint(x, y); + AddDirtyPoint(x + width * CHAR_WIDTH + 2, y + 23); + + num = "" + value; + l = num.length(); + if (l > width) + l = width; + x += 2 + CHAR_WIDTH * (width - l); + + ptr = num.charAt(0); + + for (int i = 0; i < l; i++) { + ptr = num.charAt(i); + if (ptr == '-') + frame = STAT_MINUS; + else + frame = ptr - '0'; + + re.DrawPic(x, y, sb_nums[color][frame]); + x += CHAR_WIDTH; + } + } + + /* + * =============== SCR_TouchPics + * + * Allows rendering code to cache all needed sbar graphics =============== + */ + static void TouchPics() { + int i, j; + + for (i = 0; i < 2; i++) + for (j = 0; j < 11; j++) + re.RegisterPic(sb_nums[i][j]); + + if (crosshair.value != 0.0f) { + if (crosshair.value > 3.0f || crosshair.value < 0.0f) + crosshair.value = 3.0f; + + crosshair_pic = "ch" + (int) crosshair.value; + Dimension dim = new Dimension(); + re.DrawGetPicSize(dim, crosshair_pic); + crosshair_width = dim.width; + crosshair_height = dim.height; + if (crosshair_width == 0) + crosshair_pic = ""; + } + } + + /* + * ================ SCR_ExecuteLayoutString + * + * ================ + */ + static void ExecuteLayoutString(String s) { + int x, y; + int value; + String token; + int width; + int index; + clientinfo_t ci; + + if (cls.state != ca_active || !cl.refresh_prepped) + return; + + // if (!s[0]) + if (s == null || s.length() == 0) + return; + + x = 0; + y = 0; + width = 3; + + Com.ParseHelp ph = new Com.ParseHelp(s); + + while (!ph.isEof()) { + token = Com.Parse(ph); + if (token.equals("xl")) { + token = Com.Parse(ph); + x = Lib.atoi(token); + continue; + } + if (token.equals("xr")) { + token = Com.Parse(ph); + x = viddef.width + Lib.atoi(token); + continue; + } + if (token.equals("xv")) { + token = Com.Parse(ph); + x = viddef.width / 2 - 160 + Lib.atoi(token); + continue; + } + + if (token.equals("yt")) { + token = Com.Parse(ph); + y = Lib.atoi(token); + continue; + } + if (token.equals("yb")) { + token = Com.Parse(ph); + y = viddef.height + Lib.atoi(token); + continue; + } + if (token.equals("yv")) { + token = Com.Parse(ph); + y = viddef.height / 2 - 120 + Lib.atoi(token); + continue; + } + + if (token.equals("pic")) { // draw a pic from a stat number + token = Com.Parse(ph); + value = cl.frame.playerstate.stats[Lib.atoi(token)]; + if (value >= MAX_IMAGES) + Com.Error(ERR_DROP, "Pic >= MAX_IMAGES"); + if (cl.configstrings[CS_IMAGES + value] != null) { + AddDirtyPoint(x, y); + AddDirtyPoint(x + 23, y + 23); + re.DrawPic(x, y, cl.configstrings[CS_IMAGES + value]); + } + continue; + } + + if (token.equals("client")) { // draw a deathmatch client block + int score, ping, time; + + token = Com.Parse(ph); + x = viddef.width / 2 - 160 + Lib.atoi(token); + token = Com.Parse(ph); + y = viddef.height / 2 - 120 + Lib.atoi(token); + AddDirtyPoint(x, y); + AddDirtyPoint(x + 159, y + 31); + + token = Com.Parse(ph); + value = Lib.atoi(token); + if (value >= MAX_CLIENTS || value < 0) + Com.Error(ERR_DROP, "client >= MAX_CLIENTS"); + ci = cl.clientinfo[value]; + + token = Com.Parse(ph); + score = Lib.atoi(token); + + token = Com.Parse(ph); + ping = Lib.atoi(token); + + token = Com.Parse(ph); + time = Lib.atoi(token); + + Console.DrawAltString(x + 32, y, ci.name); + Console.DrawString(x + 32, y + 8, "Score: "); + Console.DrawAltString(x + 32 + 7 * 8, y + 8, "" + score); + Console.DrawString(x + 32, y + 16, "Ping: " + ping); + Console.DrawString(x + 32, y + 24, "Time: " + time); + + if (ci.icon == null) + ci = cl.baseclientinfo; + re.DrawPic(x, y, ci.iconname); + continue; + } + + if (token.equals("ctf")) { // draw a ctf client block + int score, ping; + + token = Com.Parse(ph); + x = viddef.width / 2 - 160 + Lib.atoi(token); + token = Com.Parse(ph); + y = viddef.height / 2 - 120 + Lib.atoi(token); + AddDirtyPoint(x, y); + AddDirtyPoint(x + 159, y + 31); + + token = Com.Parse(ph); + value = Lib.atoi(token); + if (value >= MAX_CLIENTS || value < 0) + Com.Error(ERR_DROP, "client >= MAX_CLIENTS"); + ci = cl.clientinfo[value]; + + token = Com.Parse(ph); + score = Lib.atoi(token); + + token = Com.Parse(ph); + ping = Lib.atoi(token); + if (ping > 999) + ping = 999; + + // sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name); + String block = Com.sprintf("%3d %3d %-12.12s", new Vargs(3) + .add(score).add(ping).add(ci.name)); + + if (value == cl.playernum) + Console.DrawAltString(x, y, block); + else + Console.DrawString(x, y, block); + continue; + } + + if (token.equals("picn")) { // draw a pic from a name + token = Com.Parse(ph); + AddDirtyPoint(x, y); + AddDirtyPoint(x + 23, y + 23); + re.DrawPic(x, y, token); + continue; + } + + if (token.equals("num")) { // draw a number + token = Com.Parse(ph); + width = Lib.atoi(token); + token = Com.Parse(ph); + value = cl.frame.playerstate.stats[Lib.atoi(token)]; + DrawField(x, y, 0, width, value); + continue; + } + + if (token.equals("hnum")) { // health number + int color; + + width = 3; + value = cl.frame.playerstate.stats[STAT_HEALTH]; + if (value > 25) + color = 0; // green + else if (value > 0) + color = (cl.frame.serverframe >> 2) & 1; // flash + else + color = 1; + + if ((cl.frame.playerstate.stats[STAT_FLASHES] & 1) != 0) + re.DrawPic(x, y, "field_3"); + + DrawField(x, y, color, width, value); + continue; + } + + if (token.equals("anum")) { // ammo number + int color; + + width = 3; + value = cl.frame.playerstate.stats[STAT_AMMO]; + if (value > 5) + color = 0; // green + else if (value >= 0) + color = (cl.frame.serverframe >> 2) & 1; // flash + else + continue; // negative number = don't show + + if ((cl.frame.playerstate.stats[STAT_FLASHES] & 4) != 0) + re.DrawPic(x, y, "field_3"); + + DrawField(x, y, color, width, value); + continue; + } + + if (token.equals("rnum")) { // armor number + int color; + + width = 3; + value = cl.frame.playerstate.stats[STAT_ARMOR]; + if (value < 1) + continue; + + color = 0; // green + + if ((cl.frame.playerstate.stats[STAT_FLASHES] & 2) != 0) + re.DrawPic(x, y, "field_3"); + + DrawField(x, y, color, width, value); + continue; + } + + if (token.equals("stat_string")) { + token = Com.Parse(ph); + index = Lib.atoi(token); + if (index < 0 || index >= MAX_CONFIGSTRINGS) + Com.Error(ERR_DROP, "Bad stat_string index"); + index = cl.frame.playerstate.stats[index]; + if (index < 0 || index >= MAX_CONFIGSTRINGS) + Com.Error(ERR_DROP, "Bad stat_string index"); + Console.DrawString(x, y, cl.configstrings[index]); + continue; + } + + if (token.equals("cstring")) { + token = Com.Parse(ph); + DrawHUDString(token, x, y, 320, 0); + continue; + } + + if (token.equals("string")) { + token = Com.Parse(ph); + Console.DrawString(x, y, token); + continue; + } + + if (token.equals("cstring2")) { + token = Com.Parse(ph); + DrawHUDString(token, x, y, 320, 0x80); + continue; + } + + if (token.equals("string2")) { + token = Com.Parse(ph); + Console.DrawAltString(x, y, token); + continue; + } + + if (token.equals("if")) { // draw a number + token = Com.Parse(ph); + value = cl.frame.playerstate.stats[Lib.atoi(token)]; + if (value == 0) { // skip to endif + // while (s && strcmp(token, "endif") ) + // { + // token = Com.Parse(ph); + // } + + while (!ph.isEof() + && !(token = Com.Parse(ph)).equals("endif")) + ; + + } + + continue; + } + + } + } + + /* + * ================ SCR_DrawStats + * + * The status bar is a small layout program that is based on the stats array + * ================ + */ + static void DrawStats() { + //TODO: + SCR.ExecuteLayoutString(cl.configstrings[CS_STATUSBAR]); + } + + /* + * ================ SCR_DrawLayout + * + * ================ + */ + static final int STAT_LAYOUTS = 13; + + static void DrawLayout() { + if (cl.frame.playerstate.stats[STAT_LAYOUTS] != 0) + SCR.ExecuteLayoutString(cl.layout); + } + + // ======================================================= + + /* + * ================== SCR_UpdateScreen + * + * This is called every frame, and can also be called explicitly to flush + * text to the screen. ================== + */ + static void UpdateScreen2() { + int numframes; + int i; + float[] separation = { 0, 0 }; + + // if the screen is disabled (loading plaque is up, or vid mode + // changing) + // do nothing at all + if (cls.disable_screen != 0) { + if (Sys.Milliseconds() - cls.disable_screen > 120000) { + cls.disable_screen = 0; + Com.Printf("Loading plaque timed out.\n"); + } + return; + } + + if (!scr_initialized || !con.initialized) + return; // not initialized yet + + /* + * * range check cl_camera_separation so we don't inadvertently fry + * someone's * brain + */ + if (cl_stereo_separation.value > 1.0) + Cvar.SetValue("cl_stereo_separation", 1.0f); + else if (cl_stereo_separation.value < 0) + Cvar.SetValue("cl_stereo_separation", 0.0f); + + if (cl_stereo.value != 0) { + numframes = 2; + separation[0] = -cl_stereo_separation.value / 2; + separation[1] = cl_stereo_separation.value / 2; + } else { + separation[0] = 0; + separation[1] = 0; + numframes = 1; + } + + for (i = 0; i < numframes; i++) { + re.BeginFrame(separation[i]); + + if (scr_draw_loading == 2) { // loading plaque over black screen + Dimension dim = new Dimension(); + + re.CinematicSetPalette(null); + scr_draw_loading = 0; // false + re.DrawGetPicSize(dim, "loading"); + re.DrawPic((viddef.width - dim.width) / 2, + (viddef.height - dim.height) / 2, "loading"); + } + // if a cinematic is supposed to be running, handle menus + // and console specially + else if (cl.cinematictime > 0) { + if (cls.key_dest == key_menu) { + if (cl.cinematicpalette_active) { + re.CinematicSetPalette(null); + cl.cinematicpalette_active = false; + } + Menu.Draw(); + } else if (cls.key_dest == key_console) { + if (cl.cinematicpalette_active) { + re.CinematicSetPalette(null); + cl.cinematicpalette_active = false; + } + DrawConsole(); + } else { + // TODO impl: cl_cin.c for cinematics + DrawCinematic(); + } + } else { + // make sure the game palette is active + if (cl.cinematicpalette_active) { + re.CinematicSetPalette(null); + cl.cinematicpalette_active = false; + } + + // do 3D refresh drawing, and then update the screen + CalcVrect(); + + // clear any dirty part of the background + TileClear(); + + V.RenderView(separation[i]); + + DrawStats(); + + if ((cl.frame.playerstate.stats[STAT_LAYOUTS] & 1) != 0) + DrawLayout(); + if ((cl.frame.playerstate.stats[STAT_LAYOUTS] & 2) != 0) + CL_inv.DrawInventory(); + + DrawNet(); + CheckDrawCenterString(); + DrawFPS(); + + // + // if (scr_timegraph->value) + // SCR_DebugGraph (cls.frametime*300, 0); + // + // if (scr_debuggraph->value || scr_timegraph->value || + // scr_netgraph->value) + // SCR_DrawDebugGraph (); + // + DrawPause(); + DrawConsole(); + Menu.Draw(); + DrawLoading(); + } + } + + Globals.re.EndFrame(); + } + + /* + * ================= SCR_DrawCrosshair ================= + */ + static void DrawCrosshair() { + if (crosshair.value == 0.0f) + return; + + if (crosshair.modified) { + crosshair.modified = false; + SCR.TouchPics(); + } + + if (crosshair_pic.length() == 0) + return; + + re.DrawPic(scr_vrect.x + ((scr_vrect.width - crosshair_width) >> 1), + scr_vrect.y + ((scr_vrect.height - crosshair_height) >> 1), + crosshair_pic); + } + + private static xcommand_t updateScreenCallback = new xcommand_t() { + public void execute() { + UpdateScreen2(); + } + }; + + // wird anstelle von der richtigen UpdateScreen benoetigt + public static void UpdateScreen() { + Globals.re.updateScreen(updateScreenCallback); + } + + /* + * ================= SCR_AddDirtyPoint ================= + */ + static void AddDirtyPoint(int x, int y) { + if (x < scr_dirty.x1) + scr_dirty.x1 = x; + if (x > scr_dirty.x2) + scr_dirty.x2 = x; + if (y < scr_dirty.y1) + scr_dirty.y1 = y; + if (y > scr_dirty.y2) + scr_dirty.y2 = y; + } + + private static int lastframes = 0; + + private static int lasttime = 0; + + private static String fpsvalue = ""; + + static void DrawFPS() { + if (fps.value > 0.0f) { + if (fps.modified) { + fps.modified = false; + Cvar.SetValue("cl_maxfps", 1000); + } + + int diff = cls.realtime - lasttime; + if (diff > (int) (fps.value * 1000)) { + fpsvalue = (cls.framecount - lastframes) * 100000 / diff + / 100.0f + " fps"; + lastframes = cls.framecount; + lasttime = cls.realtime; + } + int x = viddef.width - 8 * fpsvalue.length() - 2; + for (int i = 0; i < fpsvalue.length(); i++) { + re.DrawChar(x, 2, fpsvalue.charAt(i)); + x += 8; + } + } else if (fps.modified) { + fps.modified = false; + Cvar.SetValue("cl_maxfps", 90); + } + } + + /* + * ================================================================= + * + * cl_cin.c + * + * Play Cinematics + * + * ================================================================= + */ + + // typedef struct + // { + // byte *data; + // int count; + // } cblock_t; + // + // typedef struct + // { + // qboolean restart_sound; + // int s_rate; + // int s_width; + // int s_channels; + // + // int width; + // int height; + // byte *pic; + // byte *pic_pending; + // + // // order 1 huffman stuff + // int *hnodes1; // [256][256][2]; + // int numhnodes1[256]; + // + // int h_used[512]; + // int h_count[512]; + // } cinematics_t; + // + // cinematics_t cin; + // + // /* + // ================================================================= + // + // PCX LOADING + // + // ================================================================= + // */ + // + // + // /* + // ============== + // SCR_LoadPCX + // ============== + // */ + // void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, + // int *height) + // { + // byte *raw; + // pcx_t *pcx; + // int x, y; + // int len; + // int dataByte, runLength; + // byte *out, *pix; + // + // *pic = NULL; + // + // // + // // load the file + // // + // len = FS_LoadFile (filename, (void **)&raw); + // if (!raw) + // return; // Com_Printf ("Bad pcx file %s\n", filename); + // + // // + // // parse the PCX file + // // + // pcx = (pcx_t *)raw; + // raw = &pcx->data; + // + // if (pcx->manufacturer != 0x0a + // || pcx->version != 5 + // || pcx->encoding != 1 + // || pcx->bits_per_pixel != 8 + // || pcx->xmax >= 640 + // || pcx->ymax >= 480) + // { + // Com_Printf ("Bad pcx file %s\n", filename); + // return; + // } + // + // out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); + // + // *pic = out; + // + // pix = out; + // + // if (palette) + // { + // *palette = Z_Malloc(768); + // memcpy (*palette, (byte *)pcx + len - 768, 768); + // } + // + // if (width) + // *width = pcx->xmax+1; + // if (height) + // *height = pcx->ymax+1; + // + // for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) + // { + // for (x=0 ; x<=pcx->xmax ; ) + // { + // dataByte = *raw++; + // + // if((dataByte & 0xC0) == 0xC0) + // { + // runLength = dataByte & 0x3F; + // dataByte = *raw++; + // } + // else + // runLength = 1; + // + // while(runLength-- > 0) + // pix[x++] = dataByte; + // } + // + // } + // + // if ( raw - (byte *)pcx > len) + // { + // Com_Printf ("PCX file %s was malformed", filename); + // Z_Free (*pic); + // *pic = NULL; + // } + // + // FS_FreeFile (pcx); + // } + // + // ============================================================= + /* + * ================== SCR_StopCinematic ================== + */ + static void StopCinematic() { + cl.cinematictime = 0; // done + // if (cin.pic) + // { + // Z_Free (cin.pic); + // cin.pic = NULL; + // } + // if (cin.pic_pending) + // { + // Z_Free (cin.pic_pending); + // cin.pic_pending = NULL; + // } + if (cl.cinematicpalette_active) { + re.CinematicSetPalette(null); + cl.cinematicpalette_active = false; + } + // if (cl.cinematic_file) + // { + // fclose (cl.cinematic_file); + // cl.cinematic_file = NULL; + // } + // if (cin.hnodes1) + // { + // Z_Free (cin.hnodes1); + // cin.hnodes1 = NULL; + // } + // + // // switch back down to 11 khz sound if necessary + // if (cin.restart_sound) + // { + // cin.restart_sound = false; + // CL_Snd_Restart_f (); + // } + // + } + + /* + * ==================== SCR_FinishCinematic + * + * Called when either the cinematic completes, or it is aborted + * ==================== + */ + static void FinishCinematic() { + // tell the server to advance to the next map / cinematic + MSG.WriteByte(cls.netchan.message, clc_stringcmd); + SZ.Print(cls.netchan.message, "nextserver " + cl.servercount + '\n'); + } + + // ========================================================================== + + // /* + // ================== + // SmallestNode1 + // ================== + // */ + // int SmallestNode1 (int numhnodes) + // { + // int i; + // int best, bestnode; + // + // best = 99999999; + // bestnode = -1; + // for (i=0 ; i>=1; + // //----------- + // if (nodenum < 256) + // { + // hnodes = hnodesbase + (nodenum<<9); + // *out_p++ = nodenum; + // if (!--count) + // break; + // nodenum = cin.numhnodes1[nodenum]; + // } + // nodenum = hnodes[nodenum*2 + (inbyte&1)]; + // inbyte >>=1; + // //----------- + // if (nodenum < 256) + // { + // hnodes = hnodesbase + (nodenum<<9); + // *out_p++ = nodenum; + // if (!--count) + // break; + // nodenum = cin.numhnodes1[nodenum]; + // } + // nodenum = hnodes[nodenum*2 + (inbyte&1)]; + // inbyte >>=1; + // //----------- + // if (nodenum < 256) + // { + // hnodes = hnodesbase + (nodenum<<9); + // *out_p++ = nodenum; + // if (!--count) + // break; + // nodenum = cin.numhnodes1[nodenum]; + // } + // nodenum = hnodes[nodenum*2 + (inbyte&1)]; + // inbyte >>=1; + // //----------- + // if (nodenum < 256) + // { + // hnodes = hnodesbase + (nodenum<<9); + // *out_p++ = nodenum; + // if (!--count) + // break; + // nodenum = cin.numhnodes1[nodenum]; + // } + // nodenum = hnodes[nodenum*2 + (inbyte&1)]; + // inbyte >>=1; + // //----------- + // if (nodenum < 256) + // { + // hnodes = hnodesbase + (nodenum<<9); + // *out_p++ = nodenum; + // if (!--count) + // break; + // nodenum = cin.numhnodes1[nodenum]; + // } + // nodenum = hnodes[nodenum*2 + (inbyte&1)]; + // inbyte >>=1; + // //----------- + // if (nodenum < 256) + // { + // hnodes = hnodesbase + (nodenum<<9); + // *out_p++ = nodenum; + // if (!--count) + // break; + // nodenum = cin.numhnodes1[nodenum]; + // } + // nodenum = hnodes[nodenum*2 + (inbyte&1)]; + // inbyte >>=1; + // //----------- + // if (nodenum < 256) + // { + // hnodes = hnodesbase + (nodenum<<9); + // *out_p++ = nodenum; + // if (!--count) + // break; + // nodenum = cin.numhnodes1[nodenum]; + // } + // nodenum = hnodes[nodenum*2 + (inbyte&1)]; + // inbyte >>=1; + // } + // + // if (input - in.data != in.count && input - in.data != in.count+1) + // { + // Com_Printf ("Decompression overread by %i", (input - in.data) - + // in.count); + // } + // out.count = out_p - out.data; + // + // return out; + // } + // + // /* + // ================== + // SCR_ReadNextFrame + // ================== + // */ + // byte *SCR_ReadNextFrame (void) + // { + // int r; + // int command; + // byte samples[22050/14*4]; + // byte compressed[0x20000]; + // int size; + // byte *pic; + // cblock_t in, huf1; + // int start, end, count; + // + // // read the next frame + // r = fread (&command, 4, 1, cl.cinematic_file); + // if (r == 0) // we'll give it one more chance + // r = fread (&command, 4, 1, cl.cinematic_file); + // + // if (r != 1) + // return NULL; + // command = LittleLong(command); + // if (command == 2) + // return NULL; // last frame marker + // + // if (command == 1) + // { // read palette + // FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), + // cl.cinematic_file); + // cl.cinematicpalette_active=0; // dubious.... exposes an edge case + // } + // + // // decompress the next frame + // FS_Read (&size, 4, cl.cinematic_file); + // size = LittleLong(size); + // if (size > sizeof(compressed) || size < 1) + // Com_Error (ERR_DROP, "Bad compressed frame size"); + // FS_Read (compressed, size, cl.cinematic_file); + // + // // read sound + // start = cl.cinematicframe*cin.s_rate/14; + // end = (cl.cinematicframe+1)*cin.s_rate/14; + // count = end - start; + // + // FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file); + // + // S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples); + // + // in.data = compressed; + // in.count = size; + // + // huf1 = Huff1Decompress (in); + // + // pic = huf1.data; + // + // cl.cinematicframe++; + // + // return pic; + // } + // + // + /* + * ================== SCR_RunCinematic + * + * ================== + */ + static void RunCinematic() { + int frame; + + if (cl.cinematictime <= 0) { + StopCinematic(); + return; + } + + // if (cl.cinematicframe == -1) + // return; // static image + // + // if (cls.key_dest != key_game) + // { // pause if menu or console is up + // cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14; + // return; + // } + // + // frame = (cls.realtime - cl.cinematictime)*14.0/1000; + // if (frame <= cl.cinematicframe) + // return; + // if (frame > cl.cinematicframe+1) + // { + // Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1); + // cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14; + // } + // if (cin.pic) + // Z_Free (cin.pic); + // cin.pic = cin.pic_pending; + // cin.pic_pending = NULL; + // cin.pic_pending = SCR_ReadNextFrame (); + // if (!cin.pic_pending) + // { + // SCR_StopCinematic (); + // SCR_FinishCinematic (); + // cl.cinematictime = 1; // hack to get the black screen behind loading + // SCR_BeginLoadingPlaque (); + // cl.cinematictime = 0; + // return; + // } + } + + /* + * ================== SCR_DrawCinematic + * + * Returns true if a cinematic is active, meaning the view rendering should + * be skipped ================== + */ + static boolean DrawCinematic() { + // if (cl.cinematictime <= 0) + // { + return false; + // } + // + // if (cls.key_dest == key_menu) + // { // blank screen and pause if menu is up + // re.CinematicSetPalette(NULL); + // cl.cinematicpalette_active = false; + // return true; + // } + // + // if (!cl.cinematicpalette_active) + // { + // re.CinematicSetPalette(cl.cinematicpalette); + // cl.cinematicpalette_active = true; + // } + // + // if (!cin.pic) + // return true; + // + // re.DrawStretchRaw (0, 0, viddef.width, viddef.height, + // cin.width, cin.height, cin.pic); + // + // return true; + } + + /* + * ================== SCR_PlayCinematic + * + * ================== + */ + static void PlayCinematic(String arg) { + // int width, height; + // byte *palette; + // char name[MAX_OSPATH], *dot; + // int old_khz; + // + // // make sure CD isn't playing music + //CDAudio.Stop(); + + cl.cinematicframe = 0; + // dot = strstr (arg, "."); + // if (dot && !strcmp (dot, ".pcx")) + // { // static pcx image + // Com_sprintf (name, sizeof(name), "pics/%s", arg); + // SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height); + // cl.cinematicframe = -1; + // cl.cinematictime = 1; + // SCR_EndLoadingPlaque (); + // cls.state = ca_active; + // if (!cin.pic) + // { + // Com_Printf ("%s not found.\n", name); + // cl.cinematictime = 0; + // } + // else + // { + // memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette)); + // Z_Free (palette); + // } + // return; + // } + // + // Com_sprintf (name, sizeof(name), "video/%s", arg); + // FS_FOpenFile (name, &cl.cinematic_file); + // if (!cl.cinematic_file) + // { + // Com_Error (ERR_DROP, "Cinematic %s not found.\n", name); + FinishCinematic(); + cl.cinematictime = 0; // done + return; + // } + // + // SCR_EndLoadingPlaque (); + // + // cls.state = ca_active; + // + // FS_Read (&width, 4, cl.cinematic_file); + // FS_Read (&height, 4, cl.cinematic_file); + // cin.width = LittleLong(width); + // cin.height = LittleLong(height); + // + // FS_Read (&cin.s_rate, 4, cl.cinematic_file); + // cin.s_rate = LittleLong(cin.s_rate); + // FS_Read (&cin.s_width, 4, cl.cinematic_file); + // cin.s_width = LittleLong(cin.s_width); + // FS_Read (&cin.s_channels, 4, cl.cinematic_file); + // cin.s_channels = LittleLong(cin.s_channels); + // + // Huff1TableInit (); + // + // // switch up to 22 khz sound if necessary + // old_khz = Cvar_VariableValue ("s_khz"); + // if (old_khz != cin.s_rate/1000) + // { + // cin.restart_sound = true; + // Cvar_SetValue ("s_khz", cin.s_rate/1000); + // CL_Snd_Restart_f (); + // Cvar_SetValue ("s_khz", old_khz); + // } + // + // cl.cinematicframe = 0; + // cin.pic = SCR_ReadNextFrame (); + // cl.cinematictime = Sys_Milliseconds (); + } } \ No newline at end of file diff --git a/src/jake2/client/V.java b/src/jake2/client/V.java index 2fd3005..402d16c 100644 --- a/src/jake2/client/V.java +++ b/src/jake2/client/V.java @@ -2,27 +2,27 @@ * V.java * Copyright (C) 2003 * - * $Id: V.java,v 1.2 2004-07-09 06:50:50 hzi Exp $ + * $Id: V.java,v 1.3 2004-09-22 19:22:08 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.client; import jake2.Globals; @@ -40,379 +40,373 @@ import java.nio.FloatBuffer; * V */ public final class V extends Globals { - - static cvar_t cl_testblend; - static cvar_t cl_testparticles; - static cvar_t cl_testentities; - static cvar_t cl_testlights; - static cvar_t cl_stats; - - static int r_numdlights; - static dlight_t[] r_dlights = new dlight_t[MAX_DLIGHTS]; - - static int r_numentities; - static entity_t[] r_entities = new entity_t[MAX_ENTITIES]; - - static int r_numparticles; - //static particle_t[] r_particles = new particle_t[MAX_PARTICLES]; - - static lightstyle_t[] r_lightstyles = new lightstyle_t[MAX_LIGHTSTYLES]; - static { - for (int i = 0; i < r_dlights.length; i++) - r_dlights[i] = new dlight_t(); - for (int i = 0; i < r_entities.length; i++) - r_entities[i] = new entity_t(); - for (int i = 0; i < r_lightstyles.length; i++) - r_lightstyles[i] = new lightstyle_t(); - } - - /* - ==================== - V_ClearScene - - Specifies the model that will be used as the world - ==================== - */ - static void ClearScene() { - r_numdlights = 0; - r_numentities = 0; - r_numparticles = 0; - } - - /* - ===================== - V_AddEntity - - ===================== - */ - static void AddEntity(entity_t ent) { - if (r_numentities >= MAX_ENTITIES) - return; - r_entities[r_numentities++].set(ent); - } - - /* - ===================== - V_AddParticle - - ===================== - */ - static void AddParticle(float[] org, int color, float alpha) { - if (r_numparticles >= MAX_PARTICLES) - return; - - int i = r_numparticles++; - - int c = particle_t.colorTable[color]; - c |= (int)(alpha * 255) << 24; - particle_t.colorArray.put(i, c); - - i *= 3; - FloatBuffer vertexBuf = particle_t.vertexArray; - vertexBuf.put(i++, org[0]); - vertexBuf.put(i++, org[1]); - vertexBuf.put(i++, org[2]); - } - - /* - ===================== - V_AddLight - - ===================== - */ - static void AddLight(float[] org, float intensity, float r, float g, float b) { - dlight_t dl; - - if (r_numdlights >= MAX_DLIGHTS) - return; - dl = r_dlights[r_numdlights++]; - VectorCopy(org, dl.origin); - dl.intensity = intensity; - dl.color[0] = r; - dl.color[1] = g; - dl.color[2] = b; - } - - - /* - ===================== - V_AddLightStyle - - ===================== - */ - static void AddLightStyle(int style, float r, float g, float b) { - lightstyle_t ls; - - if (style < 0 || style > MAX_LIGHTSTYLES) - Com.Error(ERR_DROP, "Bad light style " + style); - ls = r_lightstyles[style]; - - ls.white = r + g + b; - ls.rgb[0] = r; - ls.rgb[1] = g; - ls.rgb[2] = b; - } - - /* - ================ - V_TestParticles - - If cl_testparticles is set, create 4096 particles in the view - ================ - */ - static void TestParticles() { - int i, j; - float d, r, u; - - float[] origin = {0,0,0}; - - r_numparticles = 0; - for (i = 0; i < MAX_PARTICLES; i++) { - d = i * 0.25f; - r = 4 * ((i & 7) - 3.5f); - u = 4 * (((i >> 3) & 7) - 3.5f); - - for (j = 0; j < 3; j++) - origin[j] = - cl.refdef.vieworg[j] - + cl.v_forward[j] * d - + cl.v_right[j] * r - + cl.v_up[j] * u; - - AddParticle(origin, 8, cl_testparticles.value); - } - } - - /* - ================ - V_TestEntities - - If cl_testentities is set, create 32 player models - ================ - */ - static void TestEntities() { - int i, j; - float f, r; - entity_t ent; - - r_numentities = 32; - //memset (r_entities, 0, sizeof(r_entities)); - for (i = 0; i < r_entities.length; i++) - r_entities[i] = new entity_t(); - - for (i=0 ; i>1; - dl.color[2] = (((i%6)+1) & 4)>>2; - dl.intensity = 200; - } - } - - static xcommand_t Gun_Next_f = new xcommand_t() { - public void execute() { - gun_frame++; - Com.Printf("frame " + gun_frame + "\n"); - } - }; - - static xcommand_t Gun_Prev_f = new xcommand_t() { - public void execute() { - gun_frame--; - if (gun_frame < 0) - gun_frame = 0; - Com.Printf("frame " + gun_frame + "\n"); - } - }; - - static xcommand_t Gun_Model_f = new xcommand_t() { - public void execute() { - if (Cmd.Argc() != 2) { - gun_model = null; - return; - } - String name = "models/" + Cmd.Argv(1) + "/tris.md2"; - gun_model = re.RegisterModel(name); - } - }; - - /* - ================== - V_RenderView - - ================== - */ - static void RenderView(float stereo_separation) { -// extern int entitycmpfnc( const entity_t *, const entity_t * ); -// - if (cls.state != ca_active) return; - - if (!cl.refresh_prepped) return; // still loading - - if (cl_timedemo.value != 0.0f) { - if (cl.timedemo_start == 0) - cl.timedemo_start = Sys.Milliseconds(); - cl.timedemo_frames++; - } - - // an invalid frame will just use the exact previous refdef - // we can't use the old frame if the video mode has changed, though... - if ( cl.frame.valid && (cl.force_refdef || cl_paused.value == 0.0f) ) { - cl.force_refdef = false; - - V.ClearScene(); - - // build a refresh entity list and calc cl.sim* - // this also calls CL_CalcViewValues which loads - // v_forward, etc. - CL.AddEntities(); - - if (cl_testparticles.value != 0.0f) - TestParticles(); - if (cl_testentities.value != 0.0f) - TestEntities(); - if (cl_testlights.value != 0.0f) - TestLights(); - if (cl_testblend.value != 0.0f) { - cl.refdef.blend[0] = 1.0f; - cl.refdef.blend[1] = 0.5f; - cl.refdef.blend[2] = 0.25f; - cl.refdef.blend[3] = 0.5f; - } - - // offset vieworg appropriately if we're doing stereo separation - if ( stereo_separation != 0 ) { - float[] tmp = new float[3]; - - Math3D.VectorScale( cl.v_right, stereo_separation, tmp ); - Math3D.VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg ); - } - - // never let it sit exactly on a node line, because a water plane can - // dissapear when viewed with the eye exactly on it. - // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis - cl.refdef.vieworg[0] += 1.0/16; - cl.refdef.vieworg[1] += 1.0/16; - cl.refdef.vieworg[2] += 1.0/16; - - cl.refdef.x = scr_vrect.x; - cl.refdef.y = scr_vrect.y; - cl.refdef.width = scr_vrect.width; - cl.refdef.height = scr_vrect.height; - cl.refdef.fov_y = Math3D.CalcFov(cl.refdef.fov_x, cl.refdef.width, cl.refdef.height); - cl.refdef.time = cl.time*0.001f; - - cl.refdef.areabits = cl.frame.areabits; - - if (cl_add_entities.value == 0.0f) - r_numentities = 0; - if (cl_add_particles.value == 0.0f) - r_numparticles = 0; - if (cl_add_lights.value == 0.0f) - r_numdlights = 0; - if (cl_add_blend.value == 0) { - Math3D.VectorClear(cl.refdef.blend); - } - - cl.refdef.num_entities = r_numentities; - cl.refdef.entities = r_entities; - cl.refdef.num_particles = r_numparticles; - cl.refdef.num_dlights = r_numdlights; - cl.refdef.dlights = r_dlights; - cl.refdef.lightstyles = r_lightstyles; - - cl.refdef.rdflags = cl.frame.playerstate.rdflags; - - // sort entities for better cache locality - // !!! useless in Java !!! - //Arrays.sort(cl.refdef.entities, entitycmpfnc); - } - - re.RenderFrame(cl.refdef); - if (cl_stats.value != 0.0f) - Com.Printf("ent:%i lt:%i part:%i\n", new Vargs(3).add(r_numentities).add( - r_numdlights).add(r_numparticles)); - if ( log_stats.value != 0.0f && ( log_stats_file != null ) ) - try { - log_stats_file.write(r_numentities + "," + r_numdlights + "," + r_numparticles); - } catch (IOException e) {} - - SCR.AddDirtyPoint(scr_vrect.x, scr_vrect.y); - SCR.AddDirtyPoint(scr_vrect.x+scr_vrect.width-1, scr_vrect.y+scr_vrect.height-1); - - SCR.DrawCrosshair(); - } - - /* - ============= - V_Viewpos_f - ============= - */ - static xcommand_t Viewpos_f = new xcommand_t() { - public void execute() { - Com.Printf("(%i %i %i) : %i\n", - new Vargs(4).add((int)cl.refdef.vieworg[0]).add( - (int)cl.refdef.vieworg[1]).add( - (int)cl.refdef.vieworg[2]).add( - (int)cl.refdef.viewangles[YAW])); - } - }; - - public static void Init() { - Cmd.AddCommand("gun_next", Gun_Next_f); - Cmd.AddCommand("gun_prev", Gun_Prev_f); - Cmd.AddCommand("gun_model", Gun_Model_f); - - Cmd.AddCommand("viewpos", Viewpos_f); - - crosshair = Cvar.Get("crosshair", "0", CVAR_ARCHIVE); - - cl_testblend = Cvar.Get("cl_testblend", "0", 0); - cl_testparticles = Cvar.Get("cl_testparticles", "0", 0); - cl_testentities = Cvar.Get("cl_testentities", "0", 0); - cl_testlights = Cvar.Get("cl_testlights", "0", 0); - - cl_stats = Cvar.Get("cl_stats", "0", 0); - } -} + + static cvar_t cl_testblend; + + static cvar_t cl_testparticles; + + static cvar_t cl_testentities; + + static cvar_t cl_testlights; + + static cvar_t cl_stats; + + static int r_numdlights; + + static dlight_t[] r_dlights = new dlight_t[MAX_DLIGHTS]; + + static int r_numentities; + + static entity_t[] r_entities = new entity_t[MAX_ENTITIES]; + + static int r_numparticles; + + //static particle_t[] r_particles = new particle_t[MAX_PARTICLES]; + + static lightstyle_t[] r_lightstyles = new lightstyle_t[MAX_LIGHTSTYLES]; + static { + for (int i = 0; i < r_dlights.length; i++) + r_dlights[i] = new dlight_t(); + for (int i = 0; i < r_entities.length; i++) + r_entities[i] = new entity_t(); + for (int i = 0; i < r_lightstyles.length; i++) + r_lightstyles[i] = new lightstyle_t(); + } + + /* + * ==================== V_ClearScene + * + * Specifies the model that will be used as the world ==================== + */ + static void ClearScene() { + r_numdlights = 0; + r_numentities = 0; + r_numparticles = 0; + } + + /* + * ===================== V_AddEntity + * + * ===================== + */ + static void AddEntity(entity_t ent) { + if (r_numentities >= MAX_ENTITIES) + return; + r_entities[r_numentities++].set(ent); + } + + /* + * ===================== V_AddParticle + * + * ===================== + */ + static void AddParticle(float[] org, int color, float alpha) { + if (r_numparticles >= MAX_PARTICLES) + return; + + int i = r_numparticles++; + + int c = particle_t.colorTable[color]; + c |= (int) (alpha * 255) << 24; + particle_t.colorArray.put(i, c); + + i *= 3; + FloatBuffer vertexBuf = particle_t.vertexArray; + vertexBuf.put(i++, org[0]); + vertexBuf.put(i++, org[1]); + vertexBuf.put(i++, org[2]); + } + + /* + * ===================== V_AddLight + * + * ===================== + */ + static void AddLight(float[] org, float intensity, float r, float g, float b) { + dlight_t dl; + + if (r_numdlights >= MAX_DLIGHTS) + return; + dl = r_dlights[r_numdlights++]; + Math3D.VectorCopy(org, dl.origin); + dl.intensity = intensity; + dl.color[0] = r; + dl.color[1] = g; + dl.color[2] = b; + } + + /* + * ===================== V_AddLightStyle + * + * ===================== + */ + static void AddLightStyle(int style, float r, float g, float b) { + lightstyle_t ls; + + if (style < 0 || style > MAX_LIGHTSTYLES) + Com.Error(ERR_DROP, "Bad light style " + style); + ls = r_lightstyles[style]; + + ls.white = r + g + b; + ls.rgb[0] = r; + ls.rgb[1] = g; + ls.rgb[2] = b; + } + + /* + * ================ V_TestParticles + * + * If cl_testparticles is set, create 4096 particles in the view + * ================ + */ + static void TestParticles() { + int i, j; + float d, r, u; + + float[] origin = { 0, 0, 0 }; + + r_numparticles = 0; + for (i = 0; i < MAX_PARTICLES; i++) { + d = i * 0.25f; + r = 4 * ((i & 7) - 3.5f); + u = 4 * (((i >> 3) & 7) - 3.5f); + + for (j = 0; j < 3; j++) + origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j] * d + + cl.v_right[j] * r + cl.v_up[j] * u; + + AddParticle(origin, 8, cl_testparticles.value); + } + } + + /* + * ================ V_TestEntities + * + * If cl_testentities is set, create 32 player models ================ + */ + static void TestEntities() { + int i, j; + float f, r; + entity_t ent; + + r_numentities = 32; + //memset (r_entities, 0, sizeof(r_entities)); + for (i = 0; i < r_entities.length; i++) + r_entities[i] = new entity_t(); + + for (i = 0; i < r_numentities; i++) { + ent = r_entities[i]; + + r = 64 * ((i % 4) - 1.5f); + f = 64 * (i / 4) + 128; + + for (j = 0; j < 3; j++) + ent.origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j] * f + + cl.v_right[j] * r; + + ent.model = cl.baseclientinfo.model; + ent.skin = cl.baseclientinfo.skin; + } + } + + /* + * ================ V_TestLights + * + * If cl_testlights is set, create 32 lights models ================ + */ + static void TestLights() { + int i, j; + float f, r; + dlight_t dl; + + r_numdlights = 32; + //memset (r_dlights, 0, sizeof(r_dlights)); + for (i = 0; i < r_dlights.length; i++) + r_dlights[i] = new dlight_t(); + + for (i = 0; i < r_numdlights; i++) { + dl = r_dlights[i]; + + r = 64 * ((i % 4) - 1.5f); + f = 64 * (i / 4) + 128; + + for (j = 0; j < 3; j++) + dl.origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j] * f + + cl.v_right[j] * r; + dl.color[0] = ((i % 6) + 1) & 1; + dl.color[1] = (((i % 6) + 1) & 2) >> 1; + dl.color[2] = (((i % 6) + 1) & 4) >> 2; + dl.intensity = 200; + } + } + + static xcommand_t Gun_Next_f = new xcommand_t() { + public void execute() { + gun_frame++; + Com.Printf("frame " + gun_frame + "\n"); + } + }; + + static xcommand_t Gun_Prev_f = new xcommand_t() { + public void execute() { + gun_frame--; + if (gun_frame < 0) + gun_frame = 0; + Com.Printf("frame " + gun_frame + "\n"); + } + }; + + static xcommand_t Gun_Model_f = new xcommand_t() { + public void execute() { + if (Cmd.Argc() != 2) { + gun_model = null; + return; + } + String name = "models/" + Cmd.Argv(1) + "/tris.md2"; + gun_model = re.RegisterModel(name); + } + }; + + /* + * ================== V_RenderView + * + * ================== + */ + static void RenderView(float stereo_separation) { + // extern int entitycmpfnc( const entity_t *, const entity_t * ); + // + if (cls.state != ca_active) + return; + + if (!cl.refresh_prepped) + return; // still loading + + if (cl_timedemo.value != 0.0f) { + if (cl.timedemo_start == 0) + cl.timedemo_start = Sys.Milliseconds(); + cl.timedemo_frames++; + } + + // an invalid frame will just use the exact previous refdef + // we can't use the old frame if the video mode has changed, though... + if (cl.frame.valid && (cl.force_refdef || cl_paused.value == 0.0f)) { + cl.force_refdef = false; + + V.ClearScene(); + + // build a refresh entity list and calc cl.sim* + // this also calls CL_CalcViewValues which loads + // v_forward, etc. + CL_ents.AddEntities(); + + if (cl_testparticles.value != 0.0f) + TestParticles(); + if (cl_testentities.value != 0.0f) + TestEntities(); + if (cl_testlights.value != 0.0f) + TestLights(); + if (cl_testblend.value != 0.0f) { + cl.refdef.blend[0] = 1.0f; + cl.refdef.blend[1] = 0.5f; + cl.refdef.blend[2] = 0.25f; + cl.refdef.blend[3] = 0.5f; + } + + // offset vieworg appropriately if we're doing stereo separation + if (stereo_separation != 0) { + float[] tmp = new float[3]; + + Math3D.VectorScale(cl.v_right, stereo_separation, tmp); + Math3D.VectorAdd(cl.refdef.vieworg, tmp, cl.refdef.vieworg); + } + + // never let it sit exactly on a node line, because a water plane + // can + // dissapear when viewed with the eye exactly on it. + // the server protocol only specifies to 1/8 pixel, so add 1/16 in + // each axis + cl.refdef.vieworg[0] += 1.0 / 16; + cl.refdef.vieworg[1] += 1.0 / 16; + cl.refdef.vieworg[2] += 1.0 / 16; + + cl.refdef.x = scr_vrect.x; + cl.refdef.y = scr_vrect.y; + cl.refdef.width = scr_vrect.width; + cl.refdef.height = scr_vrect.height; + cl.refdef.fov_y = Math3D.CalcFov(cl.refdef.fov_x, cl.refdef.width, + cl.refdef.height); + cl.refdef.time = cl.time * 0.001f; + + cl.refdef.areabits = cl.frame.areabits; + + if (cl_add_entities.value == 0.0f) + r_numentities = 0; + if (cl_add_particles.value == 0.0f) + r_numparticles = 0; + if (cl_add_lights.value == 0.0f) + r_numdlights = 0; + if (cl_add_blend.value == 0) { + Math3D.VectorClear(cl.refdef.blend); + } + + cl.refdef.num_entities = r_numentities; + cl.refdef.entities = r_entities; + cl.refdef.num_particles = r_numparticles; + cl.refdef.num_dlights = r_numdlights; + cl.refdef.dlights = r_dlights; + cl.refdef.lightstyles = r_lightstyles; + + cl.refdef.rdflags = cl.frame.playerstate.rdflags; + + // sort entities for better cache locality + // !!! useless in Java !!! + //Arrays.sort(cl.refdef.entities, entitycmpfnc); + } + + re.RenderFrame(cl.refdef); + if (cl_stats.value != 0.0f) + Com.Printf("ent:%i lt:%i part:%i\n", new Vargs(3).add( + r_numentities).add(r_numdlights).add(r_numparticles)); + if (log_stats.value != 0.0f && (log_stats_file != null)) + try { + log_stats_file.write(r_numentities + "," + r_numdlights + "," + + r_numparticles); + } catch (IOException e) { + } + + SCR.AddDirtyPoint(scr_vrect.x, scr_vrect.y); + SCR.AddDirtyPoint(scr_vrect.x + scr_vrect.width - 1, scr_vrect.y + + scr_vrect.height - 1); + + SCR.DrawCrosshair(); + } + + /* + * ============= V_Viewpos_f ============= + */ + static xcommand_t Viewpos_f = new xcommand_t() { + public void execute() { + Com.Printf("(%i %i %i) : %i\n", new Vargs(4).add( + (int) cl.refdef.vieworg[0]).add((int) cl.refdef.vieworg[1]) + .add((int) cl.refdef.vieworg[2]).add( + (int) cl.refdef.viewangles[YAW])); + } + }; + + public static void Init() { + Cmd.AddCommand("gun_next", Gun_Next_f); + Cmd.AddCommand("gun_prev", Gun_Prev_f); + Cmd.AddCommand("gun_model", Gun_Model_f); + + Cmd.AddCommand("viewpos", Viewpos_f); + + crosshair = Cvar.Get("crosshair", "0", CVAR_ARCHIVE); + + cl_testblend = Cvar.Get("cl_testblend", "0", 0); + cl_testparticles = Cvar.Get("cl_testparticles", "0", 0); + cl_testentities = Cvar.Get("cl_testentities", "0", 0); + cl_testlights = Cvar.Get("cl_testlights", "0", 0); + + cl_stats = Cvar.Get("cl_stats", "0", 0); + } +} \ No newline at end of file diff --git a/src/jake2/game/Cmd.java b/src/jake2/game/Cmd.java index 591e9fc..538e9bc 100644 --- a/src/jake2/game/Cmd.java +++ b/src/jake2/game/Cmd.java @@ -2,27 +2,27 @@ * Cmd.java * Copyright (C) 2003 * - * $Id: Cmd.java,v 1.5 2004-08-19 20:56:41 hzi Exp $ + * $Id: Cmd.java,v 1.6 2004-09-22 19:22:02 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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; @@ -37,1336 +37,1183 @@ import java.util.Vector; /** * 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 : 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= token.length(); - - 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) - { - 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 (cmd.name.equals(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"); - // } - // 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 { - cmd.function.execute(); - } - 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) - { - SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n"); - return; - } - - name= Cmd.Args(); - - if (0 == Lib.Q_stricmp(name, "all")) - give_all= true; - else - give_all= false; - - if (give_all || 0 == Lib.Q_stricmp(Cmd.Argv(1), "health")) - { - if (Cmd.Argc() == 3) - ent.health= Lib.atoi(Cmd.Argv(2)); - else - ent.health= ent.max_health; - if (!give_all) - return; - } - - if (give_all || 0 == Lib.Q_stricmp(name, "weapons")) - { - for (i= 1; 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= 1; 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, GameBase.dummyplane, null); - if (it_ent.inuse) - GameUtil.G_FreeEdict(it_ent); - - if (!give_all) - return; - } - - if (give_all) - { - for (i= 1; 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= Cmd.Argv(1); - it= GameUtil.FindItem(name); - if (it == null) - { - SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "unknown item\n"); - return; - } - } - - if (it.pickup == null) - { - SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "non-pickup item\n"); - return; - } - - index= GameUtil.ITEM_INDEX(it); - - if ((it.flags & Defines.IT_AMMO) != 0) - { - if (Cmd.Argc() == 3) - ent.client.pers.inventory[index]= Lib.atoi(Cmd.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, GameBase.dummyplane, 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) - { - SV_GAME.PF_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"; - - SV_GAME.PF_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) - { - SV_GAME.PF_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"; - - SV_GAME.PF_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) - { - SV_GAME.PF_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"; - } - - SV_GAME.PF_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= Cmd.Args(); - it= GameUtil.FindItem(s); - if (it == null) - { - SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "unknown item: " + s + "\n"); - return; - } - if (it.use == null) - { - SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "Item is not usable.\n"); - return; - } - index= GameUtil.ITEM_INDEX(it); - if (0 == ent.client.pers.inventory[index]) - { - SV_GAME.PF_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= Cmd.Args(); - it= GameUtil.FindItem(s); - if (it == null) - { - SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "unknown item: " + s + "\n"); - return; - } - if (it.drop == null) - { - SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "Item is not dropable.\n"); - return; - } - index= GameUtil.ITEM_INDEX(it); - if (0 == ent.client.pers.inventory[index]) - { - SV_GAME.PF_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) - { - SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "No item to use.\n"); - return; - } - - it= GameAI.itemlist[ent.client.pers.selected_item]; - if (it.use == null) - { - SV_GAME.PF_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; - //bugfix rst - if (index == 0) - index++; - 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) - { - SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "No item to drop.\n"); - return; - } - - it= GameAI.itemlist[ent.client.pers.selected_item]; - if (it.drop == null) - { - SV_GAME.PF_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; - GameAIAdapters.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, GameAIAdapters.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 (small.length() + large.length() > 1024 - 100) - { - // can't print all of them in one packet - large += "...\n"; - break; - } - large += small; - } - - SV_GAME.PF_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(Cmd.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 : - SV_GAME.PF_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 : - SV_GAME.PF_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 : - SV_GAME.PF_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 : - SV_GAME.PF_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 : - SV_GAME.PF_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; - String text; - gclient_t cl; - - if (Cmd.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) - { - text += Cmd.Argv(0); - text += " "; - text += Cmd.Args(); - } - else - { - if (Cmd.Args().startsWith("\"")) - text += Cmd.Args().substring(1, Cmd.Args().length() - 1); - else - text += Cmd.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 (text.length() > 150) - //text[150] = 0; - text= text.substring(0, 150); - - text += "\n"; - - if (flood_msgs.value != 0) - { - cl= ent.client; - - if (level.time < cl.flood_locktill) - { - SV_GAME.PF_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; - SV_GAME.PF_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) - SV_GAME.PF_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; - } - SV_GAME.PF_cprintf(other, PRINT_CHAT, "" + text + ""); - } - - } - - /** - * Returns the playerlist. - * TODO: The list is badly formatted at the moment. - */ - 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 (text.length() + st.length() > 1024 - 50) - { - text += "And more...\n"; - SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "" + text + ""); - return; - } - text += st; - } - SV_GAME.PF_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()); - } - } - - /* - ============ - Cmd_CompleteCommand - ============ - */ - public static Vector CompleteCommand(String partial) - { - Vector cmds = new Vector(); - - // check for match - for (cmd_function_t cmd = cmd_functions; cmd != null ; cmd = cmd.next) - if (cmd.name.startsWith(partial)) - cmds.add(cmd.name); - for (cmdalias_t a = cmd_alias; a != null; a=a.next) - if (a.name.startsWith(partial)) - cmds.add(a.name); - - return cmds; - } - -} +public final class Cmd { + 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 : 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[Defines.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[Defines.MAX_STRING_CHARS]; + + private static char temporary[] = new char[Defines.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 >= Defines.MAX_STRING_CHARS) { + Com.Printf("Line exceeded " + Defines.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 = token.length(); + + len += j; + + if (len >= Defines.MAX_STRING_CHARS) { + Com.Printf("Expanded line exceeded " + Defines.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) { + String com_token; + + cmd_argc = 0; + + int len = Lib.strlen(text); + + // macro expand the text + if (macroExpand) + text = MacroExpandString(text, len); + + if (text == null) + return; + + len = Lib.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 < Defines.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 == Lib.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 (cmd.name.equals(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"); + // } + // 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 { + cmd.function.execute(); + } + return; + } + } + + // check alias + for (a = Globals.cmd_alias; a != null; a = a.next) { + + if (cmd_argv[0].equalsIgnoreCase(a.name)) { + + if (++Globals.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) { + SV_GAME + .PF_cprintf(ent, Defines.PRINT_HIGH, + "You must run the server with '+set cheats 1' to enable this command.\n"); + return; + } + + name = Cmd.Args(); + + if (0 == Lib.Q_stricmp(name, "all")) + give_all = true; + else + give_all = false; + + if (give_all || 0 == Lib.Q_stricmp(Cmd.Argv(1), "health")) { + if (Cmd.Argc() == 3) + ent.health = Lib.atoi(Cmd.Argv(2)); + else + ent.health = ent.max_health; + if (!give_all) + return; + } + + if (give_all || 0 == Lib.Q_stricmp(name, "weapons")) { + for (i = 1; 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 = 1; 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, GameBase.dummyplane, null); + if (it_ent.inuse) + GameUtil.G_FreeEdict(it_ent); + + if (!give_all) + return; + } + + if (give_all) { + for (i = 1; 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 = Cmd.Argv(1); + it = GameUtil.FindItem(name); + if (it == null) { + SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "unknown item\n"); + return; + } + } + + if (it.pickup == null) { + SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "non-pickup item\n"); + return; + } + + index = GameUtil.ITEM_INDEX(it); + + if ((it.flags & Defines.IT_AMMO) != 0) { + if (Cmd.Argc() == 3) + ent.client.pers.inventory[index] = Lib.atoi(Cmd.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, GameBase.dummyplane, 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) { + SV_GAME + .PF_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"; + + SV_GAME.PF_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) { + SV_GAME + .PF_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"; + + SV_GAME.PF_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) { + SV_GAME + .PF_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"; + } + + SV_GAME.PF_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 = Cmd.Args(); + it = GameUtil.FindItem(s); + if (it == null) { + SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "unknown item: " + s + + "\n"); + return; + } + if (it.use == null) { + SV_GAME + .PF_cprintf(ent, Defines.PRINT_HIGH, + "Item is not usable.\n"); + return; + } + index = GameUtil.ITEM_INDEX(it); + if (0 == ent.client.pers.inventory[index]) { + SV_GAME.PF_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 = Cmd.Args(); + it = GameUtil.FindItem(s); + if (it == null) { + SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "unknown item: " + s + + "\n"); + return; + } + if (it.drop == null) { + SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, + "Item is not dropable.\n"); + return; + } + index = GameUtil.ITEM_INDEX(it); + if (0 == ent.client.pers.inventory[index]) { + SV_GAME.PF_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) { + SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "No item to use.\n"); + return; + } + + it = GameAI.itemlist[ent.client.pers.selected_item]; + if (it.use == null) { + SV_GAME + .PF_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; + //bugfix rst + if (index == 0) + index++; + 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) { + SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "No item to drop.\n"); + return; + } + + it = GameAI.itemlist[ent.client.pers.selected_item]; + if (it.drop == null) { + SV_GAME.PF_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, Globals.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 (small.length() + large.length() > 1024 - 100) { + // can't print all of them in one packet + large += "...\n"; + break; + } + large += small; + } + + SV_GAME.PF_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(Cmd.Argv(1)); + + // can't wave when ducked + if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) + return; + + if (ent.client.anim_priority > Defines.ANIM_WAVE) + return; + + ent.client.anim_priority = Defines.ANIM_WAVE; + + switch (i) { + case 0: + SV_GAME.PF_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: + SV_GAME.PF_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: + SV_GAME.PF_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: + SV_GAME.PF_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: + SV_GAME.PF_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; + String text; + gclient_t cl; + + if (Cmd.Argc() < 2 && !arg0) + return; + + if (0 == ((int) (GameBase.dmflags.value) & (Defines.DF_MODELTEAMS | Defines.DF_SKINTEAMS))) + team = false; + + if (team) + text = "(" + ent.client.pers.netname + "): "; + else + text = "" + ent.client.pers.netname + ": "; + + if (arg0) { + text += Cmd.Argv(0); + text += " "; + text += Cmd.Args(); + } else { + if (Cmd.Args().startsWith("\"")) + text += Cmd.Args().substring(1, Cmd.Args().length() - 1); + else + text += Cmd.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 (text.length() > 150) + //text[150] = 0; + text = text.substring(0, 150); + + text += "\n"; + + if (GameBase.flood_msgs.value != 0) { + cl = ent.client; + + if (GameBase.level.time < cl.flood_locktill) { + SV_GAME + .PF_cprintf( + ent, + Defines.PRINT_HIGH, + "You can't talk for " + + (int) (cl.flood_locktill - GameBase.level.time) + + " more seconds\n"); + return; + } + i = (int) (cl.flood_whenhead - GameBase.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 + && GameBase.level.time - cl.flood_when[i] < GameBase.flood_persecond.value) { + cl.flood_locktill = GameBase.level.time + + GameBase.flood_waitdelay.value; + SV_GAME.PF_cprintf(ent, Globals.PRINT_CHAT, + "Flood protection: You can't talk for " + + (int) GameBase.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] = GameBase.level.time; + } + + if (GameBase.dedicated.value != 0) + SV_GAME.PF_cprintf(null, Defines.PRINT_CHAT, "" + text + ""); + + for (j = 1; j <= GameBase.game.maxclients; j++) { + other = GameBase.g_edicts[j]; + if (!other.inuse) + continue; + if (other.client == null) + continue; + if (team) { + if (!GameUtil.OnSameTeam(ent, other)) + continue; + } + SV_GAME.PF_cprintf(other, Defines.PRINT_CHAT, "" + text + ""); + } + + } + + /** + * Returns the playerlist. TODO: The list is badly formatted at the moment. + */ + 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 (text.length() + st.length() > 1024 - 50) { + text += "And more...\n"; + SV_GAME.PF_cprintf(ent, Defines.PRINT_HIGH, "" + text + ""); + return; + } + text += st; + } + SV_GAME.PF_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()); + } + } + + /* + * ============ Cmd_CompleteCommand ============ + */ + public static Vector CompleteCommand(String partial) { + Vector cmds = new Vector(); + + // check for match + for (cmd_function_t cmd = cmd_functions; cmd != null; cmd = cmd.next) + if (cmd.name.startsWith(partial)) + cmds.add(cmd.name); + for (cmdalias_t a = Globals.cmd_alias; a != null; a = a.next) + if (a.name.startsWith(partial)) + cmds.add(a.name); + + return cmds; + } +} \ No newline at end of file diff --git a/src/jake2/game/Fire.java b/src/jake2/game/Fire.java index 73a6f18..c5a426e 100644 --- a/src/jake2/game/Fire.java +++ b/src/jake2/game/Fire.java @@ -1,591 +1,533 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 04.12.2003 by RST. -// $Id: Fire.java,v 1.3 2004-09-10 19:02:53 salomo Exp $ - +// $Id: Fire.java,v 1.4 2004-09-22 19:22:02 salomo Exp $ package jake2.game; import jake2.Defines; +import jake2.Globals; import jake2.util.Lib; import jake2.util.Math3D; -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 = GameWeaponAdapters.blaster_touch; - bolt.nextthink = GameBase.level.time + 2; - bolt.think = GameUtilAdapters.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, GameBase.dummyplane, 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 = GameWeaponAdapters.Grenade_Touch; - grenade.nextthink = GameBase.level.time + timer; - grenade.think = GameWeaponAdapters.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 = GameWeaponAdapters.Grenade_Touch; - grenade.nextthink = GameBase.level.time + timer; - grenade.think = GameWeaponAdapters.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) - GameWeaponAdapters.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 = GameWeaponAdapters.rocket_touch; - rocket.nextthink = GameBase.level.time + 8000 / speed; - rocket.think = GameUtilAdapters.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 = GameWeaponAdapters.bfg_touch; - bfg.nextthink = GameBase.level.time + 8000 / speed; - bfg.think = GameUtilAdapters.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 = GameWeaponAdapters.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); - } -} +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, Globals.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 ((GameBase.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, GameBase.dummyplane, 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); + } +} \ No newline at end of file diff --git a/src/jake2/game/Game.java b/src/jake2/game/Game.java deleted file mode 100644 index 39947d6..0000000 --- a/src/jake2/game/Game.java +++ /dev/null @@ -1,30 +0,0 @@ -/* -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.2 2004-07-08 15:58:44 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 index d4ff055..fb7a3af 100644 --- a/src/jake2/game/GameAI.java +++ b/src/jake2/game/GameAI.java @@ -1,2624 +1,3441 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 02.11.2003 by RST. -// $Id: GameAI.java,v 1.4 2004-09-10 19:02:55 salomo Exp $ - +// $Id: GameAI.java,v 1.5 2004-09-22 19:22:06 salomo Exp $ package jake2.game; import jake2.Defines; +import jake2.Globals; import jake2.client.M; import jake2.qcommon.Com; +import jake2.server.SV_WORLD; import jake2.util.Lib; import jake2.util.Math3D; import jake2.util.Vargs; +import java.util.Comparator; import java.util.StringTokenizer; -public class GameAI extends M_Flash -{ - - /* - =============== - GetItemByIndex - =============== - */ - public static gitem_t GetItemByIndex(int index) - { - if (index == 0 || index >= game.num_items) - return null; - - return GameAI.itemlist[index]; - } - - public static void AttackFinished(edict_t self, float time) - { - self.monsterinfo.attack_finished = level.time + time; - } - - /* - ============= - 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 = GameUtilAdapters.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 = GameUtilAdapters.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 = GameUtilAdapters.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; - } - } - } - - GameUtilAdapters.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 - GameUtilAdapters.enemy_vis = visible(self, self.enemy); - if (GameUtilAdapters.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; - // } - - GameUtilAdapters.enemy_infront = infront(self, self.enemy); - GameUtilAdapters.enemy_range = range(self, self.enemy); - Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, temp); - GameUtilAdapters.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 (!GameUtilAdapters.enemy_vis) - return false; - - return self.monsterinfo.checkattack.think(self); - } - - 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 = GameAI.itemlist[i]; - gi.configstring(CS_ITEMS + i, it.pickup_name); - } - - GameUtilAdapters.jacket_armor_index = ITEM_INDEX(FindItem("Jacket Armor")); - GameUtilAdapters.combat_armor_index = ITEM_INDEX(FindItem("Combat Armor")); - GameUtilAdapters.body_armor_index = ITEM_INDEX(FindItem("Body Armor")); - GameUtilAdapters.power_screen_index = ITEM_INDEX(FindItem("Power Screen")); - GameUtilAdapters.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 = GameAI.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 = GameAI.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); - } - } - - /* - ============ - 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 == GameAIAdapters.Pickup_Armor || item.pickup == GameAIAdapters.Pickup_PowerArmor) - { - G_FreeEdict(ent); - return; - } - } - if (((int) dmflags.value & DF_NO_ITEMS) != 0) - { - if (item.pickup == GameAIAdapters.Pickup_Powerup) - { - G_FreeEdict(ent); - return; - } - } - if (((int) dmflags.value & DF_NO_HEALTH) != 0) - { - if (item.pickup == GameUtilAdapters.Pickup_Health - || item.pickup == GameAIAdapters.Pickup_Adrenaline - || item.pickup == GameAIAdapters.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 = GameAIAdapters.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 == GameUtilAdapters.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 = GameUtilAdapters.Touch_Item; - drop.nextthink = level.time + (self.client.quad_framenum - level.framenum) * FRAMETIME; - drop.think = GameUtilAdapters.G_FreeEdictA; - } - } - - 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 = GameAIAdapters.gib_die; - - if (type == GIB_ORGANIC) - { - gib.movetype = MOVETYPE_TOSS; - gib.touch = GameAIAdapters.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 = GameUtilAdapters.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 = GameAIAdapters.gib_die; - - if (type == GIB_ORGANIC) - { - self.movetype = MOVETYPE_TOSS; - self.touch = GameAIAdapters.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 = GameUtilAdapters.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); - } - - 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 = GameUtilAdapters.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 = GameAIAdapters.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 = string.length(); - - // 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 = entry.length(); - 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 = entry.length(); - - 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) - { - StringBuffer sb = new StringBuffer(256); - 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 - sb.append("xv 32 yv 8 picn help "); // background - sb.append("xv 202 yv 12 string2 \"").append(sk).append("\" "); // skill - sb.append("xv 0 yv 24 cstring2 \"").append(level.level_name).append("\" "); // level name - sb.append("xv 0 yv 54 cstring2 \"").append(game.helpmessage1).append("\" "); // help 1 - sb.append("xv 0 yv 110 cstring2 \"").append(game.helpmessage2).append("\" "); // help 2 - sb.append("xv 50 yv 164 string2 \" kills goals secrets\" "); - sb.append("xv 50 yv 172 string2 \""); - sb.append(Com.sprintf("%3i/%3i %i/%i %i/%i\" ", - new Vargs(6).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(sb.toString()); - gi.unicast(ent, true); - } - - /** - * 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 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 void InitItems() - { - game.num_items = GameAI.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; - } - public static gitem_t itemlist[] = { - //leave index 0 alone - new gitem_t(null, null, null, null, null, null, null, 0, null, null, null, 0, 0, null, 0, 0, null, 0, null), - - // - // ARMOR - // - new gitem_t( - /*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - - "item_armor_body", - GameAIAdapters.Pickup_Armor, - null, - null, - null, - "misc/ar1_pkup.wav", - "models/items/armor/body/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "i_bodyarmor", - /* pickup */ - "Body Armor", - /* width */ - 3, 0, null, Defines.IT_ARMOR, 0, GameAIAdapters.bodyarmor_info, Defines.ARMOR_BODY, - /* precache */ - ""), - - /*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - new gitem_t( - "item_armor_combat", - GameAIAdapters.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, GameAIAdapters.combatarmor_info, Defines.ARMOR_COMBAT, - /* precache */ - ""), - - /*QUAKED item_armor_jacket (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - new gitem_t( - "item_armor_jacket", - GameAIAdapters.Pickup_Armor, - null, - null, - null, - "misc/ar1_pkup.wav", - "models/items/armor/jacket/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "i_jacketarmor", - /* pickup */ - "Jacket Armor", - /* width */ - 3, 0, null, Defines.IT_ARMOR, 0, GameAIAdapters.jacketarmor_info, Defines.ARMOR_JACKET, - /* precache */ - ""), - - /*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - new gitem_t( - "item_armor_shard", - GameAIAdapters.Pickup_Armor, - null, - null, - null, - "misc/ar2_pkup.wav", - "models/items/armor/shard/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "i_jacketarmor", - /* pickup */ - "Armor Shard", - /* width */ - 3, 0, null, Defines.IT_ARMOR, 0, null, Defines.ARMOR_SHARD, - /* precache */ - ""), - - /*QUAKED item_power_screen (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - new gitem_t( - "item_power_screen", - GameAIAdapters.Pickup_PowerArmor, - GameAIAdapters.Use_PowerArmor, - GameAIAdapters.Drop_PowerArmor, - null, - "misc/ar3_pkup.wav", - "models/items/armor/screen/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "i_powerscreen", - /* pickup */ - "Power Screen", - /* width */ - 0, 60, null, Defines.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", - GameAIAdapters.Pickup_PowerArmor, - GameAIAdapters.Use_PowerArmor, - GameAIAdapters.Drop_PowerArmor, - null, - "misc/ar3_pkup.wav", - "models/items/armor/shield/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "i_powershield", - /* pickup */ - "Power Shield", - /* width */ - 0, 60, null, Defines.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, Defines.IT_WEAPON | Defines.IT_STAY_COOP, Defines.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", - Defines.EF_ROTATE, - "models/weapons/v_shotg/tris.md2", - /* icon */ - "w_shotgun", - /* pickup */ - "Shotgun", 0, 1, "Shells", Defines.IT_WEAPON | Defines.IT_STAY_COOP, Defines.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", - Defines.EF_ROTATE, - "models/weapons/v_shotg2/tris.md2", - /* icon */ - "w_sshotgun", - /* pickup */ - "Super Shotgun", 0, 2, "Shells", Defines.IT_WEAPON | Defines.IT_STAY_COOP, Defines.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", - Defines.EF_ROTATE, - "models/weapons/v_machn/tris.md2", - /* icon */ - "w_machinegun", - /* pickup */ - "Machinegun", 0, 1, "Bullets", Defines.IT_WEAPON | Defines.IT_STAY_COOP, Defines.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", - Defines.EF_ROTATE, - "models/weapons/v_chain/tris.md2", - /* icon */ - "w_chaingun", - /* pickup */ - "Chaingun", 0, 1, "Bullets", Defines.IT_WEAPON | Defines.IT_STAY_COOP, Defines.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", - GameAIAdapters.Pickup_Ammo, - GamePWeapon.Use_Weapon, - GameAIAdapters.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", Defines.IT_AMMO | Defines.IT_WEAPON, Defines.WEAP_GRENADES, null, Defines.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", - Defines.EF_ROTATE, - "models/weapons/v_launch/tris.md2", - /* icon */ - "w_glauncher", - /* pickup */ - "Grenade Launcher", 0, 1, "Grenades", Defines.IT_WEAPON | Defines.IT_STAY_COOP, Defines.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", - Defines.EF_ROTATE, - "models/weapons/v_rocket/tris.md2", - /* icon */ - "w_rlauncher", - /* pickup */ - "Rocket Launcher", 0, 1, "Rockets", Defines.IT_WEAPON | Defines.IT_STAY_COOP, Defines.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", - Defines.EF_ROTATE, - "models/weapons/v_hyperb/tris.md2", - /* icon */ - "w_hyperblaster", - /* pickup */ - "HyperBlaster", 0, 1, "Cells", Defines.IT_WEAPON | Defines.IT_STAY_COOP, Defines.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", - Defines.EF_ROTATE, - "models/weapons/v_rail/tris.md2", - /* icon */ - "w_railgun", - /* pickup */ - "Railgun", 0, 1, "Slugs", Defines.IT_WEAPON | Defines.IT_STAY_COOP, Defines.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", - Defines.EF_ROTATE, - "models/weapons/v_bfg/tris.md2", - /* icon */ - "w_bfg", - /* pickup */ - "BFG10K", 0, 50, "Cells", Defines.IT_WEAPON | Defines.IT_STAY_COOP, Defines.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", - GameAIAdapters.Pickup_Ammo, - null, - GameAIAdapters.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, Defines.IT_AMMO, 0, null, Defines.AMMO_SHELLS, - /* precache */ - ""), - - /*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - new gitem_t( - "ammo_bullets", - GameAIAdapters.Pickup_Ammo, - null, - GameAIAdapters.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, Defines.IT_AMMO, 0, null, Defines.AMMO_BULLETS, - /* precache */ - ""), - - /*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - new gitem_t( - "ammo_cells", - GameAIAdapters.Pickup_Ammo, - null, - GameAIAdapters.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, Defines.IT_AMMO, 0, null, Defines.AMMO_CELLS, - /* precache */ - ""), - - /*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - new gitem_t( - "ammo_rockets", - GameAIAdapters.Pickup_Ammo, - null, - GameAIAdapters.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, Defines.IT_AMMO, 0, null, Defines.AMMO_ROCKETS, - /* precache */ - ""), - - /*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - new gitem_t( - "ammo_slugs", - GameAIAdapters.Pickup_Ammo, - null, - GameAIAdapters.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, Defines.IT_AMMO, 0, null, Defines.AMMO_SLUGS, - /* precache */ - ""), - - // - // POWERUP ITEMS - // - /*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - new gitem_t( - "item_quad", - GameAIAdapters.Pickup_Powerup, - GameUtilAdapters.Use_Quad, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/quaddama/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "p_quad", - /* pickup */ - "Quad Damage", - /* width */ - 2, 60, null, Defines.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", - GameAIAdapters.Pickup_Powerup, - GameUtilAdapters.Use_Invulnerability, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/invulner/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "p_invulnerability", - /* pickup */ - "Invulnerability", - /* width */ - 2, 300, null, Defines.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", - GameAIAdapters.Pickup_Powerup, - GameUtilAdapters.Use_Silencer, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/silencer/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "p_silencer", - /* pickup */ - "Silencer", - /* width */ - 2, 60, null, Defines.IT_POWERUP, 0, null, 0, - /* precache */ - ""), - - /*QUAKED item_breather (.3 .3 1) (-16 -16 -16) (16 16 16) - */ - new gitem_t( - "item_breather", - GameAIAdapters.Pickup_Powerup, - GameUtilAdapters.Use_Breather, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/breather/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "p_rebreather", - /* pickup */ - "Rebreather", - /* width */ - 2, 60, null, Defines.IT_STAY_COOP | Defines.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", - GameAIAdapters.Pickup_Powerup, - GameUtilAdapters.Use_Envirosuit, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/enviro/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "p_envirosuit", - /* pickup */ - "Environment Suit", - /* width */ - 2, 60, null, Defines.IT_STAY_COOP | Defines.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", - GameAIAdapters.Pickup_AncientHead, - null, - null, - null, - "items/pkup.wav", - "models/items/c_head/tris.md2", - Defines.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", - GameAIAdapters.Pickup_Adrenaline, - null, - null, - null, - "items/pkup.wav", - "models/items/adrenal/tris.md2", - Defines.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", - GameAIAdapters.Pickup_Bandolier, - null, - null, - null, - "items/pkup.wav", - "models/items/band/tris.md2", - Defines.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", - GameUtilAdapters.Pickup_Pack, - null, - null, - null, - "items/pkup.wav", - "models/items/pack/tris.md2", - Defines.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", - GameUtilAdapters.Pickup_Key, - null, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/keys/data_cd/tris.md2", - Defines.EF_ROTATE, - null, - "k_datacd", - "Data CD", - 2, - 0, - null, - Defines.IT_STAY_COOP | Defines.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", - GameUtilAdapters.Pickup_Key, - null, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/keys/power/tris.md2", - Defines.EF_ROTATE, - null, - "k_powercube", - "Power Cube", - 2, - 0, - null, - Defines.IT_STAY_COOP | Defines.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", - GameUtilAdapters.Pickup_Key, - null, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/keys/pyramid/tris.md2", - Defines.EF_ROTATE, - null, - "k_pyramid", - "Pyramid Key", - 2, - 0, - null, - Defines.IT_STAY_COOP | Defines.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", - GameUtilAdapters.Pickup_Key, - null, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/keys/spinner/tris.md2", - Defines.EF_ROTATE, - null, - "k_dataspin", - "Data Spinner", - 2, - 0, - null, - Defines.IT_STAY_COOP | Defines.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", - GameUtilAdapters.Pickup_Key, - null, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/keys/pass/tris.md2", - Defines.EF_ROTATE, - null, - "k_security", - "Security Pass", - 2, - 0, - null, - Defines.IT_STAY_COOP | Defines.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", - GameUtilAdapters.Pickup_Key, - null, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/keys/key/tris.md2", - Defines.EF_ROTATE, - null, - "k_bluekey", - "Blue Key", - 2, - 0, - null, - Defines.IT_STAY_COOP | Defines.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", - GameUtilAdapters.Pickup_Key, - null, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/keys/red_key/tris.md2", - Defines.EF_ROTATE, - null, - "k_redkey", - "Red Key", - 2, - 0, - null, - Defines.IT_STAY_COOP | Defines.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", - GameUtilAdapters.Pickup_Key, - null, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/monsters/commandr/head/tris.md2", - Defines.EF_GIB, - null, - /* icon */ - "k_comhead", - /* pickup */ - "Commander's Head", - /* width */ - 2, 0, null, Defines.IT_STAY_COOP | Defines.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", - GameUtilAdapters.Pickup_Key, - null, - GameAIAdapters.Drop_General, - null, - "items/pkup.wav", - "models/items/keys/target/tris.md2", - Defines.EF_ROTATE, - null, - /* icon */ - "i_airstrike", - /* pickup */ - "Airstrike Marker", - /* width */ - 2, 0, null, Defines.IT_STAY_COOP | Defines.IT_KEY, 0, null, 0, - /* precache */ - ""), new gitem_t(null, GameUtilAdapters.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 class GameAI { + + public static gitem_armor_t jacketarmor_info = new gitem_armor_t(25, 50, + .30f, .00f, Defines.ARMOR_JACKET); + + public static gitem_armor_t combatarmor_info = new gitem_armor_t(50, 100, + .60f, .30f, Defines.ARMOR_COMBAT); + + public static gitem_armor_t bodyarmor_info = new gitem_armor_t(100, 200, + .80f, .60f, Defines.ARMOR_BODY); + + 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 & Defines.IT_WEAPON) != 0; + if ((weapon) + && ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO) != 0) + count = 1000; + else if (ent.count != 0) + count = ent.count; + else + count = ent.item.quantity; + + oldcount = other.client.pers.inventory[GameUtil + .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 == GameBase.deathmatch.value || other.client.pers.weapon == GameUtil + .FindItem("blaster"))) + other.client.newweapon = ent.item; + } + + if (0 == (ent.spawnflags & (Defines.DROPPED_ITEM | Defines.DROPPED_PLAYER_ITEM)) + && (GameBase.deathmatch.value != 0)) + GameUtil.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 = GameUtil.ArmorIndex(other); + + // handle armor shards specially + if (ent.item.tag == Defines.ARMOR_SHARD) { + if (0 == old_armor_index) + other.client.pers.inventory[GameUtil.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[GameUtil.ITEM_INDEX(ent.item)] = newinfo.base_count; + } + + // use the better armor + else { + // get info on old armor + if (old_armor_index == GameUtil.jacket_armor_index) + oldinfo = jacketarmor_info; + + else if (old_armor_index == GameUtil.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[GameUtil.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 & Defines.DROPPED_ITEM) + && (GameBase.deathmatch.value != 0)) + GameUtil.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[GameUtil + .ITEM_INDEX(ent.item)]; + + other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)]++; + + if (GameBase.deathmatch.value != 0) { + if (0 == (ent.spawnflags & Defines.DROPPED_ITEM)) + GameUtil.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[GameUtil + .ITEM_INDEX(ent.item)]; + if ((GameBase.skill.value == 1 && quantity >= 2) + || (GameBase.skill.value >= 2 && quantity >= 1)) + return false; + + if ((GameBase.coop.value != 0) + && (ent.item.flags & Defines.IT_STAY_COOP) != 0 + && (quantity > 0)) + return false; + + other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)]++; + + if (GameBase.deathmatch.value != 0) { + if (0 == (ent.spawnflags & Defines.DROPPED_ITEM)) + GameUtil.SetRespawn(ent, ent.item.quantity); + if (((int) GameBase.dmflags.value & Defines.DF_INSTANT_ITEMS) != 0 + || ((ent.item.use == GameUtil.Use_Quad) && 0 != (ent.spawnflags & Defines.DROPPED_PLAYER_ITEM))) { + if ((ent.item.use == GameUtil.Use_Quad) + && 0 != (ent.spawnflags & Defines.DROPPED_PLAYER_ITEM)) + GameUtil.quad_drop_timeout_hack = (int) ((ent.nextthink - GameBase.level.time) / Defines.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 (GameBase.deathmatch.value == 0) + other.max_health += 1; + + if (other.health < other.max_health) + other.health = other.max_health; + + if (0 == (ent.spawnflags & Defines.DROPPED_ITEM) + && (GameBase.deathmatch.value != 0)) + GameUtil.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 & Defines.DROPPED_ITEM) + && (GameBase.deathmatch.value != 0)) + GameUtil.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 = GameUtil.FindItem("Bullets"); + if (item != null) { + index = GameUtil.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 = GameUtil.FindItem("Shells"); + if (item != null) { + index = GameUtil.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 & Defines.DROPPED_ITEM) + && (GameBase.deathmatch.value != 0)) + GameUtil.SetRespawn(ent, ent.item.quantity); + + return true; + + } + }; + + /* + * =============== GetItemByIndex =============== + */ + public static gitem_t GetItemByIndex(int index) { + if (index == 0 || index >= GameBase.game.num_items) + return null; + + return itemlist[index]; + } + + public static void AttackFinished(edict_t self, float time) { + self.monsterinfo.attack_finished = GameBase.level.time + time; + } + + /* + * ============= 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[Defines.YAW], dist); + + if (GameUtil.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[Defines.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 = GameUtil.enemy_yaw; + M.M_ChangeYaw(self); + + if (FacingIdeal(self)) { + self.monsterinfo.melee.think(self); + self.monsterinfo.attack_state = Defines.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 = GameUtil.enemy_yaw; + M.M_ChangeYaw(self); + + if (FacingIdeal(self)) { + self.monsterinfo.attack.think(self); + self.monsterinfo.attack_state = Defines.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 = GameUtil.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 & Defines.AI_COMBAT_POINT) != 0) + return false; + + if ((self.monsterinfo.aiflags & Defines.AI_SOUND_TARGET) != 0) { + if ((GameBase.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 &= ~Defines.AI_SOUND_TARGET; + if ((self.monsterinfo.aiflags & Defines.AI_TEMP_STAND_GROUND) != 0) + self.monsterinfo.aiflags &= ~(Defines.AI_STAND_GROUND | Defines.AI_TEMP_STAND_GROUND); + } else { + self.show_hostile = (int) GameBase.level.time + 1; + return false; + } + } + } + + GameUtil.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 & Defines.AI_MEDIC) != 0) { + if (self.enemy.health > 0) { + hesDeadJim = true; + self.monsterinfo.aiflags &= ~Defines.AI_MEDIC; + } + } else { + if ((self.monsterinfo.aiflags & Defines.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; + GameUtil.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 = GameBase.level.time + 100000000; + self.monsterinfo.stand.think(self); + } + return true; + } + } + + self.show_hostile = (int) GameBase.level.time + 1; // wake up other + // monsters + + // check knowledge of enemy + GameUtil.enemy_vis = GameUtil.visible(self, self.enemy); + if (GameUtil.enemy_vis) { + self.monsterinfo.search_time = GameBase.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; + // } + + GameUtil.enemy_infront = GameUtil.infront(self, self.enemy); + GameUtil.enemy_range = GameUtil.range(self, self.enemy); + Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, temp); + GameUtil.enemy_yaw = Math3D.vectoyaw(temp); + + // JDC self.ideal_yaw = enemy_yaw; + + if (self.monsterinfo.attack_state == Defines.AS_MISSILE) { + ai_run_missile(self); + return true; + } + if (self.monsterinfo.attack_state == Defines.AS_MELEE) { + ai_run_melee(self); + return true; + } + + // if enemy is not currently visible, we will never attack + if (!GameUtil.enemy_vis) + return false; + + return self.monsterinfo.checkattack.think(self); + } + + 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 &= ~pmove_t.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[Defines.PITCH] > 56) + angles[Defines.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 = GameBase.gi.trace(ownerv, Globals.vec3_origin, + Globals.vec3_origin, o, targ, Defines.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 = GameBase.gi.trace(goal, Globals.vec3_origin, + Globals.vec3_origin, o, targ, Defines.MASK_SOLID); + if (trace.fraction < 1) { + Math3D.VectorCopy(trace.endpos, goal); + goal[2] -= 6; + } + + Math3D.VectorCopy(goal, o); + o[2] -= 6; + trace = GameBase.gi.trace(goal, Globals.vec3_origin, + Globals.vec3_origin, o, targ, Defines.MASK_SOLID); + if (trace.fraction < 1) { + Math3D.VectorCopy(trace.endpos, goal); + goal[2] += 6; + } + + if (targ.deadflag != 0) + ent.client.ps.pmove.pm_type = Defines.PM_DEAD; + else + ent.client.ps.pmove.pm_type = Defines.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[Defines.ROLL] = 40; + ent.client.ps.viewangles[Defines.PITCH] = -15; + ent.client.ps.viewangles[Defines.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 |= pmove_t.PMF_NO_PREDICTION; + SV_WORLD.SV_LinkEdict(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 > GameBase.maxclients.value) + i = 1; + e = GameBase.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) GameBase.maxclients.value; + e = GameBase.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 <= GameBase.maxclients.value; i++) { + other = GameBase.g_edicts[i]; + if (other.inuse && !other.client.resp.spectator) { + ent.client.chase_target = other; + ent.client.update_chase = true; + UpdateChaseCam(ent); + return; + } + } + GameBase.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 < GameBase.game.num_items; i++) { + it = itemlist[i]; + GameBase.gi.configstring(Defines.CS_ITEMS + i, it.pickup_name); + } + + GameUtil.jacket_armor_index = GameUtil.ITEM_INDEX(GameUtil + .FindItem("Jacket Armor")); + GameUtil.combat_armor_index = GameUtil.ITEM_INDEX(GameUtil + .FindItem("Combat Armor")); + GameUtil.body_armor_index = GameUtil.ITEM_INDEX(GameUtil + .FindItem("Body Armor")); + GameUtil.power_screen_index = GameUtil.ITEM_INDEX(GameUtil + .FindItem("Power Screen")); + GameUtil.power_shield_index = GameUtil.ITEM_INDEX(GameUtil + .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 <= Defines.MAX_ITEMS; i++) { + index = (cl.pers.selected_item + i) % Defines.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 <= Defines.MAX_ITEMS; i++) { + index = (cl.pers.selected_item + Defines.MAX_ITEMS - i) + % Defines.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 == Defines.AMMO_BULLETS) + max = ent.client.pers.max_bullets; + else if (item.tag == Defines.AMMO_SHELLS) + max = ent.client.pers.max_shells; + else if (item.tag == Defines.AMMO_ROCKETS) + max = ent.client.pers.max_rockets; + else if (item.tag == Defines.AMMO_GRENADES) + max = ent.client.pers.max_grenades; + else if (item.tag == Defines.AMMO_CELLS) + max = ent.client.pers.max_cells; + else if (item.tag == Defines.AMMO_SLUGS) + max = ent.client.pers.max_slugs; + else + return false; + + index = GameUtil.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) + GameBase.gi.soundindex(it.pickup_sound); + + if (it.world_model != null) + GameBase.gi.modelindex(it.world_model); + + if (it.view_model != null) + GameBase.gi.modelindex(it.view_model); + + if (it.icon != null) + GameBase.gi.imageindex(it.icon); + + // parse everything for its ammo + if (it.ammo != null && it.ammo.length() != 0) { + ammo = GameUtil.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 >= Defines.MAX_QPATH || len < 5) + GameBase.gi + .error("PrecacheItem: it.classname has bad precache string: " + + s); + + // determine type based on extension + if (data.endsWith("md2")) + GameBase.gi.modelindex(data); + else if (data.endsWith("sp2")) + GameBase.gi.modelindex(data); + else if (data.endsWith("wav")) + GameBase.gi.soundindex(data); + else if (data.endsWith("pcx")) + GameBase.gi.imageindex(data); + else + GameBase.gi.error("PrecacheItem: bad precache string: " + data); + } + } + + /* + * ============ 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; + GameBase.gi.dprintf("" + ent.classname + " at " + + Lib.vtos(ent.s.origin) + + " has invalid spawnflags set\n"); + } + } + + // some items will be prevented in deathmatch + if (GameBase.deathmatch.value != 0) { + if (((int) GameBase.dmflags.value & Defines.DF_NO_ARMOR) != 0) { + if (item.pickup == Pickup_Armor + || item.pickup == Pickup_PowerArmor) { + GameUtil.G_FreeEdict(ent); + return; + } + } + if (((int) GameBase.dmflags.value & Defines.DF_NO_ITEMS) != 0) { + if (item.pickup == Pickup_Powerup) { + GameUtil.G_FreeEdict(ent); + return; + } + } + if (((int) GameBase.dmflags.value & Defines.DF_NO_HEALTH) != 0) { + if (item.pickup == GameUtil.Pickup_Health + || item.pickup == Pickup_Adrenaline + || item.pickup == Pickup_AncientHead) { + GameUtil.G_FreeEdict(ent); + return; + } + } + if (((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO) != 0) { + if ((item.flags == Defines.IT_AMMO) + || (Lib.strcmp(ent.classname, "weapon_bfg") == 0)) { + GameUtil.G_FreeEdict(ent); + return; + } + } + } + + if (GameBase.coop.value != 0 + && (Lib.strcmp(ent.classname, "key_power_cube") == 0)) { + ent.spawnflags |= (1 << (8 + GameBase.level.power_cubes)); + GameBase.level.power_cubes++; + } + + // don't let them drop items that stay in a coop game + if ((GameBase.coop.value != 0) + && (item.flags & Defines.IT_STAY_COOP) != 0) { + item.drop = null; + } + + ent.item = item; + ent.nextthink = GameBase.level.time + 2 * Defines.FRAMETIME; + // items start after other solids + ent.think = droptofloor; + ent.s.effects = item.world_model_flags; + ent.s.renderfx = Defines.RF_GLOW; + + if (ent.model != null) + GameBase.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[Defines.STAT_PICKUP_ICON] = (short) GameBase.gi + .imageindex(ent.item.icon); + other.client.ps.stats[Defines.STAT_PICKUP_STRING] = (short) (Defines.CS_ITEMS + GameUtil + .ITEM_INDEX(ent.item)); + other.client.pickup_msg_time = GameBase.level.time + 3.0f; + + // change selected item + if (ent.item.use != null) + other.client.pers.selected_item = other.client.ps.stats[Defines.STAT_SELECTED_ITEM] = (short) GameUtil + .ITEM_INDEX(ent.item); + + if (ent.item.pickup == GameUtil.Pickup_Health) { + if (ent.count == 2) + GameBase.gi.sound(other, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/s_health.wav"), 1, + Defines.ATTN_NORM, 0); + else if (ent.count == 10) + GameBase.gi.sound(other, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/n_health.wav"), 1, + Defines.ATTN_NORM, 0); + else if (ent.count == 25) + GameBase.gi.sound(other, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/l_health.wav"), 1, + Defines.ATTN_NORM, 0); + else + // (ent.count == 100) + GameBase.gi.sound(other, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/m_health.wav"), 1, + Defines.ATTN_NORM, 0); + } else if (ent.item.pickup_sound != null) { + GameBase.gi.sound(other, Defines.CHAN_ITEM, GameBase.gi + .soundindex(ent.item.pickup_sound), 1, + Defines.ATTN_NORM, 0); + } + } + + if (0 == (ent.spawnflags & Defines.ITEM_TARGETS_USED)) { + GameUtil.G_UseTargets(ent, other); + ent.spawnflags |= Defines.ITEM_TARGETS_USED; + } + + if (!taken) + return; + + if (!((GameBase.coop.value != 0) && (ent.item.flags & Defines.IT_STAY_COOP) != 0) + || 0 != (ent.spawnflags & (Defines.DROPPED_ITEM | Defines.DROPPED_PLAYER_ITEM))) { + if ((ent.flags & Defines.FL_RESPAWN) != 0) + ent.flags &= ~Defines.FL_RESPAWN; + else + GameUtil.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 = GameBase.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[Defines.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 (GameBase.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) (GameBase.dmflags.value) & Defines.DF_QUAD_DROP)) + quad = false; + else + quad = (self.client.quad_framenum > (GameBase.level.framenum + 10)); + + if (item != null && quad) + spread = 22.5f; + else + spread = 0.0f; + + if (item != null) { + self.client.v_angle[Defines.YAW] -= spread; + drop = GameUtil.Drop_Item(self, item); + self.client.v_angle[Defines.YAW] += spread; + drop.spawnflags = Defines.DROPPED_PLAYER_ITEM; + } + + if (quad) { + self.client.v_angle[Defines.YAW] += spread; + drop = GameUtil.Drop_Item(self, GameUtil + .FindItemByClassname("item_quad")); + self.client.v_angle[Defines.YAW] -= spread; + drop.spawnflags |= Defines.DROPPED_PLAYER_ITEM; + + drop.touch = GameUtil.Touch_Item; + drop.nextthink = GameBase.level.time + + (self.client.quad_framenum - GameBase.level.framenum) + * Defines.FRAMETIME; + drop.think = GameUtil.G_FreeEdictA; + } + } + + 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 = GameUtil.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]; + + GameBase.gi.setmodel(gib, gibname); + gib.solid = Defines.SOLID_NOT; + gib.s.effects |= Defines.EF_GIB; + gib.flags |= Defines.FL_NO_KNOCKBACK; + gib.takedamage = Defines.DAMAGE_YES; + gib.die = gib_die; + + if (type == Defines.GIB_ORGANIC) { + gib.movetype = Defines.MOVETYPE_TOSS; + gib.touch = gib_touch; + vscale = 0.5f; + } else { + gib.movetype = Defines.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 = GameUtil.G_FreeEdictA; + gib.nextthink = GameBase.level.time + 10 + Lib.random() * 10; + + GameBase.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; + GameBase.gi.setmodel(self, gibname); + self.solid = Defines.SOLID_NOT; + self.s.effects |= Defines.EF_GIB; + self.s.effects &= ~Defines.EF_FLIES; + self.s.sound = 0; + self.flags |= Defines.FL_NO_KNOCKBACK; + self.svflags &= ~Defines.SVF_MONSTER; + self.takedamage = Defines.DAMAGE_YES; + self.die = gib_die; + + if (type == Defines.GIB_ORGANIC) { + self.movetype = Defines.MOVETYPE_TOSS; + self.touch = gib_touch; + vscale = 0.5f; + } else { + self.movetype = Defines.MOVETYPE_BOUNCE; + vscale = 1.0f; + } + + VelocityForDamage(damage, vd); + Math3D.VectorMA(self.velocity, vscale, vd, self.velocity); + ClipGibVelocity(self); + + self.avelocity[Defines.YAW] = Lib.crandom() * 600f; + + self.think = GameUtil.G_FreeEdictA; + self.nextthink = GameBase.level.time + 10 + Lib.random() * 10; + + GameBase.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; + GameBase.gi.setmodel(self, gibname); + Math3D.VectorSet(self.mins, -16, -16, 0); + Math3D.VectorSet(self.maxs, 16, 16, 16); + + self.takedamage = Defines.DAMAGE_NO; + self.solid = Defines.SOLID_NOT; + self.s.effects = Defines.EF_GIB; + self.s.sound = 0; + self.flags |= Defines.FL_NO_KNOCKBACK; + + self.movetype = Defines.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 = Defines.ANIM_DEATH; + self.client.anim_end = self.s.frame; + } else { + self.think = null; + self.nextthink = 0; + } + + GameBase.gi.linkentity(self); + } + + public static void ThrowDebris(edict_t self, String modelname, float speed, + float[] origin) { + edict_t chunk; + float[] v = { 0, 0, 0 }; + + chunk = GameUtil.G_Spawn(); + Math3D.VectorCopy(origin, chunk.s.origin); + GameBase.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 = Defines.MOVETYPE_BOUNCE; + chunk.solid = Defines.SOLID_NOT; + chunk.avelocity[0] = Lib.random() * 600; + chunk.avelocity[1] = Lib.random() * 600; + chunk.avelocity[2] = Lib.random() * 600; + chunk.think = GameUtil.G_FreeEdictA; + chunk.nextthink = GameBase.level.time + 5 + Lib.random() * 5; + chunk.s.frame = 0; + chunk.flags = 0; + chunk.classname = "debris"; + chunk.takedamage = Defines.DAMAGE_YES; + chunk.die = debris_die; + GameBase.gi.linkentity(chunk); + } + + public static void BecomeExplosion1(edict_t self) { + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_EXPLOSION1); + GameBase.gi.WritePosition(self.s.origin); + GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); + + GameUtil.G_FreeEdict(self); + } + + public static void BecomeExplosion2(edict_t self) { + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_EXPLOSION2); + GameBase.gi.WritePosition(self.s.origin); + GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); + + GameUtil.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 (GameBase.coop.value != 0 && attacker.client != null) + GameBase.meansOfDeath |= Defines.MOD_FRIENDLY_FIRE; + + if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0) { + ff = (GameBase.meansOfDeath & Defines.MOD_FRIENDLY_FIRE) != 0; + mod = GameBase.meansOfDeath & ~Defines.MOD_FRIENDLY_FIRE; + message = null; + message2 = ""; + + switch (mod) { + case Defines.MOD_SUICIDE: + message = "suicides"; + break; + case Defines.MOD_FALLING: + message = "cratered"; + break; + case Defines.MOD_CRUSH: + message = "was squished"; + break; + case Defines.MOD_WATER: + message = "sank like a rock"; + break; + case Defines.MOD_SLIME: + message = "melted"; + break; + case Defines.MOD_LAVA: + message = "does a back flip into the lava"; + break; + case Defines.MOD_EXPLOSIVE: + case Defines.MOD_BARREL: + message = "blew up"; + break; + case Defines.MOD_EXIT: + message = "found a way out"; + break; + case Defines.MOD_TARGET_LASER: + message = "saw the light"; + break; + case Defines.MOD_TARGET_BLASTER: + message = "got blasted"; + break; + case Defines.MOD_BOMB: + case Defines.MOD_SPLASH: + case Defines.MOD_TRIGGER_HURT: + message = "was in the wrong place"; + break; + } + if (attacker == self) { + switch (mod) { + case Defines.MOD_HELD_GRENADE: + message = "tried to put the pin back in"; + break; + case Defines.MOD_HG_SPLASH: + case Defines.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 Defines.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 Defines.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) { + GameBase.gi.bprintf(Defines.PRINT_MEDIUM, "" + + self.client.pers.netname + " " + message + ".\n"); + if (GameBase.deathmatch.value != 0) + self.client.resp.score--; + self.enemy = null; + return; + } + + self.enemy = attacker; + + if (attacker != null && attacker.client != null) { + switch (mod) { + case Defines.MOD_BLASTER: + message = "was blasted by"; + break; + case Defines.MOD_SHOTGUN: + message = "was gunned down by"; + break; + case Defines.MOD_SSHOTGUN: + message = "was blown away by"; + message2 = "'s super shotgun"; + break; + case Defines.MOD_MACHINEGUN: + message = "was machinegunned by"; + break; + case Defines.MOD_CHAINGUN: + message = "was cut in half by"; + message2 = "'s chaingun"; + break; + case Defines.MOD_GRENADE: + message = "was popped by"; + message2 = "'s grenade"; + break; + case Defines.MOD_G_SPLASH: + message = "was shredded by"; + message2 = "'s shrapnel"; + break; + case Defines.MOD_ROCKET: + message = "ate"; + message2 = "'s rocket"; + break; + case Defines.MOD_R_SPLASH: + message = "almost dodged"; + message2 = "'s rocket"; + break; + case Defines.MOD_HYPERBLASTER: + message = "was melted by"; + message2 = "'s hyperblaster"; + break; + case Defines.MOD_RAILGUN: + message = "was railed by"; + break; + case Defines.MOD_BFG_LASER: + message = "saw the pretty lights from"; + message2 = "'s BFG"; + break; + case Defines.MOD_BFG_BLAST: + message = "was disintegrated by"; + message2 = "'s BFG blast"; + break; + case Defines.MOD_BFG_EFFECT: + message = "couldn't hide from"; + message2 = "'s BFG"; + break; + case Defines.MOD_HANDGRENADE: + message = "caught"; + message2 = "'s handgrenade"; + break; + case Defines.MOD_HG_SPLASH: + message = "didn't see"; + message2 = "'s handgrenade"; + break; + case Defines.MOD_HELD_GRENADE: + message = "feels"; + message2 = "'s pain"; + break; + case Defines.MOD_TELEFRAG: + message = "tried to invade"; + message2 = "'s personal space"; + break; + } + if (message != null) { + GameBase.gi.bprintf(Defines.PRINT_MEDIUM, + self.client.pers.netname + " " + message + " " + + attacker.client.pers.netname + "" + + message2); + if (GameBase.deathmatch.value != 0) { + if (ff) + attacker.client.resp.score--; + else + attacker.client.resp.score++; + } + return; + } + } + } + + GameBase.gi.bprintf(Defines.PRINT_MEDIUM, self.client.pers.netname + + " died.\n"); + if (GameBase.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[Defines.MAX_CLIENTS]; + int sortedscores[] = new int[Defines.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 < GameBase.game.maxclients; i++) { + cl_ent = GameBase.g_edicts[1 + i]; + if (!cl_ent.inuse || GameBase.game.clients[i].resp.spectator) + continue; + score = GameBase.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 = string.length(); + + // add the clients in sorted order + if (total > 12) + total = 12; + + for (i = 0; i < total; i++) { + cl = GameBase.game.clients[sorted[i]]; + cl_ent = GameBase.g_edicts[1 + sorted[i]]; + + picnum = GameBase.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 = entry.length(); + 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 + " " + + (GameBase.level.framenum - cl.resp.enterframe) / 600f + + " "; + + j = entry.length(); + + if (stringlength + j > 1024) + break; + + string += entry; + // was: strcpy(string + stringlength, entry); + stringlength += j; + } + + GameBase.gi.WriteByte(Defines.svc_layout); + GameBase.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); + GameBase.gi.unicast(ent, true); + } + + /* + * ================== HelpComputer + * + * Draw help computer. ================== + */ + public static void HelpComputer(edict_t ent) { + StringBuffer sb = new StringBuffer(256); + String sk; + + if (GameBase.skill.value == 0) + sk = "easy"; + else if (GameBase.skill.value == 1) + sk = "medium"; + else if (GameBase.skill.value == 2) + sk = "hard"; + else + sk = "hard+"; + + // send the layout + sb.append("xv 32 yv 8 picn help "); // background + sb.append("xv 202 yv 12 string2 \"").append(sk).append("\" "); // skill + sb.append("xv 0 yv 24 cstring2 \"").append(GameBase.level.level_name) + .append("\" "); // level name + sb.append("xv 0 yv 54 cstring2 \"").append(GameBase.game.helpmessage1) + .append("\" "); // help 1 + sb.append("xv 0 yv 110 cstring2 \"").append(GameBase.game.helpmessage2) + .append("\" "); // help 2 + sb.append("xv 50 yv 164 string2 \" kills goals secrets\" "); + sb.append("xv 50 yv 172 string2 \""); + sb.append(Com.sprintf("%3i/%3i %i/%i %i/%i\" ", new Vargs(6) + .add(GameBase.level.killed_monsters).add( + GameBase.level.total_monsters).add( + GameBase.level.found_goals).add( + GameBase.level.total_goals).add( + GameBase.level.found_secrets).add( + GameBase.level.total_secrets))); + + GameBase.gi.WriteByte(Defines.svc_layout); + GameBase.gi.WriteString(sb.toString()); + GameBase.gi.unicast(ent, true); + } + + /** + * 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 = GameBase.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 (GameBase.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, Defines.IT_WEAPON); + else if (Lib.Q_stricmp(cmd, "invprevw") == 0) + SelectPrevItem(ent, Defines.IT_WEAPON); + else if (Lib.Q_stricmp(cmd, "invnextp") == 0) + SelectNextItem(ent, Defines.IT_POWERUP); + else if (Lib.Q_stricmp(cmd, "invprevp") == 0) + SelectPrevItem(ent, Defines.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 boolean Pickup_PowerArmor(edict_t ent, edict_t other) { + int quantity; + + quantity = other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)]; + + other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)]++; + + if (GameBase.deathmatch.value != 0) { + if (0 == (ent.spawnflags & Defines.DROPPED_ITEM)) + GameUtil.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 void InitItems() { + GameBase.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 (GameBase.deathmatch.value != 0 + && ((int) GameBase.dmflags.value & Defines.DF_NO_HEALTH) != 0) { + GameUtil.G_FreeEdict(self); + } + + self.model = "models/items/healing/medium/tris.md2"; + self.count = 10; + SpawnItem(self, GameUtil.FindItem("Health")); + GameBase.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 (GameBase.deathmatch.value != 0 + && ((int) GameBase.dmflags.value & Defines.DF_NO_HEALTH) != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + self.model = "models/items/healing/stimpack/tris.md2"; + self.count = 2; + SpawnItem(self, GameUtil.FindItem("Health")); + self.style = Defines.HEALTH_IGNORE_MAX; + GameBase.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 (GameBase.deathmatch.value != 0 + && ((int) GameBase.dmflags.value & Defines.DF_NO_HEALTH) != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + self.model = "models/items/healing/large/tris.md2"; + self.count = 25; + SpawnItem(self, GameUtil.FindItem("Health")); + GameBase.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 (GameBase.deathmatch.value != 0 + && ((int) GameBase.dmflags.value & Defines.DF_NO_HEALTH) != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + self.model = "models/items/mega_h/tris.md2"; + self.count = 100; + SpawnItem(self, GameUtil.FindItem("Health")); + GameBase.gi.soundindex("items/m_health.wav"); + self.style = Defines.HEALTH_IGNORE_MAX | Defines.HEALTH_TIMED; + } + + public static ItemUseAdapter Use_PowerArmor = new ItemUseAdapter() { + public void use(edict_t ent, gitem_t item) { + int index; + + if ((ent.flags & Defines.FL_POWER_ARMOR) != 0) { + ent.flags &= ~Defines.FL_POWER_ARMOR; + GameBase.gi + .sound(ent, Defines.CHAN_AUTO, GameBase.gi + .soundindex("misc/power2.wav"), 1, + Defines.ATTN_NORM, 0); + } else { + index = GameUtil.ITEM_INDEX(GameUtil.FindItem("cells")); + if (0 == ent.client.pers.inventory[index]) { + GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, + "No cells for power armor.\n"); + return; + } + ent.flags |= Defines.FL_POWER_ARMOR; + GameBase.gi + .sound(ent, Defines.CHAN_AUTO, GameBase.gi + .soundindex("misc/power1.wav"), 1, + Defines.ATTN_NORM, 0); + } + } + }; + + public static ItemDropAdapter Drop_Ammo = new ItemDropAdapter() { + public void drop(edict_t ent, gitem_t item) { + edict_t dropped; + int index; + + index = GameUtil.ITEM_INDEX(item); + dropped = GameUtil.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 == Defines.AMMO_GRENADES + && item.tag == Defines.AMMO_GRENADES + && ent.client.pers.inventory[index] - dropped.count <= 0) { + GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, + "Can't drop current weapon\n"); + GameUtil.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) { + GameUtil.Drop_Item(ent, item); + ent.client.pers.inventory[GameUtil.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 & Defines.FL_POWER_ARMOR) + && (ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)] == 1)) + Use_PowerArmor.use(ent, item); + Drop_General.drop(ent, item); + } + }; + + public static gitem_t itemlist[] = { + //leave index 0 alone + new gitem_t(null, null, null, null, null, null, null, 0, null, + null, null, 0, 0, null, 0, 0, null, 0, 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", + Defines.EF_ROTATE, null, + /* icon */ + "i_bodyarmor", + /* pickup */ + "Body Armor", + /* width */ + 3, 0, null, Defines.IT_ARMOR, 0, bodyarmor_info, + Defines.ARMOR_BODY, + /* precache */ + ""), + + /* + * QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) + */ + new gitem_t("item_armor_combat", 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, combatarmor_info, + Defines.ARMOR_COMBAT, + /* precache */ + ""), + + /* + * QUAKED item_armor_jacket (.3 .3 1) (-16 -16 -16) (16 16 16) + */ + new gitem_t("item_armor_jacket", Pickup_Armor, null, null, null, + "misc/ar1_pkup.wav", "models/items/armor/jacket/tris.md2", + Defines.EF_ROTATE, null, + /* icon */ + "i_jacketarmor", + /* pickup */ + "Jacket Armor", + /* width */ + 3, 0, null, Defines.IT_ARMOR, 0, jacketarmor_info, + Defines.ARMOR_JACKET, + /* precache */ + ""), + + /* + * QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) + */ + new gitem_t("item_armor_shard", Pickup_Armor, null, null, null, + "misc/ar2_pkup.wav", "models/items/armor/shard/tris.md2", + Defines.EF_ROTATE, null, + /* icon */ + "i_jacketarmor", + /* pickup */ + "Armor Shard", + /* width */ + 3, 0, null, Defines.IT_ARMOR, 0, null, Defines.ARMOR_SHARD, + /* precache */ + ""), + + /* + * QUAKED item_power_screen (.3 .3 1) (-16 -16 -16) (16 16 16) + */ + new gitem_t("item_power_screen", Pickup_PowerArmor, Use_PowerArmor, + Drop_PowerArmor, null, "misc/ar3_pkup.wav", + "models/items/armor/screen/tris.md2", Defines.EF_ROTATE, + null, + /* icon */ + "i_powerscreen", + /* pickup */ + "Power Screen", + /* width */ + 0, 60, null, Defines.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", Defines.EF_ROTATE, + null, + /* icon */ + "i_powershield", + /* pickup */ + "Power Shield", + /* width */ + 0, 60, null, Defines.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, Defines.IT_WEAPON + | Defines.IT_STAY_COOP, Defines.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", Defines.EF_ROTATE, + "models/weapons/v_shotg/tris.md2", + /* icon */ + "w_shotgun", + /* pickup */ + "Shotgun", 0, 1, "Shells", Defines.IT_WEAPON + | Defines.IT_STAY_COOP, Defines.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", Defines.EF_ROTATE, + "models/weapons/v_shotg2/tris.md2", + /* icon */ + "w_sshotgun", + /* pickup */ + "Super Shotgun", 0, 2, "Shells", Defines.IT_WEAPON + | Defines.IT_STAY_COOP, Defines.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", + Defines.EF_ROTATE, + "models/weapons/v_machn/tris.md2", + /* icon */ + "w_machinegun", + /* pickup */ + "Machinegun", + 0, + 1, + "Bullets", + Defines.IT_WEAPON | Defines.IT_STAY_COOP, + Defines.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", + Defines.EF_ROTATE, + "models/weapons/v_chain/tris.md2", + /* icon */ + "w_chaingun", + /* pickup */ + "Chaingun", + 0, + 1, + "Bullets", + Defines.IT_WEAPON | Defines.IT_STAY_COOP, + Defines.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", + Defines.IT_AMMO | Defines.IT_WEAPON, + Defines.WEAP_GRENADES, + null, + Defines.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", + Defines.EF_ROTATE, + "models/weapons/v_launch/tris.md2", + /* icon */ + "w_glauncher", + /* pickup */ + "Grenade Launcher", + 0, + 1, + "Grenades", + Defines.IT_WEAPON | Defines.IT_STAY_COOP, + Defines.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", + Defines.EF_ROTATE, + "models/weapons/v_rocket/tris.md2", + /* icon */ + "w_rlauncher", + /* pickup */ + "Rocket Launcher", + 0, + 1, + "Rockets", + Defines.IT_WEAPON | Defines.IT_STAY_COOP, + Defines.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", + Defines.EF_ROTATE, + "models/weapons/v_hyperb/tris.md2", + /* icon */ + "w_hyperblaster", + /* pickup */ + "HyperBlaster", + 0, + 1, + "Cells", + Defines.IT_WEAPON | Defines.IT_STAY_COOP, + Defines.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", Defines.EF_ROTATE, + "models/weapons/v_rail/tris.md2", + /* icon */ + "w_railgun", + /* pickup */ + "Railgun", 0, 1, "Slugs", Defines.IT_WEAPON + | Defines.IT_STAY_COOP, Defines.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", + Defines.EF_ROTATE, + "models/weapons/v_bfg/tris.md2", + /* icon */ + "w_bfg", + /* pickup */ + "BFG10K", + 0, + 50, + "Cells", + Defines.IT_WEAPON | Defines.IT_STAY_COOP, + Defines.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", Pickup_Ammo, null, 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, Defines.IT_AMMO, 0, null, Defines.AMMO_SHELLS, + /* precache */ + ""), + + /* + * QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) + */ + new gitem_t("ammo_bullets", Pickup_Ammo, null, 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, Defines.IT_AMMO, 0, null, + Defines.AMMO_BULLETS, + /* precache */ + ""), + + /* + * QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) + */ + new gitem_t("ammo_cells", Pickup_Ammo, null, 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, Defines.IT_AMMO, 0, null, Defines.AMMO_CELLS, + /* precache */ + ""), + + /* + * QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) + */ + new gitem_t("ammo_rockets", Pickup_Ammo, null, 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, Defines.IT_AMMO, 0, null, Defines.AMMO_ROCKETS, + /* precache */ + ""), + + /* + * QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) + */ + new gitem_t("ammo_slugs", Pickup_Ammo, null, 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, Defines.IT_AMMO, 0, null, Defines.AMMO_SLUGS, + /* precache */ + ""), + + // + // POWERUP ITEMS + // + /* + * QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) + */ + new gitem_t("item_quad", Pickup_Powerup, GameUtil.Use_Quad, + Drop_General, null, "items/pkup.wav", + "models/items/quaddama/tris.md2", Defines.EF_ROTATE, null, + /* icon */ + "p_quad", + /* pickup */ + "Quad Damage", + /* width */ + 2, 60, null, Defines.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, + GameUtil.Use_Invulnerability, Drop_General, null, + "items/pkup.wav", "models/items/invulner/tris.md2", + Defines.EF_ROTATE, null, + /* icon */ + "p_invulnerability", + /* pickup */ + "Invulnerability", + /* width */ + 2, 300, null, Defines.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, GameUtil.Use_Silencer, + Drop_General, null, "items/pkup.wav", + "models/items/silencer/tris.md2", Defines.EF_ROTATE, null, + /* icon */ + "p_silencer", + /* pickup */ + "Silencer", + /* width */ + 2, 60, null, Defines.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, GameUtil.Use_Breather, + Drop_General, null, "items/pkup.wav", + "models/items/breather/tris.md2", Defines.EF_ROTATE, null, + /* icon */ + "p_rebreather", + /* pickup */ + "Rebreather", + /* width */ + 2, 60, null, Defines.IT_STAY_COOP | Defines.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, GameUtil.Use_Envirosuit, + Drop_General, null, "items/pkup.wav", + "models/items/enviro/tris.md2", Defines.EF_ROTATE, null, + /* icon */ + "p_envirosuit", + /* pickup */ + "Environment Suit", + /* width */ + 2, 60, null, Defines.IT_STAY_COOP | Defines.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", + Defines.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", + Defines.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", + Defines.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", GameUtil.Pickup_Pack, null, null, null, + "items/pkup.wav", "models/items/pack/tris.md2", + Defines.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", GameUtil.Pickup_Key, null, Drop_General, + null, "items/pkup.wav", + "models/items/keys/data_cd/tris.md2", Defines.EF_ROTATE, + null, "k_datacd", "Data CD", 2, 0, null, + Defines.IT_STAY_COOP | Defines.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", GameUtil.Pickup_Key, null, + Drop_General, null, "items/pkup.wav", + "models/items/keys/power/tris.md2", Defines.EF_ROTATE, + null, "k_powercube", "Power Cube", 2, 0, null, + Defines.IT_STAY_COOP | Defines.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", GameUtil.Pickup_Key, null, Drop_General, + null, "items/pkup.wav", + "models/items/keys/pyramid/tris.md2", Defines.EF_ROTATE, + null, "k_pyramid", "Pyramid Key", 2, 0, null, + Defines.IT_STAY_COOP | Defines.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", GameUtil.Pickup_Key, null, + Drop_General, null, "items/pkup.wav", + "models/items/keys/spinner/tris.md2", Defines.EF_ROTATE, + null, "k_dataspin", "Data Spinner", 2, 0, null, + Defines.IT_STAY_COOP | Defines.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", GameUtil.Pickup_Key, null, Drop_General, + null, "items/pkup.wav", "models/items/keys/pass/tris.md2", + Defines.EF_ROTATE, null, "k_security", "Security Pass", 2, + 0, null, Defines.IT_STAY_COOP | Defines.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", GameUtil.Pickup_Key, null, + Drop_General, null, "items/pkup.wav", + "models/items/keys/key/tris.md2", Defines.EF_ROTATE, null, + "k_bluekey", "Blue Key", 2, 0, null, Defines.IT_STAY_COOP + | Defines.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", GameUtil.Pickup_Key, null, Drop_General, + null, "items/pkup.wav", + "models/items/keys/red_key/tris.md2", Defines.EF_ROTATE, + null, "k_redkey", "Red Key", 2, 0, null, + Defines.IT_STAY_COOP | Defines.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", GameUtil.Pickup_Key, null, + Drop_General, null, "items/pkup.wav", + "models/monsters/commandr/head/tris.md2", Defines.EF_GIB, + null, + /* icon */ + "k_comhead", + /* pickup */ + "Commander's Head", + /* width */ + 2, 0, null, Defines.IT_STAY_COOP | Defines.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", GameUtil.Pickup_Key, null, + Drop_General, null, "items/pkup.wav", + "models/items/keys/target/tris.md2", Defines.EF_ROTATE, + null, + /* icon */ + "i_airstrike", + /* pickup */ + "Airstrike Marker", + /* width */ + 2, 0, null, Defines.IT_STAY_COOP | Defines.IT_KEY, 0, null, + 0, + /* precache */ + ""), + new gitem_t(null, GameUtil.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 }; + + /** 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, + Defines.GIB_ORGANIC); + for (n = 0; n < 8; n++) + ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", + 500, Defines.GIB_METALLIC); + ThrowGib(self, "models/objects/gibs/chest/tris.md2", 500, + Defines.GIB_ORGANIC); + ThrowHead(self, "models/objects/gibs/gear/tris.md2", 500, + Defines.GIB_METALLIC); + self.deadflag = Defines.DEAD_DEAD; + return true; + } + + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_EXPLOSION1); + GameBase.gi.WritePosition(org); + GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); + + self.nextthink = GameBase.level.time + 0.1f; + return true; + } + }; + + public static EntThinkAdapter walkmonster_start_go = new EntThinkAdapter() { + public boolean think(edict_t self) { + + if (0 == (self.spawnflags & 2) && GameBase.level.time < 1) { + M.M_droptofloor.think(self); + + if (self.groundentity != null) + if (!M.M_walkmove(self, 0, 0)) + GameBase.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)) + GameBase.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 |= Defines.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 |= Defines.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[Defines.YAW], dist); + + if (GameUtil.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[Defines.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) { + if (self.index == 312) + self.index = 312; + + M.M_MoveToGoal(self, dist); + + // check for noticing a player + if (GameUtil.FindTarget(self)) + return; + + if ((self.monsterinfo.search != null) + && (GameBase.level.time > self.monsterinfo.idle_time)) { + if (self.monsterinfo.idle_time != 0) { + self.monsterinfo.search.think(self); + self.monsterinfo.idle_time = GameBase.level.time + 15 + + Globals.rnd.nextFloat() * 15; + } else { + self.monsterinfo.idle_time = GameBase.level.time + + Globals.rnd.nextFloat() * 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[Defines.YAW], dist); + + if ((self.monsterinfo.aiflags & Defines.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[Defines.YAW] != self.ideal_yaw + && 0 != (self.monsterinfo.aiflags & Defines.AI_TEMP_STAND_GROUND)) { + self.monsterinfo.aiflags &= ~(Defines.AI_STAND_GROUND | Defines.AI_TEMP_STAND_GROUND); + self.monsterinfo.run.think(self); + } + M.M_ChangeYaw(self); + ai_checkattack(self, 0); + } else + GameUtil.FindTarget(self); + return; + } + + if (GameUtil.FindTarget(self)) + return; + + if (GameBase.level.time > self.monsterinfo.pausetime) { + self.monsterinfo.walk.think(self); + return; + } + + if (0 == (self.spawnflags & 1) && (self.monsterinfo.idle != null) + && (GameBase.level.time > self.monsterinfo.idle_time)) { + if (self.monsterinfo.idle_time != 0) { + self.monsterinfo.idle.think(self); + self.monsterinfo.idle_time = GameBase.level.time + 15 + + Globals.rnd.nextFloat() * 15; + } else { + self.monsterinfo.idle_time = GameBase.level.time + + Globals.rnd.nextFloat() * 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[Defines.YAW], dist); + } + }; + + /* + * ============= ai_run + * + * The monster has an enemy it is trying to kill ============= + *///ok + public static AIAdapter ai_run = new AIAdapter() { + public void ai(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; // mem + 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 & Defines.AI_COMBAT_POINT) != 0) { + M.M_MoveToGoal(self, dist); + return; + } + + if ((self.monsterinfo.aiflags & Defines.AI_SOUND_TARGET) != 0) { + Math3D.VectorSubtract(self.s.origin, self.enemy.s.origin, v); + if (Math3D.VectorLength(v) < 64) { + self.monsterinfo.aiflags |= (Defines.AI_STAND_GROUND | Defines.AI_TEMP_STAND_GROUND); + self.monsterinfo.stand.think(self); + return; + } + + M.M_MoveToGoal(self, dist); + + if (!GameUtil.FindTarget(self)) + return; + } + + if (ai_checkattack(self, dist)) + return; + + if (self.monsterinfo.attack_state == Defines.AS_SLIDING) { + ai_run_slide(self, dist); + return; + } + + if (GameUtil.enemy_vis) { + // if (self.aiflags & AI_LOST_SIGHT) + // dprint("regained sight\n"); + M.M_MoveToGoal(self, dist); + self.monsterinfo.aiflags &= ~Defines.AI_LOST_SIGHT; + Math3D.VectorCopy(self.enemy.s.origin, + self.monsterinfo.last_sighting); + self.monsterinfo.trail_time = GameBase.level.time; + return; + } + + // coop will change to another enemy if visible + if (GameBase.coop.value != 0) { + // FIXME: insane guys get mad with this, which causes crashes! + if (GameUtil.FindTarget(self)) + return; + } + + if ((self.monsterinfo.search_time != 0) + && (GameBase.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 = GameUtil.G_Spawn(); + self.goalentity = tempgoal; + + new1 = false; + + if (0 == (self.monsterinfo.aiflags & Defines.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 |= (Defines.AI_LOST_SIGHT | Defines.AI_PURSUIT_LAST_SEEN); + self.monsterinfo.aiflags &= ~(Defines.AI_PURSUE_NEXT | Defines.AI_PURSUE_TEMP); + new1 = true; + } + + if ((self.monsterinfo.aiflags & Defines.AI_PURSUE_NEXT) != 0) { + self.monsterinfo.aiflags &= ~Defines.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 = GameBase.level.time + 5; + + if ((self.monsterinfo.aiflags & Defines.AI_PURSUE_TEMP) != 0) { + // dprint("was temp goal; retrying original\n"); + self.monsterinfo.aiflags &= ~Defines.AI_PURSUE_TEMP; + marker = null; + Math3D.VectorCopy(self.monsterinfo.saved_goal, + self.monsterinfo.last_sighting); + new1 = true; + } else if ((self.monsterinfo.aiflags & Defines.AI_PURSUIT_LAST_SEEN) != 0) { + self.monsterinfo.aiflags &= ~Defines.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[Defines.YAW] = self.ideal_yaw = marker.s.angles[Defines.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 |= Defines.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 = GameBase.gi.trace(self.s.origin, self.mins, self.maxs, + self.monsterinfo.last_sighting, self, + Defines.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[Defines.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 = GameBase.gi.trace(self.s.origin, self.mins, self.maxs, + left_target, self, Defines.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 = GameBase.gi.trace(self.s.origin, self.mins, self.maxs, + right_target, self, Defines.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 |= Defines.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[Defines.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 |= Defines.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[Defines.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); + + GameUtil.G_FreeEdict(tempgoal); + + if (self != null) + self.goalentity = save; + } + }; + + public static EntUseAdapter Use_Item = new EntUseAdapter() { + public void use(edict_t ent, edict_t other, edict_t activator) { + ent.svflags &= ~Defines.SVF_NOCLIENT; + ent.use = null; + + if ((ent.spawnflags & Defines.ITEM_NO_TOUCH) != 0) { + ent.solid = Defines.SOLID_BBOX; + ent.touch = null; + } else { + ent.solid = Defines.SOLID_TRIGGER; + ent.touch = GameUtil.Touch_Item; + } + + GameBase.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); + ent.mins[0] = ent.mins[1] = ent.mins[2] = -15; + //v = Lib.tv(15, 15, 15); + //Math3D.VectorCopy(v, ent.maxs); + ent.maxs[0] = ent.maxs[1] = ent.maxs[2] = 15; + + if (ent.model != null) + GameBase.gi.setmodel(ent, ent.model); + else + GameBase.gi.setmodel(ent, ent.item.world_model); + ent.solid = Defines.SOLID_TRIGGER; + ent.movetype = Defines.MOVETYPE_TOSS; + ent.touch = GameUtil.Touch_Item; + + float v[] = { 0, 0, -128 }; + Math3D.VectorAdd(ent.s.origin, v, dest); + + tr = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, dest, ent, + Defines.MASK_SOLID); + if (tr.startsolid) { + GameBase.gi.dprintf("droptofloor: " + ent.classname + + " startsolid at " + Lib.vtos(ent.s.origin) + "\n"); + GameUtil.G_FreeEdict(ent); + return true; + } + + Math3D.VectorCopy(tr.endpos, ent.s.origin); + + if (ent.team != null) { + ent.flags &= ~Defines.FL_TEAMSLAVE; + ent.chain = ent.teamchain; + ent.teamchain = null; + + ent.svflags |= Defines.SVF_NOCLIENT; + ent.solid = Defines.SOLID_NOT; + if (ent == ent.teammaster) { + ent.nextthink = GameBase.level.time + Defines.FRAMETIME; + ent.think = GameUtil.DoRespawn; + } + } + + if ((ent.spawnflags & Defines.ITEM_NO_TOUCH) != 0) { + ent.solid = Defines.SOLID_BBOX; + ent.touch = null; + ent.s.effects &= ~Defines.EF_ROTATE; + ent.s.renderfx &= ~Defines.RF_GLOW; + } + + if ((ent.spawnflags & Defines.ITEM_TRIGGER_SPAWN) != 0) { + ent.svflags |= Defines.SVF_NOCLIENT; + ent.solid = Defines.SOLID_NOT; + ent.use = Use_Item; + } + + GameBase.gi.linkentity(ent); + return true; + } + }; + + public static EntThinkAdapter gib_think = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.s.frame++; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + + if (self.s.frame == 10) { + self.think = GameUtil.G_FreeEdictA; + self.nextthink = GameBase.level.time + 8 + + Globals.rnd.nextFloat() * 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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/fhit3.wav"), 1, Defines.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 == GameBase.sm_meat_index) { + self.s.frame++; + self.think = gib_think; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + } + } + } + }; + + public static EntDieAdapter gib_die = new EntDieAdapter() { + public void die(edict_t self, edict_t inflictor, edict_t attacker, + int damage, float[] point) { + GameUtil.G_FreeEdict(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) { + GameUtil.G_FreeEdict(self); + } + }; + + 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 = Defines.DAMAGE_YES; + self.movetype = Defines.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 |= Defines.SVF_DEADMONSTER; + + if (self.deadflag == 0) { + self.client.respawn_time = GameBase.level.time + 1.0f; + LookAtKiller(self, inflictor, attacker); + self.client.ps.pmove.pm_type = Defines.PM_DEAD; + ClientObituary(self, inflictor, attacker); + TossClientWeapon(self); + if (GameBase.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 < GameBase.game.num_items; n++) { + if (GameBase.coop.value != 0 + && (itemlist[n].flags & Defines.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 &= ~Defines.FL_POWER_ARMOR; + + if (self.health < -40) { // gib + GameBase.gi + .sound(self, Defines.CHAN_BODY, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 4; n++) + ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", + damage, Defines.GIB_ORGANIC); + ThrowClientHead(self, damage); + + self.takedamage = Defines.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 = Defines.ANIM_DEATH; + if ((self.client.ps.pmove.pm_flags & pmove_t.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; + } + + GameBase.gi.sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("*death" + ((Lib.rand() % 4) + 1) + + ".wav"), 1, Defines.ATTN_NORM, 0); + } + } + + self.deadflag = Defines.DEAD_DEAD; + + GameBase.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 = GameBase.game.clients[anum].ps.stats[Defines.STAT_FRAGS]; + int bnum1 = GameBase.game.clients[bnum].ps.stats[Defines.STAT_FRAGS]; + + if (anum1 < bnum1) + return -1; + if (anum1 > bnum1) + return 1; + return 0; + } + }; + +} \ No newline at end of file diff --git a/src/jake2/game/GameAIAdapters.java b/src/jake2/game/GameAIAdapters.java deleted file mode 100644 index 93f0a4d..0000000 --- a/src/jake2/game/GameAIAdapters.java +++ /dev/null @@ -1,1046 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: GameAIAdapters.java,v 1.4 2004-09-10 19:02:53 salomo Exp $ - -package jake2.game; - -import jake2.Defines; -import jake2.Globals; -import jake2.client.M; -import jake2.qcommon.Com; -import jake2.util.*; - -import java.util.*; - -public class GameAIAdapters { - /** 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++) - GameAI.ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", 500, Defines.GIB_ORGANIC); - for (n= 0; n < 8; n++) - GameAI.ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", 500, Defines.GIB_METALLIC); - GameAI.ThrowGib(self, "models/objects/gibs/chest/tris.md2", 500, Defines.GIB_ORGANIC); - GameAI.ThrowHead(self, "models/objects/gibs/gear/tris.md2", 500, Defines.GIB_METALLIC); - self.deadflag= Defines.DEAD_DEAD; - return true; - } - - GameBase.gi.WriteByte(Defines.svc_temp_entity); - GameBase.gi.WriteByte(Defines.TE_EXPLOSION1); - GameBase.gi.WritePosition(org); - GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); - - self.nextthink= GameBase.level.time + 0.1f; - return true; - } - }; - public static EntThinkAdapter walkmonster_start_go= new EntThinkAdapter() { - public boolean think(edict_t self) { - - if (0 == (self.spawnflags & 2) && GameBase.level.time < 1) { - M.M_droptofloor.think(self); - - if (self.groundentity != null) - if (!M.M_walkmove(self, 0, 0)) - GameBase.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) - MonsterAdapters.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)) - GameBase.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) - MonsterAdapters.monster_triggered_start.think(self); - return true; - } - }; - public static EntThinkAdapter flymonster_start= new EntThinkAdapter() { - public boolean think(edict_t self) { - self.flags |= Defines.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) - MonsterAdapters.monster_triggered_start.think(self); - return true; - } - }; - public static EntThinkAdapter swimmonster_start= new EntThinkAdapter() { - public boolean think(edict_t self) { - self.flags |= Defines.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[Defines.YAW], dist); - - if (GameUtil.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[Defines.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) { - if (self.index == 312) - self.index= 312; - - M.M_MoveToGoal(self, dist); - - // check for noticing a player - if (GameUtil.FindTarget(self)) - return; - - if ((self.monsterinfo.search != null) && (GameBase.level.time > self.monsterinfo.idle_time)) { - if (self.monsterinfo.idle_time != 0) { - self.monsterinfo.search.think(self); - self.monsterinfo.idle_time= GameBase.level.time + 15 + Globals.rnd.nextFloat() * 15; - } - else { - self.monsterinfo.idle_time= GameBase.level.time + Globals.rnd.nextFloat() * 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[Defines.YAW], dist); - - if ((self.monsterinfo.aiflags & Defines.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[Defines.YAW] != self.ideal_yaw - && 0 != (self.monsterinfo.aiflags & Defines.AI_TEMP_STAND_GROUND)) { - self.monsterinfo.aiflags &= ~(Defines.AI_STAND_GROUND | Defines.AI_TEMP_STAND_GROUND); - self.monsterinfo.run.think(self); - } - M.M_ChangeYaw(self); - GameAI.ai_checkattack(self, 0); - } - else - GameUtil.FindTarget(self); - return; - } - - if (GameUtil.FindTarget(self)) - return; - - if (GameBase.level.time > self.monsterinfo.pausetime) { - self.monsterinfo.walk.think(self); - return; - } - - if (0 == (self.spawnflags & 1) && (self.monsterinfo.idle != null) && (GameBase.level.time > self.monsterinfo.idle_time)) { - if (self.monsterinfo.idle_time != 0) { - self.monsterinfo.idle.think(self); - self.monsterinfo.idle_time= GameBase.level.time + 15 + Globals.rnd.nextFloat() * 15; - } - else { - self.monsterinfo.idle_time= GameBase.level.time + Globals.rnd.nextFloat() * 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[Defines.YAW], dist); - } - }; - /* - ============= - ai_run - - The monster has an enemy it is trying to kill - ============= - */ //ok - public static AIAdapter ai_run= new AIAdapter() { - public void ai(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; // mem - 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 & Defines.AI_COMBAT_POINT) != 0) { - M.M_MoveToGoal(self, dist); - return; - } - - if ((self.monsterinfo.aiflags & Defines.AI_SOUND_TARGET) != 0) { - Math3D.VectorSubtract(self.s.origin, self.enemy.s.origin, v); - if (Math3D.VectorLength(v) < 64) { - self.monsterinfo.aiflags |= (Defines.AI_STAND_GROUND | Defines.AI_TEMP_STAND_GROUND); - self.monsterinfo.stand.think(self); - return; - } - - M.M_MoveToGoal(self, dist); - - if (!GameUtil.FindTarget(self)) - return; - } - - if (GameAI.ai_checkattack(self, dist)) - return; - - if (self.monsterinfo.attack_state == Defines.AS_SLIDING) { - GameAI.ai_run_slide(self, dist); - return; - } - - if (GameUtilAdapters.enemy_vis) { - // if (self.aiflags & AI_LOST_SIGHT) - // dprint("regained sight\n"); - M.M_MoveToGoal(self, dist); - self.monsterinfo.aiflags &= ~Defines.AI_LOST_SIGHT; - Math3D.VectorCopy(self.enemy.s.origin, self.monsterinfo.last_sighting); - self.monsterinfo.trail_time= GameBase.level.time; - return; - } - - // coop will change to another enemy if visible - if (GameBase.coop.value != 0) { - // FIXME: insane guys get mad with this, which causes crashes! - if (GameUtil.FindTarget(self)) - return; - } - - if ((self.monsterinfo.search_time != 0) && (GameBase.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= GameUtil.G_Spawn(); - self.goalentity= tempgoal; - - new1= false; - - if (0 == (self.monsterinfo.aiflags & Defines.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 |= (Defines.AI_LOST_SIGHT | Defines.AI_PURSUIT_LAST_SEEN); - self.monsterinfo.aiflags &= ~(Defines.AI_PURSUE_NEXT | Defines.AI_PURSUE_TEMP); - new1= true; - } - - if ((self.monsterinfo.aiflags & Defines.AI_PURSUE_NEXT) != 0) { - self.monsterinfo.aiflags &= ~Defines.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= GameBase.level.time + 5; - - if ((self.monsterinfo.aiflags & Defines.AI_PURSUE_TEMP) != 0) { - // dprint("was temp goal; retrying original\n"); - self.monsterinfo.aiflags &= ~Defines.AI_PURSUE_TEMP; - marker= null; - Math3D.VectorCopy(self.monsterinfo.saved_goal, self.monsterinfo.last_sighting); - new1= true; - } - else if ((self.monsterinfo.aiflags & Defines.AI_PURSUIT_LAST_SEEN) != 0) { - self.monsterinfo.aiflags &= ~Defines.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[Defines.YAW]= self.ideal_yaw= marker.s.angles[Defines.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 |= Defines.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= - GameBase.gi.trace( - self.s.origin, - self.mins, - self.maxs, - self.monsterinfo.last_sighting, - self, - Defines.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[Defines.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= GameBase.gi.trace(self.s.origin, self.mins, self.maxs, left_target, self, Defines.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= GameBase.gi.trace(self.s.origin, self.mins, self.maxs, right_target, self, Defines.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 |= Defines.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[Defines.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 |= Defines.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[Defines.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); - - GameUtil.G_FreeEdict(tempgoal); - - if (self != null) - self.goalentity= save; - } - }; - 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 & Defines.IT_WEAPON) != 0; - if ((weapon) && ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO) != 0) - count= 1000; - else if (ent.count != 0) - count= ent.count; - else - count= ent.item.quantity; - - oldcount= other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)]; - - if (!GameAI.Add_Ammo(other, ent.item, count)) - return false; - - if (weapon && 0 == oldcount) { - if (other.client.pers.weapon != ent.item - && (0 == GameBase.deathmatch.value || other.client.pers.weapon == GameUtil.FindItem("blaster"))) - other.client.newweapon= ent.item; - } - - if (0 == (ent.spawnflags & (Defines.DROPPED_ITEM | Defines.DROPPED_PLAYER_ITEM)) && (GameBase.deathmatch.value != 0)) - GameUtil.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= GameUtil.ArmorIndex(other); - - // handle armor shards specially - if (ent.item.tag == Defines.ARMOR_SHARD) { - if (0 == old_armor_index) - other.client.pers.inventory[GameUtilAdapters.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[GameUtil.ITEM_INDEX(ent.item)]= newinfo.base_count; - } - - // use the better armor - else { - // get info on old armor - if (old_armor_index == GameUtilAdapters.jacket_armor_index) - oldinfo= jacketarmor_info; - - else if (old_armor_index == GameUtilAdapters.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[GameUtil.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 & Defines.DROPPED_ITEM) && (GameBase.deathmatch.value != 0)) - GameUtil.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[GameUtil.ITEM_INDEX(ent.item)]; - - other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)]++; - - if (GameBase.deathmatch.value != 0) { - if (0 == (ent.spawnflags & Defines.DROPPED_ITEM)) - GameUtil.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[GameUtil.ITEM_INDEX(ent.item)]; - if ((GameBase.skill.value == 1 && quantity >= 2) || (GameBase.skill.value >= 2 && quantity >= 1)) - return false; - - if ((GameBase.coop.value != 0) && (ent.item.flags & Defines.IT_STAY_COOP) != 0 && (quantity > 0)) - return false; - - other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)]++; - - if (GameBase.deathmatch.value != 0) { - if (0 == (ent.spawnflags & Defines.DROPPED_ITEM)) - GameUtil.SetRespawn(ent, ent.item.quantity); - if (((int) GameBase.dmflags.value & Defines.DF_INSTANT_ITEMS) != 0 - || ((ent.item.use == GameUtilAdapters.Use_Quad) && 0 != (ent.spawnflags & Defines.DROPPED_PLAYER_ITEM))) { - if ((ent.item.use == GameUtilAdapters.Use_Quad) && 0 != (ent.spawnflags & Defines.DROPPED_PLAYER_ITEM)) - GameUtilAdapters.quad_drop_timeout_hack= (int) ((ent.nextthink - GameBase.level.time) / Defines.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 (GameBase.deathmatch.value == 0) - other.max_health += 1; - - if (other.health < other.max_health) - other.health= other.max_health; - - if (0 == (ent.spawnflags & Defines.DROPPED_ITEM) && (GameBase.deathmatch.value != 0)) - GameUtil.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 & Defines.DROPPED_ITEM) && (GameBase.deathmatch.value != 0)) - GameUtil.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= GameUtil.FindItem("Bullets"); - if (item != null) { - index= GameUtil.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= GameUtil.FindItem("Shells"); - if (item != null) { - index= GameUtil.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 & Defines.DROPPED_ITEM) && (GameBase.deathmatch.value != 0)) - GameUtil.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 &= ~Defines.SVF_NOCLIENT; - ent.use= null; - - if ((ent.spawnflags & Defines.ITEM_NO_TOUCH) != 0) { - ent.solid= Defines.SOLID_BBOX; - ent.touch= null; - } - else { - ent.solid= Defines.SOLID_TRIGGER; - ent.touch= GameUtilAdapters.Touch_Item; - } - - GameBase.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); - ent.mins[0]= ent.mins[1]= ent.mins[2]= -15; - //v = Lib.tv(15, 15, 15); - //Math3D.VectorCopy(v, ent.maxs); - ent.maxs[0]= ent.maxs[1]= ent.maxs[2]= 15; - - if (ent.model != null) - GameBase.gi.setmodel(ent, ent.model); - else - GameBase.gi.setmodel(ent, ent.item.world_model); - ent.solid= Defines.SOLID_TRIGGER; - ent.movetype= Defines.MOVETYPE_TOSS; - ent.touch= GameUtilAdapters.Touch_Item; - - float v[]= { 0, 0, -128 }; - Math3D.VectorAdd(ent.s.origin, v, dest); - - tr= GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, dest, ent, Defines.MASK_SOLID); - if (tr.startsolid) { - GameBase.gi.dprintf("droptofloor: " + ent.classname + " startsolid at " + Lib.vtos(ent.s.origin) + "\n"); - GameUtil.G_FreeEdict(ent); - return true; - } - - Math3D.VectorCopy(tr.endpos, ent.s.origin); - - if (ent.team != null) { - ent.flags &= ~Defines.FL_TEAMSLAVE; - ent.chain= ent.teamchain; - ent.teamchain= null; - - ent.svflags |= Defines.SVF_NOCLIENT; - ent.solid= Defines.SOLID_NOT; - if (ent == ent.teammaster) { - ent.nextthink= GameBase.level.time + Defines.FRAMETIME; - ent.think= GameUtilAdapters.DoRespawn; - } - } - - if ((ent.spawnflags & Defines.ITEM_NO_TOUCH) != 0) { - ent.solid= Defines.SOLID_BBOX; - ent.touch= null; - ent.s.effects &= ~Defines.EF_ROTATE; - ent.s.renderfx &= ~Defines.RF_GLOW; - } - - if ((ent.spawnflags & Defines.ITEM_TRIGGER_SPAWN) != 0) { - ent.svflags |= Defines.SVF_NOCLIENT; - ent.solid= Defines.SOLID_NOT; - ent.use= Use_Item; - } - - GameBase.gi.linkentity(ent); - return true; - } - }; - public static EntThinkAdapter gib_think= new EntThinkAdapter() { - public boolean think(edict_t self) { - self.s.frame++; - self.nextthink= GameBase.level.time + Defines.FRAMETIME; - - if (self.s.frame == 10) { - self.think= GameUtilAdapters.G_FreeEdictA; - self.nextthink= GameBase.level.time + 8 + Globals.rnd.nextFloat() * 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) { - GameBase.gi.sound(self, Defines.CHAN_VOICE, GameBase.gi.soundindex("misc/fhit3.wav"), 1, Defines.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 == GameBase.sm_meat_index) { - self.s.frame++; - self.think= gib_think; - self.nextthink= GameBase.level.time + Defines.FRAMETIME; - } - } - } - }; - public static EntDieAdapter gib_die= new EntDieAdapter() { - public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) { - GameUtil.G_FreeEdict(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) { - GameUtil.G_FreeEdict(self); - } - }; - 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= Defines.DAMAGE_YES; - self.movetype= Defines.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 |= Defines.SVF_DEADMONSTER; - - if (self.deadflag == 0) { - self.client.respawn_time= GameBase.level.time + 1.0f; - GameAI.LookAtKiller(self, inflictor, attacker); - self.client.ps.pmove.pm_type= Defines.PM_DEAD; - GameAI.ClientObituary(self, inflictor, attacker); - GameAI.TossClientWeapon(self); - if (GameBase.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 < GameBase.game.num_items; n++) { - if (GameBase.coop.value != 0 && (GameAI.itemlist[n].flags & Defines.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 &= ~Defines.FL_POWER_ARMOR; - - if (self.health < -40) { // gib - GameBase.gi.sound(self, Defines.CHAN_BODY, GameBase.gi.soundindex("misc/udeath.wav"), 1, Defines.ATTN_NORM, 0); - for (n= 0; n < 4; n++) - GameAI.ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, Defines.GIB_ORGANIC); - GameAI.ThrowClientHead(self, damage); - - self.takedamage= Defines.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= Defines.ANIM_DEATH; - if ((self.client.ps.pmove.pm_flags & Defines.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; - } - - GameBase.gi.sound( - self, - Defines.CHAN_VOICE, - GameBase.gi.soundindex("*death" + ((Lib.rand() % 4) + 1) + ".wav"), - 1, - Defines.ATTN_NORM, - 0); - } - } - - self.deadflag= Defines.DEAD_DEAD; - - GameBase.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= GameBase.game.clients[anum].ps.stats[Defines.STAT_FRAGS]; - int bnum1= GameBase.game.clients[bnum].ps.stats[Defines.STAT_FRAGS]; - - if (anum1 < bnum1) - return -1; - if (anum1 > bnum1) - return 1; - return 0; - } - }; - public static ItemUseAdapter Use_PowerArmor= new ItemUseAdapter() { - public void use(edict_t ent, gitem_t item) { - int index; - - if ((ent.flags & Defines.FL_POWER_ARMOR) != 0) { - ent.flags &= ~Defines.FL_POWER_ARMOR; - GameBase.gi.sound(ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/power2.wav"), 1, Defines.ATTN_NORM, 0); - } - else { - index= GameUtil.ITEM_INDEX(GameUtil.FindItem("cells")); - if (0 == ent.client.pers.inventory[index]) { - GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "No cells for power armor.\n"); - return; - } - ent.flags |= Defines.FL_POWER_ARMOR; - GameBase.gi.sound(ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/power1.wav"), 1, Defines.ATTN_NORM, 0); - } - } - }; - public static ItemDropAdapter Drop_Ammo= new ItemDropAdapter() { - public void drop(edict_t ent, gitem_t item) { - edict_t dropped; - int index; - - index= GameUtil.ITEM_INDEX(item); - dropped= GameUtil.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 == Defines.AMMO_GRENADES - && item.tag == Defines.AMMO_GRENADES - && ent.client.pers.inventory[index] - dropped.count <= 0) { - GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "Can't drop current weapon\n"); - GameUtil.G_FreeEdict(dropped); - return; - } - - ent.client.pers.inventory[index] -= dropped.count; - GameAI.ValidateSelectedItem(ent); - } - }; - public static ItemDropAdapter Drop_General= new ItemDropAdapter() { - public void drop(edict_t ent, gitem_t item) { - GameUtil.Drop_Item(ent, item); - ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)]--; - GameAI.ValidateSelectedItem(ent); - } - }; - public static ItemDropAdapter Drop_PowerArmor= new ItemDropAdapter() { - public void drop(edict_t ent, gitem_t item) { - if (0 != (ent.flags & Defines.FL_POWER_ARMOR) && (ent.client.pers.inventory[GameUtil.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, Defines.ARMOR_JACKET); - public static gitem_armor_t combatarmor_info= new gitem_armor_t(50, 100, .60f, .30f, Defines.ARMOR_COMBAT); - public static gitem_armor_t bodyarmor_info= new gitem_armor_t(100, 200, .80f, .60f, Defines.ARMOR_BODY); -} diff --git a/src/jake2/game/GameBase.java b/src/jake2/game/GameBase.java index f71ba76..f9b83de 100644 --- a/src/jake2/game/GameBase.java +++ b/src/jake2/game/GameBase.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.7 2004-09-10 19:02:54 salomo Exp $ - +// $Id: GameBase.java,v 1.8 2004-09-22 19:22:05 salomo Exp $ /** Father of all GameObjects. */ package jake2.game; @@ -33,660 +32,683 @@ import jake2.qcommon.Com; import jake2.server.*; import jake2.util.*; -public class GameBase extends Globals { - public static cplane_t dummyplane= new cplane_t(); - 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 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 int num_edicts; - - 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; - - /** - * 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 < 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 < 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 - - ============ - */ - - static edict_t touch[]= new edict_t[MAX_EDICTS]; - public static void G_TouchTriggers(edict_t ent) { - int i, num; - edict_t 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; - - //rst: just for debugging player triggers - //if (ent.index == 1) - //Com.Printf("trigger:" + hit.classname + "(" + hit.index + ")\n"); - - hit.touch.touch(hit, ent, GameBase.dummyplane, null); - } - } - - public static pushed_t pushed[]= new pushed_t[MAX_EDICTS]; - static { - for (int n= 0; n < MAX_EDICTS; n++) - pushed[n]= new pushed_t(); - } - - 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 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"); - } - - //====================================================================== - - /* - ================= - 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 < 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; - } - - 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 void GetGameApi(game_import_t imp) { - gi= imp; - - gi.pointcontents= new pmove_t.PointContentsAdapter() { - public int pointcontents(float[] o) { - return SV_WORLD.SV_PointContents(o); - } - }; - } +public class GameBase { + public static cplane_t dummyplane = new cplane_t(); + + 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 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 int num_edicts; + + public static edict_t g_edicts[] = new edict_t[Defines.MAX_EDICTS]; + static { + for (int n = 0; n < Defines.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; + + /** + * 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 < 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 < num_edicts; from.i++) { + from.o = g_edicts[from.i]; + if (!from.o.inuse) + continue; + + if (from.o.solid == Defines.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 + * + * ============ + */ + + static edict_t touch[] = new edict_t[Defines.MAX_EDICTS]; + + public static void G_TouchTriggers(edict_t ent) { + int i, num; + edict_t hit; + + // dead things don't activate triggers! + if ((ent.client != null || (ent.svflags & Defines.SVF_MONSTER) != 0) + && (ent.health <= 0)) + return; + + num = gi.BoxEdicts(ent.absmin, ent.absmax, touch, Defines.MAX_EDICTS, + Defines.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; + + //rst: just for debugging player triggers + //if (ent.index == 1) + //Com.Printf("trigger:" + hit.classname + "(" + hit.index + ")\n"); + + hit.touch.touch(hit, ent, GameBase.dummyplane, null); + } + } + + public static pushed_t pushed[] = new pushed_t[Defines.MAX_EDICTS]; + static { + for (int n = 0; n < Defines.MAX_EDICTS; n++) + pushed[n] = new pushed_t(); + } + + 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 Defines.MOVETYPE_PUSH: + case Defines.MOVETYPE_STOP: + SV.SV_Physics_Pusher(ent); + break; + case Defines.MOVETYPE_NONE: + SV.SV_Physics_None(ent); + break; + case Defines.MOVETYPE_NOCLIP: + SV.SV_Physics_Noclip(ent); + break; + case Defines.MOVETYPE_STEP: + SV.SV_Physics_Step(ent); + break; + case Defines.MOVETYPE_TOSS: + case Defines.MOVETYPE_BOUNCE: + case Defines.MOVETYPE_FLY: + case Defines.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 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"); + } + + //====================================================================== + + /* + * ================= 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; + PlayerView.ClientEndServerFrame(ent); + } + + } + + /* + * ================= CreateTargetChangeLevel + * + * Returns the created target changelevel ================= + */ + public static edict_t CreateTargetChangeLevel(String map) { + edict_t ent; + + ent = GameUtil.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 & Defines.DF_SAME_LEVEL) != 0) { + PlayerHud.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 (Lib.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 + PlayerHud + .BeginIntermission(CreateTargetChangeLevel(level.mapname)); + else + PlayerHud + .BeginIntermission(CreateTargetChangeLevel(f)); + } else + PlayerHud.BeginIntermission(CreateTargetChangeLevel(t)); + return; + } + if (f == null) + f = t; + t = tk.nextToken(); + } + + } + + if (level.nextmap.length() > 0) // go to a specific map + PlayerHud.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 + PlayerHud + .BeginIntermission(CreateTargetChangeLevel(level.mapname)); + return; + } + ent = edit.o; + PlayerHud.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 != Lib.Q_stricmp(password.string, "none")) + need |= 1; + if ((spectator_password.string.length() > 0) + && 0 != Lib.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(Defines.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(Defines.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 * Defines.FRAMETIME; + + // choose a client for monsters to target this frame + GameUtil.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 < num_edicts; i++) { + ent = g_edicts[i]; + if (!ent.inuse) + continue; + + level.current_entity = ent; + + Math3D.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 & (Defines.FL_SWIM | Defines.FL_FLY)) + && (ent.svflags & Defines.SVF_MONSTER) != 0) { + M.M_CheckGround(ent); + } + } + + if (i > 0 && i <= maxclients.value) { + PlayerClient.ClientBeginServerFrame(ent); + continue; + } + + 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 void GetGameApi(game_import_t imp) { + gi = imp; + + gi.pointcontents = new pmove_t.PointContentsAdapter() { + public int pointcontents(float[] o) { + return SV_WORLD.SV_PointContents(o); + } + }; + } } \ No newline at end of file diff --git a/src/jake2/game/GameFunc.java b/src/jake2/game/GameFunc.java index cf24377..9a77e17 100644 --- a/src/jake2/game/GameFunc.java +++ b/src/jake2/game/GameFunc.java @@ -1,574 +1,2161 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 18.11.2003 by RST. -// $Id: GameFunc.java,v 1.4 2004-09-10 19:02:53 salomo Exp $ - +// $Id: GameFunc.java,v 1.5 2004-09-22 19:22:04 salomo Exp $ package jake2.game; import jake2.Defines; import jake2.Globals; -import jake2.qcommon.Com; -import jake2.util.*; -import jake2.util.*; - -public class GameFunc extends PlayerView -{ - - 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)) - { - GameFuncAdapters.Move_Begin.think(ent); - } - else - { - ent.nextthink = level.time + FRAMETIME; - ent.think = GameFuncAdapters.Move_Begin; - } - } - else - { - // accelerative - ent.moveinfo.current_speed = 0; - ent.think = GameFuncAdapters.Think_AccelMove; - ent.nextthink = level.time + FRAMETIME; - } - } - - 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)) - { - GameFuncAdapters.AngleMove_Begin.think(ent); - } - else - { - ent.nextthink = level.time + FRAMETIME; - ent.think = GameFuncAdapters.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 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 = GameFuncAdapters.STATE_UP; - Move_Calc(ent, ent.moveinfo.start_origin, GameFuncAdapters.plat_hit_top); - } - - 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 = GameFuncAdapters.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 & GameFuncAdapters.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 = GameFuncAdapters.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 = GameFuncAdapters.Use_Plat; - - plat_spawn_inside_trigger(ent); // the "start moving" trigger - - if (ent.targetname != null) - { - ent.moveinfo.state = GameFuncAdapters.STATE_UP; - } - else - { - Math3D.VectorCopy(ent.pos2, ent.s.origin); - gi.linkentity(ent); - ent.moveinfo.state = GameFuncAdapters.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"); - } - - /* - ====================================================================== - - 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 void door_go_up(edict_t self, edict_t activator) - { - if (self.moveinfo.state == GameFuncAdapters.STATE_UP) - return; // already going up - - if (self.moveinfo.state == GameFuncAdapters.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 = GameFuncAdapters.STATE_UP; - if (Lib.strcmp(self.classname, "func_door") == 0) - Move_Calc(self, self.moveinfo.end_origin, GameFuncAdapters.door_hit_top); - else if (Lib.strcmp(self.classname, "func_door_rotating") == 0) - AngleMove_Calc(self, GameFuncAdapters.door_hit_top); - - G_UseTargets(self, activator); - door_use_areaportals(self, 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 & GameFuncAdapters.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 = GameFuncAdapters.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 = GameFuncAdapters.door_use; - - if (self.wait == -1) - self.spawnflags |= GameFuncAdapters.DOOR_TOGGLE; - - self.classname = "func_door"; - - gi.linkentity(self); - } - - 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 = GameFuncAdapters.STATE_TOP; - Math3D.VectorCopy(self.s.origin, self.moveinfo.start_origin); - Math3D.VectorCopy(dest, self.moveinfo.end_origin); - Move_Calc(self, dest, GameFuncAdapters.train_wait); - self.spawnflags |= GameFuncAdapters.TRAIN_START_ON; - - } - - static void SP_func_train(edict_t self) - { - self.movetype = MOVETYPE_PUSH; - - Math3D.VectorClear(self.s.angles); - self.blocked = GameFuncAdapters.train_blocked; - if ((self.spawnflags & GameFuncAdapters.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 = GameFuncAdapters.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 = GameFuncAdapters.func_train_find; - } - else - { - gi.dprintf("func_train without a target at " + Lib.vtos(self.absmin) + "\n"); - } - } - - static void SP_func_timer(edict_t self) - { - if (0 == self.wait) - self.wait = 1.0f; - - self.use = GameFuncAdapters.func_timer_use; - self.think = GameFuncAdapters.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; - } - -} +import jake2.util.Lib; +import jake2.util.Math3D; + +public class GameFunc { + + 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 (GameBase.level.current_entity == ((ent.flags & Defines.FL_TEAMSLAVE) != 0 ? ent.teammaster + : ent)) { + GameFunc.Move_Begin.think(ent); + } else { + ent.nextthink = GameBase.level.time + Defines.FRAMETIME; + ent.think = GameFunc.Move_Begin; + } + } else { + // accelerative + ent.moveinfo.current_speed = 0; + ent.think = GameFunc.Think_AccelMove; + ent.nextthink = GameBase.level.time + Defines.FRAMETIME; + } + } + + static void AngleMove_Calc(edict_t ent, EntThinkAdapter func) { + Math3D.VectorClear(ent.avelocity); + ent.moveinfo.endfunc = func; + if (GameBase.level.current_entity == ((ent.flags & Defines.FL_TEAMSLAVE) != 0 ? ent.teammaster + : ent)) { + GameFunc.AngleMove_Begin.think(ent); + } else { + ent.nextthink = GameBase.level.time + Defines.FRAMETIME; + ent.think = GameFunc.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 void plat_go_up(edict_t ent) { + if (0 == (ent.flags & Defines.FL_TEAMSLAVE)) { + if (ent.moveinfo.sound_start != 0) + GameBase.gi.sound(ent, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, ent.moveinfo.sound_start, 1, + Defines.ATTN_STATIC, 0); + ent.s.sound = ent.moveinfo.sound_middle; + } + ent.moveinfo.state = GameFunc.STATE_UP; + Move_Calc(ent, ent.moveinfo.start_origin, GameFunc.plat_hit_top); + } + + static void plat_spawn_inside_trigger(edict_t ent) { + edict_t trigger; + float[] tmin = { 0, 0, 0 }, tmax = { 0, 0, 0 }; + + // + // middle trigger + // + trigger = GameUtil.G_Spawn(); + trigger.touch = GameFunc.Touch_Plat_Center; + trigger.movetype = Defines.MOVETYPE_NONE; + trigger.solid = Defines.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] + GameBase.st.lip); + + if ((ent.spawnflags & GameFunc.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); + + GameBase.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 = Defines.SOLID_BSP; + ent.movetype = Defines.MOVETYPE_PUSH; + + GameBase.gi.setmodel(ent, ent.model); + + ent.blocked = GameFunc.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 (GameBase.st.lip == 0) + GameBase.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 (GameBase.st.height != 0) + ent.pos2[2] -= GameBase.st.height; + else + ent.pos2[2] -= (ent.maxs[2] - ent.mins[2]) - GameBase.st.lip; + + ent.use = GameFunc.Use_Plat; + + plat_spawn_inside_trigger(ent); // the "start moving" trigger + + if (ent.targetname != null) { + ent.moveinfo.state = GameFunc.STATE_UP; + } else { + Math3D.VectorCopy(ent.pos2, ent.s.origin); + GameBase.gi.linkentity(ent); + ent.moveinfo.state = GameFunc.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 = GameBase.gi.soundindex("plats/pt1_strt.wav"); + ent.moveinfo.sound_middle = GameBase.gi.soundindex("plats/pt1_mid.wav"); + ent.moveinfo.sound_end = GameBase.gi.soundindex("plats/pt1_end.wav"); + } + + /* + * ====================================================================== + * + * 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 = GameBase + .G_Find(edit, GameBase.findByTarget, self.target)) != null) { + t = edit.o; + if (Lib.Q_stricmp(t.classname, "func_areaportal") == 0) { + GameBase.gi.SetAreaPortalState(t.style, open); + } + } + } + + static void door_go_up(edict_t self, edict_t activator) { + if (self.moveinfo.state == GameFunc.STATE_UP) + return; // already going up + + if (self.moveinfo.state == GameFunc.STATE_TOP) { + // reset top wait time + if (self.moveinfo.wait >= 0) + self.nextthink = GameBase.level.time + self.moveinfo.wait; + return; + } + + if (0 == (self.flags & Defines.FL_TEAMSLAVE)) { + if (self.moveinfo.sound_start != 0) + GameBase.gi.sound(self, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, self.moveinfo.sound_start, 1, + Defines.ATTN_STATIC, 0); + self.s.sound = self.moveinfo.sound_middle; + } + self.moveinfo.state = GameFunc.STATE_UP; + if (Lib.strcmp(self.classname, "func_door") == 0) + Move_Calc(self, self.moveinfo.end_origin, GameFunc.door_hit_top); + else if (Lib.strcmp(self.classname, "func_door_rotating") == 0) + AngleMove_Calc(self, GameFunc.door_hit_top); + + GameUtil.G_UseTargets(self, activator); + door_use_areaportals(self, 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 }; + + GameBase.G_SetMovedir(self.s.angles, self.movedir); + self.movetype = Defines.MOVETYPE_PUSH; + self.solid = Defines.SOLID_BSP; + GameBase.gi.setmodel(self, self.model); + + switch (self.sounds) { + default: + break; + + case 1: // water + self.moveinfo.sound_start = GameBase.gi + .soundindex("world/mov_watr.wav"); + self.moveinfo.sound_end = GameBase.gi + .soundindex("world/stp_watr.wav"); + break; + + case 2: // lava + self.moveinfo.sound_start = GameBase.gi + .soundindex("world/mov_watr.wav"); + self.moveinfo.sound_end = GameBase.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] + - GameBase.st.lip; + Math3D.VectorMA(self.pos1, self.moveinfo.distance, self.movedir, + self.pos2); + + // if it starts open, switch the positions + if ((self.spawnflags & GameFunc.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 = GameFunc.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 = GameFunc.door_use; + + if (self.wait == -1) + self.spawnflags |= GameFunc.DOOR_TOGGLE; + + self.classname = "func_door"; + + GameBase.gi.linkentity(self); + } + + 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 = GameFunc.STATE_TOP; + Math3D.VectorCopy(self.s.origin, self.moveinfo.start_origin); + Math3D.VectorCopy(dest, self.moveinfo.end_origin); + Move_Calc(self, dest, GameFunc.train_wait); + self.spawnflags |= GameFunc.TRAIN_START_ON; + + } + + static void SP_func_train(edict_t self) { + self.movetype = Defines.MOVETYPE_PUSH; + + Math3D.VectorClear(self.s.angles); + self.blocked = GameFunc.train_blocked; + if ((self.spawnflags & GameFunc.TRAIN_BLOCK_STOPS) != 0) + self.dmg = 0; + else { + if (0 == self.dmg) + self.dmg = 100; + } + self.solid = Defines.SOLID_BSP; + GameBase.gi.setmodel(self, self.model); + + if (GameBase.st.noise != null) + self.moveinfo.sound_middle = GameBase.gi + .soundindex(GameBase.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 = GameFunc.train_use; + + GameBase.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 = GameBase.level.time + Defines.FRAMETIME; + self.think = GameFunc.func_train_find; + } else { + GameBase.gi.dprintf("func_train without a target at " + + Lib.vtos(self.absmin) + "\n"); + } + } + + static void SP_func_timer(edict_t self) { + if (0 == self.wait) + self.wait = 1.0f; + + self.use = GameFunc.func_timer_use; + self.think = GameFunc.func_timer_think; + + if (self.random >= self.wait) { + self.random = self.wait - Defines.FRAMETIME; + GameBase.gi.dprintf("func_timer at " + Lib.vtos(self.s.origin) + + " has random >= wait\n"); + } + + if ((self.spawnflags & 1) != 0) { + self.nextthink = GameBase.level.time + 1.0f + GameBase.st.pausetime + + self.delay + self.wait + Lib.crandom() * self.random; + self.activator = self; + } + + self.svflags = Defines.SVF_NOCLIENT; + } + + /* + * ========================================================= + * + * 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 / Defines.FRAMETIME, + ent.velocity); + + ent.think = Move_Done; + ent.nextthink = GameBase.level.time + Defines.FRAMETIME; + return true; + } + }; + + static EntThinkAdapter Move_Begin = new EntThinkAdapter() { + public boolean think(edict_t ent) { + + float frames; + + if ((ent.moveinfo.speed * Defines.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) + / Defines.FRAMETIME); + ent.moveinfo.remaining_distance -= frames * ent.moveinfo.speed + * Defines.FRAMETIME; + ent.nextthink = GameBase.level.time + (frames * Defines.FRAMETIME); + ent.think = Move_Final; + return true; + } + }; + + // + // 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, Globals.vec3_origin) != 0) { + AngleMove_Done.think(ent); + return true; + } + + Math3D.VectorScale(move, 1.0f / Defines.FRAMETIME, ent.avelocity); + + ent.think = AngleMove_Done; + ent.nextthink = GameBase.level.time + Defines.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 < Defines.FRAMETIME) { + AngleMove_Final.think(ent); + return true; + } + + frames = (float) (Math.floor(traveltime / Defines.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 = GameBase.level.time + frames * Defines.FRAMETIME; + ent.think = AngleMove_Final; + return true; + } + }; + + 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 + GameFunc.plat_CalcAcceleratedMove(ent.moveinfo); + + GameFunc.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 = GameBase.level.time + Defines.FRAMETIME; + ent.think = Think_AccelMove; + return true; + } + }; + + static EntThinkAdapter plat_hit_top = new EntThinkAdapter() { + public boolean think(edict_t ent) { + if (0 == (ent.flags & Defines.FL_TEAMSLAVE)) { + if (ent.moveinfo.sound_end != 0) + GameBase.gi.sound(ent, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, ent.moveinfo.sound_end, 1, + Defines.ATTN_STATIC, 0); + ent.s.sound = 0; + } + ent.moveinfo.state = STATE_TOP; + + ent.think = plat_go_down; + ent.nextthink = GameBase.level.time + 3; + return true; + } + }; + + static EntThinkAdapter plat_hit_bottom = new EntThinkAdapter() { + public boolean think(edict_t ent) { + + if (0 == (ent.flags & Defines.FL_TEAMSLAVE)) { + if (ent.moveinfo.sound_end != 0) + GameBase.gi.sound(ent, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, ent.moveinfo.sound_end, 1, + Defines.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 & Defines.FL_TEAMSLAVE)) { + if (ent.moveinfo.sound_start != 0) + GameBase.gi.sound(ent, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, ent.moveinfo.sound_start, 1, + Defines.ATTN_STATIC, 0); + ent.s.sound = ent.moveinfo.sound_middle; + } + ent.moveinfo.state = STATE_DOWN; + GameFunc.Move_Calc(ent, ent.moveinfo.end_origin, plat_hit_bottom); + return true; + } + }; + + static EntBlockedAdapter plat_blocked = new EntBlockedAdapter() { + public void blocked(edict_t self, edict_t other) { + if (0 == (other.svflags & Defines.SVF_MONSTER) + && (null == other.client)) { + // give it a chance to go away on it's own terms (like gibs) + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, 100000, 1, 0, + Defines.MOD_CRUSH); + // if it's still there, nuke it + if (other != null) + GameAI.BecomeExplosion1(other); + return; + } + + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, self.dmg, 1, 0, + Defines.MOD_CRUSH); + + if (self.moveinfo.state == STATE_UP) + plat_go_down.think(self); + else if (self.moveinfo.state == STATE_DOWN) + GameFunc.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) + GameFunc.plat_go_up(ent); + else if (ent.moveinfo.state == STATE_TOP) { + ent.nextthink = GameBase.level.time + 1; // the player is still + // on the plat, so + // delay going down + } + } + }; + + // ==================================================================== + + /* + * 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) { + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, self.dmg, 1, 0, + Defines.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) + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, self.dmg, 1, 0, + Defines.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, Globals.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 = Defines.SOLID_BSP; + if ((ent.spawnflags & 32) != 0) + ent.movetype = Defines.MOVETYPE_STOP; + else + ent.movetype = Defines.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 |= Defines.EF_ANIM_ALL; + if ((ent.spawnflags & 128) != 0) + ent.s.effects |= Defines.EF_ANIM_ALLFAST; + + GameBase.gi.setmodel(ent, ent.model); + GameBase.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 &= ~Defines.EF_ANIM23; + self.s.effects |= Defines.EF_ANIM01; + return true; + } + }; + + static EntThinkAdapter button_return = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.moveinfo.state = STATE_DOWN; + + GameFunc.Move_Calc(self, self.moveinfo.start_origin, button_done); + + self.s.frame = 0; + + if (self.health != 0) + self.takedamage = Defines.DAMAGE_YES; + return true; + } + }; + + static EntThinkAdapter button_wait = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.moveinfo.state = STATE_TOP; + self.s.effects &= ~Defines.EF_ANIM01; + self.s.effects |= Defines.EF_ANIM23; + + GameUtil.G_UseTargets(self, self.activator); + self.s.frame = 1; + if (self.moveinfo.wait >= 0) { + self.nextthink = GameBase.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 & Defines.FL_TEAMSLAVE)) + GameBase.gi.sound(self, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, self.moveinfo.sound_start, 1, + Defines.ATTN_STATIC, 0); + GameFunc.Move_Calc(self, self.moveinfo.end_origin, button_wait); + return true; + } + }; + + static EntUseAdapter button_use = new EntUseAdapter() { + public void use(edict_t self, edict_t other, edict_t activator) { + self.activator = activator; + button_fire.think(self); + return; + } + }; + + 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 = Defines.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; + + GameBase.G_SetMovedir(ent.s.angles, ent.movedir); + ent.movetype = Defines.MOVETYPE_STOP; + ent.solid = Defines.SOLID_BSP; + GameBase.gi.setmodel(ent, ent.model); + + if (ent.sounds != 1) + ent.moveinfo.sound_start = GameBase.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 == GameBase.st.lip) + GameBase.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] - GameBase.st.lip; + Math3D.VectorMA(ent.pos1, dist, ent.movedir, ent.pos2); + + ent.use = button_use; + ent.s.effects |= Defines.EF_ANIM01; + + if (ent.health != 0) { + ent.max_health = ent.health; + ent.die = button_killed; + ent.takedamage = Defines.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); + + GameBase.gi.linkentity(ent); + return true; + } + }; + + static EntThinkAdapter door_hit_top = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (0 == (self.flags & Defines.FL_TEAMSLAVE)) { + if (self.moveinfo.sound_end != 0) + GameBase.gi.sound(self, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, self.moveinfo.sound_end, 1, + Defines.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 = GameBase.level.time + self.moveinfo.wait; + } + return true; + } + }; + + static EntThinkAdapter door_hit_bottom = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (0 == (self.flags & Defines.FL_TEAMSLAVE)) { + if (self.moveinfo.sound_end != 0) + GameBase.gi.sound(self, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, self.moveinfo.sound_end, 1, + Defines.ATTN_STATIC, 0); + self.s.sound = 0; + } + self.moveinfo.state = STATE_BOTTOM; + GameFunc.door_use_areaportals(self, false); + return true; + } + }; + + static EntThinkAdapter door_go_down = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (0 == (self.flags & Defines.FL_TEAMSLAVE)) { + if (self.moveinfo.sound_start != 0) + GameBase.gi.sound(self, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, self.moveinfo.sound_start, 1, + Defines.ATTN_STATIC, 0); + self.s.sound = self.moveinfo.sound_middle; + } + if (self.max_health != 0) { + self.takedamage = Defines.DAMAGE_YES; + self.health = self.max_health; + } + + self.moveinfo.state = STATE_DOWN; + if (Lib.strcmp(self.classname, "func_door") == 0) + GameFunc.Move_Calc(self, self.moveinfo.start_origin, + door_hit_bottom); + else if (Lib.strcmp(self.classname, "func_door_rotating") == 0) + GameFunc.AngleMove_Calc(self, door_hit_bottom); + return 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 & Defines.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; + GameFunc.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 & Defines.SVF_MONSTER) + && (null == other.client)) + return; + + if (0 != (self.owner.spawnflags & DOOR_NOMONSTER) + && 0 != (other.svflags & Defines.SVF_MONSTER)) + return; + + if (GameBase.level.time < self.touch_debounce_time) + return; + self.touch_debounce_time = GameBase.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 & Defines.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 & Defines.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) { + GameBase.AddPointToBounds(other.absmin, mins, maxs); + GameBase.AddPointToBounds(other.absmax, mins, maxs); + } + + // expand + mins[0] -= 60; + mins[1] -= 60; + maxs[0] += 60; + maxs[1] += 60; + + other = GameUtil.G_Spawn(); + Math3D.VectorCopy(mins, other.mins); + Math3D.VectorCopy(maxs, other.maxs); + other.owner = ent; + other.solid = Defines.SOLID_TRIGGER; + other.movetype = Defines.MOVETYPE_NONE; + other.touch = Touch_DoorTrigger; + GameBase.gi.linkentity(other); + + if ((ent.spawnflags & DOOR_START_OPEN) != 0) + GameFunc.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 & Defines.SVF_MONSTER) + && (null == other.client)) { + // give it a chance to go away on it's own terms (like gibs) + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, 100000, 1, 0, + Defines.MOD_CRUSH); + // if it's still there, nuke it + if (other != null) + GameAI.BecomeExplosion1(other); + return; + } + + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, self.dmg, 1, 0, + Defines.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) + GameFunc.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 = Defines.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 (GameBase.level.time < self.touch_debounce_time) + return; + self.touch_debounce_time = GameBase.level.time + 5.0f; + + GameBase.gi.centerprintf(other, self.message); + GameBase.gi.sound(other, Defines.CHAN_AUTO, GameBase.gi + .soundindex("misc/talk1.wav"), 1, Defines.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 = GameBase.gi + .soundindex("doors/dr1_strt.wav"); + ent.moveinfo.sound_middle = GameBase.gi + .soundindex("doors/dr1_mid.wav"); + ent.moveinfo.sound_end = GameBase.gi + .soundindex("doors/dr1_end.wav"); + } + + GameBase.G_SetMovedir(ent.s.angles, ent.movedir); + ent.movetype = Defines.MOVETYPE_PUSH; + ent.solid = Defines.SOLID_BSP; + GameBase.gi.setmodel(ent, ent.model); + + ent.blocked = door_blocked; + ent.use = door_use; + + if (0 == ent.speed) + ent.speed = 100; + if (GameBase.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 == GameBase.st.lip) + GameBase.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] - GameBase.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 = Defines.DAMAGE_YES; + ent.die = door_killed; + ent.max_health = ent.health; + } else if (ent.targetname != null && ent.message != null) { + GameBase.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 |= Defines.EF_ANIM_ALL; + if ((ent.spawnflags & 64) != 0) + ent.s.effects |= Defines.EF_ANIM_ALLFAST; + + // to simplify logic elsewhere, make non-teamed doors into a team of + // one + if (null == ent.team) + ent.teammaster = ent; + + GameBase.gi.linkentity(ent); + + ent.nextthink = GameBase.level.time + Defines.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 == GameBase.st.distance) { + GameBase.gi.dprintf(ent.classname + " at " + + Lib.vtos(ent.s.origin) + " with no distance set\n"); + GameBase.st.distance = 90; + } + + Math3D.VectorCopy(ent.s.angles, ent.pos1); + Math3D.VectorMA(ent.s.angles, GameBase.st.distance, ent.movedir, + ent.pos2); + ent.moveinfo.distance = GameBase.st.distance; + + ent.movetype = Defines.MOVETYPE_PUSH; + ent.solid = Defines.SOLID_BSP; + GameBase.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 = GameBase.gi + .soundindex("doors/dr1_strt.wav"); + ent.moveinfo.sound_middle = GameBase.gi + .soundindex("doors/dr1_mid.wav"); + ent.moveinfo.sound_end = GameBase.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 = Defines.DAMAGE_YES; + ent.die = door_killed; + ent.max_health = ent.health; + } + + if (ent.targetname != null && ent.message != null) { + GameBase.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 |= Defines.EF_ANIM_ALL; + + // to simplify logic elsewhere, make non-teamed doors into a team of + // one + if (ent.team == null) + ent.teammaster = ent; + + GameBase.gi.linkentity(ent); + + ent.nextthink = GameBase.level.time + Defines.FRAMETIME; + if (ent.health != 0 || ent.targetname != null) + ent.think = Think_CalcMoveSpeed; + else + ent.think = Think_SpawnDoorTrigger; + return true; + } + }; + + 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 & Defines.SVF_MONSTER) + && (null == other.client)) { + // give it a chance to go away on it's own terms (like gibs) + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, 100000, 1, 0, + Defines.MOD_CRUSH); + // if it's still there, nuke it + if (other != null) + GameAI.BecomeExplosion1(other); + return; + } + + if (GameBase.level.time < self.touch_debounce_time) + return; + + if (self.dmg == 0) + return; + self.touch_debounce_time = GameBase.level.time + 0.5f; + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, self.dmg, 1, 0, + Defines.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; + GameUtil.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 = GameBase.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 & Defines.FL_TEAMSLAVE)) { + if (self.moveinfo.sound_end != 0) + GameBase.gi.sound(self, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, self.moveinfo.sound_end, + 1, Defines.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 = GameBase.G_PickTarget(self.target); + if (null == ent) { + GameBase.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) { + GameBase.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 = Defines.EV_OTHER_TELEPORT; + GameBase.gi.linkentity(self); + dogoto = true; + } + } + self.moveinfo.wait = ent.wait; + self.target_ent = ent; + + if (0 == (self.flags & Defines.FL_TEAMSLAVE)) { + if (self.moveinfo.sound_start != 0) + GameBase.gi.sound(self, Defines.CHAN_NO_PHS_ADD + + Defines.CHAN_VOICE, self.moveinfo.sound_start, 1, + Defines.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); + GameFunc.Move_Calc(self, dest, train_wait); + self.spawnflags |= TRAIN_START_ON; + return true; + } + }; + + public static EntThinkAdapter func_train_find = new EntThinkAdapter() { + public boolean think(edict_t self) { + edict_t ent; + + if (null == self.target) { + GameBase.gi.dprintf("train_find: no target\n"); + return true; + } + ent = GameBase.G_PickTarget(self.target); + if (null == ent) { + GameBase.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); + GameBase.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 = GameBase.level.time + Defines.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) + GameFunc.train_resume(self); + else + train_next.think(self); + } + } + }; + + /* + * 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) { + GameBase.gi.dprintf("elevator used with no pathtarget\n"); + return; + } + + target = GameBase.G_PickTarget(other.pathtarget); + if (null == target) { + GameBase.gi.dprintf("elevator used with bad pathtarget: " + + other.pathtarget + "\n"); + return; + } + + self.movetarget.target_ent = target; + GameFunc.train_resume(self.movetarget); + } + }; + + static EntThinkAdapter trigger_elevator_init = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (null == self.target) { + GameBase.gi.dprintf("trigger_elevator has no target\n"); + return true; + } + self.movetarget = GameBase.G_PickTarget(self.target); + if (null == self.movetarget) { + GameBase.gi.dprintf("trigger_elevator unable to find target " + + self.target + "\n"); + return true; + } + if (Lib.strcmp(self.movetarget.classname, "func_train") != 0) { + GameBase.gi.dprintf("trigger_elevator target " + self.target + + " is not a train\n"); + return true; + } + + self.use = trigger_elevator_use; + self.svflags = Defines.SVF_NOCLIENT; + return true; + } + }; + + static EntThinkAdapter SP_trigger_elevator = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.think = trigger_elevator_init; + self.nextthink = GameBase.level.time + Defines.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) { + GameUtil.G_UseTargets(self, self.activator); + self.nextthink = GameBase.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 = GameBase.level.time + self.delay; + else + func_timer_think.think(self); + } + }; + + /* + * 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; + + GameBase.gi.setmodel(self, self.model); + self.solid = Defines.SOLID_BSP; + GameBase.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, Globals.vec3_origin)) + return; + + GameFunc.Move_Calc(self, self.pos1, door_secret_move1); + GameFunc.door_use_areaportals(self, true); + } + }; + + static EntThinkAdapter door_secret_move1 = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.nextthink = GameBase.level.time + 1.0f; + self.think = door_secret_move2; + return true; + } + }; + + static EntThinkAdapter door_secret_move2 = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameFunc.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 = GameBase.level.time + self.wait; + self.think = door_secret_move4; + return true; + } + }; + + static EntThinkAdapter door_secret_move4 = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameFunc.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 = GameBase.level.time + 1.0f; + self.think = door_secret_move6; + return true; + } + }; + + static EntThinkAdapter door_secret_move6 = new EntThinkAdapter() { + public boolean think(edict_t self) { + + GameFunc.Move_Calc(self, Globals.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 = Defines.DAMAGE_YES; + } + GameFunc.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 & Defines.SVF_MONSTER) + && (null == other.client)) { + // give it a chance to go away on it's own terms (like gibs) + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, 100000, 1, 0, + Defines.MOD_CRUSH); + // if it's still there, nuke it + if (other != null) + GameAI.BecomeExplosion1(other); + return; + } + + if (GameBase.level.time < self.touch_debounce_time) + return; + self.touch_debounce_time = GameBase.level.time + 0.5f; + + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, self.dmg, 1, 0, + Defines.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 = Defines.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 = GameBase.gi + .soundindex("doors/dr1_strt.wav"); + ent.moveinfo.sound_middle = GameBase.gi + .soundindex("doors/dr1_mid.wav"); + ent.moveinfo.sound_end = GameBase.gi + .soundindex("doors/dr1_end.wav"); + + ent.movetype = Defines.MOVETYPE_PUSH; + ent.solid = Defines.SOLID_BSP; + GameBase.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 = Defines.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 = Defines.DAMAGE_YES; + ent.die = door_killed; + ent.max_health = ent.health; + } else if (ent.targetname != null && ent.message != null) { + GameBase.gi.soundindex("misc/talk.wav"); + ent.touch = door_touch; + } + + ent.classname = "func_door"; + + GameBase.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() { + public void use(edict_t self, edict_t other, edict_t activator) { + GameUtil.KillBox(self); + } + }; + + static EntThinkAdapter SP_func_killbox = new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameBase.gi.setmodel(ent, ent.model); + ent.use = use_killbox; + ent.svflags = Defines.SVF_NOCLIENT; + return true; + } + }; +} \ No newline at end of file diff --git a/src/jake2/game/GameFuncAdapters.java b/src/jake2/game/GameFuncAdapters.java deleted file mode 100644 index a381091..0000000 --- a/src/jake2/game/GameFuncAdapters.java +++ /dev/null @@ -1,1638 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: GameFuncAdapters.java,v 1.2 2004-08-22 14:25:11 salomo Exp $ - -package jake2.game; - -import jake2.util.Lib; -import jake2.util.Math3D; -import jake2.Defines; -import jake2.Globals; -import jake2.util.*; -import jake2.util.*; - -public class GameFuncAdapters { - - /* - ========================================================= - - 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 / Defines.FRAMETIME, ent.velocity); - - ent.think= Move_Done; - ent.nextthink= GameBase.level.time + Defines.FRAMETIME; - return true; - } - }; - static EntThinkAdapter Move_Begin= new EntThinkAdapter() { - public boolean think(edict_t ent) { - - float frames; - - if ((ent.moveinfo.speed * Defines.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) / Defines.FRAMETIME); - ent.moveinfo.remaining_distance -= frames * ent.moveinfo.speed * Defines.FRAMETIME; - ent.nextthink= GameBase.level.time + (frames * Defines.FRAMETIME); - ent.think= Move_Final; - return true; - } - }; - // - // 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, Globals.vec3_origin) != 0) { - AngleMove_Done.think(ent); - return true; - } - - Math3D.VectorScale(move, 1.0f / Defines.FRAMETIME, ent.avelocity); - - ent.think= AngleMove_Done; - ent.nextthink= GameBase.level.time + Defines.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 < Defines.FRAMETIME) { - AngleMove_Final.think(ent); - return true; - } - - frames= (float) (Math.floor(traveltime / Defines.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= GameBase.level.time + frames * Defines.FRAMETIME; - ent.think= AngleMove_Final; - return true; - } - }; - 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 - GameFunc.plat_CalcAcceleratedMove(ent.moveinfo); - - GameFunc.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= GameBase.level.time + Defines.FRAMETIME; - ent.think= Think_AccelMove; - return true; - } - }; - static EntThinkAdapter plat_hit_top= new EntThinkAdapter() { - public boolean think(edict_t ent) { - if (0 == (ent.flags & Defines.FL_TEAMSLAVE)) { - if (ent.moveinfo.sound_end != 0) - GameBase.gi.sound( - ent, - Defines.CHAN_NO_PHS_ADD + Defines.CHAN_VOICE, - ent.moveinfo.sound_end, - 1, - Defines.ATTN_STATIC, - 0); - ent.s.sound= 0; - } - ent.moveinfo.state= STATE_TOP; - - ent.think= plat_go_down; - ent.nextthink= GameBase.level.time + 3; - return true; - } - }; - static EntThinkAdapter plat_hit_bottom= new EntThinkAdapter() { - public boolean think(edict_t ent) { - - if (0 == (ent.flags & Defines.FL_TEAMSLAVE)) { - if (ent.moveinfo.sound_end != 0) - GameBase.gi.sound( - ent, - Defines.CHAN_NO_PHS_ADD + Defines.CHAN_VOICE, - ent.moveinfo.sound_end, - 1, - Defines.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 & Defines.FL_TEAMSLAVE)) { - if (ent.moveinfo.sound_start != 0) - GameBase.gi.sound( - ent, - Defines.CHAN_NO_PHS_ADD + Defines.CHAN_VOICE, - ent.moveinfo.sound_start, - 1, - Defines.ATTN_STATIC, - 0); - ent.s.sound= ent.moveinfo.sound_middle; - } - ent.moveinfo.state= STATE_DOWN; - GameFunc.Move_Calc(ent, ent.moveinfo.end_origin, plat_hit_bottom); - return true; - } - }; - static EntBlockedAdapter plat_blocked= new EntBlockedAdapter() { - public void blocked(edict_t self, edict_t other) { - if (0 == (other.svflags & Defines.SVF_MONSTER) && (null == other.client)) { - // give it a chance to go away on it's own terms (like gibs) - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - other.s.origin, - Globals.vec3_origin, - 100000, - 1, - 0, - Defines.MOD_CRUSH); - // if it's still there, nuke it - if (other != null) - GameAI.BecomeExplosion1(other); - return; - } - - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - other.s.origin, - Globals.vec3_origin, - self.dmg, - 1, - 0, - Defines.MOD_CRUSH); - - if (self.moveinfo.state == STATE_UP) - plat_go_down.think(self); - else if (self.moveinfo.state == STATE_DOWN) - GameFunc.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) - GameFunc.plat_go_up(ent); - else if (ent.moveinfo.state == STATE_TOP) { - ent.nextthink= GameBase.level.time + 1; // the player is still on the plat, so delay going down - } - } - }; - // ==================================================================== - - /*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) { - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - other.s.origin, - Globals.vec3_origin, - self.dmg, - 1, - 0, - Defines.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) - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - other.s.origin, - Globals.vec3_origin, - self.dmg, - 1, - 0, - Defines.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, Globals.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= Defines.SOLID_BSP; - if ((ent.spawnflags & 32) != 0) - ent.movetype= Defines.MOVETYPE_STOP; - else - ent.movetype= Defines.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 |= Defines.EF_ANIM_ALL; - if ((ent.spawnflags & 128) != 0) - ent.s.effects |= Defines.EF_ANIM_ALLFAST; - - GameBase.gi.setmodel(ent, ent.model); - GameBase.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 &= ~Defines.EF_ANIM23; - self.s.effects |= Defines.EF_ANIM01; - return true; - } - }; - static EntThinkAdapter button_return= new EntThinkAdapter() { - public boolean think(edict_t self) { - self.moveinfo.state= STATE_DOWN; - - GameFunc.Move_Calc(self, self.moveinfo.start_origin, button_done); - - self.s.frame= 0; - - if (self.health != 0) - self.takedamage= Defines.DAMAGE_YES; - return true; - } - }; - static EntThinkAdapter button_wait= new EntThinkAdapter() { - public boolean think(edict_t self) { - self.moveinfo.state= STATE_TOP; - self.s.effects &= ~Defines.EF_ANIM01; - self.s.effects |= Defines.EF_ANIM23; - - GameUtil.G_UseTargets(self, self.activator); - self.s.frame= 1; - if (self.moveinfo.wait >= 0) { - self.nextthink= GameBase.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 & Defines.FL_TEAMSLAVE)) - GameBase.gi.sound( - self, - Defines.CHAN_NO_PHS_ADD + Defines.CHAN_VOICE, - self.moveinfo.sound_start, - 1, - Defines.ATTN_STATIC, - 0); - GameFunc.Move_Calc(self, self.moveinfo.end_origin, button_wait); - return true; - } - }; - static EntUseAdapter button_use= new EntUseAdapter() { - public void use(edict_t self, edict_t other, edict_t activator) { - self.activator= activator; - button_fire.think(self); - return; - } - }; - 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= Defines.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; - - GameBase.G_SetMovedir(ent.s.angles, ent.movedir); - ent.movetype= Defines.MOVETYPE_STOP; - ent.solid= Defines.SOLID_BSP; - GameBase.gi.setmodel(ent, ent.model); - - if (ent.sounds != 1) - ent.moveinfo.sound_start= GameBase.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 == GameBase.st.lip) - GameBase.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] - GameBase.st.lip; - Math3D.VectorMA(ent.pos1, dist, ent.movedir, ent.pos2); - - ent.use= button_use; - ent.s.effects |= Defines.EF_ANIM01; - - if (ent.health != 0) { - ent.max_health= ent.health; - ent.die= button_killed; - ent.takedamage= Defines.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); - - GameBase.gi.linkentity(ent); - return true; - } - }; - static EntThinkAdapter door_hit_top= new EntThinkAdapter() { - public boolean think(edict_t self) { - if (0 == (self.flags & Defines.FL_TEAMSLAVE)) { - if (self.moveinfo.sound_end != 0) - GameBase.gi.sound( - self, - Defines.CHAN_NO_PHS_ADD + Defines.CHAN_VOICE, - self.moveinfo.sound_end, - 1, - Defines.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= GameBase.level.time + self.moveinfo.wait; - } - return true; - } - }; - static EntThinkAdapter door_hit_bottom= new EntThinkAdapter() { - public boolean think(edict_t self) { - if (0 == (self.flags & Defines.FL_TEAMSLAVE)) { - if (self.moveinfo.sound_end != 0) - GameBase.gi.sound( - self, - Defines.CHAN_NO_PHS_ADD + Defines.CHAN_VOICE, - self.moveinfo.sound_end, - 1, - Defines.ATTN_STATIC, - 0); - self.s.sound= 0; - } - self.moveinfo.state= STATE_BOTTOM; - GameFunc.door_use_areaportals(self, false); - return true; - } - }; - static EntThinkAdapter door_go_down= new EntThinkAdapter() { - public boolean think(edict_t self) { - if (0 == (self.flags & Defines.FL_TEAMSLAVE)) { - if (self.moveinfo.sound_start != 0) - GameBase.gi.sound( - self, - Defines.CHAN_NO_PHS_ADD + Defines.CHAN_VOICE, - self.moveinfo.sound_start, - 1, - Defines.ATTN_STATIC, - 0); - self.s.sound= self.moveinfo.sound_middle; - } - if (self.max_health != 0) { - self.takedamage= Defines.DAMAGE_YES; - self.health= self.max_health; - } - - self.moveinfo.state= STATE_DOWN; - if (Lib.strcmp(self.classname, "func_door") == 0) - GameFunc.Move_Calc(self, self.moveinfo.start_origin, door_hit_bottom); - else if (Lib.strcmp(self.classname, "func_door_rotating") == 0) - GameFunc.AngleMove_Calc(self, door_hit_bottom); - return 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 & Defines.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; - GameFunc.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 & Defines.SVF_MONSTER) && (null == other.client)) - return; - - if (0 != (self.owner.spawnflags & DOOR_NOMONSTER) && 0 != (other.svflags & Defines.SVF_MONSTER)) - return; - - if (GameBase.level.time < self.touch_debounce_time) - return; - self.touch_debounce_time= GameBase.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 & Defines.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 & Defines.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) { - GameBase.AddPointToBounds(other.absmin, mins, maxs); - GameBase.AddPointToBounds(other.absmax, mins, maxs); - } - - // expand - mins[0] -= 60; - mins[1] -= 60; - maxs[0] += 60; - maxs[1] += 60; - - other= GameUtil.G_Spawn(); - Math3D.VectorCopy(mins, other.mins); - Math3D.VectorCopy(maxs, other.maxs); - other.owner= ent; - other.solid= Defines.SOLID_TRIGGER; - other.movetype= Defines.MOVETYPE_NONE; - other.touch= Touch_DoorTrigger; - GameBase.gi.linkentity(other); - - if ((ent.spawnflags & DOOR_START_OPEN) != 0) - GameFunc.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 & Defines.SVF_MONSTER) && (null == other.client)) { - // give it a chance to go away on it's own terms (like gibs) - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - other.s.origin, - Globals.vec3_origin, - 100000, - 1, - 0, - Defines.MOD_CRUSH); - // if it's still there, nuke it - if (other != null) - GameAI.BecomeExplosion1(other); - return; - } - - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - other.s.origin, - Globals.vec3_origin, - self.dmg, - 1, - 0, - Defines.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) - GameFunc.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= Defines.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 (GameBase.level.time < self.touch_debounce_time) - return; - self.touch_debounce_time= GameBase.level.time + 5.0f; - - GameBase.gi.centerprintf(other, self.message); - GameBase.gi.sound(other, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/talk1.wav"), 1, Defines.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= GameBase.gi.soundindex("doors/dr1_strt.wav"); - ent.moveinfo.sound_middle= GameBase.gi.soundindex("doors/dr1_mid.wav"); - ent.moveinfo.sound_end= GameBase.gi.soundindex("doors/dr1_end.wav"); - } - - GameBase.G_SetMovedir(ent.s.angles, ent.movedir); - ent.movetype= Defines.MOVETYPE_PUSH; - ent.solid= Defines.SOLID_BSP; - GameBase.gi.setmodel(ent, ent.model); - - ent.blocked= door_blocked; - ent.use= door_use; - - if (0 == ent.speed) - ent.speed= 100; - if (GameBase.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 == GameBase.st.lip) - GameBase.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] - GameBase.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= Defines.DAMAGE_YES; - ent.die= door_killed; - ent.max_health= ent.health; - } - else if (ent.targetname != null && ent.message != null) { - GameBase.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 |= Defines.EF_ANIM_ALL; - if ((ent.spawnflags & 64) != 0) - ent.s.effects |= Defines.EF_ANIM_ALLFAST; - - // to simplify logic elsewhere, make non-teamed doors into a team of one - if (null == ent.team) - ent.teammaster= ent; - - GameBase.gi.linkentity(ent); - - ent.nextthink= GameBase.level.time + Defines.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 == GameBase.st.distance) { - GameBase.gi.dprintf(ent.classname + " at " + Lib.vtos(ent.s.origin) + " with no distance set\n"); - GameBase.st.distance= 90; - } - - Math3D.VectorCopy(ent.s.angles, ent.pos1); - Math3D.VectorMA(ent.s.angles, GameBase.st.distance, ent.movedir, ent.pos2); - ent.moveinfo.distance= GameBase.st.distance; - - ent.movetype= Defines.MOVETYPE_PUSH; - ent.solid= Defines.SOLID_BSP; - GameBase.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= GameBase.gi.soundindex("doors/dr1_strt.wav"); - ent.moveinfo.sound_middle= GameBase.gi.soundindex("doors/dr1_mid.wav"); - ent.moveinfo.sound_end= GameBase.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= Defines.DAMAGE_YES; - ent.die= door_killed; - ent.max_health= ent.health; - } - - if (ent.targetname != null && ent.message != null) { - GameBase.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 |= Defines.EF_ANIM_ALL; - - // to simplify logic elsewhere, make non-teamed doors into a team of one - if (ent.team == null) - ent.teammaster= ent; - - GameBase.gi.linkentity(ent); - - ent.nextthink= GameBase.level.time + Defines.FRAMETIME; - if (ent.health != 0 || ent.targetname != null) - ent.think= Think_CalcMoveSpeed; - else - ent.think= Think_SpawnDoorTrigger; - return true; - } - }; - 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 & Defines.SVF_MONSTER) && (null == other.client)) { - // give it a chance to go away on it's own terms (like gibs) - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - other.s.origin, - Globals.vec3_origin, - 100000, - 1, - 0, - Defines.MOD_CRUSH); - // if it's still there, nuke it - if (other != null) - GameAI.BecomeExplosion1(other); - return; - } - - if (GameBase.level.time < self.touch_debounce_time) - return; - - if (self.dmg == 0) - return; - self.touch_debounce_time= GameBase.level.time + 0.5f; - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - other.s.origin, - Globals.vec3_origin, - self.dmg, - 1, - 0, - Defines.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; - GameUtil.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= GameBase.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 & Defines.FL_TEAMSLAVE)) { - if (self.moveinfo.sound_end != 0) - GameBase.gi.sound( - self, - Defines.CHAN_NO_PHS_ADD + Defines.CHAN_VOICE, - self.moveinfo.sound_end, - 1, - Defines.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= GameBase.G_PickTarget(self.target); - if (null == ent) { - GameBase.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) { - GameBase.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= Defines.EV_OTHER_TELEPORT; - GameBase.gi.linkentity(self); - dogoto= true; - } - } - self.moveinfo.wait= ent.wait; - self.target_ent= ent; - - if (0 == (self.flags & Defines.FL_TEAMSLAVE)) { - if (self.moveinfo.sound_start != 0) - GameBase.gi.sound( - self, - Defines.CHAN_NO_PHS_ADD + Defines.CHAN_VOICE, - self.moveinfo.sound_start, - 1, - Defines.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); - GameFunc.Move_Calc(self, dest, train_wait); - self.spawnflags |= TRAIN_START_ON; - return true; - } - }; - public static EntThinkAdapter func_train_find= new EntThinkAdapter() { - public boolean think(edict_t self) { - edict_t ent; - - if (null == self.target) { - GameBase.gi.dprintf("train_find: no target\n"); - return true; - } - ent= GameBase.G_PickTarget(self.target); - if (null == ent) { - GameBase.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); - GameBase.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= GameBase.level.time + Defines.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) - GameFunc.train_resume(self); - else - train_next.think(self); - } - } - }; - /*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) { - GameBase.gi.dprintf("elevator used with no pathtarget\n"); - return; - } - - target= GameBase.G_PickTarget(other.pathtarget); - if (null == target) { - GameBase.gi.dprintf("elevator used with bad pathtarget: " + other.pathtarget + "\n"); - return; - } - - self.movetarget.target_ent= target; - GameFunc.train_resume(self.movetarget); - } - }; - static EntThinkAdapter trigger_elevator_init= new EntThinkAdapter() { - public boolean think(edict_t self) { - if (null == self.target) { - GameBase.gi.dprintf("trigger_elevator has no target\n"); - return true; - } - self.movetarget= GameBase.G_PickTarget(self.target); - if (null == self.movetarget) { - GameBase.gi.dprintf("trigger_elevator unable to find target " + self.target + "\n"); - return true; - } - if (Lib.strcmp(self.movetarget.classname, "func_train") != 0) { - GameBase.gi.dprintf("trigger_elevator target " + self.target + " is not a train\n"); - return true; - } - - self.use= trigger_elevator_use; - self.svflags= Defines.SVF_NOCLIENT; - return true; - } - }; - static EntThinkAdapter SP_trigger_elevator= new EntThinkAdapter() { - public boolean think(edict_t self) { - self.think= trigger_elevator_init; - self.nextthink= GameBase.level.time + Defines.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) { - GameUtil.G_UseTargets(self, self.activator); - self.nextthink= GameBase.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= GameBase.level.time + self.delay; - else - func_timer_think.think(self); - } - }; - /*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; - - GameBase.gi.setmodel(self, self.model); - self.solid= Defines.SOLID_BSP; - GameBase.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, Globals.vec3_origin)) - return; - - GameFunc.Move_Calc(self, self.pos1, door_secret_move1); - GameFunc.door_use_areaportals(self, true); - } - }; - static EntThinkAdapter door_secret_move1= new EntThinkAdapter() { - public boolean think(edict_t self) { - self.nextthink= GameBase.level.time + 1.0f; - self.think= door_secret_move2; - return true; - } - }; - static EntThinkAdapter door_secret_move2= new EntThinkAdapter() { - public boolean think(edict_t self) { - GameFunc.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= GameBase.level.time + self.wait; - self.think= door_secret_move4; - return true; - } - }; - static EntThinkAdapter door_secret_move4= new EntThinkAdapter() { - public boolean think(edict_t self) { - GameFunc.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= GameBase.level.time + 1.0f; - self.think= door_secret_move6; - return true; - } - }; - static EntThinkAdapter door_secret_move6= new EntThinkAdapter() { - public boolean think(edict_t self) { - - GameFunc.Move_Calc(self, Globals.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= Defines.DAMAGE_YES; - } - GameFunc.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 & Defines.SVF_MONSTER) && (null == other.client)) { - // give it a chance to go away on it's own terms (like gibs) - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - other.s.origin, - Globals.vec3_origin, - 100000, - 1, - 0, - Defines.MOD_CRUSH); - // if it's still there, nuke it - if (other != null) - GameAI.BecomeExplosion1(other); - return; - } - - if (GameBase.level.time < self.touch_debounce_time) - return; - self.touch_debounce_time= GameBase.level.time + 0.5f; - - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - other.s.origin, - Globals.vec3_origin, - self.dmg, - 1, - 0, - Defines.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= Defines.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= GameBase.gi.soundindex("doors/dr1_strt.wav"); - ent.moveinfo.sound_middle= GameBase.gi.soundindex("doors/dr1_mid.wav"); - ent.moveinfo.sound_end= GameBase.gi.soundindex("doors/dr1_end.wav"); - - ent.movetype= Defines.MOVETYPE_PUSH; - ent.solid= Defines.SOLID_BSP; - GameBase.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= Defines.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= Defines.DAMAGE_YES; - ent.die= door_killed; - ent.max_health= ent.health; - } - else if (ent.targetname != null && ent.message != null) { - GameBase.gi.soundindex("misc/talk.wav"); - ent.touch= door_touch; - } - - ent.classname= "func_door"; - - GameBase.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() { - public void use(edict_t self, edict_t other, edict_t activator) { - GameUtil.KillBox(self); - } - }; - static EntThinkAdapter SP_func_killbox= new EntThinkAdapter() { - public boolean think(edict_t ent) { - GameBase.gi.setmodel(ent, ent.model); - ent.use= use_killbox; - ent.svflags= Defines.SVF_NOCLIENT; - return true; - } - }; -} diff --git a/src/jake2/game/GameMisc.java b/src/jake2/game/GameMisc.java index 1d4f4e8..dba1e26 100644 --- a/src/jake2/game/GameMisc.java +++ b/src/jake2/game/GameMisc.java @@ -1,733 +1,1653 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 27.12.2003 by RST. -// $Id: GameMisc.java,v 1.3 2004-09-10 19:02:54 salomo Exp $ - +// $Id: GameMisc.java,v 1.4 2004-09-22 19:22:03 salomo Exp $ package jake2.game; -import jake2.client.M; +import java.util.Calendar; -public class GameMisc extends GameTrigger -{ - 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 = GameMiscAdapters.path_corner_touch; - VectorSet(self.mins, -8, -8, -8); - VectorSet(self.maxs, 8, 8, 8); - self.svflags |= SVF_NOCLIENT; - gi.linkentity(self); - } - - public static void SP_point_combat(edict_t self) - { - if (deathmatch.value != 0) - { - G_FreeEdict(self); - return; - } - self.solid = SOLID_TRIGGER; - self.touch = GameMiscAdapters.point_combat_touch; - VectorSet(self.mins, -8, -8, -16); - VectorSet(self.maxs, 8, 8, 16); - self.svflags = SVF_NOCLIENT; - gi.linkentity(self); - }; - - 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 = GameMiscAdapters.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); - }; - - 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 = GameMiscAdapters.light_use; - if ((self.spawnflags & GameMiscAdapters.START_OFF) != 0) - gi.configstring(CS_LIGHTS + self.style, "a"); - else - gi.configstring(CS_LIGHTS + self.style, "m"); - } - } - - 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 = GameMiscAdapters.func_wall_use; - if ((self.spawnflags & 4) != 0) - { - self.solid = SOLID_BSP; - } - else - { - self.solid = SOLID_NOT; - self.svflags |= SVF_NOCLIENT; - } - gi.linkentity(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 = GameMiscAdapters.func_object_release; - self.nextthink = level.time + 2 * FRAMETIME; - } - else - { - self.solid = SOLID_NOT; - self.movetype = MOVETYPE_PUSH; - self.use = GameMiscAdapters.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); - } - - 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 = GameMiscAdapters.func_explosive_spawn; - } - else - { - self.solid = SOLID_BSP; - if (self.targetname != null) - self.use = GameMiscAdapters.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 != GameMiscAdapters.func_explosive_use) - { - if (self.health == 0) - self.health = 100; - self.die = GameMiscAdapters.func_explosive_explode; - self.takedamage = DAMAGE_YES; - } - - gi.linkentity(self); - } - - 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 = GameMiscAdapters.barrel_delay; - self.takedamage = DAMAGE_YES; - self.monsterinfo.aiflags = AI_NOSTEP; - - self.touch = GameMiscAdapters.barrel_touch; - - self.think = M.M_droptofloor; - self.nextthink = level.time + 2 * FRAMETIME; - - gi.linkentity(self); - } - - 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 = GameMiscAdapters.misc_blackhole_use; - ent.think = GameMiscAdapters.misc_blackhole_think; - ent.nextthink = level.time + 2 * FRAMETIME; - gi.linkentity(ent); - } - - 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 = GameMiscAdapters.misc_eastertank_think; - ent.nextthink = level.time + 2 * FRAMETIME; - gi.linkentity(ent); - } - - 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 = GameMiscAdapters.misc_easterchick_think; - ent.nextthink = level.time + 2 * FRAMETIME; - gi.linkentity(ent); - } - - 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 = GameMiscAdapters.misc_easterchick2_think; - ent.nextthink = level.time + 2 * FRAMETIME; - gi.linkentity(ent); - } - - 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 = GameMiscAdapters.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 = GameMiscAdapters.commander_body_drop; - self.nextthink = level.time + 5 * FRAMETIME; - } - - 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 = GameMiscAdapters.misc_banner_think; - ent.nextthink = level.time + FRAMETIME; - } - - 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 = GameMiscAdapters.misc_deadsoldier_die; - ent.monsterinfo.aiflags |= AI_GOOD_GUY; - - gi.linkentity(ent); - } - - 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 = GameFuncAdapters.func_train_find; - ent.nextthink = level.time + FRAMETIME; - ent.use = GameMiscAdapters.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); - } - - 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 = GameMiscAdapters.misc_viper_bomb_use; - self.svflags |= SVF_NOCLIENT; - - gi.linkentity(self); - } - - 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 = GameFuncAdapters.func_train_find; - ent.nextthink = level.time + FRAMETIME; - ent.use = GameMiscAdapters.misc_strogg_ship_use; - ent.svflags |= SVF_NOCLIENT; - ent.moveinfo.accel = ent.moveinfo.decel = ent.moveinfo.speed = ent.speed; - - gi.linkentity(ent); - } - - 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 = GameMiscAdapters.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 = GameAIAdapters.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 = GameUtilAdapters.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 = GameAIAdapters.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 = GameUtilAdapters.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 = GameAIAdapters.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 = GameUtilAdapters.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; - } - - public static void SP_target_string(edict_t self) - { - if (self.message == null) - self.message = ""; - self.use = GameMiscAdapters.target_string_use; - } - - // 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 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 = new String(); - - self.think = GameMiscAdapters.func_clock_think; - - if ((self.spawnflags & 4) != 0) - self.use = GameMiscAdapters.func_clock_use; - else - self.nextthink = level.time + 1; - } - - /*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 = GameMiscAdapters.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); - } -} +import jake2.Defines; +import jake2.Globals; +import jake2.client.M; +import jake2.util.Lib; +import jake2.util.Math3D; + +public class GameMisc { + public static void SP_path_corner(edict_t self) { + if (self.targetname == null) { + GameBase.gi.dprintf("path_corner with no targetname at " + + Lib.vtos(self.s.origin) + "\n"); + GameUtil.G_FreeEdict(self); + return; + } + + self.solid = Defines.SOLID_TRIGGER; + self.touch = path_corner_touch; + Math3D.VectorSet(self.mins, -8, -8, -8); + Math3D.VectorSet(self.maxs, 8, 8, 8); + self.svflags |= Defines.SVF_NOCLIENT; + GameBase.gi.linkentity(self); + } + + public static void SP_point_combat(edict_t self) { + if (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + self.solid = Defines.SOLID_TRIGGER; + self.touch = point_combat_touch; + Math3D.VectorSet(self.mins, -8, -8, -16); + Math3D.VectorSet(self.maxs, 8, 8, 16); + self.svflags = Defines.SVF_NOCLIENT; + GameBase.gi.linkentity(self); + }; + + public static void SP_viewthing(edict_t ent) { + GameBase.gi.dprintf("viewthing spawned\n"); + + ent.movetype = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_BBOX; + ent.s.renderfx = Defines.RF_FRAMELERP; + Math3D.VectorSet(ent.mins, -16, -16, -24); + Math3D.VectorSet(ent.maxs, 16, 16, 32); + ent.s.modelindex = GameBase.gi + .modelindex("models/objects/banner/tris.md2"); + GameBase.gi.linkentity(ent); + ent.nextthink = GameBase.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) { + GameUtil.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) { + Math3D.VectorCopy(self.s.origin, self.absmin); + Math3D.VectorCopy(self.s.origin, self.absmax); + }; + + public static void SP_light(edict_t self) { + // no targeted lights in deathmatch, because they cause global messages + if (null == self.targetname || GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + if (self.style >= 32) { + self.use = light_use; + if ((self.spawnflags & START_OFF) != 0) + GameBase.gi.configstring(Defines.CS_LIGHTS + self.style, "a"); + else + GameBase.gi.configstring(Defines.CS_LIGHTS + self.style, "m"); + } + } + + public static void SP_func_wall(edict_t self) { + self.movetype = Defines.MOVETYPE_PUSH; + GameBase.gi.setmodel(self, self.model); + + if ((self.spawnflags & 8) != 0) + self.s.effects |= Defines.EF_ANIM_ALL; + if ((self.spawnflags & 16) != 0) + self.s.effects |= Defines.EF_ANIM_ALLFAST; + + // just a wall + if ((self.spawnflags & 7) == 0) { + self.solid = Defines.SOLID_BSP; + GameBase.gi.linkentity(self); + return; + } + + // it must be TRIGGER_SPAWN + if (0 == (self.spawnflags & 1)) { + GameBase.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)) { + GameBase.gi.dprintf("func_wall START_ON without TOGGLE\n"); + self.spawnflags |= 2; + } + } + + self.use = func_wall_use; + if ((self.spawnflags & 4) != 0) { + self.solid = Defines.SOLID_BSP; + } else { + self.solid = Defines.SOLID_NOT; + self.svflags |= Defines.SVF_NOCLIENT; + } + GameBase.gi.linkentity(self); + } + + public static void SP_func_object(edict_t self) { + GameBase.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 = Defines.SOLID_BSP; + self.movetype = Defines.MOVETYPE_PUSH; + self.think = func_object_release; + self.nextthink = GameBase.level.time + 2 * Defines.FRAMETIME; + } else { + self.solid = Defines.SOLID_NOT; + self.movetype = Defines.MOVETYPE_PUSH; + self.use = func_object_use; + self.svflags |= Defines.SVF_NOCLIENT; + } + + if ((self.spawnflags & 2) != 0) + self.s.effects |= Defines.EF_ANIM_ALL; + if ((self.spawnflags & 4) != 0) + self.s.effects |= Defines.EF_ANIM_ALLFAST; + + self.clipmask = Defines.MASK_MONSTERSOLID; + + GameBase.gi.linkentity(self); + } + + public static void SP_func_explosive(edict_t self) { + if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch + GameUtil.G_FreeEdict(self); + return; + } + + self.movetype = Defines.MOVETYPE_PUSH; + + GameBase.gi.modelindex("models/objects/debris1/tris.md2"); + GameBase.gi.modelindex("models/objects/debris2/tris.md2"); + + GameBase.gi.setmodel(self, self.model); + + if ((self.spawnflags & 1) != 0) { + self.svflags |= Defines.SVF_NOCLIENT; + self.solid = Defines.SOLID_NOT; + self.use = func_explosive_spawn; + } else { + self.solid = Defines.SOLID_BSP; + if (self.targetname != null) + self.use = func_explosive_use; + } + + if ((self.spawnflags & 2) != 0) + self.s.effects |= Defines.EF_ANIM_ALL; + if ((self.spawnflags & 4) != 0) + self.s.effects |= Defines.EF_ANIM_ALLFAST; + + if (self.use != func_explosive_use) { + if (self.health == 0) + self.health = 100; + self.die = func_explosive_explode; + self.takedamage = Defines.DAMAGE_YES; + } + + GameBase.gi.linkentity(self); + } + + public static void SP_misc_explobox(edict_t self) { + if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch + GameUtil.G_FreeEdict(self); + return; + } + + GameBase.gi.modelindex("models/objects/debris1/tris.md2"); + GameBase.gi.modelindex("models/objects/debris2/tris.md2"); + GameBase.gi.modelindex("models/objects/debris3/tris.md2"); + + self.solid = Defines.SOLID_BBOX; + self.movetype = Defines.MOVETYPE_STEP; + + self.model = "models/objects/barrels/tris.md2"; + self.s.modelindex = GameBase.gi.modelindex(self.model); + Math3D.VectorSet(self.mins, -16, -16, 0); + Math3D.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 = Defines.DAMAGE_YES; + self.monsterinfo.aiflags = Defines.AI_NOSTEP; + + self.touch = barrel_touch; + + self.think = M.M_droptofloor; + self.nextthink = GameBase.level.time + 2 * Defines.FRAMETIME; + + GameBase.gi.linkentity(self); + } + + public static void SP_misc_blackhole(edict_t ent) { + ent.movetype = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_NOT; + Math3D.VectorSet(ent.mins, -64, -64, 0); + Math3D.VectorSet(ent.maxs, 64, 64, 8); + ent.s.modelindex = GameBase.gi + .modelindex("models/objects/black/tris.md2"); + ent.s.renderfx = Defines.RF_TRANSLUCENT; + ent.use = misc_blackhole_use; + ent.think = misc_blackhole_think; + ent.nextthink = GameBase.level.time + 2 * Defines.FRAMETIME; + GameBase.gi.linkentity(ent); + } + + public static void SP_misc_eastertank(edict_t ent) { + ent.movetype = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_BBOX; + Math3D.VectorSet(ent.mins, -32, -32, -16); + Math3D.VectorSet(ent.maxs, 32, 32, 32); + ent.s.modelindex = GameBase.gi + .modelindex("models/monsters/tank/tris.md2"); + ent.s.frame = 254; + ent.think = misc_eastertank_think; + ent.nextthink = GameBase.level.time + 2 * Defines.FRAMETIME; + GameBase.gi.linkentity(ent); + } + + public static void SP_misc_easterchick(edict_t ent) { + ent.movetype = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_BBOX; + Math3D.VectorSet(ent.mins, -32, -32, 0); + Math3D.VectorSet(ent.maxs, 32, 32, 32); + ent.s.modelindex = GameBase.gi + .modelindex("models/monsters/bitch/tris.md2"); + ent.s.frame = 208; + ent.think = misc_easterchick_think; + ent.nextthink = GameBase.level.time + 2 * Defines.FRAMETIME; + GameBase.gi.linkentity(ent); + } + + public static void SP_misc_easterchick2(edict_t ent) { + ent.movetype = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_BBOX; + Math3D.VectorSet(ent.mins, -32, -32, 0); + Math3D.VectorSet(ent.maxs, 32, 32, 32); + ent.s.modelindex = GameBase.gi + .modelindex("models/monsters/bitch/tris.md2"); + ent.s.frame = 248; + ent.think = misc_easterchick2_think; + ent.nextthink = GameBase.level.time + 2 * Defines.FRAMETIME; + GameBase.gi.linkentity(ent); + } + + public static void SP_monster_commander_body(edict_t self) { + self.movetype = Defines.MOVETYPE_NONE; + self.solid = Defines.SOLID_BBOX; + self.model = "models/monsters/commandr/tris.md2"; + self.s.modelindex = GameBase.gi.modelindex(self.model); + Math3D.VectorSet(self.mins, -32, -32, 0); + Math3D.VectorSet(self.maxs, 32, 32, 48); + self.use = commander_body_use; + self.takedamage = Defines.DAMAGE_YES; + self.flags = Defines.FL_GODMODE; + self.s.renderfx |= Defines.RF_FRAMELERP; + GameBase.gi.linkentity(self); + + GameBase.gi.soundindex("tank/thud.wav"); + GameBase.gi.soundindex("tank/pain.wav"); + + self.think = commander_body_drop; + self.nextthink = GameBase.level.time + 5 * Defines.FRAMETIME; + } + + public static void SP_misc_banner(edict_t ent) { + ent.movetype = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_NOT; + ent.s.modelindex = GameBase.gi + .modelindex("models/objects/banner/tris.md2"); + ent.s.frame = Lib.rand() % 16; + GameBase.gi.linkentity(ent); + + ent.think = misc_banner_think; + ent.nextthink = GameBase.level.time + Defines.FRAMETIME; + } + + public static void SP_misc_deadsoldier(edict_t ent) { + if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch + GameUtil.G_FreeEdict(ent); + return; + } + + ent.movetype = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_BBOX; + ent.s.modelindex = GameBase.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; + + Math3D.VectorSet(ent.mins, -16, -16, 0); + Math3D.VectorSet(ent.maxs, 16, 16, 16); + ent.deadflag = Defines.DEAD_DEAD; + ent.takedamage = Defines.DAMAGE_YES; + ent.svflags |= Defines.SVF_MONSTER | Defines.SVF_DEADMONSTER; + ent.die = misc_deadsoldier_die; + ent.monsterinfo.aiflags |= Defines.AI_GOOD_GUY; + + GameBase.gi.linkentity(ent); + } + + public static void SP_misc_viper(edict_t ent) { + if (null == ent.target) { + GameBase.gi.dprintf("misc_viper without a target at " + + Lib.vtos(ent.absmin) + "\n"); + GameUtil.G_FreeEdict(ent); + return; + } + + if (0 == ent.speed) + ent.speed = 300; + + ent.movetype = Defines.MOVETYPE_PUSH; + ent.solid = Defines.SOLID_NOT; + ent.s.modelindex = GameBase.gi + .modelindex("models/ships/viper/tris.md2"); + Math3D.VectorSet(ent.mins, -16, -16, 0); + Math3D.VectorSet(ent.maxs, 16, 16, 32); + + ent.think = GameFunc.func_train_find; + ent.nextthink = GameBase.level.time + Defines.FRAMETIME; + ent.use = misc_viper_use; + ent.svflags |= Defines.SVF_NOCLIENT; + ent.moveinfo.accel = ent.moveinfo.decel = ent.moveinfo.speed = ent.speed; + + GameBase.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 = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_BBOX; + Math3D.VectorSet(ent.mins, -176, -120, -24); + Math3D.VectorSet(ent.maxs, 176, 120, 72); + ent.s.modelindex = GameBase.gi + .modelindex("models/ships/bigviper/tris.md2"); + GameBase.gi.linkentity(ent); + } + + public static void SP_misc_viper_bomb(edict_t self) { + self.movetype = Defines.MOVETYPE_NONE; + self.solid = Defines.SOLID_NOT; + Math3D.VectorSet(self.mins, -8, -8, -8); + Math3D.VectorSet(self.maxs, 8, 8, 8); + + self.s.modelindex = GameBase.gi + .modelindex("models/objects/bomb/tris.md2"); + + if (self.dmg == 0) + self.dmg = 1000; + + self.use = misc_viper_bomb_use; + self.svflags |= Defines.SVF_NOCLIENT; + + GameBase.gi.linkentity(self); + } + + public static void SP_misc_strogg_ship(edict_t ent) { + if (null == ent.target) { + GameBase.gi.dprintf(ent.classname + " without a target at " + + Lib.vtos(ent.absmin) + "\n"); + GameUtil.G_FreeEdict(ent); + return; + } + + if (0 == ent.speed) + ent.speed = 300; + + ent.movetype = Defines.MOVETYPE_PUSH; + ent.solid = Defines.SOLID_NOT; + ent.s.modelindex = GameBase.gi + .modelindex("models/ships/strogg1/tris.md2"); + Math3D.VectorSet(ent.mins, -16, -16, 0); + Math3D.VectorSet(ent.maxs, 16, 16, 32); + + ent.think = GameFunc.func_train_find; + ent.nextthink = GameBase.level.time + Defines.FRAMETIME; + ent.use = misc_strogg_ship_use; + ent.svflags |= Defines.SVF_NOCLIENT; + ent.moveinfo.accel = ent.moveinfo.decel = ent.moveinfo.speed = ent.speed; + + GameBase.gi.linkentity(ent); + } + + public static void SP_misc_satellite_dish(edict_t ent) { + ent.movetype = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_BBOX; + Math3D.VectorSet(ent.mins, -64, -64, 0); + Math3D.VectorSet(ent.maxs, 64, 64, 128); + ent.s.modelindex = GameBase.gi + .modelindex("models/objects/satellite/tris.md2"); + ent.use = misc_satellite_dish_use; + GameBase.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 = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_BBOX; + ent.s.modelindex = GameBase.gi + .modelindex("models/objects/minelite/light1/tris.md2"); + GameBase.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 = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_BBOX; + ent.s.modelindex = GameBase.gi + .modelindex("models/objects/minelite/light2/tris.md2"); + GameBase.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) { + GameBase.gi.setmodel(ent, "models/objects/gibs/arm/tris.md2"); + ent.solid = Defines.SOLID_NOT; + ent.s.effects |= Defines.EF_GIB; + ent.takedamage = Defines.DAMAGE_YES; + ent.die = GameAI.gib_die; + ent.movetype = Defines.MOVETYPE_TOSS; + ent.svflags |= Defines.SVF_MONSTER; + ent.deadflag = Defines.DEAD_DEAD; + ent.avelocity[0] = Lib.random() * 200; + ent.avelocity[1] = Lib.random() * 200; + ent.avelocity[2] = Lib.random() * 200; + ent.think = GameUtil.G_FreeEdictA; + ent.nextthink = GameBase.level.time + 30; + GameBase.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) { + GameBase.gi.setmodel(ent, "models/objects/gibs/leg/tris.md2"); + ent.solid = Defines.SOLID_NOT; + ent.s.effects |= Defines.EF_GIB; + ent.takedamage = Defines.DAMAGE_YES; + ent.die = GameAI.gib_die; + ent.movetype = Defines.MOVETYPE_TOSS; + ent.svflags |= Defines.SVF_MONSTER; + ent.deadflag = Defines.DEAD_DEAD; + ent.avelocity[0] = Lib.random() * 200; + ent.avelocity[1] = Lib.random() * 200; + ent.avelocity[2] = Lib.random() * 200; + ent.think = GameUtil.G_FreeEdictA; + ent.nextthink = GameBase.level.time + 30; + GameBase.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) { + GameBase.gi.setmodel(ent, "models/objects/gibs/head/tris.md2"); + ent.solid = Defines.SOLID_NOT; + ent.s.effects |= Defines.EF_GIB; + ent.takedamage = Defines.DAMAGE_YES; + ent.die = GameAI.gib_die; + ent.movetype = Defines.MOVETYPE_TOSS; + ent.svflags |= Defines.SVF_MONSTER; + ent.deadflag = Defines.DEAD_DEAD; + ent.avelocity[0] = Lib.random() * 200; + ent.avelocity[1] = Lib.random() * 200; + ent.avelocity[2] = Lib.random() * 200; + ent.think = GameUtil.G_FreeEdictA; + ent.nextthink = GameBase.level.time + 30; + GameBase.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 = Defines.MOVETYPE_PUSH; + GameBase.gi.setmodel(self, self.model); + self.solid = Defines.SOLID_BSP; + self.s.frame = 12; + GameBase.gi.linkentity(self); + return; + } + + public static void SP_target_string(edict_t self) { + if (self.message == null) + self.message = ""; + self.use = target_string_use; + } + + // 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 void SP_func_clock(edict_t self) { + if (self.target == null) { + GameBase.gi.dprintf(self.classname + " with no target at " + + Lib.vtos(self.s.origin) + "\n"); + GameUtil.G_FreeEdict(self); + return; + } + + if ((self.spawnflags & 2) != 0 && (0 == self.count)) { + GameBase.gi.dprintf(self.classname + " with no count at " + + Lib.vtos(self.s.origin) + "\n"); + GameUtil.G_FreeEdict(self); + return; + } + + if ((self.spawnflags & 1) != 0 && (0 == self.count)) + self.count = 60 * 60; + + func_clock_reset(self); + + self.message = new String(); + + self.think = func_clock_think; + + if ((self.spawnflags & 4) != 0) + self.use = func_clock_use; + else + self.nextthink = GameBase.level.time + 1; + } + + /* + * 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) { + GameBase.gi.dprintf("teleporter without a target.\n"); + GameUtil.G_FreeEdict(ent); + return; + } + + GameBase.gi.setmodel(ent, "models/objects/dmspot/tris.md2"); + ent.s.skinnum = 1; + ent.s.effects = Defines.EF_TELEPORTER; + ent.s.sound = GameBase.gi.soundindex("world/amb10.wav"); + ent.solid = Defines.SOLID_BBOX; + + Math3D.VectorSet(ent.mins, -32, -32, -24); + Math3D.VectorSet(ent.maxs, 32, 32, -16); + GameBase.gi.linkentity(ent); + + trig = GameUtil.G_Spawn(); + trig.touch = teleporter_touch; + trig.solid = Defines.SOLID_TRIGGER; + trig.target = ent.target; + trig.owner = ent; + Math3D.VectorCopy(ent.s.origin, trig.s.origin); + Math3D.VectorSet(trig.mins, -8, -8, 8); + Math3D.VectorSet(trig.maxs, 8, 8, 24); + GameBase.gi.linkentity(trig); + } + + /* + * QUAKED func_group (0 0 0) ? Used to group brushes together just for + * editor convenience. + */ + + //===================================================== + public 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); + GameBase.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 + */ + public 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; + GameUtil.G_UseTargets(self, other); + self.target = savetarget; + } + + if (self.target != null) + next = GameBase.G_PickTarget(self.target); + else + next = null; + + if ((next != null) && (next.spawnflags & 1) != 0) { + Math3D.VectorCopy(next.s.origin, v); + v[2] += next.mins[2]; + v[2] -= other.mins[2]; + Math3D.VectorCopy(v, other.s.origin); + next = GameBase.G_PickTarget(next.target); + other.s.event = Defines.EV_OTHER_TELEPORT; + } + + other.goalentity = other.movetarget = next; + + if (self.wait != 0) { + other.monsterinfo.pausetime = GameBase.level.time + self.wait; + other.monsterinfo.stand.think(other); + return; + } + + if (other.movetarget == null) { + other.monsterinfo.pausetime = GameBase.level.time + 100000000; + other.monsterinfo.stand.think(other); + } else { + Math3D.VectorSubtract(other.goalentity.s.origin, + other.s.origin, v); + other.ideal_yaw = Math3D.vectoyaw(v); + } + } + }; + + /* + * 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. + */ + public 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 = GameBase + .G_PickTarget(other.target); + if (null == other.goalentity) { + GameBase.gi.dprintf(self.classname + " at " + + Lib.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 & (Defines.FL_SWIM | Defines.FL_FLY))) { + other.monsterinfo.pausetime = GameBase.level.time + 100000000; + other.monsterinfo.aiflags |= Defines.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 &= ~Defines.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; + GameUtil.G_UseTargets(self, activator); + self.target = savetarget; + } + } + }; + + /* + * 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 = GameBase.level.time + Defines.FRAMETIME; + return true; + } + }; + + /* + * 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; + + public static EntUseAdapter light_use = new EntUseAdapter() { + + public void use(edict_t self, edict_t other, edict_t activator) { + if ((self.spawnflags & START_OFF) != 0) { + GameBase.gi.configstring(Defines.CS_LIGHTS + self.style, "m"); + self.spawnflags &= ~START_OFF; + } else { + GameBase.gi.configstring(Defines.CS_LIGHTS + self.style, "a"); + self.spawnflags |= START_OFF; + } + } + }; + + /* + * 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 == Defines.SOLID_NOT) { + self.solid = Defines.SOLID_BSP; + self.svflags &= ~Defines.SVF_NOCLIENT; + GameUtil.KillBox(self); + } else { + self.solid = Defines.SOLID_NOT; + self.svflags |= Defines.SVF_NOCLIENT; + } + GameBase.gi.linkentity(self); + + if (0 == (self.spawnflags & 2)) + self.use = null; + } + }; + + /* + * 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 == Defines.DAMAGE_NO) + return; + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + self.s.origin, Globals.vec3_origin, self.dmg, 1, 0, + Defines.MOD_CRUSH); + } + }; + + static EntThinkAdapter func_object_release = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.movetype = Defines.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 = Defines.SOLID_BSP; + self.svflags &= ~Defines.SVF_NOCLIENT; + self.use = null; + GameUtil.KillBox(self); + func_object_release.think(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. + */ + public 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 + Math3D.VectorScale(self.size, 0.5f, size); + Math3D.VectorAdd(self.absmin, size, origin); + Math3D.VectorCopy(origin, self.s.origin); + + self.takedamage = Defines.DAMAGE_NO; + + if (self.dmg != 0) + GameUtil.T_RadiusDamage(self, attacker, self.dmg, null, + self.dmg + 40, Defines.MOD_EXPLOSIVE); + + Math3D.VectorSubtract(self.s.origin, inflictor.s.origin, + self.velocity); + Math3D.VectorNormalize(self.velocity); + Math3D.VectorScale(self.velocity, 150, self.velocity); + + // start chunks towards the center + Math3D.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] + Lib.crandom() * size[0]; + chunkorigin[1] = origin[1] + Lib.crandom() * size[1]; + chunkorigin[2] = origin[2] + Lib.crandom() * size[2]; + GameAI.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] + Lib.crandom() * size[0]; + chunkorigin[1] = origin[1] + Lib.crandom() * size[1]; + chunkorigin[2] = origin[2] + Lib.crandom() * size[2]; + GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", 2, + chunkorigin); + } + + GameUtil.G_UseTargets(self, attacker); + + if (self.dmg != 0) + GameAI.BecomeExplosion1(self); + else + GameUtil.G_FreeEdict(self); + } + }; + + public 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, + Globals.vec3_origin); + } + }; + + public static EntUseAdapter func_explosive_spawn = new EntUseAdapter() { + + public void use(edict_t self, edict_t other, edict_t activator) { + self.solid = Defines.SOLID_BSP; + self.svflags &= ~Defines.SVF_NOCLIENT; + self.use = null; + GameUtil.KillBox(self); + GameBase.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). + */ + + public 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; + Math3D.VectorSubtract(self.s.origin, other.s.origin, v); + M.M_walkmove(self, Math3D.vectoyaw(v), 20 * ratio + * Defines.FRAMETIME); + } + }; + + public static EntThinkAdapter barrel_explode = new EntThinkAdapter() { + public boolean think(edict_t self) { + + float[] org = { 0, 0, 0 }; + float spd; + float[] save = { 0, 0, 0 }; + + GameUtil.T_RadiusDamage(self, self.activator, self.dmg, null, + self.dmg + 40, Defines.MOD_BARREL); + + Math3D.VectorCopy(self.s.origin, save); + Math3D.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] + Lib.crandom() * self.size[0]; + org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; + org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; + GameAI.ThrowDebris(self, "models/objects/debris1/tris.md2", spd, + org); + org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; + org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; + org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; + GameAI.ThrowDebris(self, "models/objects/debris1/tris.md2", spd, + org); + + // bottom corners + spd = 1.75f * (float) self.dmg / 200.0f; + Math3D.VectorCopy(self.absmin, org); + GameAI.ThrowDebris(self, "models/objects/debris3/tris.md2", spd, + org); + Math3D.VectorCopy(self.absmin, org); + org[0] += self.size[0]; + GameAI.ThrowDebris(self, "models/objects/debris3/tris.md2", spd, + org); + Math3D.VectorCopy(self.absmin, org); + org[1] += self.size[1]; + GameAI.ThrowDebris(self, "models/objects/debris3/tris.md2", spd, + org); + Math3D.VectorCopy(self.absmin, org); + org[0] += self.size[0]; + org[1] += self.size[1]; + GameAI.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] + Lib.crandom() * self.size[0]; + org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; + org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; + GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, + org); + org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; + org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; + org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; + GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, + org); + org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; + org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; + org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; + GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, + org); + org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; + org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; + org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; + GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, + org); + org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; + org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; + org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; + GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, + org); + org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; + org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; + org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; + GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, + org); + org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; + org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; + org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; + GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, + org); + org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; + org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; + org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; + GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, + org); + + Math3D.VectorCopy(save, self.s.origin); + if (self.groundentity != null) + GameAI.BecomeExplosion2(self); + else + GameAI.BecomeExplosion1(self); + + return true; + } + }; + + public static EntDieAdapter barrel_delay = new EntDieAdapter() { + public void die(edict_t self, edict_t inflictor, edict_t attacker, + int damage, float[] point) { + + self.takedamage = Defines.DAMAGE_NO; + self.nextthink = GameBase.level.time + 2 * Defines.FRAMETIME; + self.think = barrel_explode; + self.activator = attacker; + } + }; + + // + // 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); + */ + GameUtil.G_FreeEdict(ent); + } + }; + + static EntThinkAdapter misc_blackhole_think = new EntThinkAdapter() { + public boolean think(edict_t self) { + + if (++self.s.frame < 19) + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + else { + self.s.frame = 0; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + } + return true; + } + }; + + /* + * 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 = GameBase.level.time + Defines.FRAMETIME; + else { + self.s.frame = 254; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + } + return true; + } + }; + + /* + * 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 = GameBase.level.time + Defines.FRAMETIME; + else { + self.s.frame = 208; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + } + return true; + } + }; + + /* + * 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 = GameBase.level.time + Defines.FRAMETIME; + else { + self.s.frame = 248; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + } + return true; + } + }; + + /* + * 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. + */ + + public static EntThinkAdapter commander_body_think = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (++self.s.frame < 24) + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + else + self.nextthink = 0; + + if (self.s.frame == 22) + GameBase.gi.sound(self, Defines.CHAN_BODY, GameBase.gi + .soundindex("tank/thud.wav"), 1, Defines.ATTN_NORM, 0); + return true; + } + }; + + public 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 = GameBase.level.time + Defines.FRAMETIME; + GameBase.gi.sound(self, Defines.CHAN_BODY, GameBase.gi + .soundindex("tank/pain.wav"), 1, Defines.ATTN_NORM, 0); + } + }; + + public static EntThinkAdapter commander_body_drop = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.movetype = Defines.MOVETYPE_TOSS; + self.s.origin[2] += 2; + return true; + } + }; + + /* + * 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 = GameBase.level.time + Defines.FRAMETIME; + return true; + } + }; + + /* + * 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; + + GameBase.gi.sound(self, Defines.CHAN_BODY, GameBase.gi + .soundindex("misc/udeath.wav"), 1, Defines.ATTN_NORM, 0); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", + damage, Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + } + }; + + /* + * 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 &= ~Defines.SVF_NOCLIENT; + self.use = GameFunc.train_use; + GameFunc.train_use.use(self, other, activator); + } + }; + + /* + * 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) { + GameUtil.G_UseTargets(self, self.activator); + + self.s.origin[2] = self.absmin[2] + 1; + GameUtil.T_RadiusDamage(self, self, self.dmg, null, self.dmg + 40, + Defines.MOD_BOMB); + GameAI.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 - GameBase.level.time; + if (diff < -1.0) + diff = -1.0f; + + Math3D.VectorScale(self.moveinfo.dir, 1.0f + diff, v); + v[2] = diff; + + diff = self.s.angles[2]; + Math3D.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 = Defines.SOLID_BBOX; + self.svflags &= ~Defines.SVF_NOCLIENT; + self.s.effects |= Defines.EF_ROCKET; + self.use = null; + self.movetype = Defines.MOVETYPE_TOSS; + self.prethink = misc_viper_bomb_prethink; + self.touch = misc_viper_bomb_touch; + self.activator = activator; + + EdictIterator es = null; + + es = GameBase.G_Find(es, GameBase.findByClass, "misc_viper"); + if (es != null) + viper = es.o; + + Math3D.VectorScale(viper.moveinfo.dir, viper.moveinfo.speed, + self.velocity); + + self.timestamp = GameBase.level.time; + Math3D.VectorCopy(viper.moveinfo.dir, self.moveinfo.dir); + } + }; + + /* + * 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 &= ~Defines.SVF_NOCLIENT; + self.use = GameFunc.train_use; + GameFunc.train_use.use(self, other, activator); + } + }; + + /* + * 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 = GameBase.level.time + Defines.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 = GameBase.level.time + Defines.FRAMETIME; + } + }; + + /* + * 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 = self.message.length(); + 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; + } + } + }; + + /* + * 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; + + public static EntThinkAdapter func_clock_think = new EntThinkAdapter() { + + public boolean think(edict_t self) { + if (null == self.enemy) { + + EdictIterator es = null; + + es = GameBase.G_Find(es, GameBase.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 { + Calendar c = Calendar.getInstance(); + self.message = "" + c.get(Calendar.HOUR_OF_DAY) + ":" + + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND); + + /* + * 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; + GameUtil.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 = GameBase.level.time + 1; + return true; + + } + }; + + public 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); + } + }; + + //================================================================================= + + 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 = GameBase.G_Find(null, GameBase.findByTarget, self.target).o; + + if (dest == null) { + GameBase.gi.dprintf("Couldn't find destination\n"); + return; + } + + // unlink to make sure it can't possibly interfere with KillBox + GameBase.gi.unlinkentity(other); + + Math3D.VectorCopy(dest.s.origin, other.s.origin); + Math3D.VectorCopy(dest.s.origin, other.s.old_origin); + other.s.origin[2] += 10; + + // clear the velocity and hold them in place briefly + Math3D.VectorClear(other.velocity); + other.client.ps.pmove.pm_time = 160 >> 3; // hold time + other.client.ps.pmove.pm_flags |= pmove_t.PMF_TIME_TELEPORT; + + // draw the teleport splash at source and on the player + self.owner.s.event = Defines.EV_PLAYER_TELEPORT; + other.s.event = Defines.EV_PLAYER_TELEPORT; + + // set angles + for (i = 0; i < 3; i++) { + other.client.ps.pmove.delta_angles[i] = (short) Math3D + .ANGLE2SHORT(dest.s.angles[i] + - other.client.resp.cmd_angles[i]); + } + + Math3D.VectorClear(other.s.angles); + Math3D.VectorClear(other.client.ps.viewangles); + Math3D.VectorClear(other.client.v_angle); + + // kill anything at the destination + GameUtil.KillBox(other); + + GameBase.gi.linkentity(other); + } + }; + + /* + * 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) { + GameBase.gi.setmodel(ent, "models/objects/dmspot/tris.md2"); + ent.s.skinnum = 0; + ent.solid = Defines.SOLID_BBOX; + // ent.s.effects |= EF_FLIES; + Math3D.VectorSet(ent.mins, -32, -32, -24); + Math3D.VectorSet(ent.maxs, 32, 32, -16); + GameBase.gi.linkentity(ent); + return true; + } + }; +} \ No newline at end of file diff --git a/src/jake2/game/GameMiscAdapters.java b/src/jake2/game/GameMiscAdapters.java deleted file mode 100644 index cfbe2e4..0000000 --- a/src/jake2/game/GameMiscAdapters.java +++ /dev/null @@ -1,1016 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: GameMiscAdapters.java,v 1.3 2004-07-14 15:34:24 cawe Exp $ - -package jake2.game; - -import jake2.Defines; -import jake2.Globals; -import jake2.client.M; -import jake2.util.Lib; -import jake2.util.Math3D; - -import java.util.Calendar; - -public class GameMiscAdapters -{ - - /*QUAKED func_group (0 0 0) ? - Used to group brushes together just for editor convenience. - */ - - //===================================================== - - public 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); - GameBase.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 - */ - public 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; - GameUtil.G_UseTargets(self, other); - self.target = savetarget; - } - - if (self.target != null) - next = GameBase.G_PickTarget(self.target); - else - next = null; - - if ((next != null) && (next.spawnflags & 1) != 0) - { - Math3D.VectorCopy(next.s.origin, v); - v[2] += next.mins[2]; - v[2] -= other.mins[2]; - Math3D.VectorCopy(v, other.s.origin); - next = GameBase.G_PickTarget(next.target); - other.s.event = Defines.EV_OTHER_TELEPORT; - } - - other.goalentity = other.movetarget = next; - - if (self.wait != 0) - { - other.monsterinfo.pausetime = GameBase.level.time + self.wait; - other.monsterinfo.stand.think(other); - return; - } - - if (other.movetarget == null) - { - other.monsterinfo.pausetime = GameBase.level.time + 100000000; - other.monsterinfo.stand.think(other); - } - else - { - Math3D.VectorSubtract(other.goalentity.s.origin, other.s.origin, v); - other.ideal_yaw = Math3D.vectoyaw(v); - } - } - }; - /*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. - */ - public 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 = GameBase.G_PickTarget(other.target); - if (null == other.goalentity) - { - GameBase.gi.dprintf( - self.classname + " at " + Lib.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 & (Defines.FL_SWIM | Defines.FL_FLY))) - { - other.monsterinfo.pausetime = GameBase.level.time + 100000000; - other.monsterinfo.aiflags |= Defines.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 &= ~Defines.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; - GameUtil.G_UseTargets(self, activator); - self.target = savetarget; - } - } - }; - /*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 = GameBase.level.time + Defines.FRAMETIME; - return true; - } - }; - /*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; - public static EntUseAdapter light_use = new EntUseAdapter() - { - - public void use(edict_t self, edict_t other, edict_t activator) - { - if ((self.spawnflags & START_OFF) != 0) - { - GameBase.gi.configstring(Defines.CS_LIGHTS + self.style, "m"); - self.spawnflags &= ~START_OFF; - } - else - { - GameBase.gi.configstring(Defines.CS_LIGHTS + self.style, "a"); - self.spawnflags |= START_OFF; - } - } - }; - /*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 == Defines.SOLID_NOT) - { - self.solid = Defines.SOLID_BSP; - self.svflags &= ~Defines.SVF_NOCLIENT; - GameUtil.KillBox(self); - } - else - { - self.solid = Defines.SOLID_NOT; - self.svflags |= Defines.SVF_NOCLIENT; - } - GameBase.gi.linkentity(self); - - if (0 == (self.spawnflags & 2)) - self.use = null; - } - }; - /*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 == Defines.DAMAGE_NO) - return; - GameUtil.T_Damage( - other, - self, - self, - Globals.vec3_origin, - self.s.origin, - Globals.vec3_origin, - self.dmg, - 1, - 0, - Defines.MOD_CRUSH); - } - }; - static EntThinkAdapter func_object_release = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - self.movetype = Defines.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 = Defines.SOLID_BSP; - self.svflags &= ~Defines.SVF_NOCLIENT; - self.use = null; - GameUtil.KillBox(self); - func_object_release.think(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. - */ - public 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 - Math3D.VectorScale(self.size, 0.5f, size); - Math3D.VectorAdd(self.absmin, size, origin); - Math3D.VectorCopy(origin, self.s.origin); - - self.takedamage = Defines.DAMAGE_NO; - - if (self.dmg != 0) - GameUtil.T_RadiusDamage(self, attacker, self.dmg, null, self.dmg + 40, Defines.MOD_EXPLOSIVE); - - Math3D.VectorSubtract(self.s.origin, inflictor.s.origin, self.velocity); - Math3D.VectorNormalize(self.velocity); - Math3D.VectorScale(self.velocity, 150, self.velocity); - - // start chunks towards the center - Math3D.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] + Lib.crandom() * size[0]; - chunkorigin[1] = origin[1] + Lib.crandom() * size[1]; - chunkorigin[2] = origin[2] + Lib.crandom() * size[2]; - GameAI.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] + Lib.crandom() * size[0]; - chunkorigin[1] = origin[1] + Lib.crandom() * size[1]; - chunkorigin[2] = origin[2] + Lib.crandom() * size[2]; - GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", 2, chunkorigin); - } - - GameUtil.G_UseTargets(self, attacker); - - if (self.dmg != 0) - GameAI.BecomeExplosion1(self); - else - GameUtil.G_FreeEdict(self); - } - }; - public 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, Globals.vec3_origin); - } - }; - public static EntUseAdapter func_explosive_spawn = new EntUseAdapter() - { - - public void use(edict_t self, edict_t other, edict_t activator) - { - self.solid = Defines.SOLID_BSP; - self.svflags &= ~Defines.SVF_NOCLIENT; - self.use = null; - GameUtil.KillBox(self); - GameBase.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). - */ - - public 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; - Math3D.VectorSubtract(self.s.origin, other.s.origin, v); - M.M_walkmove(self, Math3D.vectoyaw(v), 20 * ratio * Defines.FRAMETIME); - } - }; - public static EntThinkAdapter barrel_explode = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - - float[] org = { 0, 0, 0 }; - float spd; - float[] save = { 0, 0, 0 }; - - GameUtil.T_RadiusDamage(self, self.activator, self.dmg, null, self.dmg + 40, Defines.MOD_BARREL); - - Math3D.VectorCopy(self.s.origin, save); - Math3D.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] + Lib.crandom() * self.size[0]; - org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; - org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; - GameAI.ThrowDebris(self, "models/objects/debris1/tris.md2", spd, org); - org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; - org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; - org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; - GameAI.ThrowDebris(self, "models/objects/debris1/tris.md2", spd, org); - - // bottom corners - spd = 1.75f * (float) self.dmg / 200.0f; - Math3D.VectorCopy(self.absmin, org); - GameAI.ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org); - Math3D.VectorCopy(self.absmin, org); - org[0] += self.size[0]; - GameAI.ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org); - Math3D.VectorCopy(self.absmin, org); - org[1] += self.size[1]; - GameAI.ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org); - Math3D.VectorCopy(self.absmin, org); - org[0] += self.size[0]; - org[1] += self.size[1]; - GameAI.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] + Lib.crandom() * self.size[0]; - org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; - org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; - GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; - org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; - org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; - GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; - org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; - org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; - GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; - org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; - org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; - GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; - org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; - org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; - GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; - org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; - org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; - GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; - org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; - org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; - GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - org[0] = self.s.origin[0] + Lib.crandom() * self.size[0]; - org[1] = self.s.origin[1] + Lib.crandom() * self.size[1]; - org[2] = self.s.origin[2] + Lib.crandom() * self.size[2]; - GameAI.ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org); - - Math3D.VectorCopy(save, self.s.origin); - if (self.groundentity != null) - GameAI.BecomeExplosion2(self); - else - GameAI.BecomeExplosion1(self); - - return true; - } - }; - public static EntDieAdapter barrel_delay = new EntDieAdapter() - { - public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) - { - - self.takedamage = Defines.DAMAGE_NO; - self.nextthink = GameBase.level.time + 2 * Defines.FRAMETIME; - self.think = barrel_explode; - self.activator = attacker; - } - }; - // - // 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); - */ - GameUtil.G_FreeEdict(ent); - } - }; - static EntThinkAdapter misc_blackhole_think = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - - if (++self.s.frame < 19) - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - else - { - self.s.frame = 0; - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - } - return true; - } - }; - /*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 = GameBase.level.time + Defines.FRAMETIME; - else - { - self.s.frame = 254; - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - } - return true; - } - }; - /*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 = GameBase.level.time + Defines.FRAMETIME; - else - { - self.s.frame = 208; - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - } - return true; - } - }; - /*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 = GameBase.level.time + Defines.FRAMETIME; - else - { - self.s.frame = 248; - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - } - return true; - } - }; - /*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. - */ - - public static EntThinkAdapter commander_body_think = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if (++self.s.frame < 24) - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - else - self.nextthink = 0; - - if (self.s.frame == 22) - GameBase.gi.sound(self, Defines.CHAN_BODY, GameBase.gi.soundindex("tank/thud.wav"), 1, Defines.ATTN_NORM, 0); - return true; - } - }; - public 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 = GameBase.level.time + Defines.FRAMETIME; - GameBase.gi.sound(self, Defines.CHAN_BODY, GameBase.gi.soundindex("tank/pain.wav"), 1, Defines.ATTN_NORM, 0); - } - }; - public static EntThinkAdapter commander_body_drop = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - self.movetype = Defines.MOVETYPE_TOSS; - self.s.origin[2] += 2; - return true; - } - }; - /*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 = GameBase.level.time + Defines.FRAMETIME; - return true; - } - }; - /*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; - - GameBase.gi.sound(self, Defines.CHAN_BODY, GameBase.gi.soundindex("misc/udeath.wav"), 1, Defines.ATTN_NORM, 0); - for (n = 0; n < 4; n++) - GameAI.ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, Defines.GIB_ORGANIC); - GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, Defines.GIB_ORGANIC); - } - }; - /*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 &= ~Defines.SVF_NOCLIENT; - self.use = GameFuncAdapters.train_use; - GameFuncAdapters.train_use.use(self, other, activator); - } - }; - /*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) - { - GameUtil.G_UseTargets(self, self.activator); - - self.s.origin[2] = self.absmin[2] + 1; - GameUtil.T_RadiusDamage(self, self, self.dmg, null, self.dmg + 40, Defines.MOD_BOMB); - GameAI.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 - GameBase.level.time; - if (diff < -1.0) - diff = -1.0f; - - Math3D.VectorScale(self.moveinfo.dir, 1.0f + diff, v); - v[2] = diff; - - diff = self.s.angles[2]; - Math3D.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 = Defines.SOLID_BBOX; - self.svflags &= ~Defines.SVF_NOCLIENT; - self.s.effects |= Defines.EF_ROCKET; - self.use = null; - self.movetype = Defines.MOVETYPE_TOSS; - self.prethink = misc_viper_bomb_prethink; - self.touch = misc_viper_bomb_touch; - self.activator = activator; - - EdictIterator es = null; - - es = GameBase.G_Find(es, GameBase.findByClass, "misc_viper"); - if (es != null) - viper = es.o; - - Math3D.VectorScale(viper.moveinfo.dir, viper.moveinfo.speed, self.velocity); - - self.timestamp = GameBase.level.time; - Math3D.VectorCopy(viper.moveinfo.dir, self.moveinfo.dir); - } - }; - /*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 &= ~Defines.SVF_NOCLIENT; - self.use = GameFuncAdapters.train_use; - GameFuncAdapters.train_use.use(self, other, activator); - } - }; - /*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 = GameBase.level.time + Defines.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 = GameBase.level.time + Defines.FRAMETIME; - } - }; - /*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 = self.message.length(); - 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; - } - } - }; - /*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; - public static EntThinkAdapter func_clock_think = new EntThinkAdapter() - { - - public boolean think(edict_t self) - { - if (null == self.enemy) - { - - EdictIterator es = null; - - es = GameBase.G_Find(es, GameBase.findByTarget, self.target); - if (es != null) - self.enemy = es.o; - if (self.enemy == null) - return true; - } - - if ((self.spawnflags & 1) != 0) - { - GameMisc.func_clock_format_countdown(self); - self.health++; - } - else if ((self.spawnflags & 2) != 0) - { - GameMisc.func_clock_format_countdown(self); - self.health--; - } - else - { - Calendar c = Calendar.getInstance(); - self.message = "" + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND); - - /* - 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; - GameUtil.G_UseTargets(self, self.activator); - self.target = savetarget; - self.message = savemessage; - } - - if (0 == (self.spawnflags & 8)) - return true; - - GameMisc.func_clock_reset(self); - - if ((self.spawnflags & 4) != 0) - return true; - } - - self.nextthink = GameBase.level.time + 1; - return true; - - } - }; - public 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); - } - }; - //================================================================================= - - 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 = GameBase.G_Find(null, GameBase.findByTarget, self.target).o; - - if (dest == null) - { - GameBase.gi.dprintf("Couldn't find destination\n"); - return; - } - - // unlink to make sure it can't possibly interfere with KillBox - GameBase.gi.unlinkentity(other); - - Math3D.VectorCopy(dest.s.origin, other.s.origin); - Math3D.VectorCopy(dest.s.origin, other.s.old_origin); - other.s.origin[2] += 10; - - // clear the velocity and hold them in place briefly - Math3D.VectorClear(other.velocity); - other.client.ps.pmove.pm_time = 160 >> 3; // hold time - other.client.ps.pmove.pm_flags |= Defines.PMF_TIME_TELEPORT; - - // draw the teleport splash at source and on the player - self.owner.s.event = Defines.EV_PLAYER_TELEPORT; - other.s.event = Defines.EV_PLAYER_TELEPORT; - - // set angles - for (i = 0; i < 3; i++) - { - other.client.ps.pmove.delta_angles[i] = (short) Math3D.ANGLE2SHORT(dest.s.angles[i] - other.client.resp.cmd_angles[i]); - } - - Math3D.VectorClear(other.s.angles); - Math3D.VectorClear(other.client.ps.viewangles); - Math3D.VectorClear(other.client.v_angle); - - // kill anything at the destination - GameUtil.KillBox(other); - - GameBase.gi.linkentity(other); - } - }; - /*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) - { - GameBase.gi.setmodel(ent, "models/objects/dmspot/tris.md2"); - ent.s.skinnum = 0; - ent.solid = Defines.SOLID_BBOX; - // ent.s.effects |= EF_FLIES; - Math3D.VectorSet(ent.mins, -32, -32, -24); - Math3D.VectorSet(ent.maxs, 32, 32, -16); - GameBase.gi.linkentity(ent); - return true; - } - }; -} diff --git a/src/jake2/game/GamePWeapon.java b/src/jake2/game/GamePWeapon.java index 0020633..ca183e1 100644 --- a/src/jake2/game/GamePWeapon.java +++ b/src/jake2/game/GamePWeapon.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 16.11.2003 by RST. -// $Id: GamePWeapon.java,v 1.5 2004-09-12 19:54:29 hzi Exp $ - +// $Id: GamePWeapon.java,v 1.6 2004-09-22 19:22:03 salomo Exp $ package jake2.game; import jake2.Defines; @@ -30,1374 +29,1379 @@ import jake2.util.Math3D; public class GamePWeapon { - public static EntThinkAdapter Weapon_Grenade= new EntThinkAdapter() { - - public boolean think(edict_t ent) { - if ((ent.client.newweapon != null) && (ent.client.weaponstate == Defines.WEAPON_READY)) { - GamePWeapon.ChangeWeapon(ent); - return true; - } - - if (ent.client.weaponstate == Defines.WEAPON_ACTIVATING) { - ent.client.weaponstate= Defines.WEAPON_READY; - ent.client.ps.gunframe= 16; - return true; - } - - if (ent.client.weaponstate == Defines.WEAPON_READY) { - if (((ent.client.latched_buttons | ent.client.buttons) & Defines.BUTTON_ATTACK) != 0) { - ent.client.latched_buttons &= ~Defines.BUTTON_ATTACK; - if (0 != ent.client.pers.inventory[ent.client.ammo_index]) { - ent.client.ps.gunframe= 1; - ent.client.weaponstate= Defines.WEAPON_FIRING; - ent.client.grenade_time= 0; - } else { - if (GameBase.level.time >= ent.pain_debounce_time) { - GameBase.gi.sound( - ent, - Defines.CHAN_VOICE, - GameBase.gi.soundindex("weapons/noammo.wav"), - 1, - Defines.ATTN_NORM, - 0); - ent.pain_debounce_time= GameBase.level.time + 1; - } - GamePWeapon.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 == Defines.WEAPON_FIRING) { - if (ent.client.ps.gunframe == 5) - GameBase.gi.sound( - ent, - Defines.CHAN_WEAPON, - GameBase.gi.soundindex("weapons/hgrena1b.wav"), - 1, - Defines.ATTN_NORM, - 0); - - if (ent.client.ps.gunframe == 11) { - if (0 == ent.client.grenade_time) { - ent.client.grenade_time= GameBase.level.time + Defines.GRENADE_TIMER + 0.2f; - ent.client.weapon_sound= GameBase.gi.soundindex("weapons/hgrenc1b.wav"); - } - - // they waited too long, detonate it in their hand - if (!ent.client.grenade_blew_up && GameBase.level.time >= ent.client.grenade_time) { - ent.client.weapon_sound= 0; - GamePWeapon.weapon_grenade_fire(ent, true); - ent.client.grenade_blew_up= true; - } - - if ((ent.client.buttons & Defines.BUTTON_ATTACK) != 0) - return true; - - if (ent.client.grenade_blew_up) { - if (GameBase.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; - GamePWeapon.weapon_grenade_fire(ent, false); - } - - if ((ent.client.ps.gunframe == 15) && (GameBase.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= Defines.WEAPON_READY; - } - } - return true; - } - }; - /* - ====================================================================== - - GRENADE LAUNCHER - - ====================================================================== - */ - - public 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 (GamePWeapon.is_quad) - damage *= 4; - - Math3D.VectorSet(offset, 8, 8, ent.viewheight - 8); - Math3D.AngleVectors(ent.client.v_angle, forward, right, null); - GamePWeapon.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); - - GameBase.gi.WriteByte(Defines.svc_muzzleflash); - GameBase.gi.WriteShort(ent.index); - GameBase.gi.WriteByte(Defines.MZ_GRENADE | GamePWeapon.is_silenced); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); - - ent.client.ps.gunframe++; - - GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); - - if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) - ent.client.pers.inventory[ent.client.ammo_index]--; - - return true; - } - }; - public static EntThinkAdapter Weapon_GrenadeLauncher= new EntThinkAdapter() { - - public boolean think(edict_t ent) { - - int pause_frames[]= { 34, 51, 59, 0 }; - int fire_frames[]= { 6, 0 }; - - GamePWeapon.Weapon_Generic( - ent, - 5, - 16, - 59, - 64, - pause_frames, - fire_frames, - weapon_grenadelauncher_fire); - return true; - } - }; - /* - ====================================================================== - - ROCKET - - ====================================================================== - */ - - public 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 (GamePWeapon.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); - GamePWeapon.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 - GameBase.gi.WriteByte(Defines.svc_muzzleflash); - - GameBase.gi.WriteShort(ent.index); - GameBase.gi.WriteByte(Defines.MZ_ROCKET | GamePWeapon.is_silenced); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); - - ent.client.ps.gunframe++; - - GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); - - if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) - ent.client.pers.inventory[ent.client.ammo_index]--; - - return true; - } - }; - public 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 }; - - GamePWeapon.Weapon_Generic( - ent, - 4, - 12, - 50, - 54, - pause_frames, - fire_frames, - Weapon_RocketLauncher_Fire); - return true; - } - }; - public static EntThinkAdapter Weapon_Blaster_Fire= new EntThinkAdapter() { - - public boolean think(edict_t ent) { - - int damage; - - if (GameBase.deathmatch.value != 0) - damage= 15; - else - damage= 10; - GamePWeapon.Blaster_Fire(ent, Globals.vec3_origin, damage, false, Defines.EF_BLASTER); - ent.client.ps.gunframe++; - return true; - } - }; - public static EntThinkAdapter Weapon_Blaster= new EntThinkAdapter() { - - public boolean think(edict_t ent) { - - int pause_frames[]= { 19, 32, 0 }; - int fire_frames[]= { 5, 0 }; - - GamePWeapon.Weapon_Generic(ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire); - return true; - } - }; - public 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= GameBase.gi.soundindex("weapons/hyprbl1a.wav"); - - if (0 == (ent.client.buttons & Defines.BUTTON_ATTACK)) { - ent.client.ps.gunframe++; - } else { - if (0 == ent.client.pers.inventory[ent.client.ammo_index]) { - if (GameBase.level.time >= ent.pain_debounce_time) { - GameBase.gi.sound( - ent, - Defines.CHAN_VOICE, - GameBase.gi.soundindex("weapons/noammo.wav"), - 1, - Defines.ATTN_NORM, - 0); - ent.pain_debounce_time= GameBase.level.time + 1; - } - GamePWeapon.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= Defines.EF_HYPERBLASTER; - else - effect= 0; - if (GameBase.deathmatch.value != 0) - damage= 15; - else - damage= 20; - GamePWeapon.Blaster_Fire(ent, offset, damage, true, effect); - if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) - ent.client.pers.inventory[ent.client.ammo_index]--; - - ent.client.anim_priority= Defines.ANIM_ATTACK; - if ((ent.client.ps.pmove.pm_flags & Defines.PMF_DUCKED) != 0) { - ent.s.frame= M_Player.FRAME_crattak1 - 1; - ent.client.anim_end= M_Player.FRAME_crattak9; - } else { - ent.s.frame= M_Player.FRAME_attack1 - 1; - ent.client.anim_end= M_Player.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) { - GameBase.gi.sound(ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("weapons/hyprbd1a.wav"), 1, Defines.ATTN_NORM, 0); - ent.client.weapon_sound= 0; - } - - return true; - - } - }; - public 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 }; - - GamePWeapon.Weapon_Generic(ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire); - return true; - } - }; - public static EntThinkAdapter Weapon_Machinegun= new EntThinkAdapter() { - public boolean think(edict_t ent) { - - int pause_frames[]= { 23, 45, 0 }; - int fire_frames[]= { 4, 5, 0 }; - - GamePWeapon.Weapon_Generic(ent, 3, 5, 45, 49, pause_frames, fire_frames, GamePWeapon.Machinegun_Fire); - return true; - } - }; - public 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 }; - - GamePWeapon.Weapon_Generic(ent, 4, 31, 61, 64, pause_frames, fire_frames, GamePWeapon.Chaingun_Fire); - return true; - } - }; - /* - ====================================================================== - - SHOTGUN / SUPERSHOTGUN - - ====================================================================== - */ - - public 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); - GamePWeapon.P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start); - - if (GamePWeapon.is_quad) { - damage *= 4; - kick *= 4; - } - - if (GameBase.deathmatch.value != 0) - Fire.fire_shotgun( - ent, - start, - forward, - damage, - kick, - 500, - 500, - Defines.DEFAULT_DEATHMATCH_SHOTGUN_COUNT, - Defines.MOD_SHOTGUN); - else - Fire.fire_shotgun( - ent, - start, - forward, - damage, - kick, - 500, - 500, - Defines.DEFAULT_SHOTGUN_COUNT, - Defines.MOD_SHOTGUN); - - // send muzzle flash - GameBase.gi.WriteByte(Defines.svc_muzzleflash); - - GameBase.gi.WriteShort(ent.index); - GameBase.gi.WriteByte(Defines.MZ_SHOTGUN | GamePWeapon.is_silenced); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); - - ent.client.ps.gunframe++; - GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); - - if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) - ent.client.pers.inventory[ent.client.ammo_index]--; - - return true; - } - }; - public 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 }; - - GamePWeapon.Weapon_Generic(ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire); - return true; - } - }; - public 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); - GamePWeapon.P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start); - - if (GamePWeapon.is_quad) { - damage *= 4; - kick *= 4; - } - - v[Defines.PITCH]= ent.client.v_angle[Defines.PITCH]; - v[Defines.YAW]= ent.client.v_angle[Defines.YAW] - 5; - v[Defines.ROLL]= ent.client.v_angle[Defines.ROLL]; - Math3D.AngleVectors(v, forward, null, null); - Fire.fire_shotgun( - ent, - start, - forward, - damage, - kick, - Defines.DEFAULT_SHOTGUN_HSPREAD, - Defines.DEFAULT_SHOTGUN_VSPREAD, - Defines.DEFAULT_SSHOTGUN_COUNT / 2, - Defines.MOD_SSHOTGUN); - v[Defines.YAW]= ent.client.v_angle[Defines.YAW] + 5; - Math3D.AngleVectors(v, forward, null, null); - Fire.fire_shotgun( - ent, - start, - forward, - damage, - kick, - Defines.DEFAULT_SHOTGUN_HSPREAD, - Defines.DEFAULT_SHOTGUN_VSPREAD, - Defines.DEFAULT_SSHOTGUN_COUNT / 2, - Defines.MOD_SSHOTGUN); - - // send muzzle flash - GameBase.gi.WriteByte(Defines.svc_muzzleflash); - - GameBase.gi.WriteShort(ent.index); - GameBase.gi.WriteByte(Defines.MZ_SSHOTGUN | GamePWeapon.is_silenced); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); - - ent.client.ps.gunframe++; - GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); - - if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) - ent.client.pers.inventory[ent.client.ammo_index] -= 2; - - return true; - } - }; - public static EntThinkAdapter Weapon_SuperShotgun= new EntThinkAdapter() { - public boolean think(edict_t ent) { - - int pause_frames[]= { 29, 42, 57, 0 }; - int fire_frames[]= { 7, 0 }; - - GamePWeapon.Weapon_Generic(ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire); - return true; - } - }; - /* - ====================================================================== - - RAILGUN - - ====================================================================== - */ - public 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 (GameBase.deathmatch.value != 0) { // normal damage is too extreme in dm - damage= 100; - kick= 200; - } else { - damage= 150; - kick= 250; - } - - if (GamePWeapon.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); - GamePWeapon.P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start); - Fire.fire_rail(ent, start, forward, damage, kick); - - // send muzzle flash - GameBase.gi.WriteByte(Defines.svc_muzzleflash); - - GameBase.gi.WriteShort(ent.index); - GameBase.gi.WriteByte(Defines.MZ_RAILGUN | GamePWeapon.is_silenced); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); - - ent.client.ps.gunframe++; - GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); - - if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) - ent.client.pers.inventory[ent.client.ammo_index]--; - - return true; - } - }; - public static EntThinkAdapter Weapon_Railgun= new EntThinkAdapter() { - - public boolean think(edict_t ent) { - - int pause_frames[]= { 56, 0 }; - int fire_frames[]= { 4, 0 }; - GamePWeapon.Weapon_Generic(ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire); - return true; - } - }; - /* - ====================================================================== - - BFG10K - - ====================================================================== - */ - - public 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 (GameBase.deathmatch.value != 0) - damage= 200; - else - damage= 500; - - if (ent.client.ps.gunframe == 9) { - // send muzzle flash - GameBase.gi.WriteByte(Defines.svc_muzzleflash); - - GameBase.gi.WriteShort(ent.index); - GameBase.gi.WriteByte(Defines.MZ_BFG | GamePWeapon.is_silenced); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); - - ent.client.ps.gunframe++; - - GameWeapon.PlayerNoise(ent, start, Defines.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 (GamePWeapon.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= GameBase.level.time + Defines.DAMAGE_TIME; - - Math3D.VectorSet(offset, 8, 8, ent.viewheight - 8); - GamePWeapon.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++; - - GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); - - if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) - ent.client.pers.inventory[ent.client.ammo_index] -= 50; - - return true; - } - }; - public static EntThinkAdapter Weapon_BFG= new EntThinkAdapter() { - public boolean think(edict_t ent) { - - GamePWeapon.Weapon_Generic(ent, 8, 32, 55, 58, GamePWeapon.pause_frames, GamePWeapon.fire_frames, weapon_bfg_fire); - return true; - } - }; - public static boolean is_quad; - public static byte is_silenced; - public static EntInteractAdapter Pickup_Weapon= new EntInteractAdapter() { - public boolean interact(edict_t ent, edict_t other) { - int index; - gitem_t ammo; - - index= GameUtil.ITEM_INDEX(ent.item); - - if ((((int) (GameBase.dmflags.value) & Defines.DF_WEAPONS_STAY) != 0 || GameBase.coop.value != 0) - && 0 != other.client.pers.inventory[index]) { - if (0 == (ent.spawnflags & (Defines.DROPPED_ITEM | Defines.DROPPED_PLAYER_ITEM))) - return false; // leave the weapon for others to pickup - } - - other.client.pers.inventory[index]++; - - if (0 == (ent.spawnflags & Defines.DROPPED_ITEM)) { - // give them some ammo with it - ammo= GameUtil.FindItem(ent.item.ammo); - if (((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO) != 0) - GameAI.Add_Ammo(other, ammo, 1000); - else - GameAI.Add_Ammo(other, ammo, ammo.quantity); - - if (0 == (ent.spawnflags & Defines.DROPPED_PLAYER_ITEM)) { - if (GameBase.deathmatch.value != 0) { - if (((int) (GameBase.dmflags.value) & Defines.DF_WEAPONS_STAY) != 0) - ent.flags |= Defines.FL_RESPAWN; - else - GameUtil.SetRespawn(ent, 30); - } - if (GameBase.coop.value != 0) - ent.flags |= Defines.FL_RESPAWN; - } - } - - if (other.client.pers.weapon != ent.item - && (other.client.pers.inventory[index] == 1) - && (0 == GameBase.deathmatch.value || other.client.pers.weapon == GameUtil.FindItem("blaster"))) - other.client.newweapon= ent.item; - - return true; - } - }; - /* - ================ - Use_Weapon - - Make the weapon ready if there is ammo - ================ - */ - public 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 == GameBase.g_select_empty.value && 0 == (item.flags & Defines.IT_AMMO)) { - ammo_item= GameUtil.FindItem(item.ammo); - ammo_index= GameUtil.ITEM_INDEX(ammo_item); - - if (0 == ent.client.pers.inventory[ammo_index]) { - GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "No " + ammo_item.pickup_name + " for " + item.pickup_name + ".\n"); - return; - } - - if (ent.client.pers.inventory[ammo_index] < item.quantity) { - GameBase.gi.cprintf( - ent, - Defines.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 - ================ - */ - - public static ItemDropAdapter Drop_Weapon= new ItemDropAdapter() { - public void drop(edict_t ent, gitem_t item) { - int index; - - if (0 != ((int) (GameBase.dmflags.value) & Defines.DF_WEAPONS_STAY)) - return; - - index= GameUtil.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)) { - GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "Can't drop current weapon\n"); - return; - } - - GameUtil.Drop_Item(ent, item); - ent.client.pers.inventory[index]--; - } - }; - /* - ====================================================================== - - MACHINEGUN / CHAINGUN - - ====================================================================== - */ - - public 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 & Defines.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 (GameBase.level.time >= ent.pain_debounce_time) { - GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi.soundindex("weapons/noammo.wav"), 1, Defines.ATTN_NORM, 0); - ent.pain_debounce_time= GameBase.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 == GameBase.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, - Defines.DEFAULT_BULLET_HSPREAD, - Defines.DEFAULT_BULLET_VSPREAD, - Defines.MOD_MACHINEGUN); - - GameBase.gi.WriteByte(Defines.svc_muzzleflash); - - GameBase.gi.WriteShort(ent.index); - GameBase.gi.WriteByte(Defines.MZ_MACHINEGUN | is_silenced); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); - - GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); - - if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) - ent.client.pers.inventory[ent.client.ammo_index]--; - - ent.client.anim_priority= Defines.ANIM_ATTACK; - if ((ent.client.ps.pmove.pm_flags & Defines.PMF_DUCKED) != 0) { - ent.s.frame= M_Player.FRAME_crattak1 - (int) (Lib.random() + 0.25); - ent.client.anim_end= M_Player.FRAME_crattak9; - } else { - ent.s.frame= M_Player.FRAME_attack1 - (int) (Lib.random() + 0.25); - ent.client.anim_end= M_Player.FRAME_attack8; - } - return true; - } - }; - public 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 (GameBase.deathmatch.value != 0) - damage= 6; - else - damage= 8; - - if (ent.client.ps.gunframe == 5) - GameBase.gi.sound(ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("weapons/chngnu1a.wav"), 1, Defines.ATTN_IDLE, 0); - - if ((ent.client.ps.gunframe == 14) && 0 == (ent.client.buttons & Defines.BUTTON_ATTACK)) { - ent.client.ps.gunframe= 32; - ent.client.weapon_sound= 0; - return true; - } else if ( - (ent.client.ps.gunframe == 21) - && (ent.client.buttons & Defines.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; - GameBase.gi.sound(ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("weapons/chngnd1a.wav"), 1, Defines.ATTN_IDLE, 0); - } else { - ent.client.weapon_sound= GameBase.gi.soundindex("weapons/chngnl1a.wav"); - } - - ent.client.anim_priority= Defines.ANIM_ATTACK; - if ((ent.client.ps.pmove.pm_flags & Defines.PMF_DUCKED) != 0) { - ent.s.frame= M_Player.FRAME_crattak1 - (ent.client.ps.gunframe & 1); - ent.client.anim_end= M_Player.FRAME_crattak9; - } else { - ent.s.frame= M_Player.FRAME_attack1 - (ent.client.ps.gunframe & 1); - ent.client.anim_end= M_Player.FRAME_attack8; - } - - if (ent.client.ps.gunframe <= 9) - shots= 1; - else if (ent.client.ps.gunframe <= 14) { - if ((ent.client.buttons & Defines.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 (GameBase.level.time >= ent.pain_debounce_time) { - GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi.soundindex("weapons/noammo.wav"), 1, Defines.ATTN_NORM, 0); - ent.pain_debounce_time= GameBase.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, - Defines.DEFAULT_BULLET_HSPREAD, - Defines.DEFAULT_BULLET_VSPREAD, - Defines.MOD_CHAINGUN); - } - - // send muzzle flash - GameBase.gi.WriteByte(Defines.svc_muzzleflash); - - GameBase.gi.WriteShort(ent.index); - GameBase.gi.WriteByte((Defines.MZ_CHAINGUN1 + shots - 1) | is_silenced); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); - - GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); - - if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) - ent.client.pers.inventory[ent.client.ammo_index] -= shots; - - return true; - } - }; - public static int pause_frames[]= { 39, 45, 50, 55, 0 }; - public static int fire_frames[]= { 9, 17, 0 }; - public 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 == Defines.LEFT_HANDED) - _distance[1] *= -1; - else if (client.pers.hand == Defines.CENTER_HANDED) - _distance[1]= 0; - Math3D.G_ProjectSource(point, _distance, forward, right, result); - } - /* - =============== - ChangeWeapon - - The old weapon has been dropped all the way, so make the new one - current - =============== - */ - public static void ChangeWeapon(edict_t ent) { - int i; - - if (ent.client.grenade_time != 0) { - ent.client.grenade_time= GameBase.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.index - 1) | i; - } - - if (ent.client.pers.weapon != null && ent.client.pers.weapon.ammo != null) - ent.client.ammo_index= GameUtil.ITEM_INDEX(GameUtil.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= Defines.WEAPON_ACTIVATING; - ent.client.ps.gunframe= 0; - ent.client.ps.gunindex= GameBase.gi.modelindex(ent.client.pers.weapon.view_model); - - ent.client.anim_priority= Defines.ANIM_PAIN; - if ((ent.client.ps.pmove.pm_flags & Defines.PMF_DUCKED) != 0) { - ent.s.frame= M_Player.FRAME_crpain1; - ent.client.anim_end= M_Player.FRAME_crpain4; - } else { - ent.s.frame= M_Player.FRAME_pain301; - ent.client.anim_end= M_Player.FRAME_pain304; - - } - } - /* - ================= - NoAmmoWeaponChange - ================= - */ - public static void NoAmmoWeaponChange(edict_t ent) { - if (0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("slugs"))] - && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("railgun"))]) { - ent.client.newweapon= GameUtil.FindItem("railgun"); - return; - } - if (0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("cells"))] - && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("hyperblaster"))]) { - ent.client.newweapon= GameUtil.FindItem("hyperblaster"); - return; - } - if (0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("bullets"))] - && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("chaingun"))]) { - ent.client.newweapon= GameUtil.FindItem("chaingun"); - return; - } - if (0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("bullets"))] - && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("machinegun"))]) { - ent.client.newweapon= GameUtil.FindItem("machinegun"); - return; - } - if (ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("shells"))] > 1 - && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("super shotgun"))]) { - ent.client.newweapon= GameUtil.FindItem("super shotgun"); - return; - } - if (0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("shells"))] - && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil.FindItem("shotgun"))]) { - ent.client.newweapon= GameUtil.FindItem("shotgun"); - return; - } - ent.client.newweapon= GameUtil.FindItem("blaster"); - } - /* - ================= - Think_Weapon - - Called by ClientBeginServerFrame and ClientThink - ================= - */ - public 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 > GameBase.level.framenum); - if (ent.client.silencer_shots != 0) - is_silenced= (byte) Defines.MZ_SILENCED; - else - is_silenced= 0; - ent.client.pers.weapon.weaponthink.think(ent); - } - } - /* - ================ - Weapon_Generic - - A generic function to handle the basics of weapon thinking - ================ - */ - - public 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 == Defines.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= Defines.ANIM_REVERSE; - if ((ent.client.ps.pmove.pm_flags & Defines.PMF_DUCKED) != 0) { - ent.s.frame= M_Player.FRAME_crpain4 + 1; - ent.client.anim_end= M_Player.FRAME_crpain1; - } else { - ent.s.frame= M_Player.FRAME_pain304 + 1; - ent.client.anim_end= M_Player.FRAME_pain301; - - } - } - - ent.client.ps.gunframe++; - return; - } - - if (ent.client.weaponstate == Defines.WEAPON_ACTIVATING) { - if (ent.client.ps.gunframe == FRAME_ACTIVATE_LAST) { - ent.client.weaponstate= Defines.WEAPON_READY; - ent.client.ps.gunframe= FRAME_IDLE_FIRST; - return; - } - - ent.client.ps.gunframe++; - return; - } - - if ((ent.client.newweapon != null) && (ent.client.weaponstate != Defines.WEAPON_FIRING)) { - ent.client.weaponstate= Defines.WEAPON_DROPPING; - ent.client.ps.gunframe= FRAME_DEACTIVATE_FIRST; - - if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4) { - ent.client.anim_priority= Defines.ANIM_REVERSE; - if ((ent.client.ps.pmove.pm_flags & Defines.PMF_DUCKED) != 0) { - ent.s.frame= M_Player.FRAME_crpain4 + 1; - ent.client.anim_end= M_Player.FRAME_crpain1; - } else { - ent.s.frame= M_Player.FRAME_pain304 + 1; - ent.client.anim_end= M_Player.FRAME_pain301; - - } - } - return; - } - - if (ent.client.weaponstate == Defines.WEAPON_READY) { - if (((ent.client.latched_buttons | ent.client.buttons) & Defines.BUTTON_ATTACK) != 0) { - ent.client.latched_buttons &= ~Defines.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= Defines.WEAPON_FIRING; - - // start the animation - ent.client.anim_priority= Defines.ANIM_ATTACK; - if ((ent.client.ps.pmove.pm_flags & Defines.PMF_DUCKED) != 0) { - ent.s.frame= M_Player.FRAME_crattak1 - 1; - ent.client.anim_end= M_Player.FRAME_crattak9; - } else { - ent.s.frame= M_Player.FRAME_attack1 - 1; - ent.client.anim_end= M_Player.FRAME_attack8; - } - } else { - if (GameBase.level.time >= ent.pain_debounce_time) { - GameBase.gi.sound( - ent, - Defines.CHAN_VOICE, - GameBase.gi.soundindex("weapons/noammo.wav"), - 1, - Defines.ATTN_NORM, - 0); - ent.pain_debounce_time= GameBase.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 == Defines.WEAPON_FIRING) { - for (n= 0; fire_frames[n] != 0; n++) { - if (ent.client.ps.gunframe == fire_frames[n]) { - if (ent.client.quad_framenum > GameBase.level.framenum) - GameBase.gi.sound( - ent, - Defines.CHAN_ITEM, - GameBase.gi.soundindex("items/damage3.wav"), - 1, - Defines.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= Defines.WEAPON_READY; - } - } - /* - ====================================================================== - - GRENADE - - ====================================================================== - */ - - public 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 - GameBase.level.time; - speed= - (int) (Defines.GRENADE_MINSPEED - + (Defines.GRENADE_TIMER - timer) * ((Defines.GRENADE_MAXSPEED - Defines.GRENADE_MINSPEED) / Defines.GRENADE_TIMER)); - Fire.fire_grenade2(ent, start, forward, damage, speed, timer, radius, held); - - if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) - ent.client.pers.inventory[ent.client.ammo_index]--; - - ent.client.grenade_time= GameBase.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 & Defines.PMF_DUCKED) != 0) { - ent.client.anim_priority= Defines.ANIM_ATTACK; - ent.s.frame= M_Player.FRAME_crattak1 - 1; - ent.client.anim_end= M_Player.FRAME_crattak3; - } else { - ent.client.anim_priority= Defines.ANIM_REVERSE; - ent.s.frame= M_Player.FRAME_wave08; - ent.client.anim_end= M_Player.FRAME_wave01; - } - } - /* - ====================================================================== - - BLASTER / HYPERBLASTER - - ====================================================================== - */ - - public 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 - GameBase.gi.WriteByte(Defines.svc_muzzleflash); - GameBase.gi.WriteShort(ent.index); - if (hyper) - GameBase.gi.WriteByte(Defines.MZ_HYPERBLASTER | is_silenced); - else - GameBase.gi.WriteByte(Defines.MZ_BLASTER | is_silenced); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); - - GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); - } -} + public static EntThinkAdapter Weapon_Grenade = new EntThinkAdapter() { + + public boolean think(edict_t ent) { + if ((ent.client.newweapon != null) + && (ent.client.weaponstate == Defines.WEAPON_READY)) { + ChangeWeapon(ent); + return true; + } + + if (ent.client.weaponstate == Defines.WEAPON_ACTIVATING) { + ent.client.weaponstate = Defines.WEAPON_READY; + ent.client.ps.gunframe = 16; + return true; + } + + if (ent.client.weaponstate == Defines.WEAPON_READY) { + if (((ent.client.latched_buttons | ent.client.buttons) & Defines.BUTTON_ATTACK) != 0) { + ent.client.latched_buttons &= ~Defines.BUTTON_ATTACK; + if (0 != ent.client.pers.inventory[ent.client.ammo_index]) { + ent.client.ps.gunframe = 1; + ent.client.weaponstate = Defines.WEAPON_FIRING; + ent.client.grenade_time = 0; + } else { + if (GameBase.level.time >= ent.pain_debounce_time) { + GameBase.gi.sound(ent, Defines.CHAN_VOICE, + GameBase.gi + .soundindex("weapons/noammo.wav"), + 1, Defines.ATTN_NORM, 0); + ent.pain_debounce_time = GameBase.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 == Defines.WEAPON_FIRING) { + if (ent.client.ps.gunframe == 5) + GameBase.gi.sound(ent, Defines.CHAN_WEAPON, GameBase.gi + .soundindex("weapons/hgrena1b.wav"), 1, + Defines.ATTN_NORM, 0); + + if (ent.client.ps.gunframe == 11) { + if (0 == ent.client.grenade_time) { + ent.client.grenade_time = GameBase.level.time + + Defines.GRENADE_TIMER + 0.2f; + ent.client.weapon_sound = GameBase.gi + .soundindex("weapons/hgrenc1b.wav"); + } + + // they waited too long, detonate it in their hand + if (!ent.client.grenade_blew_up + && GameBase.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 & Defines.BUTTON_ATTACK) != 0) + return true; + + if (ent.client.grenade_blew_up) { + if (GameBase.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) + && (GameBase.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 = Defines.WEAPON_READY; + } + } + return true; + } + }; + + /* + * ====================================================================== + * + * GRENADE LAUNCHER + * + * ====================================================================== + */ + + public 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); + + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte(Defines.MZ_GRENADE | is_silenced); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + ent.client.ps.gunframe++; + + GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); + + if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) + ent.client.pers.inventory[ent.client.ammo_index]--; + + return true; + } + }; + + public 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 + * + * ====================================================================== + */ + + public 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 + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte(Defines.MZ_ROCKET | is_silenced); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + ent.client.ps.gunframe++; + + GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); + + if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) + ent.client.pers.inventory[ent.client.ammo_index]--; + + return true; + } + }; + + public 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; + } + }; + + public static EntThinkAdapter Weapon_Blaster_Fire = new EntThinkAdapter() { + + public boolean think(edict_t ent) { + + int damage; + + if (GameBase.deathmatch.value != 0) + damage = 15; + else + damage = 10; + Blaster_Fire(ent, Globals.vec3_origin, damage, false, + Defines.EF_BLASTER); + ent.client.ps.gunframe++; + return true; + } + }; + + public 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; + } + }; + + public 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 = GameBase.gi + .soundindex("weapons/hyprbl1a.wav"); + + if (0 == (ent.client.buttons & Defines.BUTTON_ATTACK)) { + ent.client.ps.gunframe++; + } else { + if (0 == ent.client.pers.inventory[ent.client.ammo_index]) { + if (GameBase.level.time >= ent.pain_debounce_time) { + GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi + .soundindex("weapons/noammo.wav"), 1, + Defines.ATTN_NORM, 0); + ent.pain_debounce_time = GameBase.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 = Defines.EF_HYPERBLASTER; + else + effect = 0; + if (GameBase.deathmatch.value != 0) + damage = 15; + else + damage = 20; + Blaster_Fire(ent, offset, damage, true, effect); + if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) + ent.client.pers.inventory[ent.client.ammo_index]--; + + ent.client.anim_priority = Defines.ANIM_ATTACK; + if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) { + ent.s.frame = M_Player.FRAME_crattak1 - 1; + ent.client.anim_end = M_Player.FRAME_crattak9; + } else { + ent.s.frame = M_Player.FRAME_attack1 - 1; + ent.client.anim_end = M_Player.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) { + GameBase.gi.sound(ent, Defines.CHAN_AUTO, GameBase.gi + .soundindex("weapons/hyprbd1a.wav"), 1, + Defines.ATTN_NORM, 0); + ent.client.weapon_sound = 0; + } + + return true; + + } + }; + + public 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; + } + }; + + public 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; + } + }; + + public 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 + * + * ====================================================================== + */ + + public 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 (GameBase.deathmatch.value != 0) + Fire.fire_shotgun(ent, start, forward, damage, kick, 500, 500, + Defines.DEFAULT_DEATHMATCH_SHOTGUN_COUNT, + Defines.MOD_SHOTGUN); + else + Fire.fire_shotgun(ent, start, forward, damage, kick, 500, 500, + Defines.DEFAULT_SHOTGUN_COUNT, Defines.MOD_SHOTGUN); + + // send muzzle flash + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte(Defines.MZ_SHOTGUN | is_silenced); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + ent.client.ps.gunframe++; + GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); + + if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) + ent.client.pers.inventory[ent.client.ammo_index]--; + + return true; + } + }; + + public 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; + } + }; + + public 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[Defines.PITCH] = ent.client.v_angle[Defines.PITCH]; + v[Defines.YAW] = ent.client.v_angle[Defines.YAW] - 5; + v[Defines.ROLL] = ent.client.v_angle[Defines.ROLL]; + Math3D.AngleVectors(v, forward, null, null); + Fire.fire_shotgun(ent, start, forward, damage, kick, + Defines.DEFAULT_SHOTGUN_HSPREAD, + Defines.DEFAULT_SHOTGUN_VSPREAD, + Defines.DEFAULT_SSHOTGUN_COUNT / 2, Defines.MOD_SSHOTGUN); + v[Defines.YAW] = ent.client.v_angle[Defines.YAW] + 5; + Math3D.AngleVectors(v, forward, null, null); + Fire.fire_shotgun(ent, start, forward, damage, kick, + Defines.DEFAULT_SHOTGUN_HSPREAD, + Defines.DEFAULT_SHOTGUN_VSPREAD, + Defines.DEFAULT_SSHOTGUN_COUNT / 2, Defines.MOD_SSHOTGUN); + + // send muzzle flash + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte(Defines.MZ_SSHOTGUN | is_silenced); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + ent.client.ps.gunframe++; + GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); + + if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) + ent.client.pers.inventory[ent.client.ammo_index] -= 2; + + return true; + } + }; + + public 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 + * + * ====================================================================== + */ + public 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 (GameBase.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 + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte(Defines.MZ_RAILGUN | is_silenced); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + ent.client.ps.gunframe++; + GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); + + if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) + ent.client.pers.inventory[ent.client.ammo_index]--; + + return true; + } + }; + + public 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 + * + * ====================================================================== + */ + + public 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 (GameBase.deathmatch.value != 0) + damage = 200; + else + damage = 500; + + if (ent.client.ps.gunframe == 9) { + // send muzzle flash + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte(Defines.MZ_BFG | is_silenced); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + ent.client.ps.gunframe++; + + GameWeapon.PlayerNoise(ent, start, Defines.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 = GameBase.level.time + Defines.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++; + + GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); + + if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) + ent.client.pers.inventory[ent.client.ammo_index] -= 50; + + return true; + } + }; + + public 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; + } + }; + + public static boolean is_quad; + + public static byte is_silenced; + + public static EntInteractAdapter Pickup_Weapon = new EntInteractAdapter() { + public boolean interact(edict_t ent, edict_t other) { + int index; + gitem_t ammo; + + index = GameUtil.ITEM_INDEX(ent.item); + + if ((((int) (GameBase.dmflags.value) & Defines.DF_WEAPONS_STAY) != 0 || GameBase.coop.value != 0) + && 0 != other.client.pers.inventory[index]) { + if (0 == (ent.spawnflags & (Defines.DROPPED_ITEM | Defines.DROPPED_PLAYER_ITEM))) + return false; // leave the weapon for others to pickup + } + + other.client.pers.inventory[index]++; + + if (0 == (ent.spawnflags & Defines.DROPPED_ITEM)) { + // give them some ammo with it + ammo = GameUtil.FindItem(ent.item.ammo); + if (((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO) != 0) + GameAI.Add_Ammo(other, ammo, 1000); + else + GameAI.Add_Ammo(other, ammo, ammo.quantity); + + if (0 == (ent.spawnflags & Defines.DROPPED_PLAYER_ITEM)) { + if (GameBase.deathmatch.value != 0) { + if (((int) (GameBase.dmflags.value) & Defines.DF_WEAPONS_STAY) != 0) + ent.flags |= Defines.FL_RESPAWN; + else + GameUtil.SetRespawn(ent, 30); + } + if (GameBase.coop.value != 0) + ent.flags |= Defines.FL_RESPAWN; + } + } + + if (other.client.pers.weapon != ent.item + && (other.client.pers.inventory[index] == 1) + && (0 == GameBase.deathmatch.value || other.client.pers.weapon == GameUtil + .FindItem("blaster"))) + other.client.newweapon = ent.item; + + return true; + } + }; + + /* + * ================ Use_Weapon + * + * Make the weapon ready if there is ammo ================ + */ + public 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 == GameBase.g_select_empty.value + && 0 == (item.flags & Defines.IT_AMMO)) { + ammo_item = GameUtil.FindItem(item.ammo); + ammo_index = GameUtil.ITEM_INDEX(ammo_item); + + if (0 == ent.client.pers.inventory[ammo_index]) { + GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "No " + + ammo_item.pickup_name + " for " + + item.pickup_name + ".\n"); + return; + } + + if (ent.client.pers.inventory[ammo_index] < item.quantity) { + GameBase.gi.cprintf(ent, Defines.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 ================ + */ + + public static ItemDropAdapter Drop_Weapon = new ItemDropAdapter() { + public void drop(edict_t ent, gitem_t item) { + int index; + + if (0 != ((int) (GameBase.dmflags.value) & Defines.DF_WEAPONS_STAY)) + return; + + index = GameUtil.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)) { + GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, + "Can't drop current weapon\n"); + return; + } + + GameUtil.Drop_Item(ent, item); + ent.client.pers.inventory[index]--; + } + }; + + /* + * ====================================================================== + * + * MACHINEGUN / CHAINGUN + * + * ====================================================================== + */ + + public 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 & Defines.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 (GameBase.level.time >= ent.pain_debounce_time) { + GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi + .soundindex("weapons/noammo.wav"), 1, + Defines.ATTN_NORM, 0); + ent.pain_debounce_time = GameBase.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 == GameBase.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, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.DEFAULT_BULLET_VSPREAD, Defines.MOD_MACHINEGUN); + + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte(Defines.MZ_MACHINEGUN | is_silenced); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); + + if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) + ent.client.pers.inventory[ent.client.ammo_index]--; + + ent.client.anim_priority = Defines.ANIM_ATTACK; + if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) { + ent.s.frame = M_Player.FRAME_crattak1 + - (int) (Lib.random() + 0.25); + ent.client.anim_end = M_Player.FRAME_crattak9; + } else { + ent.s.frame = M_Player.FRAME_attack1 + - (int) (Lib.random() + 0.25); + ent.client.anim_end = M_Player.FRAME_attack8; + } + return true; + } + }; + + public 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 (GameBase.deathmatch.value != 0) + damage = 6; + else + damage = 8; + + if (ent.client.ps.gunframe == 5) + GameBase.gi.sound(ent, Defines.CHAN_AUTO, GameBase.gi + .soundindex("weapons/chngnu1a.wav"), 1, + Defines.ATTN_IDLE, 0); + + if ((ent.client.ps.gunframe == 14) + && 0 == (ent.client.buttons & Defines.BUTTON_ATTACK)) { + ent.client.ps.gunframe = 32; + ent.client.weapon_sound = 0; + return true; + } else if ((ent.client.ps.gunframe == 21) + && (ent.client.buttons & Defines.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; + GameBase.gi.sound(ent, Defines.CHAN_AUTO, GameBase.gi + .soundindex("weapons/chngnd1a.wav"), 1, + Defines.ATTN_IDLE, 0); + } else { + ent.client.weapon_sound = GameBase.gi + .soundindex("weapons/chngnl1a.wav"); + } + + ent.client.anim_priority = Defines.ANIM_ATTACK; + if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) { + ent.s.frame = M_Player.FRAME_crattak1 + - (ent.client.ps.gunframe & 1); + ent.client.anim_end = M_Player.FRAME_crattak9; + } else { + ent.s.frame = M_Player.FRAME_attack1 + - (ent.client.ps.gunframe & 1); + ent.client.anim_end = M_Player.FRAME_attack8; + } + + if (ent.client.ps.gunframe <= 9) + shots = 1; + else if (ent.client.ps.gunframe <= 14) { + if ((ent.client.buttons & Defines.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 (GameBase.level.time >= ent.pain_debounce_time) { + GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi + .soundindex("weapons/noammo.wav"), 1, + Defines.ATTN_NORM, 0); + ent.pain_debounce_time = GameBase.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, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.DEFAULT_BULLET_VSPREAD, Defines.MOD_CHAINGUN); + } + + // send muzzle flash + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte((Defines.MZ_CHAINGUN1 + shots - 1) + | is_silenced); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); + + if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) + ent.client.pers.inventory[ent.client.ammo_index] -= shots; + + return true; + } + }; + + public static int pause_frames[] = { 39, 45, 50, 55, 0 }; + + public static int fire_frames[] = { 9, 17, 0 }; + + public 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 == Defines.LEFT_HANDED) + _distance[1] *= -1; + else if (client.pers.hand == Defines.CENTER_HANDED) + _distance[1] = 0; + Math3D.G_ProjectSource(point, _distance, forward, right, result); + } + + /* + * =============== ChangeWeapon + * + * The old weapon has been dropped all the way, so make the new one current + * =============== + */ + public static void ChangeWeapon(edict_t ent) { + int i; + + if (ent.client.grenade_time != 0) { + ent.client.grenade_time = GameBase.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.index - 1) | i; + } + + if (ent.client.pers.weapon != null + && ent.client.pers.weapon.ammo != null) + ent.client.ammo_index = GameUtil.ITEM_INDEX(GameUtil + .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 = Defines.WEAPON_ACTIVATING; + ent.client.ps.gunframe = 0; + ent.client.ps.gunindex = GameBase.gi + .modelindex(ent.client.pers.weapon.view_model); + + ent.client.anim_priority = Defines.ANIM_PAIN; + if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) { + ent.s.frame = M_Player.FRAME_crpain1; + ent.client.anim_end = M_Player.FRAME_crpain4; + } else { + ent.s.frame = M_Player.FRAME_pain301; + ent.client.anim_end = M_Player.FRAME_pain304; + + } + } + + /* + * ================= NoAmmoWeaponChange ================= + */ + public static void NoAmmoWeaponChange(edict_t ent) { + if (0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("slugs"))] + && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("railgun"))]) { + ent.client.newweapon = GameUtil.FindItem("railgun"); + return; + } + if (0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("cells"))] + && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("hyperblaster"))]) { + ent.client.newweapon = GameUtil.FindItem("hyperblaster"); + return; + } + if (0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("bullets"))] + && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("chaingun"))]) { + ent.client.newweapon = GameUtil.FindItem("chaingun"); + return; + } + if (0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("bullets"))] + && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("machinegun"))]) { + ent.client.newweapon = GameUtil.FindItem("machinegun"); + return; + } + if (ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("shells"))] > 1 + && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("super shotgun"))]) { + ent.client.newweapon = GameUtil.FindItem("super shotgun"); + return; + } + if (0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("shells"))] + && 0 != ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("shotgun"))]) { + ent.client.newweapon = GameUtil.FindItem("shotgun"); + return; + } + ent.client.newweapon = GameUtil.FindItem("blaster"); + } + + /* + * ================= Think_Weapon + * + * Called by ClientBeginServerFrame and ClientThink ================= + */ + public 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 > GameBase.level.framenum); + if (ent.client.silencer_shots != 0) + is_silenced = (byte) Defines.MZ_SILENCED; + else + is_silenced = 0; + ent.client.pers.weapon.weaponthink.think(ent); + } + } + + /* + * ================ Weapon_Generic + * + * A generic function to handle the basics of weapon thinking + * ================ + */ + + public 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 == Defines.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 = Defines.ANIM_REVERSE; + if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) { + ent.s.frame = M_Player.FRAME_crpain4 + 1; + ent.client.anim_end = M_Player.FRAME_crpain1; + } else { + ent.s.frame = M_Player.FRAME_pain304 + 1; + ent.client.anim_end = M_Player.FRAME_pain301; + + } + } + + ent.client.ps.gunframe++; + return; + } + + if (ent.client.weaponstate == Defines.WEAPON_ACTIVATING) { + if (ent.client.ps.gunframe == FRAME_ACTIVATE_LAST) { + ent.client.weaponstate = Defines.WEAPON_READY; + ent.client.ps.gunframe = FRAME_IDLE_FIRST; + return; + } + + ent.client.ps.gunframe++; + return; + } + + if ((ent.client.newweapon != null) + && (ent.client.weaponstate != Defines.WEAPON_FIRING)) { + ent.client.weaponstate = Defines.WEAPON_DROPPING; + ent.client.ps.gunframe = FRAME_DEACTIVATE_FIRST; + + if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4) { + ent.client.anim_priority = Defines.ANIM_REVERSE; + if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) { + ent.s.frame = M_Player.FRAME_crpain4 + 1; + ent.client.anim_end = M_Player.FRAME_crpain1; + } else { + ent.s.frame = M_Player.FRAME_pain304 + 1; + ent.client.anim_end = M_Player.FRAME_pain301; + + } + } + return; + } + + if (ent.client.weaponstate == Defines.WEAPON_READY) { + if (((ent.client.latched_buttons | ent.client.buttons) & Defines.BUTTON_ATTACK) != 0) { + ent.client.latched_buttons &= ~Defines.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 = Defines.WEAPON_FIRING; + + // start the animation + ent.client.anim_priority = Defines.ANIM_ATTACK; + if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) { + ent.s.frame = M_Player.FRAME_crattak1 - 1; + ent.client.anim_end = M_Player.FRAME_crattak9; + } else { + ent.s.frame = M_Player.FRAME_attack1 - 1; + ent.client.anim_end = M_Player.FRAME_attack8; + } + } else { + if (GameBase.level.time >= ent.pain_debounce_time) { + GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi + .soundindex("weapons/noammo.wav"), 1, + Defines.ATTN_NORM, 0); + ent.pain_debounce_time = GameBase.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 == Defines.WEAPON_FIRING) { + for (n = 0; fire_frames[n] != 0; n++) { + if (ent.client.ps.gunframe == fire_frames[n]) { + if (ent.client.quad_framenum > GameBase.level.framenum) + GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/damage3.wav"), 1, + Defines.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 = Defines.WEAPON_READY; + } + } + + /* + * ====================================================================== + * + * GRENADE + * + * ====================================================================== + */ + + public 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 - GameBase.level.time; + speed = (int) (Defines.GRENADE_MINSPEED + (Defines.GRENADE_TIMER - timer) + * ((Defines.GRENADE_MAXSPEED - Defines.GRENADE_MINSPEED) / Defines.GRENADE_TIMER)); + Fire.fire_grenade2(ent, start, forward, damage, speed, timer, radius, + held); + + if (0 == ((int) GameBase.dmflags.value & Defines.DF_INFINITE_AMMO)) + ent.client.pers.inventory[ent.client.ammo_index]--; + + ent.client.grenade_time = GameBase.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 & pmove_t.PMF_DUCKED) != 0) { + ent.client.anim_priority = Defines.ANIM_ATTACK; + ent.s.frame = M_Player.FRAME_crattak1 - 1; + ent.client.anim_end = M_Player.FRAME_crattak3; + } else { + ent.client.anim_priority = Defines.ANIM_REVERSE; + ent.s.frame = M_Player.FRAME_wave08; + ent.client.anim_end = M_Player.FRAME_wave01; + } + } + + /* + * ====================================================================== + * + * BLASTER / HYPERBLASTER + * + * ====================================================================== + */ + + public 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 + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + GameBase.gi.WriteShort(ent.index); + if (hyper) + GameBase.gi.WriteByte(Defines.MZ_HYPERBLASTER | is_silenced); + else + GameBase.gi.WriteByte(Defines.MZ_BLASTER | is_silenced); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + GameWeapon.PlayerNoise(ent, start, Defines.PNOISE_WEAPON); + } +} \ No newline at end of file diff --git a/src/jake2/game/GameSVCmds.java b/src/jake2/game/GameSVCmds.java index 1d1c244..050b507 100644 --- a/src/jake2/game/GameSVCmds.java +++ b/src/jake2/game/GameSVCmds.java @@ -1,300 +1,305 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 01.02.2004 by RST. -// $Id: GameSVCmds.java,v 1.2 2004-07-09 06:50:49 hzi Exp $ - +// $Id: GameSVCmds.java,v 1.3 2004-09-22 19:22:05 salomo Exp $ package jake2.game; +import jake2.Defines; import jake2.qcommon.Com; +import jake2.util.Lib; import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.ByteBuffer; import java.util.StringTokenizer; -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 - removeip - - 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 " 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 \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 \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"); - } - -} +public class GameSVCmds { + + /* + * ============================================================================== + * + * PACKET FILTERING + * + * + * You can add or remove addresses from the filter list with: + * + * addip removeip + * + * 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 " 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 void Svcmd_Test_f() { + GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Svcmd_Test_f()\n"); + } + + public static final int MAX_IPFILTERS = 1024; + + static GameSVCmds.ipfilter_t ipfilters[] = new GameSVCmds.ipfilter_t[MAX_IPFILTERS]; + + static int numipfilters; + static { + for (int n = 0; n < GameSVCmds.MAX_IPFILTERS; n++) + GameSVCmds.ipfilters[n] = new ipfilter_t(); + } + + /* + * ================= StringToFilter ================= + */ + static boolean StringToFilter(String s, GameSVCmds.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) Lib.atoi(tk.nextToken()); + if (b[n] != 0) + m[n] = -1; + } + + f.mask = ByteBuffer.wrap(m).getInt(); + f.compare = ByteBuffer.wrap(b).getInt(); + } catch (Exception e) { + GameBase.gi.cprintf(null, Defines.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) GameBase.filterban.value) != 0; + + return ((int) 1 - GameBase.filterban.value) != 0; + } + + /* + * ================= SV_AddIP_f ================= + */ + static void SVCmd_AddIP_f() { + int i; + + if (GameBase.gi.argc() < 3) { + GameBase.gi.cprintf(null, Defines.PRINT_HIGH, + "Usage: addip \n"); + return; + } + + for (i = 0; i < numipfilters; i++) + if (ipfilters[i].compare == 0xffffffff) + break; // free spot + if (i == numipfilters) { + if (numipfilters == MAX_IPFILTERS) { + GameBase.gi.cprintf(null, Defines.PRINT_HIGH, + "IP filter list is full\n"); + return; + } + numipfilters++; + } + + if (!StringToFilter(GameBase.gi.argv(2), ipfilters[i])) + ipfilters[i].compare = 0xffffffff; + } + + /* + * ================= SV_RemoveIP_f ================= + */ + static void SVCmd_RemoveIP_f() { + GameSVCmds.ipfilter_t f = new GameSVCmds.ipfilter_t(); + int i, j; + + if (GameBase.gi.argc() < 3) { + GameBase.gi.cprintf(null, Defines.PRINT_HIGH, + "Usage: sv removeip \n"); + return; + } + + if (!StringToFilter(GameBase.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--; + GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Removed.\n"); + return; + } + GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Didn't find " + + GameBase.gi.argv(2) + ".\n"); + } + + /* + * ================= SV_ListIP_f ================= + */ + static void SVCmd_ListIP_f() { + int i; + byte b[]; + + GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Filter list:\n"); + for (i = 0; i < numipfilters; i++) { + b = Lib.getIntBytes(ipfilters[i].compare); + GameBase.gi + .cprintf(null, Defines.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 = GameBase.gi.cvar("game", "", 0); + + if (game.string == null) + name = Defines.GAMEVERSION + "/listip.cfg"; + else + name = game.string + "/listip.cfg"; + + GameBase.gi + .cprintf(null, Defines.PRINT_HIGH, "Writing " + name + ".\n"); + + f = Lib.fopen(name, "rw"); + if (f == null) { + GameBase.gi.cprintf(null, Defines.PRINT_HIGH, "Couldn't open " + + name + "\n"); + return; + } + + try { + f.writeChars("set filterban " + (int) GameBase.filterban.value + + "\n"); + + for (i = 0; i < numipfilters; i++) { + b = Lib.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); + } + + Lib.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 = GameBase.gi.argv(1); + if (Lib.Q_stricmp(cmd, "test") == 0) + Svcmd_Test_f(); + else if (Lib.Q_stricmp(cmd, "addip") == 0) + SVCmd_AddIP_f(); + else if (Lib.Q_stricmp(cmd, "removeip") == 0) + SVCmd_RemoveIP_f(); + else if (Lib.Q_stricmp(cmd, "listip") == 0) + SVCmd_ListIP_f(); + else if (Lib.Q_stricmp(cmd, "writeip") == 0) + SVCmd_WriteIP_f(); + else + GameBase.gi.cprintf(null, Defines.PRINT_HIGH, + "Unknown server command \"" + cmd + "\"\n"); + } +} \ No newline at end of file diff --git a/src/jake2/game/GameSave.java b/src/jake2/game/GameSave.java index 25b102b..c3d07b1 100644 --- a/src/jake2/game/GameSave.java +++ b/src/jake2/game/GameSave.java @@ -1,302 +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. - -*/ + * 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.6 2004-09-10 19:02:54 salomo Exp $ - +// $Id: GameSave.java,v 1.7 2004-09-22 19:22:01 salomo Exp $ package jake2.game; -import jake2.qcommon.Com; +import jake2.Defines; +import jake2.Globals; +import jake2.util.Lib; import jake2.util.QuakeFile; -public class GameSave extends GameFunc { - - 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); - GameBase.g_edicts= g_edicts; - } - - 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(); - - game.helpmessage1= ""; - game.helpmessage2= ""; - - // initialize all entities for this game - game.maxentities= (int) maxentities.value; - CreateEdicts(); - - // initialize all clients for this game - game.maxclients= (int) maxclients.value; - - CreateClients(); - - num_edicts= game.maxclients + 1; - } - - /* - ============ - 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) { - try { - QuakeFile f; - - if (!autosave) - SaveClientData(); - - f= new QuakeFile(filename, "rw"); - - if (f == null) - gi.error("Couldn't write to " + filename); - - game.autosaved= autosave; - game.write(f); - game.autosaved= false; - - for (int i= 0; i < game.maxclients; i++) - game.clients[i].write(f); - - fclose(f); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - public static void ReadGame(String filename) { - - QuakeFile f= null; - - try { - - f= new QuakeFile(filename, "r"); - CreateEdicts(); - - game.load(f); - - for (int i= 0; i < game.maxclients; i++) { - game.clients[i]= new gclient_t(i); - game.clients[i].read(f); - } - - f.close(); - } - - catch (Exception e) { - e.printStackTrace(); - } - } - - /* - ================= - WriteLevel - - ================= - */ - public static void WriteLevel(String filename) { - try { - int i; - edict_t ent; - QuakeFile f; - - f= new QuakeFile(filename, "rw"); - if (f == null) - gi.error("Couldn't open for writing: " + filename); - - // write out level_locals_t - level.write(f); - - // write out all the entities - for (i= 0; i < num_edicts; i++) { - ent= g_edicts[i]; - if (!ent.inuse) - continue; - f.writeInt(i); - ent.write(f); - - } - - i= -1; - f.writeInt(-1); - - f.close(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - /* - ================= - 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. - ================= - */ - public static void ReadLevel(String filename) { - try { - edict_t ent; - - QuakeFile f= new QuakeFile(filename, "r"); - - if (f == null) - gi.error("Couldn't read level file " + filename); - - // wipe all the entities - Game.CreateEdicts(); - - num_edicts= (int) maxclients.value + 1; - - // load the level locals - level.read(f); - - // load all the entities - while (true) { - int entnum= f.readInt(); - if (entnum == -1) - break; - - if (entnum >= num_edicts) - num_edicts= entnum + 1; - - ent= g_edicts[entnum]; - ent.read(f); - ent.cleararealinks(); - gi.linkentity(ent); - } - - fclose(f); - - // mark all clients as unconnected - for (int 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 (int i= 0; i < num_edicts; i++) { - ent= g_edicts[i]; - - if (!ent.inuse) - continue; - - // fire any cross-level triggers - if (ent.classname != null) - if (strcmp(ent.classname, "target_crosslevel_target") == 0) - ent.nextthink= level.time + ent.delay; - } - } - catch (Exception e) { - e.printStackTrace(); - } - } -} +public class GameSave { + + public static void CreateEdicts() { + GameBase.g_edicts = new edict_t[GameBase.game.maxentities]; + for (int i = 0; i < GameBase.game.maxentities; i++) + GameBase.g_edicts[i] = new edict_t(i); + GameBase.g_edicts = GameBase.g_edicts; + } + + public static void CreateClients() { + GameBase.game.clients = new gclient_t[GameBase.game.maxclients]; + for (int i = 0; i < GameBase.game.maxclients; i++) + GameBase.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() { + GameBase.gi.dprintf("==== InitGame ====\n"); + + GameBase.gun_x = GameBase.gi.cvar("gun_x", "0", 0); + GameBase.gun_y = GameBase.gi.cvar("gun_y", "0", 0); + GameBase.gun_z = GameBase.gi.cvar("gun_z", "0", 0); + + //FIXME: sv_ prefix is wrong for these + GameBase.sv_rollspeed = GameBase.gi.cvar("sv_rollspeed", "200", 0); + GameBase.sv_rollangle = GameBase.gi.cvar("sv_rollangle", "2", 0); + GameBase.sv_maxvelocity = GameBase.gi.cvar("sv_maxvelocity", "2000", 0); + GameBase.sv_gravity = GameBase.gi.cvar("sv_gravity", "800", 0); + + // noset vars + GameBase.dedicated = GameBase.gi.cvar("dedicated", "0", + Defines.CVAR_NOSET); + + // latched vars + GameBase.sv_cheats = GameBase.gi.cvar("cheats", "0", + Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH); + GameBase.gi.cvar("gamename", Defines.GAMEVERSION, + Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH); + GameBase.gi.cvar("gamedate", Globals.__DATE__, Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + + GameBase.maxclients = GameBase.gi.cvar("maxclients", "4", + Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH); + GameBase.maxspectators = GameBase.gi.cvar("maxspectators", "4", + Defines.CVAR_SERVERINFO); + GameBase.deathmatch = GameBase.gi.cvar("deathmatch", "0", + Defines.CVAR_LATCH); + GameBase.coop = GameBase.gi.cvar("coop", "0", Defines.CVAR_LATCH); + GameBase.skill = GameBase.gi.cvar("skill", "0", Defines.CVAR_LATCH); + GameBase.maxentities = GameBase.gi.cvar("maxentities", "1024", + Defines.CVAR_LATCH); + + // change anytime vars + GameBase.dmflags = GameBase.gi.cvar("dmflags", "0", + Defines.CVAR_SERVERINFO); + GameBase.fraglimit = GameBase.gi.cvar("fraglimit", "0", + Defines.CVAR_SERVERINFO); + GameBase.timelimit = GameBase.gi.cvar("timelimit", "0", + Defines.CVAR_SERVERINFO); + GameBase.password = GameBase.gi.cvar("password", "", + Defines.CVAR_USERINFO); + GameBase.spectator_password = GameBase.gi.cvar("spectator_password", + "", Defines.CVAR_USERINFO); + GameBase.needpass = GameBase.gi.cvar("needpass", "0", + Defines.CVAR_SERVERINFO); + GameBase.filterban = GameBase.gi.cvar("filterban", "1", 0); + + GameBase.g_select_empty = GameBase.gi.cvar("g_select_empty", "0", + Defines.CVAR_ARCHIVE); + + GameBase.run_pitch = GameBase.gi.cvar("run_pitch", "0.002", 0); + GameBase.run_roll = GameBase.gi.cvar("run_roll", "0.005", 0); + GameBase.bob_up = GameBase.gi.cvar("bob_up", "0.005", 0); + GameBase.bob_pitch = GameBase.gi.cvar("bob_pitch", "0.002", 0); + GameBase.bob_roll = GameBase.gi.cvar("bob_roll", "0.002", 0); + + // flood control + GameBase.flood_msgs = GameBase.gi.cvar("flood_msgs", "4", 0); + GameBase.flood_persecond = GameBase.gi.cvar("flood_persecond", "4", 0); + GameBase.flood_waitdelay = GameBase.gi.cvar("flood_waitdelay", "10", 0); + + // dm map list + GameBase.sv_maplist = GameBase.gi.cvar("sv_maplist", "", 0); + + // items + GameAI.InitItems(); + + GameBase.game.helpmessage1 = ""; + GameBase.game.helpmessage2 = ""; + + // initialize all entities for this game + GameBase.game.maxentities = (int) GameBase.maxentities.value; + CreateEdicts(); + + // initialize all clients for this game + GameBase.game.maxclients = (int) GameBase.maxclients.value; + + CreateClients(); + + GameBase.num_edicts = GameBase.game.maxclients + 1; + } + + /* + * ============ 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) { + try { + QuakeFile f; + + if (!autosave) + PlayerClient.SaveClientData(); + + f = new QuakeFile(filename, "rw"); + + if (f == null) + GameBase.gi.error("Couldn't write to " + filename); + + GameBase.game.autosaved = autosave; + GameBase.game.write(f); + GameBase.game.autosaved = false; + + for (int i = 0; i < GameBase.game.maxclients; i++) + GameBase.game.clients[i].write(f); + + Lib.fclose(f); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void ReadGame(String filename) { + + QuakeFile f = null; + + try { + + f = new QuakeFile(filename, "r"); + CreateEdicts(); + + GameBase.game.load(f); + + for (int i = 0; i < GameBase.game.maxclients; i++) { + GameBase.game.clients[i] = new gclient_t(i); + GameBase.game.clients[i].read(f); + } + + f.close(); + } + + catch (Exception e) { + e.printStackTrace(); + } + } + + /* + * ================= WriteLevel + * + * ================= + */ + public static void WriteLevel(String filename) { + try { + int i; + edict_t ent; + QuakeFile f; + + f = new QuakeFile(filename, "rw"); + if (f == null) + GameBase.gi.error("Couldn't open for writing: " + filename); + + // write out level_locals_t + GameBase.level.write(f); + + // write out all the entities + for (i = 0; i < GameBase.num_edicts; i++) { + ent = GameBase.g_edicts[i]; + if (!ent.inuse) + continue; + f.writeInt(i); + ent.write(f); + + } + + i = -1; + f.writeInt(-1); + + f.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /* + * ================= 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. ================= + */ + public static void ReadLevel(String filename) { + try { + edict_t ent; + + QuakeFile f = new QuakeFile(filename, "r"); + + if (f == null) + GameBase.gi.error("Couldn't read level file " + filename); + + // wipe all the entities + CreateEdicts(); + + GameBase.num_edicts = (int) GameBase.maxclients.value + 1; + + // load the level locals + GameBase.level.read(f); + + // load all the entities + while (true) { + int entnum = f.readInt(); + if (entnum == -1) + break; + + if (entnum >= GameBase.num_edicts) + GameBase.num_edicts = entnum + 1; + + ent = GameBase.g_edicts[entnum]; + ent.read(f); + ent.cleararealinks(); + GameBase.gi.linkentity(ent); + } + + Lib.fclose(f); + + // mark all clients as unconnected + for (int i = 0; i < GameBase.maxclients.value; i++) { + ent = GameBase.g_edicts[i + 1]; + ent.client = GameBase.game.clients[i]; + ent.client.pers.connected = false; + } + + // do any load time things at this point + for (int i = 0; i < GameBase.num_edicts; i++) { + ent = GameBase.g_edicts[i]; + + if (!ent.inuse) + continue; + + // fire any cross-level triggers + if (ent.classname != null) + if (Lib.strcmp(ent.classname, "target_crosslevel_target") == 0) + ent.nextthink = GameBase.level.time + ent.delay; + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/jake2/game/GameSpawn.java b/src/jake2/game/GameSpawn.java index 2701fae..6fe9924 100644 --- a/src/jake2/game/GameSpawn.java +++ b/src/jake2/game/GameSpawn.java @@ -1,471 +1,1142 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 18.11.2003 by RST. +// $Id: GameSpawn.java,v 1.9 2004-09-22 19:22:05 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.qcommon.Com; +import jake2.util.Lib; -See the GNU General Public License for more details. +public class GameSpawn { -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. + static EntThinkAdapter SP_item_health = new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameAI.SP_item_health(ent); + return true; + } + }; -*/ + static EntThinkAdapter SP_item_health_small = new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameAI.SP_item_health_small(ent); + return true; + } + }; -// Created on 18.11.2003 by RST. -// $Id: GameSpawn.java,v 1.8 2004-09-10 19:02:54 salomo Exp $ + static EntThinkAdapter SP_item_health_large = new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameAI.SP_item_health_large(ent); + return true; + } + }; -package jake2.game; + static EntThinkAdapter SP_item_health_mega = new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameAI.SP_item_health_mega(ent); + return true; + } + }; -import jake2.qcommon.Com; -import jake2.util.Lib; + static EntThinkAdapter SP_info_player_start = new EntThinkAdapter() { + public boolean think(edict_t ent) { + PlayerClient.SP_info_player_start(ent); + return true; + } + }; + + static EntThinkAdapter SP_info_player_deathmatch = new EntThinkAdapter() { + public boolean think(edict_t ent) { + PlayerClient.SP_info_player_deathmatch(ent); + return true; + } + }; + + static EntThinkAdapter SP_info_player_coop = new EntThinkAdapter() { + public boolean think(edict_t ent) { + PlayerClient.SP_info_player_coop(ent); + return true; + } + }; + + static EntThinkAdapter SP_info_player_intermission = new EntThinkAdapter() { + public boolean think(edict_t ent) { + PlayerClient.SP_info_player_intermission(); + return true; + } + }; + + static EntThinkAdapter SP_func_plat = new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameFunc.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) { + GameFunc.SP_func_water(ent); + return true; + } + }; + + static EntThinkAdapter SP_func_train = new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameFunc.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) { + GameMisc.SP_func_clock(ent); + return true; + } + }; + + /* + * 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 = Defines.MOVETYPE_PUSH; + ent.solid = Defines.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 + PlayerClient.InitBodyQue(); + // set configstrings for items + GameAI.SetItemNames(); + if (GameBase.st.nextmap != null) + GameBase.level.nextmap = GameBase.st.nextmap; + // make some data visible to the server + if (ent.message != null && ent.message.length() > 0) { + GameBase.gi.configstring(Defines.CS_NAME, ent.message); + GameBase.level.level_name = ent.message; + } else + GameBase.level.level_name = GameBase.level.mapname; + if (GameBase.st.sky != null && GameBase.st.sky.length() > 0) + GameBase.gi.configstring(Defines.CS_SKY, GameBase.st.sky); + else + GameBase.gi.configstring(Defines.CS_SKY, "unit1_"); + GameBase.gi.configstring(Defines.CS_SKYROTATE, "" + + GameBase.st.skyrotate); + GameBase.gi.configstring(Defines.CS_SKYAXIS, Lib + .vtos(GameBase.st.skyaxis)); + GameBase.gi.configstring(Defines.CS_CDTRACK, "" + ent.sounds); + GameBase.gi.configstring(Defines.CS_MAXCLIENTS, "" + + (int) (GameBase.maxclients.value)); + // status bar program + if (GameBase.deathmatch.value != 0) + GameBase.gi.configstring(Defines.CS_STATUSBAR, "" + + GameSpawn.dm_statusbar); + else + GameBase.gi.configstring(Defines.CS_STATUSBAR, "" + + GameSpawn.single_statusbar); + //--------------- + // help icon for statusbar + GameBase.gi.imageindex("i_help"); + GameBase.level.pic_health = GameBase.gi.imageindex("i_health"); + GameBase.gi.imageindex("help"); + GameBase.gi.imageindex("field_3"); + if (GameBase.st.gravity != null) + GameBase.gi.cvar_set("sv_gravity", "800"); + else + GameBase.gi.cvar_set("sv_gravity", GameBase.st.gravity); + GameBase.snd_fry = GameBase.gi.soundindex("player/fry.wav"); + // standing in lava / slime + GameAI.PrecacheItem(GameUtil.FindItem("Blaster")); + GameBase.gi.soundindex("player/lava1.wav"); + GameBase.gi.soundindex("player/lava2.wav"); + GameBase.gi.soundindex("misc/pc_up.wav"); + GameBase.gi.soundindex("misc/talk1.wav"); + GameBase.gi.soundindex("misc/udeath.wav"); + // gibs + GameBase.gi.soundindex("items/respawn1.wav"); + // sexed sounds + GameBase.gi.soundindex("*death1.wav"); + GameBase.gi.soundindex("*death2.wav"); + GameBase.gi.soundindex("*death3.wav"); + GameBase.gi.soundindex("*death4.wav"); + GameBase.gi.soundindex("*fall1.wav"); + GameBase.gi.soundindex("*fall2.wav"); + GameBase.gi.soundindex("*gurp1.wav"); + // drowning damage + GameBase.gi.soundindex("*gurp2.wav"); + GameBase.gi.soundindex("*jump1.wav"); + // player jump + GameBase.gi.soundindex("*pain25_1.wav"); + GameBase.gi.soundindex("*pain25_2.wav"); + GameBase.gi.soundindex("*pain50_1.wav"); + GameBase.gi.soundindex("*pain50_2.wav"); + GameBase.gi.soundindex("*pain75_1.wav"); + GameBase.gi.soundindex("*pain75_2.wav"); + GameBase.gi.soundindex("*pain100_1.wav"); + GameBase.gi.soundindex("*pain100_2.wav"); + // sexed models + // THIS ORDER MUST MATCH THE DEFINES IN g_local.h + // you can add more, max 15 + GameBase.gi.modelindex("#w_blaster.md2"); + GameBase.gi.modelindex("#w_shotgun.md2"); + GameBase.gi.modelindex("#w_sshotgun.md2"); + GameBase.gi.modelindex("#w_machinegun.md2"); + GameBase.gi.modelindex("#w_chaingun.md2"); + GameBase.gi.modelindex("#a_grenades.md2"); + GameBase.gi.modelindex("#w_glauncher.md2"); + GameBase.gi.modelindex("#w_rlauncher.md2"); + GameBase.gi.modelindex("#w_hyperblaster.md2"); + GameBase.gi.modelindex("#w_railgun.md2"); + GameBase.gi.modelindex("#w_bfg.md2"); + //------------------- + GameBase.gi.soundindex("player/gasp1.wav"); + // gasping for air + GameBase.gi.soundindex("player/gasp2.wav"); + // head breaking surface, not gasping + GameBase.gi.soundindex("player/watr_in.wav"); + // feet hitting water + GameBase.gi.soundindex("player/watr_out.wav"); + // feet leaving water + GameBase.gi.soundindex("player/watr_un.wav"); + // head going underwater + GameBase.gi.soundindex("player/u_breath1.wav"); + GameBase.gi.soundindex("player/u_breath2.wav"); + GameBase.gi.soundindex("items/pkup.wav"); + // bonus item pickup + GameBase.gi.soundindex("world/land.wav"); + // landing thud + GameBase.gi.soundindex("misc/h2ohit1.wav"); + // landing splash + GameBase.gi.soundindex("items/damage.wav"); + GameBase.gi.soundindex("items/protect.wav"); + GameBase.gi.soundindex("items/protect4.wav"); + GameBase.gi.soundindex("weapons/noammo.wav"); + GameBase.gi.soundindex("infantry/inflies1.wav"); + GameBase.sm_meat_index = GameBase.gi + .modelindex("models/objects/gibs/sm_meat/tris.md2"); + GameBase.gi.modelindex("models/objects/gibs/arm/tris.md2"); + GameBase.gi.modelindex("models/objects/gibs/bone/tris.md2"); + GameBase.gi.modelindex("models/objects/gibs/bone2/tris.md2"); + GameBase.gi.modelindex("models/objects/gibs/chest/tris.md2"); + GameBase.gi.modelindex("models/objects/gibs/skull/tris.md2"); + GameBase.gi.modelindex("models/objects/gibs/head2/tris.md2"); + // + // Setup light animation tables. 'a' is total darkness, 'z' is + // doublebright. + // + // 0 normal + GameBase.gi.configstring(Defines.CS_LIGHTS + 0, "m"); + // 1 FLICKER (first variety) + GameBase.gi.configstring(Defines.CS_LIGHTS + 1, + "mmnmmommommnonmmonqnmmo"); + // 2 SLOW STRONG PULSE + GameBase.gi.configstring(Defines.CS_LIGHTS + 2, + "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); + // 3 CANDLE (first variety) + GameBase.gi.configstring(Defines.CS_LIGHTS + 3, + "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); + // 4 FAST STROBE + GameBase.gi.configstring(Defines.CS_LIGHTS + 4, "mamamamamama"); + // 5 GENTLE PULSE 1 + GameBase.gi.configstring(Defines.CS_LIGHTS + 5, + "jklmnopqrstuvwxyzyxwvutsrqponmlkj"); + // 6 FLICKER (second variety) + GameBase.gi + .configstring(Defines.CS_LIGHTS + 6, "nmonqnmomnmomomno"); + // 7 CANDLE (second variety) + GameBase.gi.configstring(Defines.CS_LIGHTS + 7, + "mmmaaaabcdefgmmmmaaaammmaamm"); + // 8 CANDLE (third variety) + GameBase.gi.configstring(Defines.CS_LIGHTS + 8, + "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); + // 9 SLOW STROBE (fourth variety) + GameBase.gi.configstring(Defines.CS_LIGHTS + 9, "aaaaaaaazzzzzzzz"); + // 10 FLUORESCENT FLICKER + GameBase.gi.configstring(Defines.CS_LIGHTS + 10, + "mmamammmmammamamaaamammma"); + // 11 SLOW PULSE NOT FADE TO BLACK + GameBase.gi.configstring(Defines.CS_LIGHTS + 11, + "abcdefghijklmnopqrrqponmlkjihgfedcba"); + // styles 32-62 are assigned by the light program for switchable + // lights + // 63 testing + GameBase.gi.configstring(Defines.CS_LIGHTS + 63, "a"); + return true; + } + }; + + /* + * ============= ED_NewString ============= + */ + static String ED_NewString(String string) { + + int l = string.length(); + StringBuffer newb = new StringBuffer(l); + + for (int i = 0; i < l; i++) { + char 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) { + byte b; + float v; + float[] vec = { 0, 0, 0 }; + + if (key.equals("nextmap")) + Com.p("nextmap: " + value); + if (!GameBase.st.set(key, value)) + if (!ent.set(key, value)) + GameBase.gi.dprintf("??? The key [" + key + + "] is not a field\n"); + + } + + /* + * ==================== 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; + + GameBase.st = new spawn_temp_t(); + while (true) { + + // parse key + com_token = Com.Parse(ph); + if (com_token.equals("}")) + break; + + if (ph.isEof()) + GameBase.gi.error("ED_ParseEntity: EOF without closing brace"); + + keyname = com_token; + + // parse value + com_token = Com.Parse(ph); + + if (ph.isEof()) + GameBase.gi.error("ED_ParseEntity: EOF without closing brace"); + + if (com_token.equals("}")) + GameBase.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) { + GameUtil.G_ClearEdict(ent); + } + + 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 < GameBase.num_edicts; i++) { + e = GameBase.g_edicts[i]; + + if (!e.inuse) + continue; + if (e.team == null) + continue; + if ((e.flags & Defines.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 < GameBase.num_edicts; j++) { + e2 = GameBase.g_edicts[j]; + if (!e2.inuse) + continue; + if (null == e2.team) + continue; + if ((e2.flags & Defines.FL_TEAMSLAVE) != 0) + continue; + if (0 == Lib.strcmp(e.team, e2.team)) { + c2++; + chain.teamchain = e2; + e2.teammaster = e; + chain = e2; + e2.flags |= Defines.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. ============== + */ + + public 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(GameBase.skill.value); + + if (skill_level < 0) + skill_level = 0; + if (skill_level > 3) + skill_level = 3; + if (GameBase.skill.value != skill_level) + GameBase.gi.cvar_forceset("skill", "" + skill_level); + + PlayerClient.SaveClientData(); + + //level.clear(); + GameBase.level = new level_locals_t(); + for (int n = 0; n < GameBase.game.maxentities; n++) { + GameBase.g_edicts[n] = new edict_t(n); + } + //memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0])); + GameBase.level.mapname = mapname; + GameBase.game.spawnpoint = spawnpoint; + // set client fields on player ents + for (i = 0; i < GameBase.game.maxclients; i++) + GameBase.g_edicts[i + 1].client = GameBase.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("{")) + GameBase.gi.error("ED_LoadFromFile: found " + com_token + + " when expecting {"); + + if (ent == null) + ent = GameBase.g_edicts[0]; + else + ent = GameUtil.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 == Lib.Q_stricmp(GameBase.level.mapname, "command") + && 0 == Lib.Q_stricmp(ent.classname, "trigger_once") + && 0 == Lib.Q_stricmp(ent.model, "*27")) + ent.spawnflags &= ~Defines.SPAWNFLAG_NOT_HARD; + + // remove things (except the world) from different skill levels or + // deathmatch + if (ent != GameBase.g_edicts[0]) { + if (GameBase.deathmatch.value != 0) { + if ((ent.spawnflags & Defines.SPAWNFLAG_NOT_DEATHMATCH) != 0) { + GameUtil.G_FreeEdict(ent); + inhibit++; + continue; + } + } else { + if (/* + * ((coop.value) && (ent.spawnflags & + * SPAWNFLAG_NOT_COOP)) || + */ + ((GameBase.skill.value == 0) && (ent.spawnflags & Defines.SPAWNFLAG_NOT_EASY) != 0) + || ((GameBase.skill.value == 1) && (ent.spawnflags & Defines.SPAWNFLAG_NOT_MEDIUM) != 0) + || (((GameBase.skill.value == 2) || (GameBase.skill.value == 3)) && (ent.spawnflags & Defines.SPAWNFLAG_NOT_HARD) != 0)) { + GameUtil.G_FreeEdict(ent); + inhibit++; + continue; + } + } + + ent.spawnflags &= ~(Defines.SPAWNFLAG_NOT_EASY + | Defines.SPAWNFLAG_NOT_MEDIUM + | Defines.SPAWNFLAG_NOT_HARD + | Defines.SPAWNFLAG_NOT_COOP | Defines.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 "; + + 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", GameFunc.SP_func_button), + new spawn_t("func_door", GameFunc.SP_func_door), + new spawn_t("func_door_secret", GameFunc.SP_func_door_secret), + new spawn_t("func_door_rotating", GameFunc.SP_func_door_rotating), + new spawn_t("func_rotating", GameFunc.SP_func_rotating), + new spawn_t("func_train", SP_func_train), + new spawn_t("func_water", SP_func_water), + new spawn_t("func_conveyor", GameFunc.SP_func_conveyor), + new spawn_t("func_areaportal", GameMisc.SP_func_areaportal), + new spawn_t("func_clock", SP_func_clock), + new spawn_t("func_wall", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_func_wall(ent); + return true; + } + }), + new spawn_t("func_object", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_func_object(ent); + return true; + } + }), + new spawn_t("func_timer", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameFunc.SP_func_timer(ent); + return true; + } + }), + new spawn_t("func_explosive", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_func_explosive(ent); + return true; + } + }), + new spawn_t("func_killbox", GameFunc.SP_func_killbox), + new spawn_t("trigger_always", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTrigger.SP_trigger_always(ent); + return true; + } + }), + new spawn_t("trigger_once", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTrigger.SP_trigger_once(ent); + return true; + } + }), + new spawn_t("trigger_multiple", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTrigger.SP_trigger_multiple(ent); + return true; + } + }), + new spawn_t("trigger_relay", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTrigger.SP_trigger_relay(ent); + return true; + } + }), + new spawn_t("trigger_push", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTrigger.SP_trigger_push(ent); + return true; + } + }), + new spawn_t("trigger_hurt", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTrigger.SP_trigger_hurt(ent); + return true; + } + }), + new spawn_t("trigger_key", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTrigger.SP_trigger_key(ent); + return true; + } + }), + new spawn_t("trigger_counter", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTrigger.SP_trigger_counter(ent); + return true; + } + }), + new spawn_t("trigger_elevator", GameFunc.SP_trigger_elevator), + new spawn_t("trigger_gravity", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTrigger.SP_trigger_gravity(ent); + return true; + } + }), + new spawn_t("trigger_monsterjump", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTrigger.SP_trigger_monsterjump(ent); + return true; + } + }), + new spawn_t("target_temp_entity", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_temp_entity(ent); + return true; + } + }), + new spawn_t("target_speaker", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_speaker(ent); + return true; + } + }), + new spawn_t("target_explosion", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_explosion(ent); + return true; + } + }), + new spawn_t("target_changelevel", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_changelevel(ent); + return true; + } + }), + new spawn_t("target_secret", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_secret(ent); + return true; + } + }), + new spawn_t("target_goal", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_goal(ent); + return true; + } + }), + new spawn_t("target_splash", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_splash(ent); + return true; + } + }), + new spawn_t("target_spawner", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_spawner(ent); + return true; + } + }), + new spawn_t("target_blaster", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_blaster(ent); + return true; + } + }), + new spawn_t("target_crosslevel_trigger", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_crosslevel_trigger(ent); + return true; + } + }), + new spawn_t("target_crosslevel_target", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_crosslevel_target(ent); + return true; + } + }), + new spawn_t("target_laser", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_laser(ent); + return true; + } + }), + new spawn_t("target_help", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.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) { + GameTarget.SP_target_lightramp(ent); + return true; + } + }), + new spawn_t("target_earthquake", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTarget.SP_target_earthquake(ent); + return true; + } + }), + new spawn_t("target_character", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_target_character(ent); + return true; + } + }), + new spawn_t("target_string", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_target_string(ent); + return true; + } + }), + new spawn_t("worldspawn", SP_worldspawn), + new spawn_t("viewthing", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_viewthing(ent); + return true; + } + }), + new spawn_t("light", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_light(ent); + return true; + } + }), + new spawn_t("light_mine1", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_light_mine1(ent); + return true; + } + }), + new spawn_t("light_mine2", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_light_mine2(ent); + return true; + } + }), + new spawn_t("info_null", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_info_null(ent); + return true; + } + }), + new spawn_t("func_group", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_info_null(ent); + return true; + } + }), + new spawn_t("info_notnull", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_info_notnull(ent); + return true; + } + }), + new spawn_t("path_corner", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_path_corner(ent); + return true; + } + }), + new spawn_t("point_combat", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_point_combat(ent); + return true; + } + }), + new spawn_t("misc_explobox", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_explobox(ent); + return true; + } + }), + new spawn_t("misc_banner", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_banner(ent); + return true; + } + }), + new spawn_t("misc_satellite_dish", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.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) { + GameMisc.SP_misc_gib_arm(ent); + return true; + } + }), + new spawn_t("misc_gib_leg", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_gib_leg(ent); + return true; + } + }), + new spawn_t("misc_gib_head", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.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) { + GameMisc.SP_misc_deadsoldier(ent); + return true; + } + }), + new spawn_t("misc_viper", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_viper(ent); + return true; + } + }), + new spawn_t("misc_viper_bomb", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_viper_bomb(ent); + return true; + } + }), + new spawn_t("misc_bigviper", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_bigviper(ent); + return true; + } + }), + new spawn_t("misc_strogg_ship", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_strogg_ship(ent); + return true; + } + }), + new spawn_t("misc_teleporter", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_teleporter(ent); + return true; + } + }), + new spawn_t("misc_teleporter_dest", + GameMisc.SP_misc_teleporter_dest), + new spawn_t("misc_blackhole", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_blackhole(ent); + return true; + } + }), + new spawn_t("misc_eastertank", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_eastertank(ent); + return true; + } + }), + new spawn_t("misc_easterchick", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.SP_misc_easterchick(ent); + return true; + } + }), + new spawn_t("misc_easterchick2", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameMisc.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) { + GameMisc.SP_monster_commander_body(ent); + return true; + } + }), new spawn_t("turret_breach", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTurret.SP_turret_breach(ent); + return true; + } + }), new spawn_t("turret_base", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTurret.SP_turret_base(ent); + return true; + } + }), new spawn_t("turret_driver", new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameTurret.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) { + GameBase.gi.dprintf("ED_CallSpawn: null classname\n"); + return; + } // check item spawn functions + for (i = 1; i < GameBase.game.num_items; i++) { + + item = GameAI.itemlist[i]; + + if (item == null) + GameBase.gi.error("ED_CallSpawn: null item in pos " + i); + + if (item.classname == null) + continue; + if (item.classname.equalsIgnoreCase(ent.classname)) { // found it + GameAI.SpawnItem(ent, item); + return; + } + } // check normal spawn functions + + for (i = 0; (s = spawns[i]) != null && s.name != null; i++) { + if (s.name.equalsIgnoreCase(ent.classname)) { // found it + + if (s.spawn == null) + GameBase.gi.error("ED_CallSpawn: null-spawn on index=" + i); + s.spawn.think(ent); + return; + } + } + GameBase.gi.dprintf(ent.classname + " doesn't have a spawn function\n"); + } -public class GameSpawn extends GameSave { - - /* - ============= - ED_NewString - ============= - */ - static String ED_NewString(String string) { - - int l = string.length(); - StringBuffer newb = new StringBuffer(l); - - for (int i = 0; i < l; i++) { - char 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) { - byte b; - float v; - float[] vec = { 0, 0, 0 }; - - if (key.equals("nextmap")) - Com.p("nextmap: " + value); - if (!st.set(key, value)) - if (!ent.set(key, value)) - gi.dprintf("??? The key [" + key + "] is not a field\n"); - - } - - /* - ==================== - 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; - - st = new spawn_temp_t(); - 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) - { - GameUtil.G_ClearEdict(ent); - } - - 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 < 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 < 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. - ============== - */ - - public 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(); - 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 "; - - - static spawn_t spawns[] = - { - new spawn_t("item_health", GameSpawnAdapters.SP_item_health), - new spawn_t("item_health_small", GameSpawnAdapters.SP_item_health_small), - new spawn_t("item_health_large", GameSpawnAdapters.SP_item_health_large), - new spawn_t("item_health_mega", GameSpawnAdapters.SP_item_health_mega), - new spawn_t("info_player_start", GameSpawnAdapters.SP_info_player_start), - new spawn_t("info_player_deathmatch", GameSpawnAdapters.SP_info_player_deathmatch), - new spawn_t("info_player_coop", GameSpawnAdapters.SP_info_player_coop), - new spawn_t("info_player_intermission", GameSpawnAdapters.SP_info_player_intermission), - new spawn_t("func_plat", GameSpawnAdapters.SP_func_plat), - new spawn_t("func_button", GameFuncAdapters.SP_func_button), - new spawn_t("func_door", GameFuncAdapters.SP_func_door), - new spawn_t("func_door_secret", GameFuncAdapters.SP_func_door_secret), - new spawn_t("func_door_rotating", GameFuncAdapters.SP_func_door_rotating), - new spawn_t("func_rotating", GameFuncAdapters.SP_func_rotating), - new spawn_t("func_train", GameSpawnAdapters.SP_func_train), - new spawn_t("func_water", GameSpawnAdapters.SP_func_water), - new spawn_t("func_conveyor", GameFuncAdapters.SP_func_conveyor), - new spawn_t("func_areaportal", GameMiscAdapters.SP_func_areaportal), - new spawn_t("func_clock", GameSpawnAdapters.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", GameFuncAdapters.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", GameFuncAdapters.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", GameSpawnAdapters.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", GameMiscAdapters.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_SoldierAdapters.SP_monster_soldier_light), - new spawn_t("monster_soldier", M_SoldierAdapters.SP_monster_soldier), - new spawn_t("monster_soldier_ss", M_SoldierAdapters.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 = GameAI.itemlist[i]; - - if (item == null) - gi.error("ED_CallSpawn: null item in pos " + i); - - if (item.classname == null) - continue; - if (item.classname.equalsIgnoreCase(ent.classname)) { // found it - SpawnItem(ent, item); - return; - } - } // check normal spawn functions - - for (i=0; (s = spawns[i]) !=null && s.name != null; i++) { - if (s.name.equalsIgnoreCase(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"); - } -} +} \ No newline at end of file diff --git a/src/jake2/game/GameSpawnAdapters.java b/src/jake2/game/GameSpawnAdapters.java deleted file mode 100644 index 0a8f06d..0000000 --- a/src/jake2/game/GameSpawnAdapters.java +++ /dev/null @@ -1,220 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: GameSpawnAdapters.java,v 1.1 2004-07-08 15:58:44 hzi Exp $ - -package jake2.game; - -import jake2.Defines; -import jake2.util.*; -import jake2.qcommon.*; - -public class GameSpawnAdapters { - - static EntThinkAdapter SP_item_health = new EntThinkAdapter() {public boolean think(edict_t ent){GameAI.SP_item_health(ent);return true;}}; - static EntThinkAdapter SP_item_health_small = new EntThinkAdapter() {public boolean think(edict_t ent){ GameAI.SP_item_health_small(ent);return true;}}; - static EntThinkAdapter SP_item_health_large = new EntThinkAdapter() {public boolean think(edict_t ent){GameAI.SP_item_health_large(ent); return true;}}; - static EntThinkAdapter SP_item_health_mega = new EntThinkAdapter() {public boolean think(edict_t ent){GameAI.SP_item_health_mega(ent); return true;}}; - static EntThinkAdapter SP_info_player_start = new EntThinkAdapter() {public boolean think(edict_t ent){ PlayerClient.SP_info_player_start(ent);return true;}}; - static EntThinkAdapter SP_info_player_deathmatch = new EntThinkAdapter() {public boolean think(edict_t ent){ PlayerClient.SP_info_player_deathmatch(ent);return true;}}; - static EntThinkAdapter SP_info_player_coop = new EntThinkAdapter() {public boolean think(edict_t ent){PlayerClient.SP_info_player_coop(ent); return true;}}; - static EntThinkAdapter SP_info_player_intermission = new EntThinkAdapter() {public boolean think(edict_t ent){PlayerClient.SP_info_player_intermission(); return true;}}; - static EntThinkAdapter SP_func_plat = new EntThinkAdapter() {public boolean think(edict_t ent){GameFunc.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){GameFunc.SP_func_water(ent); return true;}}; - static EntThinkAdapter SP_func_train = new EntThinkAdapter() {public boolean think(edict_t ent){GameFunc.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){GameMisc.SP_func_clock(ent); return true;}}; - /*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 = Defines.MOVETYPE_PUSH; - ent.solid = Defines.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 - PlayerClient.InitBodyQue(); - // set configstrings for items - GameAI.SetItemNames(); - if (GameBase.st.nextmap != null) - GameBase.level.nextmap = GameBase.st.nextmap; - // make some data visible to the server - if (ent.message != null && ent.message.length() > 0) { - GameBase.gi.configstring(Defines.CS_NAME, ent.message); - GameBase.level.level_name = ent.message; - } - else - GameBase.level.level_name = GameBase.level.mapname; - if (GameBase.st.sky != null && GameBase.st.sky.length() > 0) - GameBase.gi.configstring(Defines.CS_SKY, GameBase.st.sky); - else - GameBase.gi.configstring(Defines.CS_SKY, "unit1_"); - GameBase.gi.configstring(Defines.CS_SKYROTATE, "" + GameBase.st.skyrotate); - GameBase.gi.configstring(Defines.CS_SKYAXIS, Lib.vtos(GameBase.st.skyaxis)); - GameBase.gi.configstring(Defines.CS_CDTRACK, "" + ent.sounds); - GameBase.gi.configstring(Defines.CS_MAXCLIENTS, "" + (int) (GameBase.maxclients.value)); - // status bar program - if (GameBase.deathmatch.value != 0) - GameBase.gi.configstring(Defines.CS_STATUSBAR, "" + GameSpawn.dm_statusbar); - else - GameBase.gi.configstring(Defines.CS_STATUSBAR, "" + GameSpawn.single_statusbar); - //--------------- - // help icon for statusbar - GameBase.gi.imageindex("i_help"); - GameBase.level.pic_health = GameBase.gi.imageindex("i_health"); - GameBase.gi.imageindex("help"); - GameBase.gi.imageindex("field_3"); - if (GameBase.st.gravity != null) - GameBase.gi.cvar_set("sv_gravity", "800"); - else - GameBase.gi.cvar_set("sv_gravity", GameBase.st.gravity); - GameBase.snd_fry = GameBase.gi.soundindex("player/fry.wav"); - // standing in lava / slime - GameAI.PrecacheItem(GameUtil.FindItem("Blaster")); - GameBase.gi.soundindex("player/lava1.wav"); - GameBase.gi.soundindex("player/lava2.wav"); - GameBase.gi.soundindex("misc/pc_up.wav"); - GameBase.gi.soundindex("misc/talk1.wav"); - GameBase.gi.soundindex("misc/udeath.wav"); - // gibs - GameBase.gi.soundindex("items/respawn1.wav"); - // sexed sounds - GameBase.gi.soundindex("*death1.wav"); - GameBase.gi.soundindex("*death2.wav"); - GameBase.gi.soundindex("*death3.wav"); - GameBase.gi.soundindex("*death4.wav"); - GameBase.gi.soundindex("*fall1.wav"); - GameBase.gi.soundindex("*fall2.wav"); - GameBase.gi.soundindex("*gurp1.wav"); - // drowning damage - GameBase.gi.soundindex("*gurp2.wav"); - GameBase.gi.soundindex("*jump1.wav"); - // player jump - GameBase.gi.soundindex("*pain25_1.wav"); - GameBase.gi.soundindex("*pain25_2.wav"); - GameBase.gi.soundindex("*pain50_1.wav"); - GameBase.gi.soundindex("*pain50_2.wav"); - GameBase.gi.soundindex("*pain75_1.wav"); - GameBase.gi.soundindex("*pain75_2.wav"); - GameBase.gi.soundindex("*pain100_1.wav"); - GameBase.gi.soundindex("*pain100_2.wav"); - // sexed models - // THIS ORDER MUST MATCH THE DEFINES IN g_local.h - // you can add more, max 15 - GameBase.gi.modelindex("#w_blaster.md2"); - GameBase.gi.modelindex("#w_shotgun.md2"); - GameBase.gi.modelindex("#w_sshotgun.md2"); - GameBase.gi.modelindex("#w_machinegun.md2"); - GameBase.gi.modelindex("#w_chaingun.md2"); - GameBase.gi.modelindex("#a_grenades.md2"); - GameBase.gi.modelindex("#w_glauncher.md2"); - GameBase.gi.modelindex("#w_rlauncher.md2"); - GameBase.gi.modelindex("#w_hyperblaster.md2"); - GameBase.gi.modelindex("#w_railgun.md2"); - GameBase.gi.modelindex("#w_bfg.md2"); - //------------------- - GameBase.gi.soundindex("player/gasp1.wav"); - // gasping for air - GameBase.gi.soundindex("player/gasp2.wav"); - // head breaking surface, not gasping - GameBase.gi.soundindex("player/watr_in.wav"); - // feet hitting water - GameBase.gi.soundindex("player/watr_out.wav"); - // feet leaving water - GameBase.gi.soundindex("player/watr_un.wav"); - // head going underwater - GameBase.gi.soundindex("player/u_breath1.wav"); - GameBase.gi.soundindex("player/u_breath2.wav"); - GameBase.gi.soundindex("items/pkup.wav"); - // bonus item pickup - GameBase.gi.soundindex("world/land.wav"); - // landing thud - GameBase.gi.soundindex("misc/h2ohit1.wav"); - // landing splash - GameBase.gi.soundindex("items/damage.wav"); - GameBase.gi.soundindex("items/protect.wav"); - GameBase.gi.soundindex("items/protect4.wav"); - GameBase.gi.soundindex("weapons/noammo.wav"); - GameBase.gi.soundindex("infantry/inflies1.wav"); - GameBase.sm_meat_index = GameBase.gi.modelindex("models/objects/gibs/sm_meat/tris.md2"); - GameBase.gi.modelindex("models/objects/gibs/arm/tris.md2"); - GameBase.gi.modelindex("models/objects/gibs/bone/tris.md2"); - GameBase.gi.modelindex("models/objects/gibs/bone2/tris.md2"); - GameBase.gi.modelindex("models/objects/gibs/chest/tris.md2"); - GameBase.gi.modelindex("models/objects/gibs/skull/tris.md2"); - GameBase.gi.modelindex("models/objects/gibs/head2/tris.md2"); - // - // Setup light animation tables. 'a' is total darkness, 'z' is doublebright. - // - // 0 normal - GameBase.gi.configstring(Defines.CS_LIGHTS + 0, "m"); - // 1 FLICKER (first variety) - GameBase.gi.configstring(Defines.CS_LIGHTS + 1, "mmnmmommommnonmmonqnmmo"); - // 2 SLOW STRONG PULSE - GameBase.gi.configstring(Defines.CS_LIGHTS + 2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); - // 3 CANDLE (first variety) - GameBase.gi.configstring(Defines.CS_LIGHTS + 3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); - // 4 FAST STROBE - GameBase.gi.configstring(Defines.CS_LIGHTS + 4, "mamamamamama"); - // 5 GENTLE PULSE 1 - GameBase.gi.configstring(Defines.CS_LIGHTS + 5, "jklmnopqrstuvwxyzyxwvutsrqponmlkj"); - // 6 FLICKER (second variety) - GameBase.gi.configstring(Defines.CS_LIGHTS + 6, "nmonqnmomnmomomno"); - // 7 CANDLE (second variety) - GameBase.gi.configstring(Defines.CS_LIGHTS + 7, "mmmaaaabcdefgmmmmaaaammmaamm"); - // 8 CANDLE (third variety) - GameBase.gi.configstring(Defines.CS_LIGHTS + 8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); - // 9 SLOW STROBE (fourth variety) - GameBase.gi.configstring(Defines.CS_LIGHTS + 9, "aaaaaaaazzzzzzzz"); - // 10 FLUORESCENT FLICKER - GameBase.gi.configstring(Defines.CS_LIGHTS + 10, "mmamammmmammamamaaamammma"); - // 11 SLOW PULSE NOT FADE TO BLACK - GameBase.gi.configstring(Defines.CS_LIGHTS + 11, "abcdefghijklmnopqrrqponmlkjihgfedcba"); - // styles 32-62 are assigned by the light program for switchable lights - // 63 testing - GameBase.gi.configstring(Defines.CS_LIGHTS + 63, "a"); - return true; - } - }; -} diff --git a/src/jake2/game/GameTarget.java b/src/jake2/game/GameTarget.java index 8a13ade..b612168 100644 --- a/src/jake2/game/GameTarget.java +++ b/src/jake2/game/GameTarget.java @@ -1,260 +1,860 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 28.12.2003 by RST. -// $Id: GameTarget.java,v 1.2 2004-07-08 15:58:43 hzi Exp $ - +// $Id: GameTarget.java,v 1.3 2004-09-22 19:22:03 salomo Exp $ package jake2.game; -import jake2.*; -import jake2.client.*; -import jake2.qcommon.*; -import jake2.render.*; -import jake2.server.*; +import jake2.Defines; +import jake2.Globals; import jake2.util.Lib; import jake2.util.Math3D; -public class GameTarget extends GameTurret { - - public static void SP_target_temp_entity(edict_t ent) { - ent.use = GameTargetAdapters.Use_Target_Tent; - } - - public static void SP_target_speaker(edict_t ent) { - //char buffer[MAX_QPATH]; - String buffer; - - if (st.noise == null) { - gi.dprintf("target_speaker with no noise set at " + vtos(ent.s.origin) + "\n"); - return; - } - if (st.noise.indexOf(".wav") < 0) - buffer = "" + st.noise + ".wav"; - //Com_sprintf(buffer, sizeof(buffer), "%s.wav", st.noise); - else - //strncpy(buffer, st.noise, sizeof(buffer)); - buffer = st.noise; - - ent.noise_index = gi.soundindex(buffer); - - if (ent.volume == 0) - ent.volume = 1.0f; - - if (ent.attenuation == 0) - ent.attenuation = 1.0f; - else if (ent.attenuation == -1) // use -1 so 0 defaults to 1 - ent.attenuation = 0; - - // check for prestarted looping sound - if ((ent.spawnflags & 1) != 0) - ent.s.sound = ent.noise_index; - - ent.use = GameTargetAdapters.Use_Target_Speaker; - - // must link the entity so we get areas and clusters so - // the server can determine who to send updates to - gi.linkentity(ent); - } - - /*QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1 - When fired, the "message" key becomes the current personal computer string, and the message light will be set on all clients status bars. - */ - public static void SP_target_help(edict_t ent) { - if (deathmatch.value != 0) { // auto-remove for deathmatch - G_FreeEdict(ent); - return; - } - - if (ent.message == null) { - gi.dprintf(ent.classname + " with no message at " + vtos(ent.s.origin) + "\n"); - G_FreeEdict(ent); - return; - } - ent.use = GameTargetAdapters.Use_Target_Help; - } - - public static void SP_target_secret(edict_t ent) { - if (deathmatch.value != 0) { // auto-remove for deathmatch - G_FreeEdict(ent); - return; - } - - ent.use = GameTargetAdapters.use_target_secret; - if (st.noise == null) - st.noise = "misc/secret.wav"; - ent.noise_index = gi.soundindex(st.noise); - ent.svflags = SVF_NOCLIENT; - level.total_secrets++; - // map bug hack - if (0 == Q_stricmp(level.mapname, "mine3") && ent.s.origin[0] == 280 && ent.s.origin[1] == -2048 && ent.s.origin[2] == -624) - ent.message = "You have found a secret area."; - } - - public static void SP_target_goal(edict_t ent) { - if (deathmatch.value != 0) { // auto-remove for deathmatch - G_FreeEdict(ent); - return; - } - - ent.use = GameTargetAdapters.use_target_goal; - if (st.noise == null) - st.noise = "misc/secret.wav"; - ent.noise_index = gi.soundindex(st.noise); - ent.svflags = SVF_NOCLIENT; - level.total_goals++; - } - - public static void SP_target_explosion(edict_t ent) { - ent.use = GameTargetAdapters.use_target_explosion; - ent.svflags = SVF_NOCLIENT; - } - - public static void SP_target_changelevel(edict_t ent) { - if (ent.map == null) { - gi.dprintf("target_changelevel with no map at " + vtos(ent.s.origin) + "\n"); - G_FreeEdict(ent); - return; - } - - // ugly hack because *SOMEBODY* screwed up their map - if ((Q_stricmp(level.mapname, "fact1") == 0) && (Q_stricmp(ent.map, "fact3") == 0)) - ent.map = "fact3$secret1"; - - ent.use = GameTargetAdapters.use_target_changelevel; - ent.svflags = SVF_NOCLIENT; - } - - public static void SP_target_splash(edict_t self) { - self.use = GameTargetAdapters.use_target_splash; - G_SetMovedir(self.s.angles, self.movedir); - - if (0 == self.count) - self.count = 32; - - self.svflags = SVF_NOCLIENT; - } - - public static void SP_target_spawner(edict_t self) { - self.use = GameTargetAdapters.use_target_spawner; - self.svflags = SVF_NOCLIENT; - if (self.speed != 0) { - G_SetMovedir(self.s.angles, self.movedir); - VectorScale(self.movedir, self.speed, self.movedir); - } - } - - public static void SP_target_blaster(edict_t self) { - self.use = GameTargetAdapters.use_target_blaster; - G_SetMovedir(self.s.angles, self.movedir); - self.noise_index = gi.soundindex("weapons/laser2.wav"); - - if (0 == self.dmg) - self.dmg = 15; - if (0 == self.speed) - self.speed = 1000; - - self.svflags = SVF_NOCLIENT; - } - - public static void SP_target_crosslevel_trigger(edict_t self) { - self.svflags = SVF_NOCLIENT; - self.use = GameTargetAdapters.trigger_crosslevel_trigger_use; - } - - public static void SP_target_crosslevel_target(edict_t self) { - if (0 == self.delay) - self.delay = 1; - self.svflags = SVF_NOCLIENT; - - self.think = GameTargetAdapters.target_crosslevel_target_think; - self.nextthink = level.time + self.delay; - } - - public static void target_laser_on(edict_t self) { - if (null == self.activator) - self.activator = self; - self.spawnflags |= 0x80000001; - self.svflags &= ~SVF_NOCLIENT; - GameTargetAdapters.target_laser_think.think(self); - } - - public static void target_laser_off(edict_t self) { - self.spawnflags &= ~1; - self.svflags |= SVF_NOCLIENT; - self.nextthink = 0; - } - - public static void SP_target_laser(edict_t self) { - // let everything else get spawned before we start firing - self.think = GameTargetAdapters.target_laser_start; - self.nextthink = level.time + 1; - } - - public static void SP_target_lightramp(edict_t self) { - if (self.message == null - || self.message.length() != 2 - || self.message.charAt(0) < 'a' - || self.message.charAt(0) > 'z' - || self.message.charAt(1) < 'a' - || self.message.charAt(1) > 'z' - || self.message.charAt(0) == self.message.charAt(1)) { - gi.dprintf("target_lightramp has bad ramp (" + self.message + ") at " + vtos(self.s.origin) + "\n"); - G_FreeEdict(self); - return; - } - - if (deathmatch.value != 9) { - G_FreeEdict(self); - return; - } - - if (self.target == null) { - gi.dprintf(self.classname + " with no target at " + vtos(self.s.origin) + "\n"); - G_FreeEdict(self); - return; - } - - self.svflags |= SVF_NOCLIENT; - self.use = GameTargetAdapters.target_lightramp_use; - self.think = GameTargetAdapters.target_lightramp_think; - - self.movedir[0] = self.message.charAt(0) - 'a'; - self.movedir[1] = self.message.charAt(1) - 'a'; - self.movedir[2] = (self.movedir[1] - self.movedir[0]) / (self.speed / FRAMETIME); - } - - public static void SP_target_earthquake(edict_t self) { - if (null == self.targetname) - gi.dprintf("untargeted " + self.classname + " at " + vtos(self.s.origin) + "\n"); - - if (0 == self.count) - self.count = 5; - - if (0 == self.speed) - self.speed = 200; - - self.svflags |= SVF_NOCLIENT; - self.think = GameTargetAdapters.target_earthquake_think; - self.use = GameTargetAdapters.target_earthquake_use; - - self.noise_index = gi.soundindex("world/quake.wav"); - } - -} +public class GameTarget { + + public static void SP_target_temp_entity(edict_t ent) { + ent.use = GameTarget.Use_Target_Tent; + } + + public static void SP_target_speaker(edict_t ent) { + //char buffer[MAX_QPATH]; + String buffer; + + if (GameBase.st.noise == null) { + GameBase.gi.dprintf("target_speaker with no noise set at " + + Lib.vtos(ent.s.origin) + "\n"); + return; + } + if (GameBase.st.noise.indexOf(".wav") < 0) + buffer = "" + GameBase.st.noise + ".wav"; + //Com_sprintf(buffer, sizeof(buffer), "%s.wav", st.noise); + else + //strncpy(buffer, st.noise, sizeof(buffer)); + buffer = GameBase.st.noise; + + ent.noise_index = GameBase.gi.soundindex(buffer); + + if (ent.volume == 0) + ent.volume = 1.0f; + + if (ent.attenuation == 0) + ent.attenuation = 1.0f; + else if (ent.attenuation == -1) // use -1 so 0 defaults to 1 + ent.attenuation = 0; + + // check for prestarted looping sound + if ((ent.spawnflags & 1) != 0) + ent.s.sound = ent.noise_index; + + ent.use = GameTarget.Use_Target_Speaker; + + // must link the entity so we get areas and clusters so + // the server can determine who to send updates to + GameBase.gi.linkentity(ent); + } + + /* + * QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1 When fired, the + * "message" key becomes the current personal computer string, and the + * message light will be set on all clients status bars. + */ + public static void SP_target_help(edict_t ent) { + if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch + GameUtil.G_FreeEdict(ent); + return; + } + + if (ent.message == null) { + GameBase.gi.dprintf(ent.classname + " with no message at " + + Lib.vtos(ent.s.origin) + "\n"); + GameUtil.G_FreeEdict(ent); + return; + } + ent.use = GameTarget.Use_Target_Help; + } + + public static void SP_target_secret(edict_t ent) { + if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch + GameUtil.G_FreeEdict(ent); + return; + } + + ent.use = GameTarget.use_target_secret; + if (GameBase.st.noise == null) + GameBase.st.noise = "misc/secret.wav"; + ent.noise_index = GameBase.gi.soundindex(GameBase.st.noise); + ent.svflags = Defines.SVF_NOCLIENT; + GameBase.level.total_secrets++; + // map bug hack + if (0 == Lib.Q_stricmp(GameBase.level.mapname, "mine3") + && ent.s.origin[0] == 280 && ent.s.origin[1] == -2048 + && ent.s.origin[2] == -624) + ent.message = "You have found a secret area."; + } + + public static void SP_target_goal(edict_t ent) { + if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch + GameUtil.G_FreeEdict(ent); + return; + } + + ent.use = GameTarget.use_target_goal; + if (GameBase.st.noise == null) + GameBase.st.noise = "misc/secret.wav"; + ent.noise_index = GameBase.gi.soundindex(GameBase.st.noise); + ent.svflags = Defines.SVF_NOCLIENT; + GameBase.level.total_goals++; + } + + public static void SP_target_explosion(edict_t ent) { + ent.use = GameTarget.use_target_explosion; + ent.svflags = Defines.SVF_NOCLIENT; + } + + public static void SP_target_changelevel(edict_t ent) { + if (ent.map == null) { + GameBase.gi.dprintf("target_changelevel with no map at " + + Lib.vtos(ent.s.origin) + "\n"); + GameUtil.G_FreeEdict(ent); + return; + } + + // ugly hack because *SOMEBODY* screwed up their map + if ((Lib.Q_stricmp(GameBase.level.mapname, "fact1") == 0) + && (Lib.Q_stricmp(ent.map, "fact3") == 0)) + ent.map = "fact3$secret1"; + + ent.use = GameTarget.use_target_changelevel; + ent.svflags = Defines.SVF_NOCLIENT; + } + + public static void SP_target_splash(edict_t self) { + self.use = GameTarget.use_target_splash; + GameBase.G_SetMovedir(self.s.angles, self.movedir); + + if (0 == self.count) + self.count = 32; + + self.svflags = Defines.SVF_NOCLIENT; + } + + public static void SP_target_spawner(edict_t self) { + self.use = GameTarget.use_target_spawner; + self.svflags = Defines.SVF_NOCLIENT; + if (self.speed != 0) { + GameBase.G_SetMovedir(self.s.angles, self.movedir); + Math3D.VectorScale(self.movedir, self.speed, self.movedir); + } + } + + public static void SP_target_blaster(edict_t self) { + self.use = GameTarget.use_target_blaster; + GameBase.G_SetMovedir(self.s.angles, self.movedir); + self.noise_index = GameBase.gi.soundindex("weapons/laser2.wav"); + + if (0 == self.dmg) + self.dmg = 15; + if (0 == self.speed) + self.speed = 1000; + + self.svflags = Defines.SVF_NOCLIENT; + } + + public static void SP_target_crosslevel_trigger(edict_t self) { + self.svflags = Defines.SVF_NOCLIENT; + self.use = GameTarget.trigger_crosslevel_trigger_use; + } + + public static void SP_target_crosslevel_target(edict_t self) { + if (0 == self.delay) + self.delay = 1; + self.svflags = Defines.SVF_NOCLIENT; + + self.think = GameTarget.target_crosslevel_target_think; + self.nextthink = GameBase.level.time + self.delay; + } + + public static void target_laser_on(edict_t self) { + if (null == self.activator) + self.activator = self; + self.spawnflags |= 0x80000001; + self.svflags &= ~Defines.SVF_NOCLIENT; + GameTarget.target_laser_think.think(self); + } + + public static void target_laser_off(edict_t self) { + self.spawnflags &= ~1; + self.svflags |= Defines.SVF_NOCLIENT; + self.nextthink = 0; + } + + public static void SP_target_laser(edict_t self) { + // let everything else get spawned before we start firing + self.think = GameTarget.target_laser_start; + self.nextthink = GameBase.level.time + 1; + } + + public static void SP_target_lightramp(edict_t self) { + if (self.message == null || self.message.length() != 2 + || self.message.charAt(0) < 'a' || self.message.charAt(0) > 'z' + || self.message.charAt(1) < 'a' || self.message.charAt(1) > 'z' + || self.message.charAt(0) == self.message.charAt(1)) { + GameBase.gi.dprintf("target_lightramp has bad ramp (" + + self.message + ") at " + Lib.vtos(self.s.origin) + "\n"); + GameUtil.G_FreeEdict(self); + return; + } + + if (GameBase.deathmatch.value != 9) { + GameUtil.G_FreeEdict(self); + return; + } + + if (self.target == null) { + GameBase.gi.dprintf(self.classname + " with no target at " + + Lib.vtos(self.s.origin) + "\n"); + GameUtil.G_FreeEdict(self); + return; + } + + self.svflags |= Defines.SVF_NOCLIENT; + self.use = GameTarget.target_lightramp_use; + self.think = GameTarget.target_lightramp_think; + + self.movedir[0] = self.message.charAt(0) - 'a'; + self.movedir[1] = self.message.charAt(1) - 'a'; + self.movedir[2] = (self.movedir[1] - self.movedir[0]) + / (self.speed / Defines.FRAMETIME); + } + + public static void SP_target_earthquake(edict_t self) { + if (null == self.targetname) + GameBase.gi.dprintf("untargeted " + self.classname + " at " + + Lib.vtos(self.s.origin) + "\n"); + + if (0 == self.count) + self.count = 5; + + if (0 == self.speed) + self.speed = 200; + + self.svflags |= Defines.SVF_NOCLIENT; + self.think = GameTarget.target_earthquake_think; + self.use = GameTarget.target_earthquake_use; + + self.noise_index = GameBase.gi.soundindex("world/quake.wav"); + } + + /* + * QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8) Fire an origin based + * temp entity event to the clients. "style" type byte + */ + public static EntUseAdapter Use_Target_Tent = new EntUseAdapter() { + public void use(edict_t ent, edict_t other, edict_t activator) { + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(ent.style); + GameBase.gi.WritePosition(ent.s.origin); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + } + }; + + //========================================================== + + //========================================================== + + /* + * QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off + * reliable "noise" wav file to play "attenuation" -1 = none, send to whole + * level 1 = normal fighting sounds 2 = idle sound level 3 = ambient sound + * level "volume" 0.0 to 1.0 + * + * Normal sounds play each time the target is used. The reliable flag can be + * set for crucial voiceovers. + * + * Looped sounds are always atten 3 / vol 1, and the use function toggles it + * on/off. Multiple identical looping sounds will just increase volume + * without any speed cost. + */ + public static EntUseAdapter Use_Target_Speaker = new EntUseAdapter() { + public void use(edict_t ent, edict_t other, edict_t activator) { + int chan; + + if ((ent.spawnflags & 3) != 0) { // looping sound toggles + if (ent.s.sound != 0) + ent.s.sound = 0; // turn it off + else + ent.s.sound = ent.noise_index; // start it + } else { // normal sound + if ((ent.spawnflags & 4) != 0) + chan = Defines.CHAN_VOICE | Defines.CHAN_RELIABLE; + else + chan = Defines.CHAN_VOICE; + // use a positioned_sound, because this entity won't normally be + // sent to any clients because it is invisible + GameBase.gi.positioned_sound(ent.s.origin, ent, chan, + ent.noise_index, ent.volume, ent.attenuation, 0); + } + + } + }; + + //========================================================== + public static EntUseAdapter Use_Target_Help = new EntUseAdapter() { + public void use(edict_t ent, edict_t other, edict_t activator) { + + if ((ent.spawnflags & 1) != 0) + GameBase.game.helpmessage1 = ent.message; + else + GameBase.game.helpmessage2 = ent.message; + + GameBase.game.helpchanged++; + } + }; + + //========================================================== + + /* + * QUAKED target_secret (1 0 1) (-8 -8 -8) (8 8 8) Counts a secret found. + * These are single use targets. + */ + static EntUseAdapter use_target_secret = new EntUseAdapter() { + public void use(edict_t ent, edict_t other, edict_t activator) { + GameBase.gi.sound(ent, Defines.CHAN_VOICE, ent.noise_index, 1, + Defines.ATTN_NORM, 0); + + GameBase.level.found_secrets++; + + GameUtil.G_UseTargets(ent, activator); + GameUtil.G_FreeEdict(ent); + } + }; + + //========================================================== + + /* + * QUAKED target_goal (1 0 1) (-8 -8 -8) (8 8 8) Counts a goal completed. + * These are single use targets. + */ + static EntUseAdapter use_target_goal = new EntUseAdapter() { + public void use(edict_t ent, edict_t other, edict_t activator) { + GameBase.gi.sound(ent, Defines.CHAN_VOICE, ent.noise_index, 1, + Defines.ATTN_NORM, 0); + + GameBase.level.found_goals++; + + if (GameBase.level.found_goals == GameBase.level.total_goals) + GameBase.gi.configstring(Defines.CS_CDTRACK, "0"); + + GameUtil.G_UseTargets(ent, activator); + GameUtil.G_FreeEdict(ent); + } + }; + + //========================================================== + + /* + * QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8) Spawns an explosion + * temporary entity when used. + * + * "delay" wait this long before going off "dmg" how much radius damage + * should be done, defaults to 0 + */ + static EntThinkAdapter target_explosion_explode = new EntThinkAdapter() { + public boolean think(edict_t self) { + + float save; + + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_EXPLOSION1); + GameBase.gi.WritePosition(self.s.origin); + GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS); + + GameUtil.T_RadiusDamage(self, self.activator, self.dmg, null, + self.dmg + 40, Defines.MOD_EXPLOSIVE); + + save = self.delay; + self.delay = 0; + GameUtil.G_UseTargets(self, self.activator); + self.delay = save; + return true; + } + }; + + static EntUseAdapter use_target_explosion = new EntUseAdapter() { + public void use(edict_t self, edict_t other, edict_t activator) { + self.activator = activator; + + if (0 == self.delay) { + target_explosion_explode.think(self); + return; + } + + self.think = target_explosion_explode; + self.nextthink = GameBase.level.time + self.delay; + } + }; + + //========================================================== + + /* + * QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8) Changes level to + * "map" when fired + */ + static EntUseAdapter use_target_changelevel = new EntUseAdapter() { + public void use(edict_t self, edict_t other, edict_t activator) { + if (GameBase.level.intermissiontime != 0) + return; // already activated + + if (0 == GameBase.deathmatch.value && 0 == GameBase.coop.value) { + if (GameBase.g_edicts[1].health <= 0) + return; + } + + // if noexit, do a ton of damage to other + if (GameBase.deathmatch.value != 0 + && 0 == ((int) GameBase.dmflags.value & Defines.DF_ALLOW_EXIT) + && other != GameBase.g_edicts[0] /* world */ + ) { + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, + 10 * other.max_health, 1000, 0, Defines.MOD_EXIT); + return; + } + + // if multiplayer, let everyone know who hit the exit + if (GameBase.deathmatch.value != 0) { + if (activator != null && activator.client != null) + GameBase.gi.bprintf(Defines.PRINT_HIGH, + activator.client.pers.netname + + " exited the level.\n"); + } + + // if going to a new unit, clear cross triggers + if (self.map.indexOf('*') > -1) + GameBase.game.serverflags &= ~(Defines.SFL_CROSS_TRIGGER_MASK); + + PlayerHud.BeginIntermission(self); + } + }; + + //========================================================== + + /* + * QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8) Creates a particle splash + * effect when used. + * + * Set "sounds" to one of the following: 1) sparks 2) blue water 3) brown + * water 4) slime 5) lava 6) blood + * + * "count" how many pixels in the splash "dmg" if set, does a radius damage + * at this location when it splashes useful for lava/sparks + */ + static EntUseAdapter use_target_splash = new EntUseAdapter() { + public void use(edict_t self, edict_t other, edict_t activator) { + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_SPLASH); + GameBase.gi.WriteByte(self.count); + GameBase.gi.WritePosition(self.s.origin); + GameBase.gi.WriteDir(self.movedir); + GameBase.gi.WriteByte(self.sounds); + GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); + + if (self.dmg != 0) + GameUtil.T_RadiusDamage(self, activator, self.dmg, null, + self.dmg + 40, Defines.MOD_SPLASH); + } + }; + + //========================================================== + + /* + * QUAKED target_spawner (1 0 0) (-8 -8 -8) (8 8 8) Set target to the type + * of entity you want spawned. Useful for spawning monsters and gibs in the + * factory levels. + * + * For monsters: Set direction to the facing you want it to have. + * + * For gibs: Set direction if you want it moving and speed how fast it + * should be moving otherwise it will just be dropped + */ + + static EntUseAdapter use_target_spawner = new EntUseAdapter() { + public void use(edict_t self, edict_t other, edict_t activator) { + edict_t ent; + + ent = GameUtil.G_Spawn(); + ent.classname = self.target; + Math3D.VectorCopy(self.s.origin, ent.s.origin); + Math3D.VectorCopy(self.s.angles, ent.s.angles); + GameSpawn.ED_CallSpawn(ent); + GameBase.gi.unlinkentity(ent); + GameUtil.KillBox(ent); + GameBase.gi.linkentity(ent); + if (self.speed != 0) + Math3D.VectorCopy(self.movedir, ent.velocity); + } + }; + + //========================================================== + + /* + * QUAKED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS Fires + * a blaster bolt in the set direction when triggered. + * + * dmg default is 15 speed default is 1000 + */ + public static EntUseAdapter use_target_blaster = new EntUseAdapter() { + public void use(edict_t self, edict_t other, edict_t activator) { + int effect; + + if ((self.spawnflags & 2) != 0) + effect = 0; + else if ((self.spawnflags & 1) != 0) + effect = Defines.EF_HYPERBLASTER; + else + effect = Defines.EF_BLASTER; + + Fire.fire_blaster(self, self.s.origin, self.movedir, self.dmg, + (int) self.speed, Defines.EF_BLASTER, + Defines.MOD_TARGET_BLASTER != 0 + /* true */ + ); + GameBase.gi.sound(self, Defines.CHAN_VOICE, self.noise_index, 1, + Defines.ATTN_NORM, 0); + } + }; + + //========================================================== + + /* + * QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 + * trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 Once this + * trigger is touched/used, any trigger_crosslevel_target with the same + * trigger number is automatically used when a level is started within the + * same unit. It is OK to check multiple triggers. Message, delay, target, + * and killtarget also work. + */ + public static EntUseAdapter trigger_crosslevel_trigger_use = new EntUseAdapter() { + public void use(edict_t self, edict_t other, edict_t activator) { + GameBase.game.serverflags |= self.spawnflags; + GameUtil.G_FreeEdict(self); + } + }; + + /* + * QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 + * trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 Triggered + * by a trigger_crosslevel elsewhere within a unit. If multiple triggers are + * checked, all must be true. Delay, target and killtarget also work. + * + * "delay" delay before using targets if the trigger has been activated + * (default 1) + */ + static EntThinkAdapter target_crosslevel_target_think = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (self.spawnflags == (GameBase.game.serverflags + & Defines.SFL_CROSS_TRIGGER_MASK & self.spawnflags)) { + GameUtil.G_UseTargets(self, self); + GameUtil.G_FreeEdict(self); + } + return true; + } + }; + + //========================================================== + + /* + * QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE + * YELLOW ORANGE FAT When triggered, fires a laser. You can either set a + * target or a direction. + */ + public static EntThinkAdapter target_laser_think = new EntThinkAdapter() { + public boolean think(edict_t self) { + + edict_t ignore; + float[] start = { 0, 0, 0 }; + float[] end = { 0, 0, 0 }; + trace_t tr; + float[] point = { 0, 0, 0 }; + float[] last_movedir = { 0, 0, 0 }; + int count; + + if ((self.spawnflags & 0x80000000) != 0) + count = 8; + else + count = 4; + + if (self.enemy != null) { + Math3D.VectorCopy(self.movedir, last_movedir); + Math3D + .VectorMA(self.enemy.absmin, 0.5f, self.enemy.size, + point); + Math3D.VectorSubtract(point, self.s.origin, self.movedir); + Math3D.VectorNormalize(self.movedir); + if (0 == Math3D.VectorCompare(self.movedir, last_movedir)) + self.spawnflags |= 0x80000000; + } + + ignore = self; + Math3D.VectorCopy(self.s.origin, start); + Math3D.VectorMA(start, 2048, self.movedir, end); + while (true) { + tr = GameBase.gi.trace(start, null, null, end, ignore, + Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER + | Defines.CONTENTS_DEADMONSTER); + + if (tr.ent == null) + break; + + // hurt it if we can + if ((tr.ent.takedamage != 0) + && 0 == (tr.ent.flags & Defines.FL_IMMUNE_LASER)) + GameUtil.T_Damage(tr.ent, self, self.activator, + self.movedir, tr.endpos, Globals.vec3_origin, + self.dmg, 1, Defines.DAMAGE_ENERGY, + Defines.MOD_TARGET_LASER); + + // if we hit something that's not a monster or player or is + // immune to lasers, we're done + if (0 == (tr.ent.svflags & Defines.SVF_MONSTER) + && (null == tr.ent.client)) { + if ((self.spawnflags & 0x80000000) != 0) { + self.spawnflags &= ~0x80000000; + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_LASER_SPARKS); + GameBase.gi.WriteByte(count); + GameBase.gi.WritePosition(tr.endpos); + GameBase.gi.WriteDir(tr.plane.normal); + GameBase.gi.WriteByte(self.s.skinnum); + GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS); + } + break; + } + + ignore = tr.ent; + Math3D.VectorCopy(tr.endpos, start); + } + + Math3D.VectorCopy(tr.endpos, self.s.old_origin); + + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + return true; + } + }; + + public static EntUseAdapter target_laser_use = new EntUseAdapter() { + + public void use(edict_t self, edict_t other, edict_t activator) { + self.activator = activator; + if ((self.spawnflags & 1) != 0) + GameTarget.target_laser_off(self); + else + GameTarget.target_laser_on(self); + } + }; + + static EntThinkAdapter target_laser_start = new EntThinkAdapter() { + public boolean think(edict_t self) { + + edict_t ent; + + self.movetype = Defines.MOVETYPE_NONE; + self.solid = Defines.SOLID_NOT; + self.s.renderfx |= Defines.RF_BEAM | Defines.RF_TRANSLUCENT; + self.s.modelindex = 1; // must be non-zero + + // set the beam diameter + if ((self.spawnflags & 64) != 0) + self.s.frame = 16; + else + self.s.frame = 4; + + // set the color + if ((self.spawnflags & 2) != 0) + self.s.skinnum = 0xf2f2f0f0; + else if ((self.spawnflags & 4) != 0) + self.s.skinnum = 0xd0d1d2d3; + else if ((self.spawnflags & 8) != 0) + self.s.skinnum = 0xf3f3f1f1; + else if ((self.spawnflags & 16) != 0) + self.s.skinnum = 0xdcdddedf; + else if ((self.spawnflags & 32) != 0) + self.s.skinnum = 0xe0e1e2e3; + + if (null == self.enemy) { + if (self.target != null) { + ent = GameBase.G_Find(null, GameBase.findByTarget, + self.target).o; + if (ent == null) + GameBase.gi.dprintf(self.classname + " at " + + Lib.vtos(self.s.origin) + ": " + self.target + + " is a bad target\n"); + self.enemy = ent; + } else { + GameBase.G_SetMovedir(self.s.angles, self.movedir); + } + } + self.use = target_laser_use; + self.think = target_laser_think; + + if (0 == self.dmg) + self.dmg = 1; + + Math3D.VectorSet(self.mins, -8, -8, -8); + Math3D.VectorSet(self.maxs, 8, 8, 8); + GameBase.gi.linkentity(self); + + if ((self.spawnflags & 1) != 0) + GameTarget.target_laser_on(self); + else + GameTarget.target_laser_off(self); + return true; + } + }; + + //========================================================== + + /* + * QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE speed How + * many seconds the ramping will take message two letters; starting + * lightlevel and ending lightlevel + */ + + static EntThinkAdapter target_lightramp_think = new EntThinkAdapter() { + public boolean think(edict_t self) { + + char style[] = { ' ', ' ' }; + + style[0] = (char) ('a' + (int) (self.movedir[0] + (GameBase.level.time - self.timestamp) + / Defines.FRAMETIME * self.movedir[2])); + style[1] = 0; + GameBase.gi.configstring(Defines.CS_LIGHTS + self.enemy.style, + new String(style)); + + if ((GameBase.level.time - self.timestamp) < self.speed) { + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + } else if ((self.spawnflags & 1) != 0) { + char temp; + + temp = (char) self.movedir[0]; + self.movedir[0] = self.movedir[1]; + self.movedir[1] = temp; + self.movedir[2] *= -1; + } + + return true; + } + }; + + static EntUseAdapter target_lightramp_use = new EntUseAdapter() { + public void use(edict_t self, edict_t other, edict_t activator) { + if (self.enemy == null) { + edict_t e; + + // check all the targets + e = null; + EdictIterator es = null; + + while (true) { + es = GameBase + .G_Find(es, GameBase.findByTarget, self.target); + e = es.o; + + if (e == null) + break; + if (Lib.strcmp(e.classname, "light") != 0) { + GameBase.gi.dprintf(self.classname + " at " + + Lib.vtos(self.s.origin)); + GameBase.gi.dprintf("target " + self.target + " (" + + e.classname + " at " + Lib.vtos(e.s.origin) + + ") is not a light\n"); + } else { + self.enemy = e; + } + } + + if (null == self.enemy) { + GameBase.gi.dprintf(self.classname + " target " + + self.target + " not found at " + + Lib.vtos(self.s.origin) + "\n"); + GameUtil.G_FreeEdict(self); + return; + } + } + + self.timestamp = GameBase.level.time; + target_lightramp_think.think(self); + } + }; + + //========================================================== + + /* + * QUAKED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8) When triggered, this + * initiates a level-wide earthquake. All players and monsters are affected. + * "speed" severity of the quake (default:200) "count" duration of the quake + * (default:5) + */ + + static EntThinkAdapter target_earthquake_think = new EntThinkAdapter() { + public boolean think(edict_t self) { + + int i; + edict_t e; + + if (self.last_move_time < GameBase.level.time) { + GameBase.gi.positioned_sound(self.s.origin, self, + Defines.CHAN_AUTO, self.noise_index, 1.0f, + Defines.ATTN_NONE, 0); + self.last_move_time = GameBase.level.time + 0.5f; + } + + for (i = 1; i < GameBase.num_edicts; i++) { + e = GameBase.g_edicts[i]; + + if (!e.inuse) + continue; + if (null == e.client) + continue; + if (null == e.groundentity) + continue; + + e.groundentity = null; + e.velocity[0] += Lib.crandom() * 150; + e.velocity[1] += Lib.crandom() * 150; + e.velocity[2] = self.speed * (100.0f / e.mass); + } + + if (GameBase.level.time < self.timestamp) + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + + return true; + } + }; + + static EntUseAdapter target_earthquake_use = new EntUseAdapter() { + public void use(edict_t self, edict_t other, edict_t activator) { + self.timestamp = GameBase.level.time + self.count; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + self.activator = activator; + self.last_move_time = 0; + } + }; +} \ No newline at end of file diff --git a/src/jake2/game/GameTargetAdapters.java b/src/jake2/game/GameTargetAdapters.java deleted file mode 100644 index 5833c52..0000000 --- a/src/jake2/game/GameTargetAdapters.java +++ /dev/null @@ -1,581 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: GameTargetAdapters.java,v 1.4 2004-09-10 19:02:53 salomo Exp $ - -package jake2.game; - -import jake2.Defines; -import jake2.Globals; -import jake2.util.Lib; -import jake2.util.Math3D; - -public class GameTargetAdapters { - - /*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8) - Fire an origin based temp entity event to the clients. - "style" type byte - */ - public static EntUseAdapter Use_Target_Tent = new EntUseAdapter() { - public void use(edict_t ent, edict_t other, edict_t activator) { - GameBase.gi.WriteByte(Defines.svc_temp_entity); - GameBase.gi.WriteByte(ent.style); - GameBase.gi.WritePosition(ent.s.origin); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); - } - }; - //========================================================== - - //========================================================== - - /*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off reliable - "noise" wav file to play - "attenuation" - -1 = none, send to whole level - 1 = normal fighting sounds - 2 = idle sound level - 3 = ambient sound level - "volume" 0.0 to 1.0 - - Normal sounds play each time the target is used. The reliable flag can be set for crucial voiceovers. - - Looped sounds are always atten 3 / vol 1, and the use function toggles it on/off. - Multiple identical looping sounds will just increase volume without any speed cost. - */ - public static EntUseAdapter Use_Target_Speaker = new EntUseAdapter() { - public void use(edict_t ent, edict_t other, edict_t activator) { - int chan; - - if ((ent.spawnflags & 3) != 0) { // looping sound toggles - if (ent.s.sound != 0) - ent.s.sound = 0; // turn it off - else - ent.s.sound = ent.noise_index; // start it - } - else { // normal sound - if ((ent.spawnflags & 4) != 0) - chan = Defines.CHAN_VOICE | Defines.CHAN_RELIABLE; - else - chan = Defines.CHAN_VOICE; - // use a positioned_sound, because this entity won't normally be - // sent to any clients because it is invisible - GameBase.gi.positioned_sound(ent.s.origin, ent, chan, ent.noise_index, ent.volume, ent.attenuation, 0); - } - - } - }; - //========================================================== - public static EntUseAdapter Use_Target_Help = new EntUseAdapter() { - public void use(edict_t ent, edict_t other, edict_t activator) { - - if ((ent.spawnflags & 1) != 0) - GameBase.game.helpmessage1 = ent.message; - else - GameBase.game.helpmessage2 = ent.message; - - GameBase.game.helpchanged++; - } - }; - //========================================================== - - /*QUAKED target_secret (1 0 1) (-8 -8 -8) (8 8 8) - Counts a secret found. - These are single use targets. - */ - static EntUseAdapter use_target_secret = new EntUseAdapter() { - public void use(edict_t ent, edict_t other, edict_t activator) { - GameBase.gi.sound(ent, Defines.CHAN_VOICE, ent.noise_index, 1, Defines.ATTN_NORM, 0); - - GameBase.level.found_secrets++; - - GameUtil.G_UseTargets(ent, activator); - GameUtil.G_FreeEdict(ent); - } - }; - //========================================================== - - /*QUAKED target_goal (1 0 1) (-8 -8 -8) (8 8 8) - Counts a goal completed. - These are single use targets. - */ - static EntUseAdapter use_target_goal = new EntUseAdapter() { - public void use(edict_t ent, edict_t other, edict_t activator) { - GameBase.gi.sound(ent, Defines.CHAN_VOICE, ent.noise_index, 1, Defines.ATTN_NORM, 0); - - GameBase.level.found_goals++; - - if (GameBase.level.found_goals == GameBase.level.total_goals) - GameBase.gi.configstring(Defines.CS_CDTRACK, "0"); - - GameUtil.G_UseTargets(ent, activator); - GameUtil.G_FreeEdict(ent); - } - }; - //========================================================== - - /*QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8) - Spawns an explosion temporary entity when used. - - "delay" wait this long before going off - "dmg" how much radius damage should be done, defaults to 0 - */ - static EntThinkAdapter target_explosion_explode = new EntThinkAdapter() { - public boolean think(edict_t self) { - - float save; - - GameBase.gi.WriteByte(Defines.svc_temp_entity); - GameBase.gi.WriteByte(Defines.TE_EXPLOSION1); - GameBase.gi.WritePosition(self.s.origin); - GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS); - - GameUtil.T_RadiusDamage(self, self.activator, self.dmg, null, self.dmg + 40, Defines.MOD_EXPLOSIVE); - - save = self.delay; - self.delay = 0; - GameUtil.G_UseTargets(self, self.activator); - self.delay = save; - return true; - } - }; - static EntUseAdapter use_target_explosion = new EntUseAdapter() { - public void use(edict_t self, edict_t other, edict_t activator) { - self.activator = activator; - - if (0 == self.delay) { - target_explosion_explode.think(self); - return; - } - - self.think = target_explosion_explode; - self.nextthink = GameBase.level.time + self.delay; - } - }; - //========================================================== - - /*QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8) - Changes level to "map" when fired - */ - static EntUseAdapter use_target_changelevel = new EntUseAdapter() { - public void use(edict_t self, edict_t other, edict_t activator) { - if (GameBase.level.intermissiontime != 0) - return; // already activated - - if (0 == GameBase.deathmatch.value && 0 == GameBase.coop.value) { - if (GameBase.g_edicts[1].health <= 0) - return; - } - - // if noexit, do a ton of damage to other - if (GameBase.deathmatch.value != 0 && 0 == ((int) GameBase.dmflags.value & Defines.DF_ALLOW_EXIT) && other != GameBase.g_edicts[0] /*world*/ - ) { - GameUtil.T_Damage(other, self, self, Globals.vec3_origin, other.s.origin, Globals.vec3_origin, 10 * other.max_health, 1000, 0, Defines.MOD_EXIT); - return; - } - - // if multiplayer, let everyone know who hit the exit - if (GameBase.deathmatch.value != 0) { - if (activator != null && activator.client != null) - GameBase.gi.bprintf(Defines.PRINT_HIGH, activator.client.pers.netname + " exited the level.\n"); - } - - // if going to a new unit, clear cross triggers - if (self.map.indexOf('*') > -1) - GameBase.game.serverflags &= ~(Defines.SFL_CROSS_TRIGGER_MASK); - - PlayerHud.BeginIntermission(self); - } - }; - //========================================================== - - /*QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8) - Creates a particle splash effect when used. - - Set "sounds" to one of the following: - 1) sparks - 2) blue water - 3) brown water - 4) slime - 5) lava - 6) blood - - "count" how many pixels in the splash - "dmg" if set, does a radius damage at this location when it splashes - useful for lava/sparks - */ - static EntUseAdapter use_target_splash = new EntUseAdapter() { - public void use(edict_t self, edict_t other, edict_t activator) { - GameBase.gi.WriteByte(Defines.svc_temp_entity); - GameBase.gi.WriteByte(Defines.TE_SPLASH); - GameBase.gi.WriteByte(self.count); - GameBase.gi.WritePosition(self.s.origin); - GameBase.gi.WriteDir(self.movedir); - GameBase.gi.WriteByte(self.sounds); - GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); - - if (self.dmg != 0) - GameUtil.T_RadiusDamage(self, activator, self.dmg, null, self.dmg + 40, Defines.MOD_SPLASH); - } - }; - //========================================================== - - /*QUAKED target_spawner (1 0 0) (-8 -8 -8) (8 8 8) - Set target to the type of entity you want spawned. - Useful for spawning monsters and gibs in the factory levels. - - For monsters: - Set direction to the facing you want it to have. - - For gibs: - Set direction if you want it moving and - speed how fast it should be moving otherwise it - will just be dropped - */ - - static EntUseAdapter use_target_spawner = new EntUseAdapter() { - public void use(edict_t self, edict_t other, edict_t activator) { - edict_t ent; - - ent = GameUtil.G_Spawn(); - ent.classname = self.target; - Math3D.VectorCopy(self.s.origin, ent.s.origin); - Math3D.VectorCopy(self.s.angles, ent.s.angles); - GameSpawn.ED_CallSpawn(ent); - GameBase.gi.unlinkentity(ent); - GameUtil.KillBox(ent); - GameBase.gi.linkentity(ent); - if (self.speed != 0) - Math3D.VectorCopy(self.movedir, ent.velocity); - } - }; - //========================================================== - - /*QUAKED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS - Fires a blaster bolt in the set direction when triggered. - - dmg default is 15 - speed default is 1000 - */ - public static EntUseAdapter use_target_blaster = new EntUseAdapter() { - public void use(edict_t self, edict_t other, edict_t activator) { - int effect; - - if ((self.spawnflags & 2) != 0) - effect = 0; - else if ((self.spawnflags & 1) != 0) - effect = Defines.EF_HYPERBLASTER; - else - effect = Defines.EF_BLASTER; - - Fire.fire_blaster(self, self.s.origin, self.movedir, self.dmg, (int) self.speed, Defines.EF_BLASTER, Defines.MOD_TARGET_BLASTER != 0 - /*true*/ - ); - GameBase.gi.sound(self, Defines.CHAN_VOICE, self.noise_index, 1, Defines.ATTN_NORM, 0); - } - }; - //========================================================== - - /*QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 - Once this trigger is touched/used, any trigger_crosslevel_target with the same trigger number is automatically used when a level is started within the same unit. It is OK to check multiple triggers. Message, delay, target, and killtarget also work. - */ - public static EntUseAdapter trigger_crosslevel_trigger_use = new EntUseAdapter() { - public void use(edict_t self, edict_t other, edict_t activator) { - GameBase.game.serverflags |= self.spawnflags; - GameUtil.G_FreeEdict(self); - } - }; - /*QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 - Triggered by a trigger_crosslevel elsewhere within a unit. If multiple triggers are checked, all must be true. Delay, target and - killtarget also work. - - "delay" delay before using targets if the trigger has been activated (default 1) - */ - static EntThinkAdapter target_crosslevel_target_think = new EntThinkAdapter() { - public boolean think(edict_t self) { - if (self.spawnflags == (GameBase.game.serverflags & Defines.SFL_CROSS_TRIGGER_MASK & self.spawnflags)) { - GameUtil.G_UseTargets(self, self); - GameUtil.G_FreeEdict(self); - } - return true; - } - }; - //========================================================== - - /*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE YELLOW ORANGE FAT - When triggered, fires a laser. You can either set a target - or a direction. - */ - public static EntThinkAdapter target_laser_think = new EntThinkAdapter() { - public boolean think(edict_t self) { - - edict_t ignore; - float[] start = { 0, 0, 0 }; - float[] end = { 0, 0, 0 }; - trace_t tr; - float[] point = { 0, 0, 0 }; - float[] last_movedir = { 0, 0, 0 }; - int count; - - if ((self.spawnflags & 0x80000000) != 0) - count = 8; - else - count = 4; - - if (self.enemy != null) { - Math3D.VectorCopy(self.movedir, last_movedir); - Math3D.VectorMA(self.enemy.absmin, 0.5f, self.enemy.size, point); - Math3D.VectorSubtract(point, self.s.origin, self.movedir); - Math3D.VectorNormalize(self.movedir); - if (0 == Math3D.VectorCompare(self.movedir, last_movedir)) - self.spawnflags |= 0x80000000; - } - - ignore = self; - Math3D.VectorCopy(self.s.origin, start); - Math3D.VectorMA(start, 2048, self.movedir, end); - while (true) { - tr = GameBase.gi.trace(start, null, null, end, ignore, Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER | Defines.CONTENTS_DEADMONSTER); - - if (tr.ent == null) - break; - - // hurt it if we can - if ((tr.ent.takedamage != 0) && 0 == (tr.ent.flags & Defines.FL_IMMUNE_LASER)) - GameUtil.T_Damage( - tr.ent, - self, - self.activator, - self.movedir, - tr.endpos, - Globals.vec3_origin, - self.dmg, - 1, - Defines.DAMAGE_ENERGY, - Defines.MOD_TARGET_LASER); - - // if we hit something that's not a monster or player or is immune to lasers, we're done - if (0 == (tr.ent.svflags & Defines.SVF_MONSTER) && (null == tr.ent.client)) { - if ((self.spawnflags & 0x80000000) != 0) { - self.spawnflags &= ~0x80000000; - GameBase.gi.WriteByte(Defines.svc_temp_entity); - GameBase.gi.WriteByte(Defines.TE_LASER_SPARKS); - GameBase.gi.WriteByte(count); - GameBase.gi.WritePosition(tr.endpos); - GameBase.gi.WriteDir(tr.plane.normal); - GameBase.gi.WriteByte(self.s.skinnum); - GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS); - } - break; - } - - ignore = tr.ent; - Math3D.VectorCopy(tr.endpos, start); - } - - Math3D.VectorCopy(tr.endpos, self.s.old_origin); - - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - return true; - } - }; - public static EntUseAdapter target_laser_use = new EntUseAdapter() { - - public void use(edict_t self, edict_t other, edict_t activator) { - self.activator = activator; - if ((self.spawnflags & 1) != 0) - GameTarget.target_laser_off(self); - else - GameTarget.target_laser_on(self); - } - }; - static EntThinkAdapter target_laser_start = new EntThinkAdapter() { - public boolean think(edict_t self) { - - edict_t ent; - - self.movetype = Defines.MOVETYPE_NONE; - self.solid = Defines.SOLID_NOT; - self.s.renderfx |= Defines.RF_BEAM | Defines.RF_TRANSLUCENT; - self.s.modelindex = 1; // must be non-zero - - // set the beam diameter - if ((self.spawnflags & 64) != 0) - self.s.frame = 16; - else - self.s.frame = 4; - - // set the color - if ((self.spawnflags & 2) != 0) - self.s.skinnum = 0xf2f2f0f0; - else if ((self.spawnflags & 4) != 0) - self.s.skinnum = 0xd0d1d2d3; - else if ((self.spawnflags & 8) != 0) - self.s.skinnum = 0xf3f3f1f1; - else if ((self.spawnflags & 16) != 0) - self.s.skinnum = 0xdcdddedf; - else if ((self.spawnflags & 32) != 0) - self.s.skinnum = 0xe0e1e2e3; - - if (null == self.enemy) { - if (self.target != null) { - ent = GameBase.G_Find(null, GameBase.findByTarget, self.target).o; - if (ent == null) - GameBase.gi.dprintf(self.classname + " at " + Lib.vtos(self.s.origin) + ": " + self.target + " is a bad target\n"); - self.enemy = ent; - } - else { - GameBase.G_SetMovedir(self.s.angles, self.movedir); - } - } - self.use = target_laser_use; - self.think = target_laser_think; - - if (0 == self.dmg) - self.dmg = 1; - - Math3D.VectorSet(self.mins, -8, -8, -8); - Math3D.VectorSet(self.maxs, 8, 8, 8); - GameBase.gi.linkentity(self); - - if ((self.spawnflags & 1) != 0) - GameTarget.target_laser_on(self); - else - GameTarget.target_laser_off(self); - return true; - } - }; - //========================================================== - - /*QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE - speed How many seconds the ramping will take - message two letters; starting lightlevel and ending lightlevel - */ - - static EntThinkAdapter target_lightramp_think = new EntThinkAdapter() { - public boolean think(edict_t self) { - - char style[] = { ' ', ' ' }; - - style[0] = (char) ('a' + (int) (self.movedir[0] + (GameBase.level.time - self.timestamp) / Defines.FRAMETIME * self.movedir[2])); - style[1] = 0; - GameBase.gi.configstring(Defines.CS_LIGHTS + self.enemy.style, new String(style)); - - if ((GameBase.level.time - self.timestamp) < self.speed) { - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - } - else if ((self.spawnflags & 1) != 0) { - char temp; - - temp = (char) self.movedir[0]; - self.movedir[0] = self.movedir[1]; - self.movedir[1] = temp; - self.movedir[2] *= -1; - } - - return true; - } - }; - static EntUseAdapter target_lightramp_use = new EntUseAdapter() { - public void use(edict_t self, edict_t other, edict_t activator) { - if (self.enemy == null) { - edict_t e; - - // check all the targets - e = null; - EdictIterator es = null; - - while (true) { - es = GameBase.G_Find(es, GameBase.findByTarget, self.target); - e = es.o; - - if (e == null) - break; - if (Lib.strcmp(e.classname, "light") != 0) { - GameBase.gi.dprintf(self.classname + " at " + Lib.vtos(self.s.origin)); - GameBase.gi.dprintf("target " + self.target + " (" + e.classname + " at " + Lib.vtos(e.s.origin) + ") is not a light\n"); - } - else { - self.enemy = e; - } - } - - if (null == self.enemy) { - GameBase.gi.dprintf(self.classname + " target " + self.target + " not found at " + Lib.vtos(self.s.origin) + "\n"); - GameUtil.G_FreeEdict(self); - return; - } - } - - self.timestamp = GameBase.level.time; - target_lightramp_think.think(self); - } - }; - //========================================================== - - /*QUAKED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8) - When triggered, this initiates a level-wide earthquake. - All players and monsters are affected. - "speed" severity of the quake (default:200) - "count" duration of the quake (default:5) - */ - - static EntThinkAdapter target_earthquake_think = new EntThinkAdapter() { - public boolean think(edict_t self) { - - int i; - edict_t e; - - if (self.last_move_time < GameBase.level.time) { - GameBase.gi.positioned_sound(self.s.origin, self, Defines.CHAN_AUTO, self.noise_index, 1.0f, Defines.ATTN_NONE, 0); - self.last_move_time = GameBase.level.time + 0.5f; - } - - for (i = 1; i < GameBase.num_edicts; i++) { - e = GameBase.g_edicts[i]; - - if (!e.inuse) - continue; - if (null == e.client) - continue; - if (null == e.groundentity) - continue; - - e.groundentity = null; - e.velocity[0] += Lib.crandom() * 150; - e.velocity[1] += Lib.crandom() * 150; - e.velocity[2] = self.speed * (100.0f / e.mass); - } - - if (GameBase.level.time < self.timestamp) - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - - return true; - } - }; - static EntUseAdapter target_earthquake_use = new EntUseAdapter() { - public void use(edict_t self, edict_t other, edict_t activator) { - self.timestamp = GameBase.level.time + self.count; - self.nextthink = GameBase.level.time + Defines.FRAMETIME; - self.activator = activator; - self.last_move_time = 0; - } - }; -} diff --git a/src/jake2/game/GameTrigger.java b/src/jake2/game/GameTrigger.java index 281fa4c..00964e7 100644 --- a/src/jake2/game/GameTrigger.java +++ b/src/jake2/game/GameTrigger.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 27.12.2003 by RST. -// $Id: GameTrigger.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ - +// $Id: GameTrigger.java,v 1.3 2004-09-22 19:22:06 salomo Exp $ package jake2.game; import jake2.*; @@ -31,209 +30,566 @@ import jake2.server.*; import jake2.util.Lib; import jake2.util.Math3D; -public class GameTrigger extends M_Player { - - 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 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 = GameTriggerAdapters.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 = GameUtilAdapters.G_FreeEdictA; - } - } - - 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 = GameTriggerAdapters.Touch_Multi; - ent.movetype = MOVETYPE_NONE; - ent.svflags |= SVF_NOCLIENT; - - if ((ent.spawnflags & 4) != 0) { - ent.solid = SOLID_NOT; - ent.use = GameTriggerAdapters.trigger_enable; - } - else { - ent.solid = SOLID_TRIGGER; - ent.use = GameTriggerAdapters.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); - } - - public static void SP_trigger_relay(edict_t self) { - self.use = GameTriggerAdapters.trigger_relay_use; - } - - 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 = GameTriggerAdapters.trigger_key_use; - } - - public static void SP_trigger_counter(edict_t self) { - self.wait = -1; - if (0 == self.count) - self.count = 2; - - self.use = GameTriggerAdapters.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); - } - - /*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); - GameTriggerAdapters.windsound = gi.soundindex("misc/windfly.wav"); - self.touch = GameTriggerAdapters.trigger_push_touch; - if (0 == self.speed) - self.speed = 1000; - gi.linkentity(self); - } - - public static void SP_trigger_hurt(edict_t self) { - InitTrigger(self); - - self.noise_index = gi.soundindex("world/electro.wav"); - self.touch = GameTriggerAdapters.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 = GameTriggerAdapters.hurt_use; - - gi.linkentity(self); - } - - 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 = GameTriggerAdapters.trigger_gravity_touch; - } - - 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 = GameTriggerAdapters.trigger_monsterjump_touch; - self.movedir[2] = st.height; - } - -} +public class GameTrigger { + + public static void InitTrigger(edict_t self) { + if (Math3D.VectorCompare(self.s.angles, Globals.vec3_origin) != 0) + GameBase.G_SetMovedir(self.s.angles, self.movedir); + + self.solid = Defines.SOLID_TRIGGER; + self.movetype = Defines.MOVETYPE_NONE; + GameBase.gi.setmodel(self, self.model); + self.svflags = Defines.SVF_NOCLIENT; + } + + // 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 + + GameUtil.G_UseTargets(ent, ent.activator); + + if (ent.wait > 0) { + ent.think = GameTrigger.multi_wait; + ent.nextthink = GameBase.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 = GameBase.level.time + Defines.FRAMETIME; + ent.think = GameUtil.G_FreeEdictA; + } + } + + public static void SP_trigger_multiple(edict_t ent) { + if (ent.sounds == 1) + ent.noise_index = GameBase.gi.soundindex("misc/secret.wav"); + else if (ent.sounds == 2) + ent.noise_index = GameBase.gi.soundindex("misc/talk.wav"); + else if (ent.sounds == 3) + ent.noise_index = GameBase.gi.soundindex("misc/trigger1.wav"); + + if (ent.wait == 0) + ent.wait = 0.2f; + + ent.touch = GameTrigger.Touch_Multi; + ent.movetype = Defines.MOVETYPE_NONE; + ent.svflags |= Defines.SVF_NOCLIENT; + + if ((ent.spawnflags & 4) != 0) { + ent.solid = Defines.SOLID_NOT; + ent.use = GameTrigger.trigger_enable; + } else { + ent.solid = Defines.SOLID_TRIGGER; + ent.use = GameTrigger.Use_Multi; + } + + if (0 == Math3D.VectorCompare(ent.s.angles, Globals.vec3_origin)) + GameBase.G_SetMovedir(ent.s.angles, ent.movedir); + + GameBase.gi.setmodel(ent, ent.model); + GameBase.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 }; + + Math3D.VectorMA(ent.mins, 0.5f, ent.size, v); + ent.spawnflags &= ~1; + ent.spawnflags |= 4; + GameBase.gi.dprintf("fixed TRIGGERED flag on " + ent.classname + + " at " + Lib.vtos(v) + "\n"); + } + + ent.wait = -1; + SP_trigger_multiple(ent); + } + + public static void SP_trigger_relay(edict_t self) { + self.use = GameTrigger.trigger_relay_use; + } + + public static void SP_trigger_key(edict_t self) { + if (GameBase.st.item == null) { + GameBase.gi.dprintf("no key item for trigger_key at " + + Lib.vtos(self.s.origin) + "\n"); + return; + } + self.item = GameUtil.FindItemByClassname(GameBase.st.item); + + if (null == self.item) { + GameBase.gi.dprintf("item " + GameBase.st.item + + " not found for trigger_key at " + + Lib.vtos(self.s.origin) + "\n"); + return; + } + + if (self.target == null) { + GameBase.gi.dprintf(self.classname + " at " + + Lib.vtos(self.s.origin) + " has no target\n"); + return; + } + + GameBase.gi.soundindex("misc/keytry.wav"); + GameBase.gi.soundindex("misc/keyuse.wav"); + + self.use = GameTrigger.trigger_key_use; + } + + public static void SP_trigger_counter(edict_t self) { + self.wait = -1; + if (0 == self.count) + self.count = 2; + + self.use = GameTrigger.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; + GameUtil.G_UseTargets(ent, ent); + } + + /* + * 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); + GameTrigger.windsound = GameBase.gi.soundindex("misc/windfly.wav"); + self.touch = GameTrigger.trigger_push_touch; + if (0 == self.speed) + self.speed = 1000; + GameBase.gi.linkentity(self); + } + + public static void SP_trigger_hurt(edict_t self) { + InitTrigger(self); + + self.noise_index = GameBase.gi.soundindex("world/electro.wav"); + self.touch = GameTrigger.hurt_touch; + + if (0 == self.dmg) + self.dmg = 5; + + if ((self.spawnflags & 1) != 0) + self.solid = Defines.SOLID_NOT; + else + self.solid = Defines.SOLID_TRIGGER; + + if ((self.spawnflags & 2) != 0) + self.use = GameTrigger.hurt_use; + + GameBase.gi.linkentity(self); + } + + public static void SP_trigger_gravity(edict_t self) { + if (GameBase.st.gravity == null) { + GameBase.gi.dprintf("trigger_gravity without gravity set at " + + Lib.vtos(self.s.origin) + "\n"); + GameUtil.G_FreeEdict(self); + return; + } + + InitTrigger(self); + self.gravity = Lib.atoi(GameBase.st.gravity); + self.touch = GameTrigger.trigger_gravity_touch; + } + + public static void SP_trigger_monsterjump(edict_t self) { + if (0 == self.speed) + self.speed = 200; + if (0 == GameBase.st.height) + GameBase.st.height = 200; + if (self.s.angles[Defines.YAW] == 0) + self.s.angles[Defines.YAW] = 360; + InitTrigger(self); + self.touch = GameTrigger.trigger_monsterjump_touch; + self.movedir[2] = GameBase.st.height; + } + + // 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; + } + }; + + static EntUseAdapter Use_Multi = new EntUseAdapter() { + public void use(edict_t ent, edict_t other, edict_t activator) { + ent.activator = activator; + GameTrigger.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 & Defines.SVF_MONSTER) != 0) { + if (0 == (self.spawnflags & 1)) + return; + } else + return; + + if (0 == Math3D.VectorCompare(self.movedir, Globals.vec3_origin)) { + float[] forward = { 0, 0, 0 }; + + Math3D.AngleVectors(other.s.angles, forward, null, null); + if (Math3D.DotProduct(forward, self.movedir) < 0) + return; + } + + self.activator = other; + GameTrigger.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 = Defines.SOLID_TRIGGER; + self.use = Use_Multi; + GameBase.gi.linkentity(self); + } + }; + + /* + * 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) { + GameUtil.G_UseTargets(self, activator); + } + }; + + /* + * ============================================================================== + * + * 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 = GameUtil.ITEM_INDEX(self.item); + if (activator.client.pers.inventory[index] == 0) { + if (GameBase.level.time < self.touch_debounce_time) + return; + self.touch_debounce_time = GameBase.level.time + 5.0f; + GameBase.gi.centerprintf(activator, "You need the " + + self.item.pickup_name); + GameBase.gi + .sound(activator, Defines.CHAN_AUTO, GameBase.gi + .soundindex("misc/keytry.wav"), 1, + Defines.ATTN_NORM, 0); + return; + } + + GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi + .soundindex("misc/keyuse.wav"), 1, Defines.ATTN_NORM, 0); + if (GameBase.coop.value != 0) { + int player; + edict_t ent; + + if (Lib.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 <= GameBase.game.maxclients; player++) { + ent = GameBase.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 <= GameBase.game.maxclients; player++) { + ent = GameBase.g_edicts[player]; + if (!ent.inuse) + continue; + if (ent.client == null) + continue; + ent.client.pers.inventory[index] = 0; + } + } + } else { + activator.client.pers.inventory[index]--; + } + + GameUtil.G_UseTargets(self, activator); + + self.use = null; + } + }; + + /* + * ============================================================================== + * + * 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)) { + GameBase.gi.centerprintf(activator, self.count + + " more to go..."); + GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi + .soundindex("misc/talk1.wav"), 1, + Defines.ATTN_NORM, 0); + } + return; + } + + if (0 == (self.spawnflags & 1)) { + GameBase.gi.centerprintf(activator, "Sequence completed!"); + GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi + .soundindex("misc/talk1.wav"), 1, Defines.ATTN_NORM, 0); + } + self.activator = activator; + GameTrigger.multi_trigger(self); + } + }; + + /* + * ============================================================================== + * + * 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 (Lib.strcmp(other.classname, "grenade") == 0) { + Math3D.VectorScale(self.movedir, self.speed * 10, + other.velocity); + } else if (other.health > 0) { + Math3D.VectorScale(self.movedir, self.speed * 10, + other.velocity); + + if (other.client != null) { + // don't take falling damage immediately from this + Math3D.VectorCopy(other.velocity, other.client.oldvelocity); + if (other.fly_sound_debounce_time < GameBase.level.time) { + other.fly_sound_debounce_time = GameBase.level.time + 1.5f; + GameBase.gi.sound(other, Defines.CHAN_AUTO, windsound, + 1, Defines.ATTN_NORM, 0); + } + } + } + if ((self.spawnflags & PUSH_ONCE) != 0) + GameUtil.G_FreeEdict(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 == Defines.SOLID_NOT) + self.solid = Defines.SOLID_TRIGGER; + else + self.solid = Defines.SOLID_NOT; + GameBase.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 > GameBase.level.time) + return; + + if ((self.spawnflags & 16) != 0) + self.timestamp = GameBase.level.time + 1; + else + self.timestamp = GameBase.level.time + Defines.FRAMETIME; + + if (0 == (self.spawnflags & 4)) { + if ((GameBase.level.framenum % 10) == 0) + GameBase.gi.sound(other, Defines.CHAN_AUTO, + self.noise_index, 1, Defines.ATTN_NORM, 0); + } + + if ((self.spawnflags & 8) != 0) + dflags = Defines.DAMAGE_NO_PROTECTION; + else + dflags = 0; + GameUtil.T_Damage(other, self, self, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, self.dmg, self.dmg, + dflags, Defines.MOD_TRIGGER_HURT); + } + }; + + /* + * ============================================================================== + * + * 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; + } + }; + + /* + * ============================================================================== + * + * 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 & (Defines.FL_FLY | Defines.FL_SWIM)) != 0) + return; + if ((other.svflags & Defines.SVF_DEADMONSTER) != 0) + return; + if (0 == (other.svflags & Defines.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]; + } + }; +} \ No newline at end of file diff --git a/src/jake2/game/GameTriggerAdapters.java b/src/jake2/game/GameTriggerAdapters.java deleted file mode 100644 index 9fa331b..0000000 --- a/src/jake2/game/GameTriggerAdapters.java +++ /dev/null @@ -1,359 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: GameTriggerAdapters.java,v 1.2 2004-08-22 15:46:19 salomo Exp $ - -package jake2.game; - -import jake2.*; -import jake2.client.*; -import jake2.qcommon.*; -import jake2.render.*; -import jake2.server.*; -import jake2.util.*; - -public class GameTriggerAdapters { - - // 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; - } - }; - static EntUseAdapter Use_Multi = new EntUseAdapter() { - public void use(edict_t ent, edict_t other, edict_t activator) { - ent.activator = activator; - GameTrigger.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 & Defines.SVF_MONSTER) != 0) { - if (0 == (self.spawnflags & 1)) - return; - } - else - return; - - if (0 == Math3D.VectorCompare(self.movedir, Globals.vec3_origin)) { - float[] forward = { 0, 0, 0 }; - - Math3D.AngleVectors(other.s.angles, forward, null, null); - if (Math3D.DotProduct(forward, self.movedir) < 0) - return; - } - - self.activator = other; - GameTrigger.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 = Defines.SOLID_TRIGGER; - self.use = Use_Multi; - GameBase.gi.linkentity(self); - } - }; - /*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) { - GameUtil.G_UseTargets(self, activator); - } - }; - /* - ============================================================================== - - 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 = GameUtil.ITEM_INDEX(self.item); - if (activator.client.pers.inventory[index] == 0) { - if (GameBase.level.time < self.touch_debounce_time) - return; - self.touch_debounce_time = GameBase.level.time + 5.0f; - GameBase.gi.centerprintf(activator, "You need the " + self.item.pickup_name); - GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/keytry.wav"), 1, Defines.ATTN_NORM, 0); - return; - } - - GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/keyuse.wav"), 1, Defines.ATTN_NORM, 0); - if (GameBase.coop.value != 0) { - int player; - edict_t ent; - - if (Lib.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 <= GameBase.game.maxclients; player++) { - ent = GameBase.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 <= GameBase.game.maxclients; player++) { - ent = GameBase.g_edicts[player]; - if (!ent.inuse) - continue; - if (ent.client == null) - continue; - ent.client.pers.inventory[index] = 0; - } - } - } - else { - activator.client.pers.inventory[index]--; - } - - GameUtil.G_UseTargets(self, activator); - - self.use = null; - } - }; - /* - ============================================================================== - - 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)) { - GameBase.gi.centerprintf(activator, self.count + " more to go..."); - GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/talk1.wav"), 1, Defines.ATTN_NORM, 0); - } - return; - } - - if (0 == (self.spawnflags & 1)) { - GameBase.gi.centerprintf(activator, "Sequence completed!"); - GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/talk1.wav"), 1, Defines.ATTN_NORM, 0); - } - self.activator = activator; - GameTrigger.multi_trigger(self); - } - }; - /* - ============================================================================== - - 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 (Lib.strcmp(other.classname, "grenade") == 0) { - Math3D.VectorScale(self.movedir, self.speed * 10, other.velocity); - } - else if (other.health > 0) { - Math3D.VectorScale(self.movedir, self.speed * 10, other.velocity); - - if (other.client != null) { - // don't take falling damage immediately from this - Math3D.VectorCopy(other.velocity, other.client.oldvelocity); - if (other.fly_sound_debounce_time < GameBase.level.time) { - other.fly_sound_debounce_time = GameBase.level.time + 1.5f; - GameBase.gi.sound(other, Defines.CHAN_AUTO, windsound, 1, Defines.ATTN_NORM, 0); - } - } - } - if ((self.spawnflags & PUSH_ONCE) != 0) - GameUtil.G_FreeEdict(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 == Defines.SOLID_NOT) - self.solid = Defines.SOLID_TRIGGER; - else - self.solid = Defines.SOLID_NOT; - GameBase.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 > GameBase.level.time) - return; - - if ((self.spawnflags & 16) != 0) - self.timestamp = GameBase.level.time + 1; - else - self.timestamp = GameBase.level.time + Defines.FRAMETIME; - - if (0 == (self.spawnflags & 4)) { - if ((GameBase.level.framenum % 10) == 0) - GameBase.gi.sound(other, Defines.CHAN_AUTO, self.noise_index, 1, Defines.ATTN_NORM, 0); - } - - if ((self.spawnflags & 8) != 0) - dflags = Defines.DAMAGE_NO_PROTECTION; - else - dflags = 0; - GameUtil.T_Damage(other, self, self, Globals.vec3_origin, other.s.origin, Globals.vec3_origin, self.dmg, self.dmg, dflags, Defines.MOD_TRIGGER_HURT); - } - }; - /* - ============================================================================== - - 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; - } - }; - /* - ============================================================================== - - 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 & (Defines.FL_FLY | Defines.FL_SWIM)) != 0) - return; - if ((other.svflags & Defines.SVF_DEADMONSTER) != 0) - return; - if (0 == (other.svflags & Defines.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]; - } - }; -} diff --git a/src/jake2/game/GameTurret.java b/src/jake2/game/GameTurret.java index d0bfdbb..68e3098 100644 --- a/src/jake2/game/GameTurret.java +++ b/src/jake2/game/GameTurret.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 28.12.2003 by RST. -// $Id: GameTurret.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ - +// $Id: GameTurret.java,v 1.3 2004-09-22 19:22:05 salomo Exp $ package jake2.game; import jake2.*; @@ -31,147 +30,424 @@ import jake2.server.*; import jake2.util.Lib; import jake2.util.Math3D; -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; - } - - /*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); - } - - 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 = GameTurretAdapters.turret_blocked; - - self.think = GameTurretAdapters.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 = GameTurretAdapters.turret_blocked; - gi.linkentity(self); - } - - 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 = GameTurretAdapters.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 = GameUtilAdapters.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 = GameTurretAdapters.turret_driver_link; - self.nextthink = level.time + FRAMETIME; - - gi.linkentity(self); - } -} +public class GameTurret { + + 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; + } + + /* + * 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; + + Math3D.AngleVectors(self.s.angles, f, r, u); + Math3D.VectorMA(self.s.origin, self.move_origin[0], f, start); + Math3D.VectorMA(start, self.move_origin[1], r, start); + Math3D.VectorMA(start, self.move_origin[2], u, start); + + damage = (int) (100 + Lib.random() * 50); + speed = (int) (550 + 50 * GameBase.skill.value); + Fire.fire_rocket(self.teammaster.owner, start, f, damage, speed, 150, + damage); + GameBase.gi.positioned_sound(start, self, Defines.CHAN_WEAPON, + GameBase.gi.soundindex("weapons/rocklf1a.wav"), 1, + Defines.ATTN_NORM, 0); + } + + public static void SP_turret_breach(edict_t self) { + self.solid = Defines.SOLID_BSP; + self.movetype = Defines.MOVETYPE_PUSH; + GameBase.gi.setmodel(self, self.model); + + if (self.speed == 0) + self.speed = 50; + if (self.dmg == 0) + self.dmg = 10; + + if (GameBase.st.minpitch == 0) + GameBase.st.minpitch = -30; + if (GameBase.st.maxpitch == 0) + GameBase.st.maxpitch = 30; + if (GameBase.st.maxyaw == 0) + GameBase.st.maxyaw = 360; + + self.pos1[Defines.PITCH] = -1 * GameBase.st.minpitch; + self.pos1[Defines.YAW] = GameBase.st.minyaw; + self.pos2[Defines.PITCH] = -1 * GameBase.st.maxpitch; + self.pos2[Defines.YAW] = GameBase.st.maxyaw; + + self.ideal_yaw = self.s.angles[Defines.YAW]; + self.move_angles[Defines.YAW] = self.ideal_yaw; + + self.blocked = GameTurret.turret_blocked; + + self.think = GameTurret.turret_breach_finish_init; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + GameBase.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 = Defines.SOLID_BSP; + self.movetype = Defines.MOVETYPE_PUSH; + GameBase.gi.setmodel(self, self.model); + self.blocked = GameTurret.turret_blocked; + GameBase.gi.linkentity(self); + } + + public static void SP_turret_driver(edict_t self) { + if (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + self.movetype = Defines.MOVETYPE_PUSH; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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 = 0; + self.mass = 200; + self.viewheight = 24; + + self.die = GameTurret.turret_driver_die; + self.monsterinfo.stand = M_Infantry.infantry_stand; + + self.flags |= Defines.FL_NO_KNOCKBACK; + + GameBase.level.total_monsters++; + + self.svflags |= Defines.SVF_MONSTER; + self.s.renderfx |= Defines.RF_FRAMELERP; + self.takedamage = Defines.DAMAGE_AIM; + self.use = GameUtil.monster_use; + self.clipmask = Defines.MASK_MONSTERSOLID; + Math3D.VectorCopy(self.s.origin, self.s.old_origin); + self.monsterinfo.aiflags |= Defines.AI_STAND_GROUND | Defines.AI_DUCKED; + + 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"); + } + + self.think = GameTurret.turret_driver_link; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + + GameBase.gi.linkentity(self); + } + + 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; + GameUtil.T_Damage(other, self, attacker, Globals.vec3_origin, + other.s.origin, Globals.vec3_origin, + self.teammaster.dmg, 10, 0, Defines.MOD_CRUSH); + } + } + }; + + 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 }; + + Math3D.VectorCopy(self.s.angles, current_angles); + GameTurret.AnglesNormalize(current_angles); + + GameTurret.AnglesNormalize(self.move_angles); + if (self.move_angles[Defines.PITCH] > 180) + self.move_angles[Defines.PITCH] -= 360; + + // clamp angles to mins & maxs + if (self.move_angles[Defines.PITCH] > self.pos1[Defines.PITCH]) + self.move_angles[Defines.PITCH] = self.pos1[Defines.PITCH]; + else if (self.move_angles[Defines.PITCH] < self.pos2[Defines.PITCH]) + self.move_angles[Defines.PITCH] = self.pos2[Defines.PITCH]; + + if ((self.move_angles[Defines.YAW] < self.pos1[Defines.YAW]) + || (self.move_angles[Defines.YAW] > self.pos2[Defines.YAW])) { + float dmin, dmax; + + dmin = Math.abs(self.pos1[Defines.YAW] + - self.move_angles[Defines.YAW]); + if (dmin < -180) + dmin += 360; + else if (dmin > 180) + dmin -= 360; + dmax = Math.abs(self.pos2[Defines.YAW] + - self.move_angles[Defines.YAW]); + if (dmax < -180) + dmax += 360; + else if (dmax > 180) + dmax -= 360; + if (Math.abs(dmin) < Math.abs(dmax)) + self.move_angles[Defines.YAW] = self.pos1[Defines.YAW]; + else + self.move_angles[Defines.YAW] = self.pos2[Defines.YAW]; + } + + Math3D.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 * Defines.FRAMETIME) + delta[0] = self.speed * Defines.FRAMETIME; + if (delta[0] < -1 * self.speed * Defines.FRAMETIME) + delta[0] = -1 * self.speed * Defines.FRAMETIME; + if (delta[1] > self.speed * Defines.FRAMETIME) + delta[1] = self.speed * Defines.FRAMETIME; + if (delta[1] < -1 * self.speed * Defines.FRAMETIME) + delta[1] = -1 * self.speed * Defines.FRAMETIME; + + Math3D.VectorScale(delta, 1.0f / Defines.FRAMETIME, self.avelocity); + + self.nextthink = GameBase.level.time + Defines.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] = GameTurret + .SnapToEights((float) (self.s.origin[0] + Math + .cos(angle) + * self.owner.move_origin[0])); + target[1] = GameTurret + .SnapToEights((float) (self.s.origin[1] + Math + .sin(angle) + * self.owner.move_origin[0])); + target[2] = self.owner.s.origin[2]; + + Math3D.VectorSubtract(target, self.owner.s.origin, dir); + self.owner.velocity[0] = dir[0] * 1.0f / Defines.FRAMETIME; + self.owner.velocity[1] = dir[1] * 1.0f / Defines.FRAMETIME; + + // z + angle = self.s.angles[Defines.PITCH] + * (float) (Math.PI * 2f / 360f); + target_z = GameTurret + .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 / Defines.FRAMETIME; + + if ((self.spawnflags & 65536) != 0) { + GameTurret.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) { + GameBase.gi.dprintf(self.classname + " at " + + Lib.vtos(self.s.origin) + " needs a target\n"); + } else { + self.target_ent = GameBase.G_PickTarget(self.target); + Math3D.VectorSubtract(self.target_ent.s.origin, self.s.origin, + self.move_origin); + GameUtil.G_FreeEdict(self.target_ent); + } + + self.teammaster.dmg = self.dmg; + self.think = turret_breach_think; + self.think.think(self); + return true; + } + }; + + /* + * 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 &= ~Defines.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 = GameBase.level.time + Defines.FRAMETIME; + + if (self.enemy != null + && (!self.enemy.inuse || self.enemy.health <= 0)) + self.enemy = null; + + if (null == self.enemy) { + if (!GameUtil.FindTarget(self)) + return true; + self.monsterinfo.trail_time = GameBase.level.time; + self.monsterinfo.aiflags &= ~Defines.AI_LOST_SIGHT; + } else { + if (GameUtil.visible(self, self.enemy)) { + if ((self.monsterinfo.aiflags & Defines.AI_LOST_SIGHT) != 0) { + self.monsterinfo.trail_time = GameBase.level.time; + self.monsterinfo.aiflags &= ~Defines.AI_LOST_SIGHT; + } + } else { + self.monsterinfo.aiflags |= Defines.AI_LOST_SIGHT; + return true; + } + } + + // let the turret know where we want it to aim + Math3D.VectorCopy(self.enemy.s.origin, target); + target[2] += self.enemy.viewheight; + Math3D.VectorSubtract(target, self.target_ent.s.origin, dir); + Math3D.vectoangles(dir, self.target_ent.move_angles); + + // decide if we should shoot + if (GameBase.level.time < self.monsterinfo.attack_finished) + return true; + + reaction_time = (3 - GameBase.skill.value) * 1.0f; + if ((GameBase.level.time - self.monsterinfo.trail_time) < reaction_time) + return true; + + self.monsterinfo.attack_finished = GameBase.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 = GameBase.level.time + Defines.FRAMETIME; + + self.target_ent = GameBase.G_PickTarget(self.target); + self.target_ent.owner = self; + self.target_ent.teammaster.owner = self; + Math3D.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] = Math3D.VectorLength(vec); + + Math3D.VectorSubtract(self.s.origin, self.target_ent.s.origin, vec); + Math3D.vectoangles(vec, vec); + GameTurret.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 |= Defines.FL_TEAMSLAVE; + return true; + } + }; +} \ No newline at end of file diff --git a/src/jake2/game/GameTurretAdapters.java b/src/jake2/game/GameTurretAdapters.java deleted file mode 100644 index e78a1fd..0000000 --- a/src/jake2/game/GameTurretAdapters.java +++ /dev/null @@ -1,283 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: GameTurretAdapters.java,v 1.1 2004-07-08 15:58:44 hzi Exp $ - -package jake2.game; - -import jake2.*; -import jake2.client.*; -import jake2.qcommon.*; -import jake2.render.*; -import jake2.server.*; -import jake2.util.*; - -public class GameTurretAdapters { - - 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; - GameUtil.T_Damage(other, self, attacker, Globals.vec3_origin, other.s.origin, Globals.vec3_origin, self.teammaster.dmg, 10, 0, Defines.MOD_CRUSH); - } - } - }; - 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 }; - - Math3D.VectorCopy(self.s.angles, current_angles); - GameTurret.AnglesNormalize(current_angles); - - GameTurret.AnglesNormalize(self.move_angles); - if (self.move_angles[Defines.PITCH] > 180) - self.move_angles[Defines.PITCH] -= 360; - - // clamp angles to mins & maxs - if (self.move_angles[Defines.PITCH] > self.pos1[Defines.PITCH]) - self.move_angles[Defines.PITCH] = self.pos1[Defines.PITCH]; - else if (self.move_angles[Defines.PITCH] < self.pos2[Defines.PITCH]) - self.move_angles[Defines.PITCH] = self.pos2[Defines.PITCH]; - - if ((self.move_angles[Defines.YAW] < self.pos1[Defines.YAW]) || (self.move_angles[Defines.YAW] > self.pos2[Defines.YAW])) { - float dmin, dmax; - - dmin = Math.abs(self.pos1[Defines.YAW] - self.move_angles[Defines.YAW]); - if (dmin < -180) - dmin += 360; - else if (dmin > 180) - dmin -= 360; - dmax = Math.abs(self.pos2[Defines.YAW] - self.move_angles[Defines.YAW]); - if (dmax < -180) - dmax += 360; - else if (dmax > 180) - dmax -= 360; - if (Math.abs(dmin) < Math.abs(dmax)) - self.move_angles[Defines.YAW] = self.pos1[Defines.YAW]; - else - self.move_angles[Defines.YAW] = self.pos2[Defines.YAW]; - } - - Math3D.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 * Defines.FRAMETIME) - delta[0] = self.speed * Defines.FRAMETIME; - if (delta[0] < -1 * self.speed * Defines.FRAMETIME) - delta[0] = -1 * self.speed * Defines.FRAMETIME; - if (delta[1] > self.speed * Defines.FRAMETIME) - delta[1] = self.speed * Defines.FRAMETIME; - if (delta[1] < -1 * self.speed * Defines.FRAMETIME) - delta[1] = -1 * self.speed * Defines.FRAMETIME; - - Math3D.VectorScale(delta, 1.0f / Defines.FRAMETIME, self.avelocity); - - self.nextthink = GameBase.level.time + Defines.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] = GameTurret.SnapToEights((float) (self.s.origin[0] + Math.cos(angle) * self.owner.move_origin[0])); - target[1] = GameTurret.SnapToEights((float) (self.s.origin[1] + Math.sin(angle) * self.owner.move_origin[0])); - target[2] = self.owner.s.origin[2]; - - Math3D.VectorSubtract(target, self.owner.s.origin, dir); - self.owner.velocity[0] = dir[0] * 1.0f / Defines.FRAMETIME; - self.owner.velocity[1] = dir[1] * 1.0f / Defines.FRAMETIME; - - // z - angle = self.s.angles[Defines.PITCH] * (float) (Math.PI * 2f / 360f); - target_z = - GameTurret.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 / Defines.FRAMETIME; - - if ((self.spawnflags & 65536) != 0) { - GameTurret.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) { - GameBase.gi.dprintf(self.classname + " at " + Lib.vtos(self.s.origin) + " needs a target\n"); - } - else { - self.target_ent = GameBase.G_PickTarget(self.target); - Math3D.VectorSubtract(self.target_ent.s.origin, self.s.origin, self.move_origin); - GameUtil.G_FreeEdict(self.target_ent); - } - - self.teammaster.dmg = self.dmg; - self.think = turret_breach_think; - self.think.think(self); - return true; - } - }; - /*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 &= ~Defines.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 = GameBase.level.time + Defines.FRAMETIME; - - if (self.enemy != null && (!self.enemy.inuse || self.enemy.health <= 0)) - self.enemy = null; - - if (null == self.enemy) { - if (!GameUtil.FindTarget(self)) - return true; - self.monsterinfo.trail_time = GameBase.level.time; - self.monsterinfo.aiflags &= ~Defines.AI_LOST_SIGHT; - } - else { - if (GameUtil.visible(self, self.enemy)) { - if ((self.monsterinfo.aiflags & Defines.AI_LOST_SIGHT) != 0) { - self.monsterinfo.trail_time = GameBase.level.time; - self.monsterinfo.aiflags &= ~Defines.AI_LOST_SIGHT; - } - } - else { - self.monsterinfo.aiflags |= Defines.AI_LOST_SIGHT; - return true; - } - } - - // let the turret know where we want it to aim - Math3D.VectorCopy(self.enemy.s.origin, target); - target[2] += self.enemy.viewheight; - Math3D.VectorSubtract(target, self.target_ent.s.origin, dir); - Math3D.vectoangles(dir, self.target_ent.move_angles); - - // decide if we should shoot - if (GameBase.level.time < self.monsterinfo.attack_finished) - return true; - - reaction_time = (3 - GameBase.skill.value) * 1.0f; - if ((GameBase.level.time - self.monsterinfo.trail_time) < reaction_time) - return true; - - self.monsterinfo.attack_finished = GameBase.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 = GameBase.level.time + Defines.FRAMETIME; - - self.target_ent = GameBase.G_PickTarget(self.target); - self.target_ent.owner = self; - self.target_ent.teammaster.owner = self; - Math3D.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] = Math3D.VectorLength(vec); - - Math3D.VectorSubtract(self.s.origin, self.target_ent.s.origin, vec); - Math3D.vectoangles(vec, vec); - GameTurret.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 |= Defines.FL_TEAMSLAVE; - return true; - } - }; -} diff --git a/src/jake2/game/GameUtil.java b/src/jake2/game/GameUtil.java index c76c6b0..90c266c 100644 --- a/src/jake2/game/GameUtil.java +++ b/src/jake2/game/GameUtil.java @@ -1,1260 +1,1798 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 01.11.2003 by RST. -// $Id: GameUtil.java,v 1.6 2004-09-12 18:25:49 salomo Exp $ - +// $Id: GameUtil.java,v 1.7 2004-09-22 19:22:05 salomo Exp $ package jake2.game; +import jake2.Defines; +import jake2.Globals; import jake2.client.M; import jake2.qcommon.Com; import jake2.util.Lib; import jake2.util.Math3D; -public class GameUtil extends GameBase { - - 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= GameUtilAdapters.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= new entity_state_t(e); - 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 < 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)) { - e= g_edicts[i]= new edict_t(i); - G_InitEdict(e, i); - return e; - } - } - - if (i == game.maxentities) - gi.error("ED_Alloc: no free edicts"); - - e= g_edicts[i]= new edict_t(i); - num_edicts++; - G_InitEdict(e, i); - return e; - } - - /** - * 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)); - g_edicts[ed.index]= new edict_t(ed.index); - //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_ClearEdict(edict_t ent) { - int i= ent.index; - g_edicts[i]= new edict_t(i); - } - - 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, GameBase.dummyplane, 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; - } - - 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 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= GameUtilAdapters.DoRespawn; - gi.linkentity(ent); - } - - static int ITEM_INDEX(gitem_t item) { - return item.index; - } - - 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= GameUtilAdapters.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= GameUtilAdapters.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 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= GameUtilAdapters.Touch_Item; - } - - gi.linkentity(ent); - } - - /* - ============ - 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[GameUtilAdapters.power_shield_index] > 0) - return POWER_ARMOR_SHIELD; - - if (ent.client.pers.inventory[GameUtilAdapters.power_screen_index] > 0) - return POWER_ARMOR_SCREEN; - - return POWER_ARMOR_NONE; - } - - 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; - - 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) { - 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[GameUtilAdapters.jacket_armor_index] > 0) - return GameUtilAdapters.jacket_armor_index; - - if (ent.client.pers.inventory[GameUtilAdapters.combat_armor_index] > 0) - return GameUtilAdapters.combat_armor_index; - - if (ent.client.pers.inventory[GameUtilAdapters.body_armor_index] > 0) - return GameUtilAdapters.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 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 { - // heard it - 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; - } - - // ============================================================================ - //ok - 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); - } - } - } - } -} +public class GameUtil { + + 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 = GameBase.level.time + ent.delay; + t.think = GameUtil.Think_Delay; + t.activator = activator; + if (activator == null) + GameBase.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 & Defines.SVF_MONSTER) == 0) { + GameBase.gi.centerprintf(activator, "" + ent.message); + if (ent.noise_index != 0) + GameBase.gi.sound(activator, Defines.CHAN_AUTO, + ent.noise_index, 1, Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(activator, Defines.CHAN_AUTO, GameBase.gi + .soundindex("misc/talk1.wav"), 1, Defines.ATTN_NORM, 0); + } + + // + // kill killtargets + // + + EdictIterator edit = null; + + if (ent.killtarget != null) { + while ((edit = GameBase.G_Find(edit, GameBase.findByTarget, + ent.killtarget)) != null) { + t = edit.o; + G_FreeEdict(t); + if (!ent.inuse) { + GameBase.gi + .dprintf("entity was removed while using killtargets\n"); + return; + } + } + } + + // fire targets + + if (ent.target != null) { + edit = null; + while ((edit = GameBase.G_Find(edit, GameBase.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) { + GameBase.gi.dprintf("WARNING: Entity used itself.\n"); + } else { + if (t.use != null) + t.use.use(t, ent, activator); + } + if (!ent.inuse) { + GameBase.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 = new entity_state_t(e); + 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) GameBase.maxclients.value + 1; i < GameBase.num_edicts; i++) { + e = GameBase.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 || GameBase.level.time - e.freetime > 0.5)) { + e = GameBase.g_edicts[i] = new edict_t(i); + G_InitEdict(e, i); + return e; + } + } + + if (i == GameBase.game.maxentities) + GameBase.gi.error("ED_Alloc: no free edicts"); + + e = GameBase.g_edicts[i] = new edict_t(i); + GameBase.num_edicts++; + G_InitEdict(e, i); + return e; + } + + /** + * Marks the edict as free + */ + public static void G_FreeEdict(edict_t ed) { + GameBase.gi.unlinkentity(ed); // unlink from world + + //if ((ed - g_edicts) <= (maxclients.value + BODY_QUEUE_SIZE)) + if (ed.index <= (GameBase.maxclients.value + Defines.BODY_QUEUE_SIZE)) { + // gi.dprintf("tried to free special edict\n"); + return; + } + + //memset(ed, 0, sizeof(* ed)); + GameBase.g_edicts[ed.index] = new edict_t(ed.index); + //ed.clear(); + ed.classname = "freed"; + ed.freetime = GameBase.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_ClearEdict(edict_t ent) { + int i = ent.index; + GameBase.g_edicts[i] = new edict_t(i); + } + + public static void G_TouchSolids(edict_t ent) { + int i, num; + edict_t touch[] = new edict_t[Defines.MAX_EDICTS], hit; + + num = GameBase.gi.BoxEdicts(ent.absmin, ent.absmax, touch, + Defines.MAX_EDICTS, Defines.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, GameBase.dummyplane, 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 = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, + ent.s.origin, null, Defines.MASK_PLAYERSOLID); + if (tr.ent == null || tr.ent == GameBase.g_edicts[0]) + break; + + // nail it + T_Damage(tr.ent, ent, ent, Globals.vec3_origin, ent.s.origin, + Globals.vec3_origin, 100000, 0, + Defines.DAMAGE_NO_PROTECTION, Defines.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) (GameBase.dmflags.value) & (Defines.DF_MODELTEAMS | Defines.DF_SKINTEAMS))) + return false; + + if (ClientTeam(ent1).equals(ClientTeam(ent2))) + return true; + return false; + } + + 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) (GameBase.dmflags.value) & Defines.DF_MODELTEAMS) != 0) { + return value.substring(0, p); + } + + return value.substring(p + 1, value.length()); + } + + static void SetRespawn(edict_t ent, float delay) { + ent.flags |= Defines.FL_RESPAWN; + ent.svflags |= Defines.SVF_NOCLIENT; + ent.solid = Defines.SOLID_NOT; + ent.nextthink = GameBase.level.time + delay; + ent.think = GameUtil.DoRespawn; + GameBase.gi.linkentity(ent); + } + + static int ITEM_INDEX(gitem_t item) { + return item.index; + } + + 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 = Defines.DROPPED_ITEM; + dropped.s.effects = item.world_model_flags; + dropped.s.renderfx = Defines.RF_GLOW; + Math3D.VectorSet(dropped.mins, -15, -15, -15); + Math3D.VectorSet(dropped.maxs, 15, 15, 15); + GameBase.gi.setmodel(dropped, dropped.item.world_model); + dropped.solid = Defines.SOLID_TRIGGER; + dropped.movetype = Defines.MOVETYPE_TOSS; + + dropped.touch = GameUtil.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 = GameBase.gi.trace(ent.s.origin, dropped.mins, dropped.maxs, + dropped.s.origin, ent, Defines.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 = GameUtil.drop_make_touchable; + dropped.nextthink = GameBase.level.time + 1; + + GameBase.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 void Use_Item(edict_t ent, edict_t other, edict_t activator) { + ent.svflags &= ~Defines.SVF_NOCLIENT; + ent.use = null; + + if ((ent.spawnflags & Defines.ITEM_NO_TOUCH) != 0) { + ent.solid = Defines.SOLID_BBOX; + ent.touch = null; + } else { + ent.solid = Defines.SOLID_TRIGGER; + ent.touch = GameUtil.Touch_Item; + } + + GameBase.gi.linkentity(ent); + } + + /* + * ============ 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 == Defines.MOVETYPE_PUSH) { + Math3D.VectorAdd(targ.absmin, targ.absmax, dest); + Math3D.VectorScale(dest, 0.5f, dest); + trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin, + Globals.vec3_origin, dest, inflictor, Defines.MASK_SOLID); + if (trace.fraction == 1.0f) + return true; + if (trace.ent == targ) + return true; + return false; + } + + trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin, + Globals.vec3_origin, targ.s.origin, inflictor, + Defines.MASK_SOLID); + if (trace.fraction == 1.0) + return true; + + Math3D.VectorCopy(targ.s.origin, dest); + dest[0] += 15.0; + dest[1] += 15.0; + trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin, + Globals.vec3_origin, dest, inflictor, Defines.MASK_SOLID); + if (trace.fraction == 1.0) + return true; + + Math3D.VectorCopy(targ.s.origin, dest); + dest[0] += 15.0; + dest[1] -= 15.0; + trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin, + Globals.vec3_origin, dest, inflictor, Defines.MASK_SOLID); + if (trace.fraction == 1.0) + return true; + + Math3D.VectorCopy(targ.s.origin, dest); + dest[0] -= 15.0; + dest[1] += 15.0; + trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin, + Globals.vec3_origin, dest, inflictor, Defines.MASK_SOLID); + if (trace.fraction == 1.0) + return true; + + Math3D.VectorCopy(targ.s.origin, dest); + dest[0] -= 15.0; + dest[1] -= 15.0; + trace = GameBase.gi.trace(inflictor.s.origin, Globals.vec3_origin, + Globals.vec3_origin, dest, inflictor, Defines.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) + && ((GameBase.deathmatch.value != 0 && 0 != ((int) (GameBase.dmflags.value) & (Defines.DF_MODELTEAMS | Defines.DF_SKINTEAMS))) || GameBase.coop.value != 0)) { + if (OnSameTeam(targ, attacker)) { + if (((int) (GameBase.dmflags.value) & Defines.DF_NO_FRIENDLY_FIRE) != 0) + damage = 0; + else + mod |= Defines.MOD_FRIENDLY_FIRE; + } + } + GameBase.meansOfDeath = mod; + + // easy mode takes half damage + if (GameBase.skill.value == 0 && GameBase.deathmatch.value == 0 + && targ.client != null) { + damage *= 0.5; + if (damage == 0) + damage = 1; + } + + client = targ.client; + + if ((dflags & Defines.DAMAGE_BULLET) != 0) + te_sparks = Defines.TE_BULLET_SPARKS; + else + te_sparks = Defines.TE_SPARKS; + + Math3D.VectorNormalize(dir); + + // bonus damage for suprising a monster + if (0 == (dflags & Defines.DAMAGE_RADIUS) + && (targ.svflags & Defines.SVF_MONSTER) != 0 + && (attacker.client != null) && (targ.enemy == null) + && (targ.health > 0)) + damage *= 2; + + if ((targ.flags & Defines.FL_NO_KNOCKBACK) != 0) + knockback = 0; + + // figure momentum add + if (0 == (dflags & Defines.DAMAGE_NO_KNOCKBACK)) { + if ((knockback != 0) && (targ.movetype != Defines.MOVETYPE_NONE) + && (targ.movetype != Defines.MOVETYPE_BOUNCE) + && (targ.movetype != Defines.MOVETYPE_PUSH) + && (targ.movetype != Defines.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 & Defines.FL_GODMODE) != 0 + && 0 == (dflags & Defines.DAMAGE_NO_PROTECTION)) { + take = 0; + save = damage; + SpawnDamage(te_sparks, point, normal, save); + } + + // check for invincibility + if ((client != null && client.invincible_framenum > GameBase.level.framenum) + && 0 == (dflags & Defines.DAMAGE_NO_PROTECTION)) { + if (targ.pain_debounce_time < GameBase.level.time) { + GameBase.gi.sound(targ, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/protect4.wav"), 1, + Defines.ATTN_NORM, 0); + targ.pain_debounce_time = GameBase.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 & Defines.DAMAGE_NO_PROTECTION) + && CheckTeamDamage(targ, attacker)) + return; + + // do the damage + if (take != 0) { + if (0 != (targ.svflags & Defines.SVF_MONSTER) || (client != null)) + SpawnDamage(Defines.TE_BLOOD, point, normal, take); + else + SpawnDamage(te_sparks, point, normal, take); + + targ.health = targ.health - take; + + if (targ.health <= 0) { + if ((targ.svflags & Defines.SVF_MONSTER) != 0 + || (client != null)) + targ.flags |= Defines.FL_NO_KNOCKBACK; + Killed(targ, inflictor, attacker, take, point); + return; + } + } + + if ((targ.svflags & Defines.SVF_MONSTER) != 0) { + M.M_ReactToDamage(targ, attacker); + if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED) + && (take != 0)) { + targ.pain.pain(targ, attacker, knockback, take); + // nightmare mode monsters don't go into pain frames often + if (GameBase.skill.value == 3) + targ.pain_debounce_time = GameBase.level.time + 5; + } + } else if (client != null) { + if (((targ.flags & Defines.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 & Defines.SVF_MONSTER) != 0 + && (targ.deadflag != Defines.DEAD_DEAD)) { + // targ.svflags |= SVF_DEADMONSTER; // now treat as a different + // content type + if (0 == (targ.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) { + GameBase.level.killed_monsters++; + if (GameBase.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 == Defines.MOVETYPE_PUSH + || targ.movetype == Defines.MOVETYPE_STOP + || targ.movetype == Defines.MOVETYPE_NONE) { // doors, triggers, + // etc + targ.die.die(targ, inflictor, attacker, damage, point); + return; + } + + if ((targ.svflags & Defines.SVF_MONSTER) != 0 + && (targ.deadflag != Defines.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; + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(type); + // gi.WriteByte (damage); + GameBase.gi.WritePosition(origin); + GameBase.gi.WriteDir(normal); + GameBase.gi.multicast(origin, Defines.MULTICAST_PVS); + } + + static int PowerArmorType(edict_t ent) { + if (ent.client == null) + return Defines.POWER_ARMOR_NONE; + + if (0 == (ent.flags & Defines.FL_POWER_ARMOR)) + return Defines.POWER_ARMOR_NONE; + + if (ent.client.pers.inventory[GameUtil.power_shield_index] > 0) + return Defines.POWER_ARMOR_SHIELD; + + if (ent.client.pers.inventory[GameUtil.power_screen_index] > 0) + return Defines.POWER_ARMOR_SCREEN; + + return Defines.POWER_ARMOR_NONE; + } + + 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 & Defines.DAMAGE_NO_ARMOR) != 0) + return 0; + + if (client != null) { + power_armor_type = PowerArmorType(ent); + if (power_armor_type != Defines.POWER_ARMOR_NONE) { + index = ITEM_INDEX(FindItem("Cells")); + power = client.pers.inventory[index]; + } + } else if ((ent.svflags & Defines.SVF_MONSTER) != 0) { + power_armor_type = ent.monsterinfo.power_armor_type; + power = ent.monsterinfo.power_armor_power; + } else + return 0; + + if (power_armor_type == Defines.POWER_ARMOR_NONE) + return 0; + if (power == 0) + return 0; + + if (power_armor_type == Defines.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 = Defines.TE_SCREEN_SPARKS; + damage = damage / 3; + } else { + damagePerCell = 2; + pa_te_type = Defines.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 = GameBase.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) + && (GameBase.level.time > self.monsterinfo.idle_time)) { + if (self.monsterinfo.idle_time != 0) { + self.monsterinfo.search.think(self); + self.monsterinfo.idle_time = GameBase.level.time + 15 + + Lib.random() * 15; + } else { + self.monsterinfo.idle_time = GameBase.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; + + Math3D.VectorSubtract(self.s.origin, other.s.origin, v); + len = Math3D.VectorLength(v); + if (len < Defines.MELEE_DISTANCE) + return Defines.RANGE_MELEE; + if (len < 500) + return Defines.RANGE_NEAR; + if (len < 1000) + return Defines.RANGE_MID; + return Defines.RANGE_FAR; + } + + /* + * =============== FindItemByClassname + * + * =============== + */ + static gitem_t FindItemByClassname(String classname) { + + for (int i = 1; i < GameBase.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) { + for (int i = 1; i < GameBase.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[GameUtil.jacket_armor_index] > 0) + return GameUtil.jacket_armor_index; + + if (ent.client.pers.inventory[GameUtil.combat_armor_index] > 0) + return GameUtil.combat_armor_index; + + if (ent.client.pers.inventory[GameUtil.body_armor_index] > 0) + return GameUtil.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 & Defines.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 & Defines.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 void AttackFinished(edict_t self, float time) { + self.monsterinfo.attack_finished = GameBase.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 = GameBase.gi.trace(spot1, Globals.vec3_origin, + Globals.vec3_origin, spot2, self, Defines.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 (GameBase.level.sight_client == null) + start = 1; + else + start = GameBase.level.sight_client.index; + + check = start; + while (true) { + check++; + if (check > GameBase.game.maxclients) + check = 1; + ent = GameBase.g_edicts[check]; + + if (ent.inuse && ent.health > 0 + && (ent.flags & Defines.FL_NOTARGET) == 0) { + GameBase.level.sight_client = ent; + return; // got one + } + if (check == start) { + GameBase.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[Defines.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 & Defines.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 & Defines.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 ((GameBase.level.sight_entity_framenum >= (GameBase.level.framenum - 1)) + && 0 == (self.spawnflags & 1)) { + client = GameBase.level.sight_entity; + if (client.enemy == self.enemy) { + return false; + } + } else if (GameBase.level.sound_entity_framenum >= (GameBase.level.framenum - 1)) { + client = GameBase.level.sound_entity; + heardit = true; + } else if (null != (self.enemy) + && (GameBase.level.sound2_entity_framenum >= (GameBase.level.framenum - 1)) + && 0 != (self.spawnflags & 1)) { + client = GameBase.level.sound2_entity; + heardit = true; + } else { + client = GameBase.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 & Defines.FL_NOTARGET) != 0) + return false; + } else if ((client.svflags & Defines.SVF_MONSTER) != 0) { + if (client.enemy == null) + return false; + if ((client.enemy.flags & Defines.FL_NOTARGET) != 0) + return false; + } else if (heardit) { + if ((client.owner.flags & Defines.FL_NOTARGET) != 0) + return false; + } else + return false; + + if (!heardit) { + r = range(self, client); + + if (r == Defines.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 == Defines.RANGE_NEAR) { + if (client.show_hostile < GameBase.level.time + && !infront(self, client)) { + return false; + } + } else if (r == Defines.RANGE_MID) { + if (!infront(self, client)) { + return false; + } + } + + self.enemy = client; + + if (!self.enemy.classname.equals("player_noise")) { + self.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET; + + if (self.enemy.client == null) { + self.enemy = self.enemy.enemy; + if (self.enemy.client == null) { + self.enemy = null; + return false; + } + } + } + } else { + // heard it + float[] temp = { 0, 0, 0 }; + + if ((self.spawnflags & 1) != 0) { + if (!visible(self, client)) + return false; + } else { + if (!GameBase.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 (!GameBase.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 |= Defines.AI_SOUND_TARGET; + self.enemy = client; + } + + // + // got one + // + FoundTarget(self); + + if (0 == (self.monsterinfo.aiflags & Defines.AI_SOUND_TARGET) + && (self.monsterinfo.sight != null)) + self.monsterinfo.sight.interact(self, self.enemy); + + return true; + } + + // ============================================================================ + //ok + static void HuntTarget(edict_t self) { + float[] vec = { 0, 0, 0 }; + + self.goalentity = self.enemy; + if ((self.monsterinfo.aiflags & Defines.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 & Defines.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) { + GameBase.level.sight_entity = self; + GameBase.level.sight_entity_framenum = GameBase.level.framenum; + GameBase.level.sight_entity.light_level = 128; + } + + self.show_hostile = (int) GameBase.level.time + 1; // wake up other + // monsters + + Math3D.VectorCopy(self.enemy.s.origin, self.monsterinfo.last_sighting); + self.monsterinfo.trail_time = GameBase.level.time; + + if (self.combattarget == null) { + HuntTarget(self); + return; + } + + self.goalentity = self.movetarget = GameBase + .G_PickTarget(self.combattarget); + if (self.movetarget == null) { + self.goalentity = self.movetarget = self.enemy; + HuntTarget(self); + GameBase.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 |= Defines.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 = GameBase.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, + Globals.vec3_origin, (int) points, (int) points, + Defines.DAMAGE_RADIUS, mod); + } + } + } + } + + public static EntThinkAdapter Think_Delay = new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameUtil.G_UseTargets(ent, ent.activator); + GameUtil.G_FreeEdict(ent); + return true; + } + }; + + public static EntThinkAdapter G_FreeEdictA = new EntThinkAdapter() { + public boolean think(edict_t ent) { + GameUtil.G_FreeEdict(ent); + return false; + } + }; + + static EntThinkAdapter MegaHealth_think = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (self.owner.health > self.owner.max_health) { + self.nextthink = GameBase.level.time + 1; + self.owner.health -= 1; + return false; + } + + if (!((self.spawnflags & Defines.DROPPED_ITEM) != 0) + && (GameBase.deathmatch.value != 0)) + GameUtil.SetRespawn(self, 20); + else + GameUtil.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; + + // 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 &= ~Defines.SVF_NOCLIENT; + ent.solid = Defines.SOLID_TRIGGER; + GameBase.gi.linkentity(ent); + + // send an effect + ent.s.event = Defines.EV_ITEM_RESPAWN; + + return false; + } + }; + + 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 = GameUtil.FindItem("Bullets"); + if (item != null) { + index = GameUtil.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 = GameUtil.FindItem("Shells"); + if (item != null) { + index = GameUtil.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 = GameUtil.FindItem("Cells"); + if (item != null) { + index = GameUtil.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 = GameUtil.FindItem("Grenades"); + if (item != null) { + index = GameUtil.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 = GameUtil.FindItem("Rockets"); + if (item != null) { + index = GameUtil.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 = GameUtil.FindItem("Slugs"); + if (item != null) { + index = GameUtil.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 & Defines.DROPPED_ITEM) + && (GameBase.deathmatch.value != 0)) + GameUtil.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 & Defines.HEALTH_IGNORE_MAX)) + if (other.health >= other.max_health) + return false; + + other.health += ent.count; + + if (0 == (ent.style & Defines.HEALTH_IGNORE_MAX)) { + if (other.health > other.max_health) + other.health = other.max_health; + } + + if (0 != (ent.style & Defines.HEALTH_TIMED)) { + ent.think = MegaHealth_think; + ent.nextthink = GameBase.level.time + 5f; + ent.owner = other; + ent.flags |= Defines.FL_RESPAWN; + ent.svflags |= Defines.SVF_NOCLIENT; + ent.solid = Defines.SOLID_NOT; + } else { + if (!((ent.spawnflags & Defines.DROPPED_ITEM) != 0) + && (GameBase.deathmatch.value != 0)) + GameUtil.SetRespawn(ent, 30); + } + + return true; + } + + }; + + /* + * =============== 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 (ent.classname.equals("item_breather")) + taken = false; + + 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[Defines.STAT_PICKUP_ICON] = (short) GameBase.gi + .imageindex(ent.item.icon); + other.client.ps.stats[Defines.STAT_PICKUP_STRING] = (short) (Defines.CS_ITEMS + GameUtil + .ITEM_INDEX(ent.item)); + other.client.pickup_msg_time = GameBase.level.time + 3.0f; + + // change selected item + if (ent.item.use != null) + other.client.pers.selected_item = other.client.ps.stats[Defines.STAT_SELECTED_ITEM] = (short) GameUtil + .ITEM_INDEX(ent.item); + + if (ent.item.pickup == Pickup_Health) { + if (ent.count == 2) + GameBase.gi.sound(other, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/s_health.wav"), 1, + Defines.ATTN_NORM, 0); + else if (ent.count == 10) + GameBase.gi.sound(other, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/n_health.wav"), 1, + Defines.ATTN_NORM, 0); + else if (ent.count == 25) + GameBase.gi.sound(other, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/l_health.wav"), 1, + Defines.ATTN_NORM, 0); + else + // (ent.count == 100) + GameBase.gi.sound(other, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/m_health.wav"), 1, + Defines.ATTN_NORM, 0); + } else if (ent.item.pickup_sound != null) { + GameBase.gi.sound(other, Defines.CHAN_ITEM, GameBase.gi + .soundindex(ent.item.pickup_sound), 1, + Defines.ATTN_NORM, 0); + } + } + + if (0 == (ent.spawnflags & Defines.ITEM_TARGETS_USED)) { + GameUtil.G_UseTargets(ent, other); + ent.spawnflags |= Defines.ITEM_TARGETS_USED; + } + + if (!taken) + return; + //Com.p("Picked up:" + ent.classname); + + if (!((GameBase.coop.value != 0) && (ent.item.flags & Defines.IT_STAY_COOP) != 0) + || 0 != (ent.spawnflags & (Defines.DROPPED_ITEM | Defines.DROPPED_PLAYER_ITEM))) { + if ((ent.flags & Defines.FL_RESPAWN) != 0) + ent.flags &= ~Defines.FL_RESPAWN; + else + GameUtil.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 (GameBase.deathmatch.value != 0) { + ent.nextthink = GameBase.level.time + 29; + ent.think = G_FreeEdictA; + } + return false; + } + }; + + 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[GameUtil.ITEM_INDEX(item)]--; + GameUtil.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 > GameBase.level.framenum) + ent.client.quad_framenum += timeout; + else + ent.client.quad_framenum = GameBase.level.framenum + timeout; + + GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/damage.wav"), 1, Defines.ATTN_NORM, 0); + } + }; + + static ItemUseAdapter Use_Invulnerability = new ItemUseAdapter() { + public void use(edict_t ent, gitem_t item) { + ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)]--; + GameUtil.ValidateSelectedItem(ent); + + if (ent.client.invincible_framenum > GameBase.level.framenum) + ent.client.invincible_framenum += 300; + else + ent.client.invincible_framenum = GameBase.level.framenum + 300; + + GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/protect.wav"), 1, Defines.ATTN_NORM, 0); + } + }; + + // ====================================================================== + + static ItemUseAdapter Use_Breather = new ItemUseAdapter() { + public void use(edict_t ent, gitem_t item) { + ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)]--; + + GameUtil.ValidateSelectedItem(ent); + + if (ent.client.breather_framenum > GameBase.level.framenum) + ent.client.breather_framenum += 300; + else + ent.client.breather_framenum = GameBase.level.framenum + 300; + + GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/damage.wav"), 1, Defines.ATTN_NORM, 0); + } + }; + + // ====================================================================== + + static ItemUseAdapter Use_Envirosuit = new ItemUseAdapter() { + public void use(edict_t ent, gitem_t item) { + ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)]--; + GameUtil.ValidateSelectedItem(ent); + + if (ent.client.enviro_framenum > GameBase.level.framenum) + ent.client.enviro_framenum += 300; + else + ent.client.enviro_framenum = GameBase.level.framenum + 300; + + GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/damage.wav"), 1, Defines.ATTN_NORM, 0); + } + }; + + // ====================================================================== + + static ItemUseAdapter Use_Silencer = new ItemUseAdapter() { + public void use(edict_t ent, gitem_t item) { + + ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)]--; + GameUtil.ValidateSelectedItem(ent); + ent.client.silencer_shots += 30; + + GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/damage.wav"), 1, Defines.ATTN_NORM, 0); + } + }; + + // ====================================================================== + + static EntInteractAdapter Pickup_Key = new EntInteractAdapter() { + public boolean interact(edict_t ent, edict_t other) { + if (GameBase.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[GameUtil.ITEM_INDEX(ent.item)]++; + other.client.pers.power_cubes |= ((ent.spawnflags & 0x0000ff00) >> 8); + } else { + if (other.client.pers.inventory[GameUtil + .ITEM_INDEX(ent.item)] != 0) + return false; + other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)] = 1; + } + return true; + } + other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)]++; + return true; + } + }; + + 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; + + /* + * ============= 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 = GameBase.gi.trace(spot1, null, null, spot2, self, + Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER + | Defines.CONTENTS_SLIME + | Defines.CONTENTS_LAVA + | Defines.CONTENTS_WINDOW); + + // do we have a clear shot? + if (tr.ent != self.enemy) + return false; + } + + // melee attack + if (enemy_range == Defines.RANGE_MELEE) { + // don't always melee in easy mode + if (GameBase.skill.value == 0 && (Lib.rand() & 3) != 0) + return false; + if (self.monsterinfo.melee != null) + self.monsterinfo.attack_state = Defines.AS_MELEE; + else + self.monsterinfo.attack_state = Defines.AS_MISSILE; + return true; + } + + // missile attack + if (self.monsterinfo.attack == null) + return false; + + if (GameBase.level.time < self.monsterinfo.attack_finished) + return false; + + if (enemy_range == Defines.RANGE_FAR) + return false; + + if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0) { + chance = 0.4f; + } else if (enemy_range == Defines.RANGE_MELEE) { + chance = 0.2f; + } else if (enemy_range == Defines.RANGE_NEAR) { + chance = 0.1f; + } else if (enemy_range == Defines.RANGE_MID) { + chance = 0.02f; + } else { + return false; + } + + if (GameBase.skill.value == 0) + chance *= 0.5; + else if (GameBase.skill.value >= 2) + chance *= 2; + + if (Lib.random() < chance) { + self.monsterinfo.attack_state = Defines.AS_MISSILE; + self.monsterinfo.attack_finished = GameBase.level.time + 2 + * Lib.random(); + return true; + } + + if ((self.flags & Defines.FL_FLY) != 0) { + if (Lib.random() < 0.3f) + self.monsterinfo.attack_state = Defines.AS_SLIDING; + else + self.monsterinfo.attack_state = Defines.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 & Defines.FL_NOTARGET) != 0) + return; + if ((null == activator.client) + && 0 == (activator.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) + return; + + // delay reaction so if the monster is teleported, its sound is + // still heard + self.enemy = activator; + GameUtil.FoundTarget(self); + } + }; + + static boolean enemy_vis; + + static boolean enemy_infront; + + static int enemy_range; + + static float enemy_yaw; +} \ No newline at end of file diff --git a/src/jake2/game/GameUtilAdapters.java b/src/jake2/game/GameUtilAdapters.java deleted file mode 100644 index 0cf439b..0000000 --- a/src/jake2/game/GameUtilAdapters.java +++ /dev/null @@ -1,635 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: GameUtilAdapters.java,v 1.4 2004-09-10 19:02:54 salomo Exp $ - -package jake2.game; - -import jake2.*; -import jake2.qcommon.Com; -import jake2.util.*; - -public class GameUtilAdapters -{ - - public static EntThinkAdapter Think_Delay = new EntThinkAdapter() - { - public boolean think(edict_t ent) - { - GameUtil.G_UseTargets(ent, ent.activator); - GameUtil.G_FreeEdict(ent); - return true; - } - }; - public static EntThinkAdapter G_FreeEdictA = new EntThinkAdapter() - { - public boolean think(edict_t ent) - { - GameUtil.G_FreeEdict(ent); - return false; - } - }; - static EntThinkAdapter MegaHealth_think = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if (self.owner.health > self.owner.max_health) - { - self.nextthink = GameBase.level.time + 1; - self.owner.health -= 1; - return false; - } - - if (!((self.spawnflags & Defines.DROPPED_ITEM) != 0) && (GameBase.deathmatch.value != 0)) - GameUtil.SetRespawn(self, 20); - else - GameUtil.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; - - // 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 &= ~Defines.SVF_NOCLIENT; - ent.solid = Defines.SOLID_TRIGGER; - GameBase.gi.linkentity(ent); - - // send an effect - ent.s.event = Defines.EV_ITEM_RESPAWN; - - return false; - } - }; - 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 = GameUtil.FindItem("Bullets"); - if (item != null) - { - index = GameUtil.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 = GameUtil.FindItem("Shells"); - if (item != null) - { - index = GameUtil.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 = GameUtil.FindItem("Cells"); - if (item != null) - { - index = GameUtil.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 = GameUtil.FindItem("Grenades"); - if (item != null) - { - index = GameUtil.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 = GameUtil.FindItem("Rockets"); - if (item != null) - { - index = GameUtil.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 = GameUtil.FindItem("Slugs"); - if (item != null) - { - index = GameUtil.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 & Defines.DROPPED_ITEM) && (GameBase.deathmatch.value != 0)) - GameUtil.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 & Defines.HEALTH_IGNORE_MAX)) - if (other.health >= other.max_health) - return false; - - other.health += ent.count; - - if (0 == (ent.style & Defines.HEALTH_IGNORE_MAX)) - { - if (other.health > other.max_health) - other.health = other.max_health; - } - - if (0 != (ent.style & Defines.HEALTH_TIMED)) - { - ent.think = MegaHealth_think; - ent.nextthink = GameBase.level.time + 5f; - ent.owner = other; - ent.flags |= Defines.FL_RESPAWN; - ent.svflags |= Defines.SVF_NOCLIENT; - ent.solid = Defines.SOLID_NOT; - } - else - { - if (!((ent.spawnflags & Defines.DROPPED_ITEM) != 0) && (GameBase.deathmatch.value != 0)) - GameUtil.SetRespawn(ent, 30); - } - - return true; - } - - }; - /* - =============== - 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 (ent.classname.equals("item_breather")) - taken = false; - - - 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[Defines.STAT_PICKUP_ICON] = (short) GameBase.gi.imageindex(ent.item.icon); - other.client.ps.stats[Defines.STAT_PICKUP_STRING] = (short) (Defines.CS_ITEMS + GameUtil.ITEM_INDEX(ent.item)); - other.client.pickup_msg_time = GameBase.level.time + 3.0f; - - // change selected item - if (ent.item.use != null) - other.client.pers.selected_item = - other.client.ps.stats[Defines.STAT_SELECTED_ITEM] = (short) GameUtil.ITEM_INDEX(ent.item); - - if (ent.item.pickup == Pickup_Health) - { - if (ent.count == 2) - GameBase.gi.sound( - other, - Defines.CHAN_ITEM, - GameBase.gi.soundindex("items/s_health.wav"), - 1, - Defines.ATTN_NORM, - 0); - else if (ent.count == 10) - GameBase.gi.sound( - other, - Defines.CHAN_ITEM, - GameBase.gi.soundindex("items/n_health.wav"), - 1, - Defines.ATTN_NORM, - 0); - else if (ent.count == 25) - GameBase.gi.sound( - other, - Defines.CHAN_ITEM, - GameBase.gi.soundindex("items/l_health.wav"), - 1, - Defines.ATTN_NORM, - 0); - else // (ent.count == 100) - GameBase.gi.sound( - other, - Defines.CHAN_ITEM, - GameBase.gi.soundindex("items/m_health.wav"), - 1, - Defines.ATTN_NORM, - 0); - } - else if (ent.item.pickup_sound != null) - { - GameBase.gi.sound( - other, - Defines.CHAN_ITEM, - GameBase.gi.soundindex(ent.item.pickup_sound), - 1, - Defines.ATTN_NORM, - 0); - } - } - - if (0 == (ent.spawnflags & Defines.ITEM_TARGETS_USED)) - { - GameUtil.G_UseTargets(ent, other); - ent.spawnflags |= Defines.ITEM_TARGETS_USED; - } - - if (!taken) - return; - //Com.p("Picked up:" + ent.classname); - - if (!((GameBase.coop.value != 0) && (ent.item.flags & Defines.IT_STAY_COOP) != 0) - || 0 != (ent.spawnflags & (Defines.DROPPED_ITEM | Defines.DROPPED_PLAYER_ITEM))) - { - if ((ent.flags & Defines.FL_RESPAWN) != 0) - ent.flags &= ~Defines.FL_RESPAWN; - else - GameUtil.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 (GameBase.deathmatch.value != 0) - { - ent.nextthink = GameBase.level.time + 29; - ent.think = G_FreeEdictA; - } - return false; - } - }; - 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[GameUtil.ITEM_INDEX(item)]--; - GameUtil.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 > GameBase.level.framenum) - ent.client.quad_framenum += timeout; - else - ent.client.quad_framenum = GameBase.level.framenum + timeout; - - GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi.soundindex("items/damage.wav"), 1, Defines.ATTN_NORM, 0); - } - }; - static ItemUseAdapter Use_Invulnerability = new ItemUseAdapter() - { - public void use(edict_t ent, gitem_t item) - { - ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)]--; - GameUtil.ValidateSelectedItem(ent); - - if (ent.client.invincible_framenum > GameBase.level.framenum) - ent.client.invincible_framenum += 300; - else - ent.client.invincible_framenum = GameBase.level.framenum + 300; - - GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi.soundindex("items/protect.wav"), 1, Defines.ATTN_NORM, 0); - } - }; - // ====================================================================== - - static ItemUseAdapter Use_Breather = new ItemUseAdapter() - { - public void use(edict_t ent, gitem_t item) - { - ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)]--; - - //TODO: remove this line - //ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)]=0; - - GameUtil.ValidateSelectedItem(ent); - - if (ent.client.breather_framenum > GameBase.level.framenum) - ent.client.breather_framenum += 300; - else - ent.client.breather_framenum = GameBase.level.framenum + 300; - - GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi.soundindex("items/damage.wav"), 1, Defines.ATTN_NORM, 0); - } - }; - // ====================================================================== - - static ItemUseAdapter Use_Envirosuit = new ItemUseAdapter() - { - public void use(edict_t ent, gitem_t item) - { - ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)]--; - GameUtil.ValidateSelectedItem(ent); - - if (ent.client.enviro_framenum > GameBase.level.framenum) - ent.client.enviro_framenum += 300; - else - ent.client.enviro_framenum = GameBase.level.framenum + 300; - - GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi.soundindex("items/damage.wav"), 1, Defines.ATTN_NORM, 0); - } - }; - - // ====================================================================== - - static ItemUseAdapter Use_Silencer = new ItemUseAdapter() - { - public void use(edict_t ent, gitem_t item) - { - - ent.client.pers.inventory[GameUtil.ITEM_INDEX(item)]--; - GameUtil.ValidateSelectedItem(ent); - ent.client.silencer_shots += 30; - - GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi.soundindex("items/damage.wav"), 1, Defines.ATTN_NORM, 0); - } - }; - // ====================================================================== - - static EntInteractAdapter Pickup_Key = new EntInteractAdapter() - { - public boolean interact(edict_t ent, edict_t other) - { - if (GameBase.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[GameUtil.ITEM_INDEX(ent.item)]++; - other.client.pers.power_cubes |= ((ent.spawnflags & 0x0000ff00) >> 8); - } - else - { - if (other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)] != 0) - return false; - other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)] = 1; - } - return true; - } - other.client.pers.inventory[GameUtil.ITEM_INDEX(ent.item)]++; - return true; - } - }; - 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; - /* - ============= - 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 = - GameBase.gi.trace( - spot1, - null, - null, - spot2, - self, - Defines.CONTENTS_SOLID - | Defines.CONTENTS_MONSTER - | Defines.CONTENTS_SLIME - | Defines.CONTENTS_LAVA - | Defines.CONTENTS_WINDOW); - - // do we have a clear shot? - if (tr.ent != self.enemy) - return false; - } - - // melee attack - if (enemy_range == Defines.RANGE_MELEE) - { - // don't always melee in easy mode - if (GameBase.skill.value == 0 && (Lib.rand() & 3) != 0) - return false; - if (self.monsterinfo.melee != null) - self.monsterinfo.attack_state = Defines.AS_MELEE; - else - self.monsterinfo.attack_state = Defines.AS_MISSILE; - return true; - } - - // missile attack - if (self.monsterinfo.attack == null) - return false; - - if (GameBase.level.time < self.monsterinfo.attack_finished) - return false; - - if (enemy_range == Defines.RANGE_FAR) - return false; - - if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0) - { - chance = 0.4f; - } - else if (enemy_range == Defines.RANGE_MELEE) - { - chance = 0.2f; - } - else if (enemy_range == Defines.RANGE_NEAR) - { - chance = 0.1f; - } - else if (enemy_range == Defines.RANGE_MID) - { - chance = 0.02f; - } - else - { - return false; - } - - if (GameBase.skill.value == 0) - chance *= 0.5; - else if (GameBase.skill.value >= 2) - chance *= 2; - - if (Lib.random() < chance) - { - self.monsterinfo.attack_state = Defines.AS_MISSILE; - self.monsterinfo.attack_finished = GameBase.level.time + 2 * Lib.random(); - return true; - } - - if ((self.flags & Defines.FL_FLY) != 0) - { - if (Lib.random() < 0.3f) - self.monsterinfo.attack_state = Defines.AS_SLIDING; - else - self.monsterinfo.attack_state = Defines.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 & Defines.FL_NOTARGET) != 0) - return; - if ((null == activator.client) && 0 == (activator.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) - return; - - // delay reaction so if the monster is teleported, its sound is still heard - self.enemy = activator; - GameUtil.FoundTarget(self); - } - }; - static boolean enemy_vis; - static boolean enemy_infront; - static int enemy_range; - static float enemy_yaw; -} diff --git a/src/jake2/game/GameWeapon.java b/src/jake2/game/GameWeapon.java index 5431584..e37867f 100644 --- a/src/jake2/game/GameWeapon.java +++ b/src/jake2/game/GameWeapon.java @@ -1,129 +1,519 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 12.11.2003 by RST. +// $Id: GameWeapon.java,v 1.3 2004-09-22 19:22:02 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.Globals; +import jake2.util.*; -See the GNU General Public License for more details. +public class GameWeapon { -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. + /* + * =============== 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 == Defines.PNOISE_WEAPON) { + if (who.client.silencer_shots == 0) { + who.client.silencer_shots--; + return; + } + } -// Created on 12.11.2003 by RST. -// $Id: GameWeapon.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + if (GameBase.deathmatch.value != 0) + return; -package jake2.game; + if ((who.flags & Defines.FL_NOTARGET) != 0) + return; -import jake2.Defines; -import jake2.Globals; -import jake2.util.*; + if (who.mynoise == null) { + noise = GameUtil.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 = Defines.SVF_NOCLIENT; + who.mynoise = noise; + + noise = GameUtil.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 = Defines.SVF_NOCLIENT; + who.mynoise2 = noise; + } + + if (type == Defines.PNOISE_SELF || type == Defines.PNOISE_WEAPON) { + noise = who.mynoise; + GameBase.level.sound_entity = noise; + GameBase.level.sound_entity_framenum = GameBase.level.framenum; + } else // type == PNOISE_IMPACT + { + noise = who.mynoise2; + GameBase.level.sound2_entity = noise; + GameBase.level.sound2_entity_framenum = GameBase.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 = GameBase.level.time; + GameBase.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 (GameBase.skill.value == 0) { + if (Lib.random() > 0.25) + return; + } + Math3D.VectorMA(start, 8192, dir, end); + tr = GameBase.gi.trace(start, null, null, end, self, Defines.MASK_SHOT); + if ((tr.ent != null) && (tr.ent.svflags & Defines.SVF_MONSTER) != 0 + && (tr.ent.health > 0) && (null != tr.ent.monsterinfo.dodge) + && GameUtil.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 & Defines.SURF_SKY) != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + if (self.owner.client != null) + GameWeapon.PlayerNoise(self.owner, self.s.origin, + Defines.PNOISE_IMPACT); + + if (other.takedamage != 0) { + if ((self.spawnflags & 1) != 0) + mod = Defines.MOD_HYPERBLASTER; + else + mod = Defines.MOD_BLASTER; + + // bugfix null plane rst + float[] normal; + if (plane == null) + normal = new float[3]; + else + normal = plane.normal; + + GameUtil.T_Damage(other, self, self.owner, self.velocity, + self.s.origin, normal, self.dmg, 1, + Defines.DAMAGE_ENERGY, mod); + + } else { + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_BLASTER); + GameBase.gi.WritePosition(self.s.origin); + if (plane == null) + GameBase.gi.WriteDir(Globals.vec3_origin); + else + GameBase.gi.WriteDir(plane.normal); + GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); + } + + GameUtil.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) + GameWeapon.PlayerNoise(ent.owner, ent.s.origin, + Defines.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 = Defines.MOD_HANDGRENADE; + else + mod = Defines.MOD_GRENADE; + GameUtil.T_Damage(ent.enemy, ent, ent.owner, dir, ent.s.origin, + Globals.vec3_origin, (int) points, (int) points, + Defines.DAMAGE_RADIUS, mod); + } + + if ((ent.spawnflags & 2) != 0) + mod = Defines.MOD_HELD_GRENADE; + else if ((ent.spawnflags & 1) != 0) + mod = Defines.MOD_HG_SPLASH; + else + mod = Defines.MOD_G_SPLASH; + GameUtil.T_RadiusDamage(ent, ent.owner, ent.dmg, ent.enemy, + ent.dmg_radius, mod); + + Math3D.VectorMA(ent.s.origin, -0.02f, ent.velocity, origin); + GameBase.gi.WriteByte(Defines.svc_temp_entity); + if (ent.waterlevel != 0) { + if (ent.groundentity != null) + GameBase.gi.WriteByte(Defines.TE_GRENADE_EXPLOSION_WATER); + else + GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION_WATER); + } else { + if (ent.groundentity != null) + GameBase.gi.WriteByte(Defines.TE_GRENADE_EXPLOSION); + else + GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION); + } + GameBase.gi.WritePosition(origin); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PHS); + + GameUtil.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 & Defines.SURF_SKY)) { + GameUtil.G_FreeEdict(ent); + return; + } + + if (other.takedamage == 0) { + if ((ent.spawnflags & 1) != 0) { + if (Lib.random() > 0.5f) + GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi + .soundindex("weapons/hgrenb1a.wav"), 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi + .soundindex("weapons/hgrenb2a.wav"), 1, + Defines.ATTN_NORM, 0); + } else { + GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi + .soundindex("weapons/grenlb1b.wav"), 1, + Defines.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 & Defines.SURF_SKY) != 0) { + GameUtil.G_FreeEdict(ent); + return; + } + + if (ent.owner.client != null) + GameWeapon.PlayerNoise(ent.owner, ent.s.origin, + Defines.PNOISE_IMPACT); + + // calculate position for the explosion entity + Math3D.VectorMA(ent.s.origin, -0.02f, ent.velocity, origin); + + if (other.takedamage != 0) { + GameUtil.T_Damage(other, ent, ent.owner, ent.velocity, + ent.s.origin, plane.normal, ent.dmg, 0, 0, + Defines.MOD_ROCKET); + } else { + // don't throw any debris in net games + if (GameBase.deathmatch.value == 0 && 0 == GameBase.coop.value) { + if ((surf != null) + && 0 == (surf.flags & (Defines.SURF_WARP + | Defines.SURF_TRANS33 + | Defines.SURF_TRANS66 | Defines.SURF_FLOWING))) { + n = Lib.rand() % 5; + while (n-- > 0) + GameAI.ThrowDebris(ent, + "models/objects/debris2/tris.md2", 2, + ent.s.origin); + } + } + } + + GameUtil.T_RadiusDamage(ent, ent.owner, ent.radius_dmg, other, + ent.dmg_radius, Defines.MOD_R_SPLASH); + + GameBase.gi.WriteByte(Defines.svc_temp_entity); + if (ent.waterlevel != 0) + GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION_WATER); + else + GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION); + GameBase.gi.WritePosition(origin); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PHS); + + GameUtil.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 = GameBase.findradius(edit, self.s.origin, + self.dmg_radius)) != null) { + ent = edit.o; + if (ent.takedamage == 0) + continue; + if (ent == self.owner) + continue; + if (!GameUtil.CanDamage(ent, self)) + continue; + if (!GameUtil.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; + + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_BFG_EXPLOSION); + GameBase.gi.WritePosition(ent.s.origin); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PHS); + GameUtil.T_Damage(ent, self, self.owner, self.velocity, + ent.s.origin, Globals.vec3_origin, (int) points, 0, + Defines.DAMAGE_ENERGY, Defines.MOD_BFG_EFFECT); + } + } + + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + self.s.frame++; + if (self.s.frame == 5) + self.think = GameUtil.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 & Defines.SURF_SKY) != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + if (self.owner.client != null) + GameWeapon.PlayerNoise(self.owner, self.s.origin, + Defines.PNOISE_IMPACT); + + // core explosion - prevents firing it into the wall/floor + if (other.takedamage != 0) + GameUtil.T_Damage(other, self, self.owner, self.velocity, + self.s.origin, plane.normal, 200, 0, 0, + Defines.MOD_BFG_BLAST); + GameUtil.T_RadiusDamage(self, self.owner, 200, other, 100, + Defines.MOD_BFG_BLAST); + + GameBase.gi.sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("weapons/bfg__x1b.wav"), 1, Defines.ATTN_NORM, + 0); + self.solid = Defines.SOLID_NOT; + self.touch = null; + Math3D.VectorMA(self.s.origin, -1 * Defines.FRAMETIME, + self.velocity, self.s.origin); + Math3D.VectorClear(self.velocity); + self.s.modelindex = GameBase.gi.modelindex("sprites/s_bfg3.sp2"); + self.s.frame = 0; + self.s.sound = 0; + self.s.effects &= ~Defines.EF_ANIM_ALLFAST; + self.think = bfg_explode; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + self.enemy = other; + + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_BFG_BIGEXPLOSION); + GameBase.gi.WritePosition(self.s.origin); + GameBase.gi.multicast(self.s.origin, Defines.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 (GameBase.deathmatch.value != 0) + dmg = 5; + else + dmg = 10; + + EdictIterator edit = null; + while ((edit = GameBase.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 & Defines.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 = GameBase.gi.trace(start, null, null, end, ignore, + Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER + | Defines.CONTENTS_DEADMONSTER); + + if (null == tr.ent) + break; + + // hurt it if we can + if ((tr.ent.takedamage != 0) + && 0 == (tr.ent.flags & Defines.FL_IMMUNE_LASER) + && (tr.ent != self.owner)) + GameUtil.T_Damage(tr.ent, self, self.owner, dir, + tr.endpos, Globals.vec3_origin, dmg, 1, + Defines.DAMAGE_ENERGY, Defines.MOD_BFG_LASER); + + // if we hit something that's not a monster or player we're + // done + if (0 == (tr.ent.svflags & Defines.SVF_MONSTER) + && (null == tr.ent.client)) { + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_LASER_SPARKS); + GameBase.gi.WriteByte(4); + GameBase.gi.WritePosition(tr.endpos); + GameBase.gi.WriteDir(tr.plane.normal); + GameBase.gi.WriteByte(self.s.skinnum); + GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS); + break; + } + + ignore = tr.ent; + Math3D.VectorCopy(tr.endpos, start); + } + + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_BFG_LASER); + GameBase.gi.WritePosition(self.s.origin); + GameBase.gi.WritePosition(tr.endpos); + GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS); + } -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); - } - } - -} + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + return true; + } + }; +} \ No newline at end of file diff --git a/src/jake2/game/GameWeaponAdapters.java b/src/jake2/game/GameWeaponAdapters.java deleted file mode 100644 index 1a37948..0000000 --- a/src/jake2/game/GameWeaponAdapters.java +++ /dev/null @@ -1,474 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: GameWeaponAdapters.java,v 1.1 2004-07-08 15:58:44 hzi Exp $ - -package jake2.game; - -import jake2.util.Lib; -import jake2.util.Math3D; -import jake2.Defines; -import jake2.Globals; -import jake2.util.*; - -public class GameWeaponAdapters { - - /* - ================= - 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 & Defines.SURF_SKY) != 0) { - GameUtil.G_FreeEdict(self); - return; - } - - if (self.owner.client != null) - GameWeapon.PlayerNoise(self.owner, self.s.origin, Defines.PNOISE_IMPACT); - - if (other.takedamage != 0) { - if ((self.spawnflags & 1) != 0) - mod= Defines.MOD_HYPERBLASTER; - else - mod= Defines.MOD_BLASTER; - - // bugfix null plane rst - float [] normal; - if (plane ==null) - normal = new float[3]; - else - normal = plane.normal; - - GameUtil.T_Damage( - other, - self, - self.owner, - self.velocity, - self.s.origin, - normal, - self.dmg, - 1, - Defines.DAMAGE_ENERGY, - mod); - - } else { - GameBase.gi.WriteByte(Defines.svc_temp_entity); - GameBase.gi.WriteByte(Defines.TE_BLASTER); - GameBase.gi.WritePosition(self.s.origin); - if (plane == null) - GameBase.gi.WriteDir(Globals.vec3_origin); - else - GameBase.gi.WriteDir(plane.normal); - GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); - } - - GameUtil.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) - GameWeapon.PlayerNoise(ent.owner, ent.s.origin, Defines.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= Defines.MOD_HANDGRENADE; - else - mod= Defines.MOD_GRENADE; - GameUtil.T_Damage( - ent.enemy, - ent, - ent.owner, - dir, - ent.s.origin, - Globals.vec3_origin, - (int) points, - (int) points, - Defines.DAMAGE_RADIUS, - mod); - } - - if ((ent.spawnflags & 2) != 0) - mod= Defines.MOD_HELD_GRENADE; - else if ((ent.spawnflags & 1) != 0) - mod= Defines.MOD_HG_SPLASH; - else - mod= Defines.MOD_G_SPLASH; - GameUtil.T_RadiusDamage(ent, ent.owner, ent.dmg, ent.enemy, ent.dmg_radius, mod); - - Math3D.VectorMA(ent.s.origin, -0.02f, ent.velocity, origin); - GameBase.gi.WriteByte(Defines.svc_temp_entity); - if (ent.waterlevel != 0) { - if (ent.groundentity != null) - GameBase.gi.WriteByte(Defines.TE_GRENADE_EXPLOSION_WATER); - else - GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION_WATER); - } else { - if (ent.groundentity != null) - GameBase.gi.WriteByte(Defines.TE_GRENADE_EXPLOSION); - else - GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION); - } - GameBase.gi.WritePosition(origin); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PHS); - - GameUtil.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 & Defines.SURF_SKY)) { - GameUtil.G_FreeEdict(ent); - return; - } - - if (other.takedamage == 0) { - if ((ent.spawnflags & 1) != 0) { - if (Lib.random() > 0.5f) - GameBase.gi.sound( - ent, - Defines.CHAN_VOICE, - GameBase.gi.soundindex("weapons/hgrenb1a.wav"), - 1, - Defines.ATTN_NORM, - 0); - else - GameBase.gi.sound( - ent, - Defines.CHAN_VOICE, - GameBase.gi.soundindex("weapons/hgrenb2a.wav"), - 1, - Defines.ATTN_NORM, - 0); - } else { - GameBase.gi.sound( - ent, - Defines.CHAN_VOICE, - GameBase.gi.soundindex("weapons/grenlb1b.wav"), - 1, - Defines.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 & Defines.SURF_SKY) != 0) { - GameUtil.G_FreeEdict(ent); - return; - } - - if (ent.owner.client != null) - GameWeapon.PlayerNoise(ent.owner, ent.s.origin, Defines.PNOISE_IMPACT); - - // calculate position for the explosion entity - Math3D.VectorMA(ent.s.origin, -0.02f, ent.velocity, origin); - - if (other.takedamage != 0) { - GameUtil.T_Damage( - other, - ent, - ent.owner, - ent.velocity, - ent.s.origin, - plane.normal, - ent.dmg, - 0, - 0, - Defines.MOD_ROCKET); - } else { - // don't throw any debris in net games - if (GameBase.deathmatch.value == 0 && 0 == GameBase.coop.value) { - if ((surf != null) - && 0 - == (surf.flags - & (Defines.SURF_WARP | Defines.SURF_TRANS33 | Defines.SURF_TRANS66 | Defines.SURF_FLOWING))) { - n= Lib.rand() % 5; - while (n-- > 0) - GameAI.ThrowDebris(ent, "models/objects/debris2/tris.md2", 2, ent.s.origin); - } - } - } - - GameUtil.T_RadiusDamage(ent, ent.owner, ent.radius_dmg, other, ent.dmg_radius, Defines.MOD_R_SPLASH); - - GameBase.gi.WriteByte(Defines.svc_temp_entity); - if (ent.waterlevel != 0) - GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION_WATER); - else - GameBase.gi.WriteByte(Defines.TE_ROCKET_EXPLOSION); - GameBase.gi.WritePosition(origin); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PHS); - - GameUtil.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= GameBase.findradius(edit, self.s.origin, self.dmg_radius)) != null) { - ent= edit.o; - if (ent.takedamage == 0) - continue; - if (ent == self.owner) - continue; - if (!GameUtil.CanDamage(ent, self)) - continue; - if (!GameUtil.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; - - GameBase.gi.WriteByte(Defines.svc_temp_entity); - GameBase.gi.WriteByte(Defines.TE_BFG_EXPLOSION); - GameBase.gi.WritePosition(ent.s.origin); - GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PHS); - GameUtil.T_Damage( - ent, - self, - self.owner, - self.velocity, - ent.s.origin, - Globals.vec3_origin, - (int) points, - 0, - Defines.DAMAGE_ENERGY, - Defines.MOD_BFG_EFFECT); - } - } - - self.nextthink= GameBase.level.time + Defines.FRAMETIME; - self.s.frame++; - if (self.s.frame == 5) - self.think= GameUtilAdapters.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 & Defines.SURF_SKY) != 0) { - GameUtil.G_FreeEdict(self); - return; - } - - if (self.owner.client != null) - GameWeapon.PlayerNoise(self.owner, self.s.origin, Defines.PNOISE_IMPACT); - - // core explosion - prevents firing it into the wall/floor - if (other.takedamage != 0) - GameUtil.T_Damage( - other, - self, - self.owner, - self.velocity, - self.s.origin, - plane.normal, - 200, - 0, - 0, - Defines.MOD_BFG_BLAST); - GameUtil.T_RadiusDamage(self, self.owner, 200, other, 100, Defines.MOD_BFG_BLAST); - - GameBase.gi.sound(self, Defines.CHAN_VOICE, GameBase.gi.soundindex("weapons/bfg__x1b.wav"), 1, Defines.ATTN_NORM, 0); - self.solid= Defines.SOLID_NOT; - self.touch= null; - Math3D.VectorMA(self.s.origin, -1 * Defines.FRAMETIME, self.velocity, self.s.origin); - Math3D.VectorClear(self.velocity); - self.s.modelindex= GameBase.gi.modelindex("sprites/s_bfg3.sp2"); - self.s.frame= 0; - self.s.sound= 0; - self.s.effects &= ~Defines.EF_ANIM_ALLFAST; - self.think= bfg_explode; - self.nextthink= GameBase.level.time + Defines.FRAMETIME; - self.enemy= other; - - GameBase.gi.WriteByte(Defines.svc_temp_entity); - GameBase.gi.WriteByte(Defines.TE_BFG_BIGEXPLOSION); - GameBase.gi.WritePosition(self.s.origin); - GameBase.gi.multicast(self.s.origin, Defines.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 (GameBase.deathmatch.value != 0) - dmg= 5; - else - dmg= 10; - - EdictIterator edit= null; - while ((edit= GameBase.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 & Defines.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= - GameBase.gi.trace( - start, - null, - null, - end, - ignore, - Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER | Defines.CONTENTS_DEADMONSTER); - - if (null == tr.ent) - break; - - // hurt it if we can - if ((tr.ent.takedamage != 0) - && 0 == (tr.ent.flags & Defines.FL_IMMUNE_LASER) - && (tr.ent != self.owner)) - GameUtil.T_Damage( - tr.ent, - self, - self.owner, - dir, - tr.endpos, - Globals.vec3_origin, - dmg, - 1, - Defines.DAMAGE_ENERGY, - Defines.MOD_BFG_LASER); - - // if we hit something that's not a monster or player we're done - if (0 == (tr.ent.svflags & Defines.SVF_MONSTER) && (null == tr.ent.client)) { - GameBase.gi.WriteByte(Defines.svc_temp_entity); - GameBase.gi.WriteByte(Defines.TE_LASER_SPARKS); - GameBase.gi.WriteByte(4); - GameBase.gi.WritePosition(tr.endpos); - GameBase.gi.WriteDir(tr.plane.normal); - GameBase.gi.WriteByte(self.s.skinnum); - GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS); - break; - } - - ignore= tr.ent; - Math3D.VectorCopy(tr.endpos, start); - } - - GameBase.gi.WriteByte(Defines.svc_temp_entity); - GameBase.gi.WriteByte(Defines.TE_BFG_LASER); - GameBase.gi.WritePosition(self.s.origin); - GameBase.gi.WritePosition(tr.endpos); - GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS); - } - - self.nextthink= GameBase.level.time + Defines.FRAMETIME; - return true; - } - }; -} diff --git a/src/jake2/game/Info.java b/src/jake2/game/Info.java index b13b065..f7d8b8d 100644 --- a/src/jake2/game/Info.java +++ b/src/jake2/game/Info.java @@ -1,263 +1,211 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 27.12.2003 by RST. +// $Id: Info.java,v 1.4 2004-09-22 19:22:03 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.qcommon.Com; -See the GNU General Public License for more details. +import java.util.StringTokenizer; -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. +public class Info { -*/ + public static String Info_ValueForKey(String s, String key) { -// Created on 27.12.2003 by RST. -// $Id: Info.java,v 1.3 2004-09-10 19:02:54 salomo Exp $ + StringTokenizer tk = new StringTokenizer(s, "\\"); -package jake2.game; + while (tk.hasMoreTokens()) { + String key1 = tk.nextToken(); -import java.util.StringTokenizer; + if (!tk.hasMoreTokens()) { + Com.Printf("MISSING VALUE\n"); + return s; + } + String value1 = tk.nextToken(); + + if (key.equals(key1)) + return value1; + } + + return ""; + } + + /** + * TODO RST: DANGEROUS port, 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 (key.length() > Defines.MAX_INFO_KEY - 1 + || value.length() > Defines.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(); + } + + /** TODO RST: DANGEROUS port, returns now the modified userinfo string. */ + public static String Info_RemoveKey1(String s, String key) { + + StringBuffer sb = new StringBuffer(512); -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 ""; - } - - /**TODO RST: DANGEROUS port, 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 (key.length() > MAX_INFO_KEY - 1 || value.length() > 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(); - } - - - - /** TODO RST: DANGEROUS port, 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!"); - } - -} + 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!"); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Actor.java b/src/jake2/game/M_Actor.java index 24484ab..1e5ef59 100644 --- a/src/jake2/game/M_Actor.java +++ b/src/jake2/game/M_Actor.java @@ -1,1129 +1,1584 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 11.11.2003 by RST. +// $Id: M_Actor.java,v 1.4 2004-09-22 19:22:01 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Actor { + // This file generated by ModelGen - Do NOT Modify -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. + public final static int FRAME_attak01 = 0; -*/ + public final static int FRAME_attak02 = 1; -// Created on 11.11.2003 by RST. -// $Id: M_Actor.java,v 1.3 2004-07-09 06:50:49 hzi Exp $ + public final static int FRAME_attak03 = 2; -package jake2.game; + 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 (GameBase.level.time < 1.0) + self.s.frame = self.monsterinfo.currentmove.firstframe + + (Lib.rand() % (self.monsterinfo.currentmove.lastframe + - self.monsterinfo.currentmove.firstframe + 1)); + return true; + } + }; -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(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.ai_stand, 0f, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 10, null), - new mframe_t(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.ai_walk, 10, null), - new mframe_t(GameAIAdapters.ai_walk, 1, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 4, null), - new mframe_t(GameAIAdapters.ai_run, 15, null), - new mframe_t(GameAIAdapters.ai_run, 15, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 20, null), - new mframe_t(GameAIAdapters.ai_run, 15, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 17, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, -2, null), - new mframe_t(GameAIAdapters.ai_run, -2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.ai_turn, 0, null), - new mframe_t(GameAIAdapters.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; - //GameBase.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 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 actor_frames_death1[]= - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -13, null), - new mframe_t(GameAIAdapters.ai_move, 14, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 7, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -9, null), - new mframe_t(GameAIAdapters.ai_move, -13, null), - new mframe_t(GameAIAdapters.ai_move, -13, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, -2, actor_fire), - new mframe_t(GameAIAdapters.ai_charge, -2, null), - new mframe_t(GameAIAdapters.ai_charge, 3, null), - new mframe_t(GameAIAdapters.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; - - GameAIAdapters.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); - } -} + static mframe_t actor_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.ai_stand, 0f, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 10, null), + new mframe_t(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.ai_walk, 10, null), + new mframe_t(GameAI.ai_walk, 1, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.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(GameAI.ai_run, 4, null), + new mframe_t(GameAI.ai_run, 15, null), + new mframe_t(GameAI.ai_run, 15, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 20, null), + new mframe_t(GameAI.ai_run, 15, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 17, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, -2, null), + new mframe_t(GameAI.ai_run, -2, null), + new mframe_t(GameAI.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 ((GameBase.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 & Defines.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(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.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(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.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(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.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(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.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(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.ai_turn, 0, null), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + //GameBase.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]; + + GameBase.gi.cprintf(other, Defines.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 EntThinkAdapter actor_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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t actor_frames_death1[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -13, null), + new mframe_t(GameAI.ai_move, 14, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 7, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -9, null), + new mframe_t(GameAI.ai_move, -13, null), + new mframe_t(GameAI.ai_move, -13, null), + new mframe_t(GameAI.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++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + // gi.sound (self, CHAN_VOICE, actor.sound_die, 1, ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 (GameBase.level.time >= self.monsterinfo.pausetime) + self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; + else + self.monsterinfo.aiflags |= Defines.AI_HOLD_FRAME; + + return true; + } + }; + + static mframe_t actor_frames_attack[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, -2, actor_fire), + new mframe_t(GameAI.ai_charge, -2, null), + new mframe_t(GameAI.ai_charge, 3, null), + new mframe_t(GameAI.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 = GameBase.level.time + n + * Defines.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 = GameBase + .G_PickTarget(self.target); + if ((null == self.movetarget) + || (Lib.strcmp(self.movetarget.classname, "target_actor") != 0)) { + GameBase.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[Defines.YAW] = Math3D.vectoyaw(v); + self.monsterinfo.walk.think(self); + self.target = null; + } + }; + + /* + * 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 <= GameBase.game.maxclients; n++) { + ent = GameBase.g_edicts[n]; + if (!ent.inuse) + continue; + GameBase.gi.cprintf(ent, Defines.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]; + GameBase.gi.sound(other, Defines.CHAN_VOICE, GameBase.gi + .soundindex("player/male/jump1.wav"), 1, + Defines.ATTN_NORM, 0); + } + } + + if ((self.spawnflags & 2) != 0) //shoot + { + } else if ((self.spawnflags & 4) != 0) //attack + { + other.enemy = GameBase.G_PickTarget(self.pathtarget); + if (other.enemy != null) { + other.goalentity = other.enemy; + if ((self.spawnflags & 32) != 0) + other.monsterinfo.aiflags |= Defines.AI_BRUTAL; + if ((self.spawnflags & 16) != 0) { + other.monsterinfo.aiflags |= Defines.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; + GameUtil.G_UseTargets(self, other); + self.target = savetarget; + } + + other.movetarget = GameBase.G_PickTarget(self.target); + + if (other.goalentity == null) + other.goalentity = other.movetarget; + + if (null == other.movetarget && null == other.enemy) { + other.monsterinfo.pausetime = GameBase.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 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, + M_Flash.monster_flash_offset[Defines.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, + Defines.DEFAULT_BULLET_HSPREAD, Defines.DEFAULT_BULLET_VSPREAD, + Defines.MZ2_ACTOR_MACHINEGUN_1); + } + + /** + * QUAKED misc_actor (1 .5 0) (-16 -16 -24) (16 16 32) + */ + + static void SP_misc_actor(edict_t self) { + if (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + if (self.targetname != null) { + GameBase.gi.dprintf("untargeted " + self.classname + " at " + + Lib.vtos(self.s.origin) + "\n"); + GameUtil.G_FreeEdict(self); + return; + } + + if (self.target != null) { + GameBase.gi.dprintf(self.classname + " with no target at " + + Lib.vtos(self.s.origin) + "\n"); + GameUtil.G_FreeEdict(self); + return; + } + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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 |= Defines.AI_GOOD_GUY; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = actor_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + + // actors always start in a dormant state, they *must* be used to get + // going + self.use = actor_use; + } + + static void SP_target_actor(edict_t self) { + if (self.targetname != null) + GameBase.gi.dprintf(self.classname + " with no targetname at " + + Lib.vtos(self.s.origin) + " \n"); + + self.solid = Defines.SOLID_TRIGGER; + self.touch = target_actor_touch; + Math3D.VectorSet(self.mins, -8, -8, -8); + Math3D.VectorSet(self.maxs, 8, 8, 8); + self.svflags = Defines.SVF_NOCLIENT; + + if ((self.spawnflags & 1) != 0) { + if (0 == self.speed) + self.speed = 200; + if (0 == GameBase.st.height) + GameBase.st.height = 200; + if (self.s.angles[Defines.YAW] == 0) + self.s.angles[Defines.YAW] = 360; + GameBase.G_SetMovedir(self.s.angles, self.movedir); + self.movedir[2] = GameBase.st.height; + } + + GameBase.gi.linkentity(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Berserk.java b/src/jake2/game/M_Berserk.java index 62c0d72..0b5c513 100644 --- a/src/jake2/game/M_Berserk.java +++ b/src/jake2/game/M_Berserk.java @@ -1,725 +1,975 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 11.11.2003 by RST +// $Id: M_Berserk.java,v 1.3 2004-09-22 19:22:03 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Berserk { -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. + public final static int FRAME_stand1 = 0; -*/ + public final static int FRAME_stand2 = 1; -// Created on 11.11.2003 by RST -// $Id: M_Berserk.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_stand3 = 2; -package jake2.game; + 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 boolean interact(edict_t self, edict_t other) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter berserk_search = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter berserk_fidget = new EntThinkAdapter() { + public boolean think(edict_t self) { + if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0) + return true; + + if (Lib.random() > 0.15f) + return true; + + self.monsterinfo.currentmove = berserk_move_stand_fidget; + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_idle, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; -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 boolean interact(edict_t self, edict_t other) { - gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0); - return true; - } - }; - - 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(GameAIAdapters.ai_stand, 0, berserk_fidget), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 9.1f, null), - new mframe_t(GameAIAdapters.ai_walk, 6.3f, null), - new mframe_t(GameAIAdapters.ai_walk, 4.9f, null), - new mframe_t(GameAIAdapters.ai_walk, 6.7f, null), - new mframe_t(GameAIAdapters.ai_walk, 6.0f, null), - new mframe_t(GameAIAdapters.ai_walk, 8.2f, null), - new mframe_t(GameAIAdapters.ai_walk, 7.2f, null), - new mframe_t(GameAIAdapters.ai_walk, 6.1f, null), - new mframe_t(GameAIAdapters.ai_walk, 4.9f, null), - new mframe_t(GameAIAdapters.ai_walk, 4.7f, null), - new mframe_t(GameAIAdapters.ai_walk, 4.7f, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 21, null), - new mframe_t(GameAIAdapters.ai_run, 11, null), - new mframe_t(GameAIAdapters.ai_run, 21, null), - new mframe_t(GameAIAdapters.ai_run, 25, null), - new mframe_t(GameAIAdapters.ai_run, 18, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, berserk_swing), - new mframe_t(GameAIAdapters.ai_charge, 0, berserk_attack_spike), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, berserk_swing), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, berserk_attack_club), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, berserk_swing), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, berserk_strike), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 9.7f, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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); - - GameAIAdapters.walkmonster_start.think(self); - } - -} + static mframe_t berserk_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, berserk_fidget), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 9.1f, null), + new mframe_t(GameAI.ai_walk, 6.3f, null), + new mframe_t(GameAI.ai_walk, 4.9f, null), + new mframe_t(GameAI.ai_walk, 6.7f, null), + new mframe_t(GameAI.ai_walk, 6.0f, null), + new mframe_t(GameAI.ai_walk, 8.2f, null), + new mframe_t(GameAI.ai_walk, 7.2f, null), + new mframe_t(GameAI.ai_walk, 6.1f, null), + new mframe_t(GameAI.ai_walk, 4.9f, null), + new mframe_t(GameAI.ai_walk, 4.7f, null), + new mframe_t(GameAI.ai_walk, 4.7f, null), + new mframe_t(GameAI.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(GameAI.ai_run, 21, null), + new mframe_t(GameAI.ai_run, 11, null), + new mframe_t(GameAI.ai_run, 21, null), + new mframe_t(GameAI.ai_run, 25, null), + new mframe_t(GameAI.ai_run, 18, null), + new mframe_t(GameAI.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 & Defines.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 = { Defines.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) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_punch, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t berserk_frames_attack_spike[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, berserk_swing), + new mframe_t(GameAI.ai_charge, 0, berserk_attack_spike), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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, Defines.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, berserk_swing), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, berserk_attack_club), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, berserk_swing), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, berserk_strike), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 9.7f, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain, 1, + Defines.ATTN_NORM, 0); + + if (GameBase.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t berserk_frames_death1[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_die, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + // pre-caches + sound_pain = GameBase.gi.soundindex("berserk/berpain2.wav"); + sound_die = GameBase.gi.soundindex("berserk/berdeth2.wav"); + sound_idle = GameBase.gi.soundindex("berserk/beridle1.wav"); + sound_punch = GameBase.gi.soundindex("berserk/attack.wav"); + sound_search = GameBase.gi.soundindex("berserk/bersrch1.wav"); + sound_sight = GameBase.gi.soundindex("berserk/sight.wav"); + + self.s.modelindex = GameBase.gi + .modelindex("models/monsters/berserk/tris.md2"); + Math3D.VectorSet(self.mins, -16, -16, -24); + Math3D.VectorSet(self.maxs, 16, 16, 32); + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.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; + + GameBase.gi.linkentity(self); + + GameAI.walkmonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Boss2.java b/src/jake2/game/M_Boss2.java index 8743764..4290ba8 100644 --- a/src/jake2/game/M_Boss2.java +++ b/src/jake2/game/M_Boss2.java @@ -1,899 +1,1062 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Boss2.java,v 1.3 2004-09-22 19:22:01 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Boss2 { -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. + public final static int FRAME_stand30 = 0; -*/ + public final static int FRAME_stand31 = 1; -// Created on 13.11.2003 by RST. -// $Id: M_Boss2.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_stand32 = 2; -package jake2.game; + 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 & Defines.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); -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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 1, Boss2MachineGun), - new mframe_t(GameAIAdapters.ai_charge, 1, Boss2MachineGun), - new mframe_t(GameAIAdapters.ai_charge, 1, Boss2MachineGun), - new mframe_t(GameAIAdapters.ai_charge, 1, Boss2MachineGun), - new mframe_t(GameAIAdapters.ai_charge, 1, Boss2MachineGun), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_move, -20, Boss2Rocket), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, GameAIAdapters.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; - - GameAIAdapters.flymonster_start.think(self); - } -} + 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 (GameUtil.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + // American wanted these at no attenuation + if (damage < 10) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain3, 1, + Defines.ATTN_NONE, 0); + self.monsterinfo.currentmove = boss2_move_pain_light; + } else if (damage < 30) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NONE, 0); + self.monsterinfo.currentmove = boss2_move_pain_light; + } else { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death, 1, + Defines.ATTN_NONE, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 = GameBase.gi.trace(spot1, null, null, spot2, self, + Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER + | Defines.CONTENTS_SLIME + | Defines.CONTENTS_LAVA); + + // do we have a clear shot? + if (tr.ent != self.enemy) + return false; + } + + enemy_infront = GameUtil.infront(self, self.enemy); + enemy_range = GameUtil.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 == Defines.RANGE_MELEE) { + if (self.monsterinfo.melee != null) + self.monsterinfo.attack_state = Defines.AS_MELEE; + else + self.monsterinfo.attack_state = Defines.AS_MISSILE; + return true; + } + + // missile attack + if (self.monsterinfo.attack == null) + return false; + + if (GameBase.level.time < self.monsterinfo.attack_finished) + return false; + + if (enemy_range == Defines.RANGE_FAR) + return false; + + if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0) { + chance = 0.4f; + } else if (enemy_range == Defines.RANGE_MELEE) { + chance = 0.8f; + } else if (enemy_range == Defines.RANGE_NEAR) { + chance = 0.8f; + } else if (enemy_range == Defines.RANGE_MID) { + chance = 0.8f; + } else { + return false; + } + + if (Lib.random() < chance) { + self.monsterinfo.attack_state = Defines.AS_MISSILE; + self.monsterinfo.attack_finished = GameBase.level.time + 2 + * Lib.random(); + return true; + } + + if ((self.flags & Defines.FL_FLY) != 0) { + if (Lib.random() < 0.3) + self.monsterinfo.attack_state = Defines.AS_SLIDING; + else + self.monsterinfo.attack_state = Defines.AS_STRAIGHT; + } + + return false; + } + }; + + static EntThinkAdapter boss2_search = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (Lib.random() < 0.5) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search1, 1, + Defines.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, + M_Flash.monster_flash_offset[Defines.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, + Defines.MZ2_BOSS2_ROCKET_1); + + // 2 + Math3D.G_ProjectSource(self.s.origin, + M_Flash.monster_flash_offset[Defines.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, + Defines.MZ2_BOSS2_ROCKET_2); + + // 3 + Math3D.G_ProjectSource(self.s.origin, + M_Flash.monster_flash_offset[Defines.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, + Defines.MZ2_BOSS2_ROCKET_3); + + // 4 + Math3D.G_ProjectSource(self.s.origin, + M_Flash.monster_flash_offset[Defines.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, + Defines.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, + M_Flash.monster_flash_offset[Defines.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, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.DEFAULT_BULLET_VSPREAD, + Defines.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, + M_Flash.monster_flash_offset[Defines.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, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.DEFAULT_BULLET_VSPREAD, + Defines.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.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(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 1, Boss2MachineGun), + new mframe_t(GameAI.ai_charge, 1, Boss2MachineGun), + new mframe_t(GameAI.ai_charge, 1, Boss2MachineGun), + new mframe_t(GameAI.ai_charge, 1, Boss2MachineGun), + new mframe_t(GameAI.ai_charge, 1, Boss2MachineGun), + new mframe_t(GameAI.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(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_move, -20, Boss2Rocket), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, GameAI.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_pain1 = GameBase.gi.soundindex("bosshovr/bhvpain1.wav"); + sound_pain2 = GameBase.gi.soundindex("bosshovr/bhvpain2.wav"); + sound_pain3 = GameBase.gi.soundindex("bosshovr/bhvpain3.wav"); + sound_death = GameBase.gi.soundindex("bosshovr/bhvdeth1.wav"); + sound_search1 = GameBase.gi.soundindex("bosshovr/bhvunqv1.wav"); + + self.s.sound = GameBase.gi.soundindex("bosshovr/bhvengn1.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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 |= Defines.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; + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = boss2_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.flymonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Boss3.java b/src/jake2/game/M_Boss3.java index ca41173..98d4108 100644 --- a/src/jake2/game/M_Boss3.java +++ b/src/jake2/game/M_Boss3.java @@ -1,76 +1,79 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 13.11.2003 by RST. -// $Id: M_Boss3.java,v 1.1 2004-07-07 19:59:09 hzi Exp $ - +// $Id: M_Boss3.java,v 1.2 2004-09-22 19:22:05 salomo 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); - } -} +import jake2.Defines; +import jake2.util.Math3D; + +public class M_Boss3 { + + static EntUseAdapter Use_Boss3 = new EntUseAdapter() { + public void use(edict_t ent, edict_t other, edict_t activator) { + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_BOSSTPORT); + GameBase.gi.WritePosition(ent.s.origin); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + GameUtil.G_FreeEdict(ent); + } + }; + + static EntThinkAdapter Think_Boss3Stand = new EntThinkAdapter() { + public boolean think(edict_t ent) { + if (ent.s.frame == M_Boss32.FRAME_stand260) + ent.s.frame = M_Boss32.FRAME_stand201; + else + ent.s.frame++; + ent.nextthink = GameBase.level.time + Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.model = "models/monsters/boss3/rider/tris.md2"; + self.s.modelindex = GameBase.gi.modelindex(self.model); + self.s.frame = M_Boss32.FRAME_stand201; + + GameBase.gi.soundindex("misc/bigtele.wav"); + + Math3D.VectorSet(self.mins, -32, -32, 0); + Math3D.VectorSet(self.maxs, 32, 32, 90); + + self.use = Use_Boss3; + self.think = Think_Boss3Stand; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + GameBase.gi.linkentity(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Boss31.java b/src/jake2/game/M_Boss31.java index 193ea3a..fec7e31 100644 --- a/src/jake2/game/M_Boss31.java +++ b/src/jake2/game/M_Boss31.java @@ -1,1012 +1,1186 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Boss31.java,v 1.3 2004-09-22 19:22:07 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Boss31 { -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. + public final static int FRAME_attak101 = 0; -*/ + public final static int FRAME_attak102 = 1; -// Created on 13.11.2003 by RST. -// $Id: M_Boss31.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_attak103 = 2; -package jake2.game; + 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) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search1, 1, + Defines.ATTN_NORM, 0); + else if (r <= 0.6) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search2, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search3, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter jorg_idle = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; -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(GameAIAdapters.ai_stand, 0, jorg_idle), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 10 - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 20 - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 30 - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 19, null), - new mframe_t(GameAIAdapters.ai_stand, 11, jorg_step_left), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 6, null), - new mframe_t(GameAIAdapters.ai_stand, 9, jorg_step_right), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 40 - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, -2, null), - new mframe_t(GameAIAdapters.ai_stand, -17, jorg_step_left), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, -12, null), - // 50 - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 17, jorg_step_left), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 33, jorg_step_right), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 9, null), - new mframe_t(GameAIAdapters.ai_run, 9, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.ai_walk, 9, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 17, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 12, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 10, null), - new mframe_t(GameAIAdapters.ai_walk, 33, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 9, null), - new mframe_t(GameAIAdapters.ai_walk, 9, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 11, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -28, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, -3, jorg_step_left), - new mframe_t(GameAIAdapters.ai_move, -9, null), - new mframe_t(GameAIAdapters.ai_move, 0, jorg_step_right), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -7, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, -11, null), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 10, null), - new mframe_t(GameAIAdapters.ai_move, 11, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 10, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 10, null), - new mframe_t(GameAIAdapters.ai_move, 7, jorg_step_left), - new mframe_t(GameAIAdapters.ai_move, 17, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 10 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 20 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 30 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 40 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, M_Boss32.MakronToss), - new mframe_t(GameAIAdapters.ai_move, 0, GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, jorgBFG), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, jorg_firebullet), - new mframe_t(GameAIAdapters.ai_charge, 0, jorg_firebullet), - new mframe_t(GameAIAdapters.ai_charge, 0, jorg_firebullet), - new mframe_t(GameAIAdapters.ai_charge, 0, jorg_firebullet), - new mframe_t(GameAIAdapters.ai_charge, 0, jorg_firebullet), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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; - - GameAIAdapters.walkmonster_start.think(self); - } - -} + static EntThinkAdapter jorg_death_hit = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_death_hit, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter jorg_step_left = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_step_left, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter jorg_step_right = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_step_right, 1, + Defines.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 (GameUtil.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 (GameBase.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 = GameBase.level.time + 3; + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + if (damage <= 50) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = jorg_move_pain1; + } else if (damage <= 100) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = jorg_move_pain2; + } else { + if (Lib.random() <= 0.3) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain3, 1, + Defines.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, + M_Flash.monster_flash_offset[Defines.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); + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_attack2, 1, + Defines.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, + Defines.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, + M_Flash.monster_flash_offset[Defines.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, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.DEFAULT_BULLET_VSPREAD, + Defines.MZ2_JORG_MACHINEGUN_R1); + 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, + M_Flash.monster_flash_offset[Defines.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, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.DEFAULT_BULLET_VSPREAD, + Defines.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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_attack1, 1, + Defines.ATTN_NORM, 0); + self.s.sound = GameBase.gi.soundindex("boss3/w_loop.wav"); + self.monsterinfo.currentmove = jorg_move_start_attack1; + } else { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_attack2, 1, + Defines.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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 = GameBase.gi.trace(spot1, null, null, spot2, self, + Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER + | Defines.CONTENTS_SLIME + | Defines.CONTENTS_LAVA); + + // do we have a clear shot? + if (tr.ent != self.enemy) + return false; + } + + enemy_infront = GameUtil.infront(self, self.enemy); + enemy_range = GameUtil.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 == Defines.RANGE_MELEE) { + if (self.monsterinfo.melee != null) + self.monsterinfo.attack_state = Defines.AS_MELEE; + else + self.monsterinfo.attack_state = Defines.AS_MISSILE; + return true; + } + + // missile attack ? + if (self.monsterinfo.attack == null) + return false; + + if (GameBase.level.time < self.monsterinfo.attack_finished) + return false; + + if (enemy_range == Defines.RANGE_FAR) + return false; + + if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0) { + chance = 0.4f; + } else if (enemy_range == Defines.RANGE_MELEE) { + chance = 0.8f; + } else if (enemy_range == Defines.RANGE_NEAR) { + chance = 0.4f; + } else if (enemy_range == Defines.RANGE_MID) { + chance = 0.2f; + } else { + return false; + } + + if (Lib.random() < chance) { + self.monsterinfo.attack_state = Defines.AS_MISSILE; + self.monsterinfo.attack_finished = GameBase.level.time + 2 + * Lib.random(); + return true; + } + + if ((self.flags & Defines.FL_FLY) != 0) { + if (Lib.random() < 0.3) + self.monsterinfo.attack_state = Defines.AS_SLIDING; + else + self.monsterinfo.attack_state = Defines.AS_STRAIGHT; + } + + return false; + } + }; + + // + // stand + // + + static mframe_t jorg_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, jorg_idle), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 10 + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 20 + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 30 + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 19, null), + new mframe_t(GameAI.ai_stand, 11, jorg_step_left), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 6, null), + new mframe_t(GameAI.ai_stand, 9, jorg_step_right), + new mframe_t(GameAI.ai_stand, 0, null), + // 40 + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, -2, null), + new mframe_t(GameAI.ai_stand, -17, jorg_step_left), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, -12, null), + // 50 + new mframe_t(GameAI.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(GameAI.ai_run, 17, jorg_step_left), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 33, jorg_step_right), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 9, null), + new mframe_t(GameAI.ai_run, 9, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.ai_walk, 9, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 17, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 12, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 10, null), + new mframe_t(GameAI.ai_walk, 33, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 9, null), + new mframe_t(GameAI.ai_walk, 9, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 11, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.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 & Defines.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(GameAI.ai_move, -28, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, -3, jorg_step_left), + new mframe_t(GameAI.ai_move, -9, null), + new mframe_t(GameAI.ai_move, 0, jorg_step_right), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -7, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, -11, null), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 10, null), + new mframe_t(GameAI.ai_move, 11, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 10, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 10, null), + new mframe_t(GameAI.ai_move, 7, jorg_step_left), + new mframe_t(GameAI.ai_move, 17, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 10 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 20 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 30 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 40 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, M_Boss32.MakronToss), + new mframe_t(GameAI.ai_move, 0, GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, jorgBFG), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, jorg_firebullet), + new mframe_t(GameAI.ai_charge, 0, jorg_firebullet), + new mframe_t(GameAI.ai_charge, 0, jorg_firebullet), + new mframe_t(GameAI.ai_charge, 0, jorg_firebullet), + new mframe_t(GameAI.ai_charge, 0, jorg_firebullet), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_pain1 = GameBase.gi.soundindex("boss3/bs3pain1.wav"); + sound_pain2 = GameBase.gi.soundindex("boss3/bs3pain2.wav"); + sound_pain3 = GameBase.gi.soundindex("boss3/bs3pain3.wav"); + sound_death = GameBase.gi.soundindex("boss3/bs3deth1.wav"); + sound_attack1 = GameBase.gi.soundindex("boss3/bs3atck1.wav"); + sound_attack2 = GameBase.gi.soundindex("boss3/bs3atck2.wav"); + sound_search1 = GameBase.gi.soundindex("boss3/bs3srch1.wav"); + sound_search2 = GameBase.gi.soundindex("boss3/bs3srch2.wav"); + sound_search3 = GameBase.gi.soundindex("boss3/bs3srch3.wav"); + sound_idle = GameBase.gi.soundindex("boss3/bs3idle1.wav"); + sound_step_left = GameBase.gi.soundindex("boss3/step1.wav"); + sound_step_right = GameBase.gi.soundindex("boss3/step2.wav"); + sound_firegun = GameBase.gi.soundindex("boss3/xfire.wav"); + sound_death_hit = GameBase.gi.soundindex("boss3/d_hit.wav"); + + M_Boss32.MakronPrecache(); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.gi + .modelindex("models/monsters/boss3/rider/tris.md2"); + self.s.modelindex2 = GameBase.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; + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = jorg_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Boss32.java b/src/jake2/game/M_Boss32.java index 8ba4382..d46dd50 100644 --- a/src/jake2/game/M_Boss32.java +++ b/src/jake2/game/M_Boss32.java @@ -1,1469 +1,1976 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Boss32.java,v 1.3 2004-09-22 19:22:01 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.Globals; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Boss32 { -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. + public final static int FRAME_attak101 = 0; -*/ + public final static int FRAME_attak102 = 1; -// Created on 13.11.2003 by RST. -// $Id: M_Boss32.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_attak103 = 2; -package jake2.game; + 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) + GameBase.gi.sound(self, Defines.CHAN_AUTO, sound_taunt1, 1, + Defines.ATTN_NONE, 0); + else if (r <= 0.6) + GameBase.gi.sound(self, Defines.CHAN_AUTO, sound_taunt2, 1, + Defines.ATTN_NONE, 0); + else + GameBase.gi.sound(self, Defines.CHAN_AUTO, sound_taunt3, 1, + Defines.ATTN_NONE, 0); + return true; + } + }; -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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 10 - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 20 - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 30 - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 40 - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 50 - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 3, makron_step_left), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, makron_step_right), - new mframe_t(GameAIAdapters.ai_run, 6, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 9, null), - new mframe_t(GameAIAdapters.ai_run, 6, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 3, makron_step_left), - new mframe_t(GameAIAdapters.ai_walk, 12, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 8, makron_step_right), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 12, null), - new mframe_t(GameAIAdapters.ai_walk, 9, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 10 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, makron_popup), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 20 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, makron_taunt), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -15, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, -12, null), - new mframe_t(GameAIAdapters.ai_move, 0, makron_step_left), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 10 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 11, null), - new mframe_t(GameAIAdapters.ai_move, 12, null), - new mframe_t(GameAIAdapters.ai_move, 11, makron_step_right), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 20 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 30 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.ai_move, 7, null), - new mframe_t(GameAIAdapters.ai_move, 6, makron_step_left), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - // 40 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 50 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, -6, makron_step_right), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, -4, makron_step_left), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 60 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, -3, makron_step_right), - new mframe_t(GameAIAdapters.ai_move, -8, null), - new mframe_t(GameAIAdapters.ai_move, -3, makron_step_left), - new mframe_t(GameAIAdapters.ai_move, -7, null), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, -4, makron_step_right), - // 70 - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, -7, null), - new mframe_t(GameAIAdapters.ai_move, 0, makron_step_left), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 80 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 90 - new mframe_t(GameAIAdapters.ai_move, 27, makron_hit), - new mframe_t(GameAIAdapters.ai_move, 26, null), - new mframe_t(GameAIAdapters.ai_move, 0, makron_brainsplorch), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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 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 interact(edict_t self, edict_t other) { - 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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, makronBFG), - // FIXME: BFG Attack here - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), - // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, MakronHyperblaster), // fire - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, makron_prerailgun), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, MakronSaveloc), - new mframe_t(GameAIAdapters.ai_move, 0, MakronRailgun), - // Fire railgun - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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; - - GameAIAdapters.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; - } - }; - -} + // + // 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) { + GameBase.gi.sound(self, Defines.CHAN_AUTO, sound_hit, 1, + Defines.ATTN_NONE, 0); + return true; + } + }; + + static EntThinkAdapter makron_popup = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_popup, 1, + Defines.ATTN_NONE, 0); + return true; + } + }; + + static EntThinkAdapter makron_step_left = new EntThinkAdapter() { + + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_step_left, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter makron_step_right = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_step_right, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter makron_brainsplorch = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_brainsplorch, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter makron_prerailgun = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_prerailgun, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t makron_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 10 + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 20 + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 30 + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 40 + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 50 + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_run, 3, makron_step_left), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, makron_step_right), + new mframe_t(GameAI.ai_run, 6, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 9, null), + new mframe_t(GameAI.ai_run, 6, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 3, makron_step_left), + new mframe_t(GameAI.ai_walk, 12, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 8, makron_step_right), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 12, null), + new mframe_t(GameAI.ai_walk, 9, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.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 & Defines.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 10 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, makron_popup), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 20 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, makron_taunt), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, -15, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, -12, null), + new mframe_t(GameAI.ai_move, 0, makron_step_left), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 10 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 11, null), + new mframe_t(GameAI.ai_move, 12, null), + new mframe_t(GameAI.ai_move, 11, makron_step_right), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 20 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 30 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.ai_move, 7, null), + new mframe_t(GameAI.ai_move, 6, makron_step_left), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 2, null), + // 40 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 50 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, -6, makron_step_right), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, -4, makron_step_left), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 60 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, -3, makron_step_right), + new mframe_t(GameAI.ai_move, -8, null), + new mframe_t(GameAI.ai_move, -3, makron_step_left), + new mframe_t(GameAI.ai_move, -7, null), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, -4, makron_step_right), + // 70 + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, -7, null), + new mframe_t(GameAI.ai_move, 0, makron_step_left), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 80 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + // 90 + new mframe_t(GameAI.ai_move, 27, makron_hit), + new mframe_t(GameAI.ai_move, 26, null), + new mframe_t(GameAI.ai_move, 0, makron_brainsplorch), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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, + M_Flash.monster_flash_offset[Defines.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); + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_attack_bfg, 1, + Defines.ATTN_NORM, 0); + Monster.monster_fire_bfg(self, start, dir, 50, 300, 100, 300, + Defines.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, + M_Flash.monster_flash_offset[Defines.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, + Defines.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 = Defines.MZ2_MAKRON_BLASTER_1 + + (self.s.frame - FRAME_attak405); + + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.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, + Defines.MZ2_MAKRON_BLASTER_1, Defines.EF_BLASTER); + + return true; + } + }; + + static EntPainAdapter makron_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 (GameBase.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 = GameBase.level.time + 3; + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + if (damage <= 40) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain4, 1, + Defines.ATTN_NONE, 0); + self.monsterinfo.currentmove = makron_move_pain4; + } else if (damage <= 110) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain5, 1, + Defines.ATTN_NONE, 0); + self.monsterinfo.currentmove = makron_move_pain5; + } else { + if (damage <= 150) + if (Lib.random() <= 0.45) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, + sound_pain6, 1, Defines.ATTN_NONE, 0); + self.monsterinfo.currentmove = makron_move_pain6; + } else if (Lib.random() <= 0.35) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, + sound_pain6, 1, Defines.ATTN_NONE, 0); + self.monsterinfo.currentmove = makron_move_pain6; + } + } + } + + }; + + static EntInteractAdapter makron_sight = new EntInteractAdapter() { + public boolean interact(edict_t self, edict_t other) { + 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 = GameBase.level.time + Defines.FRAMETIME; + else { + self.s.frame = 346; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + } + return true; + } + }; + + static EntThinkAdapter makron_torso = new EntThinkAdapter() { + public boolean think(edict_t ent) { + ent.movetype = Defines.MOVETYPE_NONE; + ent.solid = Defines.SOLID_NOT; + Math3D.VectorSet(ent.mins, -8, -8, 0); + Math3D.VectorSet(ent.maxs, 8, 8, 8); + ent.s.frame = 346; + ent.s.modelindex = GameBase.gi + .modelindex("models/monsters/boss3/rider/tris.md2"); + ent.think = makron_torso_think; + ent.nextthink = GameBase.level.time + 2 * Defines.FRAMETIME; + ent.s.sound = GameBase.gi.soundindex("makron/spine.wav"); + GameBase.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 1 /* 4 */; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_metal/tris.md2", damage, + Defines.GIB_METALLIC); + GameAI.ThrowHead(self, "models/objects/gibs/gear/tris.md2", + damage, Defines.GIB_METALLIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death, 1, + Defines.ATTN_NONE, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.DAMAGE_YES; + + tempent = GameUtil.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 = GameBase.gi.trace(spot1, null, null, spot2, self, + Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER + | Defines.CONTENTS_SLIME + | Defines.CONTENTS_LAVA); + + // do we have a clear shot? + if (tr.ent != self.enemy) + return false; + } + + enemy_infront = GameUtil.infront(self, self.enemy); + enemy_range = GameUtil.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 == Defines.RANGE_MELEE) { + if (self.monsterinfo.melee != null) + self.monsterinfo.attack_state = Defines.AS_MELEE; + else + self.monsterinfo.attack_state = Defines.AS_MISSILE; + return true; + } + + // missile attack + if (null != self.monsterinfo.attack) + return false; + + if (GameBase.level.time < self.monsterinfo.attack_finished) + return false; + + if (enemy_range == Defines.RANGE_FAR) + return false; + + if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0) { + chance = 0.4f; + } else if (enemy_range == Defines.RANGE_MELEE) { + chance = 0.8f; + } else if (enemy_range == Defines.RANGE_NEAR) { + chance = 0.4f; + } else if (enemy_range == Defines.RANGE_MID) { + chance = 0.2f; + } else { + return false; + } + + if (Lib.random() < chance) { + self.monsterinfo.attack_state = Defines.AS_MISSILE; + self.monsterinfo.attack_finished = GameBase.level.time + 2 + * Lib.random(); + return true; + } + + if ((self.flags & Defines.FL_FLY) != 0) { + if (Lib.random() < 0.3) + self.monsterinfo.attack_state = Defines.AS_SLIDING; + else + self.monsterinfo.attack_state = Defines.AS_STRAIGHT; + } + + return false; + } + }; + + static mframe_t makron_frames_attack3[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, makronBFG), + // FIXME: BFG Attack here + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), + // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, MakronHyperblaster), // fire + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, makron_prerailgun), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, MakronSaveloc), + new mframe_t(GameAI.ai_move, 0, MakronRailgun), + // Fire railgun + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null) }; + + static mmove_t makron_move_attack5 = new mmove_t(FRAME_attak501, + FRAME_attak516, makron_frames_attack5, makron_run); + + /* + * ================= 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 = GameBase.level.sight_client; + if (player == null) + return true; + + Math3D.VectorSubtract(player.s.origin, self.s.origin, vec); + self.s.angles[Defines.YAW] = Math3D.vectoyaw(vec); + Math3D.VectorNormalize(vec); + Math3D.VectorMA(Globals.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 = GameUtil.G_Spawn(); + ent.nextthink = GameBase.level.time + 0.8f; + ent.think = MakronSpawn; + ent.target = self.target; + Math3D.VectorCopy(self.s.origin, ent.s.origin); + return true; + } + }; + + // + // monster_makron + // + + static void MakronPrecache() { + sound_pain4 = GameBase.gi.soundindex("makron/pain3.wav"); + sound_pain5 = GameBase.gi.soundindex("makron/pain2.wav"); + sound_pain6 = GameBase.gi.soundindex("makron/pain1.wav"); + sound_death = GameBase.gi.soundindex("makron/death.wav"); + sound_step_left = GameBase.gi.soundindex("makron/step1.wav"); + sound_step_right = GameBase.gi.soundindex("makron/step2.wav"); + sound_attack_bfg = GameBase.gi.soundindex("makron/bfg_fire.wav"); + sound_brainsplorch = GameBase.gi.soundindex("makron/brain1.wav"); + sound_prerailgun = GameBase.gi.soundindex("makron/rail_up.wav"); + sound_popup = GameBase.gi.soundindex("makron/popup.wav"); + sound_taunt1 = GameBase.gi.soundindex("makron/voice4.wav"); + sound_taunt2 = GameBase.gi.soundindex("makron/voice3.wav"); + sound_taunt3 = GameBase.gi.soundindex("makron/voice.wav"); + sound_hit = GameBase.gi.soundindex("makron/bhit.wav"); + + GameBase.gi.modelindex("models/monsters/boss3/rider/tris.md2"); + } + + /* + * 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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + MakronPrecache(); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.gi.linkentity(self); + + // self.monsterinfo.currentmove = &makron_move_stand; + self.monsterinfo.currentmove = makron_move_sight; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Brain.java b/src/jake2/game/M_Brain.java index 4fa31ee..43493b6 100644 --- a/src/jake2/game/M_Brain.java +++ b/src/jake2/game/M_Brain.java @@ -1,944 +1,1152 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Brain.java,v 1.3 2004-09-22 19:22:00 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Brain { -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. + public final static int FRAME_walk101 = 0; -*/ + public final static int FRAME_walk102 = 1; -// Created on 13.11.2003 by RST. -// $Id: M_Brain.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_walk103 = 2; -package jake2.game; + 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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter brain_search = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + // + // STAND + // -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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 1, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 9, null), - new mframe_t(GameAIAdapters.ai_walk, -4, null), - new mframe_t(GameAIAdapters.ai_walk, -1, null), - new mframe_t(GameAIAdapters.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 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.pausetime= level.time + eta + 0.5f; - self.monsterinfo.currentmove= brain_move_duck; - return; - } - }; - - static mframe_t brain_frames_death2[]= - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 9, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 9, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 8, null), - new mframe_t(GameAIAdapters.ai_charge, 3, null), - new mframe_t(GameAIAdapters.ai_charge, 5, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -3, brain_swing_right), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -5, null), - new mframe_t(GameAIAdapters.ai_charge, -7, brain_hit_right), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 6, brain_swing_left), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 2, brain_hit_left), - new mframe_t(GameAIAdapters.ai_charge, -3, null), - new mframe_t(GameAIAdapters.ai_charge, 6, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, -3, null), - new mframe_t(GameAIAdapters.ai_charge, 2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 5, null), - new mframe_t(GameAIAdapters.ai_charge, -4, null), - new mframe_t(GameAIAdapters.ai_charge, -4, null), - new mframe_t(GameAIAdapters.ai_charge, -3, null), - new mframe_t(GameAIAdapters.ai_charge, 0, brain_chest_open), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 13, brain_tentacle_attack), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 2, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -9, brain_chest_closed), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 4, null), - new mframe_t(GameAIAdapters.ai_charge, 3, null), - new mframe_t(GameAIAdapters.ai_charge, 2, null), - new mframe_t(GameAIAdapters.ai_charge, -3, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 9, null), - new mframe_t(GameAIAdapters.ai_run, 2, null), - new mframe_t(GameAIAdapters.ai_run, 3, null), - new mframe_t(GameAIAdapters.ai_run, 3, null), - new mframe_t(GameAIAdapters.ai_run, 1, null), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, -4, null), - new mframe_t(GameAIAdapters.ai_run, -1, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 7, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -2, brain_duck_down), - new mframe_t(GameAIAdapters.ai_move, 17, brain_duck_hold), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, -1, brain_duck_up), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.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; - - GameAIAdapters.walkmonster_start.think(self); - } -} + static mframe_t brain_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null) }; + + static mmove_t brain_move_idle = new mmove_t(FRAME_stand31, FRAME_stand60, + brain_frames_idle, brain_stand); + + static EntThinkAdapter brain_idle = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_AUTO, sound_idle3, 1, + Defines.ATTN_IDLE, 0); + self.monsterinfo.currentmove = brain_move_idle; + return true; + } + }; + + // + // WALK + // + static mframe_t brain_frames_walk1[] = new mframe_t[] { + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 1, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 9, null), + new mframe_t(GameAI.ai_walk, -4, null), + new mframe_t(GameAI.ai_walk, -1, null), + new mframe_t(GameAI.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 & Defines.AI_DUCKED) != 0) + return true; + self.monsterinfo.aiflags |= Defines.AI_DUCKED; + self.maxs[2] -= 32; + self.takedamage = Defines.DAMAGE_YES; + GameBase.gi.linkentity(self); + return true; + } + }; + + static EntThinkAdapter brain_duck_hold = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (GameBase.level.time >= self.monsterinfo.pausetime) + self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; + else + self.monsterinfo.aiflags |= Defines.AI_HOLD_FRAME; + return true; + } + }; + + static EntThinkAdapter brain_duck_up = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.monsterinfo.aiflags &= ~Defines.AI_DUCKED; + self.maxs[2] += 32; + self.takedamage = Defines.DAMAGE_AIM; + GameBase.gi.linkentity(self); + return true; + } + }; + + static EntDodgeAdapter brain_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.pausetime = GameBase.level.time + eta + 0.5f; + self.monsterinfo.currentmove = brain_move_duck; + return; + } + }; + + static mframe_t brain_frames_death2[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 9, null), + new mframe_t(GameAI.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 9, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_melee1, 1, + Defines.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, Defines.MELEE_DISTANCE, self.maxs[0], 8); + if (Fire.fire_hit(self, aim, (15 + (Lib.rand() % 5)), 40)) + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_melee3, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter brain_swing_left = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_melee2, 1, + Defines.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, Defines.MELEE_DISTANCE, self.mins[0], 8); + if (Fire.fire_hit(self, aim, (15 + (Lib.rand() % 5)), 40)) + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_melee3, 1, + Defines.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 = Defines.POWER_ARMOR_NONE; + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_chest_open, 1, + Defines.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, Defines.MELEE_DISTANCE, 0, 8); + if (Fire.fire_hit(self, aim, (10 + (Lib.rand() % 5)), -600) + && GameBase.skill.value > 0) + self.spawnflags |= 65536; + GameBase.gi.sound(self, Defines.CHAN_WEAPON, + sound_tentacles_retract, 1, Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t brain_frames_attack1[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 8, null), + new mframe_t(GameAI.ai_charge, 3, null), + new mframe_t(GameAI.ai_charge, 5, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -3, brain_swing_right), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -5, null), + new mframe_t(GameAI.ai_charge, -7, brain_hit_right), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 6, brain_swing_left), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 2, brain_hit_left), + new mframe_t(GameAI.ai_charge, -3, null), + new mframe_t(GameAI.ai_charge, 6, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, -3, null), + new mframe_t(GameAI.ai_charge, 2, null), + new mframe_t(GameAI.ai_charge, -11, null) }; + + static EntThinkAdapter brain_chest_closed = new EntThinkAdapter() { + public boolean think(edict_t self) { + + self.monsterinfo.power_armor_type = Defines.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(GameAI.ai_charge, 5, null), + new mframe_t(GameAI.ai_charge, -4, null), + new mframe_t(GameAI.ai_charge, -4, null), + new mframe_t(GameAI.ai_charge, -3, null), + new mframe_t(GameAI.ai_charge, 0, brain_chest_open), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 13, brain_tentacle_attack), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 2, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -9, brain_chest_closed), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 4, null), + new mframe_t(GameAI.ai_charge, 3, null), + new mframe_t(GameAI.ai_charge, 2, null), + new mframe_t(GameAI.ai_charge, -3, null), + new mframe_t(GameAI.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(GameAI.ai_run, 9, null), + new mframe_t(GameAI.ai_run, 2, null), + new mframe_t(GameAI.ai_run, 3, null), + new mframe_t(GameAI.ai_run, 3, null), + new mframe_t(GameAI.ai_run, 1, null), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, -4, null), + new mframe_t(GameAI.ai_run, -1, null), + new mframe_t(GameAI.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 = Defines.POWER_ARMOR_SCREEN; + if ((self.monsterinfo.aiflags & Defines.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.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(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 7, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -2, brain_duck_down), + new mframe_t(GameAI.ai_move, 17, brain_duck_hold), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, -1, brain_duck_up), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + r = Lib.random(); + if (r < 0.33) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = brain_move_pain1; + } else if (r < 0.66) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = brain_move_pain2; + } else { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.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 = Defines.POWER_ARMOR_NONE; + + // check for gib + if (self.health <= self.gib_health) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_chest_open = GameBase.gi.soundindex("brain/brnatck1.wav"); + sound_tentacles_extend = GameBase.gi.soundindex("brain/brnatck2.wav"); + sound_tentacles_retract = GameBase.gi.soundindex("brain/brnatck3.wav"); + sound_death = GameBase.gi.soundindex("brain/brndeth1.wav"); + sound_idle1 = GameBase.gi.soundindex("brain/brnidle1.wav"); + sound_idle2 = GameBase.gi.soundindex("brain/brnidle2.wav"); + sound_idle3 = GameBase.gi.soundindex("brain/brnlens1.wav"); + sound_pain1 = GameBase.gi.soundindex("brain/brnpain1.wav"); + sound_pain2 = GameBase.gi.soundindex("brain/brnpain2.wav"); + sound_sight = GameBase.gi.soundindex("brain/brnsght1.wav"); + sound_search = GameBase.gi.soundindex("brain/brnsrch1.wav"); + sound_melee1 = GameBase.gi.soundindex("brain/melee1.wav"); + sound_melee2 = GameBase.gi.soundindex("brain/melee2.wav"); + sound_melee3 = GameBase.gi.soundindex("brain/melee3.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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 = Defines.POWER_ARMOR_SCREEN; + self.monsterinfo.power_armor_power = 100; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = brain_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Chick.java b/src/jake2/game/M_Chick.java index 5e577fb..5789180 100644 --- a/src/jake2/game/M_Chick.java +++ b/src/jake2/game/M_Chick.java @@ -1,987 +1,1302 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Chick.java,v 1.3 2004-09-22 19:22:02 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Chick { -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. + public final static int FRAME_attak101 = 0; -*/ + public final static int FRAME_attak102 = 1; -// Created on 13.11.2003 by RST. -// $Id: M_Chick.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_attak103 = 2; -package jake2.game; + 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) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle1, 1, + Defines.ATTN_IDLE, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle2, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; -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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, ChickMoan), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 1, null), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, -1, null), - new mframe_t(GameAIAdapters.ai_run, -1, null), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 1, null), - new mframe_t(GameAIAdapters.ai_run, 3, null), - new mframe_t(GameAIAdapters.ai_run, 6, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 6, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 5, null), - new mframe_t(GameAIAdapters.ai_run, 7, null), - new mframe_t(GameAIAdapters.ai_run, 4, null), - new mframe_t(GameAIAdapters.ai_run, 11, null), - new mframe_t(GameAIAdapters.ai_run, 5, null), - new mframe_t(GameAIAdapters.ai_run, 9, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 13, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 11, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 9, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 11, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.ai_move, 7, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, -8, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 10, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.ai_move, 15, null), - new mframe_t(GameAIAdapters.ai_move, 14, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -7, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.ai_move, 11, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, chick_duck_down), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 4, chick_duck_hold), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, -5, chick_duck_up), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, Chick_PreAttack1), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 4, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -3, null), - new mframe_t(GameAIAdapters.ai_charge, 3, null), - new mframe_t(GameAIAdapters.ai_charge, 5, null), - new mframe_t(GameAIAdapters.ai_charge, 7, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 19, ChickRocket), - new mframe_t(GameAIAdapters.ai_charge, -6, null), - new mframe_t(GameAIAdapters.ai_charge, -5, null), - new mframe_t(GameAIAdapters.ai_charge, -2, null), - new mframe_t(GameAIAdapters.ai_charge, -7, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 10, ChickReload), - new mframe_t(GameAIAdapters.ai_charge, 4, null), - new mframe_t(GameAIAdapters.ai_charge, 5, null), - new mframe_t(GameAIAdapters.ai_charge, 6, null), - new mframe_t(GameAIAdapters.ai_charge, 6, null), - new mframe_t(GameAIAdapters.ai_charge, 4, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, -3, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -6, null), - new mframe_t(GameAIAdapters.ai_charge, -4, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 7, ChickSlash), - new mframe_t(GameAIAdapters.ai_charge, -7, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, -6, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, -6, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 8, null), - new mframe_t(GameAIAdapters.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 interact(edict_t self, edict_t other) { - 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; - - GameAIAdapters.walkmonster_start.think(self); - } - -} + static mframe_t chick_frames_fidget[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, ChickMoan), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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 & Defines.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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 & Defines.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(GameAI.ai_run, 1, null), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, -1, null), + new mframe_t(GameAI.ai_run, -1, null), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 1, null), + new mframe_t(GameAI.ai_run, 3, null), + new mframe_t(GameAI.ai_run, 6, null), + new mframe_t(GameAI.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(GameAI.ai_run, 6, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 5, null), + new mframe_t(GameAI.ai_run, 7, null), + new mframe_t(GameAI.ai_run, 4, null), + new mframe_t(GameAI.ai_run, 11, null), + new mframe_t(GameAI.ai_run, 5, null), + new mframe_t(GameAI.ai_run, 9, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 13, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 11, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 9, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 11, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.ai_move, 7, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, -8, null), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + + r = Lib.random(); + if (r < 0.33) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + else if (r < 0.66) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain3, 1, + Defines.ATTN_NORM, 0); + + if (GameBase.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t chick_frames_death2[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 10, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.ai_move, 15, null), + new mframe_t(GameAI.ai_move, 14, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -7, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.ai_move, 11, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.DAMAGE_YES; + + n = Lib.rand() % 2; + if (n == 0) { + self.monsterinfo.currentmove = chick_move_death1; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death1, 1, + Defines.ATTN_NORM, 0); + } else { + self.monsterinfo.currentmove = chick_move_death2; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death2, 1, + Defines.ATTN_NORM, 0); + } + } + + }; + + static EntThinkAdapter chick_duck_down = new EntThinkAdapter() { + public boolean think(edict_t self) { + if ((self.monsterinfo.aiflags & Defines.AI_DUCKED) != 0) + return true; + self.monsterinfo.aiflags |= Defines.AI_DUCKED; + self.maxs[2] -= 32; + self.takedamage = Defines.DAMAGE_YES; + self.monsterinfo.pausetime = GameBase.level.time + 1; + GameBase.gi.linkentity(self); + return true; + } + }; + + static EntThinkAdapter chick_duck_hold = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (GameBase.level.time >= self.monsterinfo.pausetime) + self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; + else + self.monsterinfo.aiflags |= Defines.AI_HOLD_FRAME; + return true; + } + }; + + static EntThinkAdapter chick_duck_up = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.monsterinfo.aiflags &= ~Defines.AI_DUCKED; + self.maxs[2] += 32; + self.takedamage = Defines.DAMAGE_AIM; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t chick_frames_duck[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, chick_duck_down), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 4, chick_duck_hold), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, -5, chick_duck_up), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.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, Defines.MELEE_DISTANCE, self.mins[0], 10); + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_melee_swing, 1, + Defines.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, + M_Flash.monster_flash_offset[Defines.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, + Defines.MZ2_CHICK_ROCKET_1); + return true; + } + }; + + static EntThinkAdapter Chick_PreAttack1 = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, + sound_missile_prelaunch, 1, Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter ChickReload = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_missile_reload, + 1, Defines.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 (GameUtil.range(self, self.enemy) > Defines.RANGE_MELEE) + if (GameUtil.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(GameAI.ai_charge, 0, Chick_PreAttack1), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 4, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -3, null), + new mframe_t(GameAI.ai_charge, 3, null), + new mframe_t(GameAI.ai_charge, 5, null), + new mframe_t(GameAI.ai_charge, 7, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 19, ChickRocket), + new mframe_t(GameAI.ai_charge, -6, null), + new mframe_t(GameAI.ai_charge, -5, null), + new mframe_t(GameAI.ai_charge, -2, null), + new mframe_t(GameAI.ai_charge, -7, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 10, ChickReload), + new mframe_t(GameAI.ai_charge, 4, null), + new mframe_t(GameAI.ai_charge, 5, null), + new mframe_t(GameAI.ai_charge, 6, null), + new mframe_t(GameAI.ai_charge, 6, null), + new mframe_t(GameAI.ai_charge, 4, null), + new mframe_t(GameAI.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(GameAI.ai_charge, -3, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -6, null), + new mframe_t(GameAI.ai_charge, -4, null), + new mframe_t(GameAI.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 (GameUtil.range(self, self.enemy) == Defines.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(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 7, ChickSlash), + new mframe_t(GameAI.ai_charge, -7, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.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(GameAI.ai_charge, -6, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, -6, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 8, null), + new mframe_t(GameAI.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 interact(edict_t self, edict_t other) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_missile_prelaunch = GameBase.gi.soundindex("chick/chkatck1.wav"); + sound_missile_launch = GameBase.gi.soundindex("chick/chkatck2.wav"); + sound_melee_swing = GameBase.gi.soundindex("chick/chkatck3.wav"); + sound_melee_hit = GameBase.gi.soundindex("chick/chkatck4.wav"); + sound_missile_reload = GameBase.gi.soundindex("chick/chkatck5.wav"); + sound_death1 = GameBase.gi.soundindex("chick/chkdeth1.wav"); + sound_death2 = GameBase.gi.soundindex("chick/chkdeth2.wav"); + sound_fall_down = GameBase.gi.soundindex("chick/chkfall1.wav"); + sound_idle1 = GameBase.gi.soundindex("chick/chkidle1.wav"); + sound_idle2 = GameBase.gi.soundindex("chick/chkidle2.wav"); + sound_pain1 = GameBase.gi.soundindex("chick/chkpain1.wav"); + sound_pain2 = GameBase.gi.soundindex("chick/chkpain2.wav"); + sound_pain3 = GameBase.gi.soundindex("chick/chkpain3.wav"); + sound_sight = GameBase.gi.soundindex("chick/chksght1.wav"); + sound_search = GameBase.gi.soundindex("chick/chksrch1.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = chick_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Flash.java b/src/jake2/game/M_Flash.java index 5ea18d1..1f70990 100644 --- a/src/jake2/game/M_Flash.java +++ b/src/jake2/game/M_Flash.java @@ -1,707 +1,494 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 13.11.2003 by RST. -// $Id: M_Flash.java,v 1.1 2004-07-07 19:59:12 hzi Exp $ - +// $Id: M_Flash.java,v 1.2 2004-09-22 19:22:01 salomo 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 } - }; - -} +public class M_Flash { + + // 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 } }; + +} \ No newline at end of file diff --git a/src/jake2/game/M_Flipper.java b/src/jake2/game/M_Flipper.java index e3b7648..ad0fdce 100644 --- a/src/jake2/game/M_Flipper.java +++ b/src/jake2/game/M_Flipper.java @@ -1,600 +1,763 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Flipper.java,v 1.3 2004-09-22 19:22:06 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Flipper { -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. + // This file generated by ModelGen - Do NOT Modify -*/ + public final static int FRAME_flpbit01 = 0; -// Created on 13.11.2003 by RST. -// $Id: M_Flipper.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_flpbit02 = 1; -package jake2.game; + 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( + GameAI.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(GameAI.ai_run, FLIPPER_RUN_SPEED, null), // 6 + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + // 10 + + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + // 20 -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(GameAIAdapters.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(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), // 6 - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - // 10 - - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - // 20 - - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.ai_run, FLIPPER_RUN_SPEED, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, flipper_preattack), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, flipper_bite), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, flipper_bite), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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 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; - - GameAIAdapters.swimmonster_start.think(self); - } - -} + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.ai_run, FLIPPER_RUN_SPEED, null), + new mframe_t(GameAI.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(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.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(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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, Defines.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) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_chomp, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t flipper_frames_attack[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, flipper_preattack), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, flipper_bite), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, flipper_bite), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + n = (Lib.rand() + 1) % 2; + if (n == 0) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = flipper_move_pain1; + } else { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t flipper_frames_death[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntDieAdapter flipper_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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/sm_meat/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_pain1 = GameBase.gi.soundindex("flipper/flppain1.wav"); + sound_pain2 = GameBase.gi.soundindex("flipper/flppain2.wav"); + sound_death = GameBase.gi.soundindex("flipper/flpdeth1.wav"); + sound_chomp = GameBase.gi.soundindex("flipper/flpatck1.wav"); + sound_attack = GameBase.gi.soundindex("flipper/flpatck2.wav"); + sound_idle = GameBase.gi.soundindex("flipper/flpidle1.wav"); + sound_search = GameBase.gi.soundindex("flipper/flpsrch1.wav"); + sound_sight = GameBase.gi.soundindex("flipper/flpsght1.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = flipper_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.swimmonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Float.java b/src/jake2/game/M_Float.java index dcf00ae..a7c267f 100644 --- a/src/jake2/game/M_Float.java +++ b/src/jake2/game/M_Float.java @@ -1,1007 +1,1212 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Float.java,v 1.3 2004-09-22 19:22:01 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.Globals; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Float { -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. + // This file generated by ModelGen - Do NOT Modify -*/ + public final static int FRAME_actvat01 = 0; -// Created on 13.11.2003 by RST. -// $Id: M_Float.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_actvat02 = 1; -package jake2.game; + 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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter floater_idle = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; -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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), // Blaster attack) - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, floater_fire_blaster), - // BOOM (0, -25.8, 32.5) -- LOOP Starts - new mframe_t(GameAIAdapters.ai_charge, 0, floater_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, floater_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, floater_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, floater_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, floater_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, floater_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), // Claws - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, floater_wham), - // WHAM (0, -45, 29.6) -- LOOP Starts - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - // -- LOOP Ends - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, floater_zap), - // -- LOOP Starts - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - // -- LOOP Ends - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.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; - - GameAIAdapters.flymonster_start.think(self); - } -} + 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 = Defines.EF_HYPERBLASTER; + else + effect = 0; + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.monster_flash_offset[Defines.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, + Defines.MZ2_FLOAT_BLASTER_1, effect); + + return true; + } + }; + + static mframe_t floater_frames_stand1[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 & Defines.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(GameAI.ai_charge, 0, null), // Blaster attack) + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, floater_fire_blaster), + // BOOM (0, -25.8, 32.5) -- LOOP Starts + new mframe_t(GameAI.ai_charge, 0, floater_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, floater_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, floater_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, floater_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, floater_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, floater_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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 = { Defines.MELEE_DISTANCE, 0, 0 }; + + static EntThinkAdapter floater_wham = new EntThinkAdapter() { + public boolean think(edict_t self) { + + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_attack3, 1, + Defines.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(GameAI.ai_charge, 0, null), // Claws + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, floater_wham), + // WHAM (0, -45, 29.6) -- LOOP Starts + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + // -- LOOP Ends + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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); + + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_attack2, 1, + Defines.ATTN_NORM, 0); + + //FIXME use the flash, Luke + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_SPLASH); + GameBase.gi.WriteByte(32); + GameBase.gi.WritePosition(origin); + GameBase.gi.WriteDir(dir); + GameBase.gi.WriteByte(1); //sparks + GameBase.gi.multicast(origin, Defines.MULTICAST_PVS); + + GameUtil.T_Damage(self.enemy, self, self, dir, self.enemy.s.origin, + Globals.vec3_origin, 5 + Lib.rand() % 6, -10, + Defines.DAMAGE_ENERGY, Defines.MOD_UNKNOWN); + return true; + } + }; + + static mframe_t floater_frames_attack3[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, floater_zap), + // -- LOOP Starts + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + // -- LOOP Ends + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.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(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + n = (Lib.rand() + 1) % 3; + if (n == 0) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = floater_move_pain1; + } else { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death1, 1, + Defines.ATTN_NORM, 0); + GameAI.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_attack2 = GameBase.gi.soundindex("floater/fltatck2.wav"); + sound_attack3 = GameBase.gi.soundindex("floater/fltatck3.wav"); + sound_death1 = GameBase.gi.soundindex("floater/fltdeth1.wav"); + sound_idle = GameBase.gi.soundindex("floater/fltidle1.wav"); + sound_pain1 = GameBase.gi.soundindex("floater/fltpain1.wav"); + sound_pain2 = GameBase.gi.soundindex("floater/fltpain2.wav"); + sound_sight = GameBase.gi.soundindex("floater/fltsght1.wav"); + + GameBase.gi.soundindex("floater/fltatck1.wav"); + + self.s.sound = GameBase.gi.soundindex("floater/fltsrch1.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.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; + + GameAI.flymonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Flyer.java b/src/jake2/game/M_Flyer.java index 09b629a..3a6b3e6 100644 --- a/src/jake2/game/M_Flyer.java +++ b/src/jake2/game/M_Flyer.java @@ -1,808 +1,984 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Flyer.java,v 1.4 2004-09-22 19:22:01 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Flyer { + // This file generated by ModelGen - Do NOT Modify -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. + public final static int ACTION_nothing = 0; -*/ + public final static int ACTION_attack1 = 1; -// Created on 13.11.2003 by RST. -// $Id: M_Flyer.java,v 1.3 2004-07-23 10:07:14 hzi Exp $ + public final static int ACTION_attack2 = 2; -package jake2.game; + public final static int ACTION_run = 3; -import jake2.util.Lib; -import jake2.util.Math3D; + 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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; -public class M_Flyer extends M_Player { - // 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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // Hold this frame - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -10, flyer_fireleft), - // left gun - new mframe_t(GameAIAdapters.ai_charge, -10, flyer_fireright), // right gun - new mframe_t(GameAIAdapters.ai_charge, -10, flyer_fireleft), // left gun - new mframe_t(GameAIAdapters.ai_charge, -10, flyer_fireright), // right gun - new mframe_t(GameAIAdapters.ai_charge, -10, flyer_fireleft), // left gun - new mframe_t(GameAIAdapters.ai_charge, -10, flyer_fireright), // right gun - new mframe_t(GameAIAdapters.ai_charge, -10, flyer_fireleft), // left gun - new mframe_t(GameAIAdapters.ai_charge, -10, flyer_fireright), // right gun - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, flyer_pop_blades), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), // Loop Start - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, flyer_slash_left), // Left Wing Strike - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, flyer_slash_right), // Right Wing Strike - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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 (level.mapname.equalsIgnoreCase("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; - - GameAIAdapters.flymonster_start.think(self); - } - -} + static EntThinkAdapter flyer_idle = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; + + static EntThinkAdapter flyer_pop_blades = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sproing, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t flyer_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.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(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.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 & Defines.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // Hold this frame + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null) }; + + static mmove_t flyer_move_bankleft = new mmove_t(FRAME_bankl01, + FRAME_bankl07, flyer_frames_bankleft, null); + + static EntThinkAdapter flyer_fireleft = new EntThinkAdapter() { + public boolean think(edict_t self) { + flyer_fire(self, Defines.MZ2_FLYER_BLASTER_1); + return true; + } + }; + + static EntThinkAdapter flyer_fireright = new EntThinkAdapter() { + public boolean think(edict_t self) { + flyer_fire(self, Defines.MZ2_FLYER_BLASTER_2); + return true; + } + }; + + static mframe_t flyer_frames_attack2[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -10, flyer_fireleft), + // left gun + new mframe_t(GameAI.ai_charge, -10, flyer_fireright), // right gun + new mframe_t(GameAI.ai_charge, -10, flyer_fireleft), // left gun + new mframe_t(GameAI.ai_charge, -10, flyer_fireright), // right gun + new mframe_t(GameAI.ai_charge, -10, flyer_fireleft), // left gun + new mframe_t(GameAI.ai_charge, -10, flyer_fireright), // right gun + new mframe_t(GameAI.ai_charge, -10, flyer_fireleft), // left gun + new mframe_t(GameAI.ai_charge, -10, flyer_fireright), // right gun + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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, Defines.MELEE_DISTANCE, self.mins[0], 0); + Fire.fire_hit(self, aim, 5, 0); + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_slash, 1, + Defines.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, Defines.MELEE_DISTANCE, self.maxs[0], 0); + Fire.fire_hit(self, aim, 5, 0); + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_slash, 1, + Defines.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(GameAI.ai_charge, 0, flyer_pop_blades), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), // Loop Start + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, flyer_slash_left), + // Left Wing Strike + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, flyer_slash_right), + // Right Wing Strike + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null) // Loop Ends + + }; + + static EntThinkAdapter flyer_check_melee = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (GameUtil.range(self, self.enemy) == Defines.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + n = Lib.rand() % 3; + if (n == 0) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = flyer_move_pain1; + } else if (n == 1) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = flyer_move_pain2; + } else { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_die, 1, + Defines.ATTN_NORM, 0); + GameAI.BecomeExplosion1(self); + } + }; + + 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 = Defines.EF_HYPERBLASTER; + else + effect = 0; + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.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); + } + + /* + * 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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + // fix a map bug in jail5.bsp + if (GameBase.level.mapname.equalsIgnoreCase("jail5") + && (self.s.origin[2] == -104)) { + self.targetname = self.target; + self.target = null; + } + + sound_sight = GameBase.gi.soundindex("flyer/flysght1.wav"); + sound_idle = GameBase.gi.soundindex("flyer/flysrch1.wav"); + sound_pain1 = GameBase.gi.soundindex("flyer/flypain1.wav"); + sound_pain2 = GameBase.gi.soundindex("flyer/flypain2.wav"); + sound_slash = GameBase.gi.soundindex("flyer/flyatck2.wav"); + sound_sproing = GameBase.gi.soundindex("flyer/flyatck1.wav"); + sound_die = GameBase.gi.soundindex("flyer/flydeth1.wav"); + + GameBase.gi.soundindex("flyer/flyatck3.wav"); + + self.s.modelindex = GameBase.gi + .modelindex("models/monsters/flyer/tris.md2"); + Math3D.VectorSet(self.mins, -16, -16, -24); + Math3D.VectorSet(self.maxs, 16, 16, 32); + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + + self.s.sound = GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = flyer_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.flymonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Gladiator.java b/src/jake2/game/M_Gladiator.java index aec33f7..c579e40 100644 --- a/src/jake2/game/M_Gladiator.java +++ b/src/jake2/game/M_Gladiator.java @@ -1,570 +1,638 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Gladiator.java,v 1.3 2004-09-22 19:22:06 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Gladiator { -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. + // This file generated by ModelGen - Do NOT Modify -*/ + public final static int FRAME_stand1 = 0; -// Created on 13.11.2003 by RST. -// $Id: M_Gladiator.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_stand2 = 1; -package jake2.game; + 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) { + + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; + + static EntInteractAdapter gladiator_sight = new EntInteractAdapter() { + public boolean interact(edict_t self, edict_t other) { + + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter gladiator_search = new EntThinkAdapter() { + public boolean think(edict_t self) { + + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter gladiator_cleaver_swing = new EntThinkAdapter() { + public boolean think(edict_t self) { + + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_cleaver_swing, + 1, Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t gladiator_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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; + } + }; -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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 15, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 12, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 1, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 23, null), - new mframe_t(GameAIAdapters.ai_run, 14, null), - new mframe_t(GameAIAdapters.ai_run, 14, null), - new mframe_t(GameAIAdapters.ai_run, 21, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, gladiator_cleaver_swing), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, GaldiatorMelee), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, gladiator_cleaver_swing), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, GaldiatorMelee), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, GladiatorGun), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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; - - GameAIAdapters.walkmonster_start.think(self); - } - -} + static mframe_t gladiator_frames_walk[] = new mframe_t[] { + new mframe_t(GameAI.ai_walk, 15, null), + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 12, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 1, null), + new mframe_t(GameAI.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(GameAI.ai_run, 23, null), + new mframe_t(GameAI.ai_run, 14, null), + new mframe_t(GameAI.ai_run, 14, null), + new mframe_t(GameAI.ai_run, 21, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.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 & Defines.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, Defines.MELEE_DISTANCE, self.mins[0], -4); + if (Fire.fire_hit(self, aim, (20 + (Lib.rand() % 5)), 300)) + GameBase.gi.sound(self, Defines.CHAN_AUTO, sound_cleaver_hit, + 1, Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_AUTO, sound_cleaver_miss, + 1, Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t gladiator_frames_attack_melee[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, gladiator_cleaver_swing), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, GaldiatorMelee), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, gladiator_cleaver_swing), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, GaldiatorMelee), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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, + M_Flash.monster_flash_offset[Defines.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, + Defines.MZ2_GLADIATOR_RAILGUN_1); + + return true; + } + }; + + static mframe_t gladiator_frames_attack_gun[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, GladiatorGun), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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 <= (Defines.MELEE_DISTANCE + 32)) + return true; + + // charge up the railgun + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_gun, 1, + Defines.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 (GameBase.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 = GameBase.level.time + 3; + + if (Lib.random() < 0.5) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.ATTN_NORM, 0); + + if (GameBase.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t gladiator_frames_death[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_die, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_pain1 = GameBase.gi.soundindex("gladiator/pain.wav"); + sound_pain2 = GameBase.gi.soundindex("gladiator/gldpain2.wav"); + sound_die = GameBase.gi.soundindex("gladiator/glddeth2.wav"); + sound_gun = GameBase.gi.soundindex("gladiator/railgun.wav"); + sound_cleaver_swing = GameBase.gi.soundindex("gladiator/melee1.wav"); + sound_cleaver_hit = GameBase.gi.soundindex("gladiator/melee2.wav"); + sound_cleaver_miss = GameBase.gi.soundindex("gladiator/melee3.wav"); + sound_idle = GameBase.gi.soundindex("gladiator/gldidle1.wav"); + sound_search = GameBase.gi.soundindex("gladiator/gldsrch1.wav"); + sound_sight = GameBase.gi.soundindex("gladiator/sight.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.gi.linkentity(self); + self.monsterinfo.currentmove = gladiator_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Gunner.java b/src/jake2/game/M_Gunner.java index 1625353..15a3421 100644 --- a/src/jake2/game/M_Gunner.java +++ b/src/jake2/game/M_Gunner.java @@ -1,837 +1,1083 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Gunner.java,v 1.3 2004-09-22 19:22:01 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Gunner { + // This file generated by ModelGen - Do NOT Modify -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. + public final static int FRAME_stand01 = 0; -*/ + public final static int FRAME_stand02 = 1; -// Created on 13.11.2003 by RST. -// $Id: M_Gunner.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_stand03 = 2; -package jake2.game; + 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 gunner_idlesound = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; + + static EntInteractAdapter gunner_sight = new EntInteractAdapter() { + public boolean interact(edict_t self, edict_t other) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; -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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, gunner_idlesound), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, gunner_fidget), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, gunner_fidget), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 26, null), - new mframe_t(GameAIAdapters.ai_run, 9, null), - new mframe_t(GameAIAdapters.ai_run, 9, null), - new mframe_t(GameAIAdapters.ai_run, 9, null), - new mframe_t(GameAIAdapters.ai_run, 15, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 13, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 32, null), - new mframe_t(GameAIAdapters.ai_run, 15, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 18, null), - new mframe_t(GameAIAdapters.ai_run, 8, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 11, null), - new mframe_t(GameAIAdapters.ai_move, 6, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -7, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -7, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 8, null), - new mframe_t(GameAIAdapters.ai_move, 6, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 1, gunner_duck_down), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, gunner_duck_hold), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 0, gunner_duck_up), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, gunner_opengun), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, GunnerFire), - new mframe_t(GameAIAdapters.ai_charge, 0, GunnerFire), - new mframe_t(GameAIAdapters.ai_charge, 0, GunnerFire), - new mframe_t(GameAIAdapters.ai_charge, 0, GunnerFire), - new mframe_t(GameAIAdapters.ai_charge, 0, GunnerFire), - new mframe_t(GameAIAdapters.ai_charge, 0, GunnerFire), - new mframe_t(GameAIAdapters.ai_charge, 0, GunnerFire), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, GunnerGrenade), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, GunnerGrenade), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, GunnerGrenade), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, GunnerGrenade), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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; - - GameAIAdapters.walkmonster_start.think(self); - } - -} + static EntThinkAdapter gunner_search = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t gunner_frames_fidget[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, gunner_idlesound), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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 & Defines.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, gunner_fidget), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, gunner_fidget), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.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(GameAI.ai_run, 26, null), + new mframe_t(GameAI.ai_run, 9, null), + new mframe_t(GameAI.ai_run, 9, null), + new mframe_t(GameAI.ai_run, 9, null), + new mframe_t(GameAI.ai_run, 15, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 13, null), + new mframe_t(GameAI.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 & Defines.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(GameAI.ai_run, 32, null), + new mframe_t(GameAI.ai_run, 15, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 18, null), + new mframe_t(GameAI.ai_run, 8, null), + new mframe_t(GameAI.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(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 11, null), + new mframe_t(GameAI.ai_move, 6, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -7, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.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(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + + if ((Lib.rand() & 1) != 0) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.ATTN_NORM, 0); + + if (GameBase.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t gunner_frames_death[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -7, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 8, null), + new mframe_t(GameAI.ai_move, 6, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 & Defines.AI_DUCKED) != 0) + return true; + self.monsterinfo.aiflags |= Defines.AI_DUCKED; + if (GameBase.skill.value >= 2) { + if (Lib.random() > 0.5) + GunnerGrenade.think(self); + } + + self.maxs[2] -= 32; + self.takedamage = Defines.DAMAGE_YES; + self.monsterinfo.pausetime = GameBase.level.time + 1; + GameBase.gi.linkentity(self); + return true; + } + }; + + static EntThinkAdapter gunner_duck_hold = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (GameBase.level.time >= self.monsterinfo.pausetime) + self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; + else + self.monsterinfo.aiflags |= Defines.AI_HOLD_FRAME; + return true; + } + }; + + static EntThinkAdapter gunner_duck_up = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.monsterinfo.aiflags &= ~Defines.AI_DUCKED; + self.maxs[2] += 32; + self.takedamage = Defines.DAMAGE_AIM; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t gunner_frames_duck[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 1, gunner_duck_down), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, gunner_duck_hold), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 0, gunner_duck_up), + new mframe_t(GameAI.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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_open, 1, + Defines.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 = Defines.MZ2_GUNNER_MACHINEGUN_1 + + (self.s.frame - FRAME_attak216); + + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.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, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.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 = Defines.MZ2_GUNNER_GRENADE_1; + else if (self.s.frame == FRAME_attak108) + flash_number = Defines.MZ2_GUNNER_GRENADE_2; + else if (self.s.frame == FRAME_attak111) + flash_number = Defines.MZ2_GUNNER_GRENADE_3; + else + // (self.s.frame == FRAME_attak114) + flash_number = Defines.MZ2_GUNNER_GRENADE_4; + + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.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 (GameUtil.range(self, self.enemy) == Defines.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(GameAI.ai_charge, 0, gunner_opengun), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, GunnerFire), + new mframe_t(GameAI.ai_charge, 0, GunnerFire), + new mframe_t(GameAI.ai_charge, 0, GunnerFire), + new mframe_t(GameAI.ai_charge, 0, GunnerFire), + new mframe_t(GameAI.ai_charge, 0, GunnerFire), + new mframe_t(GameAI.ai_charge, 0, GunnerFire), + new mframe_t(GameAI.ai_charge, 0, GunnerFire), + new mframe_t(GameAI.ai_charge, 0, GunnerFire) }; + + static EntThinkAdapter gunner_refire_chain = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (self.enemy.health > 0) + if (GameUtil.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, GunnerGrenade), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, GunnerGrenade), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, GunnerGrenade), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, GunnerGrenade), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_death = GameBase.gi.soundindex("gunner/death1.wav"); + sound_pain = GameBase.gi.soundindex("gunner/gunpain2.wav"); + sound_pain2 = GameBase.gi.soundindex("gunner/gunpain1.wav"); + sound_idle = GameBase.gi.soundindex("gunner/gunidle1.wav"); + sound_open = GameBase.gi.soundindex("gunner/gunatck1.wav"); + sound_search = GameBase.gi.soundindex("gunner/gunsrch1.wav"); + sound_sight = GameBase.gi.soundindex("gunner/sight1.wav"); + + GameBase.gi.soundindex("gunner/gunatck2.wav"); + GameBase.gi.soundindex("gunner/gunatck3.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = gunner_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Hover.java b/src/jake2/game/M_Hover.java index d11fa00..d8ebe86 100644 --- a/src/jake2/game/M_Hover.java +++ b/src/jake2/game/M_Hover.java @@ -1,805 +1,1060 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Hover.java,v 1.3 2004-09-22 19:22:01 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Hover { -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. + // This file generated by ModelGen - Do NOT Modify -*/ + public final static int FRAME_stand01 = 0; -// Created on 13.11.2003 by RST. -// $Id: M_Hover.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_stand02 = 1; -package jake2.game; + 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 (GameUtil.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 = Defines.EF_HYPERBLASTER; + else + effect = 0; + + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.monster_flash_offset[Defines.MZ2_HOVER_BLASTER_1], + forward, right, start); + + Math3D.VectorCopy(self.enemy.s.origin, end); + end[2] += self.enemy.viewheight; + Math3D.VectorSubtract(end, start, dir); -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 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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, -9, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, -8, null), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 7, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -10, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 1, null), new mframe_t(GameAIAdapters.ai_charge, 1, null), new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, -10, hover_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, -10, hover_fire_blaster), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 1, null), new mframe_t(GameAIAdapters.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; - - GameAIAdapters.flymonster_start.think(self); - } - -} + Monster.monster_fire_blaster(self, start, dir, 1, 1000, + Defines.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 & Defines.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 pain(edict_t self, edict_t other, float kick, int damage) { + if (self.health < (self.max_health / 2)) + self.s.skinnum = 1; + + if (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + if (damage <= 25) { + if (Lib.random() < 0.5) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = hover_move_pain3; + } else { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = hover_move_pain2; + } + } else { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.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 + && GameBase.level.time < self.timestamp) { + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + return true; + } + GameAI.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 = Defines.MOVETYPE_TOSS; + self.think = hover_deadthink; + self.nextthink = GameBase.level.time + Defines.FRAMETIME; + self.timestamp = GameBase.level.time + 15; + GameBase.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/sm_meat/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + if (Lib.random() < 0.5) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death1, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death2, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.DAMAGE_YES; + self.monsterinfo.currentmove = hover_move_death1; + } + }; + + static EntInteractAdapter hover_sight = new EntInteractAdapter() { + public boolean interact(edict_t self, edict_t other) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter hover_search = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (Lib.random() < 0.5) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search1, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search2, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t hover_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, -9, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, -8, null), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 7, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.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( + GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.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(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -10, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.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(GameAI.ai_charge, -10, hover_fire_blaster), + new mframe_t(GameAI.ai_charge, -10, hover_fire_blaster), + new mframe_t(GameAI.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(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_pain1 = GameBase.gi.soundindex("hover/hovpain1.wav"); + sound_pain2 = GameBase.gi.soundindex("hover/hovpain2.wav"); + sound_death1 = GameBase.gi.soundindex("hover/hovdeth1.wav"); + sound_death2 = GameBase.gi.soundindex("hover/hovdeth2.wav"); + sound_sight = GameBase.gi.soundindex("hover/hovsght1.wav"); + sound_search1 = GameBase.gi.soundindex("hover/hovsrch1.wav"); + sound_search2 = GameBase.gi.soundindex("hover/hovsrch2.wav"); + + GameBase.gi.soundindex("hover/hovatck1.wav"); + + self.s.sound = GameBase.gi.soundindex("hover/hovidle1.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = hover_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.flymonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Infantry.java b/src/jake2/game/M_Infantry.java index 813b543..baef793 100644 --- a/src/jake2/game/M_Infantry.java +++ b/src/jake2/game/M_Infantry.java @@ -1,814 +1,1067 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Infantry.java,v 1.3 2004-09-22 19:22:06 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.client.M; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Infantry { -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. + // This file generated by ModelGen - Do NOT Modify -*/ + public final static int FRAME_gun02 = 0; -// Created on 13.11.2003 by RST. -// $Id: M_Infantry.java,v 1.2 2004-07-08 15:58:43 hzi Exp $ + public final static int FRAME_stand01 = 1; -package jake2.game; + public final static int FRAME_stand02 = 2; -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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 1, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 1, null), - new mframe_t(GameAIAdapters.ai_stand, 3, null), - new mframe_t(GameAIAdapters.ai_stand, 6, null), - new mframe_t(GameAIAdapters.ai_stand, 3, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 1, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 1, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, -1, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 1, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, -2, null), - new mframe_t(GameAIAdapters.ai_stand, 1, null), - new mframe_t(GameAIAdapters.ai_stand, 1, null), - new mframe_t(GameAIAdapters.ai_stand, 1, null), - new mframe_t(GameAIAdapters.ai_stand, -1, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, -1, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, -1, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 1, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, -1, null), - new mframe_t(GameAIAdapters.ai_stand, -1, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, -3, null), - new mframe_t(GameAIAdapters.ai_stand, -2, null), - new mframe_t(GameAIAdapters.ai_stand, -3, null), - new mframe_t(GameAIAdapters.ai_stand, -3, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 20, null), - new mframe_t(GameAIAdapters.ai_run, 5, null), - new mframe_t(GameAIAdapters.ai_run, 7, null), - new mframe_t(GameAIAdapters.ai_run, 30, null), - new mframe_t(GameAIAdapters.ai_run, 35, null), - new mframe_t(GameAIAdapters.ai_run, 2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 6, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 9, null), - new mframe_t(GameAIAdapters.ai_move, 9, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -2, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, -2, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, -3, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, -1, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, -2, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, 0, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, 2, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, 2, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, 3, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, -10, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, -7, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, -8, InfantryMachineGun), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, -11, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, -11, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -2, infantry_duck_down), - new mframe_t(GameAIAdapters.ai_move, -5, infantry_duck_hold), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 4, infantry_duck_up), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 4, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, 0, infantry_cock_gun), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 2, null), - new mframe_t(GameAIAdapters.ai_charge, -2, null), - new mframe_t(GameAIAdapters.ai_charge, -3, null), - new mframe_t(GameAIAdapters.ai_charge, 1, infantry_fire), - new mframe_t(GameAIAdapters.ai_charge, 5, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, -2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 3, null), - new mframe_t(GameAIAdapters.ai_charge, 6, null), - new mframe_t(GameAIAdapters.ai_charge, 0, infantry_swing), - new mframe_t(GameAIAdapters.ai_charge, 8, null), - new mframe_t(GameAIAdapters.ai_charge, 5, null), - new mframe_t(GameAIAdapters.ai_charge, 8, infantry_smack), - new mframe_t(GameAIAdapters.ai_charge, 6, null), - new mframe_t(GameAIAdapters.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; - - GameAIAdapters.walkmonster_start.think(self); - } - -} + 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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_stand, 1, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 1, null), + new mframe_t(GameAI.ai_stand, 3, null), + new mframe_t(GameAI.ai_stand, 6, null), + new mframe_t(GameAI.ai_stand, 3, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 1, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 1, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, -1, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 1, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, -2, null), + new mframe_t(GameAI.ai_stand, 1, null), + new mframe_t(GameAI.ai_stand, 1, null), + new mframe_t(GameAI.ai_stand, 1, null), + new mframe_t(GameAI.ai_stand, -1, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, -1, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, -1, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 1, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, -1, null), + new mframe_t(GameAI.ai_stand, -1, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, -3, null), + new mframe_t(GameAI.ai_stand, -2, null), + new mframe_t(GameAI.ai_stand, -3, null), + new mframe_t(GameAI.ai_stand, -3, null), + new mframe_t(GameAI.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; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; + + static mframe_t infantry_frames_walk[] = new mframe_t[] { + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.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(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 20, null), + new mframe_t(GameAI.ai_run, 5, null), + new mframe_t(GameAI.ai_run, 7, null), + new mframe_t(GameAI.ai_run, 30, null), + new mframe_t(GameAI.ai_run, 35, null), + new mframe_t(GameAI.ai_run, 2, null), + new mframe_t(GameAI.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 & Defines.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(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 6, null), + new mframe_t(GameAI.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(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + n = Lib.rand() % 2; + if (n == 0) { + self.monsterinfo.currentmove = infantry_move_pain1; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + } else { + self.monsterinfo.currentmove = infantry_move_pain2; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.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 = Defines.MZ2_INFANTRY_MACHINEGUN_1; + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.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 = Defines.MZ2_INFANTRY_MACHINEGUN_2 + + (self.s.frame - FRAME_death211); + + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.monster_flash_offset[flash_number], forward, + right, start); + + Math3D.VectorSubtract(self.s.angles, aimangles[flash_number + - Defines.MZ2_INFANTRY_MACHINEGUN_2], vec); + Math3D.AngleVectors(vec, forward, null, null); + } + + Monster.monster_fire_bullet(self, start, forward, 3, 4, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.DEFAULT_BULLET_VSPREAD, flash_number); + return true; + } + }; + + static EntInteractAdapter infantry_sight = new EntInteractAdapter() { + public boolean interact(edict_t self, edict_t other) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_sight, 1, + Defines.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + GameBase.gi.linkentity(self); + + M.M_FlyCheck.think(self); + return true; + } + }; + + static mframe_t infantry_frames_death1[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 9, null), + new mframe_t(GameAI.ai_move, 9, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -2, InfantryMachineGun), + new mframe_t(GameAI.ai_move, -2, InfantryMachineGun), + new mframe_t(GameAI.ai_move, -3, InfantryMachineGun), + new mframe_t(GameAI.ai_move, -1, InfantryMachineGun), + new mframe_t(GameAI.ai_move, -2, InfantryMachineGun), + new mframe_t(GameAI.ai_move, 0, InfantryMachineGun), + new mframe_t(GameAI.ai_move, 2, InfantryMachineGun), + new mframe_t(GameAI.ai_move, 2, InfantryMachineGun), + new mframe_t(GameAI.ai_move, 3, InfantryMachineGun), + new mframe_t(GameAI.ai_move, -10, InfantryMachineGun), + new mframe_t(GameAI.ai_move, -7, InfantryMachineGun), + new mframe_t(GameAI.ai_move, -8, InfantryMachineGun), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, -11, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, -11, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.DAMAGE_YES; + + n = Lib.rand() % 3; + if (n == 0) { + self.monsterinfo.currentmove = infantry_move_death1; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_die2, 1, + Defines.ATTN_NORM, 0); + } else if (n == 1) { + self.monsterinfo.currentmove = infantry_move_death2; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_die1, 1, + Defines.ATTN_NORM, 0); + } else { + self.monsterinfo.currentmove = infantry_move_death3; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_die2, 1, + Defines.ATTN_NORM, 0); + } + } + }; + + static EntThinkAdapter infantry_duck_down = new EntThinkAdapter() { + public boolean think(edict_t self) { + if ((self.monsterinfo.aiflags & Defines.AI_DUCKED) != 0) + return true; + self.monsterinfo.aiflags |= Defines.AI_DUCKED; + self.maxs[2] -= 32; + self.takedamage = Defines.DAMAGE_YES; + self.monsterinfo.pausetime = GameBase.level.time + 1; + GameBase.gi.linkentity(self); + return true; + } + }; + + static EntThinkAdapter infantry_duck_hold = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (GameBase.level.time >= self.monsterinfo.pausetime) + self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; + else + self.monsterinfo.aiflags |= Defines.AI_HOLD_FRAME; + return true; + } + }; + + static EntThinkAdapter infantry_duck_up = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.monsterinfo.aiflags &= ~Defines.AI_DUCKED; + self.maxs[2] += 32; + self.takedamage = Defines.DAMAGE_AIM; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t infantry_frames_duck[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, -2, infantry_duck_down), + new mframe_t(GameAI.ai_move, -5, infantry_duck_hold), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 4, infantry_duck_up), + new mframe_t(GameAI.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; + + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_weapon_cock, 1, + Defines.ATTN_NORM, 0); + n = (Lib.rand() & 15) + 3 + 7; + self.monsterinfo.pausetime = GameBase.level.time + n + * Defines.FRAMETIME; + return true; + } + }; + + static EntThinkAdapter infantry_fire = new EntThinkAdapter() { + public boolean think(edict_t self) { + InfantryMachineGun.think(self); + + if (GameBase.level.time >= self.monsterinfo.pausetime) + self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; + else + self.monsterinfo.aiflags |= Defines.AI_HOLD_FRAME; + return true; + } + }; + + static mframe_t infantry_frames_attack1[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 4, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, 0, infantry_cock_gun), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 2, null), + new mframe_t(GameAI.ai_charge, -2, null), + new mframe_t(GameAI.ai_charge, -3, null), + new mframe_t(GameAI.ai_charge, 1, infantry_fire), + new mframe_t(GameAI.ai_charge, 5, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, -2, null), + new mframe_t(GameAI.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) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_punch_swing, 1, + Defines.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, Defines.MELEE_DISTANCE, 0, 0); + if (Fire.fire_hit(self, aim, (5 + (Lib.rand() % 5)), 50)) + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_punch_hit, + 1, Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t infantry_frames_attack2[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 3, null), + new mframe_t(GameAI.ai_charge, 6, null), + new mframe_t(GameAI.ai_charge, 0, infantry_swing), + new mframe_t(GameAI.ai_charge, 8, null), + new mframe_t(GameAI.ai_charge, 5, null), + new mframe_t(GameAI.ai_charge, 8, infantry_smack), + new mframe_t(GameAI.ai_charge, 6, null), + new mframe_t(GameAI.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 (GameUtil.range(self, self.enemy) == Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_pain1 = GameBase.gi.soundindex("infantry/infpain1.wav"); + sound_pain2 = GameBase.gi.soundindex("infantry/infpain2.wav"); + sound_die1 = GameBase.gi.soundindex("infantry/infdeth1.wav"); + sound_die2 = GameBase.gi.soundindex("infantry/infdeth2.wav"); + + sound_gunshot = GameBase.gi.soundindex("infantry/infatck1.wav"); + sound_weapon_cock = GameBase.gi.soundindex("infantry/infatck3.wav"); + sound_punch_swing = GameBase.gi.soundindex("infantry/infatck2.wav"); + sound_punch_hit = GameBase.gi.soundindex("infantry/melee2.wav"); + + sound_sight = GameBase.gi.soundindex("infantry/infsght1.wav"); + sound_search = GameBase.gi.soundindex("infantry/infsrch1.wav"); + sound_idle = GameBase.gi.soundindex("infantry/infidle1.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = infantry_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Insane.java b/src/jake2/game/M_Insane.java index 3c8fe9b..bd92a5d 100644 --- a/src/jake2/game/M_Insane.java +++ b/src/jake2/game/M_Insane.java @@ -1,959 +1,1285 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Insane.java,v 1.3 2004-09-22 19:22:03 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Insane { + // This file generated by ModelGen - Do NOT Modify -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. + public final static int FRAME_stand1 = 0; -*/ + public final static int FRAME_stand2 = 1; -// Created on 13.11.2003 by RST. -// $Id: M_Insane.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_stand3 = 2; -package jake2.game; + 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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_fist, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; + + static EntThinkAdapter insane_shake = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_shake, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; + + static EntThinkAdapter insane_moan = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_moan, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; + + static EntThinkAdapter insane_scream = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, + sound_scream[Lib.rand() % 8], 1, Defines.ATTN_IDLE, 0); + return true; + } + }; -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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, insane_shake), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, insane_moan), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2.7f, null), - new mframe_t(GameAIAdapters.ai_move, 4.1f, null), - new mframe_t(GameAIAdapters.ai_move, 6f, null), - new mframe_t(GameAIAdapters.ai_move, 7.6f, null), - new mframe_t(GameAIAdapters.ai_move, 3.6f, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, insane_fist), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, insane_fist), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -0.7f, null), // 41 - new mframe_t(GameAIAdapters.ai_move, -1.2f, null), // 42 - new mframe_t(GameAIAdapters.ai_move, -1.5f, null), // 43 - new mframe_t(GameAIAdapters.ai_move, -4.5f, null), // 44 - new mframe_t(GameAIAdapters.ai_move, -3.5f, null), // 45 - new mframe_t(GameAIAdapters.ai_move, -0.2f, null), // 46 - new mframe_t(GameAIAdapters.ai_move, 0, null), // 47 - new mframe_t(GameAIAdapters.ai_move, -1.3f, null), // 48 - new mframe_t(GameAIAdapters.ai_move, -3, null), // 49 - new mframe_t(GameAIAdapters.ai_move, -2, null), // 50 - new mframe_t(GameAIAdapters.ai_move, 0, null), // 51 - new mframe_t(GameAIAdapters.ai_move, 0, null), // 52 - new mframe_t(GameAIAdapters.ai_move, 0, null), // 53 - new mframe_t(GameAIAdapters.ai_move, -3.3f, null), // 54 - new mframe_t(GameAIAdapters.ai_move, -1.6f, null), // 55 - new mframe_t(GameAIAdapters.ai_move, -0.3f, null), // 56 - new mframe_t(GameAIAdapters.ai_move, 0, null), // 57 - new mframe_t(GameAIAdapters.ai_move, 0, null), // 58 - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0.2f, null), - new mframe_t(GameAIAdapters.ai_move, 11.5f, null), - new mframe_t(GameAIAdapters.ai_move, 5.1f, null), - new mframe_t(GameAIAdapters.ai_move, 7.1f, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), // 100) - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 110) - new mframe_t(GameAIAdapters.ai_move, -1.7f, null), - new mframe_t(GameAIAdapters.ai_move, -1.6f, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, insane_fist), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 120) - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 130 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, insane_moan), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 140 - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - // 150 - new mframe_t(GameAIAdapters.ai_move, 0.5f, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -0.2f, insane_scream), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0.2f, null), - new mframe_t(GameAIAdapters.ai_move, 0.4f, null), - new mframe_t(GameAIAdapters.ai_move, 0.6f, null), - new mframe_t(GameAIAdapters.ai_move, 0.8f, null), - new mframe_t(GameAIAdapters.ai_move, 0.7f, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 0, insane_scream), - new mframe_t(GameAIAdapters.ai_walk, 2.5f, null), - new mframe_t(GameAIAdapters.ai_walk, 3.5f, null), - new mframe_t(GameAIAdapters.ai_walk, 1.7f, null), - new mframe_t(GameAIAdapters.ai_walk, 2.3f, null), - new mframe_t(GameAIAdapters.ai_walk, 2.4f, null), - new mframe_t(GameAIAdapters.ai_walk, 2.2f, null), - new mframe_t(GameAIAdapters.ai_walk, 4.2f, null), - new mframe_t(GameAIAdapters.ai_walk, 5.6f, null), - new mframe_t(GameAIAdapters.ai_walk, 3.3f, null), - new mframe_t(GameAIAdapters.ai_walk, 2.4f, null), - new mframe_t(GameAIAdapters.ai_walk, 0.9f, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 0, insane_scream), // walk 1 - new mframe_t(GameAIAdapters.ai_walk, 3.4f, null), // walk 2 - new mframe_t(GameAIAdapters.ai_walk, 3.6f, null), // 3 - new mframe_t(GameAIAdapters.ai_walk, 2.9f, null), // 4 - new mframe_t(GameAIAdapters.ai_walk, 2.2f, null), // 5 - new mframe_t(GameAIAdapters.ai_walk, 2.6f, null), // 6 - new mframe_t(GameAIAdapters.ai_walk, 0, null), // 7 - new mframe_t(GameAIAdapters.ai_walk, 0.7f, null), // 8 - new mframe_t(GameAIAdapters.ai_walk, 4.8f, null), // 9 - new mframe_t(GameAIAdapters.ai_walk, 5.3f, null), // 10 - new mframe_t(GameAIAdapters.ai_walk, 1.1f, null), // 11 - new mframe_t(GameAIAdapters.ai_walk, 2, null), // 12 - new mframe_t(GameAIAdapters.ai_walk, 0.5f, null), // 13 - new mframe_t(GameAIAdapters.ai_walk, 0, null), // 14 - new mframe_t(GameAIAdapters.ai_walk, 0, null), // 15 - new mframe_t(GameAIAdapters.ai_walk, 4.9f, null), // 16 - new mframe_t(GameAIAdapters.ai_walk, 6.7f, null), // 17 - new mframe_t(GameAIAdapters.ai_walk, 3.8f, null), // 18 - new mframe_t(GameAIAdapters.ai_walk, 2, null), // 19 - new mframe_t(GameAIAdapters.ai_walk, 0.2f, null), // 20 - new mframe_t(GameAIAdapters.ai_walk, 0, null), // 21 - new mframe_t(GameAIAdapters.ai_walk, 3.4f, null), // 22 - new mframe_t(GameAIAdapters.ai_walk, 6.4f, null), // 23 - new mframe_t(GameAIAdapters.ai_walk, 5, null), // 24 - new mframe_t(GameAIAdapters.ai_walk, 1.8f, null), // 25 - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 0, insane_scream), - new mframe_t(GameAIAdapters.ai_walk, 1.5f, null), - new mframe_t(GameAIAdapters.ai_walk, 2.1f, null), - new mframe_t(GameAIAdapters.ai_walk, 3.6f, null), - new mframe_t(GameAIAdapters.ai_walk, 2f, null), - new mframe_t(GameAIAdapters.ai_walk, 0.9f, null), - new mframe_t(GameAIAdapters.ai_walk, 3f, null), - new mframe_t(GameAIAdapters.ai_walk, 3.4f, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, insane_moan), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, insane_scream), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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; - GameAIAdapters.flymonster_start.think(self); - } else { - GameAIAdapters.walkmonster_start.think(self); - self.s.skinnum = Lib.rand() % 3; - } - } - -} + 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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.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; + GameBase.gi.sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("player/male/pain" + l + "_" + r + ".wav"), 1, + Defines.ATTN_IDLE, 0); + + if (GameBase.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 |= Defines.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 |= Defines.FL_FLY; + } else { + Math3D.VectorSet(self.mins, -16, -16, -24); + Math3D.VectorSet(self.maxs, 16, 16, -8); + self.movetype = Defines.MOVETYPE_TOSS; + } + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_IDLE, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + GameBase.gi.sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("player/male/death" + ((Lib.rand() % 4) + 1) + + ".wav"), 1, Defines.ATTN_IDLE, 0); + + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_stand, 0, insane_shake), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, insane_moan), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2.7f, null), + new mframe_t(GameAI.ai_move, 4.1f, null), + new mframe_t(GameAI.ai_move, 6f, null), + new mframe_t(GameAI.ai_move, 7.6f, null), + new mframe_t(GameAI.ai_move, 3.6f, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, insane_fist), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, insane_fist), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, -0.7f, null), // 41 + new mframe_t(GameAI.ai_move, -1.2f, null), // 42 + new mframe_t(GameAI.ai_move, -1.5f, null), // 43 + new mframe_t(GameAI.ai_move, -4.5f, null), // 44 + new mframe_t(GameAI.ai_move, -3.5f, null), // 45 + new mframe_t(GameAI.ai_move, -0.2f, null), // 46 + new mframe_t(GameAI.ai_move, 0, null), // 47 + new mframe_t(GameAI.ai_move, -1.3f, null), // 48 + new mframe_t(GameAI.ai_move, -3, null), // 49 + new mframe_t(GameAI.ai_move, -2, null), // 50 + new mframe_t(GameAI.ai_move, 0, null), // 51 + new mframe_t(GameAI.ai_move, 0, null), // 52 + new mframe_t(GameAI.ai_move, 0, null), // 53 + new mframe_t(GameAI.ai_move, -3.3f, null), // 54 + new mframe_t(GameAI.ai_move, -1.6f, null), // 55 + new mframe_t(GameAI.ai_move, -0.3f, null), // 56 + new mframe_t(GameAI.ai_move, 0, null), // 57 + new mframe_t(GameAI.ai_move, 0, null), // 58 + new mframe_t(GameAI.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(GameAI.ai_move, 0.2f, null), + new mframe_t(GameAI.ai_move, 11.5f, null), + new mframe_t(GameAI.ai_move, 5.1f, null), + new mframe_t(GameAI.ai_move, 7.1f, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), // 100) + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 110) + new mframe_t(GameAI.ai_move, -1.7f, null), + new mframe_t(GameAI.ai_move, -1.6f, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, insane_fist), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 120) + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 130 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, insane_moan), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 140 + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + // 150 + new mframe_t(GameAI.ai_move, 0.5f, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -0.2f, insane_scream), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0.2f, null), + new mframe_t(GameAI.ai_move, 0.4f, null), + new mframe_t(GameAI.ai_move, 0.6f, null), + new mframe_t(GameAI.ai_move, 0.8f, null), + new mframe_t(GameAI.ai_move, 0.7f, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 0, insane_scream), + new mframe_t(GameAI.ai_walk, 2.5f, null), + new mframe_t(GameAI.ai_walk, 3.5f, null), + new mframe_t(GameAI.ai_walk, 1.7f, null), + new mframe_t(GameAI.ai_walk, 2.3f, null), + new mframe_t(GameAI.ai_walk, 2.4f, null), + new mframe_t(GameAI.ai_walk, 2.2f, null), + new mframe_t(GameAI.ai_walk, 4.2f, null), + new mframe_t(GameAI.ai_walk, 5.6f, null), + new mframe_t(GameAI.ai_walk, 3.3f, null), + new mframe_t(GameAI.ai_walk, 2.4f, null), + new mframe_t(GameAI.ai_walk, 0.9f, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 0, insane_scream), // walk 1 + new mframe_t(GameAI.ai_walk, 3.4f, null), // walk 2 + new mframe_t(GameAI.ai_walk, 3.6f, null), // 3 + new mframe_t(GameAI.ai_walk, 2.9f, null), // 4 + new mframe_t(GameAI.ai_walk, 2.2f, null), // 5 + new mframe_t(GameAI.ai_walk, 2.6f, null), // 6 + new mframe_t(GameAI.ai_walk, 0, null), // 7 + new mframe_t(GameAI.ai_walk, 0.7f, null), // 8 + new mframe_t(GameAI.ai_walk, 4.8f, null), // 9 + new mframe_t(GameAI.ai_walk, 5.3f, null), // 10 + new mframe_t(GameAI.ai_walk, 1.1f, null), // 11 + new mframe_t(GameAI.ai_walk, 2, null), // 12 + new mframe_t(GameAI.ai_walk, 0.5f, null), // 13 + new mframe_t(GameAI.ai_walk, 0, null), // 14 + new mframe_t(GameAI.ai_walk, 0, null), // 15 + new mframe_t(GameAI.ai_walk, 4.9f, null), // 16 + new mframe_t(GameAI.ai_walk, 6.7f, null), // 17 + new mframe_t(GameAI.ai_walk, 3.8f, null), // 18 + new mframe_t(GameAI.ai_walk, 2, null), // 19 + new mframe_t(GameAI.ai_walk, 0.2f, null), // 20 + new mframe_t(GameAI.ai_walk, 0, null), // 21 + new mframe_t(GameAI.ai_walk, 3.4f, null), // 22 + new mframe_t(GameAI.ai_walk, 6.4f, null), // 23 + new mframe_t(GameAI.ai_walk, 5, null), // 24 + new mframe_t(GameAI.ai_walk, 1.8f, null), // 25 + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 0, insane_scream), + new mframe_t(GameAI.ai_walk, 1.5f, null), + new mframe_t(GameAI.ai_walk, 2.1f, null), + new mframe_t(GameAI.ai_walk, 3.6f, null), + new mframe_t(GameAI.ai_walk, 2f, null), + new mframe_t(GameAI.ai_walk, 0.9f, null), + new mframe_t(GameAI.ai_walk, 3f, null), + new mframe_t(GameAI.ai_walk, 3.4f, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, insane_moan), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, insane_scream), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_fist = GameBase.gi.soundindex("insane/insane11.wav"); + sound_shake = GameBase.gi.soundindex("insane/insane5.wav"); + sound_moan = GameBase.gi.soundindex("insane/insane7.wav"); + sound_scream[0] = GameBase.gi.soundindex("insane/insane1.wav"); + sound_scream[1] = GameBase.gi.soundindex("insane/insane2.wav"); + sound_scream[2] = GameBase.gi.soundindex("insane/insane3.wav"); + sound_scream[3] = GameBase.gi.soundindex("insane/insane4.wav"); + sound_scream[4] = GameBase.gi.soundindex("insane/insane6.wav"); + sound_scream[5] = GameBase.gi.soundindex("insane/insane8.wav"); + sound_scream[6] = GameBase.gi.soundindex("insane/insane9.wav"); + sound_scream[7] = GameBase.gi.soundindex("insane/insane10.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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 |= Defines.AI_GOOD_GUY; + + // @@ + // self.s.skinnum = skin; + // skin++; + // if (skin > 12) + // skin = 0; + + GameBase.gi.linkentity(self); + + if ((self.spawnflags & 16) != 0) // Stand Ground + self.monsterinfo.aiflags |= Defines.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 |= Defines.FL_NO_KNOCKBACK; + GameAI.flymonster_start.think(self); + } else { + GameAI.walkmonster_start.think(self); + self.s.skinnum = Lib.rand() % 3; + } + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Medic.java b/src/jake2/game/M_Medic.java index 6d5d01b..4217bd6 100644 --- a/src/jake2/game/M_Medic.java +++ b/src/jake2/game/M_Medic.java @@ -1,1006 +1,1284 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Medic.java,v 1.3 2004-09-22 19:22:03 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Medic { + // This file generated by ModelGen - Do NOT Modify -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. + public final static int FRAME_walk1 = 0; -*/ + public final static int FRAME_walk2 = 1; -// Created on 13.11.2003 by RST. -// $Id: M_Medic.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_walk3 = 2; -package jake2.game; + 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; -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(GameAIAdapters.ai_stand, 0, medic_idle), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 6.2f, null), - new mframe_t(GameAIAdapters.ai_walk, 18.1f, null), - new mframe_t(GameAIAdapters.ai_walk, 1, null), - new mframe_t(GameAIAdapters.ai_walk, 9, null), - new mframe_t(GameAIAdapters.ai_walk, 10, null), - new mframe_t(GameAIAdapters.ai_walk, 9, null), - new mframe_t(GameAIAdapters.ai_walk, 11, null), - new mframe_t(GameAIAdapters.ai_walk, 11.6f, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 9.9f, null), - new mframe_t(GameAIAdapters.ai_walk, 14, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 18, null), - new mframe_t(GameAIAdapters.ai_run, 22.5f, null), - new mframe_t(GameAIAdapters.ai_run, 25.4f, null), - new mframe_t(GameAIAdapters.ai_run, 23.4f, null), - new mframe_t(GameAIAdapters.ai_run, 24, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, medic_duck_down), - new mframe_t(GameAIAdapters.ai_move, -1, medic_duck_hold), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, medic_duck_up), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 5, null), - new mframe_t(GameAIAdapters.ai_charge, 5, null), - new mframe_t(GameAIAdapters.ai_charge, 3, null), - new mframe_t(GameAIAdapters.ai_charge, 2, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, medic_fire_blaster), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.ai_move, 4.4f, null), - new mframe_t(GameAIAdapters.ai_charge, 4.7f, null), - new mframe_t(GameAIAdapters.ai_charge, 5, null), - new mframe_t(GameAIAdapters.ai_charge, 6, null), - new mframe_t(GameAIAdapters.ai_charge, 4, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, medic_hook_launch), - new mframe_t(GameAIAdapters.ai_move, 0, medic_cable_attack), - new mframe_t(GameAIAdapters.ai_move, 0, medic_cable_attack), - new mframe_t(GameAIAdapters.ai_move, 0, medic_cable_attack), - new mframe_t(GameAIAdapters.ai_move, 0, medic_cable_attack), - new mframe_t(GameAIAdapters.ai_move, 0, medic_cable_attack), - new mframe_t(GameAIAdapters.ai_move, 0, medic_cable_attack), - new mframe_t(GameAIAdapters.ai_move, 0, medic_cable_attack), - new mframe_t(GameAIAdapters.ai_move, 0, medic_cable_attack), - new mframe_t(GameAIAdapters.ai_move, 0, medic_cable_attack), - new mframe_t(GameAIAdapters.ai_move, -15, medic_hook_retract), - new mframe_t(GameAIAdapters.ai_move, -1.5f, null), - new mframe_t(GameAIAdapters.ai_move, -1.2f, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 0.3f, null), - new mframe_t(GameAIAdapters.ai_move, 0.7f, null), - new mframe_t(GameAIAdapters.ai_move, 1.2f, null), - new mframe_t(GameAIAdapters.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 GameUtilAdapters.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; - - GameAIAdapters.walkmonster_start.think(self); - } - -} + while ((edit = GameBase.findradius(edit, self.s.origin, 1024)) != null) { + ent = edit.o; + if (ent == self) + continue; + if (0 == (ent.svflags & Defines.SVF_MONSTER)) + continue; + if ((ent.monsterinfo.aiflags & Defines.AI_GOOD_GUY) != 0) + continue; + if (ent.owner == null) + continue; + if (ent.health > 0) + continue; + if (ent.nextthink == 0) + continue; + if (!GameUtil.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; + + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle1, 1, + Defines.ATTN_IDLE, 0); + + ent = medic_FindDeadMonster(self); + if (ent != null) { + self.enemy = ent; + self.enemy.owner = self; + self.monsterinfo.aiflags |= Defines.AI_MEDIC; + GameUtil.FoundTarget(self); + } + return true; + } + }; + + static EntThinkAdapter medic_search = new EntThinkAdapter() { + public boolean think(edict_t self) { + edict_t ent; + + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search, 1, + Defines.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 |= Defines.AI_MEDIC; + GameUtil.FoundTarget(self); + } + } + return true; + } + }; + + static EntInteractAdapter medic_sight = new EntInteractAdapter() { + public boolean interact(edict_t self, edict_t other) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static mframe_t medic_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, medic_idle), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 6.2f, null), + new mframe_t(GameAI.ai_walk, 18.1f, null), + new mframe_t(GameAI.ai_walk, 1, null), + new mframe_t(GameAI.ai_walk, 9, null), + new mframe_t(GameAI.ai_walk, 10, null), + new mframe_t(GameAI.ai_walk, 9, null), + new mframe_t(GameAI.ai_walk, 11, null), + new mframe_t(GameAI.ai_walk, 11.6f, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 9.9f, null), + new mframe_t(GameAI.ai_walk, 14, null), + new mframe_t(GameAI.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(GameAI.ai_run, 18, null), + new mframe_t(GameAI.ai_run, 22.5f, null), + new mframe_t(GameAI.ai_run, 25.4f, null), + new mframe_t(GameAI.ai_run, 23.4f, null), + new mframe_t(GameAI.ai_run, 24, null), + new mframe_t(GameAI.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 & Defines.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 |= Defines.AI_MEDIC; + GameUtil.FoundTarget(self); + return true; + } + } + + if ((self.monsterinfo.aiflags & Defines.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + if (Lib.random() < 0.5) { + self.monsterinfo.currentmove = medic_move_pain1; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + } else { + self.monsterinfo.currentmove = medic_move_pain2; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.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 = Defines.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 = Defines.EF_HYPERBLASTER; + else + effect = 0; + + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.monster_flash_offset[Defines.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, + Defines.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t medic_frames_death[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_die, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 & Defines.AI_DUCKED) != 0) + return true; + self.monsterinfo.aiflags |= Defines.AI_DUCKED; + self.maxs[2] -= 32; + self.takedamage = Defines.DAMAGE_YES; + self.monsterinfo.pausetime = GameBase.level.time + 1; + GameBase.gi.linkentity(self); + return true; + } + }; + + static EntThinkAdapter medic_duck_hold = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (GameBase.level.time >= self.monsterinfo.pausetime) + self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; + else + self.monsterinfo.aiflags |= Defines.AI_HOLD_FRAME; + return true; + } + }; + + static EntThinkAdapter medic_duck_up = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.monsterinfo.aiflags &= ~Defines.AI_DUCKED; + self.maxs[2] += 32; + self.takedamage = Defines.DAMAGE_AIM; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t medic_frames_duck[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, medic_duck_down), + new mframe_t(GameAI.ai_move, -1, medic_duck_hold), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, medic_duck_up), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.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 (GameUtil.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 5, null), + new mframe_t(GameAI.ai_charge, 5, null), + new mframe_t(GameAI.ai_charge, 3, null), + new mframe_t(GameAI.ai_charge, 2, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, medic_fire_blaster), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_hook_launch, 1, + Defines.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 = GameBase.gi.trace(start, null, null, self.enemy.s.origin, + self, Defines.MASK_SHOT); + if (tr.fraction != 1.0 && tr.ent != self.enemy) + return true; + + if (self.s.frame == FRAME_attack43) { + GameBase.gi.sound(self.enemy, Defines.CHAN_AUTO, + sound_hook_hit, 1, Defines.ATTN_NORM, 0); + self.enemy.monsterinfo.aiflags |= Defines.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 = GameBase.level.time; + self.enemy.think.think(self.enemy); + } + self.enemy.monsterinfo.aiflags |= Defines.AI_RESURRECTING; + if (self.oldenemy != null && self.oldenemy.client != null) { + self.enemy.enemy = self.oldenemy; + GameUtil.FoundTarget(self.enemy); + } + } else { + if (self.s.frame == FRAME_attack44) + GameBase.gi.sound(self, Defines.CHAN_WEAPON, + sound_hook_heal, 1, Defines.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; + + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_MEDIC_CABLE_ATTACK); + GameBase.gi.WriteShort(self.index); + GameBase.gi.WritePosition(start); + GameBase.gi.WritePosition(end); + GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); + return true; + } + }; + + static EntThinkAdapter medic_hook_retract = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_hook_retract, 1, + Defines.ATTN_NORM, 0); + self.enemy.monsterinfo.aiflags &= ~Defines.AI_RESURRECTING; + return true; + } + }; + + static mframe_t medic_frames_attackCable[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.ai_move, 4.4f, null), + new mframe_t(GameAI.ai_charge, 4.7f, null), + new mframe_t(GameAI.ai_charge, 5, null), + new mframe_t(GameAI.ai_charge, 6, null), + new mframe_t(GameAI.ai_charge, 4, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_move, 0, medic_hook_launch), + new mframe_t(GameAI.ai_move, 0, medic_cable_attack), + new mframe_t(GameAI.ai_move, 0, medic_cable_attack), + new mframe_t(GameAI.ai_move, 0, medic_cable_attack), + new mframe_t(GameAI.ai_move, 0, medic_cable_attack), + new mframe_t(GameAI.ai_move, 0, medic_cable_attack), + new mframe_t(GameAI.ai_move, 0, medic_cable_attack), + new mframe_t(GameAI.ai_move, 0, medic_cable_attack), + new mframe_t(GameAI.ai_move, 0, medic_cable_attack), + new mframe_t(GameAI.ai_move, 0, medic_cable_attack), + new mframe_t(GameAI.ai_move, -15, medic_hook_retract), + new mframe_t(GameAI.ai_move, -1.5f, null), + new mframe_t(GameAI.ai_move, -1.2f, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 0.3f, null), + new mframe_t(GameAI.ai_move, 0.7f, null), + new mframe_t(GameAI.ai_move, 1.2f, null), + new mframe_t(GameAI.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 & Defines.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 & Defines.AI_MEDIC) != 0) { + medic_attack.think(self); + return true; + } + + return GameUtil.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return; + } + + sound_idle1 = GameBase.gi.soundindex("medic/idle.wav"); + sound_pain1 = GameBase.gi.soundindex("medic/medpain1.wav"); + sound_pain2 = GameBase.gi.soundindex("medic/medpain2.wav"); + sound_die = GameBase.gi.soundindex("medic/meddeth1.wav"); + sound_sight = GameBase.gi.soundindex("medic/medsght1.wav"); + sound_search = GameBase.gi.soundindex("medic/medsrch1.wav"); + sound_hook_launch = GameBase.gi.soundindex("medic/medatck2.wav"); + sound_hook_hit = GameBase.gi.soundindex("medic/medatck3.wav"); + sound_hook_heal = GameBase.gi.soundindex("medic/medatck4.wav"); + sound_hook_retract = GameBase.gi.soundindex("medic/medatck5.wav"); + + GameBase.gi.soundindex("medic/medatck1.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = medic_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Mutant.java b/src/jake2/game/M_Mutant.java index 6e387b0..91fb813 100644 --- a/src/jake2/game/M_Mutant.java +++ b/src/jake2/game/M_Mutant.java @@ -1,834 +1,1037 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Mutant.java,v 1.3 2004-09-22 19:22:01 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.client.M; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Mutant { -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. + // This file generated by ModelGen - Do NOT Modify -*/ + public final static int FRAME_attack01 = 0; -// Created on 13.11.2003 by RST. -// $Id: M_Mutant.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_attack02 = 1; -package jake2.game; + public final static int FRAME_attack03 = 2; -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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 10) - - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 20) - - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 30) - - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 40) - - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // 50) - - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - // scratch loop start - new mframe_t(GameAIAdapters.ai_stand, 0, null), new mframe_t(GameAIAdapters.ai_stand, 0, null), new mframe_t(GameAIAdapters.ai_stand, 0, mutant_idle_loop), - // scratch loop end - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 1, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 10, null), - new mframe_t(GameAIAdapters.ai_walk, 13, null), - new mframe_t(GameAIAdapters.ai_walk, 10, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 16, null), - new mframe_t(GameAIAdapters.ai_walk, 15, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, -2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 40, null), - new mframe_t(GameAIAdapters.ai_run, 40, mutant_step), - new mframe_t(GameAIAdapters.ai_run, 24, null), - new mframe_t(GameAIAdapters.ai_run, 5, mutant_step), - new mframe_t(GameAIAdapters.ai_run, 17, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, mutant_hit_left), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, mutant_hit_right), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 17, null), - new mframe_t(GameAIAdapters.ai_charge, 15, mutant_jump_takeoff), - new mframe_t(GameAIAdapters.ai_charge, 15, null), - new mframe_t(GameAIAdapters.ai_charge, 15, mutant_check_landing), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 3, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, -8, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -24, null), - new mframe_t(GameAIAdapters.ai_move, 11, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 6, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -22, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 6, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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; - GameAIAdapters.walkmonster_start.think(self); - return true; - } - }; + 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) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_step1, 1, + Defines.ATTN_NORM, 0); + else if (n == 1) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_step2, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_step3, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntInteractAdapter mutant_sight = new EntInteractAdapter() { + public boolean interact(edict_t self, edict_t other) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter mutant_search = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter mutant_swing = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_swing, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + // + // STAND + // + + static mframe_t mutant_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 10) + + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 20) + + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 30) + + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 40) + + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // 50) + + new mframe_t(GameAI.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + // scratch loop start + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, mutant_idle_loop), + // scratch loop end + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; + + // + // WALK + // + + static mframe_t mutant_frames_walk[] = new mframe_t[] { + new mframe_t(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 1, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 10, null), + new mframe_t(GameAI.ai_walk, 13, null), + new mframe_t(GameAI.ai_walk, 10, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 16, null), + new mframe_t(GameAI.ai_walk, 15, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, -2, null), + new mframe_t(GameAI.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(GameAI.ai_run, 40, null), + new mframe_t(GameAI.ai_run, 40, mutant_step), + new mframe_t(GameAI.ai_run, 24, null), + new mframe_t(GameAI.ai_run, 5, mutant_step), + new mframe_t(GameAI.ai_run, 17, null), + new mframe_t(GameAI.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 & Defines.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, Defines.MELEE_DISTANCE, self.mins[0], 8); + if (Fire.fire_hit(self, aim, (10 + (Lib.rand() % 5)), 100)) + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_hit, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_swing, 1, + Defines.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, Defines.MELEE_DISTANCE, self.maxs[0], 8); + if (Fire.fire_hit(self, aim, (10 + (Lib.rand() % 5)), 100)) + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_hit2, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_swing, 1, + Defines.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 (((GameBase.skill.value == 3) && (Lib.random() < 0.5)) + || (GameUtil.range(self, self.enemy) == Defines.RANGE_MELEE)) + self.monsterinfo.nextframe = FRAME_attack09; + return true; + } + }; + + static mframe_t mutant_frames_attack[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, mutant_hit_left), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, mutant_hit_right), + new mframe_t(GameAI.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()); + GameUtil.T_Damage(other, self, self, self.velocity, point, + normal, damage, damage, 0, Defines.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 }; + + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.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 |= Defines.AI_DUCKED; + self.monsterinfo.attack_finished = GameBase.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) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_thud, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.attack_finished = 0; + self.monsterinfo.aiflags &= ~Defines.AI_DUCKED; + return true; + } + + if (GameBase.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 17, null), + new mframe_t(GameAI.ai_charge, 15, mutant_jump_takeoff), + new mframe_t(GameAI.ai_charge, 15, null), + new mframe_t(GameAI.ai_charge, 15, mutant_check_landing), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 3, null), + new mframe_t(GameAI.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 (GameUtil.range(self, self.enemy) == Defines.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 = Defines.AS_MELEE; + return true; + } + + if (mutant_check_jump.think(self)) { + self.monsterinfo.attack_state = Defines.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(GameAI.ai_move, 4, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, -8, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.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(GameAI.ai_move, -24, null), + new mframe_t(GameAI.ai_move, 11, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 6, null), + new mframe_t(GameAI.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(GameAI.ai_move, -22, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 6, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + r = Lib.random(); + if (r < 0.33) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = mutant_move_pain1; + } else if (r < 0.66) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = mutant_move_pain2; + } else { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + GameBase.gi.linkentity(self); + + M.M_FlyCheck.think(self); + return true; + } + }; + + static mframe_t mutant_frames_death1[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return false; + } + + sound_swing = GameBase.gi.soundindex("mutant/mutatck1.wav"); + sound_hit = GameBase.gi.soundindex("mutant/mutatck2.wav"); + sound_hit2 = GameBase.gi.soundindex("mutant/mutatck3.wav"); + sound_death = GameBase.gi.soundindex("mutant/mutdeth1.wav"); + sound_idle = GameBase.gi.soundindex("mutant/mutidle1.wav"); + sound_pain1 = GameBase.gi.soundindex("mutant/mutpain1.wav"); + sound_pain2 = GameBase.gi.soundindex("mutant/mutpain2.wav"); + sound_sight = GameBase.gi.soundindex("mutant/mutsght1.wav"); + sound_search = GameBase.gi.soundindex("mutant/mutsrch1.wav"); + sound_step1 = GameBase.gi.soundindex("mutant/step1.wav"); + sound_step2 = GameBase.gi.soundindex("mutant/step2.wav"); + sound_step3 = GameBase.gi.soundindex("mutant/step3.wav"); + sound_thud = GameBase.gi.soundindex("mutant/thud1.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = mutant_move_stand; + + self.monsterinfo.scale = MODEL_SCALE; + GameAI.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 index 1ba4f5a..e3a9887 100644 --- a/src/jake2/game/M_Parasite.java +++ b/src/jake2/game/M_Parasite.java @@ -1,675 +1,841 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Parasite.java,v 1.3 2004-09-22 19:22:06 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.Globals; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Parasite { -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. + // This file generated by ModelGen - Do NOT Modify -*/ + public final static int FRAME_break01 = 0; -// Created on 13.11.2003 by RST. -// $Id: M_Parasite.java,v 1.2 2004-07-08 15:58:43 hzi Exp $ + public final static int FRAME_break02 = 1; -package jake2.game; + 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) { + + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_launch, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter parasite_reel_in = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_reelin, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntInteractAdapter parasite_sight = new EntInteractAdapter() { + public boolean interact(edict_t self, edict_t other) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter parasite_tap = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_tap, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; + + static EntThinkAdapter parasite_scratch = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_scratch, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; -import jake2.util.*; -import jake2.util.*; - -public class M_Parasite extends M_Player { - - // 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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, parasite_scratch), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, parasite_scratch), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, parasite_scratch), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, parasite_tap), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, parasite_tap), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, parasite_tap), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, parasite_tap), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, parasite_tap), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 30, null), - new mframe_t(GameAIAdapters.ai_run, 30, null), - new mframe_t(GameAIAdapters.ai_run, 22, null), - new mframe_t(GameAIAdapters.ai_run, 19, null), - new mframe_t(GameAIAdapters.ai_run, 24, null), - new mframe_t(GameAIAdapters.ai_run, 28, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 0, null), new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 20, null), - new mframe_t(GameAIAdapters.ai_run, 20, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 30, null), - new mframe_t(GameAIAdapters.ai_walk, 30, null), - new mframe_t(GameAIAdapters.ai_walk, 22, null), - new mframe_t(GameAIAdapters.ai_walk, 19, null), - new mframe_t(GameAIAdapters.ai_walk, 24, null), - new mframe_t(GameAIAdapters.ai_walk, 28, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 0, null), new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 20, null), - new mframe_t(GameAIAdapters.ai_walk, 20, null), - new mframe_t(GameAIAdapters.ai_walk, 12, null), - new mframe_t(GameAIAdapters.ai_walk, 10, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 6, null), - new mframe_t(GameAIAdapters.ai_move, 16, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, -7, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, parasite_launch), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 15, parasite_drain_attack), - // Target hits) - new mframe_t(GameAIAdapters.ai_charge, 0, parasite_drain_attack), // drain) - new mframe_t(GameAIAdapters.ai_charge, 0, parasite_drain_attack), // drain) - new mframe_t(GameAIAdapters.ai_charge, 0, parasite_drain_attack), // drain) - new mframe_t(GameAIAdapters.ai_charge, 0, parasite_drain_attack), // drain) - new mframe_t(GameAIAdapters.ai_charge, -2, parasite_drain_attack), // drain) - new mframe_t(GameAIAdapters.ai_charge, -2, parasite_drain_attack), // drain) - new mframe_t(GameAIAdapters.ai_charge, -3, parasite_drain_attack), // drain) - new mframe_t(GameAIAdapters.ai_charge, -2, parasite_drain_attack), // drain) - new mframe_t(GameAIAdapters.ai_charge, 0, parasite_drain_attack), // drain) - new mframe_t(GameAIAdapters.ai_charge, -1, parasite_drain_attack), // drain) - new mframe_t(GameAIAdapters.ai_charge, 0, parasite_reel_in), // let go) - new mframe_t(GameAIAdapters.ai_charge, -2, null), - new mframe_t(GameAIAdapters.ai_charge, -2, null), - new mframe_t(GameAIAdapters.ai_charge, -3, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -3, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 2, null), - new mframe_t(GameAIAdapters.ai_charge, -3, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 3, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -18, null), - new mframe_t(GameAIAdapters.ai_charge, 3, null), - new mframe_t(GameAIAdapters.ai_charge, 9, null), - new mframe_t(GameAIAdapters.ai_charge, 6, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -18, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 8, null), - new mframe_t(GameAIAdapters.ai_charge, 9, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -18, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - /* airborne */ - new mframe_t(GameAIAdapters.ai_charge, 0, null), /* slides */ - new mframe_t(GameAIAdapters.ai_charge, 0, null), /* slides */ - new mframe_t(GameAIAdapters.ai_charge, 0, null), /* slides */ - new mframe_t(GameAIAdapters.ai_charge, 0, null), /* slides */ - new mframe_t(GameAIAdapters.ai_charge, 4, null), - new mframe_t(GameAIAdapters.ai_charge, 11, null), - new mframe_t(GameAIAdapters.ai_charge, -2, null), - new mframe_t(GameAIAdapters.ai_charge, -5, null), - new mframe_t(GameAIAdapters.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 = ¶site_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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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; - - GameAIAdapters.walkmonster_start.think(self); - - return true; - } - }; -} + static EntThinkAdapter parasite_search = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_search, 1, + Defines.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 & Defines.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 & Defines.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_stand, 0, parasite_scratch), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, parasite_scratch), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_stand, 0, parasite_scratch), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, parasite_tap), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, parasite_tap), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, parasite_tap), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, parasite_tap), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, parasite_tap), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_run, 30, null), + new mframe_t(GameAI.ai_run, 30, null), + new mframe_t(GameAI.ai_run, 22, null), + new mframe_t(GameAI.ai_run, 19, null), + new mframe_t(GameAI.ai_run, 24, null), + new mframe_t(GameAI.ai_run, 28, null), + new mframe_t(GameAI.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(GameAI.ai_run, 0, null), + new mframe_t(GameAI.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(GameAI.ai_run, 20, null), + new mframe_t(GameAI.ai_run, 20, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 30, null), + new mframe_t(GameAI.ai_walk, 30, null), + new mframe_t(GameAI.ai_walk, 22, null), + new mframe_t(GameAI.ai_walk, 19, null), + new mframe_t(GameAI.ai_walk, 24, null), + new mframe_t(GameAI.ai_walk, 28, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 20, null), + new mframe_t(GameAI.ai_walk, 20, null), + new mframe_t(GameAI.ai_walk, 12, null), + new mframe_t(GameAI.ai_walk, 10, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 6, null), + new mframe_t(GameAI.ai_move, 16, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, -7, null), + new mframe_t(GameAI.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 (GameBase.level.time < self.pain_debounce_time) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + if (Lib.random() < 0.5) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.ATTN_NORM, 0); + + self.monsterinfo.currentmove = parasite_move_pain1; + } + }; + + 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 = GameBase.gi.trace(start, null, null, end, self, + Defines.MASK_SHOT); + if (tr.ent != self.enemy) + return true; + + if (self.s.frame == FRAME_drain03) { + damage = 5; + GameBase.gi.sound(self.enemy, Defines.CHAN_AUTO, sound_impact, + 1, Defines.ATTN_NORM, 0); + } else { + if (self.s.frame == FRAME_drain04) + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_suck, 1, + Defines.ATTN_NORM, 0); + damage = 2; + } + + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_PARASITE_ATTACK); + //gi.WriteShort(self - g_edicts); + GameBase.gi.WriteShort(self.index); + GameBase.gi.WritePosition(start); + GameBase.gi.WritePosition(end); + GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); + + Math3D.VectorSubtract(start, end, dir); + GameUtil.T_Damage(self.enemy, self, self, dir, self.enemy.s.origin, + Globals.vec3_origin, damage, 0, + Defines.DAMAGE_NO_KNOCKBACK, Defines.MOD_UNKNOWN); + return true; + } + }; + + static mframe_t parasite_frames_drain[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, parasite_launch), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 15, parasite_drain_attack), + // Target hits) + new mframe_t(GameAI.ai_charge, 0, parasite_drain_attack), // drain) + new mframe_t(GameAI.ai_charge, 0, parasite_drain_attack), // drain) + new mframe_t(GameAI.ai_charge, 0, parasite_drain_attack), // drain) + new mframe_t(GameAI.ai_charge, 0, parasite_drain_attack), // drain) + new mframe_t(GameAI.ai_charge, -2, parasite_drain_attack), // drain) + new mframe_t(GameAI.ai_charge, -2, parasite_drain_attack), // drain) + new mframe_t(GameAI.ai_charge, -3, parasite_drain_attack), // drain) + new mframe_t(GameAI.ai_charge, -2, parasite_drain_attack), // drain) + new mframe_t(GameAI.ai_charge, 0, parasite_drain_attack), // drain) + new mframe_t(GameAI.ai_charge, -1, parasite_drain_attack), // drain) + new mframe_t(GameAI.ai_charge, 0, parasite_reel_in), // let go) + new mframe_t(GameAI.ai_charge, -2, null), + new mframe_t(GameAI.ai_charge, -2, null), + new mframe_t(GameAI.ai_charge, -3, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -3, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 2, null), + new mframe_t(GameAI.ai_charge, -3, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 3, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -18, null), + new mframe_t(GameAI.ai_charge, 3, null), + new mframe_t(GameAI.ai_charge, 9, null), + new mframe_t(GameAI.ai_charge, 6, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -18, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 8, null), + new mframe_t(GameAI.ai_charge, 9, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -18, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + /* airborne */ + new mframe_t(GameAI.ai_charge, 0, null), /* slides */ + new mframe_t(GameAI.ai_charge, 0, null), /* slides */ + new mframe_t(GameAI.ai_charge, 0, null), /* slides */ + new mframe_t(GameAI.ai_charge, 0, null), /* slides */ + new mframe_t(GameAI.ai_charge, 4, null), + new mframe_t(GameAI.ai_charge, 11, null), + new mframe_t(GameAI.ai_charge, -2, null), + new mframe_t(GameAI.ai_charge, -5, null), + new mframe_t(GameAI.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 = ¶site_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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t parasite_frames_death[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 2; n++) + GameAI.ThrowGib(self, "models/objects/gibs/bone/tris.md2", + damage, Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_die, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return true; + } + + sound_pain1 = GameBase.gi.soundindex("parasite/parpain1.wav"); + sound_pain2 = GameBase.gi.soundindex("parasite/parpain2.wav"); + sound_die = GameBase.gi.soundindex("parasite/pardeth1.wav"); + sound_launch = GameBase.gi.soundindex("parasite/paratck1.wav"); + sound_impact = GameBase.gi.soundindex("parasite/paratck2.wav"); + sound_suck = GameBase.gi.soundindex("parasite/paratck3.wav"); + sound_reelin = GameBase.gi.soundindex("parasite/paratck4.wav"); + sound_sight = GameBase.gi.soundindex("parasite/parsght1.wav"); + sound_tap = GameBase.gi.soundindex("parasite/paridle1.wav"); + sound_scratch = GameBase.gi.soundindex("parasite/paridle2.wav"); + sound_search = GameBase.gi.soundindex("parasite/parsrch1.wav"); + + self.s.modelindex = GameBase.gi + .modelindex("models/monsters/parasite/tris.md2"); + Math3D.VectorSet(self.mins, -16, -16, -24); + Math3D.VectorSet(self.maxs, 16, 16, 24); + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = parasite_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + + return true; + } + }; + + 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; + } +} \ No newline at end of file diff --git a/src/jake2/game/M_Player.java b/src/jake2/game/M_Player.java index a9f8088..bdbdf3b 100644 --- a/src/jake2/game/M_Player.java +++ b/src/jake2/game/M_Player.java @@ -1,230 +1,426 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 11.11.2003 by RST. +// $Id: M_Player.java,v 1.2 2004-09-22 19:22:03 salomo Exp $ +package jake2.game; -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. +public class M_Player { + // This file generated by qdata - Do NOT Modify -See the GNU General Public License for more details. + public final static int FRAME_stand01 = 0; -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. + public final static int FRAME_stand02 = 1; -*/ + public final static int FRAME_stand03 = 2; -// Created on 11.11.2003 by RST. -// $Id: M_Player.java,v 1.1 2004-07-07 19:59:18 hzi Exp $ + public final static int FRAME_stand04 = 3; -package jake2.game; + 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; -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; - -} +} \ No newline at end of file diff --git a/src/jake2/game/M_Rider.java b/src/jake2/game/M_Rider.java deleted file mode 100644 index 42966e8..0000000 --- a/src/jake2/game/M_Rider.java +++ /dev/null @@ -1,29 +0,0 @@ -/* -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 index 6cdf19c..238df0f 100644 --- a/src/jake2/game/M_Soldier.java +++ b/src/jake2/game/M_Soldier.java @@ -1,1159 +1,2224 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Soldier.java,v 1.3 2004-09-22 19:22:04 salomo Exp $ +package jake2.game; + +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; + +public class M_Soldier { + + // 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; -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. + public final static int FRAME_death336 = 378; -See the GNU General Public License for more details. + public final static int FRAME_death337 = 379; -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. + public final static int FRAME_death338 = 380; -*/ + public final static int FRAME_death339 = 381; -// Created on 13.11.2003 by RST. -// $Id: M_Soldier.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_death340 = 382; -package jake2.game; + public final static int FRAME_death341 = 383; -import jake2.Defines; -import jake2.util.*; -import jake2.util.*; - -public class M_Soldier extends M_Player { - - // 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; - - // STAND - static mframe_t soldier_frames_stand1[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_stand, 0, M_SoldierAdapters.soldier_idle), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null)}; - static mmove_t soldier_move_stand1 = new mmove_t(FRAME_stand101, FRAME_stand130, soldier_frames_stand1, M_SoldierAdapters.soldier_stand); - - static mframe_t soldier_frames_stand3[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, M_SoldierAdapters.soldier_cock), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null)}; - - static mmove_t soldier_move_stand3 = new mmove_t(FRAME_stand301, FRAME_stand339, soldier_frames_stand3, M_SoldierAdapters.soldier_stand); - - - static mframe_t soldier_frames_walk1[] = - - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 1, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, -1, M_SoldierAdapters.soldier_walk1_random), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 9, null), - new mframe_t(GameAIAdapters.ai_walk, 8, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 1, null), - new mframe_t(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null)}; - static mmove_t soldier_move_walk2 = new mmove_t(FRAME_walk209, FRAME_walk218, soldier_frames_walk2, null); - - // - // RUN - // - - static mframe_t soldier_frames_start_run[] = new mframe_t[] { new mframe_t(GameAIAdapters.ai_run, 7, null), new mframe_t(GameAIAdapters.ai_run, 5, null)}; - static mmove_t soldier_move_start_run = new mmove_t(FRAME_run01, FRAME_run02, soldier_frames_start_run, M_SoldierAdapters.soldier_run); - - static mframe_t soldier_frames_run[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.ai_run, 11, null), - new mframe_t(GameAIAdapters.ai_run, 11, null), - new mframe_t(GameAIAdapters.ai_run, 16, null), - new mframe_t(GameAIAdapters.ai_run, 10, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null)}; - static mmove_t soldier_move_pain1 = new mmove_t(FRAME_pain101, FRAME_pain105, soldier_frames_pain1, M_SoldierAdapters.soldier_run); - - static mframe_t soldier_frames_pain2[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, -13, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 2, null)}; - static mmove_t soldier_move_pain2 = new mmove_t(FRAME_pain201, FRAME_pain207, soldier_frames_pain2, M_SoldierAdapters.soldier_run); - - static mframe_t soldier_frames_pain3[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, -8, null), - new mframe_t(GameAIAdapters.ai_move, 10, null), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 2, null)}; - static mmove_t soldier_move_pain3 = new mmove_t(FRAME_pain301, FRAME_pain318, soldier_frames_pain3, M_SoldierAdapters.soldier_run); - - static mframe_t soldier_frames_pain4[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -10, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, 8, null), - new mframe_t(GameAIAdapters.ai_move, 4, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 5, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null)}; - static mmove_t soldier_move_pain4 = new mmove_t(FRAME_pain401, FRAME_pain417, soldier_frames_pain4, M_SoldierAdapters.soldier_run); - - // - // 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; - } - } - - static mframe_t soldier_frames_attack1[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_fire1), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_attack1_refire1), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_cock), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_attack1_refire2), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null)}; - static mmove_t soldier_move_attack1 = new mmove_t(FRAME_attak101, FRAME_attak112, soldier_frames_attack1, M_SoldierAdapters.soldier_run); - - static mframe_t soldier_frames_attack2[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_fire2), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_attack2_refire1), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_cock), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_attack2_refire2), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null)}; - static mmove_t soldier_move_attack2 = new mmove_t(FRAME_attak201, FRAME_attak218, soldier_frames_attack2, M_SoldierAdapters.soldier_run); - - static mframe_t soldier_frames_attack3[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_fire3), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_attack3_refire), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_duck_up), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null)}; - static mmove_t soldier_move_attack3 = new mmove_t(FRAME_attak301, FRAME_attak309, soldier_frames_attack3, M_SoldierAdapters.soldier_run); - - static mframe_t soldier_frames_attack4[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, M_SoldierAdapters.soldier_fire4), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null)}; - static mmove_t soldier_move_attack4 = new mmove_t(FRAME_attak401, FRAME_attak406, soldier_frames_attack4, M_SoldierAdapters.soldier_run); - - - - static mframe_t soldier_frames_attack6[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_charge, 10, null), - new mframe_t(GameAIAdapters.ai_charge, 4, null), - new mframe_t(GameAIAdapters.ai_charge, 12, null), - new mframe_t(GameAIAdapters.ai_charge, 11, M_SoldierAdapters.soldier_fire8), - new mframe_t(GameAIAdapters.ai_charge, 13, null), - new mframe_t(GameAIAdapters.ai_charge, 18, null), - new mframe_t(GameAIAdapters.ai_charge, 15, null), - new mframe_t(GameAIAdapters.ai_charge, 14, null), - new mframe_t(GameAIAdapters.ai_charge, 11, null), - new mframe_t(GameAIAdapters.ai_charge, 8, null), - new mframe_t(GameAIAdapters.ai_charge, 11, null), - new mframe_t(GameAIAdapters.ai_charge, 12, null), - new mframe_t(GameAIAdapters.ai_charge, 12, null), - new mframe_t(GameAIAdapters.ai_charge, 17, M_SoldierAdapters.soldier_attack6_refire)}; - static mmove_t soldier_move_attack6 = new mmove_t(FRAME_runs01, FRAME_runs14, soldier_frames_attack6, M_SoldierAdapters.soldier_run); - - static mframe_t soldier_frames_duck[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, 5, M_SoldierAdapters.soldier_duck_down), - new mframe_t(GameAIAdapters.ai_move, -1, M_SoldierAdapters.soldier_duck_hold), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 0, M_SoldierAdapters.soldier_duck_up), - new mframe_t(GameAIAdapters.ai_move, 5, null)}; - static mmove_t soldier_move_duck = new mmove_t(FRAME_duck01, FRAME_duck05, soldier_frames_duck, M_SoldierAdapters.soldier_run); - - static mframe_t soldier_frames_death1[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -10, null), - new mframe_t(GameAIAdapters.ai_move, -10, null), - new mframe_t(GameAIAdapters.ai_move, -10, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, M_SoldierAdapters.soldier_fire6), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, M_SoldierAdapters.soldier_fire7), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null)}; - static mmove_t soldier_move_death1 = new mmove_t(FRAME_death101, FRAME_death136, soldier_frames_death1, M_SoldierAdapters.soldier_dead); - - static mframe_t soldier_frames_death2[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null)}; - static mmove_t soldier_move_death2 = new mmove_t(FRAME_death201, FRAME_death235, soldier_frames_death2, M_SoldierAdapters.soldier_dead); - - static mframe_t soldier_frames_death3[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - }; - static mmove_t soldier_move_death3 = new mmove_t(FRAME_death301, FRAME_death345, soldier_frames_death3, M_SoldierAdapters.soldier_dead); - - static mframe_t soldier_frames_death4[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null)}; - static mmove_t soldier_move_death4 = new mmove_t(FRAME_death401, FRAME_death453, soldier_frames_death4, M_SoldierAdapters.soldier_dead); - - static mframe_t soldier_frames_death5[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null)}; - static mmove_t soldier_move_death5 = new mmove_t(FRAME_death501, FRAME_death524, soldier_frames_death5, M_SoldierAdapters.soldier_dead); - - static mframe_t soldier_frames_death6[] = - new mframe_t[] { - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null)}; - static mmove_t soldier_move_death6 = new mmove_t(FRAME_death601, FRAME_death610, soldier_frames_death6, M_SoldierAdapters.soldier_dead); - -} + 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_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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.gi.linkentity(self); + return true; + } + }; + + 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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 3; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + GameAI.ThrowGib(self, "models/objects/gibs/chest/tris.md2", + damage, Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", + damage, Defines.GIB_ORGANIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.DAMAGE_YES; + self.s.skinnum |= 1; + + if (self.s.skinnum == 1) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death_light, + 1, Defines.ATTN_NORM, 0); + else if (self.s.skinnum == 3) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death, 1, + Defines.ATTN_NORM, 0); + else + // (self.s.skinnum == 5) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death_ss, 1, + Defines.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; + } + }; + + 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 (((GameBase.skill.value == 3) && (Lib.random() < 0.5)) + || (GameUtil.range(self, self.enemy) == Defines.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 (((GameBase.skill.value == 3) && (Lib.random() < 0.5)) + || (GameUtil.range(self, self.enemy) == Defines.RANGE_MELEE)) + self.monsterinfo.nextframe = FRAME_attak102; + 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 (((GameBase.skill.value == 3) && (Lib.random() < 0.5)) + || (GameUtil.range(self, self.enemy) == Defines.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 (((GameBase.skill.value == 3) && (Lib.random() < 0.5)) + || (GameUtil.range(self, self.enemy) == Defines.RANGE_MELEE)) + self.monsterinfo.nextframe = FRAME_attak204; + return true; + } + }; + + static EntThinkAdapter soldier_attack3_refire = new EntThinkAdapter() { + public boolean think(edict_t self) { + if ((GameBase.level.time + 0.4) < self.monsterinfo.pausetime) + self.monsterinfo.nextframe = FRAME_attak303; + return true; + } + }; + + static EntThinkAdapter soldier_attack6_refire = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (self.enemy.health <= 0) + return true; + + if (GameUtil.range(self, self.enemy) < Defines.RANGE_MID) + return true; + + if (GameBase.skill.value == 3) + self.monsterinfo.nextframe = FRAME_runs03; + return true; + } + }; + + // ATTACK6 (run & shoot) + static EntThinkAdapter soldier_fire8 = new EntThinkAdapter() { + public boolean think(edict_t self) { + soldier_fire(self, 7); + return true; + } + }; + + // ATTACK1 (blaster/shotgun) + + static EntThinkAdapter soldier_fire1 = new EntThinkAdapter() { + public boolean think(edict_t self) { + soldier_fire(self, 0); + return true; + } + }; + + // ATTACK2 (blaster/shotgun) + + static EntThinkAdapter soldier_fire2 = new EntThinkAdapter() { + public boolean think(edict_t self) { + soldier_fire(self, 1); + return true; + } + }; + + static EntThinkAdapter soldier_duck_down = new EntThinkAdapter() { + public boolean think(edict_t self) { + if ((self.monsterinfo.aiflags & Defines.AI_DUCKED) != 0) + return true; + self.monsterinfo.aiflags |= Defines.AI_DUCKED; + self.maxs[2] -= 32; + self.takedamage = Defines.DAMAGE_YES; + self.monsterinfo.pausetime = GameBase.level.time + 1; + GameBase.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; + } + }; + + // 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; + } + }; + + // + // 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_idle = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (Lib.random() > 0.8) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle, 1, + Defines.ATTN_IDLE, 0); + 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; + } + }; + + static EntThinkAdapter soldier_run = new EntThinkAdapter() { + public boolean think(edict_t self) { + if ((self.monsterinfo.aiflags & Defines.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; + int a = 2; + } else { + self.monsterinfo.currentmove = soldier_move_start_run; + } + return true; + } + }; + + 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 (GameBase.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 = GameBase.level.time + 3; + + n = self.s.skinnum | 1; + if (n == 1) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain_light, + 1, Defines.ATTN_NORM, 0); + else if (n == 3) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain_ss, 1, + Defines.ATTN_NORM, 0); + + if (self.velocity[2] > 100) { + self.monsterinfo.currentmove = soldier_move_pain4; + return; + } + + if (GameBase.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; + } + }; + + // + // SIGHT + // + + static EntThinkAdapter soldier_duck_up = new EntThinkAdapter() { + public boolean think(edict_t self) { + self.monsterinfo.aiflags &= ~Defines.AI_DUCKED; + self.maxs[2] += 32; + self.takedamage = Defines.DAMAGE_AIM; + GameBase.gi.linkentity(self); + return true; + } + }; + + static EntInteractAdapter soldier_sight = new EntInteractAdapter() { + public boolean interact(edict_t self, edict_t other) { + if (Lib.random() < 0.5) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight1, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight2, 1, + Defines.ATTN_NORM, 0); + + if ((GameBase.skill.value > 0) + && (GameUtil.range(self, self.enemy) >= Defines.RANGE_MID)) { + if (Lib.random() > 0.5) + self.monsterinfo.currentmove = soldier_move_attack6; + } + return true; + } + }; + + // + // SPAWN + // + + static EntThinkAdapter SP_monster_soldier_x = new EntThinkAdapter() { + public boolean think(edict_t self) { + + self.s.modelindex = GameBase.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 = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + + sound_idle = GameBase.gi.soundindex("soldier/solidle1.wav"); + sound_sight1 = GameBase.gi.soundindex("soldier/solsght1.wav"); + sound_sight2 = GameBase.gi.soundindex("soldier/solsrch1.wav"); + sound_cock = GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.stand.think(self); + + GameAI.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return true; + } + + SP_monster_soldier_x.think(self); + + sound_pain_light = GameBase.gi.soundindex("soldier/solpain2.wav"); + sound_death_light = GameBase.gi.soundindex("soldier/soldeth2.wav"); + GameBase.gi.modelindex("models/objects/laser/tris.md2"); + GameBase.gi.soundindex("misc/lasfly.wav"); + GameBase.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return true; + } + + SP_monster_soldier_x.think(self); + + sound_pain = GameBase.gi.soundindex("soldier/solpain1.wav"); + sound_death = GameBase.gi.soundindex("soldier/soldeth1.wav"); + GameBase.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return true; + } + + SP_monster_soldier_x.think(self); + + sound_pain_ss = GameBase.gi.soundindex("soldier/solpain3.wav"); + sound_death_ss = GameBase.gi.soundindex("soldier/soldeth3.wav"); + GameBase.gi.soundindex("soldier/solatck3.wav"); + + self.s.skinnum = 4; + self.health = 40; + self.gib_health = -30; + return true; + } + }; + + 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, + M_Flash.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, + Defines.EF_BLASTER); + } else if (self.s.skinnum <= 3) { + Monster.monster_fire_shotgun(self, start, aim, 2, 1, + Defines.DEFAULT_SHOTGUN_HSPREAD, + Defines.DEFAULT_SHOTGUN_VSPREAD, + Defines.DEFAULT_SHOTGUN_COUNT, flash_index); + } else { + if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME)) + self.monsterinfo.pausetime = GameBase.level.time + + (3 + Lib.rand() % 8) * Defines.FRAMETIME; + + Monster.monster_fire_bullet(self, start, aim, 2, 4, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.DEFAULT_BULLET_VSPREAD, flash_index); + + if (GameBase.level.time >= self.monsterinfo.pausetime) + self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; + else + self.monsterinfo.aiflags |= Defines.AI_HOLD_FRAME; + } + } + + static EntThinkAdapter soldier_cock = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (self.s.frame == FRAME_stand322) + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_cock, 1, + Defines.ATTN_IDLE, 0); + else + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_cock, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + // STAND + static mframe_t soldier_frames_stand1[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, soldier_idle), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, soldier_cock), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 1, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, -1, soldier_walk1_random), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 9, null), + new mframe_t(GameAI.ai_walk, 8, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 1, null), + new mframe_t(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 7, null) }; + + static mmove_t soldier_move_walk2 = new mmove_t(FRAME_walk209, + FRAME_walk218, soldier_frames_walk2, null); + + // + // RUN + // + + static mframe_t soldier_frames_start_run[] = new mframe_t[] { + new mframe_t(GameAI.ai_run, 7, null), + new mframe_t(GameAI.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(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 11, null), + new mframe_t(GameAI.ai_run, 11, null), + new mframe_t(GameAI.ai_run, 16, null), + new mframe_t(GameAI.ai_run, 10, null), + new mframe_t(GameAI.ai_run, 15, null) }; + + static mmove_t soldier_move_run = new mmove_t(FRAME_run03, FRAME_run08, + soldier_frames_run, null); + + // + // DUCK + // + + static EntThinkAdapter soldier_duck_hold = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (GameBase.level.time >= self.monsterinfo.pausetime) + self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; + else + self.monsterinfo.aiflags |= Defines.AI_HOLD_FRAME; + return true; + } + }; + + // + // PAIN + // + + static mframe_t soldier_frames_pain1[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.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(GameAI.ai_move, -13, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.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(GameAI.ai_move, -8, null), + new mframe_t(GameAI.ai_move, 10, null), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -10, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, 8, null), + new mframe_t(GameAI.ai_move, 4, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 5, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null) }; + + static mmove_t soldier_move_pain4 = new mmove_t(FRAME_pain401, + FRAME_pain417, soldier_frames_pain4, soldier_run); + + // + // ATTACK + // + + static int blaster_flash[] = { Defines.MZ2_SOLDIER_BLASTER_1, + Defines.MZ2_SOLDIER_BLASTER_2, Defines.MZ2_SOLDIER_BLASTER_3, + Defines.MZ2_SOLDIER_BLASTER_4, Defines.MZ2_SOLDIER_BLASTER_5, + Defines.MZ2_SOLDIER_BLASTER_6, Defines.MZ2_SOLDIER_BLASTER_7, + Defines.MZ2_SOLDIER_BLASTER_8 }; + + static int shotgun_flash[] = { Defines.MZ2_SOLDIER_SHOTGUN_1, + Defines.MZ2_SOLDIER_SHOTGUN_2, Defines.MZ2_SOLDIER_SHOTGUN_3, + Defines.MZ2_SOLDIER_SHOTGUN_4, Defines.MZ2_SOLDIER_SHOTGUN_5, + Defines.MZ2_SOLDIER_SHOTGUN_6, Defines.MZ2_SOLDIER_SHOTGUN_7, + Defines.MZ2_SOLDIER_SHOTGUN_8 }; + + static int machinegun_flash[] = { Defines.MZ2_SOLDIER_MACHINEGUN_1, + Defines.MZ2_SOLDIER_MACHINEGUN_2, Defines.MZ2_SOLDIER_MACHINEGUN_3, + Defines.MZ2_SOLDIER_MACHINEGUN_4, Defines.MZ2_SOLDIER_MACHINEGUN_5, + Defines.MZ2_SOLDIER_MACHINEGUN_6, Defines.MZ2_SOLDIER_MACHINEGUN_7, + Defines.MZ2_SOLDIER_MACHINEGUN_8 }; + + static mframe_t soldier_frames_attack1[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, soldier_fire1), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, soldier_attack1_refire1), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, soldier_cock), + new mframe_t(GameAI.ai_charge, 0, soldier_attack1_refire2), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null) }; + + static mmove_t soldier_move_attack1 = new mmove_t(FRAME_attak101, + FRAME_attak112, soldier_frames_attack1, soldier_run); + + static mframe_t soldier_frames_attack2[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, soldier_fire2), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, soldier_attack2_refire1), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, soldier_cock), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, soldier_attack2_refire2), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null) }; + + static mmove_t soldier_move_attack2 = new mmove_t(FRAME_attak201, + FRAME_attak218, soldier_frames_attack2, soldier_run); + + static mframe_t soldier_frames_attack3[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, soldier_fire3), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, soldier_attack3_refire), + new mframe_t(GameAI.ai_charge, 0, soldier_duck_up), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null) }; + + static mmove_t soldier_move_attack3 = new mmove_t(FRAME_attak301, + FRAME_attak309, soldier_frames_attack3, soldier_run); + + static mframe_t soldier_frames_attack4[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, soldier_fire4), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null) }; + + static mmove_t soldier_move_attack4 = new mmove_t(FRAME_attak401, + FRAME_attak406, soldier_frames_attack4, soldier_run); + + static mframe_t soldier_frames_attack6[] = new mframe_t[] { + new mframe_t(GameAI.ai_charge, 10, null), + new mframe_t(GameAI.ai_charge, 4, null), + new mframe_t(GameAI.ai_charge, 12, null), + new mframe_t(GameAI.ai_charge, 11, soldier_fire8), + new mframe_t(GameAI.ai_charge, 13, null), + new mframe_t(GameAI.ai_charge, 18, null), + new mframe_t(GameAI.ai_charge, 15, null), + new mframe_t(GameAI.ai_charge, 14, null), + new mframe_t(GameAI.ai_charge, 11, null), + new mframe_t(GameAI.ai_charge, 8, null), + new mframe_t(GameAI.ai_charge, 11, null), + new mframe_t(GameAI.ai_charge, 12, null), + new mframe_t(GameAI.ai_charge, 12, null), + new mframe_t(GameAI.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 mframe_t soldier_frames_duck[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 5, soldier_duck_down), + new mframe_t(GameAI.ai_move, -1, soldier_duck_hold), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 0, soldier_duck_up), + new mframe_t(GameAI.ai_move, 5, null) }; + + static mmove_t soldier_move_duck = new mmove_t(FRAME_duck01, FRAME_duck05, + soldier_frames_duck, soldier_run); + + static mframe_t soldier_frames_death1[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -10, null), + new mframe_t(GameAI.ai_move, -10, null), + new mframe_t(GameAI.ai_move, -10, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, soldier_fire6), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, soldier_fire7), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null) }; + + static mmove_t soldier_move_death6 = new mmove_t(FRAME_death601, + FRAME_death610, soldier_frames_death6, soldier_dead); + + // ATTACK3 (duck and shoot) + + 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; + } + }; + + 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 (GameBase.skill.value == 0) { + self.monsterinfo.currentmove = soldier_move_duck; + return; + } + + self.monsterinfo.pausetime = GameBase.level.time + eta + 0.3f; + r = Lib.random(); + + if (GameBase.skill.value == 1) { + if (r > 0.33) + self.monsterinfo.currentmove = soldier_move_duck; + else + self.monsterinfo.currentmove = soldier_move_attack3; + return; + } + + if (GameBase.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; + } + }; + +} \ No newline at end of file diff --git a/src/jake2/game/M_SoldierAdapters.java b/src/jake2/game/M_SoldierAdapters.java deleted file mode 100644 index 31c89ff..0000000 --- a/src/jake2/game/M_SoldierAdapters.java +++ /dev/null @@ -1,655 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: M_SoldierAdapters.java,v 1.2 2004-09-10 19:02:54 salomo Exp $ - -package jake2.game; - -import jake2.Defines; -import jake2.qcommon.Com; -import jake2.util.*; - -public class M_SoldierAdapters -{ - - static EntThinkAdapter soldier_cock = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if (self.s.frame == M_Soldier.FRAME_stand322) - GameBase.gi.sound(self, Defines.CHAN_WEAPON, M_Soldier.sound_cock, 1, Defines.ATTN_IDLE, 0); - else - GameBase.gi.sound(self, Defines.CHAN_WEAPON, M_Soldier.sound_cock, 1, Defines.ATTN_NORM, 0); - return true; - } - }; - // ATTACK3 (duck and shoot) - - static EntThinkAdapter soldier_duck_down = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if ((self.monsterinfo.aiflags & Defines.AI_DUCKED) != 0) - return true; - self.monsterinfo.aiflags |= Defines.AI_DUCKED; - self.maxs[2] -= 32; - self.takedamage = Defines.DAMAGE_YES; - self.monsterinfo.pausetime = GameBase.level.time + 1; - GameBase.gi.linkentity(self); - return true; - } - }; - static EntThinkAdapter soldier_duck_up = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - self.monsterinfo.aiflags &= ~Defines.AI_DUCKED; - self.maxs[2] += 32; - self.takedamage = Defines.DAMAGE_AIM; - GameBase.gi.linkentity(self); - return true; - } - }; - 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 = M_Soldier.soldier_move_attack1; - else - self.monsterinfo.currentmove = M_Soldier.soldier_move_attack2; - } - else - { - self.monsterinfo.currentmove = M_Soldier.soldier_move_attack4; - } - return true; - } - }; - // - // DUCK - // - - static EntThinkAdapter soldier_duck_hold = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if (GameBase.level.time >= self.monsterinfo.pausetime) - self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME; - else - self.monsterinfo.aiflags |= Defines.AI_HOLD_FRAME; - return true; - } - }; - 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 (GameBase.skill.value == 0) - { - self.monsterinfo.currentmove = M_Soldier.soldier_move_duck; - return; - } - - self.monsterinfo.pausetime = GameBase.level.time + eta + 0.3f; - r = Lib.random(); - - if (GameBase.skill.value == 1) - { - if (r > 0.33) - self.monsterinfo.currentmove = M_Soldier.soldier_move_duck; - else - self.monsterinfo.currentmove = M_Soldier.soldier_move_attack3; - return; - } - - if (GameBase.skill.value >= 2) - { - if (r > 0.66) - self.monsterinfo.currentmove = M_Soldier.soldier_move_duck; - else - self.monsterinfo.currentmove = M_Soldier.soldier_move_attack3; - return; - } - - self.monsterinfo.currentmove = M_Soldier.soldier_move_attack3; - } - }; - 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 = Defines.MOVETYPE_TOSS; - self.svflags |= Defines.SVF_DEADMONSTER; - self.nextthink = 0; - GameBase.gi.linkentity(self); - return true; - } - }; - 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) - { - GameBase.gi.sound(self, Defines.CHAN_VOICE, GameBase.gi.soundindex("misc/udeath.wav"), 1, Defines.ATTN_NORM, 0); - for (n = 0; n < 3; n++) - GameAI.ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, Defines.GIB_ORGANIC); - GameAI.ThrowGib(self, "models/objects/gibs/chest/tris.md2", damage, Defines.GIB_ORGANIC); - GameAI.ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, Defines.GIB_ORGANIC); - self.deadflag = Defines.DEAD_DEAD; - return; - } - - if (self.deadflag == Defines.DEAD_DEAD) - return; - - // regular death - self.deadflag = Defines.DEAD_DEAD; - self.takedamage = Defines.DAMAGE_YES; - self.s.skinnum |= 1; - - if (self.s.skinnum == 1) - GameBase.gi.sound(self, Defines.CHAN_VOICE, M_Soldier.sound_death_light, 1, Defines.ATTN_NORM, 0); - else if (self.s.skinnum == 3) - GameBase.gi.sound(self, Defines.CHAN_VOICE, M_Soldier.sound_death, 1, Defines.ATTN_NORM, 0); - else // (self.s.skinnum == 5) - GameBase.gi.sound(self, Defines.CHAN_VOICE, M_Soldier.sound_death_ss, 1, Defines.ATTN_NORM, 0); - - if (Math.abs((self.s.origin[2] + self.viewheight) - point[2]) <= 4) - { - // head shot - self.monsterinfo.currentmove = M_Soldier.soldier_move_death3; - return; - } - - n = Lib.rand() % 5; - if (n == 0) - self.monsterinfo.currentmove = M_Soldier.soldier_move_death1; - else if (n == 1) - self.monsterinfo.currentmove = M_Soldier.soldier_move_death2; - else if (n == 2) - self.monsterinfo.currentmove = M_Soldier.soldier_move_death4; - else if (n == 3) - self.monsterinfo.currentmove = M_Soldier.soldier_move_death5; - else - self.monsterinfo.currentmove = M_Soldier.soldier_move_death6; - } - }; - - 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 (((GameBase.skill.value == 3) && (Lib.random() < 0.5)) || (GameUtil.range(self, self.enemy) == Defines.RANGE_MELEE)) - self.monsterinfo.nextframe = M_Soldier.FRAME_attak102; - else - self.monsterinfo.nextframe = M_Soldier.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 (((GameBase.skill.value == 3) && (Lib.random() < 0.5)) || (GameUtil.range(self, self.enemy) == Defines.RANGE_MELEE)) - self.monsterinfo.nextframe = M_Soldier.FRAME_attak102; - 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 (((GameBase.skill.value == 3) && (Lib.random() < 0.5)) || (GameUtil.range(self, self.enemy) == Defines.RANGE_MELEE)) - self.monsterinfo.nextframe = M_Soldier.FRAME_attak204; - else - self.monsterinfo.nextframe = M_Soldier.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 (((GameBase.skill.value == 3) && (Lib.random() < 0.5)) || (GameUtil.range(self, self.enemy) == Defines.RANGE_MELEE)) - self.monsterinfo.nextframe = M_Soldier.FRAME_attak204; - return true; - } - }; - - static EntThinkAdapter soldier_attack3_refire = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if ((GameBase.level.time + 0.4) < self.monsterinfo.pausetime) - self.monsterinfo.nextframe = M_Soldier.FRAME_attak303; - return true; - } - }; - - static EntThinkAdapter soldier_attack6_refire = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if (self.enemy.health <= 0) - return true; - - if (GameUtil.range(self, self.enemy) < Defines.RANGE_MID) - return true; - - if (GameBase.skill.value == 3) - self.monsterinfo.nextframe = M_Soldier.FRAME_runs03; - return true; - } - }; - - // ATTACK6 (run & shoot) - static EntThinkAdapter soldier_fire8 = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - M_Soldier.soldier_fire(self, 7); - return true; - } - }; - - // ATTACK1 (blaster/shotgun) - - static EntThinkAdapter soldier_fire1 = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - M_Soldier.soldier_fire(self, 0); - return true; - } - }; - - // ATTACK2 (blaster/shotgun) - - static EntThinkAdapter soldier_fire2 = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - M_Soldier.soldier_fire(self, 1); - return true; - } - }; - - static EntThinkAdapter soldier_fire3 = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - M_SoldierAdapters.soldier_duck_down.think(self); - M_Soldier.soldier_fire(self, 2); - return true; - } - }; - - // ATTACK4 (machinegun) - - static EntThinkAdapter soldier_fire4 = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - M_Soldier.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; - } - }; - - // - // DEATH - // - - static EntThinkAdapter soldier_fire6 = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - M_Soldier.soldier_fire(self, 5); - return true; - } - }; - - static EntThinkAdapter soldier_fire7 = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - M_Soldier.soldier_fire(self, 6); - return true; - } - }; - - static EntThinkAdapter soldier_idle = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if (Lib.random() > 0.8) - GameBase.gi.sound(self, Defines.CHAN_VOICE, M_Soldier.sound_idle, 1, Defines.ATTN_IDLE, 0); - return true; - } - }; - - static EntThinkAdapter soldier_stand = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if ((self.monsterinfo.currentmove == M_Soldier.soldier_move_stand3) || (Lib.random() < 0.8)) - self.monsterinfo.currentmove = M_Soldier.soldier_move_stand1; - else - self.monsterinfo.currentmove = M_Soldier.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 = M_Soldier.FRAME_walk101; - return true; - } - }; - - static EntThinkAdapter soldier_walk = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if (Lib.random() < 0.5) - self.monsterinfo.currentmove = M_Soldier.soldier_move_walk1; - else - self.monsterinfo.currentmove = M_Soldier.soldier_move_walk2; - return true; - } - }; - - static EntThinkAdapter soldier_run = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - if ((self.monsterinfo.aiflags & Defines.AI_STAND_GROUND) != 0) - { - self.monsterinfo.currentmove = M_Soldier.soldier_move_stand1; - return true; - } - - if (self.monsterinfo.currentmove == M_Soldier.soldier_move_walk1 - || self.monsterinfo.currentmove == M_Soldier.soldier_move_walk2 - || self.monsterinfo.currentmove == M_Soldier.soldier_move_start_run) - { - self.monsterinfo.currentmove = M_Soldier.soldier_move_run; - int a = 2; - } - else - { - self.monsterinfo.currentmove = M_Soldier.soldier_move_start_run; - } - return true; - } - }; - - 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 (GameBase.level.time < self.pain_debounce_time) - { - if ((self.velocity[2] > 100) - && ((self.monsterinfo.currentmove == M_Soldier.soldier_move_pain1) - || (self.monsterinfo.currentmove == M_Soldier.soldier_move_pain2) - || (self.monsterinfo.currentmove == M_Soldier.soldier_move_pain3))) - self.monsterinfo.currentmove = M_Soldier.soldier_move_pain4; - return; - } - - self.pain_debounce_time = GameBase.level.time + 3; - - n = self.s.skinnum | 1; - if (n == 1) - GameBase.gi.sound(self, Defines.CHAN_VOICE, M_Soldier.sound_pain_light, 1, Defines.ATTN_NORM, 0); - else if (n == 3) - GameBase.gi.sound(self, Defines.CHAN_VOICE, M_Soldier.sound_pain, 1, Defines.ATTN_NORM, 0); - else - GameBase.gi.sound(self, Defines.CHAN_VOICE, M_Soldier.sound_pain_ss, 1, Defines.ATTN_NORM, 0); - - if (self.velocity[2] > 100) - { - self.monsterinfo.currentmove = M_Soldier.soldier_move_pain4; - return; - } - - if (GameBase.skill.value == 3) - return; // no pain anims in nightmare - - r = Lib.random(); - - if (r < 0.33) - self.monsterinfo.currentmove = M_Soldier.soldier_move_pain1; - else if (r < 0.66) - self.monsterinfo.currentmove = M_Soldier.soldier_move_pain2; - else - self.monsterinfo.currentmove = M_Soldier.soldier_move_pain3; - } - }; - - // - // SIGHT - // - - static EntInteractAdapter soldier_sight = new EntInteractAdapter() - { - public boolean interact(edict_t self, edict_t other) - { - if (Lib.random() < 0.5) - GameBase.gi.sound(self, Defines.CHAN_VOICE, M_Soldier.sound_sight1, 1, Defines.ATTN_NORM, 0); - else - GameBase.gi.sound(self, Defines.CHAN_VOICE, M_Soldier.sound_sight2, 1, Defines.ATTN_NORM, 0); - - if ((GameBase.skill.value > 0) && (GameUtil.range(self, self.enemy) >= Defines.RANGE_MID)) - { - if (Lib.random() > 0.5) - self.monsterinfo.currentmove = M_Soldier.soldier_move_attack6; - } - return true; - } - }; - - // - // SPAWN - // - - static EntThinkAdapter SP_monster_soldier_x = new EntThinkAdapter() - { - public boolean think(edict_t self) - { - - self.s.modelindex = GameBase.gi.modelindex("models/monsters/soldier/tris.md2"); - self.monsterinfo.scale = M_Soldier.MODEL_SCALE; - Math3D.VectorSet(self.mins, -16, -16, -24); - Math3D.VectorSet(self.maxs, 16, 16, 32); - self.movetype = Defines.MOVETYPE_STEP; - self.solid = Defines.SOLID_BBOX; - - M_Soldier.sound_idle = GameBase.gi.soundindex("soldier/solidle1.wav"); - M_Soldier.sound_sight1 = GameBase.gi.soundindex("soldier/solsght1.wav"); - M_Soldier.sound_sight2 = GameBase.gi.soundindex("soldier/solsrch1.wav"); - M_Soldier.sound_cock = GameBase.gi.soundindex("infantry/infatck3.wav"); - - self.mass = 100; - - self.pain = soldier_pain; - self.die = M_SoldierAdapters.soldier_die; - - self.monsterinfo.stand = soldier_stand; - self.monsterinfo.walk = soldier_walk; - self.monsterinfo.run = soldier_run; - self.monsterinfo.dodge = M_SoldierAdapters.soldier_dodge; - self.monsterinfo.attack = M_SoldierAdapters.soldier_attack; - self.monsterinfo.melee = null; - self.monsterinfo.sight = soldier_sight; - - GameBase.gi.linkentity(self); - - self.monsterinfo.stand.think(self); - - GameAIAdapters.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 (GameBase.deathmatch.value != 0) - { - GameUtil.G_FreeEdict(self); - return true; - } - - SP_monster_soldier_x.think(self); - - M_Soldier.sound_pain_light = GameBase.gi.soundindex("soldier/solpain2.wav"); - M_Soldier.sound_death_light = GameBase.gi.soundindex("soldier/soldeth2.wav"); - GameBase.gi.modelindex("models/objects/laser/tris.md2"); - GameBase.gi.soundindex("misc/lasfly.wav"); - GameBase.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 (GameBase.deathmatch.value != 0) - { - GameUtil.G_FreeEdict(self); - return true; - } - - SP_monster_soldier_x.think(self); - - M_Soldier.sound_pain = GameBase.gi.soundindex("soldier/solpain1.wav"); - M_Soldier.sound_death = GameBase.gi.soundindex("soldier/soldeth1.wav"); - GameBase.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 (GameBase.deathmatch.value != 0) - { - GameUtil.G_FreeEdict(self); - return true; - } - - SP_monster_soldier_x.think(self); - - M_Soldier.sound_pain_ss = GameBase.gi.soundindex("soldier/solpain3.wav"); - M_Soldier.sound_death_ss = GameBase.gi.soundindex("soldier/soldeth3.wav"); - GameBase.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 index 1b8f030..1e26b56 100644 --- a/src/jake2/game/M_Supertank.java +++ b/src/jake2/game/M_Supertank.java @@ -1,964 +1,1253 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Supertank.java,v 1.3 2004-09-22 19:22:04 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Supertank { -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. + // This file generated by ModelGen - Do NOT Modify -*/ + public final static int FRAME_attak1_1 = 0; -// Created on 13.11.2003 by RST. -// $Id: M_Supertank.java,v 1.2 2004-07-08 15:58:44 hzi Exp $ + public final static int FRAME_attak1_2 = 1; -package jake2.game; + 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) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, tread_sound, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; -import jake2.util.*; -import jake2.util.*; - -public class M_Supertank extends M_Player { - - // 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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 12, TreadSound), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.ai_run, 12, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 4, TreadSound), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, TreadSound), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, TreadSound), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, GameAIAdapters.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(GameAIAdapters.ai_walk, 0, TreadSound), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, supertankRocket), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, supertankRocket), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, supertankRocket), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, supertankMachineGun), - new mframe_t(GameAIAdapters.ai_charge, 0, supertankMachineGun), - new mframe_t(GameAIAdapters.ai_charge, 0, supertankMachineGun), - new mframe_t(GameAIAdapters.ai_charge, 0, supertankMachineGun), - new mframe_t(GameAIAdapters.ai_charge, 0, supertankMachineGun), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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 = GameAIAdapters.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; - - GameAIAdapters.walkmonster_start.think(self); - return true; - } - }; - - -} + static EntThinkAdapter supertank_search = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (Lib.random() < 0.5) + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search1, 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_search2, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + // + // stand + // + + static mframe_t supertank_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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(GameAI.ai_run, 12, TreadSound), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.ai_run, 12, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 4, TreadSound), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.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 & Defines.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.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 = Defines.MZ2_SUPERTANK_ROCKET_1; + else if (self.s.frame == FRAME_attak2_11) + flash_number = Defines.MZ2_SUPERTANK_ROCKET_2; + else + // (self.s.frame == FRAME_attak2_14) + flash_number = Defines.MZ2_SUPERTANK_ROCKET_3; + + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.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 = Defines.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, + M_Flash.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, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.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(GameAI.ai_move, 0, TreadSound), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, TreadSound), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, GameAI.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(GameAI.ai_walk, 0, TreadSound), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, supertankRocket), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, supertankRocket), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, supertankRocket), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 (GameUtil.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(GameAI.ai_charge, 0, supertankMachineGun), + new mframe_t(GameAI.ai_charge, 0, supertankMachineGun), + new mframe_t(GameAI.ai_charge, 0, supertankMachineGun), + new mframe_t(GameAI.ai_charge, 0, supertankMachineGun), + new mframe_t(GameAI.ai_charge, 0, supertankMachineGun), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 (GameBase.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 (GameBase.skill.value >= 2) + if ((self.s.frame >= FRAME_attak2_1) + && (self.s.frame <= FRAME_attak2_14)) + return; + + self.pain_debounce_time = GameBase.level.time + 3; + + if (GameBase.skill.value == 3) + return; // no pain anims in nightmare + + if (damage <= 10) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain1, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = supertank_move_pain1; + } else if (damage <= 25) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain3, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = supertank_move_pain2; + } else { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain2, 1, + Defines.ATTN_NORM, 0); + self.monsterinfo.currentmove = supertank_move_pain3; + } + } + }; + + static EntDieAdapter supertank_die = new EntDieAdapter() { + public void die(edict_t self, edict_t inflictor, edict_t attacker, + int damage, float[] point) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_death, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return true; + } + + sound_pain1 = GameBase.gi.soundindex("bosstank/btkpain1.wav"); + sound_pain2 = GameBase.gi.soundindex("bosstank/btkpain2.wav"); + sound_pain3 = GameBase.gi.soundindex("bosstank/btkpain3.wav"); + sound_death = GameBase.gi.soundindex("bosstank/btkdeth1.wav"); + sound_search1 = GameBase.gi.soundindex("bosstank/btkunqv1.wav"); + sound_search2 = GameBase.gi.soundindex("bosstank/btkunqv2.wav"); + + // self.s.sound = gi.soundindex ("bosstank/btkengn1.wav"); + tread_sound = GameBase.gi.soundindex("bosstank/btkengn1.wav"); + + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + self.s.modelindex = GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = supertank_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + return true; + } + }; + + void BossExplode(edict_t self) { + float[] org = { 0, 0, 0 }; + int n; + + self.think = GameAI.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++) + GameAI.ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", + 500, Defines.GIB_ORGANIC); + for (n = 0; n < 8; n++) + GameAI.ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", + 500, Defines.GIB_METALLIC); + GameAI.ThrowGib(self, "models/objects/gibs/chest/tris.md2", 500, + Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/gear/tris.md2", 500, + Defines.GIB_METALLIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + GameBase.gi.WriteByte(Defines.svc_temp_entity); + GameBase.gi.WriteByte(Defines.TE_EXPLOSION1); + GameBase.gi.WritePosition(org); + GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS); + + self.nextthink = GameBase.level.time + 0.1f; + } + +} \ No newline at end of file diff --git a/src/jake2/game/M_Tank.java b/src/jake2/game/M_Tank.java index 26669a3..2dc1788 100644 --- a/src/jake2/game/M_Tank.java +++ b/src/jake2/game/M_Tank.java @@ -1,1143 +1,1510 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 13.11.2003 by RST. +// $Id: M_Tank.java,v 1.3 2004-09-22 19:22:02 salomo Exp $ +package jake2.game; -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. +import jake2.Defines; +import jake2.util.Lib; +import jake2.util.Math3D; -See the GNU General Public License for more details. +public class M_Tank { + // G:\quake2\baseq2\models/monsters/tank -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. + // This file generated by qdata - Do NOT Modify -*/ + public final static int FRAME_stand01 = 0; -// Created on 13.11.2003 by RST. -// $Id: M_Tank.java,v 1.2 2004-07-08 15:58:43 hzi Exp $ + public final static int FRAME_stand02 = 1; -package jake2.game; + 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 interact(edict_t self, edict_t other) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_sight, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter tank_footstep = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_step, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter tank_thud = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_BODY, sound_thud, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; -import jake2.util.*; -import jake2.util.*; - -public class M_Tank extends M_Player { - // 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 interact(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(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.ai_stand, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 0, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 4, tank_footstep), - new mframe_t(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 4, null), - new mframe_t(GameAIAdapters.ai_walk, 5, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.ai_walk, 7, null), - new mframe_t(GameAIAdapters.ai_walk, 6, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 3, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.ai_walk, 2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 0, null), - new mframe_t(GameAIAdapters.ai_run, 6, null), - new mframe_t(GameAIAdapters.ai_run, 6, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 4, null), - new mframe_t(GameAIAdapters.ai_run, 5, null), - new mframe_t(GameAIAdapters.ai_run, 3, null), - new mframe_t(GameAIAdapters.ai_run, 2, null), - new mframe_t(GameAIAdapters.ai_run, 5, null), - new mframe_t(GameAIAdapters.ai_run, 5, null), - new mframe_t(GameAIAdapters.ai_run, 4, null), - new mframe_t(GameAIAdapters.ai_run, 4, tank_footstep), - new mframe_t(GameAIAdapters.ai_run, 3, null), - new mframe_t(GameAIAdapters.ai_run, 5, null), - new mframe_t(GameAIAdapters.ai_run, 4, null), - new mframe_t(GameAIAdapters.ai_run, 5, null), - new mframe_t(GameAIAdapters.ai_run, 7, null), - new mframe_t(GameAIAdapters.ai_run, 7, null), - new mframe_t(GameAIAdapters.ai_run, 6, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_run, 3, null), - new mframe_t(GameAIAdapters.ai_run, 3, null), - new mframe_t(GameAIAdapters.ai_run, 2, null), - new mframe_t(GameAIAdapters.ai_run, 2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -7, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, -2, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, TankBlaster), - // 10 - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, TankBlaster), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, TankBlaster), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 0, null), // 17) - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 6, null), - new mframe_t(GameAIAdapters.ai_move, 7, null), - new mframe_t(GameAIAdapters.ai_move, 9, tank_footstep), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 2, tank_footstep), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 0, tank_windup), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, TankStrike), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -1, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, -10, null), - new mframe_t(GameAIAdapters.ai_move, -10, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - // 10) - - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 1, null), - new mframe_t(GameAIAdapters.ai_charge, 2, null), - new mframe_t(GameAIAdapters.ai_charge, 7, null), - new mframe_t(GameAIAdapters.ai_charge, 7, null), - new mframe_t(GameAIAdapters.ai_charge, 7, tank_footstep), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - // 20) - - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, -3, null), // Loop Start 22 ) - new mframe_t(GameAIAdapters.ai_charge, 0, null), new mframe_t(GameAIAdapters.ai_charge, 0, TankRocket), // 24) - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, TankRocket), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), // 31) - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 2, null), - new mframe_t(GameAIAdapters.ai_charge, 3, null), - new mframe_t(GameAIAdapters.ai_charge, 4, null), - new mframe_t(GameAIAdapters.ai_charge, 2, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - // 40) - - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, -9, null), - new mframe_t(GameAIAdapters.ai_charge, -8, null), - new mframe_t(GameAIAdapters.ai_charge, -7, null), - new mframe_t(GameAIAdapters.ai_charge, -1, null), - new mframe_t(GameAIAdapters.ai_charge, -1, tank_footstep), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - // 50) - - new mframe_t(GameAIAdapters.ai_charge, 0, null), new mframe_t(GameAIAdapters.ai_charge, 0, null), new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.ai_charge, 0, null), - new mframe_t(GameAIAdapters.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(GameAIAdapters.ai_move, -7, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 3, null), - new mframe_t(GameAIAdapters.ai_move, 6, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 1, null), - new mframe_t(GameAIAdapters.ai_move, 2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -2, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -3, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, -6, null), - new mframe_t(GameAIAdapters.ai_move, -4, null), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, -7, null), - new mframe_t(GameAIAdapters.ai_move, -15, tank_thud), - new mframe_t(GameAIAdapters.ai_move, -5, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.ai_move, 0, null), - new mframe_t(GameAIAdapters.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; - - GameAIAdapters.walkmonster_start.think(self); - - if (Lib.strcmp(self.classname, "monster_tank_commander") == 0) - self.s.skinnum = 2; - return true; - } - }; - -} + static EntThinkAdapter tank_windup = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_windup, 1, + Defines.ATTN_NORM, 0); + return true; + } + }; + + static EntThinkAdapter tank_idle = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_idle, 1, + Defines.ATTN_IDLE, 0); + return true; + } + }; + + // + // stand + // + + static mframe_t tank_frames_stand[] = new mframe_t[] { + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.ai_stand, 0, null), + new mframe_t(GameAI.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 |= Defines.AI_BRUTAL; + else + self.monsterinfo.aiflags &= ~Defines.AI_BRUTAL; + + if ((self.monsterinfo.aiflags & Defines.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(GameAI.ai_walk, 0, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 4, tank_footstep), + new mframe_t(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 4, null), + new mframe_t(GameAI.ai_walk, 5, null), + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.ai_walk, 7, null), + new mframe_t(GameAI.ai_walk, 6, null), + new mframe_t(GameAI.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(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 3, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.ai_walk, 2, null), + new mframe_t(GameAI.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(GameAI.ai_run, 0, null), + new mframe_t(GameAI.ai_run, 6, null), + new mframe_t(GameAI.ai_run, 6, null), + new mframe_t(GameAI.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(GameAI.ai_run, 4, null), + new mframe_t(GameAI.ai_run, 5, null), + new mframe_t(GameAI.ai_run, 3, null), + new mframe_t(GameAI.ai_run, 2, null), + new mframe_t(GameAI.ai_run, 5, null), + new mframe_t(GameAI.ai_run, 5, null), + new mframe_t(GameAI.ai_run, 4, null), + new mframe_t(GameAI.ai_run, 4, tank_footstep), + new mframe_t(GameAI.ai_run, 3, null), + new mframe_t(GameAI.ai_run, 5, null), + new mframe_t(GameAI.ai_run, 4, null), + new mframe_t(GameAI.ai_run, 5, null), + new mframe_t(GameAI.ai_run, 7, null), + new mframe_t(GameAI.ai_run, 7, null), + new mframe_t(GameAI.ai_run, 6, null), + new mframe_t(GameAI.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(GameAI.ai_run, 3, null), + new mframe_t(GameAI.ai_run, 3, null), + new mframe_t(GameAI.ai_run, 2, null), + new mframe_t(GameAI.ai_run, 2, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, -7, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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 (GameBase.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 (GameBase.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 = GameBase.level.time + 3; + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_pain, 1, + Defines.ATTN_NORM, 0); + + if (GameBase.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 = Defines.MZ2_TANK_BLASTER_1; + else if (self.s.frame == FRAME_attak113) + flash_number = Defines.MZ2_TANK_BLASTER_2; + else + // (self.s.frame == FRAME_attak116) + flash_number = Defines.MZ2_TANK_BLASTER_3; + + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.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, Defines.EF_BLASTER); + + return true; + } + }; + + static EntThinkAdapter TankStrike = new EntThinkAdapter() { + public boolean think(edict_t self) { + GameBase.gi.sound(self, Defines.CHAN_WEAPON, sound_strike, 1, + Defines.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 = Defines.MZ2_TANK_ROCKET_1; + else if (self.s.frame == FRAME_attak327) + flash_number = Defines.MZ2_TANK_ROCKET_2; + else + // (self.s.frame == FRAME_attak330) + flash_number = Defines.MZ2_TANK_ROCKET_3; + + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.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 = Defines.MZ2_TANK_MACHINEGUN_1 + + (self.s.frame - FRAME_attak406); + + Math3D.AngleVectors(self.s.angles, forward, right, null); + Math3D.G_ProjectSource(self.s.origin, + M_Flash.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, + Defines.DEFAULT_BULLET_HSPREAD, + Defines.DEFAULT_BULLET_VSPREAD, flash_number); + + return true; + } + }; + + static EntThinkAdapter tank_reattack_blaster = new EntThinkAdapter() { + public boolean think(edict_t self) { + if (GameBase.skill.value >= 2) + if (GameUtil.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, -2, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, TankBlaster), + // 10 + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, TankBlaster), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, TankBlaster), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_move, 0, null), // 17) + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.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 (GameBase.skill.value >= 2) + if (self.enemy.health > 0) + if (GameUtil.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(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 6, null), + new mframe_t(GameAI.ai_move, 7, null), + new mframe_t(GameAI.ai_move, 9, tank_footstep), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 2, tank_footstep), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 0, tank_windup), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, TankStrike), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -1, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, -10, null), + new mframe_t(GameAI.ai_move, -10, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + // 10) + + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 1, null), + new mframe_t(GameAI.ai_charge, 2, null), + new mframe_t(GameAI.ai_charge, 7, null), + new mframe_t(GameAI.ai_charge, 7, null), + new mframe_t(GameAI.ai_charge, 7, tank_footstep), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + // 20) + + new mframe_t(GameAI.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(GameAI.ai_charge, -3, null), // Loop Start 22 ) + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, TankRocket), // 24) + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, TankRocket), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), // 31) + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 2, null), + new mframe_t(GameAI.ai_charge, 3, null), + new mframe_t(GameAI.ai_charge, 4, null), + new mframe_t(GameAI.ai_charge, 2, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + // 40) + + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, -9, null), + new mframe_t(GameAI.ai_charge, -8, null), + new mframe_t(GameAI.ai_charge, -7, null), + new mframe_t(GameAI.ai_charge, -1, null), + new mframe_t(GameAI.ai_charge, -1, tank_footstep), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + // 50) + + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.ai_charge, 0, null), + new mframe_t(GameAI.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 &= ~Defines.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 = GameBase.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 = Defines.MOVETYPE_TOSS; + self.svflags |= Defines.SVF_DEADMONSTER; + self.nextthink = 0; + GameBase.gi.linkentity(self); + return true; + } + }; + + static mframe_t tank_frames_death1[] = new mframe_t[] { + new mframe_t(GameAI.ai_move, -7, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 3, null), + new mframe_t(GameAI.ai_move, 6, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 1, null), + new mframe_t(GameAI.ai_move, 2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -2, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -3, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, -6, null), + new mframe_t(GameAI.ai_move, -4, null), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, -7, null), + new mframe_t(GameAI.ai_move, -15, tank_thud), + new mframe_t(GameAI.ai_move, -5, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.ai_move, 0, null), + new mframe_t(GameAI.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) { + GameBase.gi + .sound(self, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 1 /* 4 */; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_metal/tris.md2", damage, + Defines.GIB_METALLIC); + GameAI.ThrowGib(self, "models/objects/gibs/chest/tris.md2", + damage, Defines.GIB_ORGANIC); + GameAI.ThrowHead(self, "models/objects/gibs/gear/tris.md2", + damage, Defines.GIB_METALLIC); + self.deadflag = Defines.DEAD_DEAD; + return; + } + + if (self.deadflag == Defines.DEAD_DEAD) + return; + + // regular death + GameBase.gi.sound(self, Defines.CHAN_VOICE, sound_die, 1, + Defines.ATTN_NORM, 0); + self.deadflag = Defines.DEAD_DEAD; + self.takedamage = Defines.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 (GameBase.deathmatch.value != 0) { + GameUtil.G_FreeEdict(self); + return true; + } + + self.s.modelindex = GameBase.gi + .modelindex("models/monsters/tank/tris.md2"); + Math3D.VectorSet(self.mins, -32, -32, -16); + Math3D.VectorSet(self.maxs, 32, 32, 72); + self.movetype = Defines.MOVETYPE_STEP; + self.solid = Defines.SOLID_BBOX; + + sound_pain = GameBase.gi.soundindex("tank/tnkpain2.wav"); + sound_thud = GameBase.gi.soundindex("tank/tnkdeth2.wav"); + sound_idle = GameBase.gi.soundindex("tank/tnkidle1.wav"); + sound_die = GameBase.gi.soundindex("tank/death.wav"); + sound_step = GameBase.gi.soundindex("tank/step.wav"); + sound_windup = GameBase.gi.soundindex("tank/tnkatck4.wav"); + sound_strike = GameBase.gi.soundindex("tank/tnkatck5.wav"); + sound_sight = GameBase.gi.soundindex("tank/sight1.wav"); + + GameBase.gi.soundindex("tank/tnkatck1.wav"); + GameBase.gi.soundindex("tank/tnkatk2a.wav"); + GameBase.gi.soundindex("tank/tnkatk2b.wav"); + GameBase.gi.soundindex("tank/tnkatk2c.wav"); + GameBase.gi.soundindex("tank/tnkatk2d.wav"); + GameBase.gi.soundindex("tank/tnkatk2e.wav"); + GameBase.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; + + GameBase.gi.linkentity(self); + + self.monsterinfo.currentmove = tank_move_stand; + self.monsterinfo.scale = MODEL_SCALE; + + GameAI.walkmonster_start.think(self); + + if (Lib.strcmp(self.classname, "monster_tank_commander") == 0) + self.s.skinnum = 2; + return true; + } + }; + +} \ No newline at end of file diff --git a/src/jake2/game/Monster.java b/src/jake2/game/Monster.java index fb0ac21..8ced270 100644 --- a/src/jake2/game/Monster.java +++ b/src/jake2/game/Monster.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 17.12.2003 by RST. -// $Id: Monster.java,v 1.3 2004-09-12 18:25:49 salomo Exp $ - +// $Id: Monster.java,v 1.4 2004-09-22 19:22:06 salomo Exp $ package jake2.game; import jake2.Defines; @@ -31,284 +30,331 @@ import jake2.util.*; import java.util.*; -public class Monster extends GameAI { - - // FIXME monsters 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= GameUtilAdapters.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= GameUtilAdapters.M_CheckAttack; - Math3D.VectorCopy(self.s.origin, self.s.old_origin); - - if (GameBase.st.item != null && GameBase.st.item.length() > 0) { - self.item= GameUtil.FindItemByClassname(GameBase.st.item); - if (self.item == null) - GameBase.gi.dprintf( - "monster_start:" - + 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; - /* - 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); - } - */ - - EdictIterator edit= null; - - 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= MonsterAdapters.monster_think; - self.nextthink= GameBase.level.time + Defines.FRAMETIME; - } -} +public class Monster { + + // FIXME monsters 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 && GameBase.st.item.length() > 0) { + self.item = GameUtil.FindItemByClassname(GameBase.st.item); + if (self.item == null) + GameBase.gi.dprintf("monster_start:" + 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; + /* + * 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); } + */ + + EdictIterator edit = null; + + 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) { + if (self.index == 312) + Com.p("monster_triggered_start"); + 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; + } + }; +} \ No newline at end of file diff --git a/src/jake2/game/MonsterAdapters.java b/src/jake2/game/MonsterAdapters.java deleted file mode 100644 index 918ddc4..0000000 --- a/src/jake2/game/MonsterAdapters.java +++ /dev/null @@ -1,92 +0,0 @@ -/* -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 26.02.2004 by RST. -// $Id: MonsterAdapters.java,v 1.1 2004-07-08 15:58:44 hzi Exp $ - -package jake2.game; - -import jake2.Defines; -import jake2.client.M; -import jake2.qcommon.Com; - -public class MonsterAdapters { - - 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 = GameUtilAdapters.monster_use; - } - }; - public static EntThinkAdapter monster_triggered_start = new EntThinkAdapter() { - public boolean think(edict_t self) { - if (self.index ==312) - Com.p("monster_triggered_start"); - 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 index 980f0cb..852ccfd 100644 --- a/src/jake2/game/PlayerClient.java +++ b/src/jake2/game/PlayerClient.java @@ -1,1444 +1,1443 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 28.12.2003 by RST. -// $Id: PlayerClient.java,v 1.5 2004-09-04 09:01:01 salomo Exp $ - +// $Id: PlayerClient.java,v 1.6 2004-09-22 19:22:06 salomo Exp $ package jake2.game; import jake2.Defines; import jake2.util.Lib; import jake2.util.Math3D; -public class PlayerClient extends PlayerHud { - - /*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 = PlayerClientAdapters.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; - } - GameMiscAdapters.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 = PlayerClientAdapters.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() { - } - - 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; - - client.pers = new client_persistant_t(); - - item = FindItem("Blaster"); - client.pers.selected_item = ITEM_INDEX(item); - client.pers.inventory[client.pers.selected_item] = 1; - - /* Give shotgun. - item = FindItem("Shotgun"); - 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.set(client.pers); - } - - /* - ================== - 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; - } - - - /* - ================ - 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 - } - } - - } - - /* - =========== - 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"; - } - } - - 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 = PlayerClientAdapters.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 = new client_persistant_t(); - 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.set(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.set(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.set(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.set(client.pers); - //memset(client, 0, sizeof(* client)); - client.clear(); - client.pers.set(saved); - if (client.pers.health <= 0) - InitClientPersistant(client); - - client.resp.set(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 = PlayerClientAdapters.player_pain; - ent.die = GameAIAdapters.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; - GamePWeapon.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 (s.length() > 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, ""); - } - - /* - 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; - } - - PlayerClientAdapters.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 = PlayerClientAdapters.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, GameBase.dummyplane, 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; - GamePWeapon.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) - GamePWeapon.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; - } -} +public class PlayerClient { + + /* + * 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 (GameBase.coop.value == 0) + return; + if (Lib.Q_stricmp(GameBase.level.mapname, "security") == 0) { + // invoke one of our gross, ugly, disgusting hacks + self.think = PlayerClientAdapters.SP_CreateCoopSpots; + self.nextthink = GameBase.level.time + Defines.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 == GameBase.deathmatch.value) { + GameUtil.G_FreeEdict(self); + return; + } + GameMisc.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 == GameBase.coop.value) { + GameUtil.G_FreeEdict(self); + return; + } + + if ((Lib.Q_stricmp(GameBase.level.mapname, "jail2") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "jail4") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "mine1") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "mine2") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "mine3") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "mine4") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "lab") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "boss1") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "fact3") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "biggun") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "space") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "command") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "power2") == 0) + || (Lib.Q_stricmp(GameBase.level.mapname, "strike") == 0)) { + // invoke one of our gross, ugly, disgusting hacks + self.think = PlayerClientAdapters.SP_FixCoopSpots; + self.nextthink = GameBase.level.time + Defines.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() { + } + + public static void ClientObituary(edict_t self, edict_t inflictor, + edict_t attacker) { + int mod; + String message; + String message2; + boolean ff; + + if (GameBase.coop.value != 0 && attacker.client != null) + GameBase.meansOfDeath |= Defines.MOD_FRIENDLY_FIRE; + + if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0) { + ff = (GameBase.meansOfDeath & Defines.MOD_FRIENDLY_FIRE) != 0; + mod = GameBase.meansOfDeath & ~Defines.MOD_FRIENDLY_FIRE; + message = null; + message2 = ""; + + switch (mod) { + case Defines.MOD_SUICIDE: + message = "suicides"; + break; + case Defines.MOD_FALLING: + message = "cratered"; + break; + case Defines.MOD_CRUSH: + message = "was squished"; + break; + case Defines.MOD_WATER: + message = "sank like a rock"; + break; + case Defines.MOD_SLIME: + message = "melted"; + break; + case Defines.MOD_LAVA: + message = "does a back flip into the lava"; + break; + case Defines.MOD_EXPLOSIVE: + case Defines.MOD_BARREL: + message = "blew up"; + break; + case Defines.MOD_EXIT: + message = "found a way out"; + break; + case Defines.MOD_TARGET_LASER: + message = "saw the light"; + break; + case Defines.MOD_TARGET_BLASTER: + message = "got blasted"; + break; + case Defines.MOD_BOMB: + case Defines.MOD_SPLASH: + case Defines.MOD_TRIGGER_HURT: + message = "was in the wrong place"; + break; + } + if (attacker == self) { + switch (mod) { + case Defines.MOD_HELD_GRENADE: + message = "tried to put the pin back in"; + break; + case Defines.MOD_HG_SPLASH: + case Defines.MOD_G_SPLASH: + if (GameAI.IsNeutral(self)) + message = "tripped on its own grenade"; + else if (GameAI.IsFemale(self)) + message = "tripped on her own grenade"; + else + message = "tripped on his own grenade"; + break; + case Defines.MOD_R_SPLASH: + if (GameAI.IsNeutral(self)) + message = "blew itself up"; + else if (GameAI.IsFemale(self)) + message = "blew herself up"; + else + message = "blew himself up"; + break; + case Defines.MOD_BFG_BLAST: + message = "should have used a smaller gun"; + break; + default: + if (GameAI.IsNeutral(self)) + message = "killed itself"; + else if (GameAI.IsFemale(self)) + message = "killed herself"; + else + message = "killed himself"; + break; + } + } + if (message != null) { + GameBase.gi.bprintf(Defines.PRINT_MEDIUM, + self.client.pers.netname + " " + message + ".\n"); + if (GameBase.deathmatch.value != 0) + self.client.resp.score--; + self.enemy = null; + return; + } + + self.enemy = attacker; + if (attacker != null && attacker.client != null) { + switch (mod) { + case Defines.MOD_BLASTER: + message = "was blasted by"; + break; + case Defines.MOD_SHOTGUN: + message = "was gunned down by"; + break; + case Defines.MOD_SSHOTGUN: + message = "was blown away by"; + message2 = "'s super shotgun"; + break; + case Defines.MOD_MACHINEGUN: + message = "was machinegunned by"; + break; + case Defines.MOD_CHAINGUN: + message = "was cut in half by"; + message2 = "'s chaingun"; + break; + case Defines.MOD_GRENADE: + message = "was popped by"; + message2 = "'s grenade"; + break; + case Defines.MOD_G_SPLASH: + message = "was shredded by"; + message2 = "'s shrapnel"; + break; + case Defines.MOD_ROCKET: + message = "ate"; + message2 = "'s rocket"; + break; + case Defines.MOD_R_SPLASH: + message = "almost dodged"; + message2 = "'s rocket"; + break; + case Defines.MOD_HYPERBLASTER: + message = "was melted by"; + message2 = "'s hyperblaster"; + break; + case Defines.MOD_RAILGUN: + message = "was railed by"; + break; + case Defines.MOD_BFG_LASER: + message = "saw the pretty lights from"; + message2 = "'s BFG"; + break; + case Defines.MOD_BFG_BLAST: + message = "was disintegrated by"; + message2 = "'s BFG blast"; + break; + case Defines.MOD_BFG_EFFECT: + message = "couldn't hide from"; + message2 = "'s BFG"; + break; + case Defines.MOD_HANDGRENADE: + message = "caught"; + message2 = "'s handgrenade"; + break; + case Defines.MOD_HG_SPLASH: + message = "didn't see"; + message2 = "'s handgrenade"; + break; + case Defines.MOD_HELD_GRENADE: + message = "feels"; + message2 = "'s pain"; + break; + case Defines.MOD_TELEFRAG: + message = "tried to invade"; + message2 = "'s personal space"; + break; + } + if (message != null) { + GameBase.gi.bprintf(Defines.PRINT_MEDIUM, + self.client.pers.netname + " " + message + " " + + attacker.client.pers.netname + " " + + message2 + "\n"); + if (GameBase.deathmatch.value != 0) { + if (ff) + attacker.client.resp.score--; + else + attacker.client.resp.score++; + } + return; + } + } + } + + GameBase.gi.bprintf(Defines.PRINT_MEDIUM, self.client.pers.netname + + " died.\n"); + if (GameBase.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; + + client.pers = new client_persistant_t(); + + item = GameUtil.FindItem("Blaster"); + client.pers.selected_item = GameUtil.ITEM_INDEX(item); + client.pers.inventory[client.pers.selected_item] = 1; + + /* + * Give shotgun. item = FindItem("Shotgun"); 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 = GameBase.level.framenum; + client.resp.coop_respawn.set(client.pers); + } + + /* + * ================== 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 < GameBase.game.maxclients; i++) { + ent = GameBase.g_edicts[1 + i]; + if (!ent.inuse) + continue; + + GameBase.game.clients[i].pers.health = ent.health; + GameBase.game.clients[i].pers.max_health = ent.max_health; + GameBase.game.clients[i].pers.savedFlags = (ent.flags & (Defines.FL_GODMODE + | Defines.FL_NOTARGET | Defines.FL_POWER_ARMOR)); + + if (GameBase.coop.value != 0) + GameBase.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 (GameBase.coop.value != 0) + ent.client.resp.score = ent.client.pers.score; + } + + /* + * ================ 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 <= GameBase.maxclients.value; n++) { + player = GameBase.g_edicts[n]; + + if (!player.inuse) + continue; + + if (player.health <= 0) + continue; + + Math3D.VectorSubtract(spot.s.origin, player.s.origin, v); + playerdistance = Math3D.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 = GameBase.G_Find(es, GameBase.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 = Lib.rand() % count; + + spot = null; + es = null; + do { + es = GameBase.G_Find(es, GameBase.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 = GameBase.G_Find(es, GameBase.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 = GameBase.G_Find(null, GameBase.findByClass, + "info_player_deathmatch").o; + + return spot; + } + + public static edict_t SelectDeathmatchSpawnPoint() { + if (0 != ((int) (GameBase.dmflags.value) & Defines.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 = GameBase.G_Find(es, GameBase.findByClass, + "info_player_coop")).o; + if (spot == null) + return null; // we didn't have enough... + + target = spot.targetname; + if (target == null) + target = ""; + if (Lib.Q_stricmp(GameBase.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 + } + } + + } + + /* + * =========== 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 (GameBase.deathmatch.value != 0) + spot = SelectDeathmatchSpawnPoint(); + else if (GameBase.coop.value != 0) + spot = SelectCoopSpawnPoint(ent); + + EdictIterator es = null; + // find a single player start spot + if (null == spot) { + while ((es = GameBase.G_Find(es, GameBase.findByClass, + "info_player_start")) != null) { + spot = es.o; + + if (GameBase.game.spawnpoint.length() == 0 + && spot.targetname == null) + break; + + if (GameBase.game.spawnpoint.length() == 0 + || spot.targetname == null) + continue; + + if (Lib.Q_stricmp(GameBase.game.spawnpoint, spot.targetname) == 0) + break; + } + + if (null == spot) { + if (GameBase.game.spawnpoint.length() == 0) { // there wasn't a + // spawnpoint + // without a + // target, so use + // any + spot = (es = GameBase.G_Find(es, GameBase.findByClass, + "info_player_start")).o; + } + if (null == spot) + GameBase.gi.error("Couldn't find spawn point " + + GameBase.game.spawnpoint + "\n"); + } + } + + Math3D.VectorCopy(spot.s.origin, origin); + origin[2] += 9; + Math3D.VectorCopy(spot.s.angles, angles); + } + + //====================================================================== + + public static void InitBodyQue() { + int i; + edict_t ent; + + GameBase.level.body_que = 0; + for (i = 0; i < Defines.BODY_QUEUE_SIZE; i++) { + ent = GameUtil.G_Spawn(); + ent.classname = "bodyque"; + } + } + + public static void CopyToBodyQue(edict_t ent) { + edict_t body; + + // grab a body que and cycle to the next one + int i = (int) GameBase.maxclients.value + GameBase.level.body_que + 1; + body = GameBase.g_edicts[i]; + GameBase.level.body_que = (GameBase.level.body_que + 1) + % Defines.BODY_QUEUE_SIZE; + + // FIXME: send an effect on the removed body + + GameBase.gi.unlinkentity(ent); + + GameBase.gi.unlinkentity(body); + body.s = ent.s.getClone(); + + body.s.number = body.index; + + body.svflags = ent.svflags; + Math3D.VectorCopy(ent.mins, body.mins); + Math3D.VectorCopy(ent.maxs, body.maxs); + Math3D.VectorCopy(ent.absmin, body.absmin); + Math3D.VectorCopy(ent.absmax, body.absmax); + Math3D.VectorCopy(ent.size, body.size); + body.solid = ent.solid; + body.clipmask = ent.clipmask; + body.owner = ent.owner; + body.movetype = ent.movetype; + + body.die = PlayerClientAdapters.body_die; + body.takedamage = Defines.DAMAGE_YES; + + GameBase.gi.linkentity(body); + } + + public static void respawn(edict_t self) { + if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0) { + // spectator's don't leave bodies + if (self.movetype != Defines.MOVETYPE_NOCLIP) + CopyToBodyQue(self); + self.svflags &= ~Defines.SVF_NOCLIENT; + PutClientInServer(self); + + // add a teleportation effect + self.s.event = Defines.EV_PLAYER_TELEPORT; + + // hold in place briefly + self.client.ps.pmove.pm_flags = pmove_t.PMF_TIME_TELEPORT; + self.client.ps.pmove.pm_time = 14; + + self.client.respawn_time = GameBase.level.time; + + return; + } + + // restart the entire server + GameBase.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(GameBase.spectator_password.string, value)) { + GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, + "Spectator password incorrect.\n"); + ent.client.pers.spectator = false; + GameBase.gi.WriteByte(Defines.svc_stufftext); + GameBase.gi.WriteString("spectator 0\n"); + GameBase.gi.unicast(ent, true); + return; + } + + // count spectators + for (i = 1, numspec = 0; i <= GameBase.maxclients.value; i++) + if (GameBase.g_edicts[i].inuse + && GameBase.g_edicts[i].client.pers.spectator) + numspec++; + + if (numspec >= GameBase.maxspectators.value) { + GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, + "Server spectator limit is full."); + ent.client.pers.spectator = false; + // reset his spectator var + GameBase.gi.WriteByte(Defines.svc_stufftext); + GameBase.gi.WriteString("spectator 0\n"); + GameBase.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(GameBase.spectator_password.string, value)) { + GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, + "Password incorrect.\n"); + ent.client.pers.spectator = true; + GameBase.gi.WriteByte(Defines.svc_stufftext); + GameBase.gi.WriteString("spectator 1\n"); + GameBase.gi.unicast(ent, true); + return; + } + } + + // clear client on respawn + ent.client.resp.score = ent.client.pers.score = 0; + + ent.svflags &= ~Defines.SVF_NOCLIENT; + PutClientInServer(ent); + + // add a teleportation effect + if (!ent.client.pers.spectator) { + // send effect + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + //gi.WriteShort(ent - g_edicts); + GameBase.gi.WriteShort(ent.index); + + GameBase.gi.WriteByte(Defines.MZ_LOGIN); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + // hold in place briefly + ent.client.ps.pmove.pm_flags = pmove_t.PMF_TIME_TELEPORT; + ent.client.ps.pmove.pm_time = 14; + } + + ent.client.respawn_time = GameBase.level.time; + + if (ent.client.pers.spectator) + GameBase.gi.bprintf(Defines.PRINT_HIGH, ent.client.pers.netname + + " has moved to the sidelines\n"); + else + GameBase.gi.bprintf(Defines.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 = new client_persistant_t(); + 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 (GameBase.deathmatch.value != 0) { + String userinfo; + //char userinfo[MAX_INFO_STRING]; + + resp.set(client.resp); + userinfo = client.pers.userinfo; + + //memcpy(userinfo, client.pers.userinfo, sizeof(userinfo)); + InitClientPersistant(client); + userinfo = ClientUserinfoChanged(ent, userinfo); + } else if (GameBase.coop.value != 0) { + // int n; + //char userinfo[MAX_INFO_STRING]; + String userinfo; + + resp.set(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.set(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.set(client.pers); + //memset(client, 0, sizeof(* client)); + client.clear(); + client.pers.set(saved); + if (client.pers.health <= 0) + InitClientPersistant(client); + + client.resp.set(resp); + + // copy some data from the client to the entity + FetchClientEntData(ent); + + // clear entity values + ent.groundentity = null; + ent.client = GameBase.game.clients[index]; + ent.takedamage = Defines.DAMAGE_AIM; + ent.movetype = Defines.MOVETYPE_WALK; + ent.viewheight = 22; + ent.inuse = true; + ent.classname = "player"; + ent.mass = 200; + ent.solid = Defines.SOLID_BBOX; + ent.deadflag = Defines.DEAD_NO; + ent.air_finished = GameBase.level.time + 12; + ent.clipmask = Defines.MASK_PLAYERSOLID; + ent.model = "players/male/tris.md2"; + ent.pain = PlayerClientAdapters.player_pain; + ent.die = GameAI.player_die; + ent.waterlevel = 0; + ent.watertype = 0; + ent.flags &= ~Defines.FL_NO_KNOCKBACK; + ent.svflags &= ~Defines.SVF_DEADMONSTER; + + Math3D.VectorCopy(mins, ent.mins); + Math3D.VectorCopy(maxs, ent.maxs); + Math3D.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 (GameBase.deathmatch.value != 0 + && 0 != ((int) GameBase.dmflags.value & Defines.DF_FIXED_FOV)) { + client.ps.fov = 90; + } else { + client.ps.fov = Lib.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 = GameBase.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; + Math3D.VectorCopy(spawn_origin, ent.s.origin); + ent.s.origin[2] += 1; // make sure off ground + Math3D.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) Math3D + .ANGLE2SHORT(spawn_angles[i] - client.resp.cmd_angles[i]); + } + + ent.s.angles[Defines.PITCH] = 0; + ent.s.angles[Defines.YAW] = spawn_angles[Defines.YAW]; + ent.s.angles[Defines.ROLL] = 0; + Math3D.VectorCopy(ent.s.angles, client.ps.viewangles); + Math3D.VectorCopy(ent.s.angles, client.v_angle); + + // spawn a spectator + if (client.pers.spectator) { + client.chase_target = null; + + client.resp.spectator = true; + + ent.movetype = Defines.MOVETYPE_NOCLIP; + ent.solid = Defines.SOLID_NOT; + ent.svflags |= Defines.SVF_NOCLIENT; + ent.client.ps.gunindex = 0; + GameBase.gi.linkentity(ent); + return; + } else + client.resp.spectator = false; + + if (!GameUtil.KillBox(ent)) { // could't spawn in? + } + + GameBase.gi.linkentity(ent); + + // force the current weapon up + client.newweapon = client.pers.weapon; + GamePWeapon.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) { + GameUtil.G_InitEdict(ent, ent.index); + + InitClientResp(ent.client); + + // locate ent at a spawn point + PutClientInServer(ent); + + if (GameBase.level.intermissiontime != 0) { + PlayerHud.MoveClientToIntermission(ent); + } else { + // send effect + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + //gi.WriteShort(ent - g_edicts); + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte(Defines.MZ_LOGIN); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + } + + GameBase.gi.bprintf(Defines.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 = GameBase.game.clients[ent.index - 1]; + + if (GameBase.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) Math3D + .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 + GameUtil.G_InitEdict(ent, ent.index); + ent.classname = "player"; + InitClientResp(ent.client); + PutClientInServer(ent); + } + + if (GameBase.level.intermissiontime != 0) { + PlayerHud.MoveClientToIntermission(ent); + } else { + // send effect if in a multiplayer game + if (GameBase.game.maxclients > 1) { + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + //gi.WriteShort(ent - g_edicts); + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte(Defines.MZ_LOGIN); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + GameBase.gi.bprintf(Defines.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 (GameBase.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 + GameBase.gi.configstring(Defines.CS_PLAYERSKINS + playernum, + ent.client.pers.netname + "\\" + s); + + // fov + if (GameBase.deathmatch.value != 0 + && 0 != ((int) GameBase.dmflags.value & Defines.DF_FIXED_FOV)) { + ent.client.ps.fov = 90; + } else { + ent.client.ps.fov = Lib + .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 (s.length() > 0) { + ent.client.pers.hand = Lib.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 (GameBase.deathmatch.value != 0 && value.length() != 0 + && 0 != Lib.strcmp(value, "0")) { + int i, numspec; + + if (!passwdOK(GameBase.spectator_password.string, value)) { + userinfo = Info.Info_SetValueForKey1(userinfo, "rejmsg", + "Spectator password required or incorrect."); + return false; + } + + // count spectators + for (i = numspec = 0; i < GameBase.maxclients.value; i++) + if (GameBase.g_edicts[i + 1].inuse + && GameBase.g_edicts[i + 1].client.pers.spectator) + numspec++; + + if (numspec >= GameBase.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(GameBase.spectator_password.string, value)) { + userinfo = Info.Info_SetValueForKey1(userinfo, "rejmsg", + "Password required or incorrect."); + return false; + } + } + + // they can connect + ent.client = GameBase.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 (!GameBase.game.autosaved || null == ent.client.pers.weapon) + InitClientPersistant(ent.client); + } + + userinfo = ClientUserinfoChanged(ent, userinfo); + + if (GameBase.game.maxclients > 1) + GameBase.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; + + GameBase.gi.bprintf(Defines.PRINT_HIGH, ent.client.pers.netname + + " disconnected\n"); + + // send effect + GameBase.gi.WriteByte(Defines.svc_muzzleflash); + GameBase.gi.WriteShort(ent.index); + GameBase.gi.WriteByte(Defines.MZ_LOGOUT); + GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS); + + GameBase.gi.unlinkentity(ent); + ent.s.modelindex = 0; + ent.solid = Defines.SOLID_NOT; + ent.inuse = false; + ent.classname = "disconnected"; + ent.client.pers.connected = false; + + playernum = ent.index - 1; + GameBase.gi.configstring(Defines.CS_PLAYERSKINS + playernum, ""); + } + + /* + * 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; + + GameBase.level.current_entity = ent; + client = ent.client; + + if (GameBase.level.intermissiontime != 0) { + client.ps.pmove.pm_type = Defines.PM_FREEZE; + // can exit intermission after five seconds + if (GameBase.level.time > GameBase.level.intermissiontime + 5.0f + && 0 != (ucmd.buttons & Defines.BUTTON_ANY)) + GameBase.level.exitintermission = true; + return; + } + + PlayerClientAdapters.pm_passent = ent; + + if (ent.client.chase_target != null) { + + client.resp.cmd_angles[0] = Math3D.SHORT2ANGLE(ucmd.angles[0]); + client.resp.cmd_angles[1] = Math3D.SHORT2ANGLE(ucmd.angles[1]); + client.resp.cmd_angles[2] = Math3D.SHORT2ANGLE(ucmd.angles[2]); + + } else { + + // set up for pmove + //memset(& pm, 0, sizeof(pm)); + pm = new pmove_t(); + + if (ent.movetype == Defines.MOVETYPE_NOCLIP) + client.ps.pmove.pm_type = Defines.PM_SPECTATOR; + else if (ent.s.modelindex != 255) + client.ps.pmove.pm_type = Defines.PM_GIB; + else if (ent.deadflag != 0) + client.ps.pmove.pm_type = Defines.PM_DEAD; + else + client.ps.pmove.pm_type = Defines.PM_NORMAL; + + client.ps.pmove.gravity = (short) GameBase.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 = PlayerClientAdapters.PM_trace; // adds default parms + pm.pointcontents = GameBase.gi.pointcontents; + + // perform a pmove + GameBase.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; + } + + Math3D.VectorCopy(pm.mins, ent.mins); + Math3D.VectorCopy(pm.maxs, ent.maxs); + + client.resp.cmd_angles[0] = Math3D.SHORT2ANGLE(ucmd.angles[0]); + client.resp.cmd_angles[1] = Math3D.SHORT2ANGLE(ucmd.angles[1]); + client.resp.cmd_angles[2] = Math3D.SHORT2ANGLE(ucmd.angles[2]); + + if (ent.groundentity != null && null == pm.groundentity + && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0)) { + GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi + .soundindex("*jump1.wav"), 1, Defines.ATTN_NORM, 0); + GameWeapon.PlayerNoise(ent, ent.s.origin, Defines.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[Defines.ROLL] = 40; + client.ps.viewangles[Defines.PITCH] = -15; + client.ps.viewangles[Defines.YAW] = client.killer_yaw; + } else { + Math3D.VectorCopy(pm.viewangles, client.v_angle); + Math3D.VectorCopy(pm.viewangles, client.ps.viewangles); + } + + GameBase.gi.linkentity(ent); + + if (ent.movetype != Defines.MOVETYPE_NOCLIP) + GameBase.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, GameBase.dummyplane, 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 & Defines.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 &= ~pmove_t.PMF_NO_PREDICTION; + } else + GameAI.GetChaseTarget(ent); + + } else if (!client.weapon_thunk) { + client.weapon_thunk = true; + GamePWeapon.Think_Weapon(ent); + } + } + + if (client.resp.spectator) { + if (ucmd.upmove >= 10) { + if (0 == (client.ps.pmove.pm_flags & pmove_t.PMF_JUMP_HELD)) { + client.ps.pmove.pm_flags |= pmove_t.PMF_JUMP_HELD; + if (client.chase_target != null) + GameAI.ChaseNext(ent); + else + GameAI.GetChaseTarget(ent); + } + } else + client.ps.pmove.pm_flags &= ~pmove_t.PMF_JUMP_HELD; + } + + // update chase cam if being followed + for (i = 1; i <= GameBase.maxclients.value; i++) { + other = GameBase.g_edicts[i]; + if (other.inuse && other.client.chase_target == ent) + GameAI.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 (GameBase.level.intermissiontime != 0) + return; + + client = ent.client; + + if (GameBase.deathmatch.value != 0 + && client.pers.spectator != client.resp.spectator + && (GameBase.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) + GamePWeapon.Think_Weapon(ent); + else + client.weapon_thunk = false; + + if (ent.deadflag != 0) { + // wait for any button just going down + if (GameBase.level.time > client.respawn_time) { + // in deathmatch, only wait for attack button + if (GameBase.deathmatch.value != 0) + buttonMask = Defines.BUTTON_ATTACK; + else + buttonMask = -1; + + if ((client.latched_buttons & buttonMask) != 0 + || (GameBase.deathmatch.value != 0 && 0 != ((int) GameBase.dmflags.value & Defines.DF_FORCE_RESPAWN))) { + respawn(ent); + client.latched_buttons = 0; + } + } + return; + } + + // add player trail so monsters can follow + if (GameBase.deathmatch.value != 0) + if (!GameUtil.visible(ent, PlayerTrail.LastSpot())) + PlayerTrail.Add(ent.s.old_origin); + + client.latched_buttons = 0; + } +} \ No newline at end of file diff --git a/src/jake2/game/PlayerClientAdapters.java b/src/jake2/game/PlayerClientAdapters.java index f6d1e8d..198c124 100644 --- a/src/jake2/game/PlayerClientAdapters.java +++ b/src/jake2/game/PlayerClientAdapters.java @@ -1,146 +1,163 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 26.02.2004 by RST. -// $Id: PlayerClientAdapters.java,v 1.2 2004-08-20 21:29:58 salomo Exp $ - +// $Id: PlayerClientAdapters.java,v 1.3 2004-09-22 19:22:05 salomo Exp $ package jake2.game; -import jake2.game.pmove_t.TraceAdapter; - import jake2.Defines; import jake2.util.Lib; import jake2.util.Math3D; -public class PlayerClientAdapters extends PlayerClient { - - // - // 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= GameBase.G_Find(es, GameBase.findByClass, "info_player_start"); - spot= es.o; - if (spot == null) - return true; - if (spot.targetname == null) - continue; - Math3D.VectorSubtract(self.s.origin, spot.s.origin, d); - if (Math3D.VectorLength(d) < 384) { - if ((self.targetname == null) || Lib.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; - } - } - } - }; - // 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 (Lib.Q_stricmp(GameBase.level.mapname, "security") == 0) { - spot= GameUtil.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= GameUtil.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= GameUtil.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; - } - }; - //======================================================================= - - // player pain is handled at the end of the frame in P_DamageFeedback - static EntPainAdapter player_pain= new EntPainAdapter() { - public void pain(edict_t self, edict_t other, float kick, int damage) { - } - }; - 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) { - GameBase.gi.sound(self, Defines.CHAN_BODY, GameBase.gi.soundindex("misc/udeath.wav"), 1, Defines.ATTN_NORM, 0); - for (n= 0; n < 4; n++) - GameAI.ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, Defines.GIB_ORGANIC); - self.s.origin[2] -= 48; - GameAI.ThrowClientHead(self, damage); - self.takedamage= Defines.DAMAGE_NO; - } - } - }; - //============================================================== - - 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 GameBase.gi.trace(start, mins, maxs, end, pm_passent, Defines.MASK_PLAYERSOLID); - else - return GameBase.gi.trace(start, mins, maxs, end, pm_passent, Defines.MASK_DEADSOLID); - } - - }; -} +public class PlayerClientAdapters { + + // + // 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 = GameBase.G_Find(es, GameBase.findByClass, + "info_player_start"); + spot = es.o; + if (spot == null) + return true; + if (spot.targetname == null) + continue; + Math3D.VectorSubtract(self.s.origin, spot.s.origin, d); + if (Math3D.VectorLength(d) < 384) { + if ((self.targetname == null) + || Lib.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; + } + } + } + }; + + // 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 (Lib.Q_stricmp(GameBase.level.mapname, "security") == 0) { + spot = GameUtil.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 = GameUtil.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 = GameUtil.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; + } + }; + + //======================================================================= + + // player pain is handled at the end of the frame in P_DamageFeedback + static EntPainAdapter player_pain = new EntPainAdapter() { + public void pain(edict_t self, edict_t other, float kick, int damage) { + } + }; + + 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) { + GameBase.gi + .sound(self, Defines.CHAN_BODY, GameBase.gi + .soundindex("misc/udeath.wav"), 1, + Defines.ATTN_NORM, 0); + for (n = 0; n < 4; n++) + GameAI.ThrowGib(self, + "models/objects/gibs/sm_meat/tris.md2", damage, + Defines.GIB_ORGANIC); + self.s.origin[2] -= 48; + GameAI.ThrowClientHead(self, damage); + self.takedamage = Defines.DAMAGE_NO; + } + } + }; + + //============================================================== + + 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 GameBase.gi.trace(start, mins, maxs, end, pm_passent, + Defines.MASK_PLAYERSOLID); + else + return GameBase.gi.trace(start, mins, maxs, end, pm_passent, + Defines.MASK_DEADSOLID); + } + + }; +} \ No newline at end of file diff --git a/src/jake2/game/PlayerHud.java b/src/jake2/game/PlayerHud.java index 17f73ce..23c0c09 100644 --- a/src/jake2/game/PlayerHud.java +++ b/src/jake2/game/PlayerHud.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 28.12.2003 by RST. -// $Id: PlayerHud.java,v 1.5 2004-08-27 21:59:23 hzi Exp $ - +// $Id: PlayerHud.java,v 1.6 2004-09-22 19:22:03 salomo Exp $ package jake2.game; import jake2.*; @@ -28,472 +27,480 @@ import jake2.client.*; import jake2.qcommon.*; import jake2.render.*; import jake2.server.*; +import jake2.util.Lib; +import jake2.util.Math3D; 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 = 1; n < MAX_ITEMS; n++) { - if ((GameAI.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); - } - - //======================================================================= - - /* - =============== - 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 = GameAI.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(GameAI.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; - } - -} +public class PlayerHud { + + /* + * ====================================================================== + * + * INTERMISSION + * + * ====================================================================== + */ + + public static void MoveClientToIntermission(edict_t ent) { + if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0) + ent.client.showscores = true; + Math3D.VectorCopy(GameBase.level.intermission_origin, ent.s.origin); + ent.client.ps.pmove.origin[0] = (short) (GameBase.level.intermission_origin[0] * 8); + ent.client.ps.pmove.origin[1] = (short) (GameBase.level.intermission_origin[1] * 8); + ent.client.ps.pmove.origin[2] = (short) (GameBase.level.intermission_origin[2] * 8); + Math3D.VectorCopy(GameBase.level.intermission_angle, + ent.client.ps.viewangles); + ent.client.ps.pmove.pm_type = Defines.PM_FREEZE; + ent.client.ps.gunindex = 0; + ent.client.ps.blend[3] = 0; + ent.client.ps.rdflags &= ~Defines.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 = Defines.SOLID_NOT; + + // add the layout + + if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0) { + DeathmatchScoreboardMessage(ent, null); + GameBase.gi.unicast(ent, true); + } + + } + + public static void BeginIntermission(edict_t targ) { + int i, n; + edict_t ent, client; + + if (GameBase.level.intermissiontime != 0) + return; // already activated + + GameBase.game.autosaved = false; + + // respawn any dead clients + for (i = 0; i < GameBase.maxclients.value; i++) { + client = GameBase.g_edicts[1 + i]; + if (!client.inuse) + continue; + if (client.health <= 0) + PlayerClient.respawn(client); + } + + GameBase.level.intermissiontime = GameBase.level.time; + GameBase.level.changemap = targ.map; + + if (GameBase.level.changemap.indexOf('*') > -1) { + if (GameBase.coop.value != 0) { + for (i = 0; i < GameBase.maxclients.value; i++) { + client = GameBase.g_edicts[1 + i]; + if (!client.inuse) + continue; + // strip players of all keys between units + for (n = 1; n < Defines.MAX_ITEMS; n++) { + if ((GameAI.itemlist[n].flags & Defines.IT_KEY) != 0) + client.client.pers.inventory[n] = 0; + } + } + } + } else { + if (0 == GameBase.deathmatch.value) { + GameBase.level.exitintermission = true; // go immediately to the + // next level + return; + } + } + + GameBase.level.exitintermission = false; + + // find an intermission spot + ent = GameBase.G_FindEdict(null, GameBase.findByClass, + "info_player_intermission"); + if (ent == null) { // the map creator forgot to put in an intermission + // point... + ent = GameBase.G_FindEdict(null, GameBase.findByClass, + "info_player_start"); + if (ent == null) + ent = GameBase.G_FindEdict(null, GameBase.findByClass, + "info_player_deathmatch"); + } else { // chose one of four spots + i = Lib.rand() & 3; + EdictIterator es = null; + + while (i-- > 0) { + es = GameBase.G_Find(es, GameBase.findByClass, + "info_player_intermission"); + + if (es == null) // wrap around the list + continue; + ent = es.o; + + } + } + + Math3D.VectorCopy(ent.s.origin, GameBase.level.intermission_origin); + Math3D.VectorCopy(ent.s.angles, GameBase.level.intermission_angle); + + // move all clients to the intermission point + for (i = 0; i < GameBase.maxclients.value; i++) { + client = GameBase.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); + + int stringlength; + int i, j, k; + int sorted[] = new int[Defines.MAX_CLIENTS]; + int sortedscores[] = new int[Defines.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 < GameBase.game.maxclients; i++) { + cl_ent = GameBase.g_edicts[1 + i]; + if (!cl_ent.inuse || GameBase.game.clients[i].resp.spectator) + continue; + score = GameBase.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 = GameBase.game.clients[sorted[i]]; + cl_ent = GameBase.g_edicts[1 + sorted[i]]; + + picnum = GameBase.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( + (GameBase.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; + */ + + } + + GameBase.gi.WriteByte(Defines.svc_layout); + GameBase.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); + GameBase.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 == GameBase.deathmatch.value && 0 == GameBase.coop.value) + return; + + if (ent.client.showscores) { + ent.client.showscores = false; + return; + } + + ent.client.showscores = true; + DeathmatchScoreboard(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[Defines.STAT_HEALTH_ICON] = (short) GameBase.level.pic_health; + ent.client.ps.stats[Defines.STAT_HEALTH] = (short) ent.health; + + // + // ammo + // + if (0 == ent.client.ammo_index /* + * || + * !ent.client.pers.inventory[ent.client.ammo_index] + */ + ) { + ent.client.ps.stats[Defines.STAT_AMMO_ICON] = 0; + ent.client.ps.stats[Defines.STAT_AMMO] = 0; + } else { + item = GameAI.itemlist[ent.client.ammo_index]; + ent.client.ps.stats[Defines.STAT_AMMO_ICON] = (short) GameBase.gi + .imageindex(item.icon); + ent.client.ps.stats[Defines.STAT_AMMO] = (short) ent.client.pers.inventory[ent.client.ammo_index]; + } + + // + // armor + // + power_armor_type = GameUtil.PowerArmorType(ent); + if (power_armor_type != 0) { + cells = ent.client.pers.inventory[GameUtil.ITEM_INDEX(GameUtil + .FindItem("cells"))]; + if (cells == 0) { // ran out of cells for power armor + ent.flags &= ~Defines.FL_POWER_ARMOR; + GameBase.gi + .sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("misc/power2.wav"), 1, + Defines.ATTN_NORM, 0); + power_armor_type = 0; + ; + } + } + + index = GameUtil.ArmorIndex(ent); + if (power_armor_type != 0 + && (0 == index || 0 != (GameBase.level.framenum & 8))) { // flash + // between + // power + // armor + // and + // other + // armor + // icon + ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = (short) GameBase.gi + .imageindex("i_powershield"); + ent.client.ps.stats[Defines.STAT_ARMOR] = (short) cells; + } else if (index != 0) { + item = GameAI.GetItemByIndex(index); + ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = (short) GameBase.gi + .imageindex(item.icon); + ent.client.ps.stats[Defines.STAT_ARMOR] = (short) ent.client.pers.inventory[index]; + } else { + ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = 0; + ent.client.ps.stats[Defines.STAT_ARMOR] = 0; + } + + // + // pickup message + // + if (GameBase.level.time > ent.client.pickup_msg_time) { + ent.client.ps.stats[Defines.STAT_PICKUP_ICON] = 0; + ent.client.ps.stats[Defines.STAT_PICKUP_STRING] = 0; + } + + // + // timers + // + if (ent.client.quad_framenum > GameBase.level.framenum) { + ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi + .imageindex("p_quad"); + ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.quad_framenum - GameBase.level.framenum) / 10); + } else if (ent.client.invincible_framenum > GameBase.level.framenum) { + ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi + .imageindex("p_invulnerability"); + ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.invincible_framenum - GameBase.level.framenum) / 10); + } else if (ent.client.enviro_framenum > GameBase.level.framenum) { + ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi + .imageindex("p_envirosuit"); + ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.enviro_framenum - GameBase.level.framenum) / 10); + } else if (ent.client.breather_framenum > GameBase.level.framenum) { + ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi + .imageindex("p_rebreather"); + ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.breather_framenum - GameBase.level.framenum) / 10); + } else { + ent.client.ps.stats[Defines.STAT_TIMER_ICON] = 0; + ent.client.ps.stats[Defines.STAT_TIMER] = 0; + } + + // + // selected item + // + // bugfix rst + if (ent.client.pers.selected_item <= 0) + ent.client.ps.stats[Defines.STAT_SELECTED_ICON] = 0; + else + ent.client.ps.stats[Defines.STAT_SELECTED_ICON] = (short) GameBase.gi + .imageindex(GameAI.itemlist[ent.client.pers.selected_item].icon); + + ent.client.ps.stats[Defines.STAT_SELECTED_ITEM] = (short) ent.client.pers.selected_item; + + // + // layouts + // + ent.client.ps.stats[Defines.STAT_LAYOUTS] = 0; + + if (GameBase.deathmatch.value != 0) { + if (ent.client.pers.health <= 0 + || GameBase.level.intermissiontime != 0 + || ent.client.showscores) + ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 1; + if (ent.client.showinventory && ent.client.pers.health > 0) + ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 2; + } else { + if (ent.client.showscores || ent.client.showhelp) + ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 1; + if (ent.client.showinventory && ent.client.pers.health > 0) + ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 2; + } + + // + // frags + // + ent.client.ps.stats[Defines.STAT_FRAGS] = (short) ent.client.resp.score; + + // + // help icon / current weapon if not shown + // + if (ent.client.pers.helpchanged != 0 + && (GameBase.level.framenum & 8) != 0) + ent.client.ps.stats[Defines.STAT_HELPICON] = (short) GameBase.gi + .imageindex("i_help"); + else if ((ent.client.pers.hand == Defines.CENTER_HANDED || ent.client.ps.fov > 91) + && ent.client.pers.weapon != null) + ent.client.ps.stats[Defines.STAT_HELPICON] = (short) GameBase.gi + .imageindex(ent.client.pers.weapon.icon); + else + ent.client.ps.stats[Defines.STAT_HELPICON] = 0; + + ent.client.ps.stats[Defines.STAT_SPECTATOR] = 0; + } + + /* + * =============== G_CheckChaseStats =============== + */ + public static void G_CheckChaseStats(edict_t ent) { + int i; + gclient_t cl; + + for (i = 1; i <= GameBase.maxclients.value; i++) { + cl = GameBase.g_edicts[i].client; + if (!GameBase.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(GameBase.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[Defines.STAT_SPECTATOR] = 1; + + // layouts are independant in spectator + cl.ps.stats[Defines.STAT_LAYOUTS] = 0; + if (cl.pers.health <= 0 || GameBase.level.intermissiontime != 0 + || cl.showscores) + cl.ps.stats[Defines.STAT_LAYOUTS] |= 1; + if (cl.showinventory && cl.pers.health > 0) + cl.ps.stats[Defines.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[Defines.STAT_CHASE] = (short) (Defines.CS_PLAYERSKINS + + cl.chase_target.index - 1); + else + cl.ps.stats[Defines.STAT_CHASE] = 0; + } +} \ No newline at end of file diff --git a/src/jake2/game/PlayerTrail.java b/src/jake2/game/PlayerTrail.java index 09af3d8..4e48353 100644 --- a/src/jake2/game/PlayerTrail.java +++ b/src/jake2/game/PlayerTrail.java @@ -1,151 +1,148 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 13.11.2003 by RST. -// $Id: PlayerTrail.java,v 1.1 2004-07-07 19:59:23 hzi Exp $ - +// $Id: PlayerTrail.java,v 1.2 2004-09-22 19:22:04 salomo Exp $ package jake2.game; -import jake2.util.*; -import jake2.util.*; +import jake2.util.Math3D; + +public class PlayerTrail { -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 - */ + /* + * ============================================================================== + * + * 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 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 edict_t trail[] = new edict_t[TRAIL_LENGTH]; - static int NEXT(int n) { - return (n + 1) % TRAIL_LENGTH; - } + static int trail_head; - static int PREV(int n) { - return (n + TRAIL_LENGTH - 1) % TRAIL_LENGTH; - } + static boolean trail_active = false; + static { + //TODO: potential error + for (int n = 0; n < TRAIL_LENGTH; n++) + trail[n] = new edict_t(n); + } - static void Init() { + static int NEXT(int n) { + return (n + 1) % PlayerTrail.TRAIL_LENGTH; + } - // FIXME || coop - if (deathmatch.value != 0) - return; + static int PREV(int n) { + return (n + PlayerTrail.TRAIL_LENGTH - 1) % PlayerTrail.TRAIL_LENGTH; + } - for (int n= 0; n < TRAIL_LENGTH; n++) { - trail[n]= G_Spawn(); - trail[n].classname= "player_trail"; - } + static void Init() { - trail_head= 0; - trail_active= true; - } + // FIXME || coop + if (GameBase.deathmatch.value != 0) + return; - static void Add(float[] spot) { - float[] temp= { 0, 0, 0 }; + for (int n = 0; n < PlayerTrail.TRAIL_LENGTH; n++) { + PlayerTrail.trail[n] = GameUtil.G_Spawn(); + PlayerTrail.trail[n].classname = "player_trail"; + } - if (!trail_active) - return; + trail_head = 0; + trail_active = true; + } - Math3D.VectorCopy(spot, trail[trail_head].s.origin); + static void Add(float[] spot) { + float[] temp = { 0, 0, 0 }; - trail[trail_head].timestamp= level.time; + if (!trail_active) + return; - Math3D.VectorSubtract(spot, trail[PREV(trail_head)].s.origin, temp); - trail[trail_head].s.angles[1]= Math3D.vectoyaw(temp); + Math3D.VectorCopy(spot, PlayerTrail.trail[trail_head].s.origin); - trail_head= NEXT(trail_head); - } + PlayerTrail.trail[trail_head].timestamp = GameBase.level.time; - static void New(float[] spot) { - if (!trail_active) - return; + Math3D.VectorSubtract(spot, + PlayerTrail.trail[PREV(trail_head)].s.origin, temp); + PlayerTrail.trail[trail_head].s.angles[1] = Math3D.vectoyaw(temp); - Init(); - Add(spot); - } + trail_head = NEXT(trail_head); + } - static edict_t PickFirst(edict_t self) { + static void New(float[] spot) { + if (!trail_active) + return; - if (!trail_active) - return null; + Init(); + Add(spot); + } - int marker= trail_head; + static edict_t PickFirst(edict_t self) { - for (int n= TRAIL_LENGTH; n > 0; n--) { - if (trail[marker].timestamp <= self.monsterinfo.trail_time) - marker= NEXT(marker); - else - break; - } + if (!trail_active) + return null; - if (visible(self, trail[marker])) { - return trail[marker]; - } + int marker = trail_head; - if (visible(self, trail[PREV(marker)])) { - return trail[PREV(marker)]; - } + for (int n = PlayerTrail.TRAIL_LENGTH; n > 0; n--) { + if (PlayerTrail.trail[marker].timestamp <= self.monsterinfo.trail_time) + marker = NEXT(marker); + else + break; + } - return trail[marker]; - } + if (GameUtil.visible(self, PlayerTrail.trail[marker])) { + return PlayerTrail.trail[marker]; + } - static edict_t PickNext(edict_t self) { - int marker; - int n; + if (GameUtil.visible(self, PlayerTrail.trail[PREV(marker)])) { + return PlayerTrail.trail[PREV(marker)]; + } - if (!trail_active) - return null; + return PlayerTrail.trail[marker]; + } - for (marker= trail_head, n= TRAIL_LENGTH; n > 0; n--) { - if (trail[marker].timestamp <= self.monsterinfo.trail_time) - marker= NEXT(marker); - else - break; - } + static edict_t PickNext(edict_t self) { + int marker; + int n; - return trail[marker]; - } + if (!trail_active) + return null; - static edict_t LastSpot() { - return trail[PREV(trail_head)]; - } + for (marker = trail_head, n = PlayerTrail.TRAIL_LENGTH; n > 0; n--) { + if (PlayerTrail.trail[marker].timestamp <= self.monsterinfo.trail_time) + marker = NEXT(marker); + else + break; + } + return PlayerTrail.trail[marker]; + } -} + static edict_t LastSpot() { + return PlayerTrail.trail[PREV(trail_head)]; + } +} \ No newline at end of file diff --git a/src/jake2/game/PlayerView.java b/src/jake2/game/PlayerView.java index 289aa0f..4fd338b 100644 --- a/src/jake2/game/PlayerView.java +++ b/src/jake2/game/PlayerView.java @@ -1,1054 +1,1068 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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.2 2004-09-22 19:22:03 salomo Exp $ +package jake2.game; -*/ +import jake2.Defines; +import jake2.Globals; +import jake2.util.Lib; +import jake2.util.Math3D; + +public class PlayerView { + + public static edict_t current_player; + + public static gclient_t current_client; + + public static float[] forward = { 0, 0, 0 }; + + public static float[] right = { 0, 0, 0 }; + + public static float[] up = { 0, 0, 0 }; + + /* + * =============== SV_CalcRoll + * + * =============== + */ + public static float SV_CalcRoll(float[] angles, float[] velocity) { + float sign; + float side; + float value; + + side = Math3D.DotProduct(velocity, right); + sign = side < 0 ? -1 : 1; + side = Math.abs(side); + + value = GameBase.sv_rollangle.value; + + if (side < GameBase.sv_rollspeed.value) + side = side * value / GameBase.sv_rollspeed.value; + else + side = value; + + return side * sign; + } + + /* + * =============== P_DamageFeedback + * + * Handles color blends and view kicks =============== + */ + + 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[Defines.STAT_FLASHES] = 0; + if (client.damage_blood != 0) + client.ps.stats[Defines.STAT_FLASHES] |= 1; + if (client.damage_armor != 0 + && 0 == (player.flags & Defines.FL_GODMODE) + && (client.invincible_framenum <= GameBase.level.framenum)) + client.ps.stats[Defines.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 < Defines.ANIM_PAIN) + & (player.s.modelindex == 255)) { + client.anim_priority = Defines.ANIM_PAIN; + if ((client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) { + player.s.frame = M_Player.FRAME_crpain1 - 1; + client.anim_end = M_Player.FRAME_crpain4; + } else { + + xxxi = (xxxi + 1) % 3; + switch (xxxi) { + case 0: + player.s.frame = M_Player.FRAME_pain101 - 1; + client.anim_end = M_Player.FRAME_pain104; + break; + case 1: + player.s.frame = M_Player.FRAME_pain201 - 1; + client.anim_end = M_Player.FRAME_pain204; + break; + case 2: + player.s.frame = M_Player.FRAME_pain301 - 1; + client.anim_end = M_Player.FRAME_pain304; + break; + } + } + } + + realcount = count; + if (count < 10) + count = 10; // always make a visible effect + + // play an apropriate pain sound + if ((GameBase.level.time > player.pain_debounce_time) + && 0 == (player.flags & Defines.FL_GODMODE) + && (client.invincible_framenum <= GameBase.level.framenum)) { + r = 1 + (Lib.rand() & 1); + player.pain_debounce_time = GameBase.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; + GameBase.gi.sound(player, Defines.CHAN_VOICE, GameBase.gi + .soundindex("*pain" + l + "_" + r + ".wav"), 1, + Defines.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 + Math3D.VectorClear(v); + if (client.damage_parmor != 0) + Math3D.VectorMA(v, (float) client.damage_parmor / realcount, + power_color, v); + + if (client.damage_armor != 0) + Math3D.VectorMA(v, (float) client.damage_armor / realcount, acolor, + v); + + if (client.damage_blood != 0) + Math3D.VectorMA(v, (float) client.damage_blood / realcount, bcolor, + v); + Math3D.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; + + Math3D.VectorSubtract(client.damage_from, player.s.origin, v); + Math3D.VectorNormalize(v); + + side = Math3D.DotProduct(v, right); + client.v_dmg_roll = kick * side * 0.3f; + + side = -Math3D.DotProduct(v, forward); + client.v_dmg_pitch = kick * side * 0.3f; + + client.v_dmg_time = GameBase.level.time + Defines.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) { + Math3D.VectorClear(angles); + + ent.client.ps.viewangles[Defines.ROLL] = 40; + ent.client.ps.viewangles[Defines.PITCH] = -15; + ent.client.ps.viewangles[Defines.YAW] = ent.client.killer_yaw; + } else { + // add angles based on weapon kick + + Math3D.VectorCopy(ent.client.kick_angles, angles); + + // add angles based on damage kick + + ratio = (ent.client.v_dmg_time - GameBase.level.time) + / Defines.DAMAGE_TIME; + if (ratio < 0) { + ratio = 0; + ent.client.v_dmg_pitch = 0; + ent.client.v_dmg_roll = 0; + } + angles[Defines.PITCH] += ratio * ent.client.v_dmg_pitch; + angles[Defines.ROLL] += ratio * ent.client.v_dmg_roll; + + // add pitch based on fall kick + + ratio = (ent.client.fall_time - GameBase.level.time) + / Defines.FALL_TIME; + if (ratio < 0) + ratio = 0; + angles[Defines.PITCH] += ratio * ent.client.fall_value; + + // add angles based on velocity + + delta = Math3D.DotProduct(ent.velocity, forward); + angles[Defines.PITCH] += delta * GameBase.run_pitch.value; + + delta = Math3D.DotProduct(ent.velocity, right); + angles[Defines.ROLL] += delta * GameBase.run_roll.value; + + // add angles based on bob + + delta = bobfracsin * GameBase.bob_pitch.value * xyspeed; + if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) + delta *= 6; // crouching + angles[Defines.PITCH] += delta; + delta = bobfracsin * GameBase.bob_roll.value * xyspeed; + if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) + delta *= 6; // crouching + if ((bobcycle & 1) != 0) + delta = -delta; + angles[Defines.ROLL] += delta; + } + + //=================================== + + // base origin + + Math3D.VectorClear(v); + + // add view height + + v[2] += ent.viewheight; + + // add fall height + + ratio = (ent.client.fall_time - GameBase.level.time) + / Defines.FALL_TIME; + if (ratio < 0) + ratio = 0; + v[2] -= ratio * ent.client.fall_value * 0.4; + + // add bob height + + bob = bobfracsin * xyspeed * GameBase.bob_up.value; + if (bob > 6) + bob = 6; + //gi.DebugGraph (bob *2, 255); + v[2] += bob; + + // add kick offset + + Math3D.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; + + Math3D.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[Defines.ROLL] = xyspeed * bobfracsin * 0.005f; + ent.client.ps.gunangles[Defines.YAW] = xyspeed * bobfracsin * 0.01f; + if ((bobcycle & 1) != 0) { + ent.client.ps.gunangles[Defines.ROLL] = -ent.client.ps.gunangles[Defines.ROLL]; + ent.client.ps.gunangles[Defines.YAW] = -ent.client.ps.gunangles[Defines.YAW]; + } + + ent.client.ps.gunangles[Defines.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 == Defines.YAW) + ent.client.ps.gunangles[Defines.ROLL] += 0.1 * delta; + ent.client.ps.gunangles[i] += 0.2 * delta; + } + + // gun height + Math3D.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] * (GameBase.gun_y.value); + ent.client.ps.gunoffset[i] += right[i] * GameBase.gun_x.value; + ent.client.ps.gunoffset[i] += up[i] * (-GameBase.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 + Math3D.VectorAdd(ent.s.origin, ent.client.ps.viewoffset, vieworg); + contents = GameBase.gi.pointcontents.pointcontents(vieworg); + if ((contents & (Defines.CONTENTS_LAVA | Defines.CONTENTS_SLIME | Defines.CONTENTS_WATER)) != 0) + ent.client.ps.rdflags |= Defines.RDF_UNDERWATER; + else + ent.client.ps.rdflags &= ~Defines.RDF_UNDERWATER; + + if ((contents & (Defines.CONTENTS_SOLID | Defines.CONTENTS_LAVA)) != 0) + SV_AddBlend(1.0f, 0.3f, 0.0f, 0.6f, ent.client.ps.blend); + else if ((contents & Defines.CONTENTS_SLIME) != 0) + SV_AddBlend(0.0f, 0.1f, 0.05f, 0.6f, ent.client.ps.blend); + else if ((contents & Defines.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 > GameBase.level.framenum) { + remaining = (int) (ent.client.quad_framenum - GameBase.level.framenum); + if (remaining == 30) // beginning to fade + GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/damage2.wav"), 1, Defines.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 > GameBase.level.framenum) { + remaining = (int) ent.client.invincible_framenum + - GameBase.level.framenum; + if (remaining == 30) // beginning to fade + GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/protect2.wav"), 1, + Defines.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 > GameBase.level.framenum) { + remaining = (int) ent.client.enviro_framenum + - GameBase.level.framenum; + if (remaining == 30) // beginning to fade + GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/airout.wav"), 1, Defines.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 > GameBase.level.framenum) { + remaining = (int) ent.client.breather_framenum + - GameBase.level.framenum; + if (remaining == 30) // beginning to fade + GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi + .soundindex("items/airout.wav"), 1, Defines.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 == Defines.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 = Defines.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 = GameBase.level.time + Defines.FALL_TIME; + + if (delta > 30) { + if (ent.health > 0) { + if (delta >= 55) + ent.s.event = Defines.EV_FALLFAR; + else + ent.s.event = Defines.EV_FALL; + } + ent.pain_debounce_time = GameBase.level.time; // no normal pain + // sound + damage = (int) ((delta - 30) / 2); + if (damage < 1) + damage = 1; + Math3D.VectorSet(dir, 0, 0, 1); + + if (GameBase.deathmatch.value == 0 + || 0 == ((int) GameBase.dmflags.value & Defines.DF_NO_FALLING)) + GameUtil.T_Damage(ent, GameBase.g_edicts[0], + GameBase.g_edicts[0], dir, ent.s.origin, + Globals.vec3_origin, damage, 0, 0, Defines.MOD_FALLING); + } else { + ent.s.event = Defines.EV_FALLSHORT; + return; + } + } + + /* + * ============= P_WorldEffects ============= + */ + public static void P_WorldEffects() { + boolean breather; + boolean envirosuit; + int waterlevel, old_waterlevel; + + if (current_player.movetype == Defines.MOVETYPE_NOCLIP) { + current_player.air_finished = GameBase.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 > GameBase.level.framenum; + envirosuit = current_client.enviro_framenum > GameBase.level.framenum; + + // + // if just entered a water volume, play a sound + // + if (old_waterlevel == 0 && waterlevel != 0) { + GameWeapon.PlayerNoise(current_player, current_player.s.origin, + Defines.PNOISE_SELF); + if ((current_player.watertype & Defines.CONTENTS_LAVA) != 0) + GameBase.gi.sound(current_player, Defines.CHAN_BODY, + GameBase.gi.soundindex("player/lava_in.wav"), 1, + Defines.ATTN_NORM, 0); + else if ((current_player.watertype & Defines.CONTENTS_SLIME) != 0) + GameBase.gi.sound(current_player, Defines.CHAN_BODY, + GameBase.gi.soundindex("player/watr_in.wav"), 1, + Defines.ATTN_NORM, 0); + else if ((current_player.watertype & Defines.CONTENTS_WATER) != 0) + GameBase.gi.sound(current_player, Defines.CHAN_BODY, + GameBase.gi.soundindex("player/watr_in.wav"), 1, + Defines.ATTN_NORM, 0); + current_player.flags |= Defines.FL_INWATER; + + // clear damage_debounce, so the pain sound will play immediately + current_player.damage_debounce_time = GameBase.level.time - 1; + } + + // + // if just completely exited a water volume, play a sound + // + if (old_waterlevel != 0 && waterlevel == 0) { + GameWeapon.PlayerNoise(current_player, current_player.s.origin, + Defines.PNOISE_SELF); + GameBase.gi + .sound(current_player, Defines.CHAN_BODY, GameBase.gi + .soundindex("player/watr_out.wav"), 1, + Defines.ATTN_NORM, 0); + current_player.flags &= ~Defines.FL_INWATER; + } + + // + // check for head just going under water + // + if (old_waterlevel != 3 && waterlevel == 3) { + GameBase.gi.sound(current_player, Defines.CHAN_BODY, GameBase.gi + .soundindex("player/watr_un.wav"), 1, Defines.ATTN_NORM, 0); + } + + // + // check for head just coming out of water + // + if (old_waterlevel == 3 && waterlevel != 3) { + if (current_player.air_finished < GameBase.level.time) { // gasp for + // air + GameBase.gi.sound(current_player, Defines.CHAN_VOICE, + GameBase.gi.soundindex("player/gasp1.wav"), 1, + Defines.ATTN_NORM, 0); + GameWeapon.PlayerNoise(current_player, current_player.s.origin, + Defines.PNOISE_SELF); + } else if (current_player.air_finished < GameBase.level.time + 11) { // just + // break + // surface + GameBase.gi.sound(current_player, Defines.CHAN_VOICE, + GameBase.gi.soundindex("player/gasp2.wav"), 1, + Defines.ATTN_NORM, 0); + } + } + + // + // check for drowning + // + if (waterlevel == 3) { + // breather or envirosuit give air + if (breather || envirosuit) { + current_player.air_finished = GameBase.level.time + 10; + + if (((int) (current_client.breather_framenum - GameBase.level.framenum) % 25) == 0) { + if (current_client.breather_sound == 0) + GameBase.gi.sound(current_player, Defines.CHAN_AUTO, + GameBase.gi.soundindex("player/u_breath1.wav"), + 1, Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(current_player, Defines.CHAN_AUTO, + GameBase.gi.soundindex("player/u_breath2.wav"), + 1, Defines.ATTN_NORM, 0); + current_client.breather_sound ^= 1; + GameWeapon.PlayerNoise(current_player, + current_player.s.origin, Defines.PNOISE_SELF); + //FIXME: release a bubble? + } + } + + // if out of air, start drowning + if (current_player.air_finished < GameBase.level.time) { // drown! + if (current_player.client.next_drown_time < GameBase.level.time + && current_player.health > 0) { + current_player.client.next_drown_time = GameBase.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) + GameBase.gi.sound(current_player, Defines.CHAN_VOICE, + GameBase.gi.soundindex("player/drown1.wav"), 1, + Defines.ATTN_NORM, 0); + else if ((Lib.rand() & 1) != 0) + GameBase.gi.sound(current_player, Defines.CHAN_VOICE, + GameBase.gi.soundindex("*gurp1.wav"), 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(current_player, Defines.CHAN_VOICE, + GameBase.gi.soundindex("*gurp2.wav"), 1, + Defines.ATTN_NORM, 0); + + current_player.pain_debounce_time = GameBase.level.time; + + GameUtil.T_Damage(current_player, GameBase.g_edicts[0], + GameBase.g_edicts[0], Globals.vec3_origin, + current_player.s.origin, Globals.vec3_origin, + current_player.dmg, 0, Defines.DAMAGE_NO_ARMOR, + Defines.MOD_WATER); + } + } + } else { + current_player.air_finished = GameBase.level.time + 12; + current_player.dmg = 2; + } + + // + // check for sizzle damage + // + if (waterlevel != 0 + && 0 != (current_player.watertype & (Defines.CONTENTS_LAVA | Defines.CONTENTS_SLIME))) { + if ((current_player.watertype & Defines.CONTENTS_LAVA) != 0) { + if (current_player.health > 0 + && current_player.pain_debounce_time <= GameBase.level.time + && current_client.invincible_framenum < GameBase.level.framenum) { + if ((Lib.rand() & 1) != 0) + GameBase.gi.sound(current_player, Defines.CHAN_VOICE, + GameBase.gi.soundindex("player/burn1.wav"), 1, + Defines.ATTN_NORM, 0); + else + GameBase.gi.sound(current_player, Defines.CHAN_VOICE, + GameBase.gi.soundindex("player/burn2.wav"), 1, + Defines.ATTN_NORM, 0); + current_player.pain_debounce_time = GameBase.level.time + 1; + } + + if (envirosuit) // take 1/3 damage with envirosuit + GameUtil.T_Damage(current_player, GameBase.g_edicts[0], + GameBase.g_edicts[0], Globals.vec3_origin, + current_player.s.origin, Globals.vec3_origin, + 1 * waterlevel, 0, 0, Defines.MOD_LAVA); + else + GameUtil.T_Damage(current_player, GameBase.g_edicts[0], + GameBase.g_edicts[0], Globals.vec3_origin, + current_player.s.origin, Globals.vec3_origin, + 3 * waterlevel, 0, 0, Defines.MOD_LAVA); + } + + if ((current_player.watertype & Defines.CONTENTS_SLIME) != 0) { + if (!envirosuit) { // no damage from slime with envirosuit + GameUtil.T_Damage(current_player, GameBase.g_edicts[0], + GameBase.g_edicts[0], Globals.vec3_origin, + current_player.s.origin, Globals.vec3_origin, + 1 * waterlevel, 0, 0, Defines.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 || GameBase.level.intermissiontime != 0) + return; + + if (ent.powerarmor_time > GameBase.level.time) { + pa_type = GameUtil.PowerArmorType(ent); + if (pa_type == Defines.POWER_ARMOR_SCREEN) { + ent.s.effects |= Defines.EF_POWERSCREEN; + } else if (pa_type == Defines.POWER_ARMOR_SHIELD) { + ent.s.effects |= Defines.EF_COLOR_SHELL; + ent.s.renderfx |= Defines.RF_SHELL_GREEN; + } + } + + if (ent.client.quad_framenum > GameBase.level.framenum) { + remaining = (int) ent.client.quad_framenum + - GameBase.level.framenum; + if (remaining > 30 || 0 != (remaining & 4)) + ent.s.effects |= Defines.EF_QUAD; + } + + if (ent.client.invincible_framenum > GameBase.level.framenum) { + remaining = (int) ent.client.invincible_framenum + - GameBase.level.framenum; + if (remaining > 30 || 0 != (remaining & 4)) + ent.s.effects |= Defines.EF_PENT; + } + + // show cheaters!!! + if ((ent.flags & Defines.FL_GODMODE) != 0) { + ent.s.effects |= Defines.EF_COLOR_SHELL; + ent.s.renderfx |= (Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.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 = Defines.EV_FOOTSTEP; + } + } + + /* + * =============== G_SetClientSound =============== + */ + public static void G_SetClientSound(edict_t ent) { + String weap; + + if (ent.client.pers.game_helpchanged != GameBase.game.helpchanged) { + ent.client.pers.game_helpchanged = GameBase.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 == (GameBase.level.framenum & 63)) { + ent.client.pers.helpchanged++; + GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi + .soundindex("misc/pc_up.wav"), 1, Defines.ATTN_STATIC, 0); + } + + if (ent.client.pers.weapon != null) + weap = ent.client.pers.weapon.classname; + else + weap = ""; + + if (ent.waterlevel != 0 + && 0 != (ent.watertype & (Defines.CONTENTS_LAVA | Defines.CONTENTS_SLIME))) + ent.s.sound = GameBase.snd_fry; + else if (Lib.strcmp(weap, "weapon_railgun") == 0) + ent.s.sound = GameBase.gi.soundindex("weapons/rg_hum.wav"); + else if (Lib.strcmp(weap, "weapon_bfg") == 0) + ent.s.sound = GameBase.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 & pmove_t.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 < Defines.ANIM_DEATH) + skip = true; + + if (run != client.anim_run + && client.anim_priority == Defines.ANIM_BASIC) + skip = true; + + if (null == ent.groundentity + && client.anim_priority <= Defines.ANIM_WAVE) + skip = true; + + if (!skip) { + if (client.anim_priority == Defines.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 == Defines.ANIM_DEATH) + return; // stay there + if (client.anim_priority == Defines.ANIM_JUMP) { + if (null == ent.groundentity) + return; // stay there + ent.client.anim_priority = Defines.ANIM_WAVE; + ent.s.frame = M_Player.FRAME_jump3; + ent.client.anim_end = M_Player.FRAME_jump6; + return; + } + } + + // return to either a running or standing frame + client.anim_priority = Defines.ANIM_BASIC; + client.anim_duck = duck; + client.anim_run = run; + + if (null == ent.groundentity) { + client.anim_priority = Defines.ANIM_JUMP; + if (ent.s.frame != M_Player.FRAME_jump2) + ent.s.frame = M_Player.FRAME_jump1; + client.anim_end = M_Player.FRAME_jump2; + } else if (run) { // running + if (duck) { + ent.s.frame = M_Player.FRAME_crwalk1; + client.anim_end = M_Player.FRAME_crwalk6; + } else { + ent.s.frame = M_Player.FRAME_run1; + client.anim_end = M_Player.FRAME_run6; + } + } else { // standing + if (duck) { + ent.s.frame = M_Player.FRAME_crstnd01; + client.anim_end = M_Player.FRAME_crstnd19; + } else { + ent.s.frame = M_Player.FRAME_stand01; + client.anim_end = M_Player.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 (GameBase.level.intermissiontime != 0) { + // FIXME: add view drifting here? + current_client.ps.blend[3] = 0; + current_client.ps.fov = 90; + PlayerHud.G_SetStats(ent); + return; + } + + Math3D.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[Defines.PITCH] > 180) + ent.s.angles[Defines.PITCH] = (-360 + ent.client.v_angle[Defines.PITCH]) / 3; + else + ent.s.angles[Defines.PITCH] = ent.client.v_angle[Defines.PITCH] / 3; + ent.s.angles[Defines.YAW] = ent.client.v_angle[Defines.YAW]; + ent.s.angles[Defines.ROLL] = 0; + ent.s.angles[Defines.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 & pmove_t.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) + PlayerHud.G_SetSpectatorStats(ent); + else + PlayerHud.G_SetStats(ent); + PlayerHud.G_CheckChaseStats(ent); + + G_SetClientEvent(ent); + + G_SetClientEffects(ent); + + G_SetClientSound(ent); + + G_SetClientFrame(ent); + + Math3D.VectorCopy(ent.velocity, ent.client.oldvelocity); + Math3D.VectorCopy(ent.client.ps.viewangles, ent.client.oldviewangles); + + // clear weapon kicks + Math3D.VectorClear(ent.client.kick_origin); + Math3D.VectorClear(ent.client.kick_angles); + + // if the scoreboard is up, update it + if (ent.client.showscores && 0 == (GameBase.level.framenum & 31)) { + PlayerHud.DeathmatchScoreboardMessage(ent, ent.enemy); + GameBase.gi.unicast(ent, false); + } + } + + public static float xyspeed; + + public static float bobmove; -// Created on 28.12.2003 by RST. -// $Id: PlayerView.java,v 1.1 2004-07-07 19:59:24 hzi Exp $ + public static int bobcycle; // odd cycles are right foot going forward -package jake2.game; + public static float bobfracsin; // sin(bobfrac*M_PI)} -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); - } - } -} + private static int xxxi = 0; +} \ No newline at end of file diff --git a/src/jake2/game/edict_t.java b/src/jake2/game/edict_t.java index 0de35df..274db25 100644 --- a/src/jake2/game/edict_t.java +++ b/src/jake2/game/edict_t.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 04.11.2003 by RST. -// $Id: edict_t.java,v 1.5 2004-09-04 19:08:30 salomo Exp $ - +// $Id: edict_t.java,v 1.6 2004-09-22 19:22:01 salomo Exp $ package jake2.game; import java.io.IOException; @@ -31,681 +30,746 @@ import jake2.util.*; public class edict_t { - /** Constructor. */ - public edict_t(int i) { - s.number= i; - index= i; - } - - /** Used during level loading. */ - public void cleararealinks() { - area= new link_t(this); - } - - /** 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. - * linked to a division node or leaf. */ - public link_t area= new link_t(this); - - /** if -1, use headnode instead.*/ - public int num_clusters; - public int clusternums[]= new int[Defines.MAX_ENT_CLUSTERS]; - - /** unused if num_clusters != -1. */ - public int headnode; - public int areanum, areanum2; - - //================================ - - /** SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc. */ - public int svflags; - 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; - - //================================ - public int movetype; - public int flags; - - public String model= null; - - /** sv.time when the object was freed. */ - public float freetime; - - // - // only used locally in game, not by server - // - public String message= null; - 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; - - /** per entity gravity multiplier (1.0 is normal). */ - public float gravity; - /** use for lowgrav artifact, flares. */ + /** Constructor. */ + public edict_t(int i) { + s.number = i; + index = i; + } + + /** Used during level loading. */ + public void cleararealinks() { + area = new link_t(this); + } + + /** 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. linked to a + * division node or leaf. + */ + public link_t area = new link_t(this); + + /** if -1, use headnode instead. */ + public int num_clusters; + + public int clusternums[] = new int[Defines.MAX_ENT_CLUSTERS]; + + /** unused if num_clusters != -1. */ + public int headnode; + + public int areanum, areanum2; + + //================================ + + /** SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc. */ + public int svflags; + + 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; + + //================================ + public int movetype; + + public int flags; + + public String model = null; + + /** sv.time when the object was freed. */ + public float freetime; + + // + // only used locally in game, not by server + // + public String message = null; + + 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; + + /** per entity gravity multiplier (1.0 is normal). */ + public float gravity; + + /** 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; + + /** Are all these legit? do we need more/less of them? */ + public float touch_debounce_time; + + public float pain_debounce_time; + + public float damage_debounce_time; + + /** Move to clientinfo. */ + public float fly_sound_debounce_time; + + 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; + + /** target_changelevel. */ + public String map = null; + + /** Height above origin where eyesight is determined. */ + public int viewheight; + + public int takedamage; + + public int dmg; + + public int radius_dmg; + + public float dmg_radius; + + /** make this a spawntemp var? */ + public int sounds; + + 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; + + /** can go in client only. */ + public edict_t mynoise = null; + + public edict_t mynoise2 = null; + + public int noise_index; + + public int noise_index2; + + public float volume; + + public float attenuation; + + /** Timing variables. */ + public float wait; + + /** before firing targets... */ + public float delay; + + 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; + + /** also used as areaportal number. */ + public int style; + + 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; + + /** Introduced by rst. */ + public int index; + + ///////////////////////////////////////////////// + + 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), - public edict_t goalentity= null; - public edict_t movetarget= null; - public float yaw_speed; - public float ideal_yaw; - - public float nextthink; + 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), - 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; - - /** Are all these legit? do we need more/less of them? */ - public float touch_debounce_time; - public float pain_debounce_time; - public float damage_debounce_time; - - /** Move to clientinfo.*/ - public float fly_sound_debounce_time; - 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; - - /** target_changelevel. */ - public String map= null; - - /** Height above origin where eyesight is determined. */ - public int viewheight; - public int takedamage; - public int dmg; - public int radius_dmg; - public float dmg_radius; - - /** make this a spawntemp var? */ - public int sounds; - 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; - - /** can go in client only. */ - public edict_t mynoise= null; - public edict_t mynoise2= null; - - public int noise_index; - public int noise_index2; - public float volume; - public float attenuation; - - /** Timing variables. */ - public float wait; - /** before firing targets...*/ - public float delay; - 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; - - /** also used as areaportal number. */ - public int style; - - 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; - - /** Introduced by rst. */ - public int index; - - ///////////////////////////////////////////////// - - 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), - - if (key.equals("item")) { - Game.gi.error("ent.set(\"item\") called."); - return true; - } // F_ITEM) - - return false; - } - - /** Writes the entity to the file. */ - public void write(QuakeFile f) throws IOException { - - s.write(f); - f.writeBoolean(inuse); - f.writeInt(linkcount); - f.writeInt(num_clusters); - - f.writeInt(9999); - - if (clusternums == null) - f.writeInt(-1); - else { - f.writeInt(Defines.MAX_ENT_CLUSTERS); - for (int n= 0; n < Defines.MAX_ENT_CLUSTERS; n++) - f.writeInt(clusternums[n]); - - } - f.writeInt(headnode); - f.writeInt(areanum); - f.writeInt(areanum2); - f.writeInt(svflags); - f.writeVector(mins); - f.writeVector(maxs); - f.writeVector(absmin); - f.writeVector(absmax); - f.writeVector(size); - f.writeInt(solid); - f.writeInt(clipmask); - - f.writeInt(movetype); - f.writeInt(flags); - - f.writeString(model); - f.writeFloat(freetime); - f.writeString(message); - f.writeString(classname); - f.writeInt(spawnflags); - f.writeFloat(timestamp); - - f.writeFloat(angle); - - f.writeString(target); - f.writeString(targetname); - f.writeString(killtarget); - f.writeString(team); - f.writeString(pathtarget); - f.writeString(deathtarget); - f.writeString(combattarget); - - f.writeEdictRef(target_ent); - - f.writeFloat(speed); - f.writeFloat(accel); - f.writeFloat(decel); - - f.writeVector(movedir); - - f.writeVector(pos1); - f.writeVector(pos2); - - f.writeVector(velocity); - f.writeVector(avelocity); - - f.writeInt(mass); - f.writeFloat(air_finished); - - f.writeFloat(gravity); - - f.writeEdictRef(goalentity); - f.writeEdictRef(movetarget); + 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), + + if (key.equals("item")) { + GameBase.gi.error("ent.set(\"item\") called."); + return true; + } // F_ITEM) + + return false; + } + + /** Writes the entity to the file. */ + public void write(QuakeFile f) throws IOException { + + s.write(f); + f.writeBoolean(inuse); + f.writeInt(linkcount); + f.writeInt(num_clusters); + + f.writeInt(9999); + + if (clusternums == null) + f.writeInt(-1); + else { + f.writeInt(Defines.MAX_ENT_CLUSTERS); + for (int n = 0; n < Defines.MAX_ENT_CLUSTERS; n++) + f.writeInt(clusternums[n]); + + } + f.writeInt(headnode); + f.writeInt(areanum); + f.writeInt(areanum2); + f.writeInt(svflags); + f.writeVector(mins); + f.writeVector(maxs); + f.writeVector(absmin); + f.writeVector(absmax); + f.writeVector(size); + f.writeInt(solid); + f.writeInt(clipmask); + + f.writeInt(movetype); + f.writeInt(flags); + + f.writeString(model); + f.writeFloat(freetime); + f.writeString(message); + f.writeString(classname); + f.writeInt(spawnflags); + f.writeFloat(timestamp); + + f.writeFloat(angle); + + f.writeString(target); + f.writeString(targetname); + f.writeString(killtarget); + f.writeString(team); + f.writeString(pathtarget); + f.writeString(deathtarget); + f.writeString(combattarget); + + f.writeEdictRef(target_ent); + + f.writeFloat(speed); + f.writeFloat(accel); + f.writeFloat(decel); + + f.writeVector(movedir); + + f.writeVector(pos1); + f.writeVector(pos2); + + f.writeVector(velocity); + f.writeVector(avelocity); + + f.writeInt(mass); + f.writeFloat(air_finished); + + f.writeFloat(gravity); + + f.writeEdictRef(goalentity); + f.writeEdictRef(movetarget); - f.writeFloat(yaw_speed); - f.writeFloat(ideal_yaw); - - f.writeFloat(nextthink); - - f.writeAdapter(prethink); - f.writeAdapter(think); - f.writeAdapter(blocked); - - f.writeAdapter(touch); - f.writeAdapter(use); - f.writeAdapter(pain); - f.writeAdapter(die); - - f.writeFloat(touch_debounce_time); - f.writeFloat(pain_debounce_time); - f.writeFloat(damage_debounce_time); - - f.writeFloat(fly_sound_debounce_time); - f.writeFloat(last_move_time); - - f.writeInt(health); - f.writeInt(max_health); - - f.writeInt(gib_health); - f.writeInt(deadflag); - f.writeInt(show_hostile); - - f.writeFloat(powerarmor_time); - - f.writeString(map); - - f.writeInt(viewheight); - f.writeInt(takedamage); - f.writeInt(dmg); - f.writeInt(radius_dmg); - f.writeFloat(dmg_radius); - - f.writeInt(sounds); - f.writeInt(count); - - f.writeEdictRef(chain); - f.writeEdictRef(enemy); - f.writeEdictRef(oldenemy); - f.writeEdictRef(activator); - f.writeEdictRef(groundentity); - f.writeInt(groundentity_linkcount); - f.writeEdictRef(teamchain); - f.writeEdictRef(teammaster); - - f.writeEdictRef(mynoise); - f.writeEdictRef(mynoise2); + f.writeFloat(yaw_speed); + f.writeFloat(ideal_yaw); + + f.writeFloat(nextthink); + + f.writeAdapter(prethink); + f.writeAdapter(think); + f.writeAdapter(blocked); + + f.writeAdapter(touch); + f.writeAdapter(use); + f.writeAdapter(pain); + f.writeAdapter(die); + + f.writeFloat(touch_debounce_time); + f.writeFloat(pain_debounce_time); + f.writeFloat(damage_debounce_time); + + f.writeFloat(fly_sound_debounce_time); + f.writeFloat(last_move_time); + + f.writeInt(health); + f.writeInt(max_health); + + f.writeInt(gib_health); + f.writeInt(deadflag); + f.writeInt(show_hostile); + + f.writeFloat(powerarmor_time); + + f.writeString(map); + + f.writeInt(viewheight); + f.writeInt(takedamage); + f.writeInt(dmg); + f.writeInt(radius_dmg); + f.writeFloat(dmg_radius); + + f.writeInt(sounds); + f.writeInt(count); + + f.writeEdictRef(chain); + f.writeEdictRef(enemy); + f.writeEdictRef(oldenemy); + f.writeEdictRef(activator); + f.writeEdictRef(groundentity); + f.writeInt(groundentity_linkcount); + f.writeEdictRef(teamchain); + f.writeEdictRef(teammaster); + + f.writeEdictRef(mynoise); + f.writeEdictRef(mynoise2); - f.writeInt(noise_index); - f.writeInt(noise_index2); + f.writeInt(noise_index); + f.writeInt(noise_index2); - f.writeFloat(volume); - f.writeFloat(attenuation); - f.writeFloat(wait); - f.writeFloat(delay); - f.writeFloat(random); + f.writeFloat(volume); + f.writeFloat(attenuation); + f.writeFloat(wait); + f.writeFloat(delay); + f.writeFloat(random); - f.writeFloat(teleport_time); + f.writeFloat(teleport_time); - f.writeInt(watertype); - f.writeInt(waterlevel); - f.writeVector(move_origin); - f.writeVector(move_angles); + f.writeInt(watertype); + f.writeInt(waterlevel); + f.writeVector(move_origin); + f.writeVector(move_angles); - f.writeInt(light_level); - f.writeInt(style); + f.writeInt(light_level); + f.writeInt(style); - f.writeItem(item); + f.writeItem(item); - moveinfo.write(f); - monsterinfo.write(f); - if (client == null) - f.writeInt(-1); - else - f.writeInt(client.index); + moveinfo.write(f); + monsterinfo.write(f); + if (client == null) + f.writeInt(-1); + else + f.writeInt(client.index); - f.writeEdictRef(owner); + f.writeEdictRef(owner); - // rst's checker :-) - f.writeInt(9876); - } + // rst's checker :-) + f.writeInt(9876); + } - /** Reads the entity from the file.*/ - public void read(QuakeFile f) throws IOException { - s.read(f); - inuse= f.readBoolean(); - linkcount= f.readInt(); - num_clusters= f.readInt(); + /** Reads the entity from the file. */ + public void read(QuakeFile f) throws IOException { + s.read(f); + inuse = f.readBoolean(); + linkcount = f.readInt(); + num_clusters = f.readInt(); - if (f.readInt() != 9999) - new Throwable("wrong read pos!").printStackTrace(); + if (f.readInt() != 9999) + new Throwable("wrong read pos!").printStackTrace(); - int len= f.readInt(); + int len = f.readInt(); - if (len == -1) - clusternums= null; - else { - clusternums= new int[Defines.MAX_ENT_CLUSTERS]; - for (int n= 0; n < Defines.MAX_ENT_CLUSTERS; n++) - clusternums[n]= f.readInt(); - } + if (len == -1) + clusternums = null; + else { + clusternums = new int[Defines.MAX_ENT_CLUSTERS]; + for (int n = 0; n < Defines.MAX_ENT_CLUSTERS; n++) + clusternums[n] = f.readInt(); + } - headnode= f.readInt(); - areanum= f.readInt(); - areanum2= f.readInt(); - svflags= f.readInt(); - mins= f.readVector(); - maxs= f.readVector(); - absmin= f.readVector(); - absmax= f.readVector(); - size= f.readVector(); - solid= f.readInt(); - clipmask= f.readInt(); + headnode = f.readInt(); + areanum = f.readInt(); + areanum2 = f.readInt(); + svflags = f.readInt(); + mins = f.readVector(); + maxs = f.readVector(); + absmin = f.readVector(); + absmax = f.readVector(); + size = f.readVector(); + solid = f.readInt(); + clipmask = f.readInt(); - movetype= f.readInt(); - flags= f.readInt(); + movetype = f.readInt(); + flags = f.readInt(); - model= f.readString(); - freetime= f.readFloat(); - message= f.readString(); - classname= f.readString(); - spawnflags= f.readInt(); - timestamp= f.readFloat(); + model = f.readString(); + freetime = f.readFloat(); + message = f.readString(); + classname = f.readString(); + spawnflags = f.readInt(); + timestamp = f.readFloat(); - angle= f.readFloat(); + angle = f.readFloat(); - target= f.readString(); - targetname= f.readString(); - killtarget= f.readString(); - team= f.readString(); - pathtarget= f.readString(); - deathtarget= f.readString(); - combattarget= f.readString(); + target = f.readString(); + targetname = f.readString(); + killtarget = f.readString(); + team = f.readString(); + pathtarget = f.readString(); + deathtarget = f.readString(); + combattarget = f.readString(); - target_ent= f.readEdictRef(); + target_ent = f.readEdictRef(); - speed= f.readFloat(); - accel= f.readFloat(); - decel= f.readFloat(); + speed = f.readFloat(); + accel = f.readFloat(); + decel = f.readFloat(); - movedir= f.readVector(); + movedir = f.readVector(); - pos1= f.readVector(); - pos2= f.readVector(); + pos1 = f.readVector(); + pos2 = f.readVector(); - velocity= f.readVector(); - avelocity= f.readVector(); + velocity = f.readVector(); + avelocity = f.readVector(); - mass= f.readInt(); - air_finished= f.readFloat(); + mass = f.readInt(); + air_finished = f.readFloat(); - gravity= f.readFloat(); + gravity = f.readFloat(); - goalentity= f.readEdictRef(); - movetarget= f.readEdictRef(); + goalentity = f.readEdictRef(); + movetarget = f.readEdictRef(); - yaw_speed= f.readFloat(); - ideal_yaw= f.readFloat(); + yaw_speed = f.readFloat(); + ideal_yaw = f.readFloat(); - nextthink= f.readFloat(); + nextthink = f.readFloat(); - prethink= (EntThinkAdapter) f.readAdapter(); - think= (EntThinkAdapter) f.readAdapter(); - blocked= (EntBlockedAdapter) f.readAdapter(); + prethink = (EntThinkAdapter) f.readAdapter(); + think = (EntThinkAdapter) f.readAdapter(); + blocked = (EntBlockedAdapter) f.readAdapter(); - touch= (EntTouchAdapter) f.readAdapter(); - use= (EntUseAdapter) f.readAdapter(); - pain= (EntPainAdapter) f.readAdapter(); - die= (EntDieAdapter) f.readAdapter(); + touch = (EntTouchAdapter) f.readAdapter(); + use = (EntUseAdapter) f.readAdapter(); + pain = (EntPainAdapter) f.readAdapter(); + die = (EntDieAdapter) f.readAdapter(); - touch_debounce_time= f.readFloat(); - pain_debounce_time= f.readFloat(); - damage_debounce_time= f.readFloat(); + touch_debounce_time = f.readFloat(); + pain_debounce_time = f.readFloat(); + damage_debounce_time = f.readFloat(); - fly_sound_debounce_time= f.readFloat(); - last_move_time= f.readFloat(); + fly_sound_debounce_time = f.readFloat(); + last_move_time = f.readFloat(); - health= f.readInt(); - max_health= f.readInt(); + health = f.readInt(); + max_health = f.readInt(); - gib_health= f.readInt(); - deadflag= f.readInt(); - show_hostile= f.readInt(); + gib_health = f.readInt(); + deadflag = f.readInt(); + show_hostile = f.readInt(); - powerarmor_time= f.readFloat(); + powerarmor_time = f.readFloat(); - map= f.readString(); + map = f.readString(); - viewheight= f.readInt(); - takedamage= f.readInt(); - dmg= f.readInt(); - radius_dmg= f.readInt(); - dmg_radius= f.readFloat(); + viewheight = f.readInt(); + takedamage = f.readInt(); + dmg = f.readInt(); + radius_dmg = f.readInt(); + dmg_radius = f.readFloat(); - sounds= f.readInt(); - count= f.readInt(); + sounds = f.readInt(); + count = f.readInt(); - chain= f.readEdictRef(); - enemy= f.readEdictRef(); + chain = f.readEdictRef(); + enemy = f.readEdictRef(); - oldenemy= f.readEdictRef(); - activator= f.readEdictRef(); - groundentity= f.readEdictRef(); + oldenemy = f.readEdictRef(); + activator = f.readEdictRef(); + groundentity = f.readEdictRef(); - groundentity_linkcount= f.readInt(); - teamchain= f.readEdictRef(); - teammaster= f.readEdictRef(); + groundentity_linkcount = f.readInt(); + teamchain = f.readEdictRef(); + teammaster = f.readEdictRef(); - mynoise= f.readEdictRef(); - mynoise2= f.readEdictRef(); + mynoise = f.readEdictRef(); + mynoise2 = f.readEdictRef(); - noise_index= f.readInt(); - noise_index2= f.readInt(); + noise_index = f.readInt(); + noise_index2 = f.readInt(); - volume= f.readFloat(); - attenuation= f.readFloat(); - wait= f.readFloat(); - delay= f.readFloat(); - random= f.readFloat(); + volume = f.readFloat(); + attenuation = f.readFloat(); + wait = f.readFloat(); + delay = f.readFloat(); + random = f.readFloat(); - teleport_time= f.readFloat(); + teleport_time = f.readFloat(); - watertype= f.readInt(); - waterlevel= f.readInt(); - move_origin= f.readVector(); - move_angles= f.readVector(); + watertype = f.readInt(); + waterlevel = f.readInt(); + move_origin = f.readVector(); + move_angles = f.readVector(); - light_level= f.readInt(); - style= f.readInt(); + light_level = f.readInt(); + style = f.readInt(); - item= f.readItem(); + item = f.readItem(); - moveinfo.read(f); - monsterinfo.read(f); + moveinfo.read(f); + monsterinfo.read(f); - int ndx= f.readInt(); - if (ndx == -1) - client= null; - else - client= Game.game.clients[ndx]; + int ndx = f.readInt(); + if (ndx == -1) + client = null; + else + client = GameBase.game.clients[ndx]; - owner= f.readEdictRef(); + owner = f.readEdictRef(); - // rst's checker :-) - if (f.readInt() != 9876) - System.err.println("ent load check failed for num " + index); - } -} + // rst's checker :-) + if (f.readInt() != 9876) + System.err.println("ent load check failed for num " + index); + } +} \ No newline at end of file diff --git a/src/jake2/game/game_import_t.java b/src/jake2/game/game_import_t.java index 940867f..2fcadbe 100644 --- a/src/jake2/game/game_import_t.java +++ b/src/jake2/game/game_import_t.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 31.10.2003 by RST. -// $Id: game_import_t.java,v 1.3 2004-08-22 14:25:11 salomo Exp $ - +// $Id: game_import_t.java,v 1.4 2004-09-22 19:22:00 salomo Exp $ package jake2.game; import jake2.Defines; @@ -38,242 +37,213 @@ import jake2.server.SV_WORLD; // // collection of functions provided by the main engine // -public class game_import_t -{ - // 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); - } -} +public class game_import_t { + // special messages + public void bprintf(int printlevel, String s) { + SV_SEND.SV_BroadcastPrintf(printlevel, s); + } + + public void dprintf(String s) { + SV_GAME.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); + } +} \ No newline at end of file diff --git a/src/jake2/game/game_locals_t.java b/src/jake2/game/game_locals_t.java index 679bbd2..85c67f0 100644 --- a/src/jake2/game/game_locals_t.java +++ b/src/jake2/game/game_locals_t.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 31.10.2003 by RST. -// $Id: game_locals_t.java,v 1.6 2004-09-10 19:02:54 salomo Exp $ - +// $Id: game_locals_t.java,v 1.7 2004-09-22 19:22:06 salomo Exp $ package jake2.game; import jake2.Defines; @@ -33,78 +32,80 @@ import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.Date; -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; - - /** Reads the game locals from a file. */ - public void load(QuakeFile f) throws IOException - { - String date = f.readString(); - - helpmessage1 = f.readString(); - helpmessage2 = f.readString(); - - helpchanged = f.readInt(); - // gclient_t* - - spawnpoint = f.readString(); - maxclients = f.readInt(); - maxentities = f.readInt(); - serverflags = f.readInt(); - num_items = f.readInt(); - autosaved = f.readInt() != 0; - - // rst's checker :-) - if (f.readInt()!=1928) - Com.DPrintf("error in loading game_locals, 1928\n"); - - } - - /** Writes the game locals to a file. */ - public void write(QuakeFile f) throws IOException - { - f.writeString(new Date().toString()); - - f.writeString(helpmessage1); - f.writeString(helpmessage2); - - f.writeInt(helpchanged); - // gclient_t* - - f.writeString(spawnpoint); - f.writeInt(maxclients); - f.writeInt(maxentities); - f.writeInt(serverflags); - f.writeInt(num_items); - f.writeInt(autosaved?1:0); - // rst's checker :-) - f.writeInt(1928); - } -} +public class game_locals_t { + // + // 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[Defines.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; + + /** Reads the game locals from a file. */ + public void load(QuakeFile f) throws IOException { + String date = f.readString(); + + helpmessage1 = f.readString(); + helpmessage2 = f.readString(); + + helpchanged = f.readInt(); + // gclient_t* + + spawnpoint = f.readString(); + maxclients = f.readInt(); + maxentities = f.readInt(); + serverflags = f.readInt(); + num_items = f.readInt(); + autosaved = f.readInt() != 0; + + // rst's checker :-) + if (f.readInt() != 1928) + Com.DPrintf("error in loading game_locals, 1928\n"); + + } + + /** Writes the game locals to a file. */ + public void write(QuakeFile f) throws IOException { + f.writeString(new Date().toString()); + + f.writeString(helpmessage1); + f.writeString(helpmessage2); + + f.writeInt(helpchanged); + // gclient_t* + + f.writeString(spawnpoint); + f.writeInt(maxclients); + f.writeInt(maxentities); + f.writeInt(serverflags); + f.writeInt(num_items); + f.writeInt(autosaved ? 1 : 0); + // rst's checker :-) + f.writeInt(1928); + } +} \ No newline at end of file diff --git a/src/jake2/game/gitem_t.java b/src/jake2/game/gitem_t.java index f478f34..107cca3 100644 --- a/src/jake2/game/gitem_t.java +++ b/src/jake2/game/gitem_t.java @@ -1,145 +1,127 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 20.11.2003 by RST. +// $Id: gitem_t.java,v 1.4 2004-09-22 19:22:04 salomo Exp $ +package jake2.game; -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. +import jake2.*; +import jake2.*; -See the GNU General Public License for more details. +public class gitem_t { + private static int id = 0; -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. + public gitem_t(int xxx) { + index = xxx; + } -*/ + public gitem_t(String classname, EntInteractAdapter pickup, + ItemUseAdapter use, ItemDropAdapter drop, + EntThinkAdapter weaponthink) { + } -// Created on 20.11.2003 by RST. -// $Id: gitem_t.java,v 1.3 2004-08-20 21:29:57 salomo Exp $ + 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; -package jake2.game; + this.index = id++; + } -import jake2.*; -import jake2.*; + 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 */ + ""); + } -public class gitem_t -{ - private static int id=0; - 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; - - this.index = id++; - } - - 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", - GameAIAdapters.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, GameAIAdapters.combatarmor_info, Defines.ARMOR_COMBAT, - /* precache */ - ""); - } - - public int index; -} + public int index; +} \ No newline at end of file diff --git a/src/jake2/game/pmove_t.java b/src/jake2/game/pmove_t.java index d4138f4..7156e2a 100644 --- a/src/jake2/game/pmove_t.java +++ b/src/jake2/game/pmove_t.java @@ -1,83 +1,108 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 31.10.2003 by RST. +// $Id: pmove_t.java,v 1.2 2004-09-22 19:22:04 salomo Exp $ +package jake2.game; -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. +import jake2.*; +import jake2.server.SV_WORLD; -See the GNU General Public License for more details. +public class pmove_t { -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. + 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; + } + } -// Created on 31.10.2003 by RST. -// $Id: pmove_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $ + // state (in / out) + public pmove_state_t s = new pmove_state_t(); -package jake2.game; + // command (in) + public usercmd_t cmd = new usercmd_t(); -import jake2.*; -import jake2.server.SV_WORLD; + public boolean snapinitial; // if s has been changed outside pmove -public class pmove_t { + // 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; + + // pmove->pm_flags + public final static int PMF_DUCKED = 1; + + public final static int PMF_JUMP_HELD = 2; + + public final static int PMF_ON_GROUND = 4; + + public final static int PMF_TIME_WATERJUMP = 8; // pm_time is waterjump + + public final static int PMF_TIME_LAND = 16; // pm_time is time before rejump + + public final static int PMF_TIME_TELEPORT = 32; // pm_time is non-moving + // time + + public final static int PMF_NO_PREDICTION = 64; // temporarily disables + // prediction (used for + // grappling hook) + + public void clear() { - 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(); - } -} + 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(); + } +} \ No newline at end of file diff --git a/src/jake2/qcommon/CM.java b/src/jake2/qcommon/CM.java index 5978f88..52495db 100644 --- a/src/jake2/qcommon/CM.java +++ b/src/jake2/qcommon/CM.java @@ -1,29 +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. - -*/ + * 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: CM.java,v 1.5 2004-07-28 12:01:27 hzi Exp $ - +// $Id: CM.java,v 1.6 2004-09-22 19:22:09 salomo Exp $ package jake2.qcommon; import jake2.Defines; +import jake2.Globals; import jake2.game.*; import jake2.util.*; @@ -31,1889 +31,1866 @@ import java.io.RandomAccessFile; import java.nio.*; import java.util.Arrays; -public class CM extends Game { - - public static class cnode_t { - cplane_t plane; // ptr - int children[] = { 0, 0 }; // negative numbers are leafs - } - - public static class cbrushside_t { - cplane_t plane; // ptr - mapsurface_t surface; // ptr - } - - public static class cleaf_t { - int contents; - int cluster; - int area; - - // was unsigned short, but is ok (rst) - short firstleafbrush; - // was unsigned short, but is ok (rst) - short numleafbrushes; - } - - public static class cbrush_t { - int contents; - int numsides; - int firstbrushside; - int checkcount; // to avoid repeated testings - } - - public static class carea_t { - int numareaportals; - int firstareaportal; - int floodnum; // if two areas have equal floodnums, they are connected - int floodvalid; - } +public class CM { + + public static class cnode_t { + cplane_t plane; // ptr + + int children[] = { 0, 0 }; // negative numbers are leafs + } + + public static class cbrushside_t { + cplane_t plane; // ptr + + mapsurface_t surface; // ptr + } + + public static class cleaf_t { + int contents; + + int cluster; + + int area; + + // was unsigned short, but is ok (rst) + short firstleafbrush; + + // was unsigned short, but is ok (rst) + short numleafbrushes; + } + + public static class cbrush_t { + int contents; + + int numsides; + + int firstbrushside; + + int checkcount; // to avoid repeated testings + } + + public static class carea_t { + int numareaportals; + + int firstareaportal; + + int floodnum; // if two areas have equal floodnums, they are connected + + int floodvalid; + } + + static int checkcount; + + static String map_name = ""; + + static int numbrushsides; + + static cbrushside_t map_brushsides[] = new cbrushside_t[Defines.MAX_MAP_BRUSHSIDES]; + static { + for (int n = 0; n < Defines.MAX_MAP_BRUSHSIDES; n++) + map_brushsides[n] = new cbrushside_t(); + } + + public static int numtexinfo; + + public static mapsurface_t map_surfaces[] = new mapsurface_t[Defines.MAX_MAP_TEXINFO]; + static { + for (int n = 0; n < Defines.MAX_MAP_TEXINFO; n++) + map_surfaces[n] = new mapsurface_t(); + } + + static int numplanes; + + // extra for box hull ( +6) + static cplane_t map_planes[] = new cplane_t[Defines.MAX_MAP_PLANES + 6]; + + static { + for (int n = 0; n < Defines.MAX_MAP_PLANES + 6; n++) + map_planes[n] = new cplane_t(); + } + + static int numnodes; + + // extra for box hull ( +6) + static cnode_t map_nodes[] = new cnode_t[Defines.MAX_MAP_NODES + 6]; + + static { + for (int n = 0; n < Defines.MAX_MAP_NODES + 6; n++) + map_nodes[n] = new cnode_t(); + } + + static int numleafs = 1; // allow leaf funcs to be called without a map + + static cleaf_t map_leafs[] = new cleaf_t[Defines.MAX_MAP_LEAFS]; + static { + for (int n = 0; n < Defines.MAX_MAP_LEAFS; n++) + map_leafs[n] = new cleaf_t(); + } + + static int emptyleaf, solidleaf; + + static int numleafbrushes; + + //static unsigned short map_leafbrushes[Defines.MAX_MAP_LEAFBRUSHES]; + public static int map_leafbrushes[] = new int[Defines.MAX_MAP_LEAFBRUSHES]; + + public static int numcmodels; + + public static cmodel_t map_cmodels[] = new cmodel_t[Defines.MAX_MAP_MODELS]; + static { + for (int n = 0; n < Defines.MAX_MAP_MODELS; n++) + map_cmodels[n] = new cmodel_t(); + + } + + public static int numbrushes; + + public static cbrush_t map_brushes[] = new cbrush_t[Defines.MAX_MAP_BRUSHES]; + static { + for (int n = 0; n < Defines.MAX_MAP_BRUSHES; n++) + map_brushes[n] = new cbrush_t(); + + } + + public static int numvisibility; + + public static byte map_visibility[] = new byte[Defines.MAX_MAP_VISIBILITY]; + + // main visibility data. rst + // was: static dvis_t *map_vis = (dvis_t *)map_visibility; + public static qfiles.dvis_t map_vis = new qfiles.dvis_t(ByteBuffer + .wrap(map_visibility)); + + public static int numentitychars; + + public static String map_entitystring; + + public static int numareas = 1; + + public static carea_t map_areas[] = new carea_t[Defines.MAX_MAP_AREAS]; + static { + for (int n = 0; n < Defines.MAX_MAP_AREAS; n++) + map_areas[n] = new carea_t(); + + } + + public static int numareaportals; + + public static qfiles.dareaportal_t map_areaportals[] = new qfiles.dareaportal_t[Defines.MAX_MAP_AREAPORTALS]; + + static { + for (int n = 0; n < Defines.MAX_MAP_AREAPORTALS; n++) + map_areaportals[n] = new qfiles.dareaportal_t(); + + } + + public static int numclusters = 1; + + public static mapsurface_t nullsurface = new mapsurface_t(); + + public static int floodvalid; + + public static boolean portalopen[] = new boolean[Defines.MAX_MAP_AREAPORTALS]; + + public static cvar_t map_noareas; + + /* + * =============================================================================== + * + * MAP LOADING + * + * =============================================================================== + */ + + public static byte cmod_base[]; + + // is that right (rst) ? + public static int checksum; + + public static int last_checksum; + + /* + * ================== CM_LoadMap + * + * Loads in the map and all submodels ================== + */ + public static cmodel_t CM_LoadMap(String name, boolean clientload, + int checksum[]) { + Com.DPrintf("CM_LoadMap...\n"); + byte buf[]; + int i; + qfiles.dheader_t header; + int length; + + map_noareas = Cvar.Get("map_noareas", "0", 0); + + if (map_name.equals(name) + && (clientload || 0 == Cvar.VariableValue("flushmap"))) { + + checksum[0] = last_checksum; + + if (!clientload) { + Arrays.fill(portalopen, false); + FloodAreaConnections(); + } + return map_cmodels[0]; // still have the right version + } + + // free old stuff + numnodes = 0; + numleafs = 0; + numcmodels = 0; + numvisibility = 0; + numentitychars = 0; + map_entitystring = ""; + map_name = ""; + + if (name == null || name.length() == 0) { + numleafs = 1; + numclusters = 1; + numareas = 1; + checksum[0] = 0; + return map_cmodels[0]; + // cinematic servers won't have anything at all + } + + // + // load the file + // + buf = FS.LoadFile(name); + + if (buf == null) + Com.Error(Defines.ERR_DROP, "Couldn't load " + name); + + length = buf.length; + + ByteBuffer bbuf = ByteBuffer.wrap(buf); + + last_checksum = MD4.Com_BlockChecksum(buf, length); + checksum[0] = last_checksum; + + header = new qfiles.dheader_t(bbuf.slice()); + + if (header.version != Defines.BSPVERSION) + Com.Error(Defines.ERR_DROP, "CMod_LoadBrushModel: " + name + + " has wrong version number (" + header.version + + " should be " + Defines.BSPVERSION + ")"); + + cmod_base = buf; + + // load into heap + CMod_LoadSurfaces(header.lumps[Defines.LUMP_TEXINFO]); // ok. + CMod_LoadLeafs(header.lumps[Defines.LUMP_LEAFS]); + CMod_LoadLeafBrushes(header.lumps[Defines.LUMP_LEAFBRUSHES]); + CMod_LoadPlanes(header.lumps[Defines.LUMP_PLANES]); + CMod_LoadBrushes(header.lumps[Defines.LUMP_BRUSHES]); + CMod_LoadBrushSides(header.lumps[Defines.LUMP_BRUSHSIDES]); + CMod_LoadSubmodels(header.lumps[Defines.LUMP_MODELS]); + + CMod_LoadNodes(header.lumps[Defines.LUMP_NODES]); + CMod_LoadAreas(header.lumps[Defines.LUMP_AREAS]); + CMod_LoadAreaPortals(header.lumps[Defines.LUMP_AREAPORTALS]); + CMod_LoadVisibility(header.lumps[Defines.LUMP_VISIBILITY]); + CMod_LoadEntityString(header.lumps[Defines.LUMP_ENTITIES]); + + FS.FreeFile(buf); + + CM_InitBoxHull(); + + Arrays.fill(portalopen, false); + + FloodAreaConnections(); + + map_name = name; + + // debug (rst) + /* + * Com.p("Testing pointleafes:"); for (int n = 0; n < 20; n++) { float + * pos[] = new float[] {(float) (Math.random() * 1000), (float) + * (Math.random() * 1000), 0 }; int x = CM_PointLeafnum(pos); + * Com.p(Lib.vtofsbeaty(pos) + " ---> leaf=" + x + " area = " + * +map_leafs[x].area); } + */ + return map_cmodels[0]; + } + + /* + * ================= CMod_LoadSubmodels ================= + */ + public static void CMod_LoadSubmodels(lump_t l) { + Com.DPrintf("CMod_LoadSubmodels...\n"); + qfiles.dmodel_t in; + cmodel_t out; + int i, j, count; + + if ((l.filelen % qfiles.dmodel_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dmodel_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no models"); + if (count > Defines.MAX_MAP_MODELS) + Com.Error(Defines.ERR_DROP, "Map has too many models"); + + Com.DPrintf(" numcmodels=" + count + "\n"); + numcmodels = count; + + if (debugloadmap) { + Com.DPrintf("submodles(headnode, , , )\n"); + } + for (i = 0; i < count; i++) { + in = new qfiles.dmodel_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dmodel_t.SIZE + l.fileofs, qfiles.dmodel_t.SIZE)); + out = map_cmodels[i]; + + for (j = 0; j < 3; j++) { // spread the mins / maxs by a pixel + out.mins[j] = in.mins[j] - 1; + out.maxs[j] = in.maxs[j] + 1; + out.origin[j] = in.origin[j]; + } + out.headnode = in.headnode; + if (debugloadmap) { + Com + .DPrintf( + "|%6i|%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n", + new Vargs().add(out.headnode) + .add(out.origin[0]).add(out.origin[1]) + .add(out.origin[2]).add(out.mins[0]) + .add(out.mins[1]).add(out.mins[2]).add( + out.maxs[0]).add(out.maxs[1]) + .add(out.maxs[2])); + } + } + } + + static boolean debugloadmap = false; + + /* + * ================= CMod_LoadSurfaces ================= + */ + public static void CMod_LoadSurfaces(lump_t l) { + Com.DPrintf("CMod_LoadSurfaces...\n"); + texinfo_t in; + mapsurface_t out; + int i, count; + + if ((l.filelen % texinfo_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / texinfo_t.SIZE; + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no surfaces"); + if (count > Defines.MAX_MAP_TEXINFO) + Com.Error(Defines.ERR_DROP, "Map has too many surfaces"); + + numtexinfo = count; + Com.DPrintf("numtexinfo=" + count + "\n"); + if (debugloadmap) + Com.DPrintf("surfaces:\n"); + + for (i = 0; i < count; i++) { + out = map_surfaces[i] = new mapsurface_t(); + in = new texinfo_t(cmod_base, l.fileofs + i * texinfo_t.SIZE, + texinfo_t.SIZE); + + out.c.name = in.texture; + out.rname = in.texture; + out.c.flags = in.flags; + out.c.value = in.value; + + if (debugloadmap) { + Com.DPrintf("|%20s|%20s|%6i|%6i|\n", new Vargs() + .add(out.c.name).add(out.rname).add(out.c.value).add( + out.c.flags)); + } + + } + } + + /* + * ================= CMod_LoadNodes + * + * ================= + */ + public static void CMod_LoadNodes(lump_t l) { + Com.DPrintf("CMod_LoadNodes...\n"); + qfiles.dnode_t in; + int child; + cnode_t out; + int i, j, count; + + if ((l.filelen % qfiles.dnode_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size:" + + l.fileofs + "," + qfiles.dnode_t.SIZE); + count = l.filelen / qfiles.dnode_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map has no nodes"); + if (count > Defines.MAX_MAP_NODES) + Com.Error(Defines.ERR_DROP, "Map has too many nodes"); + + numnodes = count; + Com.DPrintf(" numnodes=" + count + "\n"); + + if (debugloadmap) { + Com.DPrintf("nodes(planenum, child[0], child[1])\n"); + } + + for (i = 0; i < count; i++) { + in = new qfiles.dnode_t(ByteBuffer.wrap(cmod_base, + qfiles.dnode_t.SIZE * i + l.fileofs, qfiles.dnode_t.SIZE)); + out = map_nodes[i]; + + out.plane = map_planes[in.planenum]; + for (j = 0; j < 2; j++) { + child = in.children[j]; + out.children[j] = child; + } + if (debugloadmap) { + Com.DPrintf("|%6i| %6i| %6i|\n", new Vargs().add(in.planenum) + .add(out.children[0]).add(out.children[1])); + } + } + } + + /* + * ================= CMod_LoadBrushes + * + * ================= + */ + public static void CMod_LoadBrushes(lump_t l) { + Com.DPrintf("CMod_LoadBrushes...\n"); + qfiles.dbrush_t in; + cbrush_t out; + int i, count; + + if ((l.filelen % qfiles.dbrush_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dbrush_t.SIZE; + + if (count > Defines.MAX_MAP_BRUSHES) + Com.Error(Defines.ERR_DROP, "Map has too many brushes"); + + numbrushes = count; + Com.DPrintf(" numbrushes=" + count + "\n"); + if (debugloadmap) { + Com.DPrintf("brushes:(firstbrushside, numsides, contents)\n"); + } + for (i = 0; i < count; i++) { + in = new qfiles.dbrush_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dbrush_t.SIZE + l.fileofs, qfiles.dbrush_t.SIZE)); + out = map_brushes[i]; + out.firstbrushside = in.firstside; + out.numsides = in.numsides; + out.contents = in.contents; + + if (debugloadmap) { + Com + .DPrintf("| %6i| %6i| %8X|\n", new Vargs().add( + out.firstbrushside).add(out.numsides).add( + out.contents)); + } + } + } + + /* + * ================= CMod_LoadLeafs ================= + */ + public static void CMod_LoadLeafs(lump_t l) { + Com.DPrintf("CMod_LoadLeafs...\n"); + int i; + cleaf_t out; + qfiles.dleaf_t in; + int count; + + if ((l.filelen % qfiles.dleaf_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dleaf_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no leafs"); + + // need to save space for box planes + if (count > Defines.MAX_MAP_PLANES) + Com.Error(Defines.ERR_DROP, "Map has too many planes"); + + Com.DPrintf(" numleafes=" + count + "\n"); + + numleafs = count; + numclusters = 0; + if (debugloadmap) + Com + .DPrintf("cleaf-list:(contents, cluster, area, firstleafbrush, numleafbrushes)\n"); + for (i = 0; i < count; i++) { + in = new qfiles.dleaf_t(cmod_base, i * qfiles.dleaf_t.SIZE + + l.fileofs, qfiles.dleaf_t.SIZE); + + out = map_leafs[i]; + + out.contents = in.contents; + out.cluster = in.cluster; + out.area = in.area; + out.firstleafbrush = (short) in.firstleafbrush; + out.numleafbrushes = (short) in.numleafbrushes; + + if (out.cluster >= numclusters) + numclusters = out.cluster + 1; + + if (debugloadmap) { + Com.DPrintf("|%8x|%6i|%6i|%6i|\n", new Vargs() + .add(out.contents).add(out.cluster).add(out.area).add( + out.firstleafbrush).add(out.numleafbrushes)); + } + + } + + Com.DPrintf(" numclusters=" + numclusters + "\n"); + + if (map_leafs[0].contents != Defines.CONTENTS_SOLID) + Com.Error(Defines.ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID"); + + solidleaf = 0; + emptyleaf = -1; + + for (i = 1; i < numleafs; i++) { + if (map_leafs[i].contents == 0) { + emptyleaf = i; + break; + } + } + + if (emptyleaf == -1) + Com.Error(Defines.ERR_DROP, "Map does not have an empty leaf"); + } + + /* + * ================= CMod_LoadPlanes ================= + */ + public static void CMod_LoadPlanes(lump_t l) { + Com.DPrintf("CMod_LoadPlanes...\n"); + int i, j; + cplane_t out; + qfiles.dplane_t in; + int count; + int bits; + + if ((l.filelen % qfiles.dplane_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dplane_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no planes"); + + // need to save space for box planes + if (count > Defines.MAX_MAP_PLANES) + Com.Error(Defines.ERR_DROP, "Map has too many planes"); + + Com.DPrintf(" numplanes=" + count + "\n"); + + numplanes = count; + if (debugloadmap) { + Com + .DPrintf("cplanes(normal[0],normal[1],normal[2], dist, type, signbits)\n"); + } + + for (i = 0; i < count; i++) { + in = new qfiles.dplane_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dplane_t.SIZE + l.fileofs, qfiles.dplane_t.SIZE)); + + out = map_planes[i]; + + bits = 0; + for (j = 0; j < 3; j++) { + out.normal[j] = in.normal[j]; + + if (out.normal[j] < 0) + bits |= 1 << j; + } + + out.dist = in.dist; + out.type = (byte) in.type; + out.signbits = (byte) bits; + + if (debugloadmap) { + Com.DPrintf("|%6.2f|%6.2f|%6.2f| %10.2f|%3i| %1i|\n", + new Vargs().add(out.normal[0]).add(out.normal[1]).add( + out.normal[2]).add(out.dist).add(out.type).add( + out.signbits)); + } + } + } + + /* + * ================= CMod_LoadLeafBrushes ================= + */ + public static void CMod_LoadLeafBrushes(lump_t l) { + Com.DPrintf("CMod_LoadLeafBrushes...\n"); + int i; + int out[]; + short in[]; + int count; + + if ((l.filelen % 2) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / 2; + + Com.DPrintf(" numbrushes=" + count + "\n"); + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no planes"); + + // need to save space for box planes + if (count > Defines.MAX_MAP_LEAFBRUSHES) + Com.Error(Defines.ERR_DROP, "Map has too many leafbrushes"); + + out = map_leafbrushes; + numleafbrushes = count; + + ByteBuffer bb = ByteBuffer.wrap(cmod_base, l.fileofs, count * 2).order( + ByteOrder.LITTLE_ENDIAN); + + if (debugloadmap) { + Com.DPrintf("map_brushes:\n"); + } + + for (i = 0; i < count; i++) { + out[i] = bb.getShort(); + if (debugloadmap) { + Com.DPrintf("|%6i|%6i|\n", new Vargs().add(i).add(out[i])); + } + } + } + + /* + * ================= CMod_LoadBrushSides ================= + */ + public static void CMod_LoadBrushSides(lump_t l) { + Com.DPrintf("CMod_LoadBrushSides...\n"); + int i, j; + cbrushside_t out; + qfiles.dbrushside_t in; + int count; + int num; + + if ((l.filelen % qfiles.dbrushside_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l.filelen / qfiles.dbrushside_t.SIZE; + + // need to save space for box planes + if (count > Defines.MAX_MAP_BRUSHSIDES) + Com.Error(Defines.ERR_DROP, "Map has too many planes"); + + numbrushsides = count; + + Com.DPrintf(" numbrushsides=" + count + "\n"); + + if (debugloadmap) { + Com.DPrintf("brushside(planenum, surfacenum):\n"); + } + for (i = 0; i < count; i++) { + + in = new qfiles.dbrushside_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dbrushside_t.SIZE + l.fileofs, + qfiles.dbrushside_t.SIZE)); + + out = map_brushsides[i]; + + num = in.planenum; + + out.plane = map_planes[num]; // pointer + + j = in.texinfo; + + if (j >= numtexinfo) + Com.Error(Defines.ERR_DROP, "Bad brushside texinfo"); + + // rst: some mysterious happens here, even in the original code ???, + // texinfo is -1!!! + // hoz: checked against c version: ok. + if (j == -1) + out.surface = new mapsurface_t(); // just for safety + else + out.surface = map_surfaces[j]; + + if (debugloadmap) { + Com.DPrintf("| %6i| %6i|\n", new Vargs().add(num).add(j)); + } + } + } + + /* + * ================= CMod_LoadAreas ================= + */ + public static void CMod_LoadAreas(lump_t l) { + Com.DPrintf("CMod_LoadAreas...\n"); + int i; + carea_t out; + qfiles.darea_t in; + int count; + + if ((l.filelen % qfiles.darea_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.darea_t.SIZE; + + if (count > Defines.MAX_MAP_AREAS) + Com.Error(Defines.ERR_DROP, "Map has too many areas"); + + Com.DPrintf(" numareas=" + count + "\n"); + numareas = count; + + if (debugloadmap) { + Com.DPrintf("areas(numportals, firstportal)\n"); + } + + for (i = 0; i < count; i++) { + + in = new qfiles.darea_t(ByteBuffer.wrap(cmod_base, i + * qfiles.darea_t.SIZE + l.fileofs, qfiles.darea_t.SIZE)); + out = map_areas[i]; + + out.numareaportals = in.numareaportals; + out.firstareaportal = in.firstareaportal; + out.floodvalid = 0; + out.floodnum = 0; + if (debugloadmap) { + Com.DPrintf("| %6i| %6i|\n", new Vargs() + .add(out.numareaportals).add(out.firstareaportal)); + } + } + } + + /* + * ================= CMod_LoadAreaPortals ================= + */ + public static void CMod_LoadAreaPortals(lump_t l) { + Com.DPrintf("CMod_LoadAreaPortals...\n"); + int i; + qfiles.dareaportal_t out; + qfiles.dareaportal_t in; + int count; + + if ((l.filelen % qfiles.dareaportal_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l.filelen / qfiles.dareaportal_t.SIZE; - static int checkcount; - - static String map_name = ""; - - static int numbrushsides; - static cbrushside_t map_brushsides[] = new cbrushside_t[MAX_MAP_BRUSHSIDES]; - static { - for (int n = 0; n < MAX_MAP_BRUSHSIDES; n++) - map_brushsides[n] = new cbrushside_t(); - } - - public static int numtexinfo; - public static mapsurface_t map_surfaces[] = new mapsurface_t[MAX_MAP_TEXINFO]; - static { - for (int n = 0; n < MAX_MAP_TEXINFO; n++) - map_surfaces[n] = new mapsurface_t(); - } - - static int numplanes; - // extra for box hull ( +6) - static cplane_t map_planes[] = new cplane_t[MAX_MAP_PLANES + 6]; - - static { - for (int n = 0; n < MAX_MAP_PLANES + 6; n++) - map_planes[n] = new cplane_t(); - } - - static int numnodes; - // extra for box hull ( +6) - static cnode_t map_nodes[] = new cnode_t[MAX_MAP_NODES + 6]; - - static { - for (int n = 0; n < MAX_MAP_NODES + 6; n++) - map_nodes[n] = new cnode_t(); - } - - static int numleafs = 1; // allow leaf funcs to be called without a map - static cleaf_t map_leafs[] = new cleaf_t[MAX_MAP_LEAFS]; - static { - for (int n = 0; n < MAX_MAP_LEAFS; n++) - map_leafs[n] = new cleaf_t(); - } - - static int emptyleaf, solidleaf; - - static int numleafbrushes; - //static unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES]; - public static int map_leafbrushes[] = new int[MAX_MAP_LEAFBRUSHES]; - public static int numcmodels; - public static cmodel_t map_cmodels[] = new cmodel_t[MAX_MAP_MODELS]; - static { - for (int n = 0; n < MAX_MAP_MODELS; n++) - map_cmodels[n] = new cmodel_t(); - - } - - public static int numbrushes; - public static cbrush_t map_brushes[] = new cbrush_t[MAX_MAP_BRUSHES]; - static { - for (int n = 0; n < MAX_MAP_BRUSHES; n++) - map_brushes[n] = new cbrush_t(); - - } - - public static int numvisibility; - public static byte map_visibility[] = new byte[MAX_MAP_VISIBILITY]; - - // main visibility data. rst - // was: static dvis_t *map_vis = (dvis_t *)map_visibility; - public static qfiles.dvis_t map_vis = new qfiles.dvis_t(ByteBuffer.wrap(map_visibility)); - - public static int numentitychars; - public static String map_entitystring; - - public static int numareas = 1; - public static carea_t map_areas[] = new carea_t[MAX_MAP_AREAS]; - static { - for (int n = 0; n < MAX_MAP_AREAS; n++) - map_areas[n] = new carea_t(); - - } - public static int numareaportals; - public static qfiles.dareaportal_t map_areaportals[] = new qfiles.dareaportal_t[MAX_MAP_AREAPORTALS]; - - static { - for (int n = 0; n < MAX_MAP_AREAPORTALS; n++) - map_areaportals[n] = new qfiles.dareaportal_t(); - - } - - public static int numclusters = 1; - - public static mapsurface_t nullsurface = new mapsurface_t(); - - public static int floodvalid; - - public static boolean portalopen[] = new boolean[MAX_MAP_AREAPORTALS]; - - public static cvar_t map_noareas; - - /* - =============================================================================== - - MAP LOADING - - =============================================================================== - */ - - public static byte cmod_base[]; - - // is that right (rst) ? - public static int checksum; - public static int last_checksum; - - /* - ================== - CM_LoadMap - - Loads in the map and all submodels - ================== - */ - public static cmodel_t CM_LoadMap(String name, boolean clientload, int checksum[]) { - Com.DPrintf("CM_LoadMap...\n"); - byte buf[]; - int i; - qfiles.dheader_t header; - int length; - - map_noareas = Cvar.Get("map_noareas", "0", 0); - - if (map_name.equals(name) && (clientload || 0 == Cvar.VariableValue("flushmap"))) { - - checksum[0] = last_checksum; - - if (!clientload) { - Arrays.fill(portalopen, false); - FloodAreaConnections(); - } - return map_cmodels[0]; // still have the right version - } - - // free old stuff - numnodes = 0; - numleafs = 0; - numcmodels = 0; - numvisibility = 0; - numentitychars = 0; - map_entitystring = ""; - map_name = ""; - - if (name == null || name.length() == 0) { - numleafs = 1; - numclusters = 1; - numareas = 1; - checksum[0] = 0; - return map_cmodels[0]; - // cinematic servers won't have anything at all - } - - // - // load the file - // - buf = FS.LoadFile(name); - - if (buf == null) - Com.Error(ERR_DROP, "Couldn't load " + name); - - length = buf.length; - - ByteBuffer bbuf = ByteBuffer.wrap(buf); - - last_checksum = MD4.Com_BlockChecksum(buf, length); - checksum[0] = last_checksum; - - header = new qfiles.dheader_t(bbuf.slice()); - - if (header.version != BSPVERSION) - Com.Error( - ERR_DROP, - "CMod_LoadBrushModel: " + name + " has wrong version number (" + header.version + " should be " + BSPVERSION + ")"); - - cmod_base = buf; - - // load into heap - CMod_LoadSurfaces(header.lumps[LUMP_TEXINFO]); // ok. - CMod_LoadLeafs(header.lumps[LUMP_LEAFS]); - CMod_LoadLeafBrushes(header.lumps[LUMP_LEAFBRUSHES]); - CMod_LoadPlanes(header.lumps[LUMP_PLANES]); - CMod_LoadBrushes(header.lumps[LUMP_BRUSHES]); - CMod_LoadBrushSides(header.lumps[LUMP_BRUSHSIDES]); - CMod_LoadSubmodels(header.lumps[LUMP_MODELS]); - - CMod_LoadNodes(header.lumps[LUMP_NODES]); - CMod_LoadAreas(header.lumps[LUMP_AREAS]); - CMod_LoadAreaPortals(header.lumps[LUMP_AREAPORTALS]); - CMod_LoadVisibility(header.lumps[LUMP_VISIBILITY]); - CMod_LoadEntityString(header.lumps[LUMP_ENTITIES]); - - FS.FreeFile(buf); - - CM_InitBoxHull(); - - Arrays.fill(portalopen, false); - - FloodAreaConnections(); - - map_name = name; - - // debug (rst) - /* - Com.p("Testing pointleafes:"); - for (int n = 0; n < 20; n++) { - float pos[] = new float[] {(float) (Math.random() * 1000), (float) (Math.random() * 1000), 0 }; - int x = CM_PointLeafnum(pos); - Com.p(Lib.vtofsbeaty(pos) + " ---> leaf=" + x + " area = " +map_leafs[x].area); - } - */ - return map_cmodels[0]; - } - - /* - ================= - CMod_LoadSubmodels - ================= - */ - public static void CMod_LoadSubmodels(lump_t l) { - Com.DPrintf("CMod_LoadSubmodels...\n"); - qfiles.dmodel_t in; - cmodel_t out; - int i, j, count; - - if ((l.filelen % qfiles.dmodel_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dmodel_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map with no models"); - if (count > MAX_MAP_MODELS) - Com.Error(ERR_DROP, "Map has too many models"); - - Com.DPrintf(" numcmodels=" + count + "\n"); - numcmodels = count; - - if (debugloadmap) { - Com.DPrintf("submodles(headnode, , , )\n"); - } - for (i = 0; i < count; i++) { - in = new qfiles.dmodel_t(ByteBuffer.wrap(cmod_base, i * qfiles.dmodel_t.SIZE + l.fileofs, qfiles.dmodel_t.SIZE)); - out = map_cmodels[i]; - - for (j = 0; j < 3; j++) { // spread the mins / maxs by a pixel - out.mins[j] = in.mins[j] - 1; - out.maxs[j] = in.maxs[j] + 1; - out.origin[j] = in.origin[j]; - } - out.headnode = in.headnode; - if (debugloadmap) { - Com.DPrintf( - "|%6i|%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n", - new Vargs() - .add(out.headnode) - .add(out.origin[0]) - .add(out.origin[1]) - .add(out.origin[2]) - .add(out.mins[0]) - .add(out.mins[1]) - .add(out.mins[2]) - .add(out.maxs[0]) - .add(out.maxs[1]) - .add(out.maxs[2])); - } - } - } - static boolean debugloadmap = false; - - /* - ================= - CMod_LoadSurfaces - ================= - */ - public static void CMod_LoadSurfaces(lump_t l) { - Com.DPrintf("CMod_LoadSurfaces...\n"); - texinfo_t in; - mapsurface_t out; - int i, count; - - if ((l.filelen % texinfo_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / texinfo_t.SIZE; - if (count < 1) - Com.Error(ERR_DROP, "Map with no surfaces"); - if (count > MAX_MAP_TEXINFO) - Com.Error(ERR_DROP, "Map has too many surfaces"); - - numtexinfo = count; - Com.DPrintf("numtexinfo=" + count + "\n"); - if (debugloadmap) - Com.DPrintf("surfaces:\n"); - - for (i = 0; i < count; i++) { - out = map_surfaces[i] = new mapsurface_t(); - in = new texinfo_t(cmod_base, l.fileofs + i * texinfo_t.SIZE, texinfo_t.SIZE); - - out.c.name = in.texture; - out.rname = in.texture; - out.c.flags = in.flags; - out.c.value = in.value; - - if (debugloadmap) { - Com.DPrintf("|%20s|%20s|%6i|%6i|\n", new Vargs().add(out.c.name).add(out.rname).add(out.c.value).add(out.c.flags)); - } - - } - } - - /* - ================= - CMod_LoadNodes - - ================= - */ - public static void CMod_LoadNodes(lump_t l) { - Com.DPrintf("CMod_LoadNodes...\n"); - qfiles.dnode_t in; - int child; - cnode_t out; - int i, j, count; - - if ((l.filelen % qfiles.dnode_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size:" + l.fileofs + "," + qfiles.dnode_t.SIZE); - count = l.filelen / qfiles.dnode_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map has no nodes"); - if (count > MAX_MAP_NODES) - Com.Error(ERR_DROP, "Map has too many nodes"); - - numnodes = count; - Com.DPrintf(" numnodes=" + count + "\n"); - - if (debugloadmap) { - Com.DPrintf("nodes(planenum, child[0], child[1])\n"); - } - - for (i = 0; i < count; i++) { - in = new qfiles.dnode_t(ByteBuffer.wrap(cmod_base, qfiles.dnode_t.SIZE * i + l.fileofs, qfiles.dnode_t.SIZE)); - out = map_nodes[i]; - - out.plane = map_planes[in.planenum]; - for (j = 0; j < 2; j++) { - child = in.children[j]; - out.children[j] = child; - } - if (debugloadmap) { - Com.DPrintf("|%6i| %6i| %6i|\n", new Vargs().add(in.planenum).add(out.children[0]).add(out.children[1])); - } - } - } - - /* - ================= - CMod_LoadBrushes - - ================= - */ - public static void CMod_LoadBrushes(lump_t l) { - Com.DPrintf("CMod_LoadBrushes...\n"); - qfiles.dbrush_t in; - cbrush_t out; - int i, count; - - if ((l.filelen % qfiles.dbrush_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dbrush_t.SIZE; - - if (count > MAX_MAP_BRUSHES) - Com.Error(ERR_DROP, "Map has too many brushes"); - - numbrushes = count; - Com.DPrintf(" numbrushes=" + count + "\n"); - if (debugloadmap) { - Com.DPrintf("brushes:(firstbrushside, numsides, contents)\n"); - } - for (i = 0; i < count; i++) { - in = new qfiles.dbrush_t(ByteBuffer.wrap(cmod_base, i * qfiles.dbrush_t.SIZE + l.fileofs, qfiles.dbrush_t.SIZE)); - out = map_brushes[i]; - out.firstbrushside = in.firstside; - out.numsides = in.numsides; - out.contents = in.contents; - - if (debugloadmap) { - Com.DPrintf("| %6i| %6i| %8X|\n", new Vargs().add(out.firstbrushside).add(out.numsides).add(out.contents)); - } - } - } - - /* - ================= - CMod_LoadLeafs - ================= - */ - public static void CMod_LoadLeafs(lump_t l) { - Com.DPrintf("CMod_LoadLeafs...\n"); - int i; - cleaf_t out; - qfiles.dleaf_t in; - int count; - - if ((l.filelen % qfiles.dleaf_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dleaf_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map with no leafs"); - - // need to save space for box planes - if (count > MAX_MAP_PLANES) - Com.Error(ERR_DROP, "Map has too many planes"); - - Com.DPrintf(" numleafes=" + count + "\n"); - - numleafs = count; - numclusters = 0; - if (debugloadmap) - Com.DPrintf("cleaf-list:(contents, cluster, area, firstleafbrush, numleafbrushes)\n"); - for (i = 0; i < count; i++) { - in = new qfiles.dleaf_t(cmod_base, i * qfiles.dleaf_t.SIZE + l.fileofs, qfiles.dleaf_t.SIZE); - - out = map_leafs[i]; - - out.contents = in.contents; - out.cluster = in.cluster; - out.area = in.area; - out.firstleafbrush = (short) in.firstleafbrush; - out.numleafbrushes = (short) in.numleafbrushes; - - if (out.cluster >= numclusters) - numclusters = out.cluster + 1; - - if (debugloadmap) { - Com.DPrintf( - "|%8x|%6i|%6i|%6i|\n", - new Vargs().add(out.contents).add(out.cluster).add(out.area).add(out.firstleafbrush).add(out.numleafbrushes)); - } - - } - - Com.DPrintf(" numclusters=" + numclusters + "\n"); - - if (map_leafs[0].contents != CONTENTS_SOLID) - Com.Error(ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID"); - - solidleaf = 0; - emptyleaf = -1; - - for (i = 1; i < numleafs; i++) { - if (map_leafs[i].contents == 0) { - emptyleaf = i; - break; - } - } - - if (emptyleaf == -1) - Com.Error(ERR_DROP, "Map does not have an empty leaf"); - } - - /* - ================= - CMod_LoadPlanes - ================= - */ - public static void CMod_LoadPlanes(lump_t l) { - Com.DPrintf("CMod_LoadPlanes...\n"); - int i, j; - cplane_t out; - qfiles.dplane_t in; - int count; - int bits; - - if ((l.filelen % qfiles.dplane_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dplane_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map with no planes"); - - // need to save space for box planes - if (count > MAX_MAP_PLANES) - Com.Error(ERR_DROP, "Map has too many planes"); - - Com.DPrintf(" numplanes=" + count + "\n"); - - numplanes = count; - if (debugloadmap) { - Com.DPrintf("cplanes(normal[0],normal[1],normal[2], dist, type, signbits)\n"); - } - - for (i = 0; i < count; i++) { - in = new qfiles.dplane_t(ByteBuffer.wrap(cmod_base, i * qfiles.dplane_t.SIZE + l.fileofs, qfiles.dplane_t.SIZE)); - - out = map_planes[i]; - - bits = 0; - for (j = 0; j < 3; j++) { - out.normal[j] = in.normal[j]; + if (count > Defines.MAX_MAP_AREAS) + Com.Error(Defines.ERR_DROP, "Map has too many areas"); - if (out.normal[j] < 0) - bits |= 1 << j; - } - - out.dist = in.dist; - out.type = (byte) in.type; - out.signbits = (byte) bits; - - if (debugloadmap) { - Com.DPrintf( - "|%6.2f|%6.2f|%6.2f| %10.2f|%3i| %1i|\n", - new Vargs().add(out.normal[0]).add(out.normal[1]).add(out.normal[2]).add(out.dist).add(out.type).add( - out.signbits)); - } - } - } - - /* - ================= - CMod_LoadLeafBrushes - ================= - */ - public static void CMod_LoadLeafBrushes(lump_t l) { - Com.DPrintf("CMod_LoadLeafBrushes...\n"); - int i; - int out[]; - short in[]; - int count; - - if ((l.filelen % 2) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / 2; - - Com.DPrintf(" numbrushes=" + count + "\n"); - - if (count < 1) - Com.Error(ERR_DROP, "Map with no planes"); - - // need to save space for box planes - if (count > MAX_MAP_LEAFBRUSHES) - Com.Error(ERR_DROP, "Map has too many leafbrushes"); - - out = map_leafbrushes; - numleafbrushes = count; - - ByteBuffer bb = ByteBuffer.wrap(cmod_base, l.fileofs, count * 2).order(ByteOrder.LITTLE_ENDIAN); - - if (debugloadmap) { - Com.DPrintf("map_brushes:\n"); - } - - for (i = 0; i < count; i++) { - out[i] = bb.getShort(); - if (debugloadmap) { - Com.DPrintf("|%6i|%6i|\n", new Vargs().add(i).add(out[i])); - } - } - } - - /* - ================= - CMod_LoadBrushSides - ================= - */ - public static void CMod_LoadBrushSides(lump_t l) { - Com.DPrintf("CMod_LoadBrushSides...\n"); - int i, j; - cbrushside_t out; - qfiles.dbrushside_t in; - int count; - int num; - - if ((l.filelen % qfiles.dbrushside_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - count = l.filelen / qfiles.dbrushside_t.SIZE; - - // need to save space for box planes - if (count > MAX_MAP_BRUSHSIDES) - Com.Error(ERR_DROP, "Map has too many planes"); - - numbrushsides = count; - - Com.DPrintf(" numbrushsides=" + count + "\n"); - - if (debugloadmap) { - Com.DPrintf("brushside(planenum, surfacenum):\n"); - } - for (i = 0; i < count; i++) { - - in = - new qfiles.dbrushside_t( - ByteBuffer.wrap(cmod_base, i * qfiles.dbrushside_t.SIZE + l.fileofs, qfiles.dbrushside_t.SIZE)); - - out = map_brushsides[i]; - - num = in.planenum; - - out.plane = map_planes[num]; // pointer - - j = in.texinfo; - - if (j >= numtexinfo) - Com.Error(ERR_DROP, "Bad brushside texinfo"); - - // rst: some mysterious happens here, even in the original code ???, texinfo is -1!!! - // hoz: checked against c version: ok. - if (j == -1) - out.surface = new mapsurface_t(); // just for safety - else - out.surface = map_surfaces[j]; - - if (debugloadmap) { - Com.DPrintf("| %6i| %6i|\n", new Vargs().add(num).add(j)); - } - } - } - - /* - ================= - CMod_LoadAreas - ================= - */ - public static void CMod_LoadAreas(lump_t l) { - Com.DPrintf("CMod_LoadAreas...\n"); - int i; - carea_t out; - qfiles.darea_t in; - int count; - - if ((l.filelen % qfiles.darea_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.darea_t.SIZE; - - if (count > MAX_MAP_AREAS) - Com.Error(ERR_DROP, "Map has too many areas"); - - Com.DPrintf(" numareas=" + count + "\n"); - numareas = count; - - if (debugloadmap) { - Com.DPrintf("areas(numportals, firstportal)\n"); - } - - for (i = 0; i < count; i++) { - - in = new qfiles.darea_t(ByteBuffer.wrap(cmod_base, i * qfiles.darea_t.SIZE + l.fileofs, qfiles.darea_t.SIZE)); - out = map_areas[i]; - - out.numareaportals = in.numareaportals; - out.firstareaportal = in.firstareaportal; - out.floodvalid = 0; - out.floodnum = 0; - if (debugloadmap) { - Com.DPrintf("| %6i| %6i|\n", new Vargs().add(out.numareaportals).add(out.firstareaportal)); - } - } - } - - /* - ================= - CMod_LoadAreaPortals - ================= - */ - public static void CMod_LoadAreaPortals(lump_t l) { - Com.DPrintf("CMod_LoadAreaPortals...\n"); - int i; - qfiles.dareaportal_t out; - qfiles.dareaportal_t in; - int count; + numareaportals = count; + Com.DPrintf(" numareaportals=" + count + "\n"); + if (debugloadmap) { + Com.DPrintf("areaportals(portalnum, otherarea)\n"); + } + for (i = 0; i < count; i++) { + in = new qfiles.dareaportal_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dareaportal_t.SIZE + l.fileofs, + qfiles.dareaportal_t.SIZE)); + + out = map_areaportals[i]; - if ((l.filelen % qfiles.dareaportal_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - count = l.filelen / qfiles.dareaportal_t.SIZE; + out.portalnum = in.portalnum; + out.otherarea = in.otherarea; - if (count > MAX_MAP_AREAS) - Com.Error(ERR_DROP, "Map has too many areas"); + if (debugloadmap) { + Com.DPrintf("|%6i|%6i|\n", new Vargs().add(out.portalnum).add( + out.otherarea)); + } + } + } - numareaportals = count; - Com.DPrintf(" numareaportals=" + count + "\n"); - if (debugloadmap) { - Com.DPrintf("areaportals(portalnum, otherarea)\n"); - } - for (i = 0; i < count; i++) { - in = - new qfiles.dareaportal_t( - ByteBuffer.wrap(cmod_base, i * qfiles.dareaportal_t.SIZE + l.fileofs, qfiles.dareaportal_t.SIZE)); - - out = map_areaportals[i]; - - out.portalnum = in.portalnum; - out.otherarea = in.otherarea; - - if (debugloadmap) { - Com.DPrintf("|%6i|%6i|\n", new Vargs().add(out.portalnum).add(out.otherarea)); - } - } - } - - - /* - ================= - CMod_LoadVisibility - ================= - */ - public static void CMod_LoadVisibility(lump_t l) { - Com.DPrintf("CMod_LoadVisibility...\n"); - int i; - - numvisibility = l.filelen; - - Com.DPrintf(" numvisibility=" + numvisibility + "\n"); - - if (l.filelen > MAX_MAP_VISIBILITY) - Com.Error(ERR_DROP, "Map has too large visibility lump"); - - System.arraycopy(cmod_base, l.fileofs, map_visibility, 0, l.filelen); - - ByteBuffer bb = ByteBuffer.wrap(map_visibility, 0, l.filelen); - bb.order(ByteOrder.LITTLE_ENDIAN); - - map_vis = new qfiles.dvis_t(bb); - - } - - /* - ================= - CMod_LoadEntityString - ================= - */ - public static void CMod_LoadEntityString(lump_t l) { - Com.DPrintf("CMod_LoadEntityString...\n"); - - numentitychars = l.filelen; - - if (l.filelen > MAX_MAP_ENTSTRING) - Com.Error(ERR_DROP, "Map has too large entity lump"); - - int x = 0; - for (; x < l.filelen && cmod_base[x + l.fileofs] != 0; x++); - - map_entitystring = new String(cmod_base, l.fileofs, x).trim(); - } - - /* - ================== - CM_InlineModel - ================== - */ - - // works fine - public static cmodel_t InlineModel(String name) { - int num; - - if (name == null || name.charAt(0) != '*') - Com.Error(ERR_DROP, "CM_InlineModel: bad name"); - - num = atoi(name.substring(1)); - - if (num < 1 || num >= numcmodels) - Com.Error(ERR_DROP, "CM_InlineModel: bad number"); - - return map_cmodels[num]; - } - - public static int CM_NumClusters() { - return numclusters; - } - - public static int CM_NumInlineModels() { - return numcmodels; - } - - public static String CM_EntityString() { - return map_entitystring; - } - - public static int CM_LeafContents(int leafnum) { - if (leafnum < 0 || leafnum >= numleafs) - Com.Error(ERR_DROP, "CM_LeafContents: bad number"); - return map_leafs[leafnum].contents; - } - - public static int CM_LeafCluster(int leafnum) { - if (leafnum < 0 || leafnum >= numleafs) - Com.Error(ERR_DROP, "CM_LeafCluster: bad number"); - return map_leafs[leafnum].cluster; - } - - public static int CM_LeafArea(int leafnum) { - if (leafnum < 0 || leafnum >= numleafs) - Com.Error(ERR_DROP, "CM_LeafArea: bad number"); - return map_leafs[leafnum].area; - } - - //======================================================================= - - static cplane_t box_planes[]; - static int box_headnode; - static cbrush_t box_brush; - static cleaf_t box_leaf; - - /* - =================== - CM_InitBoxHull - - Set up the planes and nodes so that the six floats of a bounding box - can just be stored out and get a proper clipping hull structure. - =================== - */ - public static void CM_InitBoxHull() { - int i; - int side; - cnode_t c; - cplane_t p; - cbrushside_t s; - - box_headnode = numnodes; // noch platz f?r 6 brushes - - box_planes = - new cplane_t[] { - map_planes[numplanes], - map_planes[numplanes + 1], - map_planes[numplanes + 2], - map_planes[numplanes + 3], - map_planes[numplanes + 4], - map_planes[numplanes + 5], - map_planes[numplanes + 6], - map_planes[numplanes + 7], - map_planes[numplanes + 8], - map_planes[numplanes + 9], - map_planes[numplanes + 10], - map_planes[numplanes + 11], - map_planes[numplanes + 12] }; - - if (numnodes + 6 > MAX_MAP_NODES - || numbrushes + 1 > MAX_MAP_BRUSHES - || numleafbrushes + 1 > MAX_MAP_LEAFBRUSHES - || numbrushsides + 6 > MAX_MAP_BRUSHSIDES - || numplanes + 12 > MAX_MAP_PLANES) - Com.Error(ERR_DROP, "Not enough room for box tree"); - - box_brush = map_brushes[numbrushes]; - box_brush.numsides = 6; - box_brush.firstbrushside = numbrushsides; - box_brush.contents = CONTENTS_MONSTER; - - box_leaf = map_leafs[numleafs]; - box_leaf.contents = CONTENTS_MONSTER; - box_leaf.firstleafbrush = (short) numleafbrushes; - box_leaf.numleafbrushes = 1; - - map_leafbrushes[numleafbrushes] = numbrushes; - - for (i = 0; i < 6; i++) { - side = i & 1; - - // brush sides - s = map_brushsides[numbrushsides + i]; - s.plane = map_planes[(numplanes + i * 2 + side)]; - s.surface = nullsurface; - - // nodes - c = map_nodes[box_headnode + i]; - c.plane = map_planes[(numplanes + i * 2)]; - c.children[side] = -1 - emptyleaf; - if (i != 5) - c.children[side ^ 1] = box_headnode + i + 1; - else - c.children[side ^ 1] = -1 - numleafs; - - // planes - p = box_planes[i * 2]; - p.type = (byte) (i >> 1); - p.signbits = 0; - VectorClear(p.normal); - p.normal[i >> 1] = 1; - - p = box_planes[i * 2 + 1]; - p.type = (byte) (3 + (i >> 1)); - p.signbits = 0; - VectorClear(p.normal); - p.normal[i >> 1] = -1; - } - } - - /* - =================== - CM_HeadnodeForBox - - To keep everything totally uniform, bounding boxes are turned into small - BSP trees instead of being compared directly. - =================== - */ - public static int HeadnodeForBox(float[] mins, float[] maxs) { - box_planes[0].dist = maxs[0]; - box_planes[1].dist = -maxs[0]; - box_planes[2].dist = mins[0]; - box_planes[3].dist = -mins[0]; - box_planes[4].dist = maxs[1]; - box_planes[5].dist = -maxs[1]; - box_planes[6].dist = mins[1]; - box_planes[7].dist = -mins[1]; - box_planes[8].dist = maxs[2]; - box_planes[9].dist = -maxs[2]; - box_planes[10].dist = mins[2]; - box_planes[11].dist = -mins[2]; - - return box_headnode; - } - - /* - ================== - CM_PointLeafnum_r - ================== - */ - public static int CM_PointLeafnum_r(float[] p, int num) { - float d; - cnode_t node; - cplane_t plane; - - while (num >= 0) { - node = map_nodes[num]; - plane = node.plane; - - if (plane.type < 3) - d = p[plane.type] - plane.dist; - else - d = DotProduct(plane.normal, p) - plane.dist; - if (d < 0) - num = node.children[1]; - else - num = node.children[0]; - } - - c_pointcontents++; // optimize counter - - return -1 - num; - } - - public static int CM_PointLeafnum(float[] p) { - if (numplanes == 0) - return 0; // sound may call this without map loaded - return CM_PointLeafnum_r(p, 0); - } - - /* - ============= - CM_BoxLeafnums - - Fills in a list of all the leafs touched - ============= - */ - static int leaf_count, leaf_maxcount; - static int leaf_list[]; - static float leaf_mins[], leaf_maxs[]; - static int leaf_topnode; - - public static void CM_BoxLeafnums_r(int nodenum) { - cplane_t plane; - cnode_t node; - int s; - - while (true) { - if (nodenum < 0) { - if (leaf_count >= leaf_maxcount) { - //TODO: here is still an error. - //Com.DPrintf("CM_BoxLeafnums_r: overflow\n"); - return; - } - leaf_list[leaf_count++] = -1 - nodenum; - return; - } - - node = map_nodes[nodenum]; - plane = node.plane; - - s = Math3D.BoxOnPlaneSide(leaf_mins, leaf_maxs, plane); - - if (s == 1) - nodenum = node.children[0]; - else if (s == 2) - nodenum = node.children[1]; - else { - // go down both - if (leaf_topnode == -1) - leaf_topnode = nodenum; - CM_BoxLeafnums_r(node.children[0]); - nodenum = node.children[1]; - } - } - } - - public static int CM_BoxLeafnums_headnode(float[] mins, float[] maxs, int list[], int listsize, int headnode, int topnode[]) { - leaf_list = list; - leaf_count = 0; - leaf_maxcount = listsize; - leaf_mins = mins; - leaf_maxs = maxs; - - leaf_topnode = -1; - - CM_BoxLeafnums_r(headnode); - - if (topnode != null) - topnode[0] = leaf_topnode; - - return leaf_count; - } - - public static int CM_BoxLeafnums(float[] mins, float[] maxs, int list[], int listsize, int topnode[]) { - return CM_BoxLeafnums_headnode(mins, maxs, list, listsize, map_cmodels[0].headnode, topnode); - } - - /* - public static class intwrap1 { - public intwrap(int i) { - this.i = i; - } - public int i; - } - */ - /* - ================== - CM_PointContents - ================== - */ - public static int PointContents(float[] p, int headnode) { - int l; - - if (numnodes == 0) // map not loaded - return 0; - - l = CM_PointLeafnum_r(p, headnode); - - return map_leafs[l].contents; - } - - /* - ================== - CM_TransformedPointContents - - Handles offseting and rotation of the end points for moving and - rotating entities - ================== - */ - public static int TransformedPointContents(float[] p, int headnode, float[] origin, float[] angles) { - float[] p_l = { 0, 0, 0 }; - float[] temp = { 0, 0, 0 }; - float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; - int l; - - // subtract origin offset - VectorSubtract(p, origin, p_l); - - // rotate start and end into the models frame of reference - if (headnode != box_headnode && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) { - AngleVectors(angles, forward, right, up); - - VectorCopy(p_l, temp); - p_l[0] = DotProduct(temp, forward); - p_l[1] = -DotProduct(temp, right); - p_l[2] = DotProduct(temp, up); - } - - l = CM_PointLeafnum_r(p_l, headnode); - - return map_leafs[l].contents; - } - - /* - =============================================================================== - - BOX TRACING - - =============================================================================== - */ - - // 1/32 epsilon to keep floating point happy - private static final float DIST_EPSILON = 0.03125f; - - private static float[] trace_start = { 0, 0, 0 }, trace_end = { 0, 0, 0 }; - private static float[] trace_mins = { 0, 0, 0 }, trace_maxs = { 0, 0, 0 }; - private static float[] trace_extents = { 0, 0, 0 }; - - private static trace_t trace_trace = new trace_t(); - private static int trace_contents; - private static boolean trace_ispoint; // optimized case - - /* - ================ - CM_ClipBoxToBrush - ================ - */ - public static void CM_ClipBoxToBrush(float[] mins, float[] maxs, float[] p1, float[] p2, trace_t trace, cbrush_t brush) { - int i, j; - cplane_t plane, clipplane; - float dist; - float enterfrac, leavefrac; - float[] ofs = { 0, 0, 0 }; - float d1, d2; - boolean getout, startout; - float f; - cbrushside_t side, leadside; - - enterfrac = -1; - leavefrac = 1; - clipplane = null; - - if (brush.numsides == 0) - return; - - c_brush_traces++; - - getout = false; - startout = false; - leadside = null; - - for (i = 0; i < brush.numsides; i++) { - side = map_brushsides[brush.firstbrushside + i]; - plane = side.plane; - - // FIXME: special case for axial - - if (!trace_ispoint) { // general box case - - // push the plane out apropriately for mins/maxs - - // FIXME: use signbits into 8 way lookup for each mins/maxs - for (j = 0; j < 3; j++) { - if (plane.normal[j] < 0) - ofs[j] = maxs[j]; - else - ofs[j] = mins[j]; - } - dist = DotProduct(ofs, plane.normal); - dist = plane.dist - dist; - } - else { // special point case - dist = plane.dist; - } - - d1 = DotProduct(p1, plane.normal) - dist; - d2 = DotProduct(p2, plane.normal) - dist; - - if (d2 > 0) - getout = true; // endpoint is not in solid - if (d1 > 0) - startout = true; - - // if completely in front of face, no intersection - if (d1 > 0 && d2 >= d1) - return; - - if (d1 <= 0 && d2 <= 0) - continue; - - // crosses face - if (d1 > d2) { // enter - f = (d1 - DIST_EPSILON) / (d1 - d2); - if (f > enterfrac) { - enterfrac = f; - clipplane = plane; - leadside = side; - } - } - else { // leave - f = (d1 + DIST_EPSILON) / (d1 - d2); - if (f < leavefrac) - leavefrac = f; - } - } - - if (!startout) { // original point was inside brush - trace.startsolid = true; - if (!getout) - trace.allsolid = true; - return; - } - if (enterfrac < leavefrac) { - if (enterfrac > -1 && enterfrac < trace.fraction) { - if (enterfrac < 0) - enterfrac = 0; - trace.fraction = enterfrac; - // copy - trace.plane.set(clipplane); - trace.surface = leadside.surface.c; - trace.contents = brush.contents; - } - } - } - - /* - ================ - CM_TestBoxInBrush - ================ - */ - public static void CM_TestBoxInBrush(float[] mins, float[] maxs, float[] p1, trace_t trace, cbrush_t brush) { - int i, j; - cplane_t plane; - float dist; - float[] ofs = { 0, 0, 0 }; - float d1; - cbrushside_t side; - - if (brush.numsides == 0) - return; - - for (i = 0; i < brush.numsides; i++) { - side = map_brushsides[brush.firstbrushside + i]; - plane = side.plane; - - // FIXME: special case for axial - // general box case - // push the plane out apropriately for mins/maxs - // FIXME: use signbits into 8 way lookup for each mins/maxs - - for (j = 0; j < 3; j++) { - if (plane.normal[j] < 0) - ofs[j] = maxs[j]; - else - ofs[j] = mins[j]; - } - dist = DotProduct(ofs, plane.normal); - dist = plane.dist - dist; - - d1 = DotProduct(p1, plane.normal) - dist; - - // if completely in front of face, no intersection - if (d1 > 0) - return; - - } - - // inside this brush - trace.startsolid = trace.allsolid = true; - trace.fraction = 0; - trace.contents = brush.contents; - } - - /* - ================ - CM_TraceToLeaf - ================ - */ - public static void CM_TraceToLeaf(int leafnum) { - int k; - int brushnum; - cleaf_t leaf; - cbrush_t b; - - leaf = map_leafs[leafnum]; - if (0 == (leaf.contents & trace_contents)) - return; - - // trace line against all brushes in the leaf - for (k = 0; k < leaf.numleafbrushes; k++) { - - brushnum = map_leafbrushes[leaf.firstleafbrush + k]; - b = map_brushes[brushnum]; - if (b.checkcount == checkcount) - continue; // already checked this brush in another leaf - b.checkcount = checkcount; - - if (0 == (b.contents & trace_contents)) - continue; - CM_ClipBoxToBrush(trace_mins, trace_maxs, trace_start, trace_end, trace_trace, b); - if (0 == trace_trace.fraction) - return; - } - - } - - /* - ================ - CM_TestInLeaf - ================ - */ - public static void CM_TestInLeaf(int leafnum) { - int k; - int brushnum; - cleaf_t leaf; - cbrush_t b; - - leaf = map_leafs[leafnum]; - if (0 == (leaf.contents & trace_contents)) - return; - // trace line against all brushes in the leaf - for (k = 0; k < leaf.numleafbrushes; k++) { - brushnum = map_leafbrushes[leaf.firstleafbrush + k]; - b = map_brushes[brushnum]; - if (b.checkcount == checkcount) - continue; // already checked this brush in another leaf - b.checkcount = checkcount; - - if (0 == (b.contents & trace_contents)) - continue; - CM_TestBoxInBrush(trace_mins, trace_maxs, trace_start, trace_trace, b); - if (0 == trace_trace.fraction) - return; - } - - } - - /* - ================== - CM_RecursiveHullCheck - ================== - */ - public static void CM_RecursiveHullCheck(int num, float p1f, float p2f, float[] p1, float[] p2) { - cnode_t node; - cplane_t plane; - float t1, t2, offset; - float frac, frac2; - float idist; - int i; - float[] mid = { 0, 0, 0 }; - int side; - float midf; - - if (trace_trace.fraction <= p1f) - return; // already hit something nearer - - // if < 0, we are in a leaf node - if (num < 0) { - CM_TraceToLeaf(-1 - num); - return; - } - - // - // find the point distances to the seperating plane - // and the offset for the size of the box - // - node = map_nodes[num]; - plane = node.plane; - - if (plane.type < 3) { - t1 = p1[plane.type] - plane.dist; - t2 = p2[plane.type] - plane.dist; - offset = trace_extents[plane.type]; - } - else { - t1 = DotProduct(plane.normal, p1) - plane.dist; - t2 = DotProduct(plane.normal, p2) - plane.dist; - if (trace_ispoint) - offset = 0; - else - offset = - Math.abs(trace_extents[0] * plane.normal[0]) - + Math.abs(trace_extents[1] * plane.normal[1]) - + Math.abs(trace_extents[2] * plane.normal[2]); - } - - // see which sides we need to consider - if (t1 >= offset && t2 >= offset) { - CM_RecursiveHullCheck(node.children[0], p1f, p2f, p1, p2); - return; - } - if (t1 < -offset && t2 < -offset) { - CM_RecursiveHullCheck(node.children[1], p1f, p2f, p1, p2); - return; - } - - // put the crosspoint DIST_EPSILON pixels on the near side - if (t1 < t2) { - idist = 1.0f / (t1 - t2); - side = 1; - frac2 = (t1 + offset + DIST_EPSILON) * idist; - frac = (t1 - offset + DIST_EPSILON) * idist; - } - else if (t1 > t2) { - idist = 1.0f / (t1 - t2); - side = 0; - frac2 = (t1 - offset - DIST_EPSILON) * idist; - frac = (t1 + offset + DIST_EPSILON) * idist; - } - else { - side = 0; - frac = 1; - frac2 = 0; - } - - // move up to the node - if (frac < 0) - frac = 0; - if (frac > 1) - frac = 1; - - midf = p1f + (p2f - p1f) * frac; - for (i = 0; i < 3; i++) - mid[i] = p1[i] + frac * (p2[i] - p1[i]); - - CM_RecursiveHullCheck(node.children[side], p1f, midf, p1, mid); - - // go past the node - if (frac2 < 0) - frac2 = 0; - if (frac2 > 1) - frac2 = 1; - - midf = p1f + (p2f - p1f) * frac2; - for (i = 0; i < 3; i++) - mid[i] = p1[i] + frac2 * (p2[i] - p1[i]); - - CM_RecursiveHullCheck(node.children[side ^ 1], midf, p2f, mid, p2); - } - - //====================================================================== - - /* - ================== - CM_BoxTrace - ================== - */ - public static trace_t BoxTrace(float[] start, float[] end, float[] mins, float[] maxs, int headnode, int brushmask) { - - // for multi-check avoidance - checkcount++; - - // for statistics, may be zeroed - c_traces++; - - // fill in a default trace - //was: memset(& trace_trace, 0, sizeof(trace_trace)); - trace_trace = new trace_t(); - - trace_trace.fraction = 1; - trace_trace.surface = nullsurface.c; - - if (numnodes == 0) // map not loaded - { - Com.DPrintf("dummy trace zurueck, da map not loaded!\n"); - return trace_trace; - } - - trace_contents = brushmask; - VectorCopy(start, trace_start); - VectorCopy(end, trace_end); - VectorCopy(mins, trace_mins); - VectorCopy(maxs, trace_maxs); - - // - // check for position test special case - // - if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) { - - int leafs[] = new int[1024]; - int i, numleafs; - float[] c1 = { 0, 0, 0 }, c2 = { 0, 0, 0 }; - int topnode = 0; - - VectorAdd(start, mins, c1); - VectorAdd(start, maxs, c2); - - for (i = 0; i < 3; i++) { - c1[i] -= 1; - c2[i] += 1; - } - - int tn[] = {topnode}; - - numleafs = CM_BoxLeafnums_headnode(c1, c2, leafs, 1024, headnode, tn); - topnode = tn[0]; - for (i = 0; i < numleafs; i++) { - CM_TestInLeaf(leafs[i]); - if (trace_trace.allsolid) - break; - } - VectorCopy(start, trace_trace.endpos); - return trace_trace; - } - - // - // check for point special case - // - if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0 && maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0) { - trace_ispoint = true; - VectorClear(trace_extents); - } - else { - trace_ispoint = false; - trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0]; - trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1]; - trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2]; - } - - // - // general sweeping through world - // - CM_RecursiveHullCheck(headnode, 0, 1, start, end); - - if (trace_trace.fraction == 1) { - VectorCopy(end, trace_trace.endpos); - } - else { - for (int i = 0; i < 3; i++) - trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]); - } - return trace_trace; - } - - /* - ================== - CM_TransformedBoxTrace - - Handles offseting and rotation of the end points for moving and - rotating entities - ================== - */ - public static trace_t TransformedBoxTrace( - float[] start, - float[] end, - float[] mins, - float[] maxs, - int headnode, - int brushmask, - float[] origin, - float[] angles) { - trace_t trace; - float[] start_l = { 0, 0, 0 }, end_l = { 0, 0, 0 }; - float[] a = { 0, 0, 0 }; - float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; - float[] temp = { 0, 0, 0 }; - boolean rotated; - - // subtract origin offset - VectorSubtract(start, origin, start_l); - VectorSubtract(end, origin, end_l); - - // rotate start and end into the models frame of reference - if (headnode != box_headnode && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) - rotated = true; - else - rotated = false; - - if (rotated) { - AngleVectors(angles, forward, right, up); - - VectorCopy(start_l, temp); - start_l[0] = DotProduct(temp, forward); - start_l[1] = -DotProduct(temp, right); - start_l[2] = DotProduct(temp, up); - - VectorCopy(end_l, temp); - end_l[0] = DotProduct(temp, forward); - end_l[1] = -DotProduct(temp, right); - end_l[2] = DotProduct(temp, up); - } - - // sweep the box through the model - trace = BoxTrace(start_l, end_l, mins, maxs, headnode, brushmask); - - if (rotated && trace.fraction != 1.0) { - // FIXME: figure out how to do this with existing angles - VectorNegate(angles, a); - AngleVectors(a, forward, right, up); - - VectorCopy(trace.plane.normal, temp); - trace.plane.normal[0] = DotProduct(temp, forward); - trace.plane.normal[1] = -DotProduct(temp, right); - trace.plane.normal[2] = DotProduct(temp, up); - } - - trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]); - trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]); - trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]); - - return trace; - } - - /* - =============================================================================== - PVS / PHS - =============================================================================== - */ - - /* - =================== - CM_DecompressVis - =================== - */ - public static void CM_DecompressVis(byte in[], int offset, byte out[]) { - int c; - - int row; - - row = (numclusters + 7) >> 3; - int outp = 0; - int inp = offset; - - if (in == null || numvisibility == 0) { // no vis info, so make all visible - while (row != 0) { - out[outp++] = (byte) 0xFF; - row--; - } - return; - } - - do { - if (in[inp] != 0) { - out[outp++] = in[inp++]; - continue; - } - - c = in[inp + 1] & 0xFF; - inp += 2; - if (outp + c > row) { - c = row - (outp); - Com.DPrintf("warning: Vis decompression overrun\n"); - } - while (c != 0) { - out[outp++] = 0; - c--; - } - } - while (outp < row); - } - - public static byte pvsrow[] = new byte[MAX_MAP_LEAFS / 8]; - public static byte phsrow[] = new byte[MAX_MAP_LEAFS / 8]; - - public static byte[] CM_ClusterPVS(int cluster) { - if (cluster == -1) - Arrays.fill(pvsrow, 0, (numclusters + 7) >> 3, (byte)0); - else - CM_DecompressVis(map_visibility, map_vis.bitofs[cluster][DVIS_PVS], pvsrow); - return pvsrow; - } - - public static byte[] CM_ClusterPHS(int cluster) { - if (cluster == -1) - Arrays.fill(phsrow, 0, (numclusters + 7) >> 3, (byte)0); - else - CM_DecompressVis(map_visibility, map_vis.bitofs[cluster][Defines.DVIS_PHS], phsrow); - return phsrow; - } - - /* - =============================================================================== - AREAPORTALS - =============================================================================== - */ - - public static void FloodArea_r(carea_t area, int floodnum) { - //Com.Printf("FloodArea_r(" + floodnum + ")...\n"); - int i; - qfiles.dareaportal_t p; - - if (area.floodvalid == floodvalid) { - if (area.floodnum == floodnum) - return; - Com.Error(ERR_DROP, "FloodArea_r: reflooded"); - } - - area.floodnum = floodnum; - area.floodvalid = floodvalid; - - for (i = 0; i < area.numareaportals; i++) { - p = map_areaportals[area.firstareaportal + i]; - if (portalopen[p.portalnum]) - FloodArea_r(map_areas[p.otherarea], floodnum); - } - } - - /* - ==================== - FloodAreaConnections - ==================== - */ - public static void FloodAreaConnections() { - Com.DPrintf("FloodAreaConnections...\n"); - - int i; - carea_t area; - int floodnum; - - // all current floods are now invalid - floodvalid++; - floodnum = 0; - - // area 0 is not used - for (i = 1; i < numareas; i++) { - - area = map_areas[i]; - - if (area.floodvalid == floodvalid) - continue; // already flooded into - floodnum++; - FloodArea_r(area, floodnum); - } - } - - /* - ================= - CM_SetAreaPortalState - ================= - */ - public static void CM_SetAreaPortalState(int portalnum, boolean open) { - if (portalnum > numareaportals) - Com.Error(ERR_DROP, "areaportal > numareaportals"); - - portalopen[portalnum] = open; - FloodAreaConnections(); - } - - /* - ================= - CM_AreasConnected - ================= - */ - - public static boolean CM_AreasConnected(int area1, int area2) { - if (map_noareas.value != 0) - return true; - - if (area1 > numareas || area2 > numareas) - Com.Error(ERR_DROP, "area > numareas"); - - if (map_areas[area1].floodnum == map_areas[area2].floodnum) - return true; - - return false; - } - - /* - ================= - CM_WriteAreaBits - - Writes a length byte followed by a bit vector of all the areas - that area in the same flood as the area parameter - - This is used by the client refreshes to cull visibility - ================= - */ - public static int CM_WriteAreaBits(byte buffer[], int area) { - int i; - int floodnum; - int bytes; - - bytes = (numareas + 7) >> 3; - - if (map_noareas.value != 0) { // for debugging, send everything - Arrays.fill(buffer, 0, bytes, (byte)255); - } - else { - Arrays.fill(buffer, 0, bytes, (byte)0); - floodnum = map_areas[area].floodnum; - for (i = 0; i < numareas; i++) { - if (map_areas[i].floodnum == floodnum || area == 0) - buffer[i >> 3] |= 1 << (i & 7); - } - } - - return bytes; - } - - /* - =================== - CM_WritePortalState - - Writes the portal state to a savegame file - =================== - */ - - public static void CM_WritePortalState(RandomAccessFile os) { - - //was: fwrite(portalopen, sizeof(portalopen), 1, f); - try { - - for (int n = 0; n < portalopen.length; n++) - if (portalopen[n]) - os.writeInt(1); - else - os.writeInt(0); - } - catch (Exception e) { - Com.Printf("ERROR:" + e); - e.printStackTrace(); - } - } - - /* - =================== - CM_ReadPortalState - - Reads the portal state from a savegame file - and recalculates the area connections - =================== - */ - public static void CM_ReadPortalState(RandomAccessFile f) { - - //was: FS_Read(portalopen, sizeof(portalopen), f); - int len = portalopen.length * 4; - - byte buf[] = new byte[len]; - - - FS.Read(buf, len, f); - - ByteBuffer bb = ByteBuffer.wrap(buf); - IntBuffer ib = bb.asIntBuffer(); - - for (int n = 0; n < portalopen.length; n++) - portalopen[n] = ib.get() != 0; - - FloodAreaConnections(); - } - - /* - ============= - CM_HeadnodeVisible - - Returns true if any leaf under headnode has a cluster that - is potentially visible - ============= - */ - public static boolean CM_HeadnodeVisible(int nodenum, byte visbits[]) { - int leafnum; - int cluster; - cnode_t node; - - if (nodenum < 0) { - leafnum = -1 - nodenum; - cluster = map_leafs[leafnum].cluster; - if (cluster == -1) - return false; - if (0 != (visbits[cluster >>> 3] & (1 << (cluster & 7)))) - return true; - return false; - } - - node = map_nodes[nodenum]; - if (CM_HeadnodeVisible(node.children[0], visbits)) - return true; - return CM_HeadnodeVisible(node.children[1], visbits); - } -} + /* + * ================= CMod_LoadVisibility ================= + */ + public static void CMod_LoadVisibility(lump_t l) { + Com.DPrintf("CMod_LoadVisibility...\n"); + int i; + + numvisibility = l.filelen; + + Com.DPrintf(" numvisibility=" + numvisibility + "\n"); + + if (l.filelen > Defines.MAX_MAP_VISIBILITY) + Com.Error(Defines.ERR_DROP, "Map has too large visibility lump"); + + System.arraycopy(cmod_base, l.fileofs, map_visibility, 0, l.filelen); + + ByteBuffer bb = ByteBuffer.wrap(map_visibility, 0, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + map_vis = new qfiles.dvis_t(bb); + + } + + /* + * ================= CMod_LoadEntityString ================= + */ + public static void CMod_LoadEntityString(lump_t l) { + Com.DPrintf("CMod_LoadEntityString...\n"); + + numentitychars = l.filelen; + + if (l.filelen > Defines.MAX_MAP_ENTSTRING) + Com.Error(Defines.ERR_DROP, "Map has too large entity lump"); + + int x = 0; + for (; x < l.filelen && cmod_base[x + l.fileofs] != 0; x++) + ; + + map_entitystring = new String(cmod_base, l.fileofs, x).trim(); + } + + /* + * ================== CM_InlineModel ================== + */ + + // works fine + public static cmodel_t InlineModel(String name) { + int num; + + if (name == null || name.charAt(0) != '*') + Com.Error(Defines.ERR_DROP, "CM_InlineModel: bad name"); + + num = Lib.atoi(name.substring(1)); + + if (num < 1 || num >= numcmodels) + Com.Error(Defines.ERR_DROP, "CM_InlineModel: bad number"); + + return map_cmodels[num]; + } + + public static int CM_NumClusters() { + return numclusters; + } + + public static int CM_NumInlineModels() { + return numcmodels; + } + + public static String CM_EntityString() { + return map_entitystring; + } + + public static int CM_LeafContents(int leafnum) { + if (leafnum < 0 || leafnum >= numleafs) + Com.Error(Defines.ERR_DROP, "CM_LeafContents: bad number"); + return map_leafs[leafnum].contents; + } + + public static int CM_LeafCluster(int leafnum) { + if (leafnum < 0 || leafnum >= numleafs) + Com.Error(Defines.ERR_DROP, "CM_LeafCluster: bad number"); + return map_leafs[leafnum].cluster; + } + + public static int CM_LeafArea(int leafnum) { + if (leafnum < 0 || leafnum >= numleafs) + Com.Error(Defines.ERR_DROP, "CM_LeafArea: bad number"); + return map_leafs[leafnum].area; + } + + //======================================================================= + + static cplane_t box_planes[]; + + static int box_headnode; + + static cbrush_t box_brush; + + static cleaf_t box_leaf; + + /* + * =================== CM_InitBoxHull + * + * Set up the planes and nodes so that the six floats of a bounding box can + * just be stored out and get a proper clipping hull structure. + * =================== + */ + public static void CM_InitBoxHull() { + int i; + int side; + cnode_t c; + cplane_t p; + cbrushside_t s; + + box_headnode = numnodes; // noch platz f?r 6 brushes + + box_planes = new cplane_t[] { map_planes[numplanes], + map_planes[numplanes + 1], map_planes[numplanes + 2], + map_planes[numplanes + 3], map_planes[numplanes + 4], + map_planes[numplanes + 5], map_planes[numplanes + 6], + map_planes[numplanes + 7], map_planes[numplanes + 8], + map_planes[numplanes + 9], map_planes[numplanes + 10], + map_planes[numplanes + 11], map_planes[numplanes + 12] }; + + if (numnodes + 6 > Defines.MAX_MAP_NODES + || numbrushes + 1 > Defines.MAX_MAP_BRUSHES + || numleafbrushes + 1 > Defines.MAX_MAP_LEAFBRUSHES + || numbrushsides + 6 > Defines.MAX_MAP_BRUSHSIDES + || numplanes + 12 > Defines.MAX_MAP_PLANES) + Com.Error(Defines.ERR_DROP, "Not enough room for box tree"); + + box_brush = map_brushes[numbrushes]; + box_brush.numsides = 6; + box_brush.firstbrushside = numbrushsides; + box_brush.contents = Defines.CONTENTS_MONSTER; + + box_leaf = map_leafs[numleafs]; + box_leaf.contents = Defines.CONTENTS_MONSTER; + box_leaf.firstleafbrush = (short) numleafbrushes; + box_leaf.numleafbrushes = 1; + + map_leafbrushes[numleafbrushes] = numbrushes; + + for (i = 0; i < 6; i++) { + side = i & 1; + + // brush sides + s = map_brushsides[numbrushsides + i]; + s.plane = map_planes[(numplanes + i * 2 + side)]; + s.surface = nullsurface; + + // nodes + c = map_nodes[box_headnode + i]; + c.plane = map_planes[(numplanes + i * 2)]; + c.children[side] = -1 - emptyleaf; + if (i != 5) + c.children[side ^ 1] = box_headnode + i + 1; + else + c.children[side ^ 1] = -1 - numleafs; + + // planes + p = box_planes[i * 2]; + p.type = (byte) (i >> 1); + p.signbits = 0; + Math3D.VectorClear(p.normal); + p.normal[i >> 1] = 1; + + p = box_planes[i * 2 + 1]; + p.type = (byte) (3 + (i >> 1)); + p.signbits = 0; + Math3D.VectorClear(p.normal); + p.normal[i >> 1] = -1; + } + } + + /* + * =================== CM_HeadnodeForBox + * + * To keep everything totally uniform, bounding boxes are turned into small + * BSP trees instead of being compared directly. =================== + */ + public static int HeadnodeForBox(float[] mins, float[] maxs) { + box_planes[0].dist = maxs[0]; + box_planes[1].dist = -maxs[0]; + box_planes[2].dist = mins[0]; + box_planes[3].dist = -mins[0]; + box_planes[4].dist = maxs[1]; + box_planes[5].dist = -maxs[1]; + box_planes[6].dist = mins[1]; + box_planes[7].dist = -mins[1]; + box_planes[8].dist = maxs[2]; + box_planes[9].dist = -maxs[2]; + box_planes[10].dist = mins[2]; + box_planes[11].dist = -mins[2]; + + return box_headnode; + } + + /* + * ================== CM_PointLeafnum_r ================== + */ + public static int CM_PointLeafnum_r(float[] p, int num) { + float d; + cnode_t node; + cplane_t plane; + + while (num >= 0) { + node = map_nodes[num]; + plane = node.plane; + + if (plane.type < 3) + d = p[plane.type] - plane.dist; + else + d = Math3D.DotProduct(plane.normal, p) - plane.dist; + if (d < 0) + num = node.children[1]; + else + num = node.children[0]; + } + + Globals.c_pointcontents++; // optimize counter + + return -1 - num; + } + + public static int CM_PointLeafnum(float[] p) { + if (numplanes == 0) + return 0; // sound may call this without map loaded + return CM_PointLeafnum_r(p, 0); + } + + /* + * ============= CM_BoxLeafnums + * + * Fills in a list of all the leafs touched ============= + */ + static int leaf_count, leaf_maxcount; + + static int leaf_list[]; + + static float leaf_mins[], leaf_maxs[]; + + static int leaf_topnode; + + public static void CM_BoxLeafnums_r(int nodenum) { + cplane_t plane; + cnode_t node; + int s; + + while (true) { + if (nodenum < 0) { + if (leaf_count >= leaf_maxcount) { + //TODO: here is still an error. + //Com.DPrintf("CM_BoxLeafnums_r: overflow\n"); + return; + } + leaf_list[leaf_count++] = -1 - nodenum; + return; + } + + node = map_nodes[nodenum]; + plane = node.plane; + + s = Math3D.BoxOnPlaneSide(leaf_mins, leaf_maxs, plane); + + if (s == 1) + nodenum = node.children[0]; + else if (s == 2) + nodenum = node.children[1]; + else { + // go down both + if (leaf_topnode == -1) + leaf_topnode = nodenum; + CM_BoxLeafnums_r(node.children[0]); + nodenum = node.children[1]; + } + } + } + + public static int CM_BoxLeafnums_headnode(float[] mins, float[] maxs, + int list[], int listsize, int headnode, int topnode[]) { + leaf_list = list; + leaf_count = 0; + leaf_maxcount = listsize; + leaf_mins = mins; + leaf_maxs = maxs; + + leaf_topnode = -1; + + CM_BoxLeafnums_r(headnode); + + if (topnode != null) + topnode[0] = leaf_topnode; + + return leaf_count; + } + + public static int CM_BoxLeafnums(float[] mins, float[] maxs, int list[], + int listsize, int topnode[]) { + return CM_BoxLeafnums_headnode(mins, maxs, list, listsize, + map_cmodels[0].headnode, topnode); + } + + /* + * public static class intwrap1 { public intwrap(int i) { this.i = i; } + * public int i; } + */ + /* + * ================== CM_PointContents ================== + */ + public static int PointContents(float[] p, int headnode) { + int l; + + if (numnodes == 0) // map not loaded + return 0; + + l = CM_PointLeafnum_r(p, headnode); + + return map_leafs[l].contents; + } + + /* + * ================== CM_TransformedPointContents + * + * Handles offseting and rotation of the end points for moving and rotating + * entities ================== + */ + public static int TransformedPointContents(float[] p, int headnode, + float[] origin, float[] angles) { + float[] p_l = { 0, 0, 0 }; + float[] temp = { 0, 0, 0 }; + float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; + int l; + + // subtract origin offset + Math3D.VectorSubtract(p, origin, p_l); + + // rotate start and end into the models frame of reference + if (headnode != box_headnode + && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) { + Math3D.AngleVectors(angles, forward, right, up); + + Math3D.VectorCopy(p_l, temp); + p_l[0] = Math3D.DotProduct(temp, forward); + p_l[1] = -Math3D.DotProduct(temp, right); + p_l[2] = Math3D.DotProduct(temp, up); + } + + l = CM_PointLeafnum_r(p_l, headnode); + + return map_leafs[l].contents; + } + + /* + * =============================================================================== + * + * BOX TRACING + * + * =============================================================================== + */ + + // 1/32 epsilon to keep floating point happy + private static final float DIST_EPSILON = 0.03125f; + + private static float[] trace_start = { 0, 0, 0 }, trace_end = { 0, 0, 0 }; + + private static float[] trace_mins = { 0, 0, 0 }, trace_maxs = { 0, 0, 0 }; + + private static float[] trace_extents = { 0, 0, 0 }; + + private static trace_t trace_trace = new trace_t(); + + private static int trace_contents; + + private static boolean trace_ispoint; // optimized case + + /* + * ================ CM_ClipBoxToBrush ================ + */ + public static void CM_ClipBoxToBrush(float[] mins, float[] maxs, + float[] p1, float[] p2, trace_t trace, cbrush_t brush) { + int i, j; + cplane_t plane, clipplane; + float dist; + float enterfrac, leavefrac; + float[] ofs = { 0, 0, 0 }; + float d1, d2; + boolean getout, startout; + float f; + cbrushside_t side, leadside; + + enterfrac = -1; + leavefrac = 1; + clipplane = null; + + if (brush.numsides == 0) + return; + + Globals.c_brush_traces++; + + getout = false; + startout = false; + leadside = null; + + for (i = 0; i < brush.numsides; i++) { + side = map_brushsides[brush.firstbrushside + i]; + plane = side.plane; + + // FIXME: special case for axial + + if (!trace_ispoint) { // general box case + + // push the plane out apropriately for mins/maxs + + // FIXME: use signbits into 8 way lookup for each mins/maxs + for (j = 0; j < 3; j++) { + if (plane.normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + dist = Math3D.DotProduct(ofs, plane.normal); + dist = plane.dist - dist; + } else { // special point case + dist = plane.dist; + } + + d1 = Math3D.DotProduct(p1, plane.normal) - dist; + d2 = Math3D.DotProduct(p2, plane.normal) - dist; + + if (d2 > 0) + getout = true; // endpoint is not in solid + if (d1 > 0) + startout = true; + + // if completely in front of face, no intersection + if (d1 > 0 && d2 >= d1) + return; + + if (d1 <= 0 && d2 <= 0) + continue; + + // crosses face + if (d1 > d2) { // enter + f = (d1 - DIST_EPSILON) / (d1 - d2); + if (f > enterfrac) { + enterfrac = f; + clipplane = plane; + leadside = side; + } + } else { // leave + f = (d1 + DIST_EPSILON) / (d1 - d2); + if (f < leavefrac) + leavefrac = f; + } + } + + if (!startout) { // original point was inside brush + trace.startsolid = true; + if (!getout) + trace.allsolid = true; + return; + } + if (enterfrac < leavefrac) { + if (enterfrac > -1 && enterfrac < trace.fraction) { + if (enterfrac < 0) + enterfrac = 0; + trace.fraction = enterfrac; + // copy + trace.plane.set(clipplane); + trace.surface = leadside.surface.c; + trace.contents = brush.contents; + } + } + } + + /* + * ================ CM_TestBoxInBrush ================ + */ + public static void CM_TestBoxInBrush(float[] mins, float[] maxs, + float[] p1, trace_t trace, cbrush_t brush) { + int i, j; + cplane_t plane; + float dist; + float[] ofs = { 0, 0, 0 }; + float d1; + cbrushside_t side; + + if (brush.numsides == 0) + return; + + for (i = 0; i < brush.numsides; i++) { + side = map_brushsides[brush.firstbrushside + i]; + plane = side.plane; + + // FIXME: special case for axial + // general box case + // push the plane out apropriately for mins/maxs + // FIXME: use signbits into 8 way lookup for each mins/maxs + + for (j = 0; j < 3; j++) { + if (plane.normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + dist = Math3D.DotProduct(ofs, plane.normal); + dist = plane.dist - dist; + + d1 = Math3D.DotProduct(p1, plane.normal) - dist; + + // if completely in front of face, no intersection + if (d1 > 0) + return; + + } + + // inside this brush + trace.startsolid = trace.allsolid = true; + trace.fraction = 0; + trace.contents = brush.contents; + } + + /* + * ================ CM_TraceToLeaf ================ + */ + public static void CM_TraceToLeaf(int leafnum) { + int k; + int brushnum; + cleaf_t leaf; + cbrush_t b; + + leaf = map_leafs[leafnum]; + if (0 == (leaf.contents & trace_contents)) + return; + + // trace line against all brushes in the leaf + for (k = 0; k < leaf.numleafbrushes; k++) { + + brushnum = map_leafbrushes[leaf.firstleafbrush + k]; + b = map_brushes[brushnum]; + if (b.checkcount == checkcount) + continue; // already checked this brush in another leaf + b.checkcount = checkcount; + + if (0 == (b.contents & trace_contents)) + continue; + CM_ClipBoxToBrush(trace_mins, trace_maxs, trace_start, trace_end, + trace_trace, b); + if (0 == trace_trace.fraction) + return; + } + + } + + /* + * ================ CM_TestInLeaf ================ + */ + public static void CM_TestInLeaf(int leafnum) { + int k; + int brushnum; + cleaf_t leaf; + cbrush_t b; + + leaf = map_leafs[leafnum]; + if (0 == (leaf.contents & trace_contents)) + return; + // trace line against all brushes in the leaf + for (k = 0; k < leaf.numleafbrushes; k++) { + brushnum = map_leafbrushes[leaf.firstleafbrush + k]; + b = map_brushes[brushnum]; + if (b.checkcount == checkcount) + continue; // already checked this brush in another leaf + b.checkcount = checkcount; + + if (0 == (b.contents & trace_contents)) + continue; + CM_TestBoxInBrush(trace_mins, trace_maxs, trace_start, trace_trace, + b); + if (0 == trace_trace.fraction) + return; + } + + } + + /* + * ================== CM_RecursiveHullCheck ================== + */ + public static void CM_RecursiveHullCheck(int num, float p1f, float p2f, + float[] p1, float[] p2) { + cnode_t node; + cplane_t plane; + float t1, t2, offset; + float frac, frac2; + float idist; + int i; + float[] mid = { 0, 0, 0 }; + int side; + float midf; + + if (trace_trace.fraction <= p1f) + return; // already hit something nearer + + // if < 0, we are in a leaf node + if (num < 0) { + CM_TraceToLeaf(-1 - num); + return; + } + + // + // find the point distances to the seperating plane + // and the offset for the size of the box + // + node = map_nodes[num]; + plane = node.plane; + + if (plane.type < 3) { + t1 = p1[plane.type] - plane.dist; + t2 = p2[plane.type] - plane.dist; + offset = trace_extents[plane.type]; + } else { + t1 = Math3D.DotProduct(plane.normal, p1) - plane.dist; + t2 = Math3D.DotProduct(plane.normal, p2) - plane.dist; + if (trace_ispoint) + offset = 0; + else + offset = Math.abs(trace_extents[0] * plane.normal[0]) + + Math.abs(trace_extents[1] * plane.normal[1]) + + Math.abs(trace_extents[2] * plane.normal[2]); + } + + // see which sides we need to consider + if (t1 >= offset && t2 >= offset) { + CM_RecursiveHullCheck(node.children[0], p1f, p2f, p1, p2); + return; + } + if (t1 < -offset && t2 < -offset) { + CM_RecursiveHullCheck(node.children[1], p1f, p2f, p1, p2); + return; + } + + // put the crosspoint DIST_EPSILON pixels on the near side + if (t1 < t2) { + idist = 1.0f / (t1 - t2); + side = 1; + frac2 = (t1 + offset + DIST_EPSILON) * idist; + frac = (t1 - offset + DIST_EPSILON) * idist; + } else if (t1 > t2) { + idist = 1.0f / (t1 - t2); + side = 0; + frac2 = (t1 - offset - DIST_EPSILON) * idist; + frac = (t1 + offset + DIST_EPSILON) * idist; + } else { + side = 0; + frac = 1; + frac2 = 0; + } + + // move up to the node + if (frac < 0) + frac = 0; + if (frac > 1) + frac = 1; + + midf = p1f + (p2f - p1f) * frac; + for (i = 0; i < 3; i++) + mid[i] = p1[i] + frac * (p2[i] - p1[i]); + + CM_RecursiveHullCheck(node.children[side], p1f, midf, p1, mid); + + // go past the node + if (frac2 < 0) + frac2 = 0; + if (frac2 > 1) + frac2 = 1; + + midf = p1f + (p2f - p1f) * frac2; + for (i = 0; i < 3; i++) + mid[i] = p1[i] + frac2 * (p2[i] - p1[i]); + + CM_RecursiveHullCheck(node.children[side ^ 1], midf, p2f, mid, p2); + } + + //====================================================================== + + /* + * ================== CM_BoxTrace ================== + */ + public static trace_t BoxTrace(float[] start, float[] end, float[] mins, + float[] maxs, int headnode, int brushmask) { + + // for multi-check avoidance + checkcount++; + + // for statistics, may be zeroed + Globals.c_traces++; + + // fill in a default trace + //was: memset(& trace_trace, 0, sizeof(trace_trace)); + trace_trace = new trace_t(); + + trace_trace.fraction = 1; + trace_trace.surface = nullsurface.c; + + if (numnodes == 0) // map not loaded + { + Com.DPrintf("dummy trace zurueck, da map not loaded!\n"); + return trace_trace; + } + + trace_contents = brushmask; + Math3D.VectorCopy(start, trace_start); + Math3D.VectorCopy(end, trace_end); + Math3D.VectorCopy(mins, trace_mins); + Math3D.VectorCopy(maxs, trace_maxs); + + // + // check for position test special case + // + if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) { + + int leafs[] = new int[1024]; + int i, numleafs; + float[] c1 = { 0, 0, 0 }, c2 = { 0, 0, 0 }; + int topnode = 0; + + Math3D.VectorAdd(start, mins, c1); + Math3D.VectorAdd(start, maxs, c2); + + for (i = 0; i < 3; i++) { + c1[i] -= 1; + c2[i] += 1; + } + + int tn[] = { topnode }; + + numleafs = CM_BoxLeafnums_headnode(c1, c2, leafs, 1024, headnode, + tn); + topnode = tn[0]; + for (i = 0; i < numleafs; i++) { + CM_TestInLeaf(leafs[i]); + if (trace_trace.allsolid) + break; + } + Math3D.VectorCopy(start, trace_trace.endpos); + return trace_trace; + } + + // + // check for point special case + // + if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0 && maxs[0] == 0 + && maxs[1] == 0 && maxs[2] == 0) { + trace_ispoint = true; + Math3D.VectorClear(trace_extents); + } else { + trace_ispoint = false; + trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0]; + trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1]; + trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2]; + } + + // + // general sweeping through world + // + CM_RecursiveHullCheck(headnode, 0, 1, start, end); + + if (trace_trace.fraction == 1) { + Math3D.VectorCopy(end, trace_trace.endpos); + } else { + for (int i = 0; i < 3; i++) + trace_trace.endpos[i] = start[i] + trace_trace.fraction + * (end[i] - start[i]); + } + return trace_trace; + } + + /* + * ================== CM_TransformedBoxTrace + * + * Handles offseting and rotation of the end points for moving and rotating + * entities ================== + */ + public static trace_t TransformedBoxTrace(float[] start, float[] end, + float[] mins, float[] maxs, int headnode, int brushmask, + float[] origin, float[] angles) { + trace_t trace; + float[] start_l = { 0, 0, 0 }, end_l = { 0, 0, 0 }; + float[] a = { 0, 0, 0 }; + float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; + float[] temp = { 0, 0, 0 }; + boolean rotated; + + // subtract origin offset + Math3D.VectorSubtract(start, origin, start_l); + Math3D.VectorSubtract(end, origin, end_l); + + // rotate start and end into the models frame of reference + if (headnode != box_headnode + && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) + rotated = true; + else + rotated = false; + + if (rotated) { + Math3D.AngleVectors(angles, forward, right, up); + + Math3D.VectorCopy(start_l, temp); + start_l[0] = Math3D.DotProduct(temp, forward); + start_l[1] = -Math3D.DotProduct(temp, right); + start_l[2] = Math3D.DotProduct(temp, up); + + Math3D.VectorCopy(end_l, temp); + end_l[0] = Math3D.DotProduct(temp, forward); + end_l[1] = -Math3D.DotProduct(temp, right); + end_l[2] = Math3D.DotProduct(temp, up); + } + + // sweep the box through the model + trace = BoxTrace(start_l, end_l, mins, maxs, headnode, brushmask); + + if (rotated && trace.fraction != 1.0) { + // FIXME: figure out how to do this with existing angles + Math3D.VectorNegate(angles, a); + Math3D.AngleVectors(a, forward, right, up); + + Math3D.VectorCopy(trace.plane.normal, temp); + trace.plane.normal[0] = Math3D.DotProduct(temp, forward); + trace.plane.normal[1] = -Math3D.DotProduct(temp, right); + trace.plane.normal[2] = Math3D.DotProduct(temp, up); + } + + trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]); + trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]); + trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]); + + return trace; + } + + /* + * =============================================================================== + * PVS / PHS + * =============================================================================== + */ + + /* + * =================== CM_DecompressVis =================== + */ + public static void CM_DecompressVis(byte in[], int offset, byte out[]) { + int c; + + int row; + + row = (numclusters + 7) >> 3; + int outp = 0; + int inp = offset; + + if (in == null || numvisibility == 0) { // no vis info, so make all + // visible + while (row != 0) { + out[outp++] = (byte) 0xFF; + row--; + } + return; + } + + do { + if (in[inp] != 0) { + out[outp++] = in[inp++]; + continue; + } + + c = in[inp + 1] & 0xFF; + inp += 2; + if (outp + c > row) { + c = row - (outp); + Com.DPrintf("warning: Vis decompression overrun\n"); + } + while (c != 0) { + out[outp++] = 0; + c--; + } + } while (outp < row); + } + + public static byte pvsrow[] = new byte[Defines.MAX_MAP_LEAFS / 8]; + + public static byte phsrow[] = new byte[Defines.MAX_MAP_LEAFS / 8]; + + public static byte[] CM_ClusterPVS(int cluster) { + if (cluster == -1) + Arrays.fill(pvsrow, 0, (numclusters + 7) >> 3, (byte) 0); + else + CM_DecompressVis(map_visibility, + map_vis.bitofs[cluster][Defines.DVIS_PVS], pvsrow); + return pvsrow; + } + + public static byte[] CM_ClusterPHS(int cluster) { + if (cluster == -1) + Arrays.fill(phsrow, 0, (numclusters + 7) >> 3, (byte) 0); + else + CM_DecompressVis(map_visibility, + map_vis.bitofs[cluster][Defines.DVIS_PHS], phsrow); + return phsrow; + } + + /* + * =============================================================================== + * AREAPORTALS + * =============================================================================== + */ + + public static void FloodArea_r(carea_t area, int floodnum) { + //Com.Printf("FloodArea_r(" + floodnum + ")...\n"); + int i; + qfiles.dareaportal_t p; + + if (area.floodvalid == floodvalid) { + if (area.floodnum == floodnum) + return; + Com.Error(Defines.ERR_DROP, "FloodArea_r: reflooded"); + } + + area.floodnum = floodnum; + area.floodvalid = floodvalid; + + for (i = 0; i < area.numareaportals; i++) { + p = map_areaportals[area.firstareaportal + i]; + if (portalopen[p.portalnum]) + FloodArea_r(map_areas[p.otherarea], floodnum); + } + } + + /* + * ==================== FloodAreaConnections ==================== + */ + public static void FloodAreaConnections() { + Com.DPrintf("FloodAreaConnections...\n"); + + int i; + carea_t area; + int floodnum; + + // all current floods are now invalid + floodvalid++; + floodnum = 0; + + // area 0 is not used + for (i = 1; i < numareas; i++) { + + area = map_areas[i]; + + if (area.floodvalid == floodvalid) + continue; // already flooded into + floodnum++; + FloodArea_r(area, floodnum); + } + } + + /* + * ================= CM_SetAreaPortalState ================= + */ + public static void CM_SetAreaPortalState(int portalnum, boolean open) { + if (portalnum > numareaportals) + Com.Error(Defines.ERR_DROP, "areaportal > numareaportals"); + + portalopen[portalnum] = open; + FloodAreaConnections(); + } + + /* + * ================= CM_AreasConnected ================= + */ + + public static boolean CM_AreasConnected(int area1, int area2) { + if (map_noareas.value != 0) + return true; + + if (area1 > numareas || area2 > numareas) + Com.Error(Defines.ERR_DROP, "area > numareas"); + + if (map_areas[area1].floodnum == map_areas[area2].floodnum) + return true; + + return false; + } + + /* + * ================= CM_WriteAreaBits + * + * Writes a length byte followed by a bit vector of all the areas that area + * in the same flood as the area parameter + * + * This is used by the client refreshes to cull visibility ================= + */ + public static int CM_WriteAreaBits(byte buffer[], int area) { + int i; + int floodnum; + int bytes; + + bytes = (numareas + 7) >> 3; + + if (map_noareas.value != 0) { // for debugging, send everything + Arrays.fill(buffer, 0, bytes, (byte) 255); + } else { + Arrays.fill(buffer, 0, bytes, (byte) 0); + floodnum = map_areas[area].floodnum; + for (i = 0; i < numareas; i++) { + if (map_areas[i].floodnum == floodnum || area == 0) + buffer[i >> 3] |= 1 << (i & 7); + } + } + + return bytes; + } + + /* + * =================== CM_WritePortalState + * + * Writes the portal state to a savegame file =================== + */ + + public static void CM_WritePortalState(RandomAccessFile os) { + + //was: fwrite(portalopen, sizeof(portalopen), 1, f); + try { + + for (int n = 0; n < portalopen.length; n++) + if (portalopen[n]) + os.writeInt(1); + else + os.writeInt(0); + } catch (Exception e) { + Com.Printf("ERROR:" + e); + e.printStackTrace(); + } + } + + /* + * =================== CM_ReadPortalState + * + * Reads the portal state from a savegame file and recalculates the area + * connections =================== + */ + public static void CM_ReadPortalState(RandomAccessFile f) { + + //was: FS_Read(portalopen, sizeof(portalopen), f); + int len = portalopen.length * 4; + + byte buf[] = new byte[len]; + + FS.Read(buf, len, f); + + ByteBuffer bb = ByteBuffer.wrap(buf); + IntBuffer ib = bb.asIntBuffer(); + + for (int n = 0; n < portalopen.length; n++) + portalopen[n] = ib.get() != 0; + + FloodAreaConnections(); + } + + /* + * ============= CM_HeadnodeVisible + * + * Returns true if any leaf under headnode has a cluster that is potentially + * visible ============= + */ + public static boolean CM_HeadnodeVisible(int nodenum, byte visbits[]) { + int leafnum; + int cluster; + cnode_t node; + + if (nodenum < 0) { + leafnum = -1 - nodenum; + cluster = map_leafs[leafnum].cluster; + if (cluster == -1) + return false; + if (0 != (visbits[cluster >>> 3] & (1 << (cluster & 7)))) + return true; + return false; + } + + node = map_nodes[nodenum]; + if (CM_HeadnodeVisible(node.children[0], visbits)) + return true; + return CM_HeadnodeVisible(node.children[1], visbits); + } +} \ No newline at end of file diff --git a/src/jake2/qcommon/Cbuf.java b/src/jake2/qcommon/Cbuf.java index f78577b..baa7090 100644 --- a/src/jake2/qcommon/Cbuf.java +++ b/src/jake2/qcommon/Cbuf.java @@ -2,245 +2,249 @@ * Cbuf.java * Copyright (C) 2003 * - * $Id: Cbuf.java,v 1.4 2004-09-18 13:07:46 hzi Exp $ + * $Id: Cbuf.java,v 1.5 2004-09-22 19:22:09 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.qcommon; import jake2.Defines; import jake2.Globals; import jake2.game.Cmd; +import jake2.util.Lib; /** * Cbuf */ public final class Cbuf { - /** - * - */ - public static void Init() { - SZ.Init(Globals.cmd_text, Globals.cmd_text_buf, Globals.cmd_text_buf.length); - } - - public static void InsertText(String text) { - - byte[] temp = null; - int templen = 0; - - // copy off any commands still remaining in the exec buffer - templen = Globals.cmd_text.cursize; - if (templen != 0) { - temp = new byte[templen]; - System.arraycopy(Globals.cmd_text.data, 0, temp, 0, templen); - SZ.Clear(Globals.cmd_text); - } - - // add the entire text of the file - Cbuf.AddText(text); - - // add the copied off data - if (templen != 0) { - SZ.Write(Globals.cmd_text, temp, templen); - temp = null; - } - } - - /** - * @param clear - */ - static void AddEarlyCommands(boolean clear) { - - for (int i = 0; i < Com.Argc(); i++) { - String s = Com.Argv(i); - if (!s.equals("+set")) - continue; - Cbuf.AddText("set " + Com.Argv(i + 1) + " " + Com.Argv(i + 2) + "\n"); - if (clear) { - Com.ClearArgv(i); - Com.ClearArgv(i + 1); - Com.ClearArgv(i + 2); - } - i += 2; - } - } - - /** - * @return - */ - static boolean AddLateCommands() { - int i; - int j; - boolean ret = false; - - // build the combined string to parse from - int s = 0; - int argc = Com.Argc(); - for (i = 1; i < argc; i++) { - s += Com.Argv(i).length(); - } - if (s == 0) - return false; - - String text = ""; - for (i = 1; i < argc; i++) { - text += Com.Argv(i); - if (i != argc - 1) - text += " "; - } - - // pull out the commands - String build = ""; - for (i = 0; i < text.length(); i++) { - if (text.charAt(i) == '+') { - i++; - - for (j = i;(text.charAt(j) != '+') && (text.charAt(j) != '-') && j < text.length(); j++); - - build += text.substring(i, j - 1); - build += "\n"; - - i = j - 1; - } - } - - ret = (build.length() != 0); - if (ret) - Cbuf.AddText(build); - - text = null; - build = null; - - return ret; - } - - /** - * @param text - */ - public static void AddText(String text) { - int l = text.length(); - - if (Globals.cmd_text.cursize + l >= Globals.cmd_text.maxsize) { - Com.Printf("Cbuf_AddText: overflow\n"); - return; - } - SZ.Write(Globals.cmd_text, text.getBytes(), l); - } - - /** - * - */ - public static void Execute() { - - byte[] text = null; - byte[] line = new byte[1024]; - - Globals.alias_count = 0; // don't allow infinite alias loops - - while (Globals.cmd_text.cursize != 0) { - // find a \n or ; line break - text = Globals.cmd_text.data; - - int quotes = 0; - int i; - - for (i = 0; i < Globals.cmd_text.cursize; i++) { - if (text[i] == '"') - quotes++; - if (!(quotes % 2 != 0) && text[i] == ';') - break; // don't break if inside a quoted string - if (text[i] == '\n') - break; - } - - System.arraycopy(text, 0, line, 0, i); - line[i] = 0; - - // delete the text from the command buffer and move remaining commands down - // this is necessary because commands (exec, alias) can insert data at the - // beginning of the text buffer - - if (i == Globals.cmd_text.cursize) - Globals.cmd_text.cursize = 0; - else { - i++; - Globals.cmd_text.cursize -= i; - byte[] tmp = new byte[Globals.cmd_text.cursize]; - - System.arraycopy(text, i, tmp, 0, Globals.cmd_text.cursize); - System.arraycopy(tmp, 0, text, 0, Globals.cmd_text.cursize); - text[Globals.cmd_text.cursize] = '\0'; - - } - - // execute the command line - int len = jake2.util.Lib.strlen(line); - - String cmd = new String(line, 0, len); - Cmd.ExecuteString(cmd); - - if (Globals.cmd_wait) { - // skip out while text still remains in buffer, leaving it - // for next frame - Globals.cmd_wait = false; - break; - } - } - } - - public static void ExecuteText(int exec_when, String text) { - switch(exec_when) { - case Defines.EXEC_NOW: - Cmd.ExecuteString(text); - break; - case Defines.EXEC_INSERT: - Cbuf.InsertText(text); - break; - case Defines.EXEC_APPEND: - Cbuf.AddText(text); - break; - default: - Com.Error(Defines.ERR_FATAL, "Cbuf_ExecuteText: bad exec_when"); - } - } - - /* - ============ - Cbuf_CopyToDefer - ============ - */ - public static void CopyToDefer() { - System.arraycopy(Globals.cmd_text_buf, 0, Globals.defer_text_buf, 0, Globals.cmd_text.cursize); - Globals.defer_text_buf[Globals.cmd_text.cursize] = 0; - Globals.cmd_text.cursize = 0; - } - - /* - ============ - Cbuf_InsertFromDefer - ============ - */ - public static void InsertFromDefer() { - InsertText(new String(Globals.defer_text_buf).trim()); - Globals.defer_text_buf[0] = 0; - } - -} + /** + * + */ + public static void Init() { + SZ.Init(Globals.cmd_text, Globals.cmd_text_buf, + Globals.cmd_text_buf.length); + } + + public static void InsertText(String text) { + + byte[] temp = null; + int templen = 0; + + // copy off any commands still remaining in the exec buffer + templen = Globals.cmd_text.cursize; + if (templen != 0) { + temp = new byte[templen]; + System.arraycopy(Globals.cmd_text.data, 0, temp, 0, templen); + SZ.Clear(Globals.cmd_text); + } + + // add the entire text of the file + Cbuf.AddText(text); + + // add the copied off data + if (templen != 0) { + SZ.Write(Globals.cmd_text, temp, templen); + temp = null; + } + } + + /** + * @param clear + */ + static void AddEarlyCommands(boolean clear) { + + for (int i = 0; i < Com.Argc(); i++) { + String s = Com.Argv(i); + if (!s.equals("+set")) + continue; + Cbuf.AddText("set " + Com.Argv(i + 1) + " " + Com.Argv(i + 2) + + "\n"); + if (clear) { + Com.ClearArgv(i); + Com.ClearArgv(i + 1); + Com.ClearArgv(i + 2); + } + i += 2; + } + } + + /** + * @return + */ + static boolean AddLateCommands() { + int i; + int j; + boolean ret = false; + + // build the combined string to parse from + int s = 0; + int argc = Com.Argc(); + for (i = 1; i < argc; i++) { + s += Com.Argv(i).length(); + } + if (s == 0) + return false; + + String text = ""; + for (i = 1; i < argc; i++) { + text += Com.Argv(i); + if (i != argc - 1) + text += " "; + } + + // pull out the commands + String build = ""; + for (i = 0; i < text.length(); i++) { + if (text.charAt(i) == '+') { + i++; + + for (j = i; (text.charAt(j) != '+') && (text.charAt(j) != '-') + && j < text.length(); j++) + ; + + build += text.substring(i, j - 1); + build += "\n"; + + i = j - 1; + } + } + + ret = (build.length() != 0); + if (ret) + Cbuf.AddText(build); + + text = null; + build = null; + + return ret; + } + + /** + * @param text + */ + public static void AddText(String text) { + int l = text.length(); + + if (Globals.cmd_text.cursize + l >= Globals.cmd_text.maxsize) { + Com.Printf("Cbuf_AddText: overflow\n"); + return; + } + SZ.Write(Globals.cmd_text, text.getBytes(), l); + } + + /** + * + */ + public static void Execute() { + + byte[] text = null; + byte[] line = new byte[1024]; + + Globals.alias_count = 0; // don't allow infinite alias loops + + while (Globals.cmd_text.cursize != 0) { + // find a \n or ; line break + text = Globals.cmd_text.data; + + int quotes = 0; + int i; + + for (i = 0; i < Globals.cmd_text.cursize; i++) { + if (text[i] == '"') + quotes++; + if (!(quotes % 2 != 0) && text[i] == ';') + break; // don't break if inside a quoted string + if (text[i] == '\n') + break; + } + + System.arraycopy(text, 0, line, 0, i); + line[i] = 0; + + // delete the text from the command buffer and move remaining + // commands down + // this is necessary because commands (exec, alias) can insert data + // at the + // beginning of the text buffer + + if (i == Globals.cmd_text.cursize) + Globals.cmd_text.cursize = 0; + else { + i++; + Globals.cmd_text.cursize -= i; + byte[] tmp = new byte[Globals.cmd_text.cursize]; + + System.arraycopy(text, i, tmp, 0, Globals.cmd_text.cursize); + System.arraycopy(tmp, 0, text, 0, Globals.cmd_text.cursize); + text[Globals.cmd_text.cursize] = '\0'; + + } + + // execute the command line + int len = Lib.strlen(line); + + String cmd = new String(line, 0, len); + Cmd.ExecuteString(cmd); + + if (Globals.cmd_wait) { + // skip out while text still remains in buffer, leaving it + // for next frame + Globals.cmd_wait = false; + break; + } + } + } + + public static void ExecuteText(int exec_when, String text) { + switch (exec_when) { + case Defines.EXEC_NOW: + Cmd.ExecuteString(text); + break; + case Defines.EXEC_INSERT: + Cbuf.InsertText(text); + break; + case Defines.EXEC_APPEND: + Cbuf.AddText(text); + break; + default: + Com.Error(Defines.ERR_FATAL, "Cbuf_ExecuteText: bad exec_when"); + } + } + + /* + * ============ Cbuf_CopyToDefer ============ + */ + public static void CopyToDefer() { + System.arraycopy(Globals.cmd_text_buf, 0, Globals.defer_text_buf, 0, + Globals.cmd_text.cursize); + Globals.defer_text_buf[Globals.cmd_text.cursize] = 0; + Globals.cmd_text.cursize = 0; + } + + /* + * ============ Cbuf_InsertFromDefer ============ + */ + public static void InsertFromDefer() { + InsertText(new String(Globals.defer_text_buf).trim()); + Globals.defer_text_buf[0] = 0; + } + +} \ No newline at end of file diff --git a/src/jake2/qcommon/Cvar.java b/src/jake2/qcommon/Cvar.java index a43464b..7255afd 100644 --- a/src/jake2/qcommon/Cvar.java +++ b/src/jake2/qcommon/Cvar.java @@ -2,459 +2,437 @@ * Cvar.java * Copyright (C) 2003 * - * $Id: Cvar.java,v 1.4 2004-08-19 20:56:41 hzi Exp $ + * $Id: Cvar.java,v 1.5 2004-09-22 19:22:09 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.qcommon; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.Vector; - import jake2.Defines; import jake2.Globals; -import jake2.game.*; +import jake2.game.Cmd; +import jake2.game.Info; +import jake2.game.cvar_t; import jake2.util.Lib; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Vector; + /** - * Cvar implements console variables. The original code is - * located in cvar.c + * Cvar implements console variables. The original code is located in cvar.c */ public class Cvar extends Globals { - /** - * @param var_name - * @param var_value - * @param flags - * @return - */ - public static cvar_t Get(String var_name, String var_value, int flags) { - cvar_t var; - - if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { - if (!Info.Info_Validate(var_name)) { - Com.Printf("invalid info cvar name\n"); - return null; - } - } - - var = Cvar.FindVar(var_name); - if (var != null) { - var.flags |= flags; - return var; - } - - if (var_value == null) - return null; - - if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { - if (!InfoValidate(var_value)) { - Com.Printf("invalid info cvar value\n"); - return null; - } - } - var = new cvar_t(); - var.name = new String(var_name); - var.string = new String(var_value); - var.modified = true; - // handles atof(var.string) - try { - var.value = Float.parseFloat(var.string); - } - catch (NumberFormatException e) { - var.value = 0.0f; - } - // link the variable in - var.next = Globals.cvar_vars; - Globals.cvar_vars = var; - - var.flags = flags; - - return var; - } - - static void Init() { - Cmd.AddCommand("set", Set_f); - Cmd.AddCommand("cvarlist", List_f); - } - - public static String VariableString(String var_name) { - cvar_t var; - var = FindVar(var_name); - return (var == null) ? "" : var.string; - } - - static cvar_t FindVar(String var_name) { - cvar_t var; - - for (var = Globals.cvar_vars; var != null; var = var.next) { - if (var_name.equals(var.name)) - return var; - } - - return null; - } - - /* - ============ - Cvar_FullSet - ============ - */ - public static cvar_t FullSet(String var_name, String value, int flags) { - cvar_t var; - - var = Cvar.FindVar(var_name); - if (null == var) { // create it - return Cvar.Get(var_name, value, flags); - } - - var.modified = true; - - if ((var.flags & CVAR_USERINFO) != 0) - Globals.userinfo_modified = true; // transmit at next oportunity - - var.string = value; - try { - var.value = Float.parseFloat(var.string); - } catch (Exception e) { - var.value = 0.0f; - } - - var.flags = flags; - - return var; - } - - /* - ============ - Cvar_Set - ============ - */ - public static cvar_t Set(String var_name, String value) { - return Set2(var_name, value, false); - } - - /* - ============ - Cvar_Set2 - ============ - */ - static cvar_t Set2(String var_name, String value, boolean force) { - - cvar_t var = Cvar.FindVar(var_name); - if (var == null) { // create it - return Cvar.Get(var_name, value, 0); - } - - if ((var.flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { - if (!InfoValidate(value)) { - Com.Printf("invalid info cvar value\n"); - return var; - } - } - - if (!force) { - if ((var.flags & CVAR_NOSET) != 0) { - Com.Printf(var_name + " is write protected.\n"); - return var; - } - - if ((var.flags & CVAR_LATCH) != 0) { - if (var.latched_string != null) { - if (value.equals(var.latched_string)) - return var; - //Z_Free (var.latched_string); - var.latched_string = null; - } - else { - if (value.equals(var.string)) - return var; - } - - if (Globals.server_state != 0) { - Com.Printf(var_name + " will be changed for next game.\n"); - var.latched_string = value; - } - else { - var.string = value; - try { - var.value = Float.parseFloat(var.string); - } catch (Exception e) { - var.value = 0.0f; - } - if (var.name.equals("game")) { - FS.SetGamedir(var.string); - FS.ExecAutoexec(); - } - } - return var; - } - } - else { - if (var.latched_string != null) { - //Z_Free(var.latched_string); - var.latched_string = null; - } - } - - if (value.equals(var.string)) - return var; // not changed - - var.modified = true; - - if ((var.flags & CVAR_USERINFO) != 0) - Globals.userinfo_modified = true; // transmit at next oportunity - - var.string = value; - try { - var.value = Float.parseFloat(var.string); - } catch (Exception e) { - var.value = 0.0f; - } - - return var; - } - - static xcommand_t Set_f = new xcommand_t() { - public void execute() { - int c; - int flags; - - c = Cmd.Argc(); - if (c != 3 && c != 4) { - Com.Printf("usage: set [u / s]\n"); - return; - } - - if (c == 4) { - if (Cmd.Argv(3).equals("u")) - flags = CVAR_USERINFO; - else if (Cmd.Argv(3).equals("s")) - flags = CVAR_SERVERINFO; - else { - Com.Printf("flags can only be 'u' or 's'\n"); - return; - } - Cvar.FullSet(Cmd.Argv(1), Cmd.Argv(2), flags); - } - else - Cvar.Set(Cmd.Argv(1), Cmd.Argv(2)); - - } - - }; - - static xcommand_t List_f = new xcommand_t() { - public void execute() { - cvar_t var; - int i; - - i = 0; - for (var = Globals.cvar_vars; var != null; var = var.next, i++) { - if ((var.flags & CVAR_ARCHIVE) != 0) - Com.Printf("*"); - else - Com.Printf(" "); - if ((var.flags & CVAR_USERINFO) != 0) - Com.Printf("U"); - else - Com.Printf(" "); - if ((var.flags & CVAR_SERVERINFO) != 0) - Com.Printf("S"); - else - Com.Printf(" "); - if ((var.flags & CVAR_NOSET) != 0) - Com.Printf("-"); - else if ((var.flags & CVAR_LATCH) != 0) - Com.Printf("L"); - else - Com.Printf(" "); - Com.Printf(" " + var.name + " \"" + var.string + "\"\n"); - } - Com.Printf(i + " cvars\n"); - } - }; - - /* - ============ - Cvar_ForceSet - ============ - */ - public static cvar_t ForceSet(String var_name, String value) { - return Cvar.Set2(var_name, value, true); - } - /* - ============ - Cvar_SetValue - ============ - */ - public static void SetValue(String var_name, float value) { - Cvar.Set(var_name, "" + value); - } - - /* - ============ - Cvar_VariableValue - ============ - */ - public static float VariableValue(String var_name) { - cvar_t var = Cvar.FindVar(var_name); - if (var == null) - return 0; - float val = 0.0f; - try { - val = Float.parseFloat(var.string); - } catch (Exception e) {} - return val; - } - - /* - ============ - Cvar_Command - - Handles variable inspection and changing from the console - ============ - */ - public static boolean Command() { - cvar_t v; - - // check variables - v = Cvar.FindVar(Cmd.Argv(0)); - if (v == null) - return false; - - // perform a variable print or set - if (Cmd.Argc() == 1) { - Com.Printf("\"" + v.name + "\" is \"" + v.string + "\"\n"); - return true; - } - - Cvar.Set(v.name, Cmd.Argv(1)); - return true; - } - - public static String BitInfo(int bit) { - String info; - cvar_t var; - - info = ""; - - for (var = Globals.cvar_vars; var != null; var = var.next) { - if ((var.flags & bit) != 0) - info = Info.Info_SetValueForKey1(info, var.name, var.string); - } - return info; - } - - // returns an info string containing all the CVAR_SERVERINFO cvars - public static String Serverinfo() { - return BitInfo(Defines.CVAR_SERVERINFO); - } - - public static void GetLatchedVars() { - cvar_t var; - - for (var = Globals.cvar_vars; var != null; var = var.next) { - if (var.latched_string == null || var.latched_string == "") - continue; - var.string = var.latched_string; - var.latched_string = null; - try { - var.value = Float.parseFloat(var.string); - } - catch (NumberFormatException e) { - var.value = 0.0f; - } - if (var.name.equals("game")) { - FS.SetGamedir(var.string); - FS.ExecAutoexec(); - } - } - } - - /** - * returns an info string containing all the CVAR_USERINFO cvars. - */ - public static String Userinfo() { - return BitInfo(CVAR_USERINFO); - } - - public static void WriteVariables(String path) { - cvar_t var; - RandomAccessFile f; - String buffer; - - f = Lib.fopen(path, "rw"); - if (f == null) - return; - - try { - f.seek(f.length()); - } catch (IOException e1) { - fclose(f); - return; - } - for (var = cvar_vars; var != null; var = var.next) { - if ((var.flags & CVAR_ARCHIVE) != 0) { - buffer = "set " + var.name + " \"" + var.string + "\"\n"; - try { - f.writeBytes(buffer); - } - catch (IOException e) { - } - } - } - fclose(f); - } - - /* - ============ - Cvar_CompleteVariable - ============ - */ - public static Vector CompleteVariable(String partial) { - - Vector vars = new Vector(); - - // check match - for (cvar_t cvar = Globals.cvar_vars; cvar != null; cvar = cvar.next) - if (cvar.name.startsWith(partial)) - vars.add(cvar.name); - - return vars; - } - - /* - ============ - Cvar_InfoValidate - ============ - */ - static boolean InfoValidate(String s) { - if (s.indexOf("\\") != -1) - return false; - if (s.indexOf("\"") != -1) - return false; - if (s.indexOf(";") != -1) - return false; - return true; - } -} + /** + * @param var_name + * @param var_value + * @param flags + * @return + */ + public static cvar_t Get(String var_name, String var_value, int flags) { + cvar_t var; + + if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { + if (!Info.Info_Validate(var_name)) { + Com.Printf("invalid info cvar name\n"); + return null; + } + } + + var = Cvar.FindVar(var_name); + if (var != null) { + var.flags |= flags; + return var; + } + + if (var_value == null) + return null; + + if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { + if (!InfoValidate(var_value)) { + Com.Printf("invalid info cvar value\n"); + return null; + } + } + var = new cvar_t(); + var.name = new String(var_name); + var.string = new String(var_value); + var.modified = true; + // handles atof(var.string) + try { + var.value = Float.parseFloat(var.string); + } catch (NumberFormatException e) { + var.value = 0.0f; + } + // link the variable in + var.next = Globals.cvar_vars; + Globals.cvar_vars = var; + + var.flags = flags; + + return var; + } + + static void Init() { + Cmd.AddCommand("set", Set_f); + Cmd.AddCommand("cvarlist", List_f); + } + + public static String VariableString(String var_name) { + cvar_t var; + var = FindVar(var_name); + return (var == null) ? "" : var.string; + } + + static cvar_t FindVar(String var_name) { + cvar_t var; + + for (var = Globals.cvar_vars; var != null; var = var.next) { + if (var_name.equals(var.name)) + return var; + } + + return null; + } + + /* + * ============ Cvar_FullSet ============ + */ + public static cvar_t FullSet(String var_name, String value, int flags) { + cvar_t var; + + var = Cvar.FindVar(var_name); + if (null == var) { // create it + return Cvar.Get(var_name, value, flags); + } + + var.modified = true; + + if ((var.flags & CVAR_USERINFO) != 0) + Globals.userinfo_modified = true; // transmit at next oportunity + + var.string = value; + try { + var.value = Float.parseFloat(var.string); + } catch (Exception e) { + var.value = 0.0f; + } + + var.flags = flags; + + return var; + } + + /* + * ============ Cvar_Set ============ + */ + public static cvar_t Set(String var_name, String value) { + return Set2(var_name, value, false); + } + + /* + * ============ Cvar_Set2 ============ + */ + static cvar_t Set2(String var_name, String value, boolean force) { + + cvar_t var = Cvar.FindVar(var_name); + if (var == null) { // create it + return Cvar.Get(var_name, value, 0); + } + + if ((var.flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) { + if (!InfoValidate(value)) { + Com.Printf("invalid info cvar value\n"); + return var; + } + } + + if (!force) { + if ((var.flags & CVAR_NOSET) != 0) { + Com.Printf(var_name + " is write protected.\n"); + return var; + } + + if ((var.flags & CVAR_LATCH) != 0) { + if (var.latched_string != null) { + if (value.equals(var.latched_string)) + return var; + //Z_Free (var.latched_string); + var.latched_string = null; + } else { + if (value.equals(var.string)) + return var; + } + + if (Globals.server_state != 0) { + Com.Printf(var_name + " will be changed for next game.\n"); + var.latched_string = value; + } else { + var.string = value; + try { + var.value = Float.parseFloat(var.string); + } catch (Exception e) { + var.value = 0.0f; + } + if (var.name.equals("game")) { + FS.SetGamedir(var.string); + FS.ExecAutoexec(); + } + } + return var; + } + } else { + if (var.latched_string != null) { + //Z_Free(var.latched_string); + var.latched_string = null; + } + } + + if (value.equals(var.string)) + return var; // not changed + + var.modified = true; + + if ((var.flags & CVAR_USERINFO) != 0) + Globals.userinfo_modified = true; // transmit at next oportunity + + var.string = value; + try { + var.value = Float.parseFloat(var.string); + } catch (Exception e) { + var.value = 0.0f; + } + + return var; + } + + static xcommand_t Set_f = new xcommand_t() { + public void execute() { + int c; + int flags; + + c = Cmd.Argc(); + if (c != 3 && c != 4) { + Com.Printf("usage: set [u / s]\n"); + return; + } + + if (c == 4) { + if (Cmd.Argv(3).equals("u")) + flags = CVAR_USERINFO; + else if (Cmd.Argv(3).equals("s")) + flags = CVAR_SERVERINFO; + else { + Com.Printf("flags can only be 'u' or 's'\n"); + return; + } + Cvar.FullSet(Cmd.Argv(1), Cmd.Argv(2), flags); + } else + Cvar.Set(Cmd.Argv(1), Cmd.Argv(2)); + + } + + }; + + static xcommand_t List_f = new xcommand_t() { + public void execute() { + cvar_t var; + int i; + + i = 0; + for (var = Globals.cvar_vars; var != null; var = var.next, i++) { + if ((var.flags & CVAR_ARCHIVE) != 0) + Com.Printf("*"); + else + Com.Printf(" "); + if ((var.flags & CVAR_USERINFO) != 0) + Com.Printf("U"); + else + Com.Printf(" "); + if ((var.flags & CVAR_SERVERINFO) != 0) + Com.Printf("S"); + else + Com.Printf(" "); + if ((var.flags & CVAR_NOSET) != 0) + Com.Printf("-"); + else if ((var.flags & CVAR_LATCH) != 0) + Com.Printf("L"); + else + Com.Printf(" "); + Com.Printf(" " + var.name + " \"" + var.string + "\"\n"); + } + Com.Printf(i + " cvars\n"); + } + }; + + /* + * ============ Cvar_ForceSet ============ + */ + public static cvar_t ForceSet(String var_name, String value) { + return Cvar.Set2(var_name, value, true); + } + + /* + * ============ Cvar_SetValue ============ + */ + public static void SetValue(String var_name, float value) { + Cvar.Set(var_name, "" + value); + } + + /* + * ============ Cvar_VariableValue ============ + */ + public static float VariableValue(String var_name) { + cvar_t var = Cvar.FindVar(var_name); + if (var == null) + return 0; + float val = 0.0f; + try { + val = Float.parseFloat(var.string); + } catch (Exception e) { + } + return val; + } + + /* + * ============ Cvar_Command + * + * Handles variable inspection and changing from the console ============ + */ + public static boolean Command() { + cvar_t v; + + // check variables + v = Cvar.FindVar(Cmd.Argv(0)); + if (v == null) + return false; + + // perform a variable print or set + if (Cmd.Argc() == 1) { + Com.Printf("\"" + v.name + "\" is \"" + v.string + "\"\n"); + return true; + } + + Cvar.Set(v.name, Cmd.Argv(1)); + return true; + } + + public static String BitInfo(int bit) { + String info; + cvar_t var; + + info = ""; + + for (var = Globals.cvar_vars; var != null; var = var.next) { + if ((var.flags & bit) != 0) + info = Info.Info_SetValueForKey1(info, var.name, var.string); + } + return info; + } + + // returns an info string containing all the CVAR_SERVERINFO cvars + public static String Serverinfo() { + return BitInfo(Defines.CVAR_SERVERINFO); + } + + public static void GetLatchedVars() { + cvar_t var; + + for (var = Globals.cvar_vars; var != null; var = var.next) { + if (var.latched_string == null || var.latched_string == "") + continue; + var.string = var.latched_string; + var.latched_string = null; + try { + var.value = Float.parseFloat(var.string); + } catch (NumberFormatException e) { + var.value = 0.0f; + } + if (var.name.equals("game")) { + FS.SetGamedir(var.string); + FS.ExecAutoexec(); + } + } + } + + /** + * returns an info string containing all the CVAR_USERINFO cvars. + */ + public static String Userinfo() { + return BitInfo(CVAR_USERINFO); + } + + public static void WriteVariables(String path) { + cvar_t var; + RandomAccessFile f; + String buffer; + + f = Lib.fopen(path, "rw"); + if (f == null) + return; + + try { + f.seek(f.length()); + } catch (IOException e1) { + Lib.fclose(f); + return; + } + for (var = cvar_vars; var != null; var = var.next) { + if ((var.flags & CVAR_ARCHIVE) != 0) { + buffer = "set " + var.name + " \"" + var.string + "\"\n"; + try { + f.writeBytes(buffer); + } catch (IOException e) { + } + } + } + Lib.fclose(f); + } + + /* + * ============ Cvar_CompleteVariable ============ + */ + public static Vector CompleteVariable(String partial) { + + Vector vars = new Vector(); + + // check match + for (cvar_t cvar = Globals.cvar_vars; cvar != null; cvar = cvar.next) + if (cvar.name.startsWith(partial)) + vars.add(cvar.name); + + return vars; + } + + /* + * ============ Cvar_InfoValidate ============ + */ + static boolean InfoValidate(String s) { + if (s.indexOf("\\") != -1) + return false; + if (s.indexOf("\"") != -1) + return false; + if (s.indexOf(";") != -1) + return false; + return true; + } +} \ No newline at end of file diff --git a/src/jake2/qcommon/MSG.java b/src/jake2/qcommon/MSG.java index 4396ac3..ee2a089 100644 --- a/src/jake2/qcommon/MSG.java +++ b/src/jake2/qcommon/MSG.java @@ -1,562 +1,559 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 29.11.2003 by RST. -// $Id: MSG.java,v 1.4 2004-07-28 11:58:10 hzi Exp $ - +// $Id: MSG.java,v 1.5 2004-09-22 19:22:09 salomo Exp $ package jake2.qcommon; +import jake2.Globals; import jake2.game.*; import jake2.util.*; -public class MSG extends GameBase { - - // - // writing functions - // - - //ok. - public static void WriteChar(sizebuf_t sb, int c) { - sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF); - } - - //ok. - public static void WriteChar(sizebuf_t sb, float c) { - - WriteChar(sb, (int) c); - } - - //ok. - public static void WriteByte(sizebuf_t sb, int c) { - sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF); - } - - //ok. - public static void WriteByte(sizebuf_t sb, float c) { - WriteByte(sb, (int) c); - } - - - public static void WriteShort(sizebuf_t sb, int c) { - int i = SZ.GetSpace(sb, 2); - sb.data[i++] = (byte) (c & 0xff); - sb.data[i] = (byte) ((c >>> 8) & 0xFF); - } - - //ok. - public static void WriteInt(sizebuf_t sb, int c) { - int i = SZ.GetSpace(sb, 4); - sb.data[i++] = (byte) ((c & 0xff)); - sb.data[i++] = (byte) ((c >>> 8) & 0xff); - sb.data[i++] = (byte) ((c >>> 16) & 0xff); - sb.data[i++] = (byte) ((c >>> 24) & 0xff); - } - - //ok. - public static void WriteLong(sizebuf_t sb, int c) { - WriteInt(sb, c); - } - - //ok. - public static void WriteFloat(sizebuf_t sb, float f) { - WriteInt(sb, Float.floatToIntBits(f)); - } - - // had a bug, now its ok. - public static void WriteString(sizebuf_t sb, String s) { - String x = s; - - if (s == null) - x = ""; - - SZ.Write(sb, x.getBytes()); - WriteByte(sb, 0); - } - - //ok. - public static void WriteString(sizebuf_t sb, byte s[]) { - WriteString(sb, new String(s).trim()); - } - - public static void WriteCoord(sizebuf_t sb, float f) { - WriteShort(sb, (int) (f * 8)); - } - - public static void WritePos(sizebuf_t sb, float[] pos) { - assert(pos.length == 3) : "vec3_t bug"; - WriteShort(sb, (int) (pos[0] * 8)); - WriteShort(sb, (int) (pos[1] * 8)); - WriteShort(sb, (int) (pos[2] * 8)); - } - - public static void WriteAngle(sizebuf_t sb, float f) { - WriteByte(sb, (int) (f * 256 / 360) & 255); - } - - public static void WriteAngle16(sizebuf_t sb, float f) { - WriteShort(sb, Math3D.ANGLE2SHORT(f)); - } - - public static void WriteDeltaUsercmd(sizebuf_t buf, usercmd_t from, usercmd_t cmd) { - int bits; - - // - // send the movement message - // - bits = 0; - if (cmd.angles[0] != from.angles[0]) - bits |= CM_ANGLE1; - if (cmd.angles[1] != from.angles[1]) - bits |= CM_ANGLE2; - if (cmd.angles[2] != from.angles[2]) - bits |= CM_ANGLE3; - if (cmd.forwardmove != from.forwardmove) - bits |= CM_FORWARD; - if (cmd.sidemove != from.sidemove) - bits |= CM_SIDE; - if (cmd.upmove != from.upmove) - bits |= CM_UP; - if (cmd.buttons != from.buttons) - bits |= CM_BUTTONS; - if (cmd.impulse != from.impulse) - bits |= CM_IMPULSE; - - WriteByte(buf, bits); - - if ((bits & CM_ANGLE1) != 0) - WriteShort(buf, cmd.angles[0]); - if ((bits & CM_ANGLE2) != 0) - WriteShort(buf, cmd.angles[1]); - if ((bits & CM_ANGLE3) != 0) - WriteShort(buf, cmd.angles[2]); - - if ((bits & CM_FORWARD) != 0) - WriteShort(buf, cmd.forwardmove); - if ((bits & CM_SIDE) != 0) - WriteShort(buf, cmd.sidemove); - if ((bits & CM_UP) != 0) - WriteShort(buf, cmd.upmove); - - if ((bits & CM_BUTTONS) != 0) - WriteByte(buf, cmd.buttons); - if ((bits & CM_IMPULSE) != 0) - WriteByte(buf, cmd.impulse); - - WriteByte(buf, cmd.msec); - WriteByte(buf, cmd.lightlevel); - } - - //should be ok. - public static void WriteDir(sizebuf_t sb, float[] dir) { - int i, best; - float d, bestd; - - if (dir == null) { - WriteByte(sb, 0); - return; - } - - bestd = 0; - best = 0; - for (i = 0; i < NUMVERTEXNORMALS; i++) { - d = Math3D.DotProduct(dir, bytedirs[i]); - if (d > bestd) { - bestd = d; - best = i; - } - } - WriteByte(sb, best); - } - - //should be ok. - public static void ReadDir(sizebuf_t sb, float[] dir) { - int b; - - b = ReadByte(sb); - if (b >= NUMVERTEXNORMALS) - Com.Error(ERR_DROP, "MSF_ReadDir: out of range"); - Math3D.VectorCopy(bytedirs[b], dir); - } - - /* - ================== - WriteDeltaEntity - - Writes part of a packetentities message. - Can delta from either a baseline or a previous packet_entity - ================== - */ - public static void WriteDeltaEntity(entity_state_t from, entity_state_t to, sizebuf_t msg, boolean force, boolean newentity) { - int bits; - - if (0 == to.number) - Com.Error(ERR_FATAL, "Unset entity number"); - if (to.number >= MAX_EDICTS) - Com.Error(ERR_FATAL, "Entity number >= MAX_EDICTS"); - - // send an update - bits = 0; - - if (to.number >= 256) - bits |= U_NUMBER16; // number8 is implicit otherwise - - if (to.origin[0] != from.origin[0]) - bits |= U_ORIGIN1; - if (to.origin[1] != from.origin[1]) - bits |= U_ORIGIN2; - if (to.origin[2] != from.origin[2]) - bits |= U_ORIGIN3; - - if (to.angles[0] != from.angles[0]) - bits |= U_ANGLE1; - if (to.angles[1] != from.angles[1]) - bits |= U_ANGLE2; - if (to.angles[2] != from.angles[2]) - bits |= U_ANGLE3; - - if (to.skinnum != from.skinnum) { - if (to.skinnum < 256) - bits |= U_SKIN8; - else if (to.skinnum < 0x10000) - bits |= U_SKIN16; - else - bits |= (U_SKIN8 | U_SKIN16); - } - - if (to.frame != from.frame) { - if (to.frame < 256) - bits |= U_FRAME8; - else - bits |= U_FRAME16; - } - - if (to.effects != from.effects) { - if (to.effects < 256) - bits |= U_EFFECTS8; - else if (to.effects < 0x8000) - bits |= U_EFFECTS16; - else - bits |= U_EFFECTS8 | U_EFFECTS16; - } - - if (to.renderfx != from.renderfx) { - if (to.renderfx < 256) - bits |= U_RENDERFX8; - else if (to.renderfx < 0x8000) - bits |= U_RENDERFX16; - else - bits |= U_RENDERFX8 | U_RENDERFX16; - } - - if (to.solid != from.solid) - bits |= U_SOLID; - - // event is not delta compressed, just 0 compressed - if (to.event != 0) - bits |= U_EVENT; - - if (to.modelindex != from.modelindex) - bits |= U_MODEL; - if (to.modelindex2 != from.modelindex2) - bits |= U_MODEL2; - if (to.modelindex3 != from.modelindex3) - bits |= U_MODEL3; - if (to.modelindex4 != from.modelindex4) - bits |= U_MODEL4; - - if (to.sound != from.sound) - bits |= U_SOUND; - - if (newentity || (to.renderfx & RF_BEAM) != 0) - bits |= U_OLDORIGIN; - - // - // write the message - // - if (bits == 0 && !force) - return; // nothing to send! - - //---------- - - if ((bits & 0xff000000) != 0) - bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1; - else if ((bits & 0x00ff0000) != 0) - bits |= U_MOREBITS2 | U_MOREBITS1; - else if ((bits & 0x0000ff00) != 0) - bits |= U_MOREBITS1; - - WriteByte(msg, bits & 255); - - if ((bits & 0xff000000) != 0) { - WriteByte(msg, (bits >>> 8) & 255); - WriteByte(msg, (bits >>> 16) & 255); - WriteByte(msg, (bits >>> 24) & 255); - } - else if ((bits & 0x00ff0000) != 0) { - WriteByte(msg, (bits >>> 8) & 255); - WriteByte(msg, (bits >>> 16) & 255); - } - else if ((bits & 0x0000ff00) != 0) { - WriteByte(msg, (bits >>> 8) & 255); - } - - //---------- - - if ((bits & U_NUMBER16) != 0) - WriteShort(msg, to.number); - else - WriteByte(msg, to.number); - - if ((bits & U_MODEL) != 0) - WriteByte(msg, to.modelindex); - if ((bits & U_MODEL2) != 0) - WriteByte(msg, to.modelindex2); - if ((bits & U_MODEL3) != 0) - WriteByte(msg, to.modelindex3); - if ((bits & U_MODEL4) != 0) - WriteByte(msg, to.modelindex4); - - if ((bits & U_FRAME8) != 0) - WriteByte(msg, to.frame); - if ((bits & U_FRAME16) != 0) - WriteShort(msg, to.frame); - - if ((bits & U_SKIN8) != 0 && (bits & U_SKIN16) != 0) //used for laser colors - WriteInt(msg, to.skinnum); - else if ((bits & U_SKIN8) != 0) - WriteByte(msg, to.skinnum); - else if ((bits & U_SKIN16) != 0) - WriteShort(msg, to.skinnum); - - if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16)) - WriteInt(msg, to.effects); - else if ((bits & U_EFFECTS8) != 0) - WriteByte(msg, to.effects); - else if ((bits & U_EFFECTS16) != 0) - WriteShort(msg, to.effects); - - if ((bits & (U_RENDERFX8 | U_RENDERFX16)) == (U_RENDERFX8 | U_RENDERFX16)) - WriteInt(msg, to.renderfx); - else if ((bits & U_RENDERFX8) != 0) - WriteByte(msg, to.renderfx); - else if ((bits & U_RENDERFX16) != 0) - WriteShort(msg, to.renderfx); - - if ((bits & U_ORIGIN1) != 0) - WriteCoord(msg, to.origin[0]); - if ((bits & U_ORIGIN2) != 0) - WriteCoord(msg, to.origin[1]); - if ((bits & U_ORIGIN3) != 0) - WriteCoord(msg, to.origin[2]); - - if ((bits & U_ANGLE1) != 0) - WriteAngle(msg, to.angles[0]); - if ((bits & U_ANGLE2) != 0) - WriteAngle(msg, to.angles[1]); - if ((bits & U_ANGLE3) != 0) - WriteAngle(msg, to.angles[2]); - - if ((bits & U_OLDORIGIN) != 0) { - WriteCoord(msg, to.old_origin[0]); - WriteCoord(msg, to.old_origin[1]); - WriteCoord(msg, to.old_origin[2]); - } - - if ((bits & U_SOUND) != 0) - WriteByte(msg, to.sound); - if ((bits & U_EVENT) != 0) - WriteByte(msg, to.event); - if ((bits & U_SOLID) != 0) - WriteShort(msg, to.solid); - } - - //============================================================ - - // - // reading functions - // - - public static void BeginReading(sizebuf_t msg) { - msg.readcount = 0; - } - - // returns -1 if no more characters are available, but also [-128 , 127] - public static int ReadChar(sizebuf_t msg_read) { - int c; - - if (msg_read.readcount + 1 > msg_read.cursize) - c = -1; - else - c = msg_read.data[msg_read.readcount]; - msg_read.readcount++; - // kickangles bugfix (rst) - return c; - } - - public static int ReadByte(sizebuf_t msg_read) { - int c; - - if (msg_read.readcount + 1 > msg_read.cursize) - c = -1; - else - c = msg_read.data[msg_read.readcount] & 0xff; - msg_read.readcount++; - - return c; - } - - public static short ReadShort(sizebuf_t msg_read) { - int c; - - if (msg_read.readcount + 2 > msg_read.cursize) - c = -1; - else - c = (short) ((msg_read.data[msg_read.readcount] & 0xff) + (msg_read.data[msg_read.readcount + 1] << 8)); - - msg_read.readcount += 2; - - return (short) c; - } - - public static int ReadLong(sizebuf_t msg_read) { - int c; - - if (msg_read.readcount + 4 > msg_read.cursize) - { - Com.Printf("buffer underrun in ReadLong!"); - c = -1; - } - - else - c = - (msg_read.data[msg_read.readcount] & 0xff) - | ((msg_read.data[msg_read.readcount + 1] & 0xff) << 8) - | ((msg_read.data[msg_read.readcount + 2] & 0xff) << 16) - | ((msg_read.data[msg_read.readcount + 3] & 0xff) << 24); - - msg_read.readcount += 4; - - return c; - } - - public static float ReadFloat(sizebuf_t msg_read) { - int n = ReadLong(msg_read); - return Float.intBitsToFloat(n); - } - - // 2k read buffer. - public static byte readbuf[] = new byte[2048]; - - public static String ReadString(sizebuf_t msg_read) { - - byte c; - int l = 0; - do { - c = (byte)ReadByte(msg_read); - if (c == -1 || c == 0) - break; - - readbuf[l] = c; - l++; - } while (l < 2047); - - return new String(readbuf, 0, l); - } - - public static String ReadStringLine(sizebuf_t msg_read) { - - int l; - byte c; - - l = 0; - do { - c = (byte) ReadChar(msg_read); - if (c == -1 || c == 0 || c == 0x0a) - break; - readbuf[l] = c; - l++; - } while (l < 2047); - - return new String(readbuf, 0, l).trim(); - } - - public static float ReadCoord(sizebuf_t msg_read) { - return ReadShort(msg_read) * (1.0f / 8); - } - - public static void ReadPos(sizebuf_t msg_read, float pos[]) { - assert(pos.length == 3) : "vec3_t bug"; - pos[0] = ReadShort(msg_read) * (1.0f / 8); - pos[1] = ReadShort(msg_read) * (1.0f / 8); - pos[2] = ReadShort(msg_read) * (1.0f / 8); - } - - public static float ReadAngle(sizebuf_t msg_read) { - return ReadChar(msg_read) * (360.0f / 256); - } - - public static float ReadAngle16(sizebuf_t msg_read) { - return Math3D.SHORT2ANGLE(ReadShort(msg_read)); - } - - public static void ReadDeltaUsercmd(sizebuf_t msg_read, usercmd_t from, usercmd_t move) { - int bits; - - //memcpy(move, from, sizeof(* move)); - // IMPORTANT!! copy without new - move.set(from); - bits = ReadByte(msg_read); - - // read current angles - if ((bits & CM_ANGLE1) != 0) - move.angles[0] = ReadShort(msg_read); - if ((bits & CM_ANGLE2) != 0) - move.angles[1] = ReadShort(msg_read); - if ((bits & CM_ANGLE3) != 0) - move.angles[2] = ReadShort(msg_read); - - // read movement - if ((bits & CM_FORWARD) != 0) - move.forwardmove = ReadShort(msg_read); - if ((bits & CM_SIDE) != 0) - move.sidemove = ReadShort(msg_read); - if ((bits & CM_UP) != 0) - move.upmove = ReadShort(msg_read); - - // read buttons - if ((bits & CM_BUTTONS) != 0) - move.buttons = (byte) ReadByte(msg_read); - - if ((bits & CM_IMPULSE) != 0) - move.impulse = (byte) ReadByte(msg_read); - - // read time to run command - move.msec = (byte) ReadByte(msg_read); - - // read the light level - move.lightlevel = (byte) ReadByte(msg_read); - - } - - public static void ReadData(sizebuf_t msg_read, byte data[], int len) { - for (int i = 0; i < len; i++) - data[i] = (byte) ReadByte(msg_read); - } -} +public class MSG extends Globals { + + // + // writing functions + // + + //ok. + public static void WriteChar(sizebuf_t sb, int c) { + sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF); + } + + //ok. + public static void WriteChar(sizebuf_t sb, float c) { + + WriteChar(sb, (int) c); + } + + //ok. + public static void WriteByte(sizebuf_t sb, int c) { + sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF); + } + + //ok. + public static void WriteByte(sizebuf_t sb, float c) { + WriteByte(sb, (int) c); + } + + public static void WriteShort(sizebuf_t sb, int c) { + int i = SZ.GetSpace(sb, 2); + sb.data[i++] = (byte) (c & 0xff); + sb.data[i] = (byte) ((c >>> 8) & 0xFF); + } + + //ok. + public static void WriteInt(sizebuf_t sb, int c) { + int i = SZ.GetSpace(sb, 4); + sb.data[i++] = (byte) ((c & 0xff)); + sb.data[i++] = (byte) ((c >>> 8) & 0xff); + sb.data[i++] = (byte) ((c >>> 16) & 0xff); + sb.data[i++] = (byte) ((c >>> 24) & 0xff); + } + + //ok. + public static void WriteLong(sizebuf_t sb, int c) { + WriteInt(sb, c); + } + + //ok. + public static void WriteFloat(sizebuf_t sb, float f) { + WriteInt(sb, Float.floatToIntBits(f)); + } + + // had a bug, now its ok. + public static void WriteString(sizebuf_t sb, String s) { + String x = s; + + if (s == null) + x = ""; + + SZ.Write(sb, x.getBytes()); + WriteByte(sb, 0); + } + + //ok. + public static void WriteString(sizebuf_t sb, byte s[]) { + WriteString(sb, new String(s).trim()); + } + + public static void WriteCoord(sizebuf_t sb, float f) { + WriteShort(sb, (int) (f * 8)); + } + + public static void WritePos(sizebuf_t sb, float[] pos) { + assert (pos.length == 3) : "vec3_t bug"; + WriteShort(sb, (int) (pos[0] * 8)); + WriteShort(sb, (int) (pos[1] * 8)); + WriteShort(sb, (int) (pos[2] * 8)); + } + + public static void WriteAngle(sizebuf_t sb, float f) { + WriteByte(sb, (int) (f * 256 / 360) & 255); + } + + public static void WriteAngle16(sizebuf_t sb, float f) { + WriteShort(sb, Math3D.ANGLE2SHORT(f)); + } + + public static void WriteDeltaUsercmd(sizebuf_t buf, usercmd_t from, + usercmd_t cmd) { + int bits; + + // + // send the movement message + // + bits = 0; + if (cmd.angles[0] != from.angles[0]) + bits |= CM_ANGLE1; + if (cmd.angles[1] != from.angles[1]) + bits |= CM_ANGLE2; + if (cmd.angles[2] != from.angles[2]) + bits |= CM_ANGLE3; + if (cmd.forwardmove != from.forwardmove) + bits |= CM_FORWARD; + if (cmd.sidemove != from.sidemove) + bits |= CM_SIDE; + if (cmd.upmove != from.upmove) + bits |= CM_UP; + if (cmd.buttons != from.buttons) + bits |= CM_BUTTONS; + if (cmd.impulse != from.impulse) + bits |= CM_IMPULSE; + + WriteByte(buf, bits); + + if ((bits & CM_ANGLE1) != 0) + WriteShort(buf, cmd.angles[0]); + if ((bits & CM_ANGLE2) != 0) + WriteShort(buf, cmd.angles[1]); + if ((bits & CM_ANGLE3) != 0) + WriteShort(buf, cmd.angles[2]); + + if ((bits & CM_FORWARD) != 0) + WriteShort(buf, cmd.forwardmove); + if ((bits & CM_SIDE) != 0) + WriteShort(buf, cmd.sidemove); + if ((bits & CM_UP) != 0) + WriteShort(buf, cmd.upmove); + + if ((bits & CM_BUTTONS) != 0) + WriteByte(buf, cmd.buttons); + if ((bits & CM_IMPULSE) != 0) + WriteByte(buf, cmd.impulse); + + WriteByte(buf, cmd.msec); + WriteByte(buf, cmd.lightlevel); + } + + //should be ok. + public static void WriteDir(sizebuf_t sb, float[] dir) { + int i, best; + float d, bestd; + + if (dir == null) { + WriteByte(sb, 0); + return; + } + + bestd = 0; + best = 0; + for (i = 0; i < NUMVERTEXNORMALS; i++) { + d = Math3D.DotProduct(dir, bytedirs[i]); + if (d > bestd) { + bestd = d; + best = i; + } + } + WriteByte(sb, best); + } + + //should be ok. + public static void ReadDir(sizebuf_t sb, float[] dir) { + int b; + + b = ReadByte(sb); + if (b >= NUMVERTEXNORMALS) + Com.Error(ERR_DROP, "MSF_ReadDir: out of range"); + Math3D.VectorCopy(bytedirs[b], dir); + } + + /* + * ================== WriteDeltaEntity + * + * Writes part of a packetentities message. Can delta from either a baseline + * or a previous packet_entity ================== + */ + public static void WriteDeltaEntity(entity_state_t from, entity_state_t to, + sizebuf_t msg, boolean force, boolean newentity) { + int bits; + + if (0 == to.number) + Com.Error(ERR_FATAL, "Unset entity number"); + if (to.number >= MAX_EDICTS) + Com.Error(ERR_FATAL, "Entity number >= MAX_EDICTS"); + + // send an update + bits = 0; + + if (to.number >= 256) + bits |= U_NUMBER16; // number8 is implicit otherwise + + if (to.origin[0] != from.origin[0]) + bits |= U_ORIGIN1; + if (to.origin[1] != from.origin[1]) + bits |= U_ORIGIN2; + if (to.origin[2] != from.origin[2]) + bits |= U_ORIGIN3; + + if (to.angles[0] != from.angles[0]) + bits |= U_ANGLE1; + if (to.angles[1] != from.angles[1]) + bits |= U_ANGLE2; + if (to.angles[2] != from.angles[2]) + bits |= U_ANGLE3; + + if (to.skinnum != from.skinnum) { + if (to.skinnum < 256) + bits |= U_SKIN8; + else if (to.skinnum < 0x10000) + bits |= U_SKIN16; + else + bits |= (U_SKIN8 | U_SKIN16); + } + + if (to.frame != from.frame) { + if (to.frame < 256) + bits |= U_FRAME8; + else + bits |= U_FRAME16; + } + + if (to.effects != from.effects) { + if (to.effects < 256) + bits |= U_EFFECTS8; + else if (to.effects < 0x8000) + bits |= U_EFFECTS16; + else + bits |= U_EFFECTS8 | U_EFFECTS16; + } + + if (to.renderfx != from.renderfx) { + if (to.renderfx < 256) + bits |= U_RENDERFX8; + else if (to.renderfx < 0x8000) + bits |= U_RENDERFX16; + else + bits |= U_RENDERFX8 | U_RENDERFX16; + } + + if (to.solid != from.solid) + bits |= U_SOLID; + + // event is not delta compressed, just 0 compressed + if (to.event != 0) + bits |= U_EVENT; + + if (to.modelindex != from.modelindex) + bits |= U_MODEL; + if (to.modelindex2 != from.modelindex2) + bits |= U_MODEL2; + if (to.modelindex3 != from.modelindex3) + bits |= U_MODEL3; + if (to.modelindex4 != from.modelindex4) + bits |= U_MODEL4; + + if (to.sound != from.sound) + bits |= U_SOUND; + + if (newentity || (to.renderfx & RF_BEAM) != 0) + bits |= U_OLDORIGIN; + + // + // write the message + // + if (bits == 0 && !force) + return; // nothing to send! + + //---------- + + if ((bits & 0xff000000) != 0) + bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1; + else if ((bits & 0x00ff0000) != 0) + bits |= U_MOREBITS2 | U_MOREBITS1; + else if ((bits & 0x0000ff00) != 0) + bits |= U_MOREBITS1; + + WriteByte(msg, bits & 255); + + if ((bits & 0xff000000) != 0) { + WriteByte(msg, (bits >>> 8) & 255); + WriteByte(msg, (bits >>> 16) & 255); + WriteByte(msg, (bits >>> 24) & 255); + } else if ((bits & 0x00ff0000) != 0) { + WriteByte(msg, (bits >>> 8) & 255); + WriteByte(msg, (bits >>> 16) & 255); + } else if ((bits & 0x0000ff00) != 0) { + WriteByte(msg, (bits >>> 8) & 255); + } + + //---------- + + if ((bits & U_NUMBER16) != 0) + WriteShort(msg, to.number); + else + WriteByte(msg, to.number); + + if ((bits & U_MODEL) != 0) + WriteByte(msg, to.modelindex); + if ((bits & U_MODEL2) != 0) + WriteByte(msg, to.modelindex2); + if ((bits & U_MODEL3) != 0) + WriteByte(msg, to.modelindex3); + if ((bits & U_MODEL4) != 0) + WriteByte(msg, to.modelindex4); + + if ((bits & U_FRAME8) != 0) + WriteByte(msg, to.frame); + if ((bits & U_FRAME16) != 0) + WriteShort(msg, to.frame); + + if ((bits & U_SKIN8) != 0 && (bits & U_SKIN16) != 0) //used for laser + // colors + WriteInt(msg, to.skinnum); + else if ((bits & U_SKIN8) != 0) + WriteByte(msg, to.skinnum); + else if ((bits & U_SKIN16) != 0) + WriteShort(msg, to.skinnum); + + if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16)) + WriteInt(msg, to.effects); + else if ((bits & U_EFFECTS8) != 0) + WriteByte(msg, to.effects); + else if ((bits & U_EFFECTS16) != 0) + WriteShort(msg, to.effects); + + if ((bits & (U_RENDERFX8 | U_RENDERFX16)) == (U_RENDERFX8 | U_RENDERFX16)) + WriteInt(msg, to.renderfx); + else if ((bits & U_RENDERFX8) != 0) + WriteByte(msg, to.renderfx); + else if ((bits & U_RENDERFX16) != 0) + WriteShort(msg, to.renderfx); + + if ((bits & U_ORIGIN1) != 0) + WriteCoord(msg, to.origin[0]); + if ((bits & U_ORIGIN2) != 0) + WriteCoord(msg, to.origin[1]); + if ((bits & U_ORIGIN3) != 0) + WriteCoord(msg, to.origin[2]); + + if ((bits & U_ANGLE1) != 0) + WriteAngle(msg, to.angles[0]); + if ((bits & U_ANGLE2) != 0) + WriteAngle(msg, to.angles[1]); + if ((bits & U_ANGLE3) != 0) + WriteAngle(msg, to.angles[2]); + + if ((bits & U_OLDORIGIN) != 0) { + WriteCoord(msg, to.old_origin[0]); + WriteCoord(msg, to.old_origin[1]); + WriteCoord(msg, to.old_origin[2]); + } + + if ((bits & U_SOUND) != 0) + WriteByte(msg, to.sound); + if ((bits & U_EVENT) != 0) + WriteByte(msg, to.event); + if ((bits & U_SOLID) != 0) + WriteShort(msg, to.solid); + } + + //============================================================ + + // + // reading functions + // + + public static void BeginReading(sizebuf_t msg) { + msg.readcount = 0; + } + + // returns -1 if no more characters are available, but also [-128 , 127] + public static int ReadChar(sizebuf_t msg_read) { + int c; + + if (msg_read.readcount + 1 > msg_read.cursize) + c = -1; + else + c = msg_read.data[msg_read.readcount]; + msg_read.readcount++; + // kickangles bugfix (rst) + return c; + } + + public static int ReadByte(sizebuf_t msg_read) { + int c; + + if (msg_read.readcount + 1 > msg_read.cursize) + c = -1; + else + c = msg_read.data[msg_read.readcount] & 0xff; + msg_read.readcount++; + + return c; + } + + public static short ReadShort(sizebuf_t msg_read) { + int c; + + if (msg_read.readcount + 2 > msg_read.cursize) + c = -1; + else + c = (short) ((msg_read.data[msg_read.readcount] & 0xff) + (msg_read.data[msg_read.readcount + 1] << 8)); + + msg_read.readcount += 2; + + return (short) c; + } + + public static int ReadLong(sizebuf_t msg_read) { + int c; + + if (msg_read.readcount + 4 > msg_read.cursize) { + Com.Printf("buffer underrun in ReadLong!"); + c = -1; + } + + else + c = (msg_read.data[msg_read.readcount] & 0xff) + | ((msg_read.data[msg_read.readcount + 1] & 0xff) << 8) + | ((msg_read.data[msg_read.readcount + 2] & 0xff) << 16) + | ((msg_read.data[msg_read.readcount + 3] & 0xff) << 24); + + msg_read.readcount += 4; + + return c; + } + + public static float ReadFloat(sizebuf_t msg_read) { + int n = ReadLong(msg_read); + return Float.intBitsToFloat(n); + } + + // 2k read buffer. + public static byte readbuf[] = new byte[2048]; + + public static String ReadString(sizebuf_t msg_read) { + + byte c; + int l = 0; + do { + c = (byte) ReadByte(msg_read); + if (c == -1 || c == 0) + break; + + readbuf[l] = c; + l++; + } while (l < 2047); + + return new String(readbuf, 0, l); + } + + public static String ReadStringLine(sizebuf_t msg_read) { + + int l; + byte c; + + l = 0; + do { + c = (byte) ReadChar(msg_read); + if (c == -1 || c == 0 || c == 0x0a) + break; + readbuf[l] = c; + l++; + } while (l < 2047); + + return new String(readbuf, 0, l).trim(); + } + + public static float ReadCoord(sizebuf_t msg_read) { + return ReadShort(msg_read) * (1.0f / 8); + } + + public static void ReadPos(sizebuf_t msg_read, float pos[]) { + assert (pos.length == 3) : "vec3_t bug"; + pos[0] = ReadShort(msg_read) * (1.0f / 8); + pos[1] = ReadShort(msg_read) * (1.0f / 8); + pos[2] = ReadShort(msg_read) * (1.0f / 8); + } + + public static float ReadAngle(sizebuf_t msg_read) { + return ReadChar(msg_read) * (360.0f / 256); + } + + public static float ReadAngle16(sizebuf_t msg_read) { + return Math3D.SHORT2ANGLE(ReadShort(msg_read)); + } + + public static void ReadDeltaUsercmd(sizebuf_t msg_read, usercmd_t from, + usercmd_t move) { + int bits; + + //memcpy(move, from, sizeof(* move)); + // IMPORTANT!! copy without new + move.set(from); + bits = ReadByte(msg_read); + + // read current angles + if ((bits & CM_ANGLE1) != 0) + move.angles[0] = ReadShort(msg_read); + if ((bits & CM_ANGLE2) != 0) + move.angles[1] = ReadShort(msg_read); + if ((bits & CM_ANGLE3) != 0) + move.angles[2] = ReadShort(msg_read); + + // read movement + if ((bits & CM_FORWARD) != 0) + move.forwardmove = ReadShort(msg_read); + if ((bits & CM_SIDE) != 0) + move.sidemove = ReadShort(msg_read); + if ((bits & CM_UP) != 0) + move.upmove = ReadShort(msg_read); + + // read buttons + if ((bits & CM_BUTTONS) != 0) + move.buttons = (byte) ReadByte(msg_read); + + if ((bits & CM_IMPULSE) != 0) + move.impulse = (byte) ReadByte(msg_read); + + // read time to run command + move.msec = (byte) ReadByte(msg_read); + + // read the light level + move.lightlevel = (byte) ReadByte(msg_read); + + } + + public static void ReadData(sizebuf_t msg_read, byte data[], int len) { + for (int i = 0; i < len; i++) + data[i] = (byte) ReadByte(msg_read); + } +} \ No newline at end of file diff --git a/src/jake2/qcommon/Netchan.java b/src/jake2/qcommon/Netchan.java index 3331646..458bcbd 100644 --- a/src/jake2/qcommon/Netchan.java +++ b/src/jake2/qcommon/Netchan.java @@ -2,27 +2,27 @@ * NetChannel.java * Copyright (C) 2003 * - * $Id: Netchan.java,v 1.3 2004-07-12 20:47:00 hzi Exp $ + * $Id: Netchan.java,v 1.4 2004-09-22 19:22:09 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.qcommon; import jake2.Defines; @@ -37,350 +37,335 @@ import jake2.sys.Sys; */ public final class Netchan extends SV_MAIN { - /* - - packet header - ------------- - 31 sequence - 1 does this message contains a reliable payload - 31 acknowledge sequence - 1 acknowledge receipt of even/odd message - 16 qport - - The remote connection never knows if it missed a reliable message, the - local side detects that it has been dropped by seeing a sequence acknowledge - higher thatn the last reliable sequence, but without the correct evon/odd - bit for the reliable set. - - If the sender notices that a reliable message has been dropped, it will be - retransmitted. It will not be retransmitted again until a message after - the retransmit has been acknowledged and the reliable still failed to get there. - - if the sequence number is -1, the packet should be handled without a netcon - - The reliable message can be added to at any time by doing - MSG_Write* (&netchan.message, ). - - If the message buffer is overflowed, either by a single message, or by - multiple frames worth piling up while the last reliable transmit goes - unacknowledged, the netchan signals a fatal error. - - Reliable messages are always placed first in a packet, then the unreliable - message is included if there is sufficient room. - - To the receiver, there is no distinction between the reliable and unreliable - parts of the message, they are just processed out as a single larger message. - - Illogical packet sequence numbers cause the packet to be dropped, but do - not kill the connection. This, combined with the tight window of valid - reliable acknowledgement numbers provides protection against malicious - address spoofing. - - - The qport field is a workaround for bad address translating routers that - sometimes remap the client's source port on a packet during gameplay. - - If the base part of the net address matches and the qport matches, then the - channel matches even if the IP port differs. The IP port should be updated - to the new value before sending out any replies. - - - If there is no information that needs to be transfered on a given frame, - such as during the connection stage while waiting for the client to load, - then a packet only needs to be delivered if there is something in the - unacknowledged reliable - */ - - public static cvar_t showpackets; - public static cvar_t showdrop; - public static cvar_t qport; - - //public static netadr_t net_from = new netadr_t(); - public static sizebuf_t net_message = new sizebuf_t(); - public static byte net_message_buffer[] = new byte[Defines.MAX_MSGLEN]; - - /* - =============== - Netchan_Init - - =============== - */ - //ok. - public static void Netchan_Init() { - long port; - - // pick a port value that should be nice and random - port = Sys.Milliseconds() & 0xffff; - - showpackets = Cvar.Get("showpackets", "0", 0); - showdrop = Cvar.Get("showdrop", "0", 0); - qport = Cvar.Get("qport", "" + port, Defines.CVAR_NOSET); - } - - /* - =============== - Netchan_OutOfBand - - Sends an out-of-band datagram - ================ - */ - //ok. - public static void Netchan_OutOfBand(int net_socket, netadr_t adr, int length, byte data[]) { - sizebuf_t send = new sizebuf_t(); - byte send_buf[] = new byte[Defines.MAX_MSGLEN]; - - // write the packet header - SZ.Init(send, send_buf, Defines.MAX_MSGLEN); - - MSG.WriteInt(send, -1); // -1 sequence means out of band - SZ.Write(send, data, length); - - // send the datagram - NET.SendPacket(net_socket, send.cursize, send.data, adr); - } - - public static void OutOfBandPrint(int net_socket, netadr_t adr, String s) { - Netchan_OutOfBand(net_socket, adr, s.length(), s.getBytes()); - } - - /* - ============== - Netchan_Setup - - called to open a channel to a remote system - ============== - */ - public static void Setup(int sock, netchan_t chan, netadr_t adr, int qport) { - //memset (chan, 0, sizeof(*chan)); - - chan.clear(); - chan.sock = sock; - chan.remote_address.set(adr); - chan.qport = qport; - chan.last_received = Globals.curtime; - chan.incoming_sequence = 0; - chan.outgoing_sequence = 1; - - SZ.Init(chan.message, chan.message_buf, chan.message_buf.length); - chan.message.allowoverflow = true; - } - - /* - =============== - Netchan_CanReliable - - Returns true if the last reliable message has acked - ================ - */ - public static boolean Netchan_CanReliable(netchan_t chan) { - if (chan.reliable_length != 0) - return false; // waiting for ack - return true; - } - // das ist richtig !!! - public static boolean Netchan_NeedReliable(netchan_t chan) { - boolean send_reliable; - - // if the remote side dropped the last reliable message, resend it - send_reliable = false; - - if (chan.incoming_acknowledged > chan.last_reliable_sequence && chan.incoming_reliable_acknowledged != chan.reliable_sequence) - send_reliable = true; - - // if the reliable transmit buffer is empty, copy the current message out - if (0 == chan.reliable_length && chan.message.cursize != 0) { - send_reliable = true; - } - - return send_reliable; - } - - /* - =============== - Netchan_Transmit - - tries to send an unreliable message to a connection, and handles the - transmition / retransmition of the reliable messages. - - A 0 length will still generate a packet and deal with the reliable messages. - ================ - */ - public static void Transmit(netchan_t chan, int length, byte data[]) { - sizebuf_t send = new sizebuf_t(); - byte send_buf[] = new byte[MAX_MSGLEN]; - int send_reliable; - int w1, w2; - - // check for message overflow - if (chan.message.overflowed) { - chan.fatal_error = true; - Com.Printf(NET.AdrToString(chan.remote_address) + ":Outgoing message overflow\n"); - return; - } - - send_reliable = Netchan_NeedReliable(chan) ? 1 : 0; - - if (chan.reliable_length == 0 && chan.message.cursize != 0) { - System.arraycopy(chan.message_buf, 0, chan.reliable_buf, 0, chan.message.cursize); - chan.reliable_length = chan.message.cursize; - chan.message.cursize = 0; - chan.reliable_sequence ^= 1; - } - - // write the packet header - SZ.Init(send, send_buf, send_buf.length); - - w1 = (chan.outgoing_sequence & ~(1 << 31)) | (send_reliable << 31); - w2 = (chan.incoming_sequence & ~(1 << 31)) | (chan.incoming_reliable_sequence << 31); - - chan.outgoing_sequence++; - chan.last_sent = (int) Globals.curtime; - - MSG.WriteInt(send, w1); - MSG.WriteInt(send, w2); - - // send the qport if we are a client - if (chan.sock == Defines.NS_CLIENT) - MSG.WriteShort(send, (int) qport.value); - - // copy the reliable message to the packet first - if (send_reliable != 0) { - SZ.Write(send, chan.reliable_buf, chan.reliable_length); - chan.last_reliable_sequence = chan.outgoing_sequence; - } - - // add the unreliable part if space is available - if (send.maxsize - send.cursize >= length) - SZ.Write(send, data, length); - else - Com.Printf("Netchan_Transmit: dumped unreliable\n"); - - // send the datagram - NET.SendPacket(chan.sock, send.cursize, send.data, chan.remote_address); - - if (showpackets.value != 0) { - if (send_reliable != 0) - Com.Printf(//"send %4i : s=%i reliable=%i ack=%i rack=%i\n" - "send " - + send.cursize - + " : s=" - + (chan.outgoing_sequence - 1) - + " reliable=" - + chan.reliable_sequence - + " ack=" - + chan.incoming_sequence - + " rack=" - + chan.incoming_reliable_sequence - + "\n"); - else - Com.Printf(//"send %4i : s=%i ack=%i rack=%i\n" - "send " - + send.cursize - + " : s=" - + (chan.outgoing_sequence - 1) - + " ack=" - + chan.incoming_sequence - + " rack=" - + chan.incoming_reliable_sequence - + "\n"); - } - } - - /* - ================= - Netchan_Process - - called when the current net_message is from remote_address - modifies net_message so that it points to the packet payload - ================= - */ - public static boolean Process(netchan_t chan, sizebuf_t msg) { - int sequence, sequence_ack; - int reliable_ack, reliable_message; - int qport; - - // get sequence numbers - MSG.BeginReading(msg); - sequence = MSG.ReadLong(msg); - sequence_ack = MSG.ReadLong(msg); - - // read the qport if we are a server - if (chan.sock == NS_SERVER) - qport = MSG.ReadShort(msg); - - // achtung unsigned int - reliable_message = sequence >>> 31; - reliable_ack = sequence_ack >>> 31; - - sequence &= ~(1 << 31); - sequence_ack &= ~(1 << 31); - - if (showpackets.value != 0) { - if (reliable_message != 0) - Com.Printf(//"recv %4i : s=%i reliable=%i ack=%i rack=%i\n" - "recv " - + msg.cursize - + " : s=" - + sequence - + " reliable=" - + (chan.incoming_reliable_sequence ^ 1) - + " ack=" - + sequence_ack - + " rack=" - + reliable_ack - + "\n"); - else - Com.Printf(//"recv %4i : s=%i ack=%i rack=%i\n" - "recv " + msg.cursize + " : s=" + sequence + " ack=" + sequence_ack + " rack=" + reliable_ack + "\n"); - } - - // - // discard stale or duplicated packets - // - if (sequence <= chan.incoming_sequence) { - if (showdrop.value != 0) - Com.Printf( - NET.AdrToString(chan.remote_address) - + ":Out of order packet " - + sequence - + " at " - + chan.incoming_sequence - + "\n"); - return false; - } - - // - // dropped packets don't keep the message from being used - // - chan.dropped = sequence - (chan.incoming_sequence + 1); - if (chan.dropped > 0) { - if (showdrop.value != 0) - Com.Printf(NET.AdrToString(chan.remote_address) + ":Dropped " + chan.dropped + " packets at " + sequence + "\n"); - } - - // - // if the current outgoing reliable message has been acknowledged - // clear the buffer to make way for the next - // - if (reliable_ack == chan.reliable_sequence) - chan.reliable_length = 0; // it has been received - - // - // if this message contains a reliable message, bump incoming_reliable_sequence - // - chan.incoming_sequence = sequence; - chan.incoming_acknowledged = sequence_ack; - chan.incoming_reliable_acknowledged = reliable_ack; - if (reliable_message != 0) { - chan.incoming_reliable_sequence ^= 1; - } - - // - // the message can now be read from the current message pointer - // - chan.last_received = (int) Globals.curtime; - - return true; - } - -} + /* + * + * packet header ------------- 31 sequence 1 does this message contains a + * reliable payload 31 acknowledge sequence 1 acknowledge receipt of + * even/odd message 16 qport + * + * The remote connection never knows if it missed a reliable message, the + * local side detects that it has been dropped by seeing a sequence + * acknowledge higher thatn the last reliable sequence, but without the + * correct evon/odd bit for the reliable set. + * + * If the sender notices that a reliable message has been dropped, it will + * be retransmitted. It will not be retransmitted again until a message + * after the retransmit has been acknowledged and the reliable still failed + * to get there. + * + * if the sequence number is -1, the packet should be handled without a + * netcon + * + * The reliable message can be added to at any time by doing MSG_Write* + * (&netchan.message, ). + * + * If the message buffer is overflowed, either by a single message, or by + * multiple frames worth piling up while the last reliable transmit goes + * unacknowledged, the netchan signals a fatal error. + * + * Reliable messages are always placed first in a packet, then the + * unreliable message is included if there is sufficient room. + * + * To the receiver, there is no distinction between the reliable and + * unreliable parts of the message, they are just processed out as a single + * larger message. + * + * Illogical packet sequence numbers cause the packet to be dropped, but do + * not kill the connection. This, combined with the tight window of valid + * reliable acknowledgement numbers provides protection against malicious + * address spoofing. + * + * + * The qport field is a workaround for bad address translating routers that + * sometimes remap the client's source port on a packet during gameplay. + * + * If the base part of the net address matches and the qport matches, then + * the channel matches even if the IP port differs. The IP port should be + * updated to the new value before sending out any replies. + * + * + * If there is no information that needs to be transfered on a given frame, + * such as during the connection stage while waiting for the client to load, + * then a packet only needs to be delivered if there is something in the + * unacknowledged reliable + */ + + public static cvar_t showpackets; + + public static cvar_t showdrop; + + public static cvar_t qport; + + //public static netadr_t net_from = new netadr_t(); + public static sizebuf_t net_message = new sizebuf_t(); + + public static byte net_message_buffer[] = new byte[Defines.MAX_MSGLEN]; + + /* + * =============== Netchan_Init + * + * =============== + */ + //ok. + public static void Netchan_Init() { + long port; + + // pick a port value that should be nice and random + port = Sys.Milliseconds() & 0xffff; + + showpackets = Cvar.Get("showpackets", "0", 0); + showdrop = Cvar.Get("showdrop", "0", 0); + qport = Cvar.Get("qport", "" + port, Defines.CVAR_NOSET); + } + + /* + * =============== Netchan_OutOfBand + * + * Sends an out-of-band datagram ================ + */ + //ok. + public static void Netchan_OutOfBand(int net_socket, netadr_t adr, + int length, byte data[]) { + sizebuf_t send = new sizebuf_t(); + byte send_buf[] = new byte[Defines.MAX_MSGLEN]; + + // write the packet header + SZ.Init(send, send_buf, Defines.MAX_MSGLEN); + + MSG.WriteInt(send, -1); // -1 sequence means out of band + SZ.Write(send, data, length); + + // send the datagram + NET.SendPacket(net_socket, send.cursize, send.data, adr); + } + + public static void OutOfBandPrint(int net_socket, netadr_t adr, String s) { + Netchan_OutOfBand(net_socket, adr, s.length(), s.getBytes()); + } + + /* + * ============== Netchan_Setup + * + * called to open a channel to a remote system ============== + */ + public static void Setup(int sock, netchan_t chan, netadr_t adr, int qport) { + //memset (chan, 0, sizeof(*chan)); + + chan.clear(); + chan.sock = sock; + chan.remote_address.set(adr); + chan.qport = qport; + chan.last_received = Globals.curtime; + chan.incoming_sequence = 0; + chan.outgoing_sequence = 1; + + SZ.Init(chan.message, chan.message_buf, chan.message_buf.length); + chan.message.allowoverflow = true; + } + + /* + * =============== Netchan_CanReliable + * + * Returns true if the last reliable message has acked ================ + */ + public static boolean Netchan_CanReliable(netchan_t chan) { + if (chan.reliable_length != 0) + return false; // waiting for ack + return true; + } + + // das ist richtig !!! + public static boolean Netchan_NeedReliable(netchan_t chan) { + boolean send_reliable; + + // if the remote side dropped the last reliable message, resend it + send_reliable = false; + + if (chan.incoming_acknowledged > chan.last_reliable_sequence + && chan.incoming_reliable_acknowledged != chan.reliable_sequence) + send_reliable = true; + + // if the reliable transmit buffer is empty, copy the current message + // out + if (0 == chan.reliable_length && chan.message.cursize != 0) { + send_reliable = true; + } + + return send_reliable; + } + + /* + * =============== Netchan_Transmit + * + * tries to send an unreliable message to a connection, and handles the + * transmition / retransmition of the reliable messages. + * + * A 0 length will still generate a packet and deal with the reliable + * messages. ================ + */ + public static void Transmit(netchan_t chan, int length, byte data[]) { + sizebuf_t send = new sizebuf_t(); + byte send_buf[] = new byte[Defines.MAX_MSGLEN]; + int send_reliable; + int w1, w2; + + // check for message overflow + if (chan.message.overflowed) { + chan.fatal_error = true; + Com.Printf(NET.AdrToString(chan.remote_address) + + ":Outgoing message overflow\n"); + return; + } + + send_reliable = Netchan_NeedReliable(chan) ? 1 : 0; + + if (chan.reliable_length == 0 && chan.message.cursize != 0) { + System.arraycopy(chan.message_buf, 0, chan.reliable_buf, 0, + chan.message.cursize); + chan.reliable_length = chan.message.cursize; + chan.message.cursize = 0; + chan.reliable_sequence ^= 1; + } + + // write the packet header + SZ.Init(send, send_buf, send_buf.length); + + w1 = (chan.outgoing_sequence & ~(1 << 31)) | (send_reliable << 31); + w2 = (chan.incoming_sequence & ~(1 << 31)) + | (chan.incoming_reliable_sequence << 31); + + chan.outgoing_sequence++; + chan.last_sent = (int) Globals.curtime; + + MSG.WriteInt(send, w1); + MSG.WriteInt(send, w2); + + // send the qport if we are a client + if (chan.sock == Defines.NS_CLIENT) + MSG.WriteShort(send, (int) qport.value); + + // copy the reliable message to the packet first + if (send_reliable != 0) { + SZ.Write(send, chan.reliable_buf, chan.reliable_length); + chan.last_reliable_sequence = chan.outgoing_sequence; + } + + // add the unreliable part if space is available + if (send.maxsize - send.cursize >= length) + SZ.Write(send, data, length); + else + Com.Printf("Netchan_Transmit: dumped unreliable\n"); + + // send the datagram + NET.SendPacket(chan.sock, send.cursize, send.data, chan.remote_address); + + if (showpackets.value != 0) { + if (send_reliable != 0) + Com.Printf( + //"send %4i : s=%i reliable=%i ack=%i rack=%i\n" + "send " + send.cursize + " : s=" + + (chan.outgoing_sequence - 1) + " reliable=" + + chan.reliable_sequence + " ack=" + + chan.incoming_sequence + " rack=" + + chan.incoming_reliable_sequence + "\n"); + else + Com.Printf( + //"send %4i : s=%i ack=%i rack=%i\n" + "send " + send.cursize + " : s=" + + (chan.outgoing_sequence - 1) + " ack=" + + chan.incoming_sequence + " rack=" + + chan.incoming_reliable_sequence + "\n"); + } + } + + /* + * ================= Netchan_Process + * + * called when the current net_message is from remote_address modifies + * net_message so that it points to the packet payload ================= + */ + public static boolean Process(netchan_t chan, sizebuf_t msg) { + int sequence, sequence_ack; + int reliable_ack, reliable_message; + int qport; + + // get sequence numbers + MSG.BeginReading(msg); + sequence = MSG.ReadLong(msg); + sequence_ack = MSG.ReadLong(msg); + + // read the qport if we are a server + if (chan.sock == Defines.NS_SERVER) + qport = MSG.ReadShort(msg); + + // achtung unsigned int + reliable_message = sequence >>> 31; + reliable_ack = sequence_ack >>> 31; + + sequence &= ~(1 << 31); + sequence_ack &= ~(1 << 31); + + if (showpackets.value != 0) { + if (reliable_message != 0) + Com.Printf( + //"recv %4i : s=%i reliable=%i ack=%i rack=%i\n" + "recv " + msg.cursize + " : s=" + sequence + + " reliable=" + + (chan.incoming_reliable_sequence ^ 1) + + " ack=" + sequence_ack + " rack=" + + reliable_ack + "\n"); + else + Com + .Printf( + //"recv %4i : s=%i ack=%i rack=%i\n" + "recv " + msg.cursize + " : s=" + sequence + " ack=" + + sequence_ack + " rack=" + reliable_ack + "\n"); + } + + // + // discard stale or duplicated packets + // + if (sequence <= chan.incoming_sequence) { + if (showdrop.value != 0) + Com.Printf(NET.AdrToString(chan.remote_address) + + ":Out of order packet " + sequence + " at " + + chan.incoming_sequence + "\n"); + return false; + } + + // + // dropped packets don't keep the message from being used + // + chan.dropped = sequence - (chan.incoming_sequence + 1); + if (chan.dropped > 0) { + if (showdrop.value != 0) + Com.Printf(NET.AdrToString(chan.remote_address) + ":Dropped " + + chan.dropped + " packets at " + sequence + "\n"); + } + + // + // if the current outgoing reliable message has been acknowledged + // clear the buffer to make way for the next + // + if (reliable_ack == chan.reliable_sequence) + chan.reliable_length = 0; // it has been received + + // + // if this message contains a reliable message, bump + // incoming_reliable_sequence + // + chan.incoming_sequence = sequence; + chan.incoming_acknowledged = sequence_ack; + chan.incoming_reliable_acknowledged = reliable_ack; + if (reliable_message != 0) { + chan.incoming_reliable_sequence ^= 1; + } + + // + // the message can now be read from the current message pointer + // + chan.last_received = (int) Globals.curtime; + + return true; + } +} \ No newline at end of file diff --git a/src/jake2/qcommon/PMove.java b/src/jake2/qcommon/PMove.java index 2043c8a..f4e92c3 100644 --- a/src/jake2/qcommon/PMove.java +++ b/src/jake2/qcommon/PMove.java @@ -1,1259 +1,1184 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 25.01.2004 by RST. -// $Id: PMove.java,v 1.4 2004-09-10 19:02:53 salomo Exp $ - +// $Id: PMove.java,v 1.5 2004-09-22 19:22:09 salomo Exp $ package jake2.qcommon; import jake2.*; import jake2.client.*; import jake2.game.*; -import jake2.qcommon.*; import jake2.render.*; import jake2.server.*; +import jake2.util.Math3D; + +public class PMove { + + // all of the locals will be zeroed before each + // pmove, just to make damn sure we don't have + // any differences when running on client or server + + public static class pml_t { + public float[] origin = { 0, 0, 0 }; // full float precision + + public float[] velocity = { 0, 0, 0 }; // full float precision + + public float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, + 0 }; + + public float frametime; + + public csurface_t groundsurface; + + public cplane_t groundplane = new cplane_t(); + + public int groundcontents; + + public float[] previous_origin = { 0, 0, 0 }; + + public boolean ladder; + } + + public static pmove_t pm; + + public static PMove.pml_t pml = new PMove.pml_t(); + + // movement parameters + public static float pm_stopspeed = 100; + + public static float pm_maxspeed = 300; + + public static float pm_duckspeed = 100; + + public static float pm_accelerate = 10; + + public static float pm_airaccelerate = 0; + + public static float pm_wateraccelerate = 10; + + public static float pm_friction = 6; + + public static float pm_waterfriction = 1; + + public static float pm_waterspeed = 400; + + /* + * ================ PM_SnapPosition + * + * On exit, the origin will have a value that is pre-quantized to the 0.125 + * precision of the network channel and in a valid position. + * ================ + */ + // try all single bits first + public static int jitterbits[] = { 0, 4, 1, 2, 3, 5, 6, 7 }; + + /* + * ================ PM_InitialSnapPosition + * + * ================ + */ + public static int offset[] = { 0, -1, 1 }; + + /* + * + * walking up a step should kill some velocity + * + */ + + /* + * ================== PM_ClipVelocity + * + * Slide off of the impacting object returns the blocked flags (1 = floor, 2 = + * step / wall) ================== + */ -public class PMove extends Game -{ - - public final static int STEPSIZE = 18; - - // all of the locals will be zeroed before each - // pmove, just to make damn sure we don't have - // any differences when running on client or server - - public static class pml_t - { - float[] origin = { 0, 0, 0 }; // full float precision - float[] velocity = { 0, 0, 0 }; // full float precision - - float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; - float frametime; - - csurface_t groundsurface; - cplane_t groundplane = new cplane_t(); - int groundcontents; - - float[] previous_origin = { 0, 0, 0 }; - boolean ladder; - } - - public static pmove_t pm; - public static pml_t pml = new pml_t(); - - // movement parameters - public static float pm_stopspeed = 100; - public static float pm_maxspeed = 300; - public static float pm_duckspeed = 100; - public static float pm_accelerate = 10; - public static float pm_airaccelerate = 0; - public static float pm_wateraccelerate = 10; - public static float pm_friction = 6; - public static float pm_waterfriction = 1; - public static float pm_waterspeed = 400; - - /* - - walking up a step should kill some velocity - - */ - - /* - ================== - PM_ClipVelocity - - Slide off of the impacting object - returns the blocked flags (1 = floor, 2 = step / wall) - ================== - */ - public static final float STOP_EPSILON = 0.1f; - - public static void PM_ClipVelocity(float[] in, float[] normal, float[] out, float overbounce) - { - float backoff; - float change; - int i; - - backoff = 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; - } - } - - /* - ================== - PM_StepSlideMove - - Each intersection will try to step over the obstruction instead of - sliding along it. - - Returns a new origin, velocity, and contact entity - Does not modify any world state? - ================== - */ - public final static float MIN_STEP_NORMAL = 0.7f; // can't step up onto very steep slopes - - public static void PM_StepSlideMove_() - { - int bumpcount, numbumps; - float[] dir = { 0, 0, 0 }; - float d; - int numplanes; - float[] planes[] = new float[MAX_CLIP_PLANES][3]; - float[] primal_velocity = { 0, 0, 0 }; - int i, j; - trace_t trace; - float[] end = { 0, 0, 0 }; - float time_left; - - numbumps = 4; - - VectorCopy(pml.velocity, primal_velocity); - numplanes = 0; - - time_left = pml.frametime; - - for (bumpcount = 0; bumpcount < numbumps; bumpcount++) - { - for (i = 0; i < 3; i++) - end[i] = pml.origin[i] + time_left * pml.velocity[i]; - - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, end); - - if (trace.allsolid) - { // entity is trapped in another solid - pml.velocity[2] = 0; // don't build up falling damage - return; - } - - if (trace.fraction > 0) - { // actually covered some distance - VectorCopy(trace.endpos, pml.origin); - numplanes = 0; - } - - if (trace.fraction == 1) - break; // moved the entire distance - - // save entity for contact - if (pm.numtouch < MAXTOUCH && trace.ent != null) - { - //rst: just for debugging touches. - //if (trace.ent.index != -1 && trace.ent.index != 0) - //Com.p("touch: " + trace.ent.classname + " (" + trace.ent.index + ")" ); - - pm.touchents[pm.numtouch] = trace.ent; - pm.numtouch++; - } - - time_left -= time_left * trace.fraction; - - // slide along this plane - if (numplanes >= MAX_CLIP_PLANES) - { // this shouldn't really happen - VectorCopy(vec3_origin, pml.velocity); - break; - } - - VectorCopy(trace.plane.normal, planes[numplanes]); - numplanes++; - - // - // modify original_velocity so it parallels all of the clip planes - // - - for (i = 0; i < numplanes; i++) - { - PM_ClipVelocity(pml.velocity, planes[i], pml.velocity, 1.01f); - for (j = 0; j < numplanes; j++) - if (j != i) - { - if (DotProduct(pml.velocity, planes[j]) < 0) - break; // not ok - } - if (j == numplanes) - break; - } - - if (i != numplanes) - { // go along this plane - } - else - { // go along the crease - if (numplanes != 2) - { - // Con_Printf ("clip velocity, numplanes == %i\n",numplanes); - VectorCopy(vec3_origin, pml.velocity); - break; - } - CrossProduct(planes[0], planes[1], dir); - d = DotProduct(dir, pml.velocity); - VectorScale(dir, d, pml.velocity); - } - - // - // if velocity is against the original velocity, stop dead - // to avoid tiny occilations in sloping corners - // - if (DotProduct(pml.velocity, primal_velocity) <= 0) - { - VectorCopy(vec3_origin, pml.velocity); - break; - } - } - - if (pm.s.pm_time != 0) - { - VectorCopy(primal_velocity, pml.velocity); - } - } - - /* - ================== - PM_StepSlideMove - - ================== - */ - public static void PM_StepSlideMove() - { - float[] start_o = { 0, 0, 0 }, start_v = { 0, 0, 0 }; - float[] down_o = { 0, 0, 0 }, down_v = { 0, 0, 0 }; - trace_t trace; - float down_dist, up_dist; - // float [] delta; - float[] up = { 0, 0, 0 }, down = { 0, 0, 0 }; - - VectorCopy(pml.origin, start_o); - VectorCopy(pml.velocity, start_v); - - PM_StepSlideMove_(); - - VectorCopy(pml.origin, down_o); - VectorCopy(pml.velocity, down_v); - - VectorCopy(start_o, up); - up[2] += STEPSIZE; - - trace = pm.trace.trace(up, pm.mins, pm.maxs, up); - if (trace.allsolid) - return; // can't step up - - // try sliding above - VectorCopy(up, pml.origin); - VectorCopy(start_v, pml.velocity); - - PM_StepSlideMove_(); - - // push down the final amount - VectorCopy(pml.origin, down); - down[2] -= STEPSIZE; - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, down); - if (!trace.allsolid) - { - VectorCopy(trace.endpos, pml.origin); - } - - VectorCopy(pml.origin, up); - - // decide which one went farther - down_dist = (down_o[0] - start_o[0]) * (down_o[0] - start_o[0]) + (down_o[1] - start_o[1]) * (down_o[1] - start_o[1]); - up_dist = (up[0] - start_o[0]) * (up[0] - start_o[0]) + (up[1] - start_o[1]) * (up[1] - start_o[1]); - - if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL) - { - VectorCopy(down_o, pml.origin); - VectorCopy(down_v, pml.velocity); - return; - } - //!! Special case - // if we were walking along a plane, then we need to copy the Z over - pml.velocity[2] = down_v[2]; - } - - /* - ================== - PM_Friction - - Handles both ground friction and water friction - ================== - */ - public static void PM_Friction() - { - float vel[]; - float speed, newspeed, control; - float friction; - float drop; - - vel = pml.velocity; - - speed = (float) (Math.sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2])); - if (speed < 1) - { - vel[0] = 0; - vel[1] = 0; - return; - } - - drop = 0; - - // apply ground friction - if ((pm.groundentity != null && pml.groundsurface != null && 0 == (pml.groundsurface.flags & SURF_SLICK)) || (pml.ladder)) - { - friction = pm_friction; - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control * friction * pml.frametime; - } - - // apply water friction - if (pm.waterlevel != 0 && !pml.ladder) - drop += speed * pm_waterfriction * pm.waterlevel * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - { - newspeed = 0; - } - newspeed /= speed; - - vel[0] = vel[0] * newspeed; - vel[1] = vel[1] * newspeed; - vel[2] = vel[2] * newspeed; - } - - /* - ============== - PM_Accelerate - - Handles user intended acceleration - ============== - */ - public static void PM_Accelerate(float[] wishdir, float wishspeed, float accel) - { - int i; - float addspeed, accelspeed, currentspeed; - - currentspeed = DotProduct(pml.velocity, wishdir); - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - accelspeed = accel * pml.frametime * wishspeed; - if (accelspeed > addspeed) - accelspeed = addspeed; - - for (i = 0; i < 3; i++) - pml.velocity[i] += accelspeed * wishdir[i]; - } - - public static void PM_AirAccelerate(float[] wishdir, float wishspeed, float accel) - { - int i; - float addspeed, accelspeed, currentspeed, wishspd = wishspeed; - - if (wishspd > 30) - wishspd = 30; - currentspeed = DotProduct(pml.velocity, wishdir); - addspeed = wishspd - currentspeed; - if (addspeed <= 0) - return; - accelspeed = accel * wishspeed * pml.frametime; - if (accelspeed > addspeed) - accelspeed = addspeed; - - for (i = 0; i < 3; i++) - pml.velocity[i] += accelspeed * wishdir[i]; - } - - /* - ============= - PM_AddCurrents - ============= - */ - public static void PM_AddCurrents(float[] wishvel) - { - float[] v = { 0, 0, 0 }; - float s; - - // - // account for ladders - // - - if (pml.ladder && Math.abs(pml.velocity[2]) <= 200) - { - if ((pm.viewangles[PITCH] <= -15) && (pm.cmd.forwardmove > 0)) - wishvel[2] = 200; - else if ((pm.viewangles[PITCH] >= 15) && (pm.cmd.forwardmove > 0)) - wishvel[2] = -200; - else if (pm.cmd.upmove > 0) - wishvel[2] = 200; - else if (pm.cmd.upmove < 0) - wishvel[2] = -200; - else - wishvel[2] = 0; - - // limit horizontal speed when on a ladder - if (wishvel[0] < -25) - wishvel[0] = -25; - else if (wishvel[0] > 25) - wishvel[0] = 25; - - if (wishvel[1] < -25) - wishvel[1] = -25; - else if (wishvel[1] > 25) - wishvel[1] = 25; - } - - // - // add water currents - // - - if ((pm.watertype & MASK_CURRENT) != 0) - { - VectorClear(v); - - if ((pm.watertype & CONTENTS_CURRENT_0) != 0) - v[0] += 1; - if ((pm.watertype & CONTENTS_CURRENT_90) != 0) - v[1] += 1; - if ((pm.watertype & CONTENTS_CURRENT_180) != 0) - v[0] -= 1; - if ((pm.watertype & CONTENTS_CURRENT_270) != 0) - v[1] -= 1; - if ((pm.watertype & CONTENTS_CURRENT_UP) != 0) - v[2] += 1; - if ((pm.watertype & CONTENTS_CURRENT_DOWN) != 0) - v[2] -= 1; - - s = pm_waterspeed; - if ((pm.waterlevel == 1) && (pm.groundentity != null)) - s /= 2; - - VectorMA(wishvel, s, v, wishvel); - } - - // - // add conveyor belt velocities - // - - if (pm.groundentity != null) - { - VectorClear(v); - - if ((pml.groundcontents & CONTENTS_CURRENT_0) != 0) - v[0] += 1; - if ((pml.groundcontents & CONTENTS_CURRENT_90) != 0) - v[1] += 1; - if ((pml.groundcontents & CONTENTS_CURRENT_180) != 0) - v[0] -= 1; - if ((pml.groundcontents & CONTENTS_CURRENT_270) != 0) - v[1] -= 1; - if ((pml.groundcontents & CONTENTS_CURRENT_UP) != 0) - v[2] += 1; - if ((pml.groundcontents & CONTENTS_CURRENT_DOWN) != 0) - v[2] -= 1; - - VectorMA(wishvel, 100 /* pm.groundentity.speed */ - , v, wishvel); - } - } - - /* - =================== - PM_WaterMove - - =================== - */ - public static void PM_WaterMove() - { - int i; - float[] wishvel = { 0, 0, 0 }; - float wishspeed; - float[] wishdir = { 0, 0, 0 }; - - // - // user intentions - // - for (i = 0; i < 3; i++) - wishvel[i] = pml.forward[i] * pm.cmd.forwardmove + pml.right[i] * pm.cmd.sidemove; - - if (0 == pm.cmd.forwardmove && 0 == pm.cmd.sidemove && 0 == pm.cmd.upmove) - wishvel[2] -= 60; // drift towards bottom - else - wishvel[2] += pm.cmd.upmove; - - PM_AddCurrents(wishvel); - - VectorCopy(wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - if (wishspeed > pm_maxspeed) - { - VectorScale(wishvel, pm_maxspeed / wishspeed, wishvel); - wishspeed = pm_maxspeed; - } - wishspeed *= 0.5; - - PM_Accelerate(wishdir, wishspeed, pm_wateraccelerate); - - PM_StepSlideMove(); - } - - /* - =================== - PM_AirMove - - =================== - */ - public static void PM_AirMove() - { - int i; - float[] wishvel = { 0, 0, 0 }; - float fmove, smove; - float[] wishdir = { 0, 0, 0 }; - float wishspeed; - float maxspeed; - - fmove = pm.cmd.forwardmove; - smove = pm.cmd.sidemove; - - for (i = 0; i < 2; i++) - wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel[2] = 0; - - PM_AddCurrents(wishvel); - - VectorCopy(wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - // - // clamp to server defined max speed - // - maxspeed = (pm.s.pm_flags & PMF_DUCKED) != 0 ? pm_duckspeed : pm_maxspeed; - - if (wishspeed > maxspeed) - { - VectorScale(wishvel, maxspeed / wishspeed, wishvel); - wishspeed = maxspeed; - } - - if (pml.ladder) - { - PM_Accelerate(wishdir, wishspeed, pm_accelerate); - if (0 == wishvel[2]) - { - if (pml.velocity[2] > 0) - { - pml.velocity[2] -= pm.s.gravity * pml.frametime; - if (pml.velocity[2] < 0) - pml.velocity[2] = 0; - } - else - { - pml.velocity[2] += pm.s.gravity * pml.frametime; - if (pml.velocity[2] > 0) - pml.velocity[2] = 0; - } - } - PM_StepSlideMove(); - } - else if (pm.groundentity != null) - { // walking on ground - pml.velocity[2] = 0; //!!! this is before the accel - PM_Accelerate(wishdir, wishspeed, pm_accelerate); - - // PGM -- fix for negative trigger_gravity fields - // pml.velocity[2] = 0; - if (pm.s.gravity > 0) - pml.velocity[2] = 0; - else - pml.velocity[2] -= pm.s.gravity * pml.frametime; - // PGM - - if (0 == pml.velocity[0] && 0 == pml.velocity[1]) - return; - PM_StepSlideMove(); - } - else - { // not on ground, so little effect on velocity - if (pm_airaccelerate != 0) - PM_AirAccelerate(wishdir, wishspeed, pm_accelerate); - else - PM_Accelerate(wishdir, wishspeed, 1); - // add gravity - pml.velocity[2] -= pm.s.gravity * pml.frametime; - PM_StepSlideMove(); - } - } - - /* - ============= - PM_CatagorizePosition - ============= - */ - public static void PM_CatagorizePosition() - { - float[] point = { 0, 0, 0 }; - int cont; - trace_t trace; - int sample1; - int sample2; - - // if the player hull point one unit down is solid, the player - // is on ground - - // see if standing on something solid - point[0] = pml.origin[0]; - point[1] = pml.origin[1]; - point[2] = pml.origin[2] - 0.25f; - if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel) - { - pm.s.pm_flags &= ~PMF_ON_GROUND; - pm.groundentity = null; - } - else - { - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, point); - pml.groundplane = trace.plane; - pml.groundsurface = trace.surface; - pml.groundcontents = trace.contents; - - if (null == trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid)) - { - pm.groundentity = null; - pm.s.pm_flags &= ~PMF_ON_GROUND; - } - else - { - pm.groundentity = trace.ent; - // hitting solid ground will end a waterjump - if ((pm.s.pm_flags & PMF_TIME_WATERJUMP) != 0) - { - pm.s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); - pm.s.pm_time = 0; - } - - if (0 == (pm.s.pm_flags & PMF_ON_GROUND)) - { // just hit the ground - pm.s.pm_flags |= PMF_ON_GROUND; - // don't do landing time if we were just going down a slope - if (pml.velocity[2] < -200) - { - pm.s.pm_flags |= PMF_TIME_LAND; - // don't allow another jump for a little while - if (pml.velocity[2] < -400) - pm.s.pm_time = 25; - else - pm.s.pm_time = 18; - } - } - } - - if (pm.numtouch < MAXTOUCH && trace.ent != null) - { - pm.touchents[pm.numtouch] = trace.ent; - pm.numtouch++; - } - } - - // - // get waterlevel, accounting for ducking - // - pm.waterlevel = 0; - pm.watertype = 0; - - sample2 = (int) (pm.viewheight - pm.mins[2]); - sample1 = sample2 / 2; - - point[2] = pml.origin[2] + pm.mins[2] + 1; - cont = pm.pointcontents.pointcontents(point); - - if ((cont & MASK_WATER) != 0) - { - pm.watertype = cont; - pm.waterlevel = 1; - point[2] = pml.origin[2] + pm.mins[2] + sample1; - cont = pm.pointcontents.pointcontents(point); - if ((cont & MASK_WATER) != 0) - { - pm.waterlevel = 2; - point[2] = pml.origin[2] + pm.mins[2] + sample2; - cont = pm.pointcontents.pointcontents(point); - if ((cont & MASK_WATER) != 0) - pm.waterlevel = 3; - } - } - - } - - /* - ============= - PM_CheckJump - ============= - */ - public static void PM_CheckJump() - { - if ((pm.s.pm_flags & PMF_TIME_LAND) != 0) - { // hasn't been long enough since landing to jump again - return; - } - - if (pm.cmd.upmove < 10) - { // not holding jump - pm.s.pm_flags &= ~PMF_JUMP_HELD; - return; - } - - // must wait for jump to be released - if ((pm.s.pm_flags & PMF_JUMP_HELD) != 0) - return; - - if (pm.s.pm_type == PM_DEAD) - return; - - if (pm.waterlevel >= 2) - { // swimming, not jumping - pm.groundentity = null; - - if (pml.velocity[2] <= -300) - return; - - if (pm.watertype == CONTENTS_WATER) - pml.velocity[2] = 100; - else if (pm.watertype == CONTENTS_SLIME) - pml.velocity[2] = 80; - else - pml.velocity[2] = 50; - return; - } - - if (pm.groundentity == null) - return; // in air, so no effect - - pm.s.pm_flags |= PMF_JUMP_HELD; - - pm.groundentity = null; - pml.velocity[2] += 270; - if (pml.velocity[2] < 270) - pml.velocity[2] = 270; - } - - /* - ============= - PM_CheckSpecialMovement - ============= - */ - public static void PM_CheckSpecialMovement() - { - float[] spot = { 0, 0, 0 }; - int cont; - float[] flatforward = { 0, 0, 0 }; - trace_t trace; - - if (pm.s.pm_time != 0) - return; - - pml.ladder = false; - - // check for ladder - flatforward[0] = pml.forward[0]; - flatforward[1] = pml.forward[1]; - flatforward[2] = 0; - VectorNormalize(flatforward); - - VectorMA(pml.origin, 1, flatforward, spot); - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, spot); - if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER) != 0) - pml.ladder = true; - - // check for water jump - if (pm.waterlevel != 2) - return; - - VectorMA(pml.origin, 30, flatforward, spot); - spot[2] += 4; - cont = pm.pointcontents.pointcontents(spot); - if (0 == (cont & CONTENTS_SOLID)) - return; - - spot[2] += 16; - cont = pm.pointcontents.pointcontents(spot); - if (cont != 0) - return; - // jump out of water - VectorScale(flatforward, 50, pml.velocity); - pml.velocity[2] = 350; - - pm.s.pm_flags |= PMF_TIME_WATERJUMP; - pm.s.pm_time = -1; // was 255 - } - - /* - =============== - PM_FlyMove - =============== - */ - public static void PM_FlyMove(boolean doclip) - { - float speed, drop, friction, control, newspeed; - float currentspeed, addspeed, accelspeed; - int i; - float[] wishvel = { 0, 0, 0 }; - float fmove, smove; - float[] wishdir = { 0, 0, 0 }; - float wishspeed; - float[] end = { 0, 0, 0 }; - trace_t trace; - - pm.viewheight = 22; - - // friction - - speed = VectorLength(pml.velocity); - if (speed < 1) - { - VectorCopy(vec3_origin, pml.velocity); - } - else - { - drop = 0; - - friction = pm_friction * 1.5f; // extra friction - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control * friction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - newspeed /= speed; - - VectorScale(pml.velocity, newspeed, pml.velocity); - } - - // accelerate - fmove = pm.cmd.forwardmove; - smove = pm.cmd.sidemove; - - VectorNormalize(pml.forward); - VectorNormalize(pml.right); - - for (i = 0; i < 3; i++) - wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel[2] += pm.cmd.upmove; - - VectorCopy(wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - // - // clamp to server defined max speed - // - if (wishspeed > pm_maxspeed) - { - VectorScale(wishvel, pm_maxspeed / wishspeed, wishvel); - wishspeed = pm_maxspeed; - } - - currentspeed = DotProduct(pml.velocity, wishdir); - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - accelspeed = pm_accelerate * pml.frametime * wishspeed; - if (accelspeed > addspeed) - accelspeed = addspeed; - - for (i = 0; i < 3; i++) - pml.velocity[i] += accelspeed * wishdir[i]; - - if (doclip) - { - for (i = 0; i < 3; i++) - end[i] = pml.origin[i] + pml.frametime * pml.velocity[i]; - - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, end); - - VectorCopy(trace.endpos, pml.origin); - } - else - { - // move - VectorMA(pml.origin, pml.frametime, pml.velocity, pml.origin); - } - } - - /* - ============== - PM_CheckDuck - - Sets mins, maxs, and pm.viewheight - ============== - */ - public static void PM_CheckDuck() - { - trace_t trace; - - pm.mins[0] = -16; - pm.mins[1] = -16; - - pm.maxs[0] = 16; - pm.maxs[1] = 16; - - if (pm.s.pm_type == PM_GIB) - { - pm.mins[2] = 0; - pm.maxs[2] = 16; - pm.viewheight = 8; - return; - } - - pm.mins[2] = -24; - - if (pm.s.pm_type == PM_DEAD) - { - pm.s.pm_flags |= PMF_DUCKED; - } - else if (pm.cmd.upmove < 0 && (pm.s.pm_flags & PMF_ON_GROUND) != 0) - { // duck - pm.s.pm_flags |= PMF_DUCKED; - } - else - { // stand up if possible - if ((pm.s.pm_flags & PMF_DUCKED) != 0) - { - // try to stand up - pm.maxs[2] = 32; - trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, pml.origin); - if (!trace.allsolid) - pm.s.pm_flags &= ~PMF_DUCKED; - } - } - - if ((pm.s.pm_flags & PMF_DUCKED) != 0) - { - pm.maxs[2] = 4; - pm.viewheight = -2; - } - else - { - pm.maxs[2] = 32; - pm.viewheight = 22; - } - } - - /* - ============== - PM_DeadMove - ============== - */ - public static void PM_DeadMove() - { - float forward; - - if (null == pm.groundentity) - return; - - // extra friction - - forward = VectorLength(pml.velocity); - forward -= 20; - if (forward <= 0) - { - VectorClear(pml.velocity); - } - else - { - VectorNormalize(pml.velocity); - VectorScale(pml.velocity, forward, pml.velocity); - } - } - - public static boolean PM_GoodPosition() - { - trace_t trace; - float[] origin = { 0, 0, 0 }, end = { 0, 0, 0 }; - int i; - - if (pm.s.pm_type == PM_SPECTATOR) - return true; - - for (i = 0; i < 3; i++) - origin[i] = end[i] = pm.s.origin[i] * 0.125f; - trace = pm.trace.trace(origin, pm.mins, pm.maxs, end); - - return !trace.allsolid; - } - - /* - ================ - PM_SnapPosition - - On exit, the origin will have a value that is pre-quantized to the 0.125 - precision of the network channel and in a valid position. - ================ - */ - // try all single bits first - static int jitterbits[] = { 0, 4, 1, 2, 3, 5, 6, 7 }; - public static void PM_SnapPosition() - { - int sign[] = { 0, 0, 0 }; - int i, j, bits; - short base[] = { 0, 0, 0 }; - - // snap velocity to eigths - for (i = 0; i < 3; i++) - pm.s.velocity[i] = (short) (pml.velocity[i] * 8); - - for (i = 0; i < 3; i++) - { - if (pml.origin[i] >= 0) - sign[i] = 1; - else - sign[i] = -1; - pm.s.origin[i] = (short) (pml.origin[i] * 8); - if (pm.s.origin[i] * 0.125 == pml.origin[i]) - sign[i] = 0; - } - VectorCopy(pm.s.origin, base); - - // try all combinations - for (j = 0; j < 8; j++) - { - bits = jitterbits[j]; - VectorCopy(base, pm.s.origin); - for (i = 0; i < 3; i++) - if ((bits & (1 << i)) != 0) - pm.s.origin[i] += sign[i]; - - if (PM_GoodPosition()) - return; - } - - // go back to the last position - VectorCopy(pml.previous_origin, pm.s.origin); - // Com_DPrintf ("using previous_origin\n"); - } - - /* - ================ - PM_InitialSnapPosition - - ================ - */ - static int offset[] = { 0, -1, 1 }; - public static void PM_InitialSnapPosition() - { - int x, y, z; - short base[] = { 0, 0, 0 }; - - VectorCopy(pm.s.origin, base); - - for (z = 0; z < 3; z++) - { - pm.s.origin[2] = (short) (base[2] + offset[z]); - for (y = 0; y < 3; y++) - { - pm.s.origin[1] = (short) (base[1] + offset[y]); - for (x = 0; x < 3; x++) - { - pm.s.origin[0] = (short) (base[0] + offset[x]); - if (PM_GoodPosition()) - { - pml.origin[0] = pm.s.origin[0] * 0.125f; - pml.origin[1] = pm.s.origin[1] * 0.125f; - pml.origin[2] = pm.s.origin[2] * 0.125f; - VectorCopy(pm.s.origin, pml.previous_origin); - return; - } - } - } - } - - Com.DPrintf("Bad InitialSnapPosition\n"); - } - - /* - ================ - PM_ClampAngles - - ================ - */ - public static void PM_ClampAngles() - { - short temp; - int i; - - if ((pm.s.pm_flags & PMF_TIME_TELEPORT) != 0) - { - pm.viewangles[YAW] = SHORT2ANGLE(pm.cmd.angles[YAW] + pm.s.delta_angles[YAW]); - pm.viewangles[PITCH] = 0; - pm.viewangles[ROLL] = 0; - } - else - { - // circularly clamp the angles with deltas - for (i = 0; i < 3; i++) - { - temp = (short) (pm.cmd.angles[i] + pm.s.delta_angles[i]); - pm.viewangles[i] = SHORT2ANGLE(temp); - } - - // don't let the player look up or down more than 90 degrees - if (pm.viewangles[PITCH] > 89 && pm.viewangles[PITCH] < 180) - pm.viewangles[PITCH] = 89; - else if (pm.viewangles[PITCH] < 271 && pm.viewangles[PITCH] >= 180) - pm.viewangles[PITCH] = 271; - } - AngleVectors(pm.viewangles, pml.forward, pml.right, pml.up); - } - - /* - ================ - Pmove - - Can be called by either the server or the client - ================ - */ - public static void Pmove(pmove_t pmove) - { - pm = pmove; - - // clear results - pm.numtouch = 0; - VectorClear(pm.viewangles); - pm.viewheight = 0; - pm.groundentity = null; - pm.watertype = 0; - pm.waterlevel = 0; - - // clear all pmove local vars - pml = new pml_t(); - - // convert origin and velocity to float values - pml.origin[0] = pm.s.origin[0] * 0.125f; - pml.origin[1] = pm.s.origin[1] * 0.125f; - pml.origin[2] = pm.s.origin[2] * 0.125f; - - pml.velocity[0] = pm.s.velocity[0] * 0.125f; - pml.velocity[1] = pm.s.velocity[1] * 0.125f; - pml.velocity[2] = pm.s.velocity[2] * 0.125f; - - // save old org in case we get stuck - VectorCopy(pm.s.origin, pml.previous_origin); - - pml.frametime = (pm.cmd.msec & 0xFF) * 0.001f; - - PM_ClampAngles(); - - if (pm.s.pm_type == PM_SPECTATOR) - { - PM_FlyMove(false); - PM_SnapPosition(); - return; - } - - if (pm.s.pm_type >= PM_DEAD) - { - pm.cmd.forwardmove = 0; - pm.cmd.sidemove = 0; - pm.cmd.upmove = 0; - } - - if (pm.s.pm_type == PM_FREEZE) - return; // no movement at all - - // set mins, maxs, and viewheight - PM_CheckDuck(); - - if (pm.snapinitial) - PM_InitialSnapPosition(); - - // set groundentity, watertype, and waterlevel - PM_CatagorizePosition(); - - if (pm.s.pm_type == PM_DEAD) - PM_DeadMove(); - - PM_CheckSpecialMovement(); - - // drop timing counter - if (pm.s.pm_time != 0) - { - int msec; - - // TOD o bugfix cwei - msec = pm.cmd.msec >>> 3; - if (msec == 0) - msec = 1; - if (msec >= (pm.s.pm_time & 0xFF)) - { - pm.s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); - pm.s.pm_time = 0; - } - else - pm.s.pm_time = (byte)((pm.s.pm_time & 0xFF) - msec); - } - - if ((pm.s.pm_flags & PMF_TIME_TELEPORT) != 0) - { // teleport pause stays exactly in place - } - else if ((pm.s.pm_flags & PMF_TIME_WATERJUMP) != 0) - { // waterjump has no control, but falls - pml.velocity[2] -= pm.s.gravity * pml.frametime; - if (pml.velocity[2] < 0) - { // cancel as soon as we are falling down again - pm.s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); - pm.s.pm_time = 0; - } - - PM_StepSlideMove(); - } - else - { - PM_CheckJump(); - - PM_Friction(); - - if (pm.waterlevel >= 2) - PM_WaterMove(); - else - { - float[] angles={0,0,0}; - - VectorCopy(pm.viewangles, angles); - if (angles[PITCH] > 180) - angles[PITCH] = angles[PITCH] - 360; - angles[PITCH] /= 3; - - AngleVectors(angles, pml.forward, pml.right, pml.up); - - PM_AirMove(); - } - } - - // set groundentity, watertype, and waterlevel for final spot - PM_CatagorizePosition(); - - PM_SnapPosition(); - } -} + public static void PM_ClipVelocity(float[] in, float[] normal, float[] out, + float overbounce) { + float backoff; + float change; + int i; + + backoff = Math3D.DotProduct(in, normal) * overbounce; + + for (i = 0; i < 3; i++) { + change = normal[i] * backoff; + out[i] = in[i] - change; + if (out[i] > -Defines.MOVE_STOP_EPSILON + && out[i] < Defines.MOVE_STOP_EPSILON) + out[i] = 0; + } + } + + public static void PM_StepSlideMove_() { + int bumpcount, numbumps; + float[] dir = { 0, 0, 0 }; + float d; + int numplanes; + float[] planes[] = new float[GameBase.MAX_CLIP_PLANES][3]; + float[] primal_velocity = { 0, 0, 0 }; + int i, j; + trace_t trace; + float[] end = { 0, 0, 0 }; + float time_left; + + numbumps = 4; + + Math3D.VectorCopy(PMove.pml.velocity, primal_velocity); + numplanes = 0; + + time_left = PMove.pml.frametime; + + for (bumpcount = 0; bumpcount < numbumps; bumpcount++) { + for (i = 0; i < 3; i++) + end[i] = PMove.pml.origin[i] + time_left + * PMove.pml.velocity[i]; + + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, end); + + if (trace.allsolid) { // entity is trapped in another solid + PMove.pml.velocity[2] = 0; // don't build up falling damage + return; + } + + if (trace.fraction > 0) { // actually covered some distance + Math3D.VectorCopy(trace.endpos, PMove.pml.origin); + numplanes = 0; + } + + if (trace.fraction == 1) + break; // moved the entire distance + + // save entity for contact + if (PMove.pm.numtouch < Defines.MAXTOUCH && trace.ent != null) { + //rst: just for debugging touches. + //if (trace.ent.index != -1 && trace.ent.index != 0) + //Com.p("touch: " + trace.ent.classname + " (" + + // trace.ent.index + ")" ); + + PMove.pm.touchents[PMove.pm.numtouch] = trace.ent; + PMove.pm.numtouch++; + } + + time_left -= time_left * trace.fraction; + + // slide along this plane + if (numplanes >= GameBase.MAX_CLIP_PLANES) { // this shouldn't + // really happen + Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity); + break; + } + + Math3D.VectorCopy(trace.plane.normal, planes[numplanes]); + numplanes++; + + // + // modify original_velocity so it parallels all of the clip planes + // + + for (i = 0; i < numplanes; i++) { + PMove.PM_ClipVelocity(PMove.pml.velocity, planes[i], + PMove.pml.velocity, 1.01f); + for (j = 0; j < numplanes; j++) + if (j != i) { + if (Math3D.DotProduct(PMove.pml.velocity, planes[j]) < 0) + break; // not ok + } + if (j == numplanes) + break; + } + + if (i != numplanes) { // go along this plane + } else { // go along the crease + if (numplanes != 2) { + // Con_Printf ("clip velocity, numplanes == + // %i\n",numplanes); + Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity); + break; + } + Math3D.CrossProduct(planes[0], planes[1], dir); + d = Math3D.DotProduct(dir, PMove.pml.velocity); + Math3D.VectorScale(dir, d, PMove.pml.velocity); + } + + // + // if velocity is against the original velocity, stop dead + // to avoid tiny occilations in sloping corners + // + if (Math3D.DotProduct(PMove.pml.velocity, primal_velocity) <= 0) { + Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity); + break; + } + } + + if (PMove.pm.s.pm_time != 0) { + Math3D.VectorCopy(primal_velocity, PMove.pml.velocity); + } + } + + /* + * ================== PM_StepSlideMove + * + * ================== + */ + public static void PM_StepSlideMove() { + float[] start_o = { 0, 0, 0 }, start_v = { 0, 0, 0 }; + float[] down_o = { 0, 0, 0 }, down_v = { 0, 0, 0 }; + trace_t trace; + float down_dist, up_dist; + // float [] delta; + float[] up = { 0, 0, 0 }, down = { 0, 0, 0 }; + + Math3D.VectorCopy(PMove.pml.origin, start_o); + Math3D.VectorCopy(PMove.pml.velocity, start_v); + + PM_StepSlideMove_(); + + Math3D.VectorCopy(PMove.pml.origin, down_o); + Math3D.VectorCopy(PMove.pml.velocity, down_v); + + Math3D.VectorCopy(start_o, up); + up[2] += Defines.STEPSIZE; + + trace = PMove.pm.trace.trace(up, PMove.pm.mins, PMove.pm.maxs, up); + if (trace.allsolid) + return; // can't step up + + // try sliding above + Math3D.VectorCopy(up, PMove.pml.origin); + Math3D.VectorCopy(start_v, PMove.pml.velocity); + + PM_StepSlideMove_(); + + // push down the final amount + Math3D.VectorCopy(PMove.pml.origin, down); + down[2] -= Defines.STEPSIZE; + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, down); + if (!trace.allsolid) { + Math3D.VectorCopy(trace.endpos, PMove.pml.origin); + } + + Math3D.VectorCopy(PMove.pml.origin, up); + + // decide which one went farther + down_dist = (down_o[0] - start_o[0]) * (down_o[0] - start_o[0]) + + (down_o[1] - start_o[1]) * (down_o[1] - start_o[1]); + up_dist = (up[0] - start_o[0]) * (up[0] - start_o[0]) + + (up[1] - start_o[1]) * (up[1] - start_o[1]); + + if (down_dist > up_dist + || trace.plane.normal[2] < Defines.MIN_STEP_NORMAL) { + Math3D.VectorCopy(down_o, PMove.pml.origin); + Math3D.VectorCopy(down_v, PMove.pml.velocity); + return; + } + //!! Special case + // if we were walking along a plane, then we need to copy the Z over + PMove.pml.velocity[2] = down_v[2]; + } + + /* + * ================== PM_Friction + * + * Handles both ground friction and water friction ================== + */ + public static void PM_Friction() { + float vel[]; + float speed, newspeed, control; + float friction; + float drop; + + vel = PMove.pml.velocity; + + speed = (float) (Math.sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] + * vel[2])); + if (speed < 1) { + vel[0] = 0; + vel[1] = 0; + return; + } + + drop = 0; + + // apply ground friction + if ((PMove.pm.groundentity != null && PMove.pml.groundsurface != null && 0 == (PMove.pml.groundsurface.flags & Defines.SURF_SLICK)) + || (PMove.pml.ladder)) { + friction = PMove.pm_friction; + control = speed < PMove.pm_stopspeed ? PMove.pm_stopspeed : speed; + drop += control * friction * PMove.pml.frametime; + } + + // apply water friction + if (PMove.pm.waterlevel != 0 && !PMove.pml.ladder) + drop += speed * PMove.pm_waterfriction * PMove.pm.waterlevel + * PMove.pml.frametime; + + // scale the velocity + newspeed = speed - drop; + if (newspeed < 0) { + newspeed = 0; + } + newspeed /= speed; + + vel[0] = vel[0] * newspeed; + vel[1] = vel[1] * newspeed; + vel[2] = vel[2] * newspeed; + } + + /* + * ============== PM_Accelerate + * + * Handles user intended acceleration ============== + */ + public static void PM_Accelerate(float[] wishdir, float wishspeed, + float accel) { + int i; + float addspeed, accelspeed, currentspeed; + + currentspeed = Math3D.DotProduct(PMove.pml.velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = accel * PMove.pml.frametime * wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i = 0; i < 3; i++) + PMove.pml.velocity[i] += accelspeed * wishdir[i]; + } + + public static void PM_AirAccelerate(float[] wishdir, float wishspeed, + float accel) { + int i; + float addspeed, accelspeed, currentspeed, wishspd = wishspeed; + + if (wishspd > 30) + wishspd = 30; + currentspeed = Math3D.DotProduct(PMove.pml.velocity, wishdir); + addspeed = wishspd - currentspeed; + if (addspeed <= 0) + return; + accelspeed = accel * wishspeed * PMove.pml.frametime; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i = 0; i < 3; i++) + PMove.pml.velocity[i] += accelspeed * wishdir[i]; + } + + /* + * ============= PM_AddCurrents ============= + */ + public static void PM_AddCurrents(float[] wishvel) { + float[] v = { 0, 0, 0 }; + float s; + + // + // account for ladders + // + + if (PMove.pml.ladder && Math.abs(PMove.pml.velocity[2]) <= 200) { + if ((PMove.pm.viewangles[Defines.PITCH] <= -15) + && (PMove.pm.cmd.forwardmove > 0)) + wishvel[2] = 200; + else if ((PMove.pm.viewangles[Defines.PITCH] >= 15) + && (PMove.pm.cmd.forwardmove > 0)) + wishvel[2] = -200; + else if (PMove.pm.cmd.upmove > 0) + wishvel[2] = 200; + else if (PMove.pm.cmd.upmove < 0) + wishvel[2] = -200; + else + wishvel[2] = 0; + + // limit horizontal speed when on a ladder + if (wishvel[0] < -25) + wishvel[0] = -25; + else if (wishvel[0] > 25) + wishvel[0] = 25; + + if (wishvel[1] < -25) + wishvel[1] = -25; + else if (wishvel[1] > 25) + wishvel[1] = 25; + } + + // + // add water currents + // + + if ((PMove.pm.watertype & Defines.MASK_CURRENT) != 0) { + Math3D.VectorClear(v); + + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_0) != 0) + v[0] += 1; + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_90) != 0) + v[1] += 1; + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_180) != 0) + v[0] -= 1; + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_270) != 0) + v[1] -= 1; + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_UP) != 0) + v[2] += 1; + if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_DOWN) != 0) + v[2] -= 1; + + s = PMove.pm_waterspeed; + if ((PMove.pm.waterlevel == 1) && (PMove.pm.groundentity != null)) + s /= 2; + + Math3D.VectorMA(wishvel, s, v, wishvel); + } + + // + // add conveyor belt velocities + // + + if (PMove.pm.groundentity != null) { + Math3D.VectorClear(v); + + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_0) != 0) + v[0] += 1; + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_90) != 0) + v[1] += 1; + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_180) != 0) + v[0] -= 1; + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_270) != 0) + v[1] -= 1; + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_UP) != 0) + v[2] += 1; + if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_DOWN) != 0) + v[2] -= 1; + + Math3D.VectorMA(wishvel, 100 /* pm.groundentity.speed */ + , v, wishvel); + } + } + + /* + * =================== PM_WaterMove + * + * =================== + */ + public static void PM_WaterMove() { + int i; + float[] wishvel = { 0, 0, 0 }; + float wishspeed; + float[] wishdir = { 0, 0, 0 }; + + // + // user intentions + // + for (i = 0; i < 3; i++) + wishvel[i] = PMove.pml.forward[i] * PMove.pm.cmd.forwardmove + + PMove.pml.right[i] * PMove.pm.cmd.sidemove; + + if (0 == PMove.pm.cmd.forwardmove && 0 == PMove.pm.cmd.sidemove + && 0 == PMove.pm.cmd.upmove) + wishvel[2] -= 60; // drift towards bottom + else + wishvel[2] += PMove.pm.cmd.upmove; + + PM_AddCurrents(wishvel); + + Math3D.VectorCopy(wishvel, wishdir); + wishspeed = Math3D.VectorNormalize(wishdir); + + if (wishspeed > PMove.pm_maxspeed) { + Math3D.VectorScale(wishvel, PMove.pm_maxspeed / wishspeed, wishvel); + wishspeed = PMove.pm_maxspeed; + } + wishspeed *= 0.5; + + PM_Accelerate(wishdir, wishspeed, PMove.pm_wateraccelerate); + + PM_StepSlideMove(); + } + + /* + * =================== PM_AirMove + * + * =================== + */ + public static void PM_AirMove() { + int i; + float[] wishvel = { 0, 0, 0 }; + float fmove, smove; + float[] wishdir = { 0, 0, 0 }; + float wishspeed; + float maxspeed; + + fmove = PMove.pm.cmd.forwardmove; + smove = PMove.pm.cmd.sidemove; + + for (i = 0; i < 2; i++) + wishvel[i] = PMove.pml.forward[i] * fmove + PMove.pml.right[i] + * smove; + wishvel[2] = 0; + + PM_AddCurrents(wishvel); + + Math3D.VectorCopy(wishvel, wishdir); + wishspeed = Math3D.VectorNormalize(wishdir); + + // + // clamp to server defined max speed + // + maxspeed = (PMove.pm.s.pm_flags & pmove_t.PMF_DUCKED) != 0 ? PMove.pm_duckspeed + : PMove.pm_maxspeed; + + if (wishspeed > maxspeed) { + Math3D.VectorScale(wishvel, maxspeed / wishspeed, wishvel); + wishspeed = maxspeed; + } + + if (PMove.pml.ladder) { + PM_Accelerate(wishdir, wishspeed, PMove.pm_accelerate); + if (0 == wishvel[2]) { + if (PMove.pml.velocity[2] > 0) { + PMove.pml.velocity[2] -= PMove.pm.s.gravity + * PMove.pml.frametime; + if (PMove.pml.velocity[2] < 0) + PMove.pml.velocity[2] = 0; + } else { + PMove.pml.velocity[2] += PMove.pm.s.gravity + * PMove.pml.frametime; + if (PMove.pml.velocity[2] > 0) + PMove.pml.velocity[2] = 0; + } + } + PM_StepSlideMove(); + } else if (PMove.pm.groundentity != null) { // walking on ground + PMove.pml.velocity[2] = 0; //!!! this is before the accel + PM_Accelerate(wishdir, wishspeed, PMove.pm_accelerate); + + // PGM -- fix for negative trigger_gravity fields + // pml.velocity[2] = 0; + if (PMove.pm.s.gravity > 0) + PMove.pml.velocity[2] = 0; + else + PMove.pml.velocity[2] -= PMove.pm.s.gravity + * PMove.pml.frametime; + // PGM + + if (0 == PMove.pml.velocity[0] && 0 == PMove.pml.velocity[1]) + return; + PM_StepSlideMove(); + } else { // not on ground, so little effect on velocity + if (PMove.pm_airaccelerate != 0) + PM_AirAccelerate(wishdir, wishspeed, PMove.pm_accelerate); + else + PM_Accelerate(wishdir, wishspeed, 1); + // add gravity + PMove.pml.velocity[2] -= PMove.pm.s.gravity * PMove.pml.frametime; + PM_StepSlideMove(); + } + } + + /* + * ============= PM_CatagorizePosition ============= + */ + public static void PM_CatagorizePosition() { + float[] point = { 0, 0, 0 }; + int cont; + trace_t trace; + int sample1; + int sample2; + + // if the player hull point one unit down is solid, the player + // is on ground + + // see if standing on something solid + point[0] = PMove.pml.origin[0]; + point[1] = PMove.pml.origin[1]; + point[2] = PMove.pml.origin[2] - 0.25f; + if (PMove.pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp + // accel) + { + PMove.pm.s.pm_flags &= ~pmove_t.PMF_ON_GROUND; + PMove.pm.groundentity = null; + } else { + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, point); + PMove.pml.groundplane = trace.plane; + PMove.pml.groundsurface = trace.surface; + PMove.pml.groundcontents = trace.contents; + + if (null == trace.ent + || (trace.plane.normal[2] < 0.7 && !trace.startsolid)) { + PMove.pm.groundentity = null; + PMove.pm.s.pm_flags &= ~pmove_t.PMF_ON_GROUND; + } else { + PMove.pm.groundentity = trace.ent; + // hitting solid ground will end a waterjump + if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_WATERJUMP) != 0) { + PMove.pm.s.pm_flags &= ~(pmove_t.PMF_TIME_WATERJUMP + | pmove_t.PMF_TIME_LAND | pmove_t.PMF_TIME_TELEPORT); + PMove.pm.s.pm_time = 0; + } + + if (0 == (PMove.pm.s.pm_flags & pmove_t.PMF_ON_GROUND)) { // just + // hit + // the + // ground + PMove.pm.s.pm_flags |= pmove_t.PMF_ON_GROUND; + // don't do landing time if we were just going down a slope + if (PMove.pml.velocity[2] < -200) { + PMove.pm.s.pm_flags |= pmove_t.PMF_TIME_LAND; + // don't allow another jump for a little while + if (PMove.pml.velocity[2] < -400) + PMove.pm.s.pm_time = 25; + else + PMove.pm.s.pm_time = 18; + } + } + } + + if (PMove.pm.numtouch < Defines.MAXTOUCH && trace.ent != null) { + PMove.pm.touchents[PMove.pm.numtouch] = trace.ent; + PMove.pm.numtouch++; + } + } + + // + // get waterlevel, accounting for ducking + // + PMove.pm.waterlevel = 0; + PMove.pm.watertype = 0; + + sample2 = (int) (PMove.pm.viewheight - PMove.pm.mins[2]); + sample1 = sample2 / 2; + + point[2] = PMove.pml.origin[2] + PMove.pm.mins[2] + 1; + cont = PMove.pm.pointcontents.pointcontents(point); + + if ((cont & Defines.MASK_WATER) != 0) { + PMove.pm.watertype = cont; + PMove.pm.waterlevel = 1; + point[2] = PMove.pml.origin[2] + PMove.pm.mins[2] + sample1; + cont = PMove.pm.pointcontents.pointcontents(point); + if ((cont & Defines.MASK_WATER) != 0) { + PMove.pm.waterlevel = 2; + point[2] = PMove.pml.origin[2] + PMove.pm.mins[2] + sample2; + cont = PMove.pm.pointcontents.pointcontents(point); + if ((cont & Defines.MASK_WATER) != 0) + PMove.pm.waterlevel = 3; + } + } + + } + + /* + * ============= PM_CheckJump ============= + */ + public static void PM_CheckJump() { + if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_LAND) != 0) { + // hasn't been long enough since landing to jump again + return; + } + + if (PMove.pm.cmd.upmove < 10) { // not holding jump + PMove.pm.s.pm_flags &= ~pmove_t.PMF_JUMP_HELD; + return; + } + + // must wait for jump to be released + if ((PMove.pm.s.pm_flags & pmove_t.PMF_JUMP_HELD) != 0) + return; + + if (PMove.pm.s.pm_type == Defines.PM_DEAD) + return; + + if (PMove.pm.waterlevel >= 2) { // swimming, not jumping + PMove.pm.groundentity = null; + + if (PMove.pml.velocity[2] <= -300) + return; + + if (PMove.pm.watertype == Defines.CONTENTS_WATER) + PMove.pml.velocity[2] = 100; + else if (PMove.pm.watertype == Defines.CONTENTS_SLIME) + PMove.pml.velocity[2] = 80; + else + PMove.pml.velocity[2] = 50; + return; + } + + if (PMove.pm.groundentity == null) + return; // in air, so no effect + + PMove.pm.s.pm_flags |= pmove_t.PMF_JUMP_HELD; + + PMove.pm.groundentity = null; + PMove.pml.velocity[2] += 270; + if (PMove.pml.velocity[2] < 270) + PMove.pml.velocity[2] = 270; + } + + /* + * ============= PM_CheckSpecialMovement ============= + */ + public static void PM_CheckSpecialMovement() { + float[] spot = { 0, 0, 0 }; + int cont; + float[] flatforward = { 0, 0, 0 }; + trace_t trace; + + if (PMove.pm.s.pm_time != 0) + return; + + PMove.pml.ladder = false; + + // check for ladder + flatforward[0] = PMove.pml.forward[0]; + flatforward[1] = PMove.pml.forward[1]; + flatforward[2] = 0; + Math3D.VectorNormalize(flatforward); + + Math3D.VectorMA(PMove.pml.origin, 1, flatforward, spot); + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, spot); + if ((trace.fraction < 1) + && (trace.contents & Defines.CONTENTS_LADDER) != 0) + PMove.pml.ladder = true; + + // check for water jump + if (PMove.pm.waterlevel != 2) + return; + + Math3D.VectorMA(PMove.pml.origin, 30, flatforward, spot); + spot[2] += 4; + cont = PMove.pm.pointcontents.pointcontents(spot); + if (0 == (cont & Defines.CONTENTS_SOLID)) + return; + + spot[2] += 16; + cont = PMove.pm.pointcontents.pointcontents(spot); + if (cont != 0) + return; + // jump out of water + Math3D.VectorScale(flatforward, 50, PMove.pml.velocity); + PMove.pml.velocity[2] = 350; + + PMove.pm.s.pm_flags |= pmove_t.PMF_TIME_WATERJUMP; + PMove.pm.s.pm_time = -1; // was 255 + } + + /* + * =============== PM_FlyMove =============== + */ + public static void PM_FlyMove(boolean doclip) { + float speed, drop, friction, control, newspeed; + float currentspeed, addspeed, accelspeed; + int i; + float[] wishvel = { 0, 0, 0 }; + float fmove, smove; + float[] wishdir = { 0, 0, 0 }; + float wishspeed; + float[] end = { 0, 0, 0 }; + trace_t trace; + + PMove.pm.viewheight = 22; + + // friction + + speed = Math3D.VectorLength(PMove.pml.velocity); + if (speed < 1) { + Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity); + } else { + drop = 0; + + friction = PMove.pm_friction * 1.5f; // extra friction + control = speed < PMove.pm_stopspeed ? PMove.pm_stopspeed : speed; + drop += control * friction * PMove.pml.frametime; + + // scale the velocity + newspeed = speed - drop; + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + Math3D + .VectorScale(PMove.pml.velocity, newspeed, + PMove.pml.velocity); + } + + // accelerate + fmove = PMove.pm.cmd.forwardmove; + smove = PMove.pm.cmd.sidemove; + + Math3D.VectorNormalize(PMove.pml.forward); + Math3D.VectorNormalize(PMove.pml.right); + + for (i = 0; i < 3; i++) + wishvel[i] = PMove.pml.forward[i] * fmove + PMove.pml.right[i] + * smove; + wishvel[2] += PMove.pm.cmd.upmove; + + Math3D.VectorCopy(wishvel, wishdir); + wishspeed = Math3D.VectorNormalize(wishdir); + + // + // clamp to server defined max speed + // + if (wishspeed > PMove.pm_maxspeed) { + Math3D.VectorScale(wishvel, PMove.pm_maxspeed / wishspeed, wishvel); + wishspeed = PMove.pm_maxspeed; + } + + currentspeed = Math3D.DotProduct(PMove.pml.velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = PMove.pm_accelerate * PMove.pml.frametime * wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i = 0; i < 3; i++) + PMove.pml.velocity[i] += accelspeed * wishdir[i]; + + if (doclip) { + for (i = 0; i < 3; i++) + end[i] = PMove.pml.origin[i] + PMove.pml.frametime + * PMove.pml.velocity[i]; + + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, end); + + Math3D.VectorCopy(trace.endpos, PMove.pml.origin); + } else { + // move + Math3D.VectorMA(PMove.pml.origin, PMove.pml.frametime, + PMove.pml.velocity, PMove.pml.origin); + } + } + + /* + * ============== PM_CheckDuck + * + * Sets mins, maxs, and pm.viewheight ============== + */ + public static void PM_CheckDuck() { + trace_t trace; + + PMove.pm.mins[0] = -16; + PMove.pm.mins[1] = -16; + + PMove.pm.maxs[0] = 16; + PMove.pm.maxs[1] = 16; + + if (PMove.pm.s.pm_type == Defines.PM_GIB) { + PMove.pm.mins[2] = 0; + PMove.pm.maxs[2] = 16; + PMove.pm.viewheight = 8; + return; + } + + PMove.pm.mins[2] = -24; + + if (PMove.pm.s.pm_type == Defines.PM_DEAD) { + PMove.pm.s.pm_flags |= pmove_t.PMF_DUCKED; + } else if (PMove.pm.cmd.upmove < 0 + && (PMove.pm.s.pm_flags & pmove_t.PMF_ON_GROUND) != 0) { // duck + PMove.pm.s.pm_flags |= pmove_t.PMF_DUCKED; + } else { // stand up if possible + if ((PMove.pm.s.pm_flags & pmove_t.PMF_DUCKED) != 0) { + // try to stand up + PMove.pm.maxs[2] = 32; + trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins, + PMove.pm.maxs, PMove.pml.origin); + if (!trace.allsolid) + PMove.pm.s.pm_flags &= ~pmove_t.PMF_DUCKED; + } + } + + if ((PMove.pm.s.pm_flags & pmove_t.PMF_DUCKED) != 0) { + PMove.pm.maxs[2] = 4; + PMove.pm.viewheight = -2; + } else { + PMove.pm.maxs[2] = 32; + PMove.pm.viewheight = 22; + } + } + + /* + * ============== PM_DeadMove ============== + */ + public static void PM_DeadMove() { + float forward; + + if (null == PMove.pm.groundentity) + return; + + // extra friction + + forward = Math3D.VectorLength(PMove.pml.velocity); + forward -= 20; + if (forward <= 0) { + Math3D.VectorClear(PMove.pml.velocity); + } else { + Math3D.VectorNormalize(PMove.pml.velocity); + Math3D.VectorScale(PMove.pml.velocity, forward, PMove.pml.velocity); + } + } + + public static boolean PM_GoodPosition() { + trace_t trace; + float[] origin = { 0, 0, 0 }, end = { 0, 0, 0 }; + int i; + + if (PMove.pm.s.pm_type == Defines.PM_SPECTATOR) + return true; + + for (i = 0; i < 3; i++) + origin[i] = end[i] = PMove.pm.s.origin[i] * 0.125f; + trace = PMove.pm.trace.trace(origin, PMove.pm.mins, PMove.pm.maxs, end); + + return !trace.allsolid; + } + + public static void PM_SnapPosition() { + int sign[] = { 0, 0, 0 }; + int i, j, bits; + short base[] = { 0, 0, 0 }; + + // snap velocity to eigths + for (i = 0; i < 3; i++) + PMove.pm.s.velocity[i] = (short) (PMove.pml.velocity[i] * 8); + + for (i = 0; i < 3; i++) { + if (PMove.pml.origin[i] >= 0) + sign[i] = 1; + else + sign[i] = -1; + PMove.pm.s.origin[i] = (short) (PMove.pml.origin[i] * 8); + if (PMove.pm.s.origin[i] * 0.125 == PMove.pml.origin[i]) + sign[i] = 0; + } + Math3D.VectorCopy(PMove.pm.s.origin, base); + + // try all combinations + for (j = 0; j < 8; j++) { + bits = jitterbits[j]; + Math3D.VectorCopy(base, PMove.pm.s.origin); + for (i = 0; i < 3; i++) + if ((bits & (1 << i)) != 0) + PMove.pm.s.origin[i] += sign[i]; + + if (PMove.PM_GoodPosition()) + return; + } + + // go back to the last position + Math3D.VectorCopy(PMove.pml.previous_origin, PMove.pm.s.origin); + // Com_DPrintf ("using previous_origin\n"); + } + + public static void PM_InitialSnapPosition() { + int x, y, z; + short base[] = { 0, 0, 0 }; + + Math3D.VectorCopy(PMove.pm.s.origin, base); + + for (z = 0; z < 3; z++) { + PMove.pm.s.origin[2] = (short) (base[2] + offset[z]); + for (y = 0; y < 3; y++) { + PMove.pm.s.origin[1] = (short) (base[1] + offset[y]); + for (x = 0; x < 3; x++) { + PMove.pm.s.origin[0] = (short) (base[0] + offset[x]); + if (PMove.PM_GoodPosition()) { + PMove.pml.origin[0] = PMove.pm.s.origin[0] * 0.125f; + PMove.pml.origin[1] = PMove.pm.s.origin[1] * 0.125f; + PMove.pml.origin[2] = PMove.pm.s.origin[2] * 0.125f; + Math3D.VectorCopy(PMove.pm.s.origin, + PMove.pml.previous_origin); + return; + } + } + } + } + + Com.DPrintf("Bad InitialSnapPosition\n"); + } + + /* + * ================ PM_ClampAngles + * + * ================ + */ + public static void PM_ClampAngles() { + short temp; + int i; + + if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_TELEPORT) != 0) { + PMove.pm.viewangles[Defines.YAW] = Math3D + .SHORT2ANGLE(PMove.pm.cmd.angles[Defines.YAW] + + PMove.pm.s.delta_angles[Defines.YAW]); + PMove.pm.viewangles[Defines.PITCH] = 0; + PMove.pm.viewangles[Defines.ROLL] = 0; + } else { + // circularly clamp the angles with deltas + for (i = 0; i < 3; i++) { + temp = (short) (PMove.pm.cmd.angles[i] + PMove.pm.s.delta_angles[i]); + PMove.pm.viewangles[i] = Math3D.SHORT2ANGLE(temp); + } + + // don't let the player look up or down more than 90 degrees + if (PMove.pm.viewangles[Defines.PITCH] > 89 + && PMove.pm.viewangles[Defines.PITCH] < 180) + PMove.pm.viewangles[Defines.PITCH] = 89; + else if (PMove.pm.viewangles[Defines.PITCH] < 271 + && PMove.pm.viewangles[Defines.PITCH] >= 180) + PMove.pm.viewangles[Defines.PITCH] = 271; + } + Math3D.AngleVectors(PMove.pm.viewangles, PMove.pml.forward, + PMove.pml.right, PMove.pml.up); + } + + /* + * ================ Pmove + * + * Can be called by either the server or the client ================ + */ + public static void Pmove(pmove_t pmove) { + PMove.pm = pmove; + + // clear results + PMove.pm.numtouch = 0; + Math3D.VectorClear(PMove.pm.viewangles); + PMove.pm.viewheight = 0; + PMove.pm.groundentity = null; + PMove.pm.watertype = 0; + PMove.pm.waterlevel = 0; + + // clear all pmove local vars + PMove.pml = new PMove.pml_t(); + + // convert origin and velocity to float values + PMove.pml.origin[0] = PMove.pm.s.origin[0] * 0.125f; + PMove.pml.origin[1] = PMove.pm.s.origin[1] * 0.125f; + PMove.pml.origin[2] = PMove.pm.s.origin[2] * 0.125f; + + PMove.pml.velocity[0] = PMove.pm.s.velocity[0] * 0.125f; + PMove.pml.velocity[1] = PMove.pm.s.velocity[1] * 0.125f; + PMove.pml.velocity[2] = PMove.pm.s.velocity[2] * 0.125f; + + // save old org in case we get stuck + Math3D.VectorCopy(PMove.pm.s.origin, PMove.pml.previous_origin); + + PMove.pml.frametime = (PMove.pm.cmd.msec & 0xFF) * 0.001f; + + PM_ClampAngles(); + + if (PMove.pm.s.pm_type == Defines.PM_SPECTATOR) { + PMove.PM_FlyMove(false); + PM_SnapPosition(); + return; + } + + if (PMove.pm.s.pm_type >= Defines.PM_DEAD) { + PMove.pm.cmd.forwardmove = 0; + PMove.pm.cmd.sidemove = 0; + PMove.pm.cmd.upmove = 0; + } + + if (PMove.pm.s.pm_type == Defines.PM_FREEZE) + return; // no movement at all + + // set mins, maxs, and viewheight + PMove.PM_CheckDuck(); + + if (PMove.pm.snapinitial) + PM_InitialSnapPosition(); + + // set groundentity, watertype, and waterlevel + PMove.PM_CatagorizePosition(); + + if (PMove.pm.s.pm_type == Defines.PM_DEAD) + PMove.PM_DeadMove(); + + PMove.PM_CheckSpecialMovement(); + + // drop timing counter + if (PMove.pm.s.pm_time != 0) { + int msec; + + // TOD o bugfix cwei + msec = PMove.pm.cmd.msec >>> 3; + if (msec == 0) + msec = 1; + if (msec >= (PMove.pm.s.pm_time & 0xFF)) { + PMove.pm.s.pm_flags &= ~(pmove_t.PMF_TIME_WATERJUMP + | pmove_t.PMF_TIME_LAND | pmove_t.PMF_TIME_TELEPORT); + PMove.pm.s.pm_time = 0; + } else + PMove.pm.s.pm_time = (byte) ((PMove.pm.s.pm_time & 0xFF) - msec); + } + + if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_TELEPORT) != 0) { // teleport + // pause + // stays + // exactly + // in + // place + } else if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_WATERJUMP) != 0) { // waterjump + // has + // no + // control, + // but + // falls + PMove.pml.velocity[2] -= PMove.pm.s.gravity * PMove.pml.frametime; + if (PMove.pml.velocity[2] < 0) { // cancel as soon as we are falling + // down again + PMove.pm.s.pm_flags &= ~(pmove_t.PMF_TIME_WATERJUMP + | pmove_t.PMF_TIME_LAND | pmove_t.PMF_TIME_TELEPORT); + PMove.pm.s.pm_time = 0; + } + + PMove.PM_StepSlideMove(); + } else { + PMove.PM_CheckJump(); + + PMove.PM_Friction(); + + if (PMove.pm.waterlevel >= 2) + PMove.PM_WaterMove(); + else { + float[] angles = { 0, 0, 0 }; + + Math3D.VectorCopy(PMove.pm.viewangles, angles); + if (angles[Defines.PITCH] > 180) + angles[Defines.PITCH] = angles[Defines.PITCH] - 360; + angles[Defines.PITCH] /= 3; + + Math3D.AngleVectors(angles, PMove.pml.forward, PMove.pml.right, + PMove.pml.up); + + PMove.PM_AirMove(); + } + } + + // set groundentity, watertype, and waterlevel for final spot + PMove.PM_CatagorizePosition(); + + PM_SnapPosition(); + } +} \ No newline at end of file diff --git a/src/jake2/qcommon/Q2DataDialog.java b/src/jake2/qcommon/Q2DataDialog.java index cb7dc62..d139000 100644 --- a/src/jake2/qcommon/Q2DataDialog.java +++ b/src/jake2/qcommon/Q2DataDialog.java @@ -1,427 +1,427 @@ -/* - * Q2DataDialog.java - * - * Created on 17. September 2004, 20:13 - */ - -package jake2.qcommon; - -import java.awt.*; -import java.io.*; -import java.net.URL; -import java.net.URLConnection; -import java.util.Enumeration; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import javax.swing.*; - -/** - * - * @author hoz - */ -public class Q2DataDialog extends javax.swing.JDialog { - - /** Creates new form Q2DataDialog */ - public Q2DataDialog() { - super(); - initComponents(); - - DisplayMode mode = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode(); - int x = (mode.getWidth() - getWidth()) / 2; - int y = (mode.getHeight() - getHeight()) / 2; - setLocation(x, y); - dir = System.getProperty("user.home") + "/jake2"; - jTextField1.setText(dir); - } - - /** This method is called from within the constructor to - * initialize the form. - * WARNING: Do NOT modify this code. The content of this method is - * always regenerated by the Form Editor. - */ - private void initComponents() {//GEN-BEGIN:initComponents - java.awt.GridBagConstraints gridBagConstraints; - - choosePanel = new javax.swing.JPanel(); - statusPanel = new JPanel(); - status = new JLabel("initializing Jake2..."); - jTextField1 = new javax.swing.JTextField(); - changeButton = new javax.swing.JButton(); - installButton = new javax.swing.JButton(); - exitButton = new javax.swing.JButton(); - okButton = new javax.swing.JButton(); - - setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); - setTitle("Jake2 - Bytonic Software"); - - setResizable(false); - addWindowListener(new java.awt.event.WindowAdapter() { - public void windowClosing(java.awt.event.WindowEvent evt) { - formWindowClosing(evt); - } - }); - - choosePanel.setLayout(new java.awt.GridBagLayout()); - - choosePanel.setMaximumSize(new java.awt.Dimension(400, 100)); - choosePanel.setMinimumSize(new java.awt.Dimension(400, 100)); - choosePanel.setPreferredSize(new java.awt.Dimension(400, 100)); - jTextField1.setPreferredSize(null); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - gridBagConstraints.gridwidth = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); - gridBagConstraints.weightx = 1.0; - choosePanel.add(jTextField1, gridBagConstraints); - - changeButton.setText("change"); - changeButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - changeButtonActionPerformed(evt); - } - }); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 2; - gridBagConstraints.gridy = 0; - gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); - gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; - choosePanel.add(changeButton, gridBagConstraints); - - installButton.setText("Install"); - installButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - installButtonActionPerformed(evt); - } - }); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; - gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - choosePanel.add(installButton, gridBagConstraints); - - exitButton.setText("Exit"); - exitButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - exitButtonActionPerformed(evt); - } - }); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 1; - gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); - choosePanel.add(exitButton, gridBagConstraints); - - okButton.setText("OK"); - okButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - okButtonActionPerformed(evt); - } - }); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 2; - gridBagConstraints.gridy = 1; - gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); - gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; - choosePanel.add(okButton, gridBagConstraints); - - //getContentPane().add(choosePanel, java.awt.BorderLayout.SOUTH); - - Jake2Canvas c = new Jake2Canvas(); - getContentPane().add(c, BorderLayout.CENTER); - - statusPanel.setLayout(new java.awt.GridBagLayout()); - statusPanel.setMaximumSize(new java.awt.Dimension(400, 100)); - statusPanel.setMinimumSize(new java.awt.Dimension(400, 100)); - statusPanel.setPreferredSize(new java.awt.Dimension(400, 100)); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - gridBagConstraints.gridwidth = 1; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); - gridBagConstraints.weightx = 1.0; - statusPanel.add(status, gridBagConstraints); - getContentPane().add(statusPanel, java.awt.BorderLayout.SOUTH); - - installPanel = new InstallPanel(this); - - pack(); - }//GEN-END:initComponents - - - private void installButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_installButtonActionPerformed - dir = jTextField1.getText(); - showInstallPanel(); - installPanel.destDir = dir; - - dir += "/baseq2"; - jTextField1.setText(dir); - - new Thread(installPanel).start(); - }//GEN-LAST:event_installButtonActionPerformed - - private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed - System.exit(1); - dispose(); - }//GEN-LAST:event_exitButtonActionPerformed - - private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - - dir = jTextField1.getText(); - Cvar.Set("cddir", dir); - FS.setCDDir(); - - synchronized(this) { - notifyAll(); - } - }//GEN-LAST:event_okButtonActionPerformed - - private void changeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changeButtonActionPerformed - JFileChooser chooser = new JFileChooser(); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - chooser.setDialogType(JFileChooser.CUSTOM_DIALOG); - chooser.setMultiSelectionEnabled(false); - chooser.setDialogTitle("choose a valid baseq2 directory"); - chooser.showDialog(this, "OK"); - - dir = null; - try { - dir = chooser.getSelectedFile().getCanonicalPath(); - } catch (IOException e) {} - jTextField1.setText(dir); - - }//GEN-LAST:event_changeButtonActionPerformed - - private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing - System.exit(1); - dispose(); - }//GEN-LAST:event_formWindowClosing - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton changeButton; - private javax.swing.JButton exitButton; - private javax.swing.JButton installButton; - private Jake2Canvas canvas; - private javax.swing.JPanel choosePanel; - private JPanel statusPanel; - private InstallPanel installPanel; - private JLabel status; - private javax.swing.JTextField jTextField1; - private javax.swing.JButton okButton; - // End of variables declaration//GEN-END:variables - - private String dir; - - void showChooseDialog() { - getContentPane().remove(statusPanel); - getContentPane().remove(installPanel); - getContentPane().add(choosePanel, BorderLayout.SOUTH); - validate(); - repaint(); - } - - void showStatus() { - getContentPane().remove(choosePanel); - getContentPane().add(statusPanel, BorderLayout.SOUTH); - validate(); - repaint(); - } - - void showInstallPanel() { - getContentPane().remove(choosePanel); - getContentPane().add(installPanel, BorderLayout.SOUTH); - validate(); - repaint(); - } - - void setStatus(String text) { - status.setText(text); - } - - void testQ2Data() { - while (FS.LoadFile("pics/colormap.pcx") == null) { - showChooseDialog(); - - try { - synchronized(this) { - wait(); - } - } catch (InterruptedException e) {} - } - showStatus(); - repaint(); - } - - static class Jake2Canvas extends Canvas { - private Image image; - Jake2Canvas() { - setSize(400, 200); - image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/splash.png")); - while (!Toolkit.getDefaultToolkit().prepareImage(image, -1, -1, null)) { - try { - Thread.sleep(50); - } catch (InterruptedException e) {} - } - } - - - /* (non-Javadoc) - * @see java.awt.Component#paint(java.awt.Graphics) - */ - public void paint(Graphics g) { - g.drawImage(image, 0, 0, null); - } - - } - - static class InstallPanel extends JPanel implements Runnable { - - static final String[] locs = { - "ftp://ftp.fu-berlin.de/pc/msdos/games/idgames/idstuff/quake2/q2-314-demo-x86.exe", - "ftp://ftp.demon.co.uk/pub/mirrors/idsoftware/quake2/q2-314-demo-x86.exe", - "ftp://ftp.fragzone.se/pub/spel/quake2/q2-314-demo-x86.exe", - "ftp://ftp.idsoftware.com/idstuff/quake2/q2-314-demo-x86.exe" }; - static byte[] buf = new byte[8192]; - String destDir; - - JProgressBar progress = new JProgressBar(); - JLabel label = new JLabel("test"); - Q2DataDialog parent; - - public InstallPanel(Q2DataDialog d) { - initComponents(); - parent = d; - } - - void initComponents() { - progress.setMinimum(0); - progress.setMaximum(100); - setLayout(new GridBagLayout()); - GridBagConstraints gridBagConstraints = new GridBagConstraints(); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - gridBagConstraints.gridwidth = 1; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); - gridBagConstraints.weightx = 1.0; - gridBagConstraints.anchor = GridBagConstraints.SOUTH; - add(label, gridBagConstraints); - gridBagConstraints.gridy = 1; - gridBagConstraints.anchor = GridBagConstraints.NORTH; - add(progress, gridBagConstraints); - Dimension d = new Dimension(400, 100); - setMinimumSize(d); - setMaximumSize(d); - setPreferredSize(d); - } - - public void run() { - - InputStream in = null; - OutputStream out = null; - File outFile = null; - - label.setText("downloading..."); - - File dir = null; - try { - dir = new File(destDir); - dir.mkdirs(); - } - catch (Exception e) {} - try { - if (!dir.isDirectory() || !dir.canWrite()) return; - } - catch (Exception e) { - return; - } - - for (int i = 0; i < locs.length; i++) { - try { - URL url = new URL(locs[i]); - URLConnection conn = url.openConnection(); - int length = conn.getContentLength(); - progress.setMaximum(length / 1024); - - in = conn.getInputStream(); - - outFile = File.createTempFile("Jake2Data", ".zip"); - outFile.deleteOnExit(); - out = new FileOutputStream(outFile); - - copyStream(in, out); - break; - } catch (Exception e) {} - } - try { - installData(outFile.getCanonicalPath()); - } catch (Exception e) {} - - - try { - if (outFile != null) outFile.delete(); - } catch (Exception e) {} - - parent.showChooseDialog(); - parent.okButtonActionPerformed(null); - } - - - void installData(String filename) { - try { - ZipFile f = new ZipFile(filename); - Enumeration e = f.entries(); - while (e.hasMoreElements()) { - ZipEntry entry = (ZipEntry)e.nextElement(); - String name = entry.getName(); - int i; - if ((i = name.indexOf("/baseq2")) > -1 && name.indexOf(".dll") == -1) { - name = destDir + name.substring(i); - File outFile = new File(name); - if (entry.isDirectory()) { - outFile.mkdirs(); - } else { - label.setText("installing " + outFile.getName()); - progress.setMaximum((int)entry.getSize()/1024); - progress.setValue(0); - outFile.getParentFile().mkdirs(); - OutputStream out = new FileOutputStream(outFile); - InputStream in = f.getInputStream(entry); - copyStream(in, out); - } - } - } - } catch (Exception e) {} - } - - void copyStream(InputStream in, OutputStream out) { - try { - int c = 0; - int l; - while ((l = in.read(buf)) > 0) { - out.write(buf, 0, l); - c += l; - progress.setValue(c / 1024); - } - } catch (Exception e) {} - - try { - in.close(); - } catch (Exception e) {} - try { - out.close(); - } catch (Exception e) {} - } - } - -} +/* + * Q2DataDialog.java + * + * Created on 17. September 2004, 20:13 + */ + +package jake2.qcommon; + +import java.awt.*; +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import javax.swing.*; + +/** + * + * @author hoz + */ +public class Q2DataDialog extends javax.swing.JDialog { + + /** Creates new form Q2DataDialog */ + public Q2DataDialog() { + super(); + initComponents(); + + DisplayMode mode = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode(); + int x = (mode.getWidth() - getWidth()) / 2; + int y = (mode.getHeight() - getHeight()) / 2; + setLocation(x, y); + dir = System.getProperty("user.home") + "/jake2"; + jTextField1.setText(dir); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + private void initComponents() {//GEN-BEGIN:initComponents + java.awt.GridBagConstraints gridBagConstraints; + + choosePanel = new javax.swing.JPanel(); + statusPanel = new JPanel(); + status = new JLabel("initializing Jake2..."); + jTextField1 = new javax.swing.JTextField(); + changeButton = new javax.swing.JButton(); + installButton = new javax.swing.JButton(); + exitButton = new javax.swing.JButton(); + okButton = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); + setTitle("Jake2 - Bytonic Software"); + + setResizable(false); + addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent evt) { + formWindowClosing(evt); + } + }); + + choosePanel.setLayout(new java.awt.GridBagLayout()); + + choosePanel.setMaximumSize(new java.awt.Dimension(400, 100)); + choosePanel.setMinimumSize(new java.awt.Dimension(400, 100)); + choosePanel.setPreferredSize(new java.awt.Dimension(400, 100)); + jTextField1.setPreferredSize(null); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.weightx = 1.0; + choosePanel.add(jTextField1, gridBagConstraints); + + changeButton.setText("change"); + changeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + changeButtonActionPerformed(evt); + } + }); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 0; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; + choosePanel.add(changeButton, gridBagConstraints); + + installButton.setText("Install"); + installButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + installButtonActionPerformed(evt); + } + }); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + choosePanel.add(installButton, gridBagConstraints); + + exitButton.setText("Exit"); + exitButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + exitButtonActionPerformed(evt); + } + }); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 1; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + choosePanel.add(exitButton, gridBagConstraints); + + okButton.setText("OK"); + okButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 1; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; + choosePanel.add(okButton, gridBagConstraints); + + //getContentPane().add(choosePanel, java.awt.BorderLayout.SOUTH); + + Jake2Canvas c = new Jake2Canvas(); + getContentPane().add(c, BorderLayout.CENTER); + + statusPanel.setLayout(new java.awt.GridBagLayout()); + statusPanel.setMaximumSize(new java.awt.Dimension(400, 100)); + statusPanel.setMinimumSize(new java.awt.Dimension(400, 100)); + statusPanel.setPreferredSize(new java.awt.Dimension(400, 100)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.weightx = 1.0; + statusPanel.add(status, gridBagConstraints); + getContentPane().add(statusPanel, java.awt.BorderLayout.SOUTH); + + installPanel = new InstallPanel(this); + + pack(); + }//GEN-END:initComponents + + + private void installButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_installButtonActionPerformed + dir = jTextField1.getText(); + showInstallPanel(); + installPanel.destDir = dir; + + dir += "/baseq2"; + jTextField1.setText(dir); + + new Thread(installPanel).start(); + }//GEN-LAST:event_installButtonActionPerformed + + private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed + System.exit(1); + dispose(); + }//GEN-LAST:event_exitButtonActionPerformed + + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed + + dir = jTextField1.getText(); + Cvar.Set("cddir", dir); + FS.setCDDir(); + + synchronized(this) { + notifyAll(); + } + }//GEN-LAST:event_okButtonActionPerformed + + private void changeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changeButtonActionPerformed + JFileChooser chooser = new JFileChooser(); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setDialogType(JFileChooser.CUSTOM_DIALOG); + chooser.setMultiSelectionEnabled(false); + chooser.setDialogTitle("choose a valid baseq2 directory"); + chooser.showDialog(this, "OK"); + + dir = null; + try { + dir = chooser.getSelectedFile().getCanonicalPath(); + } catch (IOException e) {} + jTextField1.setText(dir); + + }//GEN-LAST:event_changeButtonActionPerformed + + private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing + System.exit(1); + dispose(); + }//GEN-LAST:event_formWindowClosing + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton changeButton; + private javax.swing.JButton exitButton; + private javax.swing.JButton installButton; + private Jake2Canvas canvas; + private javax.swing.JPanel choosePanel; + private JPanel statusPanel; + private InstallPanel installPanel; + private JLabel status; + private javax.swing.JTextField jTextField1; + private javax.swing.JButton okButton; + // End of variables declaration//GEN-END:variables + + private String dir; + + void showChooseDialog() { + getContentPane().remove(statusPanel); + getContentPane().remove(installPanel); + getContentPane().add(choosePanel, BorderLayout.SOUTH); + validate(); + repaint(); + } + + void showStatus() { + getContentPane().remove(choosePanel); + getContentPane().add(statusPanel, BorderLayout.SOUTH); + validate(); + repaint(); + } + + void showInstallPanel() { + getContentPane().remove(choosePanel); + getContentPane().add(installPanel, BorderLayout.SOUTH); + validate(); + repaint(); + } + + void setStatus(String text) { + status.setText(text); + } + + void testQ2Data() { + while (FS.LoadFile("pics/colormap.pcx") == null) { + showChooseDialog(); + + try { + synchronized(this) { + wait(); + } + } catch (InterruptedException e) {} + } + showStatus(); + repaint(); + } + + static class Jake2Canvas extends Canvas { + private Image image; + Jake2Canvas() { + setSize(400, 200); + image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/splash.png")); + while (!Toolkit.getDefaultToolkit().prepareImage(image, -1, -1, null)) { + try { + Thread.sleep(50); + } catch (InterruptedException e) {} + } + } + + + /* (non-Javadoc) + * @see java.awt.Component#paint(java.awt.Graphics) + */ + public void paint(Graphics g) { + g.drawImage(image, 0, 0, null); + } + + } + + static class InstallPanel extends JPanel implements Runnable { + + static final String[] locs = { + "ftp://ftp.fu-berlin.de/pc/msdos/games/idgames/idstuff/quake2/q2-314-demo-x86.exe", + "ftp://ftp.demon.co.uk/pub/mirrors/idsoftware/quake2/q2-314-demo-x86.exe", + "ftp://ftp.fragzone.se/pub/spel/quake2/q2-314-demo-x86.exe", + "ftp://ftp.idsoftware.com/idstuff/quake2/q2-314-demo-x86.exe" }; + static byte[] buf = new byte[8192]; + String destDir; + + JProgressBar progress = new JProgressBar(); + JLabel label = new JLabel("test"); + Q2DataDialog parent; + + public InstallPanel(Q2DataDialog d) { + initComponents(); + parent = d; + } + + void initComponents() { + progress.setMinimum(0); + progress.setMaximum(100); + setLayout(new GridBagLayout()); + GridBagConstraints gridBagConstraints = new GridBagConstraints(); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10); + gridBagConstraints.weightx = 1.0; + gridBagConstraints.anchor = GridBagConstraints.SOUTH; + add(label, gridBagConstraints); + gridBagConstraints.gridy = 1; + gridBagConstraints.anchor = GridBagConstraints.NORTH; + add(progress, gridBagConstraints); + Dimension d = new Dimension(400, 100); + setMinimumSize(d); + setMaximumSize(d); + setPreferredSize(d); + } + + public void run() { + + InputStream in = null; + OutputStream out = null; + File outFile = null; + + label.setText("downloading..."); + + File dir = null; + try { + dir = new File(destDir); + dir.mkdirs(); + } + catch (Exception e) {} + try { + if (!dir.isDirectory() || !dir.canWrite()) return; + } + catch (Exception e) { + return; + } + + for (int i = 0; i < locs.length; i++) { + try { + URL url = new URL(locs[i]); + URLConnection conn = url.openConnection(); + int length = conn.getContentLength(); + progress.setMaximum(length / 1024); + + in = conn.getInputStream(); + + outFile = File.createTempFile("Jake2Data", ".zip"); + outFile.deleteOnExit(); + out = new FileOutputStream(outFile); + + copyStream(in, out); + break; + } catch (Exception e) {} + } + try { + installData(outFile.getCanonicalPath()); + } catch (Exception e) {} + + + try { + if (outFile != null) outFile.delete(); + } catch (Exception e) {} + + parent.showChooseDialog(); + parent.okButtonActionPerformed(null); + } + + + void installData(String filename) { + try { + ZipFile f = new ZipFile(filename); + Enumeration e = f.entries(); + while (e.hasMoreElements()) { + ZipEntry entry = (ZipEntry)e.nextElement(); + String name = entry.getName(); + int i; + if ((i = name.indexOf("/baseq2")) > -1 && name.indexOf(".dll") == -1) { + name = destDir + name.substring(i); + File outFile = new File(name); + if (entry.isDirectory()) { + outFile.mkdirs(); + } else { + label.setText("installing " + outFile.getName()); + progress.setMaximum((int)entry.getSize()/1024); + progress.setValue(0); + outFile.getParentFile().mkdirs(); + OutputStream out = new FileOutputStream(outFile); + InputStream in = f.getInputStream(entry); + copyStream(in, out); + } + } + } + } catch (Exception e) {} + } + + void copyStream(InputStream in, OutputStream out) { + try { + int c = 0; + int l; + while ((l = in.read(buf)) > 0) { + out.write(buf, 0, l); + c += l; + progress.setValue(c / 1024); + } + } catch (Exception e) {} + + try { + in.close(); + } catch (Exception e) {} + try { + out.close(); + } catch (Exception e) {} + } + } + +} diff --git a/src/jake2/qcommon/netchan_t.java b/src/jake2/qcommon/netchan_t.java index 06a283a..77022d6 100644 --- a/src/jake2/qcommon/netchan_t.java +++ b/src/jake2/qcommon/netchan_t.java @@ -1,79 +1,87 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 27.11.2003 by RST. +// $Id: netchan_t.java,v 1.2 2004-09-22 19:22:09 salomo Exp $ +package jake2.qcommon; -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. +import jake2.*; -See the GNU General Public License for more details. +public class netchan_t { -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. + public boolean fatal_error; -*/ + // was enum {NS_CLIENT, NS_SERVER} + public int sock; -// Created on 27.11.2003 by RST. -// $Id: netchan_t.java,v 1.1 2004-07-07 19:59:34 hzi Exp $ + public int dropped; // between last packet and previous -package jake2.qcommon; + public int last_received; // for timeouts -import jake2.*; + public int last_sent; // for retransmits -public class netchan_t { + public netadr_t remote_address = new netadr_t(); + + public int qport; // qport value to write when transmitting + + // sequencing variables + public int incoming_sequence; + + public int incoming_acknowledged; + + public int incoming_reliable_acknowledged; // single bit + public int incoming_reliable_sequence; // single bit, maintained local - public boolean fatal_error; + public int outgoing_sequence; - // was enum {NS_CLIENT, NS_SERVER} - public int sock; + public int reliable_sequence; // single bit - public int dropped; // between last packet and previous + public int last_reliable_sequence; // sequence number of last send - public int last_received; // for timeouts - public int last_sent; // for retransmits + // reliable staging and holding areas + public sizebuf_t message = new sizebuf_t(); // writing buffer to send to + // server - public netadr_t remote_address = new netadr_t(); - public int qport; // qport value to write when transmitting + public byte message_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // leave + // space for + // header - // sequencing variables - public int incoming_sequence; - public int incoming_acknowledged; - public int incoming_reliable_acknowledged; // single bit + // message is copied to this buffer when it is first transfered + public int reliable_length; - public int incoming_reliable_sequence; // single bit, maintained local + public byte reliable_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // unpcked + // reliable + // message - public int outgoing_sequence; - public int reliable_sequence; // single bit - public int last_reliable_sequence; // sequence number of last send + //ok. + public void clear() { + sock = dropped = last_received = last_sent = 0; + remote_address = new netadr_t(); + qport = incoming_sequence = incoming_acknowledged = incoming_reliable_acknowledged = incoming_reliable_sequence = outgoing_sequence = reliable_sequence = last_reliable_sequence = 0; + message = new sizebuf_t(); - // reliable staging and holding areas - public sizebuf_t message = new sizebuf_t(); // writing buffer to send to server - public byte message_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // leave space for header + message_buf = new byte[Defines.MAX_MSGLEN - 16]; - // message is copied to this buffer when it is first transfered - int reliable_length; - - byte reliable_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // unpcked reliable message + reliable_length = 0; + reliable_buf = new byte[Defines.MAX_MSGLEN - 16]; + } - //ok. - public void clear() - { - sock=dropped=last_received=last_sent=0; - remote_address = new netadr_t(); - qport = incoming_sequence = incoming_acknowledged = incoming_reliable_acknowledged = incoming_reliable_sequence - = outgoing_sequence = reliable_sequence = last_reliable_sequence =0; - message = new sizebuf_t(); - - message_buf = new byte[Defines.MAX_MSGLEN - 16]; - - reliable_length =0; - reliable_buf = new byte[Defines.MAX_MSGLEN - 16]; - } - -} +} \ No newline at end of file diff --git a/src/jake2/render/fastjogl/Image.java b/src/jake2/render/fastjogl/Image.java index 22f3d02..3fd97c0 100644 --- a/src/jake2/render/fastjogl/Image.java +++ b/src/jake2/render/fastjogl/Image.java @@ -2,34 +2,36 @@ * Image.java * Copyright (C) 2003 * - * $Id: Image.java,v 1.5 2004-07-19 19:39:57 hzi Exp $ + * $Id: Image.java,v 1.6 2004-09-22 19:22:10 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.render.fastjogl; import jake2.Defines; import jake2.client.VID; import jake2.client.particle_t; import jake2.game.cvar_t; -import jake2.qcommon.*; +import jake2.qcommon.Com; +import jake2.qcommon.Cvar; +import jake2.qcommon.FS; import jake2.qcommon.longjmpException; import jake2.qcommon.qfiles; import jake2.render.image_t; @@ -40,7 +42,9 @@ import java.awt.Dimension; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; -import java.nio.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; import java.util.Arrays; import net.java.games.jogl.GL; @@ -52,1628 +56,1605 @@ import net.java.games.jogl.GL; */ public abstract class Image extends Main { - image_t draw_chars; - - image_t[] gltextures = new image_t[MAX_GLTEXTURES]; - //Map gltextures = new Hashtable(MAX_GLTEXTURES); // image_t - int numgltextures; - int base_textureid; // gltextures[i] = base_textureid+i - - byte[] intensitytable = new byte[256]; - byte[] gammatable = new byte[256]; - - cvar_t intensity; - - // - // qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky ); - // qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap); - // - - int gl_solid_format = 3; - int gl_alpha_format = 4; - - int gl_tex_solid_format = 3; - int gl_tex_alpha_format = 4; - - int gl_filter_min = GL.GL_LINEAR_MIPMAP_NEAREST; - int gl_filter_max = GL.GL_LINEAR; - - Image() { - // init the texture cache - for (int i = 0; i < gltextures.length; i++) - { - gltextures[i] = new image_t(i); - } - numgltextures = 0; - } - - void GL_SetTexturePalette(int[] palette) { - - assert(palette != null && palette.length == 256) : "int palette[256] bug"; - - int i; - byte[] temptable = new byte[768]; - - if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f) { - for (i = 0; i < 256; i++) { - temptable[i * 3 + 0] = (byte) ((palette[i] >> 0) & 0xff); - temptable[i * 3 + 1] = (byte) ((palette[i] >> 8) & 0xff); - temptable[i * 3 + 2] = (byte) ((palette[i] >> 16) & 0xff); - } - - gl.glColorTableEXT(GL.GL_SHARED_TEXTURE_PALETTE_EXT, GL.GL_RGB, 256, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, temptable); - } - } - - void GL_EnableMultitexture(boolean enable) { - if (enable) { - GL_SelectTexture(GL_TEXTURE1); - gl.glEnable(GL.GL_TEXTURE_2D); - GL_TexEnv(GL.GL_REPLACE); - } - else { - GL_SelectTexture(GL_TEXTURE1); - gl.glDisable(GL.GL_TEXTURE_2D); - GL_TexEnv(GL.GL_REPLACE); - } - GL_SelectTexture(GL_TEXTURE0); - GL_TexEnv(GL.GL_REPLACE); - } - - void GL_SelectTexture(int texture /* GLenum */) { - int tmu; - - tmu = (texture == GL_TEXTURE0) ? 0 : 1; - - if (tmu == gl_state.currenttmu) { - return; - } - - gl_state.currenttmu = tmu; - - gl.glActiveTextureARB(texture); - gl.glClientActiveTextureARB(texture); - } - - int[] lastmodes = { -1, -1 }; - - void GL_TexEnv(int mode /* GLenum */ - ) { - - if (mode != lastmodes[gl_state.currenttmu]) { - gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, mode); - lastmodes[gl_state.currenttmu] = mode; - } - } - - void GL_Bind(int texnum) { - - if ((gl_nobind.value != 0) && (draw_chars != null)) { - // performance evaluation option - texnum = draw_chars.texnum; - } - if (gl_state.currenttextures[gl_state.currenttmu] == texnum) - return; - - gl_state.currenttextures[gl_state.currenttmu] = texnum; - gl.glBindTexture(GL.GL_TEXTURE_2D, texnum); - } - - void GL_MBind(int target /* GLenum */, int texnum) { - GL_SelectTexture(target); - if (target == GL_TEXTURE0) { - if (gl_state.currenttextures[0] == texnum) - return; - } - else { - if (gl_state.currenttextures[1] == texnum) - return; - } - GL_Bind(texnum); - } - - // glmode_t - static class glmode_t { - String name; - int minimize, maximize; - - glmode_t(String name, int minimize, int maximze) { - this.name = name; - this.minimize = minimize; - this.maximize = maximze; - } - } - - static final glmode_t modes[] = - { - new glmode_t("GL_NEAREST", GL.GL_NEAREST, GL.GL_NEAREST), - new glmode_t("GL_LINEAR", GL.GL_LINEAR, GL.GL_LINEAR), - new glmode_t("GL_NEAREST_MIPMAP_NEAREST", GL.GL_NEAREST_MIPMAP_NEAREST, GL.GL_NEAREST), - new glmode_t("GL_LINEAR_MIPMAP_NEAREST", GL.GL_LINEAR_MIPMAP_NEAREST, GL.GL_LINEAR), - new glmode_t("GL_NEAREST_MIPMAP_LINEAR", GL.GL_NEAREST_MIPMAP_LINEAR, GL.GL_NEAREST), - new glmode_t("GL_LINEAR_MIPMAP_LINEAR", GL.GL_LINEAR_MIPMAP_LINEAR, GL.GL_LINEAR)}; - - static final int NUM_GL_MODES = modes.length; - - // gltmode_t - static class gltmode_t { - String name; - int mode; - - gltmode_t(String name, int mode) { - this.name = name; - this.mode = mode; - } - } - - static final gltmode_t[] gl_alpha_modes = - { - new gltmode_t("default", 4), - new gltmode_t("GL_RGBA", GL.GL_RGBA), - new gltmode_t("GL_RGBA8", GL.GL_RGBA8), - new gltmode_t("GL_RGB5_A1", GL.GL_RGB5_A1), - new gltmode_t("GL_RGBA4", GL.GL_RGBA4), - new gltmode_t("GL_RGBA2", GL.GL_RGBA2), - }; - - static final int NUM_GL_ALPHA_MODES = gl_alpha_modes.length; - - static final gltmode_t[] gl_solid_modes = - { - new gltmode_t("default", 3), - new gltmode_t("GL_RGB", GL.GL_RGB), - new gltmode_t("GL_RGB8", GL.GL_RGB8), - new gltmode_t("GL_RGB5", GL.GL_RGB5), - new gltmode_t("GL_RGB4", GL.GL_RGB4), - new gltmode_t("GL_R3_G3_B2", GL.GL_R3_G3_B2), - // #ifdef GL_RGB2_EXT - new gltmode_t("GL_RGB2", GL.GL_RGB2_EXT) - // #endif - }; - - static final int NUM_GL_SOLID_MODES = gl_solid_modes.length; - - /* - =============== - GL_TextureMode - =============== - */ - void GL_TextureMode(String string) { - - int i; - for (i = 0; i < NUM_GL_MODES; i++) { - if (modes[i].name.equalsIgnoreCase(string)) - break; - } - - if (i == NUM_GL_MODES) { - VID.Printf(Defines.PRINT_ALL, "bad filter name: [" + string + "]\n"); - return; - } - - gl_filter_min = modes[i].minimize; - gl_filter_max = modes[i].maximize; - - image_t glt; - // change all the existing mipmap texture objects - for (i = 0; i < numgltextures; i++) { - glt = gltextures[i]; - - if (glt.type != it_pic && glt.type != it_sky) { - GL_Bind(glt.texnum); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, gl_filter_min); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - } - } - - /* - =============== - GL_TextureAlphaMode - =============== - */ - void GL_TextureAlphaMode(String string) { - - int i; - for (i = 0; i < NUM_GL_ALPHA_MODES; i++) { - if (gl_alpha_modes[i].name.equalsIgnoreCase(string)) - break; - } - - if (i == NUM_GL_ALPHA_MODES) { - VID.Printf(Defines.PRINT_ALL, "bad alpha texture mode name: [" + string + "]\n"); - return; - } - - gl_tex_alpha_format = gl_alpha_modes[i].mode; - } - - /* - =============== - GL_TextureSolidMode - =============== - */ - void GL_TextureSolidMode(String string) { - int i; - for (i = 0; i < NUM_GL_SOLID_MODES; i++) { - if (gl_solid_modes[i].name.equalsIgnoreCase(string)) - break; - } - - if (i == NUM_GL_SOLID_MODES) { - VID.Printf(Defines.PRINT_ALL, "bad solid texture mode name: [" + string + "]\n"); - return; - } - - gl_tex_solid_format = gl_solid_modes[i].mode; - } - - /* - =============== - GL_ImageList_f - =============== - */ - void GL_ImageList_f() { - - image_t image; - int texels; - final String[] palstrings = { "RGB", "PAL" }; - - VID.Printf(Defines.PRINT_ALL, "------------------\n"); - texels = 0; - - for (int i = 0; i < numgltextures; i++) { - image = gltextures[i]; - if (image.texnum <= 0) - continue; - - texels += image.upload_width * image.upload_height; - switch (image.type) { - case it_skin : - VID.Printf(Defines.PRINT_ALL, "M"); - break; - case it_sprite : - VID.Printf(Defines.PRINT_ALL, "S"); - break; - case it_wall : - VID.Printf(Defines.PRINT_ALL, "W"); - break; - case it_pic : - VID.Printf(Defines.PRINT_ALL, "P"); - break; - default : - VID.Printf(Defines.PRINT_ALL, " "); - break; - } - - VID.Printf( - Defines.PRINT_ALL, - " %3i %3i %s: %s\n", - new Vargs(4).add(image.upload_width).add(image.upload_height).add(palstrings[(image.paletted) ? 1 : 0]).add( - image.name)); - } - VID.Printf(Defines.PRINT_ALL, "Total texel count (not counting mipmaps): " + texels + '\n'); - } - - /* - ============================================================================= - - scrap allocation - - Allocate all the little status bar objects into a single texture - to crutch up inefficient hardware / drivers - - ============================================================================= - */ - - static final int MAX_SCRAPS = 1; - static final int BLOCK_WIDTH = 256; - static final int BLOCK_HEIGHT = 256; - - int[][] scrap_allocated = new int[MAX_SCRAPS][BLOCK_WIDTH]; - byte[][] scrap_texels = new byte[MAX_SCRAPS][BLOCK_WIDTH * BLOCK_HEIGHT]; - boolean scrap_dirty; - - static class pos_t { - int x, y; - - pos_t(int x, int y) { - this.x = x; - this.y = y; - } - } - - // returns a texture number and the position inside it - int Scrap_AllocBlock(int w, int h, pos_t pos) { - int i, j; - int best, best2; - int texnum; - - for (texnum = 0; texnum < MAX_SCRAPS; texnum++) { - best = BLOCK_HEIGHT; - - for (i = 0; i < BLOCK_WIDTH - w; i++) { - best2 = 0; - - for (j = 0; j < w; j++) { - if (scrap_allocated[texnum][i + j] >= best) - break; - if (scrap_allocated[texnum][i + j] > best2) - best2 = scrap_allocated[texnum][i + j]; - } - if (j == w) { // this is a valid spot - pos.x = i; - pos.y = best = best2; - } - } - - if (best + h > BLOCK_HEIGHT) - continue; - - for (i = 0; i < w; i++) - scrap_allocated[texnum][pos.x + i] = best + h; - - return texnum; - } - - return -1; - // Sys_Error ("Scrap_AllocBlock: full"); - } - - int scrap_uploads = 0; - - void Scrap_Upload() { - scrap_uploads++; - GL_Bind(TEXNUM_SCRAPS); - GL_Upload8(scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, false); - scrap_dirty = false; - } - - /* - ================================================================= - - PCX LOADING - - ================================================================= - */ - - /* - ============== - LoadPCX - ============== - */ - byte[] LoadPCX(String filename, byte[][] palette, Dimension dim) { - qfiles.pcx_t pcx; - - // - // load the file - // - byte[] raw = FS.LoadFile(filename); - - if (raw == null) { - VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename + '\n'); - return null; - } - - // - // parse the PCX file - // - pcx = new qfiles.pcx_t(raw); - - if (pcx.manufacturer != 0x0a - || pcx.version != 5 - || pcx.encoding != 1 - || pcx.bits_per_pixel != 8 - || pcx.xmax >= 640 - || pcx.ymax >= 480) { - - VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n'); - return null; - } - - int width = pcx.xmax - pcx.xmin + 1; - int height = pcx.ymax - pcx.ymin + 1; - - byte[] pix = new byte[width * height]; - - if (palette != null) { - palette[0] = new byte[768]; - System.arraycopy(raw, raw.length - 768, palette[0], 0, 768); - } - - if (dim != null) { - dim.width = width; - dim.height = height; - } - - // - // decode pcx - // - int count = 0; - byte dataByte = 0; - int runLength = 0; - int x, y; - - for (y = 0; y < height; y++) { - for (x = 0; x < width;) { - - dataByte = pcx.data.get(); - - if ((dataByte & 0xC0) == 0xC0) { - runLength = dataByte & 0x3F; - dataByte = pcx.data.get(); - // write runLength pixel - while (runLength-- > 0) { - pix[count++] = dataByte; - x++; - } - } - else { - // write one pixel - pix[count++] = dataByte; - x++; - } - } - } - return pix; - } - - // /* - // ========================================================= - // - // TARGA LOADING - // - // ========================================================= - // */ - /* - ============= - LoadTGA - ============= - */ - byte[] LoadTGA(String name, Dimension dim) { - int columns, rows, numPixels; - int pixbuf; // index into pic - int row, column; - byte[] raw; - ByteBuffer buf_p; - int length; - qfiles.tga_t targa_header; - byte[] pic = null; - - // - // load the file - // - raw = FS.LoadFile(name); - - if (raw == null) - { - VID.Printf(Defines.PRINT_DEVELOPER, "Bad tga file "+ name +'\n'); - return null; - } - - targa_header = new qfiles.tga_t(raw); - - if (targa_header.image_type != 2 && targa_header.image_type != 10) - Com.Error(Defines.ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); - - if (targa_header.colormap_type != 0 || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24)) - Com.Error (Defines.ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); - - columns = targa_header.width; - rows = targa_header.height; - numPixels = columns * rows; - - if (dim != null) { - dim.width = columns; - dim.height = rows; - } - - pic = new byte[numPixels * 4]; // targa_rgba; - - if (targa_header.id_length != 0) - targa_header.data.position(targa_header.id_length); // skip TARGA image comment - - buf_p = targa_header.data; - - byte red,green,blue,alphabyte; - red = green = blue = alphabyte = 0; - int packetHeader, packetSize, j; - - if (targa_header.image_type==2) { // Uncompressed, RGB images - for(row=rows-1; row>=0; row--) { - - pixbuf = row * columns * 4; - - for(column=0; column=0; row--) { - - pixbuf = row * columns * 4; - try { - - for(column=0; column0) - row--; - else - // goto label breakOut; - throw new longjmpException(); - - pixbuf = row * columns * 4; - } - } - } - else { // non run-length packet - for(j=0;j0) - row--; - else - // goto label breakOut; - throw new longjmpException(); - - pixbuf = row * columns * 4; - } - } - } - } - } catch (longjmpException e){ - // label breakOut: - } - } - } - return pic; - } - - /* - ==================================================================== - - IMAGE FLOOD FILLING - - ==================================================================== - */ - - /* - ================= - Mod_FloodFillSkin - - Fill background pixels so mipmapping doesn't have haloes - ================= - */ - - static class floodfill_t { - short x, y; - } - - // must be a power of 2 - static final int FLOODFILL_FIFO_SIZE = 0x1000; - static final int FLOODFILL_FIFO_MASK = FLOODFILL_FIFO_SIZE - 1; - // - // #define FLOODFILL_STEP( off, dx, dy ) \ - // { \ - // if (pos[off] == fillcolor) \ - // { \ - // pos[off] = 255; \ - // fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ - // inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ - // } \ - // else if (pos[off] != 255) fdc = pos[off]; \ - // } - - // void FLOODFILL_STEP( int off, int dx, int dy ) - // { - // if (pos[off] == fillcolor) - // { - // pos[off] = 255; - // fifo[inpt].x = x + dx; fifo[inpt].y = y + dy; - // inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - // } - // else if (pos[off] != 255) fdc = pos[off]; - // } - static floodfill_t[] fifo = new floodfill_t[FLOODFILL_FIFO_SIZE]; - static { - for (int j = 0; j < fifo.length; j++) { - fifo[j] = new floodfill_t(); - } - } - // TODO check this: R_FloodFillSkin( byte[] skin, int skinwidth, int skinheight) - void R_FloodFillSkin(byte[] skin, int skinwidth, int skinheight) { - // byte fillcolor = *skin; // assume this is the pixel to fill - int fillcolor = skin[0] & 0xff; -// floodfill_t[] fifo = new floodfill_t[FLOODFILL_FIFO_SIZE]; - int inpt = 0, outpt = 0; - int filledcolor = -1; - int i; - -// for (int j = 0; j < fifo.length; j++) { -// fifo[j] = new floodfill_t(); -// } - - if (filledcolor == -1) { - filledcolor = 0; - // attempt to find opaque black - for (i = 0; i < 256; ++i) - // TODO check this - if (d_8to24table[i] == 0xFF000000) { // alpha 1.0 - //if (d_8to24table[i] == (255 << 0)) // alpha 1.0 - filledcolor = i; - break; - } - } - - // can't fill to filled color or to transparent color (used as visited marker) - if ((fillcolor == filledcolor) || (fillcolor == 255)) { - return; - } - - fifo[inpt].x = 0; - fifo[inpt].y = 0; - inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - - while (outpt != inpt) { - int x = fifo[outpt].x; - int y = fifo[outpt].y; - int fdc = filledcolor; - // byte *pos = &skin[x + skinwidth * y]; - int pos = x + skinwidth * y; - // - outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; - - int off, dx, dy; - - if (x > 0) { - // FLOODFILL_STEP( -1, -1, 0 ); - off = -1; - dx = -1; - dy = 0; - if (skin[pos + off] == (byte) fillcolor) { - skin[pos + off] = (byte) 255; - fifo[inpt].x = (short) (x + dx); - fifo[inpt].y = (short) (y + dy); - inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - } - else if (skin[pos + off] != (byte) 255) - fdc = skin[pos + off] & 0xff; - } - - if (x < skinwidth - 1) { - // FLOODFILL_STEP( 1, 1, 0 ); - off = 1; - dx = 1; - dy = 0; - if (skin[pos + off] == (byte) fillcolor) { - skin[pos + off] = (byte) 255; - fifo[inpt].x = (short) (x + dx); - fifo[inpt].y = (short) (y + dy); - inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - } - else if (skin[pos + off] != (byte) 255) - fdc = skin[pos + off] & 0xff; - } - - if (y > 0) { - // FLOODFILL_STEP( -skinwidth, 0, -1 ); - off = -skinwidth; - dx = 0; - dy = -1; - if (skin[pos + off] == (byte) fillcolor) { - skin[pos + off] = (byte) 255; - fifo[inpt].x = (short) (x + dx); - fifo[inpt].y = (short) (y + dy); - inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - } - else if (skin[pos + off] != (byte) 255) - fdc = skin[pos + off] & 0xff; - } - - if (y < skinheight - 1) { - // FLOODFILL_STEP( skinwidth, 0, 1 ); - off = skinwidth; - dx = 0; - dy = 1; - if (skin[pos + off] == (byte) fillcolor) { - skin[pos + off] = (byte) 255; - fifo[inpt].x = (short) (x + dx); - fifo[inpt].y = (short) (y + dy); - inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - } - else if (skin[pos + off] != (byte) 255) - fdc = skin[pos + off] & 0xff; - - } - - skin[x + skinwidth * y] = (byte) fdc; - } - } - - // ======================================================= - - /* - ================ - GL_ResampleTexture - ================ - */ - // cwei :-) - void GL_ResampleTexture(int[] in, int inwidth, int inheight, int[] out, int outwidth, int outheight) { - // int i, j; - // unsigned *inrow, *inrow2; - // int frac, fracstep; - // int[] p1 = new int[1024]; - // int[] p2 = new int[1024]; - // - - // *** this source do the same *** - BufferedImage image = new BufferedImage(inwidth, inheight, BufferedImage.TYPE_INT_ARGB); - - image.setRGB(0, 0, inwidth, inheight, in, 0, inwidth); - - AffineTransformOp op = - new AffineTransformOp( - AffineTransform.getScaleInstance(outwidth * 1.0 / inwidth, outheight * 1.0 / inheight), - AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - BufferedImage tmp = op.filter(image, null); - - tmp.getRGB(0, 0, outwidth, outheight, out, 0, outwidth); - - // *** end *** - - // byte *pix1, *pix2, *pix3, *pix4; - // - // fracstep = inwidth*0x10000/outwidth; - // - // frac = fracstep>>2; - // for (i=0 ; i>16); - // frac += fracstep; - // } - // frac = 3*(fracstep>>2); - // for (i=0 ; i>16); - // frac += fracstep; - // } - // - // for (i=0 ; i> 1; - // for (j=0 ; j>2; - // ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; - // ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; - // ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; - // } - // } - } - - /* - ================ - GL_LightScaleTexture - - Scale up the pixel values in a texture to increase the - lighting range - ================ - */ - void GL_LightScaleTexture(int[] in, int inwidth, int inheight, boolean only_gamma) { - if (only_gamma) { - int i, c; - int r, g, b, color; - - c = inwidth * inheight; - for (i = 0; i < c; i++) { - color = in[i]; - r = (color >> 0) & 0xFF; - g = (color >> 8) & 0xFF; - b = (color >> 16) & 0xFF; - - r = gammatable[r] & 0xFF; - g = gammatable[g] & 0xFF; - b = gammatable[b] & 0xFF; - - in[i] = (r << 0) | (g << 8) | (b << 16) | (color & 0xFF000000); - } - } - else { - int i, c; - int r, g, b, color; - - c = inwidth * inheight; - for (i = 0; i < c; i++) { - color = in[i]; - r = (color >> 0) & 0xFF; - g = (color >> 8) & 0xFF; - b = (color >> 16) & 0xFF; - - r = gammatable[intensitytable[r] & 0xFF] & 0xFF; - g = gammatable[intensitytable[g] & 0xFF] & 0xFF; - b = gammatable[intensitytable[b] & 0xFF] & 0xFF; - - in[i] = (r << 0) | (g << 8) | (b << 16) | (color & 0xFF000000); - } - - } - } - - /* - ================ - GL_MipMap - - Operates in place, quartering the size of the texture - ================ - */ - void GL_MipMap(int[] in, int width, int height) { - int i, j; - int[] out; - - out = in; - - int inIndex = 0; - int outIndex = 0; - - int r, g, b, a; - int p1, p2, p3, p4; - - for (i = 0; i < height; i += 2, inIndex += width) { - for (j = 0; j < width; j += 2, outIndex += 1, inIndex += 2) { - - p1 = in[inIndex + 0]; - p2 = in[inIndex + 1]; - p3 = in[inIndex + width + 0]; - p4 = in[inIndex + width + 1]; - - r = (((p1 >> 0) & 0xFF) + ((p2 >> 0) & 0xFF) + ((p3 >> 0) & 0xFF) + ((p4 >> 0) & 0xFF)) >> 2; - g = (((p1 >> 8) & 0xFF) + ((p2 >> 8) & 0xFF) + ((p3 >> 8) & 0xFF) + ((p4 >> 8) & 0xFF)) >> 2; - b = (((p1 >> 16) & 0xFF) + ((p2 >> 16) & 0xFF) + ((p3 >> 16) & 0xFF) + ((p4 >> 16) & 0xFF)) >> 2; - a = (((p1 >> 24) & 0xFF) + ((p2 >> 24) & 0xFF) + ((p3 >> 24) & 0xFF) + ((p4 >> 24) & 0xFF)) >> 2; - - out[outIndex] = (r << 0) | (g << 8) | (b << 16) | (a << 24); - } - } - } - - /* - =============== - GL_Upload32 - - Returns has_alpha - =============== - */ - void GL_BuildPalettedTexture(byte[] paletted_texture, int[] scaled, int scaled_width, int scaled_height) { - - int r, g, b, c; - int size = scaled_width * scaled_height; - - for (int i = 0; i < size; i++) { - - r = (scaled[i] >> 3) & 31; - g = (scaled[i] >> 10) & 63; - b = (scaled[i] >> 19) & 31; - - c = r | (g << 5) | (b << 11); - - paletted_texture[i] = gl_state.d_16to8table[c]; - } - } - - int upload_width, upload_height; - boolean uploaded_paletted; - - /* - =============== - GL_Upload32 - - Returns has_alpha - =============== - */ - int[] scaled = new int[256 * 256]; - byte[] paletted_texture = new byte[256 * 256]; - IntBuffer tex = Lib.newIntBuffer(512 * 256, ByteOrder.LITTLE_ENDIAN); - - boolean GL_Upload32(int[] data, int width, int height, boolean mipmap) { - int samples; - int scaled_width, scaled_height; - int i, c; - int comp; - - Arrays.fill(scaled, 0); - Arrays.fill(paletted_texture, (byte)0); - - uploaded_paletted = false; - - for (scaled_width = 1; scaled_width < width; scaled_width <<= 1); - if (gl_round_down.value > 0.0f && scaled_width > width && mipmap) - scaled_width >>= 1; - for (scaled_height = 1; scaled_height < height; scaled_height <<= 1); - if (gl_round_down.value > 0.0f && scaled_height > height && mipmap) - scaled_height >>= 1; - - // let people sample down the world textures for speed - if (mipmap) { - scaled_width >>= (int) gl_picmip.value; - scaled_height >>= (int) gl_picmip.value; - } - - // don't ever bother with >256 textures - if (scaled_width > 256) - scaled_width = 256; - if (scaled_height > 256) - scaled_height = 256; - - if (scaled_width < 1) - scaled_width = 1; - if (scaled_height < 1) - scaled_height = 1; - - upload_width = scaled_width; - upload_height = scaled_height; - - if (scaled_width * scaled_height > 256 * 256) - Com.Error(Defines.ERR_DROP, "GL_Upload32: too big"); - - // scan the texture for any non-255 alpha - c = width * height; - samples = gl_solid_format; - - for (i = 0; i < c; i++) { - if ((data[i] & 0xff000000) != 0xff000000) { - samples = gl_alpha_format; - break; - } - } - - if (samples == gl_solid_format) - comp = gl_tex_solid_format; - else if (samples == gl_alpha_format) - comp = gl_tex_alpha_format; - else { - VID.Printf(Defines.PRINT_ALL, "Unknown number of texture components " + samples + '\n'); - comp = samples; - } - - // simulates a goto - try { - if (scaled_width == width && scaled_height == height) { - if (!mipmap) { - if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && samples == gl_solid_format) { - uploaded_paletted = true; - GL_BuildPalettedTexture(paletted_texture, data, scaled_width, scaled_height); - gl.glTexImage2D( - GL.GL_TEXTURE_2D, - 0, - GL_COLOR_INDEX8_EXT, - scaled_width, - scaled_height, - 0, - GL.GL_COLOR_INDEX, - GL.GL_UNSIGNED_BYTE, - paletted_texture); - } - else { - tex.rewind(); tex.put(data); - gl.glTexImage2D( - GL.GL_TEXTURE_2D, - 0, - comp, - scaled_width, - scaled_height, - 0, - GL.GL_RGBA, - GL.GL_UNSIGNED_BYTE, - tex); - } - //goto done; - throw new longjmpException(); - } - //memcpy (scaled, data, width*height*4); were bytes - System.arraycopy(data, 0, scaled, 0, width * height); - } - else - GL_ResampleTexture(data, width, height, scaled, scaled_width, scaled_height); - - GL_LightScaleTexture(scaled, scaled_width, scaled_height, !mipmap); - - if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && (samples == gl_solid_format)) { - uploaded_paletted = true; - GL_BuildPalettedTexture(paletted_texture, scaled, scaled_width, scaled_height); - gl.glTexImage2D( - GL.GL_TEXTURE_2D, - 0, - GL_COLOR_INDEX8_EXT, - scaled_width, - scaled_height, - 0, - GL.GL_COLOR_INDEX, - GL.GL_UNSIGNED_BYTE, - paletted_texture); - } - else { - tex.rewind(); tex.put(scaled); - gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, tex); - } - - if (mipmap) { - int miplevel; - miplevel = 0; - while (scaled_width > 1 || scaled_height > 1) { - GL_MipMap(scaled, scaled_width, scaled_height); - scaled_width >>= 1; - scaled_height >>= 1; - if (scaled_width < 1) - scaled_width = 1; - if (scaled_height < 1) - scaled_height = 1; - - miplevel++; - if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && samples == gl_solid_format) { - uploaded_paletted = true; - GL_BuildPalettedTexture(paletted_texture, scaled, scaled_width, scaled_height); - gl.glTexImage2D( - GL.GL_TEXTURE_2D, - miplevel, - GL_COLOR_INDEX8_EXT, - scaled_width, - scaled_height, - 0, - GL.GL_COLOR_INDEX, - GL.GL_UNSIGNED_BYTE, - paletted_texture); - } - else { - tex.rewind(); tex.put(scaled); - gl.glTexImage2D( - GL.GL_TEXTURE_2D, - miplevel, - comp, - scaled_width, - scaled_height, - 0, - GL.GL_RGBA, - GL.GL_UNSIGNED_BYTE, - tex); - } - } - } - // label done: - } - catch (longjmpException e) { - ; // replaces label done - } - - if (mipmap) { - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, gl_filter_min); - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - else { - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, gl_filter_max); - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - - return (samples == gl_alpha_format); - } - - /* - =============== - GL_Upload8 - - Returns has_alpha - =============== - */ - - int[] trans = new int[512 * 256]; - - boolean GL_Upload8(byte[] data, int width, int height, boolean mipmap, boolean is_sky) { - - Arrays.fill(trans, 0); - - int s = width * height; - - if (s > trans.length) - Com.Error(Defines.ERR_DROP, "GL_Upload8: too large"); - - if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && is_sky) { - gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, width, height, 0, GL.GL_COLOR_INDEX, GL.GL_UNSIGNED_BYTE, data); - - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, gl_filter_max); - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, gl_filter_max); - - // TODO check this - return false; - } - else { - int p; - int rgb; - for (int i = 0; i < s; i++) { - p = data[i] & 0xff; - trans[i] = d_8to24table[p]; - - if (p == 255) { // transparent, so scan around for another color - // to avoid alpha fringes - // FIXME: do a full flood fill so mips work... - if (i > width && (data[i - width] & 0xff) != 255) - p = data[i - width] & 0xff; - else if (i < s - width && (data[i + width] & 0xff) != 255) - p = data[i + width] & 0xff; - else if (i > 0 && (data[i - 1] & 0xff) != 255) - p = data[i - 1] & 0xff; - else if (i < s - 1 && (data[i + 1] & 0xff) != 255) - p = data[i + 1] & 0xff; - else - p = 0; - // copy rgb components - - // ((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0]; - // ((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1]; - // ((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2]; - - trans[i] = d_8to24table[p] & 0x00FFFFFF; // only rgb - } - } - - return GL_Upload32(trans, width, height, mipmap); - } - } - - /* - ================ - GL_LoadPic - - This is also used as an entry point for the generated r_notexture - ================ - */ - image_t GL_LoadPic(String name, byte[] pic, int width, int height, int type, int bits) { - image_t image; - int i; - - // find a free image_t - for (i = 0; i Defines.MAX_QPATH) - Com.Error(Defines.ERR_DROP, "Draw_LoadPic: \"" + name + "\" is too long"); - - image.name = name; - image.registration_sequence = registration_sequence; - - image.width = width; - image.height = height; - image.type = type; - - - if (type == it_skin && bits == 8) - R_FloodFillSkin(pic, width, height); - - // load little pics into the scrap - if (image.type == it_pic && bits == 8 && image.width < 64 && image.height < 64) { - pos_t pos = new pos_t(0, 0); - int j, k; - - int texnum = Scrap_AllocBlock(image.width, image.height, pos); - - if (texnum == -1) { - // replace goto nonscrap - - image.scrap = false; - - image.texnum = TEXNUM_IMAGES + image.getId(); // image pos in array - GL_Bind(image.texnum); - - if (bits == 8) { - image.has_alpha = - GL_Upload8(pic, width, height, (image.type != it_pic && image.type != it_sky), image.type == it_sky); - } - else { - int[] tmp = new int[pic.length / 4]; - - for (i = 0; i < tmp.length; i++) { - tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0); // & 0x000000FF; - tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8); // & 0x0000FF00; - tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16); // & 0x00FF0000; - tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24); // & 0xFF000000; - } - - image.has_alpha = GL_Upload32(tmp, width, height, (image.type != it_pic && image.type != it_sky)); - } - - image.upload_width = upload_width; // after power of 2 and scales - image.upload_height = upload_height; - image.paletted = uploaded_paletted; - image.sl = 0; - image.sh = 1; - image.tl = 0; - image.th = 1; - - return image; - } - - scrap_dirty = true; - - // copy the texels into the scrap block - k = 0; - for (i = 0; i < image.height; i++) - for (j = 0; j < image.width; j++, k++) - scrap_texels[texnum][(pos.y + i) * BLOCK_WIDTH + pos.x + j] = pic[k]; - - image.texnum = TEXNUM_SCRAPS + texnum; - image.scrap = true; - image.has_alpha = true; - image.sl = (pos.x + 0.01f) / (float) BLOCK_WIDTH; - image.sh = (pos.x + image.width - 0.01f) / (float) BLOCK_WIDTH; - image.tl = (pos.y + 0.01f) / (float) BLOCK_WIDTH; - image.th = (pos.y + image.height - 0.01f) / (float) BLOCK_WIDTH; - - } - else { - // this was label nonscrap - - image.scrap = false; - - image.texnum = TEXNUM_IMAGES + image.getId(); //image pos in array - GL_Bind(image.texnum); - - if (bits == 8) { - image.has_alpha = GL_Upload8(pic, width, height, (image.type != it_pic && image.type != it_sky), image.type == it_sky); - } - else { - int[] tmp = new int[pic.length / 4]; - - for (i = 0; i < tmp.length; i++) { - tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0); // & 0x000000FF; - tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8); // & 0x0000FF00; - tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16); // & 0x00FF0000; - tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24); // & 0xFF000000; - } - - image.has_alpha = GL_Upload32(tmp, width, height, (image.type != it_pic && image.type != it_sky)); - } - image.upload_width = upload_width; // after power of 2 and scales - image.upload_height = upload_height; - image.paletted = uploaded_paletted; - image.sl = 0; - image.sh = 1; - image.tl = 0; - image.th = 1; - } - return image; - } - - /* - ================ - GL_LoadWal - ================ - */ - image_t GL_LoadWal(String name) { - - image_t image = null; - - byte[] raw = FS.LoadFile(name); - if (raw == null) { - VID.Printf(Defines.PRINT_ALL, "GL_FindImage: can't load " + name + '\n'); - return r_notexture; - } - - qfiles.miptex_t mt = new qfiles.miptex_t(raw); - - byte[] pix = new byte[mt.width * mt.height]; - System.arraycopy(raw, mt.offsets[0], pix, 0, pix.length); - - image = GL_LoadPic(name, pix, mt.width, mt.height, it_wall, 8); - - return image; - } - - /* - =============== - GL_FindImage - - Finds or loads the given image - =============== - */ - image_t GL_FindImage(String name, int type) { - image_t image = null; - -// // TODO loest das grossschreibungs problem -// name = name.toLowerCase(); -// // bughack for bad strings (fuck \0) -// int index = name.indexOf('\0'); -// if (index != -1) -// name = name.substring(0, index); - - if (name == null || name.length() < 5) - return null; // Com.Error (ERR_DROP, "GL_FindImage: NULL name"); - // Com.Error (ERR_DROP, "GL_FindImage: bad name: %s", name); - - // look for it - for (int i = 0; i < numgltextures; i++) - { - image = gltextures[i]; - if (name.equals(image.name)) - { - image.registration_sequence = registration_sequence; - return image; - } - } - - // - // load the pic from disk - // - image = null; - byte[] pic = null; - Dimension dim = new Dimension(); - - if (name.endsWith(".pcx")) { - - pic = LoadPCX(name, null, dim); - if (pic == null) - return null; - image = GL_LoadPic(name, pic, dim.width, dim.height, type, 8); - - } - else if (name.endsWith(".wal")) { - - image = GL_LoadWal(name); - - } - else if (name.endsWith(".tga")) { - - pic = LoadTGA(name, dim); - - if (pic == null) - return null; - - image = GL_LoadPic(name, pic, dim.width, dim.height, type, 32); - - } - - return image; - } - - /* - =============== - R_RegisterSkin - =============== - */ - protected image_t R_RegisterSkin(String name) { - return GL_FindImage(name, it_skin); - } - - /* - ================ - GL_FreeUnusedImages - - Any image that was not touched on this registration sequence - will be freed. - ================ - */ - void GL_FreeUnusedImages() { - - // never free r_notexture or particle texture - r_notexture.registration_sequence = registration_sequence; - r_particletexture.registration_sequence = registration_sequence; - - image_t image = null; - - for (int i = 0; i < numgltextures; i++) { - image = gltextures[i]; - // used this sequence - if (image.registration_sequence == registration_sequence) - continue; - // free image_t slot - if (image.registration_sequence == 0) - continue; - // don't free pics - if (image.type == it_pic) - continue; - - // free it - // TODO jogl bug - gl.glDeleteTextures(1, new int[] {image.texnum}); - image.clear(); - } - } - - /* - =============== - Draw_GetPalette - =============== - */ - protected void Draw_GetPalette() { - int r, g, b; - Dimension dim; - byte[] pic; - byte[][] palette = new byte[1][]; //new byte[768]; - - // get the palette - - pic = LoadPCX("pics/colormap.pcx", palette, dim = new Dimension()); - - if (palette[0] == null || palette[0].length != 768) - Com.Error(Defines.ERR_FATAL, "Couldn't load pics/colormap.pcx"); - - byte[] pal = palette[0]; - - int j = 0; - for (int i = 0; i < 256; i++) { - r = pal[j++] & 0xFF; - g = pal[j++] & 0xFF; - b = pal[j++] & 0xFF; - - d_8to24table[i] = (255 << 24) | (b << 16) | (g << 8) | (r << 0); - } - - d_8to24table[255] &= 0x00FFFFFF; // 255 is transparent - - particle_t.setColorPalette(d_8to24table); - } - - /* - =============== - GL_InitImages - =============== - */ - void GL_InitImages() { - int i, j; - float g = vid_gamma.value; - - registration_sequence = 1; - - // init intensity conversions - intensity = Cvar.Get("intensity", "2", 0); - - if (intensity.value <= 1) - Cvar.Set("intensity", "1"); - - gl_state.inverse_intensity = 1 / intensity.value; - - Draw_GetPalette(); - - if (qglColorTableEXT) { - gl_state.d_16to8table = FS.LoadFile("pics/16to8.dat"); - if (gl_state.d_16to8table == null) - Com.Error(Defines.ERR_FATAL, "Couldn't load pics/16to8.pcx"); - } - - if ((gl_config.renderer & (GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2)) != 0) { - g = 1.0F; - } - - for (i = 0; i < 256; i++) { - - if (g == 1.0f) { - gammatable[i] = (byte) i; - } - else { - - int inf = (int) (255.0f * Math.pow((i + 0.5) / 255.5, g) + 0.5); - if (inf < 0) - inf = 0; - if (inf > 255) - inf = 255; - gammatable[i] = (byte) inf; - } - } - - for (i = 0; i < 256; i++) { - j = (int) (i * intensity.value); - if (j > 255) - j = 255; - intensitytable[i] = (byte) j; - } - } - - /* - =============== - GL_ShutdownImages - =============== - */ - void GL_ShutdownImages() { - image_t image; - - for (int i=0; i < numgltextures ; i++) - { - image = gltextures[i]; - - if (image.registration_sequence == 0) - continue; // free image_t slot - // free it - // TODO jogl bug - gl.glDeleteTextures(1, new int[] {image.texnum}); - image.clear(); - } - } - -} + image_t draw_chars; + + image_t[] gltextures = new image_t[MAX_GLTEXTURES]; + + //Map gltextures = new Hashtable(MAX_GLTEXTURES); // image_t + int numgltextures; + + int base_textureid; // gltextures[i] = base_textureid+i + + byte[] intensitytable = new byte[256]; + + byte[] gammatable = new byte[256]; + + cvar_t intensity; + + // + // qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, + // qboolean is_sky ); + // qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean + // mipmap); + // + + int gl_solid_format = 3; + + int gl_alpha_format = 4; + + int gl_tex_solid_format = 3; + + int gl_tex_alpha_format = 4; + + int gl_filter_min = GL.GL_LINEAR_MIPMAP_NEAREST; + + int gl_filter_max = GL.GL_LINEAR; + + Image() { + // init the texture cache + for (int i = 0; i < gltextures.length; i++) { + gltextures[i] = new image_t(i); + } + numgltextures = 0; + } + + void GL_SetTexturePalette(int[] palette) { + + assert (palette != null && palette.length == 256) : "int palette[256] bug"; + + int i; + byte[] temptable = new byte[768]; + + if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f) { + for (i = 0; i < 256; i++) { + temptable[i * 3 + 0] = (byte) ((palette[i] >> 0) & 0xff); + temptable[i * 3 + 1] = (byte) ((palette[i] >> 8) & 0xff); + temptable[i * 3 + 2] = (byte) ((palette[i] >> 16) & 0xff); + } + + gl.glColorTableEXT(GL.GL_SHARED_TEXTURE_PALETTE_EXT, GL.GL_RGB, + 256, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, temptable); + } + } + + void GL_EnableMultitexture(boolean enable) { + if (enable) { + GL_SelectTexture(GL_TEXTURE1); + gl.glEnable(GL.GL_TEXTURE_2D); + GL_TexEnv(GL.GL_REPLACE); + } else { + GL_SelectTexture(GL_TEXTURE1); + gl.glDisable(GL.GL_TEXTURE_2D); + GL_TexEnv(GL.GL_REPLACE); + } + GL_SelectTexture(GL_TEXTURE0); + GL_TexEnv(GL.GL_REPLACE); + } + + void GL_SelectTexture(int texture /* GLenum */ + ) { + int tmu; + + tmu = (texture == GL_TEXTURE0) ? 0 : 1; + + if (tmu == gl_state.currenttmu) { + return; + } + + gl_state.currenttmu = tmu; + + gl.glActiveTextureARB(texture); + gl.glClientActiveTextureARB(texture); + } + + int[] lastmodes = { -1, -1 }; + + void GL_TexEnv(int mode /* GLenum */ + ) { + + if (mode != lastmodes[gl_state.currenttmu]) { + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, mode); + lastmodes[gl_state.currenttmu] = mode; + } + } + + void GL_Bind(int texnum) { + + if ((gl_nobind.value != 0) && (draw_chars != null)) { + // performance evaluation option + texnum = draw_chars.texnum; + } + if (gl_state.currenttextures[gl_state.currenttmu] == texnum) + return; + + gl_state.currenttextures[gl_state.currenttmu] = texnum; + gl.glBindTexture(GL.GL_TEXTURE_2D, texnum); + } + + void GL_MBind(int target /* GLenum */ + , int texnum) { + GL_SelectTexture(target); + if (target == GL_TEXTURE0) { + if (gl_state.currenttextures[0] == texnum) + return; + } else { + if (gl_state.currenttextures[1] == texnum) + return; + } + GL_Bind(texnum); + } + + // glmode_t + static class glmode_t { + String name; + + int minimize, maximize; + + glmode_t(String name, int minimize, int maximze) { + this.name = name; + this.minimize = minimize; + this.maximize = maximze; + } + } + + static final glmode_t modes[] = { + new glmode_t("GL_NEAREST", GL.GL_NEAREST, GL.GL_NEAREST), + new glmode_t("GL_LINEAR", GL.GL_LINEAR, GL.GL_LINEAR), + new glmode_t("GL_NEAREST_MIPMAP_NEAREST", + GL.GL_NEAREST_MIPMAP_NEAREST, GL.GL_NEAREST), + new glmode_t("GL_LINEAR_MIPMAP_NEAREST", + GL.GL_LINEAR_MIPMAP_NEAREST, GL.GL_LINEAR), + new glmode_t("GL_NEAREST_MIPMAP_LINEAR", + GL.GL_NEAREST_MIPMAP_LINEAR, GL.GL_NEAREST), + new glmode_t("GL_LINEAR_MIPMAP_LINEAR", GL.GL_LINEAR_MIPMAP_LINEAR, + GL.GL_LINEAR) }; + + static final int NUM_GL_MODES = modes.length; + + // gltmode_t + static class gltmode_t { + String name; + + int mode; + + gltmode_t(String name, int mode) { + this.name = name; + this.mode = mode; + } + } + + static final gltmode_t[] gl_alpha_modes = { new gltmode_t("default", 4), + new gltmode_t("GL_RGBA", GL.GL_RGBA), + new gltmode_t("GL_RGBA8", GL.GL_RGBA8), + new gltmode_t("GL_RGB5_A1", GL.GL_RGB5_A1), + new gltmode_t("GL_RGBA4", GL.GL_RGBA4), + new gltmode_t("GL_RGBA2", GL.GL_RGBA2), }; + + static final int NUM_GL_ALPHA_MODES = gl_alpha_modes.length; + + static final gltmode_t[] gl_solid_modes = { new gltmode_t("default", 3), + new gltmode_t("GL_RGB", GL.GL_RGB), + new gltmode_t("GL_RGB8", GL.GL_RGB8), + new gltmode_t("GL_RGB5", GL.GL_RGB5), + new gltmode_t("GL_RGB4", GL.GL_RGB4), + new gltmode_t("GL_R3_G3_B2", GL.GL_R3_G3_B2), + // #ifdef GL_RGB2_EXT + new gltmode_t("GL_RGB2", GL.GL_RGB2_EXT) + // #endif + }; + + static final int NUM_GL_SOLID_MODES = gl_solid_modes.length; + + /* + * =============== GL_TextureMode =============== + */ + void GL_TextureMode(String string) { + + int i; + for (i = 0; i < NUM_GL_MODES; i++) { + if (modes[i].name.equalsIgnoreCase(string)) + break; + } + + if (i == NUM_GL_MODES) { + VID + .Printf(Defines.PRINT_ALL, "bad filter name: [" + string + + "]\n"); + return; + } + + gl_filter_min = modes[i].minimize; + gl_filter_max = modes[i].maximize; + + image_t glt; + // change all the existing mipmap texture objects + for (i = 0; i < numgltextures; i++) { + glt = gltextures[i]; + + if (glt.type != it_pic && glt.type != it_sky) { + GL_Bind(glt.texnum); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + gl_filter_min); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + gl_filter_max); + } + } + } + + /* + * =============== GL_TextureAlphaMode =============== + */ + void GL_TextureAlphaMode(String string) { + + int i; + for (i = 0; i < NUM_GL_ALPHA_MODES; i++) { + if (gl_alpha_modes[i].name.equalsIgnoreCase(string)) + break; + } + + if (i == NUM_GL_ALPHA_MODES) { + VID.Printf(Defines.PRINT_ALL, "bad alpha texture mode name: [" + + string + "]\n"); + return; + } + + gl_tex_alpha_format = gl_alpha_modes[i].mode; + } + + /* + * =============== GL_TextureSolidMode =============== + */ + void GL_TextureSolidMode(String string) { + int i; + for (i = 0; i < NUM_GL_SOLID_MODES; i++) { + if (gl_solid_modes[i].name.equalsIgnoreCase(string)) + break; + } + + if (i == NUM_GL_SOLID_MODES) { + VID.Printf(Defines.PRINT_ALL, "bad solid texture mode name: [" + + string + "]\n"); + return; + } + + gl_tex_solid_format = gl_solid_modes[i].mode; + } + + /* + * =============== GL_ImageList_f =============== + */ + void GL_ImageList_f() { + + image_t image; + int texels; + final String[] palstrings = { "RGB", "PAL" }; + + VID.Printf(Defines.PRINT_ALL, "------------------\n"); + texels = 0; + + for (int i = 0; i < numgltextures; i++) { + image = gltextures[i]; + if (image.texnum <= 0) + continue; + + texels += image.upload_width * image.upload_height; + switch (image.type) { + case it_skin: + VID.Printf(Defines.PRINT_ALL, "M"); + break; + case it_sprite: + VID.Printf(Defines.PRINT_ALL, "S"); + break; + case it_wall: + VID.Printf(Defines.PRINT_ALL, "W"); + break; + case it_pic: + VID.Printf(Defines.PRINT_ALL, "P"); + break; + default: + VID.Printf(Defines.PRINT_ALL, " "); + break; + } + + VID.Printf(Defines.PRINT_ALL, " %3i %3i %s: %s\n", new Vargs(4) + .add(image.upload_width).add(image.upload_height).add( + palstrings[(image.paletted) ? 1 : 0]).add( + image.name)); + } + VID.Printf(Defines.PRINT_ALL, + "Total texel count (not counting mipmaps): " + texels + '\n'); + } + + /* + * ============================================================================= + * + * scrap allocation + * + * Allocate all the little status bar objects into a single texture to + * crutch up inefficient hardware / drivers + * + * ============================================================================= + */ + + static final int MAX_SCRAPS = 1; + + static final int BLOCK_WIDTH = 256; + + static final int BLOCK_HEIGHT = 256; + + int[][] scrap_allocated = new int[MAX_SCRAPS][BLOCK_WIDTH]; + + byte[][] scrap_texels = new byte[MAX_SCRAPS][BLOCK_WIDTH * BLOCK_HEIGHT]; + + boolean scrap_dirty; + + static class pos_t { + int x, y; + + pos_t(int x, int y) { + this.x = x; + this.y = y; + } + } + + // returns a texture number and the position inside it + int Scrap_AllocBlock(int w, int h, pos_t pos) { + int i, j; + int best, best2; + int texnum; + + for (texnum = 0; texnum < MAX_SCRAPS; texnum++) { + best = BLOCK_HEIGHT; + + for (i = 0; i < BLOCK_WIDTH - w; i++) { + best2 = 0; + + for (j = 0; j < w; j++) { + if (scrap_allocated[texnum][i + j] >= best) + break; + if (scrap_allocated[texnum][i + j] > best2) + best2 = scrap_allocated[texnum][i + j]; + } + if (j == w) { // this is a valid spot + pos.x = i; + pos.y = best = best2; + } + } + + if (best + h > BLOCK_HEIGHT) + continue; + + for (i = 0; i < w; i++) + scrap_allocated[texnum][pos.x + i] = best + h; + + return texnum; + } + + return -1; + // Sys_Error ("Scrap_AllocBlock: full"); + } + + int scrap_uploads = 0; + + void Scrap_Upload() { + scrap_uploads++; + GL_Bind(TEXNUM_SCRAPS); + GL_Upload8(scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, false); + scrap_dirty = false; + } + + /* + * ================================================================= + * + * PCX LOADING + * + * ================================================================= + */ + + /* + * ============== LoadPCX ============== + */ + byte[] LoadPCX(String filename, byte[][] palette, Dimension dim) { + qfiles.pcx_t pcx; + + // + // load the file + // + byte[] raw = FS.LoadFile(filename); + + if (raw == null) { + VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename + + '\n'); + return null; + } + + // + // parse the PCX file + // + pcx = new qfiles.pcx_t(raw); + + if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 + || pcx.bits_per_pixel != 8 || pcx.xmax >= 640 + || pcx.ymax >= 480) { + + VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n'); + return null; + } + + int width = pcx.xmax - pcx.xmin + 1; + int height = pcx.ymax - pcx.ymin + 1; + + byte[] pix = new byte[width * height]; + + if (palette != null) { + palette[0] = new byte[768]; + System.arraycopy(raw, raw.length - 768, palette[0], 0, 768); + } + + if (dim != null) { + dim.width = width; + dim.height = height; + } + + // + // decode pcx + // + int count = 0; + byte dataByte = 0; + int runLength = 0; + int x, y; + + for (y = 0; y < height; y++) { + for (x = 0; x < width;) { + + dataByte = pcx.data.get(); + + if ((dataByte & 0xC0) == 0xC0) { + runLength = dataByte & 0x3F; + dataByte = pcx.data.get(); + // write runLength pixel + while (runLength-- > 0) { + pix[count++] = dataByte; + x++; + } + } else { + // write one pixel + pix[count++] = dataByte; + x++; + } + } + } + return pix; + } + + // /* + // ========================================================= + // + // TARGA LOADING + // + // ========================================================= + // */ + /* + * ============= LoadTGA ============= + */ + byte[] LoadTGA(String name, Dimension dim) { + int columns, rows, numPixels; + int pixbuf; // index into pic + int row, column; + byte[] raw; + ByteBuffer buf_p; + int length; + qfiles.tga_t targa_header; + byte[] pic = null; + + // + // load the file + // + raw = FS.LoadFile(name); + + if (raw == null) { + VID.Printf(Defines.PRINT_DEVELOPER, "Bad tga file " + name + '\n'); + return null; + } + + targa_header = new qfiles.tga_t(raw); + + if (targa_header.image_type != 2 && targa_header.image_type != 10) + Com.Error(Defines.ERR_DROP, + "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); + + if (targa_header.colormap_type != 0 + || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24)) + Com + .Error(Defines.ERR_DROP, + "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (dim != null) { + dim.width = columns; + dim.height = rows; + } + + pic = new byte[numPixels * 4]; // targa_rgba; + + if (targa_header.id_length != 0) + targa_header.data.position(targa_header.id_length); // skip TARGA + // image comment + + buf_p = targa_header.data; + + byte red, green, blue, alphabyte; + red = green = blue = alphabyte = 0; + int packetHeader, packetSize, j; + + if (targa_header.image_type == 2) { // Uncompressed, RGB images + for (row = rows - 1; row >= 0; row--) { + + pixbuf = row * columns * 4; + + for (column = 0; column < columns; column++) { + switch (targa_header.pixel_size) { + case 24: + + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + pic[pixbuf++] = red; + pic[pixbuf++] = green; + pic[pixbuf++] = blue; + pic[pixbuf++] = (byte) 255; + break; + case 32: + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + alphabyte = buf_p.get(); + pic[pixbuf++] = red; + pic[pixbuf++] = green; + pic[pixbuf++] = blue; + pic[pixbuf++] = alphabyte; + break; + } + } + } + } else if (targa_header.image_type == 10) { // Runlength encoded RGB + // images + for (row = rows - 1; row >= 0; row--) { + + pixbuf = row * columns * 4; + try { + + for (column = 0; column < columns;) { + + packetHeader = buf_p.get() & 0xFF; + packetSize = 1 + (packetHeader & 0x7f); + + if ((packetHeader & 0x80) != 0) { // run-length packet + switch (targa_header.pixel_size) { + case 24: + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + alphabyte = (byte) 255; + break; + case 32: + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + alphabyte = buf_p.get(); + break; + } + + for (j = 0; j < packetSize; j++) { + pic[pixbuf++] = red; + pic[pixbuf++] = green; + pic[pixbuf++] = blue; + pic[pixbuf++] = alphabyte; + column++; + if (column == columns) { // run spans across + // rows + column = 0; + if (row > 0) + row--; + else + // goto label breakOut; + throw new longjmpException(); + + pixbuf = row * columns * 4; + } + } + } else { // non run-length packet + for (j = 0; j < packetSize; j++) { + switch (targa_header.pixel_size) { + case 24: + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + pic[pixbuf++] = red; + pic[pixbuf++] = green; + pic[pixbuf++] = blue; + pic[pixbuf++] = (byte) 255; + break; + case 32: + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + alphabyte = buf_p.get(); + pic[pixbuf++] = red; + pic[pixbuf++] = green; + pic[pixbuf++] = blue; + pic[pixbuf++] = alphabyte; + break; + } + column++; + if (column == columns) { // pixel packet run + // spans across rows + column = 0; + if (row > 0) + row--; + else + // goto label breakOut; + throw new longjmpException(); + + pixbuf = row * columns * 4; + } + } + } + } + } catch (longjmpException e) { + // label breakOut: + } + } + } + return pic; + } + + /* + * ==================================================================== + * + * IMAGE FLOOD FILLING + * + * ==================================================================== + */ + + /* + * ================= Mod_FloodFillSkin + * + * Fill background pixels so mipmapping doesn't have haloes + * ================= + */ + + static class floodfill_t { + short x, y; + } + + // must be a power of 2 + static final int FLOODFILL_FIFO_SIZE = 0x1000; + + static final int FLOODFILL_FIFO_MASK = FLOODFILL_FIFO_SIZE - 1; + + // + // #define FLOODFILL_STEP( off, dx, dy ) \ + // { \ + // if (pos[off] == fillcolor) \ + // { \ + // pos[off] = 255; \ + // fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ + // inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ + // } \ + // else if (pos[off] != 255) fdc = pos[off]; \ + // } + + // void FLOODFILL_STEP( int off, int dx, int dy ) + // { + // if (pos[off] == fillcolor) + // { + // pos[off] = 255; + // fifo[inpt].x = x + dx; fifo[inpt].y = y + dy; + // inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + // } + // else if (pos[off] != 255) fdc = pos[off]; + // } + static floodfill_t[] fifo = new floodfill_t[FLOODFILL_FIFO_SIZE]; + static { + for (int j = 0; j < fifo.length; j++) { + fifo[j] = new floodfill_t(); + } + } + + // TODO check this: R_FloodFillSkin( byte[] skin, int skinwidth, int + // skinheight) + void R_FloodFillSkin(byte[] skin, int skinwidth, int skinheight) { + // byte fillcolor = *skin; // assume this is the pixel to fill + int fillcolor = skin[0] & 0xff; + // floodfill_t[] fifo = new floodfill_t[FLOODFILL_FIFO_SIZE]; + int inpt = 0, outpt = 0; + int filledcolor = -1; + int i; + + // for (int j = 0; j < fifo.length; j++) { + // fifo[j] = new floodfill_t(); + // } + + if (filledcolor == -1) { + filledcolor = 0; + // attempt to find opaque black + for (i = 0; i < 256; ++i) + // TODO check this + if (d_8to24table[i] == 0xFF000000) { // alpha 1.0 + //if (d_8to24table[i] == (255 << 0)) // alpha 1.0 + filledcolor = i; + break; + } + } + + // can't fill to filled color or to transparent color (used as visited + // marker) + if ((fillcolor == filledcolor) || (fillcolor == 255)) { + return; + } + + fifo[inpt].x = 0; + fifo[inpt].y = 0; + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + + while (outpt != inpt) { + int x = fifo[outpt].x; + int y = fifo[outpt].y; + int fdc = filledcolor; + // byte *pos = &skin[x + skinwidth * y]; + int pos = x + skinwidth * y; + // + outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; + + int off, dx, dy; + + if (x > 0) { + // FLOODFILL_STEP( -1, -1, 0 ); + off = -1; + dx = -1; + dy = 0; + if (skin[pos + off] == (byte) fillcolor) { + skin[pos + off] = (byte) 255; + fifo[inpt].x = (short) (x + dx); + fifo[inpt].y = (short) (y + dy); + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + } else if (skin[pos + off] != (byte) 255) + fdc = skin[pos + off] & 0xff; + } + + if (x < skinwidth - 1) { + // FLOODFILL_STEP( 1, 1, 0 ); + off = 1; + dx = 1; + dy = 0; + if (skin[pos + off] == (byte) fillcolor) { + skin[pos + off] = (byte) 255; + fifo[inpt].x = (short) (x + dx); + fifo[inpt].y = (short) (y + dy); + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + } else if (skin[pos + off] != (byte) 255) + fdc = skin[pos + off] & 0xff; + } + + if (y > 0) { + // FLOODFILL_STEP( -skinwidth, 0, -1 ); + off = -skinwidth; + dx = 0; + dy = -1; + if (skin[pos + off] == (byte) fillcolor) { + skin[pos + off] = (byte) 255; + fifo[inpt].x = (short) (x + dx); + fifo[inpt].y = (short) (y + dy); + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + } else if (skin[pos + off] != (byte) 255) + fdc = skin[pos + off] & 0xff; + } + + if (y < skinheight - 1) { + // FLOODFILL_STEP( skinwidth, 0, 1 ); + off = skinwidth; + dx = 0; + dy = 1; + if (skin[pos + off] == (byte) fillcolor) { + skin[pos + off] = (byte) 255; + fifo[inpt].x = (short) (x + dx); + fifo[inpt].y = (short) (y + dy); + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + } else if (skin[pos + off] != (byte) 255) + fdc = skin[pos + off] & 0xff; + + } + + skin[x + skinwidth * y] = (byte) fdc; + } + } + + // ======================================================= + + /* + * ================ GL_ResampleTexture ================ + */ + // cwei :-) + void GL_ResampleTexture(int[] in, int inwidth, int inheight, int[] out, + int outwidth, int outheight) { + // int i, j; + // unsigned *inrow, *inrow2; + // int frac, fracstep; + // int[] p1 = new int[1024]; + // int[] p2 = new int[1024]; + // + + // *** this source do the same *** + BufferedImage image = new BufferedImage(inwidth, inheight, + BufferedImage.TYPE_INT_ARGB); + + image.setRGB(0, 0, inwidth, inheight, in, 0, inwidth); + + AffineTransformOp op = new AffineTransformOp(AffineTransform + .getScaleInstance(outwidth * 1.0 / inwidth, outheight * 1.0 + / inheight), AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + BufferedImage tmp = op.filter(image, null); + + tmp.getRGB(0, 0, outwidth, outheight, out, 0, outwidth); + + // *** end *** + + // byte *pix1, *pix2, *pix3, *pix4; + // + // fracstep = inwidth*0x10000/outwidth; + // + // frac = fracstep>>2; + // for (i=0 ; i>16); + // frac += fracstep; + // } + // frac = 3*(fracstep>>2); + // for (i=0 ; i>16); + // frac += fracstep; + // } + // + // for (i=0 ; i> 1; + // for (j=0 ; j>2; + // ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; + // ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; + // ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; + // } + // } + } + + /* + * ================ GL_LightScaleTexture + * + * Scale up the pixel values in a texture to increase the lighting range + * ================ + */ + void GL_LightScaleTexture(int[] in, int inwidth, int inheight, + boolean only_gamma) { + if (only_gamma) { + int i, c; + int r, g, b, color; + + c = inwidth * inheight; + for (i = 0; i < c; i++) { + color = in[i]; + r = (color >> 0) & 0xFF; + g = (color >> 8) & 0xFF; + b = (color >> 16) & 0xFF; + + r = gammatable[r] & 0xFF; + g = gammatable[g] & 0xFF; + b = gammatable[b] & 0xFF; + + in[i] = (r << 0) | (g << 8) | (b << 16) | (color & 0xFF000000); + } + } else { + int i, c; + int r, g, b, color; + + c = inwidth * inheight; + for (i = 0; i < c; i++) { + color = in[i]; + r = (color >> 0) & 0xFF; + g = (color >> 8) & 0xFF; + b = (color >> 16) & 0xFF; + + r = gammatable[intensitytable[r] & 0xFF] & 0xFF; + g = gammatable[intensitytable[g] & 0xFF] & 0xFF; + b = gammatable[intensitytable[b] & 0xFF] & 0xFF; + + in[i] = (r << 0) | (g << 8) | (b << 16) | (color & 0xFF000000); + } + + } + } + + /* + * ================ GL_MipMap + * + * Operates in place, quartering the size of the texture ================ + */ + void GL_MipMap(int[] in, int width, int height) { + int i, j; + int[] out; + + out = in; + + int inIndex = 0; + int outIndex = 0; + + int r, g, b, a; + int p1, p2, p3, p4; + + for (i = 0; i < height; i += 2, inIndex += width) { + for (j = 0; j < width; j += 2, outIndex += 1, inIndex += 2) { + + p1 = in[inIndex + 0]; + p2 = in[inIndex + 1]; + p3 = in[inIndex + width + 0]; + p4 = in[inIndex + width + 1]; + + r = (((p1 >> 0) & 0xFF) + ((p2 >> 0) & 0xFF) + + ((p3 >> 0) & 0xFF) + ((p4 >> 0) & 0xFF)) >> 2; + g = (((p1 >> 8) & 0xFF) + ((p2 >> 8) & 0xFF) + + ((p3 >> 8) & 0xFF) + ((p4 >> 8) & 0xFF)) >> 2; + b = (((p1 >> 16) & 0xFF) + ((p2 >> 16) & 0xFF) + + ((p3 >> 16) & 0xFF) + ((p4 >> 16) & 0xFF)) >> 2; + a = (((p1 >> 24) & 0xFF) + ((p2 >> 24) & 0xFF) + + ((p3 >> 24) & 0xFF) + ((p4 >> 24) & 0xFF)) >> 2; + + out[outIndex] = (r << 0) | (g << 8) | (b << 16) | (a << 24); + } + } + } + + /* + * =============== GL_Upload32 + * + * Returns has_alpha =============== + */ + void GL_BuildPalettedTexture(byte[] paletted_texture, int[] scaled, + int scaled_width, int scaled_height) { + + int r, g, b, c; + int size = scaled_width * scaled_height; + + for (int i = 0; i < size; i++) { + + r = (scaled[i] >> 3) & 31; + g = (scaled[i] >> 10) & 63; + b = (scaled[i] >> 19) & 31; + + c = r | (g << 5) | (b << 11); + + paletted_texture[i] = gl_state.d_16to8table[c]; + } + } + + int upload_width, upload_height; + + boolean uploaded_paletted; + + /* + * =============== GL_Upload32 + * + * Returns has_alpha =============== + */ + int[] scaled = new int[256 * 256]; + + byte[] paletted_texture = new byte[256 * 256]; + + IntBuffer tex = Lib.newIntBuffer(512 * 256, ByteOrder.LITTLE_ENDIAN); + + boolean GL_Upload32(int[] data, int width, int height, boolean mipmap) { + int samples; + int scaled_width, scaled_height; + int i, c; + int comp; + + Arrays.fill(scaled, 0); + Arrays.fill(paletted_texture, (byte) 0); + + uploaded_paletted = false; + + for (scaled_width = 1; scaled_width < width; scaled_width <<= 1) + ; + if (gl_round_down.value > 0.0f && scaled_width > width && mipmap) + scaled_width >>= 1; + for (scaled_height = 1; scaled_height < height; scaled_height <<= 1) + ; + if (gl_round_down.value > 0.0f && scaled_height > height && mipmap) + scaled_height >>= 1; + + // let people sample down the world textures for speed + if (mipmap) { + scaled_width >>= (int) gl_picmip.value; + scaled_height >>= (int) gl_picmip.value; + } + + // don't ever bother with >256 textures + if (scaled_width > 256) + scaled_width = 256; + if (scaled_height > 256) + scaled_height = 256; + + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + upload_width = scaled_width; + upload_height = scaled_height; + + if (scaled_width * scaled_height > 256 * 256) + Com.Error(Defines.ERR_DROP, "GL_Upload32: too big"); + + // scan the texture for any non-255 alpha + c = width * height; + samples = gl_solid_format; + + for (i = 0; i < c; i++) { + if ((data[i] & 0xff000000) != 0xff000000) { + samples = gl_alpha_format; + break; + } + } + + if (samples == gl_solid_format) + comp = gl_tex_solid_format; + else if (samples == gl_alpha_format) + comp = gl_tex_alpha_format; + else { + VID.Printf(Defines.PRINT_ALL, + "Unknown number of texture components " + samples + '\n'); + comp = samples; + } + + // simulates a goto + try { + if (scaled_width == width && scaled_height == height) { + if (!mipmap) { + if (qglColorTableEXT + && gl_ext_palettedtexture.value != 0.0f + && samples == gl_solid_format) { + uploaded_paletted = true; + GL_BuildPalettedTexture(paletted_texture, data, + scaled_width, scaled_height); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, + GL_COLOR_INDEX8_EXT, scaled_width, + scaled_height, 0, GL.GL_COLOR_INDEX, + GL.GL_UNSIGNED_BYTE, paletted_texture); + } else { + tex.rewind(); + tex.put(data); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, comp, + scaled_width, scaled_height, 0, GL.GL_RGBA, + GL.GL_UNSIGNED_BYTE, tex); + } + //goto done; + throw new longjmpException(); + } + //memcpy (scaled, data, width*height*4); were bytes + System.arraycopy(data, 0, scaled, 0, width * height); + } else + GL_ResampleTexture(data, width, height, scaled, scaled_width, + scaled_height); + + GL_LightScaleTexture(scaled, scaled_width, scaled_height, !mipmap); + + if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f + && (samples == gl_solid_format)) { + uploaded_paletted = true; + GL_BuildPalettedTexture(paletted_texture, scaled, scaled_width, + scaled_height); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, + scaled_width, scaled_height, 0, GL.GL_COLOR_INDEX, + GL.GL_UNSIGNED_BYTE, paletted_texture); + } else { + tex.rewind(); + tex.put(scaled); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, comp, scaled_width, + scaled_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, tex); + } + + if (mipmap) { + int miplevel; + miplevel = 0; + while (scaled_width > 1 || scaled_height > 1) { + GL_MipMap(scaled, scaled_width, scaled_height); + scaled_width >>= 1; + scaled_height >>= 1; + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + miplevel++; + if (qglColorTableEXT + && gl_ext_palettedtexture.value != 0.0f + && samples == gl_solid_format) { + uploaded_paletted = true; + GL_BuildPalettedTexture(paletted_texture, scaled, + scaled_width, scaled_height); + gl.glTexImage2D(GL.GL_TEXTURE_2D, miplevel, + GL_COLOR_INDEX8_EXT, scaled_width, + scaled_height, 0, GL.GL_COLOR_INDEX, + GL.GL_UNSIGNED_BYTE, paletted_texture); + } else { + tex.rewind(); + tex.put(scaled); + gl.glTexImage2D(GL.GL_TEXTURE_2D, miplevel, comp, + scaled_width, scaled_height, 0, GL.GL_RGBA, + GL.GL_UNSIGNED_BYTE, tex); + } + } + } + // label done: + } catch (longjmpException e) { + ; // replaces label done + } + + if (mipmap) { + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + gl_filter_min); + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + gl_filter_max); + } else { + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + gl_filter_max); + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + gl_filter_max); + } + + return (samples == gl_alpha_format); + } + + /* + * =============== GL_Upload8 + * + * Returns has_alpha =============== + */ + + int[] trans = new int[512 * 256]; + + boolean GL_Upload8(byte[] data, int width, int height, boolean mipmap, + boolean is_sky) { + + Arrays.fill(trans, 0); + + int s = width * height; + + if (s > trans.length) + Com.Error(Defines.ERR_DROP, "GL_Upload8: too large"); + + if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && is_sky) { + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, width, + height, 0, GL.GL_COLOR_INDEX, GL.GL_UNSIGNED_BYTE, data); + + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + gl_filter_max); + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + gl_filter_max); + + // TODO check this + return false; + } else { + int p; + int rgb; + for (int i = 0; i < s; i++) { + p = data[i] & 0xff; + trans[i] = d_8to24table[p]; + + if (p == 255) { // transparent, so scan around for another color + // to avoid alpha fringes + // FIXME: do a full flood fill so mips work... + if (i > width && (data[i - width] & 0xff) != 255) + p = data[i - width] & 0xff; + else if (i < s - width && (data[i + width] & 0xff) != 255) + p = data[i + width] & 0xff; + else if (i > 0 && (data[i - 1] & 0xff) != 255) + p = data[i - 1] & 0xff; + else if (i < s - 1 && (data[i + 1] & 0xff) != 255) + p = data[i + 1] & 0xff; + else + p = 0; + // copy rgb components + + // ((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0]; + // ((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1]; + // ((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2]; + + trans[i] = d_8to24table[p] & 0x00FFFFFF; // only rgb + } + } + + return GL_Upload32(trans, width, height, mipmap); + } + } + + /* + * ================ GL_LoadPic + * + * This is also used as an entry point for the generated r_notexture + * ================ + */ + image_t GL_LoadPic(String name, byte[] pic, int width, int height, + int type, int bits) { + image_t image; + int i; + + // find a free image_t + for (i = 0; i < numgltextures; i++) { + image = gltextures[i]; + if (image.texnum == 0) + break; + } + + if (i == numgltextures) { + if (numgltextures == MAX_GLTEXTURES) + Com.Error(Defines.ERR_DROP, "MAX_GLTEXTURES"); + + numgltextures++; + } + image = gltextures[i]; + + if (name.length() > Defines.MAX_QPATH) + Com.Error(Defines.ERR_DROP, "Draw_LoadPic: \"" + name + + "\" is too long"); + + image.name = name; + image.registration_sequence = registration_sequence; + + image.width = width; + image.height = height; + image.type = type; + + if (type == it_skin && bits == 8) + R_FloodFillSkin(pic, width, height); + + // load little pics into the scrap + if (image.type == it_pic && bits == 8 && image.width < 64 + && image.height < 64) { + pos_t pos = new pos_t(0, 0); + int j, k; + + int texnum = Scrap_AllocBlock(image.width, image.height, pos); + + if (texnum == -1) { + // replace goto nonscrap + + image.scrap = false; + + image.texnum = TEXNUM_IMAGES + image.getId(); // image pos in + // array + GL_Bind(image.texnum); + + if (bits == 8) { + image.has_alpha = GL_Upload8(pic, width, height, + (image.type != it_pic && image.type != it_sky), + image.type == it_sky); + } else { + int[] tmp = new int[pic.length / 4]; + + for (i = 0; i < tmp.length; i++) { + tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0); // & + // 0x000000FF; + tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8); // & + // 0x0000FF00; + tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16); // & + // 0x00FF0000; + tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24); // & + // 0xFF000000; + } + + image.has_alpha = GL_Upload32(tmp, width, height, + (image.type != it_pic && image.type != it_sky)); + } + + image.upload_width = upload_width; // after power of 2 and + // scales + image.upload_height = upload_height; + image.paletted = uploaded_paletted; + image.sl = 0; + image.sh = 1; + image.tl = 0; + image.th = 1; + + return image; + } + + scrap_dirty = true; + + // copy the texels into the scrap block + k = 0; + for (i = 0; i < image.height; i++) + for (j = 0; j < image.width; j++, k++) + scrap_texels[texnum][(pos.y + i) * BLOCK_WIDTH + pos.x + j] = pic[k]; + + image.texnum = TEXNUM_SCRAPS + texnum; + image.scrap = true; + image.has_alpha = true; + image.sl = (pos.x + 0.01f) / (float) BLOCK_WIDTH; + image.sh = (pos.x + image.width - 0.01f) / (float) BLOCK_WIDTH; + image.tl = (pos.y + 0.01f) / (float) BLOCK_WIDTH; + image.th = (pos.y + image.height - 0.01f) / (float) BLOCK_WIDTH; + + } else { + // this was label nonscrap + + image.scrap = false; + + image.texnum = TEXNUM_IMAGES + image.getId(); //image pos in array + GL_Bind(image.texnum); + + if (bits == 8) { + image.has_alpha = GL_Upload8(pic, width, height, + (image.type != it_pic && image.type != it_sky), + image.type == it_sky); + } else { + int[] tmp = new int[pic.length / 4]; + + for (i = 0; i < tmp.length; i++) { + tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0); // & 0x000000FF; + tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8); // & 0x0000FF00; + tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16); // & 0x00FF0000; + tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24); // & 0xFF000000; + } + + image.has_alpha = GL_Upload32(tmp, width, height, + (image.type != it_pic && image.type != it_sky)); + } + image.upload_width = upload_width; // after power of 2 and scales + image.upload_height = upload_height; + image.paletted = uploaded_paletted; + image.sl = 0; + image.sh = 1; + image.tl = 0; + image.th = 1; + } + return image; + } + + /* + * ================ GL_LoadWal ================ + */ + image_t GL_LoadWal(String name) { + + image_t image = null; + + byte[] raw = FS.LoadFile(name); + if (raw == null) { + VID.Printf(Defines.PRINT_ALL, "GL_FindImage: can't load " + name + + '\n'); + return r_notexture; + } + + qfiles.miptex_t mt = new qfiles.miptex_t(raw); + + byte[] pix = new byte[mt.width * mt.height]; + System.arraycopy(raw, mt.offsets[0], pix, 0, pix.length); + + image = GL_LoadPic(name, pix, mt.width, mt.height, it_wall, 8); + + return image; + } + + /* + * =============== GL_FindImage + * + * Finds or loads the given image =============== + */ + image_t GL_FindImage(String name, int type) { + image_t image = null; + + // // TODO loest das grossschreibungs problem + // name = name.toLowerCase(); + // // bughack for bad strings (fuck \0) + // int index = name.indexOf('\0'); + // if (index != -1) + // name = name.substring(0, index); + + if (name == null || name.length() < 5) + return null; // Com.Error (ERR_DROP, "GL_FindImage: NULL name"); + // Com.Error (ERR_DROP, "GL_FindImage: bad name: %s", name); + + // look for it + for (int i = 0; i < numgltextures; i++) { + image = gltextures[i]; + if (name.equals(image.name)) { + image.registration_sequence = registration_sequence; + return image; + } + } + + // + // load the pic from disk + // + image = null; + byte[] pic = null; + Dimension dim = new Dimension(); + + if (name.endsWith(".pcx")) { + + pic = LoadPCX(name, null, dim); + if (pic == null) + return null; + image = GL_LoadPic(name, pic, dim.width, dim.height, type, 8); + + } else if (name.endsWith(".wal")) { + + image = GL_LoadWal(name); + + } else if (name.endsWith(".tga")) { + + pic = LoadTGA(name, dim); + + if (pic == null) + return null; + + image = GL_LoadPic(name, pic, dim.width, dim.height, type, 32); + + } + + return image; + } + + /* + * =============== R_RegisterSkin =============== + */ + protected image_t R_RegisterSkin(String name) { + return GL_FindImage(name, it_skin); + } + + /* + * ================ GL_FreeUnusedImages + * + * Any image that was not touched on this registration sequence will be + * freed. ================ + */ + void GL_FreeUnusedImages() { + + // never free r_notexture or particle texture + r_notexture.registration_sequence = registration_sequence; + r_particletexture.registration_sequence = registration_sequence; + + image_t image = null; + + for (int i = 0; i < numgltextures; i++) { + image = gltextures[i]; + // used this sequence + if (image.registration_sequence == registration_sequence) + continue; + // free image_t slot + if (image.registration_sequence == 0) + continue; + // don't free pics + if (image.type == it_pic) + continue; + + // free it + // TODO jogl bug + gl.glDeleteTextures(1, new int[] { image.texnum }); + image.clear(); + } + } + + /* + * =============== Draw_GetPalette =============== + */ + protected void Draw_GetPalette() { + int r, g, b; + Dimension dim; + byte[] pic; + byte[][] palette = new byte[1][]; //new byte[768]; + + // get the palette + + pic = LoadPCX("pics/colormap.pcx", palette, dim = new Dimension()); + + if (palette[0] == null || palette[0].length != 768) + Com.Error(Defines.ERR_FATAL, "Couldn't load pics/colormap.pcx"); + + byte[] pal = palette[0]; + + int j = 0; + for (int i = 0; i < 256; i++) { + r = pal[j++] & 0xFF; + g = pal[j++] & 0xFF; + b = pal[j++] & 0xFF; + + d_8to24table[i] = (255 << 24) | (b << 16) | (g << 8) | (r << 0); + } + + d_8to24table[255] &= 0x00FFFFFF; // 255 is transparent + + particle_t.setColorPalette(d_8to24table); + } + + /* + * =============== GL_InitImages =============== + */ + void GL_InitImages() { + int i, j; + float g = vid_gamma.value; + + registration_sequence = 1; + + // init intensity conversions + intensity = Cvar.Get("intensity", "2", 0); + + if (intensity.value <= 1) + Cvar.Set("intensity", "1"); + + gl_state.inverse_intensity = 1 / intensity.value; + + Draw_GetPalette(); + + if (qglColorTableEXT) { + gl_state.d_16to8table = FS.LoadFile("pics/16to8.dat"); + if (gl_state.d_16to8table == null) + Com.Error(Defines.ERR_FATAL, "Couldn't load pics/16to8.pcx"); + } + + if ((gl_config.renderer & (GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2)) != 0) { + g = 1.0F; + } + + for (i = 0; i < 256; i++) { + + if (g == 1.0f) { + gammatable[i] = (byte) i; + } else { + + int inf = (int) (255.0f * Math.pow((i + 0.5) / 255.5, g) + 0.5); + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + gammatable[i] = (byte) inf; + } + } + + for (i = 0; i < 256; i++) { + j = (int) (i * intensity.value); + if (j > 255) + j = 255; + intensitytable[i] = (byte) j; + } + } + + /* + * =============== GL_ShutdownImages =============== + */ + void GL_ShutdownImages() { + image_t image; + + for (int i = 0; i < numgltextures; i++) { + image = gltextures[i]; + + if (image.registration_sequence == 0) + continue; // free image_t slot + // free it + // TODO jogl bug + gl.glDeleteTextures(1, new int[] { image.texnum }); + image.clear(); + } + } + +} \ No newline at end of file diff --git a/src/jake2/render/fastjogl/Light.java b/src/jake2/render/fastjogl/Light.java index 7dee8fe..97d0e18 100644 --- a/src/jake2/render/fastjogl/Light.java +++ b/src/jake2/render/fastjogl/Light.java @@ -2,37 +2,38 @@ * Light.java * Copyright (C) 2003 * - * $Id: Light.java,v 1.8 2004-09-10 19:02:52 salomo Exp $ + * $Id: Light.java,v 1.9 2004-09-22 19:22:11 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.render.fastjogl; import jake2.Defines; import jake2.Globals; import jake2.client.dlight_t; -import jake2.game.GameBase; import jake2.game.cplane_t; import jake2.qcommon.Com; import jake2.qcommon.longjmpException; -import jake2.render.*; +import jake2.render.mnode_t; +import jake2.render.msurface_t; +import jake2.render.mtexinfo_t; import jake2.util.Math3D; import java.nio.ByteBuffer; @@ -43,720 +44,673 @@ import net.java.games.jogl.GL; /** * Light - * + * * @author cwei */ public abstract class Light extends Warp { - // r_light.c - - int r_dlightframecount; - - static final int DLIGHT_CUTOFF = 64; - - /* - ============================================================================= - - DYNAMIC LIGHTS BLEND RENDERING - - ============================================================================= - */ - - void R_RenderDlight (dlight_t light) - { - int i, j; - float a; - float[] v = {0, 0, 0}; - float rad; - - rad = light.intensity * 0.35f; - - Math3D.VectorSubtract (light.origin, r_origin, v); - - gl.glBegin (GL.GL_TRIANGLE_FAN); - gl.glColor3f (light.color[0]*0.2f, light.color[1]*0.2f, light.color[2]*0.2f); - for (i=0 ; i<3 ; i++) - v[i] = light.origin[i] - vpn[i]*rad; - gl.glVertex3f(v[0], v[1], v[2]); - gl.glColor3f (0,0,0); - for (i=16 ; i>=0 ; i--) - { - a = (float)(i/16.0f * Math.PI*2); - for (j=0 ; j<3 ; j++) - v[j] = (float)(light.origin[j] + vright[j]*Math.cos(a)*rad - + vup[j]*Math.sin(a)*rad); - gl.glVertex3f(v[0], v[1], v[2]); - } - gl.glEnd (); - } - - /* - ============= - R_RenderDlights - ============= - */ - void R_RenderDlights() - { - if (gl_flashblend.value == 0) - return; - - r_dlightframecount = r_framecount + 1; // because the count hasn't - // advanced yet for this frame - gl.glDepthMask(false); - gl.glDisable(GL.GL_TEXTURE_2D); - gl.glShadeModel (GL.GL_SMOOTH); - gl.glEnable (GL.GL_BLEND); - gl.glBlendFunc (GL.GL_ONE, GL.GL_ONE); - - for (int i=0 ; i light.intensity - DLIGHT_CUTOFF) - { - R_MarkLights (light, bit, node.children[0]); - return; - } - if (dist < -light.intensity + DLIGHT_CUTOFF) - { - R_MarkLights (light, bit, node.children[1]); - return; - } - - // mark the polygons - for (i=0 ; i= 0) ? 0 : Defines.SURF_PLANEBACK; - if ( (surf.flags & Defines.SURF_PLANEBACK) != sidebit ) - continue; - /* - * cwei - * bugfix end - */ - - if (surf.dlightframe != r_dlightframecount) - { - surf.dlightbits = 0; - surf.dlightframe = r_dlightframecount; - } - surf.dlightbits |= bit; - } - - R_MarkLights (light, bit, node.children[0]); - R_MarkLights (light, bit, node.children[1]); - } - - - /* - ============= - R_PushDlights - ============= - */ - void R_PushDlights() - { - int i; - dlight_t l; - - if (gl_flashblend.value != 0) - return; - - r_dlightframecount = r_framecount + 1; // because the count hasn't - // advanced yet for this frame - for (i=0 ; i= 0) - return r; // hit something - - if ( (back < 0) == side ) - return -1; // didn't hit anuthing - - // check for impact on this node - Math3D.VectorCopy (mid, lightspot); - lightplane = plane; - - int surfIndex = node.firstsurface; - float[] scale = {0, 0, 0}; - for (i=0 ; i surf.extents[0] || dt > surf.extents[1] ) - continue; - - if (surf.samples == null) - return 0; - - ds >>= 4; - dt >>= 4; - - lightmap = surf.samples; - int lightmapIndex = 0; - - Math3D.VectorCopy (Globals.vec3_origin, pointcolor); - if (lightmap != null) - { - //float[] scale = {0, 0, 0}; - float[] rgb; - lightmapIndex += 3 * (dt * ((surf.extents[0] >> 4) + 1) + ds); - - for (maps = 0 ; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255; maps++) - { - rgb = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb; - scale[0] = gl_modulate.value * rgb[0]; - scale[1] = gl_modulate.value * rgb[1]; - scale[2] = gl_modulate.value * rgb[2]; - - pointcolor[0] += (lightmap.get(lightmapIndex + 0) & 0xFF) * scale[0] * (1.0f/255); - pointcolor[1] += (lightmap.get(lightmapIndex + 1) & 0xFF) * scale[1] * (1.0f/255); - pointcolor[2] += (lightmap.get(lightmapIndex + 2) & 0xFF) * scale[2] * (1.0f/255); - lightmapIndex += 3 * ((surf.extents[0] >> 4) + 1) * ((surf.extents[1] >> 4) + 1); - } - } - return 1; - } - - // go down back side - return RecursiveLightPoint (node.children[1 - sideIndex], mid, end); - } - - /* - =============== - R_LightPoint - =============== - */ - void R_LightPoint (float[] p, float[] color) - { - assert (p.length == 3) : "vec3_t bug"; - assert (color.length == 3) : "rgb bug"; - - float[] end = {0, 0, 0}; - dlight_t dl; - float add; - - if (r_worldmodel.lightdata == null) - { - color[0] = color[1] = color[2] = 1.0f; - return; - } - - end[0] = p[0]; - end[1] = p[1]; - end[2] = p[2] - 2048; - - float r = RecursiveLightPoint(r_worldmodel.nodes[0], p, end); - - if (r == -1) - { - Math3D.VectorCopy (GameBase.vec3_origin, color); - } - else - { - Math3D.VectorCopy (pointcolor, color); - } - - // - // add dynamic lights - // - for (int lnum=0 ; lnum 0) - { - Math3D.VectorMA (color, add, dl.color, color); - } - } - - Math3D.VectorScale (color, gl_modulate.value, color); - } - -// =================================================================== - - float[] s_blocklights = new float[34 * 34 * 3]; - - /* - =============== - R_AddDynamicLights - =============== - */ - // TODO sync with jogl renderer. hoz - void R_AddDynamicLights(msurface_t surf) - { - int sd, td; - float fdist, frad, fminlight; - float[] impact = {0, 0, 0}; - float[] local = {0, 0, 0}; - int s, t; - dlight_t dl; - float[] pfBL; - float fsacc, ftacc; - - int smax = (surf.extents[0]>>4)+1; - int tmax = (surf.extents[1]>>4)+1; - mtexinfo_t tex = surf.texinfo; - - for (int lnum=0 ; lnum td) - fdist = sd + (td>>1); - else - fdist = td + (sd>>1); - - if ( fdist < fminlight ) - { - pfBL[pfBLindex + 0] += ( frad - fdist ) * dl.color[0]; - pfBL[pfBLindex + 1] += ( frad - fdist ) * dl.color[1]; - pfBL[pfBLindex + 2] += ( frad - fdist ) * dl.color[2]; - } - } - } - } - } - - - /* - ** R_SetCacheState - */ - void R_SetCacheState( msurface_t surf ) - { - for (int maps = 0 ; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255 ; maps++) - { - surf.cached_light[maps] = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].white; - } - } - - /* - =============== - R_BuildLightMap - - Combine and scale multiple lightmaps into the floating format in blocklights - =============== - */ -// TODO sync with jogl renderer. hoz - void R_BuildLightMap(msurface_t surf, IntBuffer dest, int stride) - { - int r, g, b, a, max; - int i, j; - ByteBuffer lightmap; - float[] scale = {0, 0, 0}; - int nummaps; - float[] bl; - //lightstyle_t style; - - if ( (surf.texinfo.flags & (Defines.SURF_SKY | Defines.SURF_TRANS33 | Defines.SURF_TRANS66 | Defines.SURF_WARP)) != 0 ) - Com.Error(Defines.ERR_DROP, "R_BuildLightMap called for non-lit surface"); - - int smax = (surf.extents[0] >> 4) + 1; - int tmax = (surf.extents[1] >> 4) + 1; - int size = smax * tmax; - if (size > ((s_blocklights.length * Defines.SIZE_OF_FLOAT) >> 4) ) - Com.Error(Defines.ERR_DROP, "Bad s_blocklights size"); - - try { - // set to full bright if no light data - if (surf.samples == null) - { - int maps; - - for (i=0 ; i g) - max = r; - else - max = g; - if (b > max) - max = b; - - /* - ** alpha is ONLY used for the mono lightmap case. For this reason - ** we set it to the brightest of the color components so that - ** things don't get too dim. - */ - a = max; - - /* - ** rescale all the color components if the intensity of the greatest - ** channel exceeds 1.0 - */ - if (max > 255) - { - float t = 255.0F / max; - - r = (int)(r*t); - g = (int)(g*t); - b = (int)(b*t); - a = (int)(a*t); - } - //r &= 0xFF; g &= 0xFF; b &= 0xFF; a &= 0xFF; - dest.put(destp++, (a << 24) | (b << 16) | (g << 8) | (r << 0)); - } - } - } - else - { - for (i=0 ; i g) - max = r; - else - max = g; - if (b > max) - max = b; - - /* - ** alpha is ONLY used for the mono lightmap case. For this reason - ** we set it to the brightest of the color components so that - ** things don't get too dim. - */ - a = max; - - /* - ** rescale all the color components if the intensity of the greatest - ** channel exceeds 1.0 - */ - if (max > 255) - { - float t = 255.0F / max; - - r = (int)(r*t); - g = (int)(g*t); - b = (int)(b*t); - a = (int)(a*t); - } - - /* - ** So if we are doing alpha lightmaps we need to set the R, G, and B - ** components to 0 and we need to set alpha to 1-alpha. - */ - switch ( monolightmap ) - { - case 'L': - case 'I': - r = a; - g = b = 0; - break; - case 'C': - // try faking colored lighting - a = 255 - ((r+g+b)/3); - r *= a/255.0f; - g *= a/255.0f; - b *= a/255.0f; - break; - case 'A': - default: - r = g = b = 0; - a = 255 - a; - break; - } - //r &= 0xFF; g &= 0xFF; b &= 0xFF; a &= 0xFF; - dest.put(destp++, (a << 24) | (b << 16) | (g << 8) | (r << 0)); - } - } - } - } -} + // r_light.c + + int r_dlightframecount; + + static final int DLIGHT_CUTOFF = 64; + + /* + * ============================================================================= + * + * DYNAMIC LIGHTS BLEND RENDERING + * + * ============================================================================= + */ + + void R_RenderDlight(dlight_t light) { + int i, j; + float a; + float[] v = { 0, 0, 0 }; + float rad; + + rad = light.intensity * 0.35f; + + Math3D.VectorSubtract(light.origin, r_origin, v); + + gl.glBegin(GL.GL_TRIANGLE_FAN); + gl.glColor3f(light.color[0] * 0.2f, light.color[1] * 0.2f, + light.color[2] * 0.2f); + for (i = 0; i < 3; i++) + v[i] = light.origin[i] - vpn[i] * rad; + gl.glVertex3f(v[0], v[1], v[2]); + gl.glColor3f(0, 0, 0); + for (i = 16; i >= 0; i--) { + a = (float) (i / 16.0f * Math.PI * 2); + for (j = 0; j < 3; j++) + v[j] = (float) (light.origin[j] + vright[j] * Math.cos(a) * rad + vup[j] + * Math.sin(a) * rad); + gl.glVertex3f(v[0], v[1], v[2]); + } + gl.glEnd(); + } + + /* + * ============= R_RenderDlights ============= + */ + void R_RenderDlights() { + if (gl_flashblend.value == 0) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + gl.glDepthMask(false); + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glShadeModel(GL.GL_SMOOTH); + gl.glEnable(GL.GL_BLEND); + gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE); + + for (int i = 0; i < r_newrefdef.num_dlights; i++) { + R_RenderDlight(r_newrefdef.dlights[i]); + } + + gl.glColor3f(1, 1, 1); + gl.glDisable(GL.GL_BLEND); + gl.glEnable(GL.GL_TEXTURE_2D); + gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); + gl.glDepthMask(true); + } + + /* + * ============================================================================= + * + * DYNAMIC LIGHTS + * + * ============================================================================= + */ + + /* + * ============= R_MarkLights ============= + */ + void R_MarkLights(dlight_t light, int bit, mnode_t node) { + cplane_t splitplane; + float dist; + msurface_t surf; + int i; + int sidebit; + + if (node.contents != -1) + return; + + splitplane = node.plane; + dist = Math3D.DotProduct(light.origin, splitplane.normal) + - splitplane.dist; + + if (dist > light.intensity - DLIGHT_CUTOFF) { + R_MarkLights(light, bit, node.children[0]); + return; + } + if (dist < -light.intensity + DLIGHT_CUTOFF) { + R_MarkLights(light, bit, node.children[1]); + return; + } + + // mark the polygons + for (i = 0; i < node.numsurfaces; i++) { + + surf = r_worldmodel.surfaces[node.firstsurface + i]; + + /* + * cwei bugfix for dlight behind the walls + */ + dist = Math3D.DotProduct(light.origin, surf.plane.normal) + - surf.plane.dist; + sidebit = (dist >= 0) ? 0 : Defines.SURF_PLANEBACK; + if ((surf.flags & Defines.SURF_PLANEBACK) != sidebit) + continue; + /* + * cwei bugfix end + */ + + if (surf.dlightframe != r_dlightframecount) { + surf.dlightbits = 0; + surf.dlightframe = r_dlightframecount; + } + surf.dlightbits |= bit; + } + + R_MarkLights(light, bit, node.children[0]); + R_MarkLights(light, bit, node.children[1]); + } + + /* + * ============= R_PushDlights ============= + */ + void R_PushDlights() { + int i; + dlight_t l; + + if (gl_flashblend.value != 0) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + for (i = 0; i < r_newrefdef.num_dlights; i++) { + l = r_newrefdef.dlights[i]; + R_MarkLights(l, 1 << i, r_worldmodel.nodes[0]); + } + } + + /* + * ============================================================================= + * + * LIGHT SAMPLING + * + * ============================================================================= + */ + + float[] pointcolor = { 0, 0, 0 }; // vec3_t + + cplane_t lightplane; // used as shadow plane + + float[] lightspot = { 0, 0, 0 }; // vec3_t + + int RecursiveLightPoint(mnode_t node, float[] start, float[] end) { + if (node.contents != -1) + return -1; // didn't hit anything + + msurface_t surf; + int s, t, ds, dt; + int i; + mtexinfo_t tex; + ByteBuffer lightmap; + int maps; + float[] mid = { 0, 0, 0 }; + + // calculate mid point + + // FIXME: optimize for axial + cplane_t plane = node.plane; + float front = Math3D.DotProduct(start, plane.normal) - plane.dist; + float back = Math3D.DotProduct(end, plane.normal) - plane.dist; + boolean side = (front < 0); + int sideIndex = (side) ? 1 : 0; + + if ((back < 0) == side) + return RecursiveLightPoint(node.children[sideIndex], start, end); + + float frac = front / (front - back); + mid[0] = start[0] + (end[0] - start[0]) * frac; + mid[1] = start[1] + (end[1] - start[1]) * frac; + mid[2] = start[2] + (end[2] - start[2]) * frac; + + // go down front side + int r = RecursiveLightPoint(node.children[sideIndex], start, mid); + if (r >= 0) + return r; // hit something + + if ((back < 0) == side) + return -1; // didn't hit anuthing + + // check for impact on this node + Math3D.VectorCopy(mid, lightspot); + lightplane = plane; + + int surfIndex = node.firstsurface; + float[] scale = { 0, 0, 0 }; + for (i = 0; i < node.numsurfaces; i++, surfIndex++) { + surf = r_worldmodel.surfaces[surfIndex]; + + if ((surf.flags & (Defines.SURF_DRAWTURB | Defines.SURF_DRAWSKY)) != 0) + continue; // no lightmaps + + tex = surf.texinfo; + + s = (int) (Math3D.DotProduct(mid, tex.vecs[0]) + tex.vecs[0][3]); + t = (int) (Math3D.DotProduct(mid, tex.vecs[1]) + tex.vecs[1][3]); + + if (s < surf.texturemins[0] || t < surf.texturemins[1]) + continue; + + ds = s - surf.texturemins[0]; + dt = t - surf.texturemins[1]; + + if (ds > surf.extents[0] || dt > surf.extents[1]) + continue; + + if (surf.samples == null) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf.samples; + int lightmapIndex = 0; + + Math3D.VectorCopy(Globals.vec3_origin, pointcolor); + if (lightmap != null) { + //float[] scale = {0, 0, 0}; + float[] rgb; + lightmapIndex += 3 * (dt * ((surf.extents[0] >> 4) + 1) + ds); + + for (maps = 0; maps < Defines.MAXLIGHTMAPS + && surf.styles[maps] != (byte) 255; maps++) { + rgb = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb; + scale[0] = gl_modulate.value * rgb[0]; + scale[1] = gl_modulate.value * rgb[1]; + scale[2] = gl_modulate.value * rgb[2]; + + pointcolor[0] += (lightmap.get(lightmapIndex + 0) & 0xFF) + * scale[0] * (1.0f / 255); + pointcolor[1] += (lightmap.get(lightmapIndex + 1) & 0xFF) + * scale[1] * (1.0f / 255); + pointcolor[2] += (lightmap.get(lightmapIndex + 2) & 0xFF) + * scale[2] * (1.0f / 255); + lightmapIndex += 3 * ((surf.extents[0] >> 4) + 1) + * ((surf.extents[1] >> 4) + 1); + } + } + return 1; + } + + // go down back side + return RecursiveLightPoint(node.children[1 - sideIndex], mid, end); + } + + /* + * =============== R_LightPoint =============== + */ + void R_LightPoint(float[] p, float[] color) { + assert (p.length == 3) : "vec3_t bug"; + assert (color.length == 3) : "rgb bug"; + + float[] end = { 0, 0, 0 }; + dlight_t dl; + float add; + + if (r_worldmodel.lightdata == null) { + color[0] = color[1] = color[2] = 1.0f; + return; + } + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 2048; + + float r = RecursiveLightPoint(r_worldmodel.nodes[0], p, end); + + if (r == -1) { + Math3D.VectorCopy(Globals.vec3_origin, color); + } else { + Math3D.VectorCopy(pointcolor, color); + } + + // + // add dynamic lights + // + for (int lnum = 0; lnum < r_newrefdef.num_dlights; lnum++) { + dl = r_newrefdef.dlights[lnum]; + + Math3D.VectorSubtract(currententity.origin, dl.origin, end); + add = dl.intensity - Math3D.VectorLength(end); + add *= (1.0f / 256); + if (add > 0) { + Math3D.VectorMA(color, add, dl.color, color); + } + } + + Math3D.VectorScale(color, gl_modulate.value, color); + } + + // =================================================================== + + float[] s_blocklights = new float[34 * 34 * 3]; + + /* + * =============== R_AddDynamicLights =============== + */ + // TODO sync with jogl renderer. hoz + void R_AddDynamicLights(msurface_t surf) { + int sd, td; + float fdist, frad, fminlight; + float[] impact = { 0, 0, 0 }; + float[] local = { 0, 0, 0 }; + int s, t; + dlight_t dl; + float[] pfBL; + float fsacc, ftacc; + + int smax = (surf.extents[0] >> 4) + 1; + int tmax = (surf.extents[1] >> 4) + 1; + mtexinfo_t tex = surf.texinfo; + + for (int lnum = 0; lnum < r_newrefdef.num_dlights; lnum++) { + if ((surf.dlightbits & (1 << lnum)) == 0) + continue; // not lit by this light + + dl = r_newrefdef.dlights[lnum]; + frad = dl.intensity; + fdist = Math3D.DotProduct(dl.origin, surf.plane.normal) + - surf.plane.dist; + frad -= Math.abs(fdist); + // rad is now the highest intensity on the plane + + fminlight = DLIGHT_CUTOFF; // FIXME: make configurable? + if (frad < fminlight) + continue; + fminlight = frad - fminlight; + + for (int i = 0; i < 3; i++) { + impact[i] = dl.origin[i] - surf.plane.normal[i] * fdist; + } + + local[0] = Math3D.DotProduct(impact, tex.vecs[0]) + tex.vecs[0][3] + - surf.texturemins[0]; + local[1] = Math3D.DotProduct(impact, tex.vecs[1]) + tex.vecs[1][3] + - surf.texturemins[1]; + + pfBL = s_blocklights; + int pfBLindex = 0; + for (t = 0, ftacc = 0; t < tmax; t++, ftacc += 16) { + td = (int) (local[1] - ftacc); + if (td < 0) + td = -td; + + for (s = 0, fsacc = 0; s < smax; s++, fsacc += 16, pfBLindex += 3) { + sd = (int) (local[0] - fsacc); + + if (sd < 0) + sd = -sd; + + if (sd > td) + fdist = sd + (td >> 1); + else + fdist = td + (sd >> 1); + + if (fdist < fminlight) { + pfBL[pfBLindex + 0] += (frad - fdist) * dl.color[0]; + pfBL[pfBLindex + 1] += (frad - fdist) * dl.color[1]; + pfBL[pfBLindex + 2] += (frad - fdist) * dl.color[2]; + } + } + } + } + } + + /* + * * R_SetCacheState + */ + void R_SetCacheState(msurface_t surf) { + for (int maps = 0; maps < Defines.MAXLIGHTMAPS + && surf.styles[maps] != (byte) 255; maps++) { + surf.cached_light[maps] = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].white; + } + } + + /* + * =============== R_BuildLightMap + * + * Combine and scale multiple lightmaps into the floating format in + * blocklights =============== + */ + // TODO sync with jogl renderer. hoz + void R_BuildLightMap(msurface_t surf, IntBuffer dest, int stride) { + int r, g, b, a, max; + int i, j; + ByteBuffer lightmap; + float[] scale = { 0, 0, 0 }; + int nummaps; + float[] bl; + //lightstyle_t style; + + if ((surf.texinfo.flags & (Defines.SURF_SKY | Defines.SURF_TRANS33 + | Defines.SURF_TRANS66 | Defines.SURF_WARP)) != 0) + Com.Error(Defines.ERR_DROP, + "R_BuildLightMap called for non-lit surface"); + + int smax = (surf.extents[0] >> 4) + 1; + int tmax = (surf.extents[1] >> 4) + 1; + int size = smax * tmax; + if (size > ((s_blocklights.length * Defines.SIZE_OF_FLOAT) >> 4)) + Com.Error(Defines.ERR_DROP, "Bad s_blocklights size"); + + try { + // set to full bright if no light data + if (surf.samples == null) { + int maps; + + for (i = 0; i < size * 3; i++) + s_blocklights[i] = 255; + + // TODO useless? hoz + // for (maps = 0 ; maps < Defines.MAXLIGHTMAPS && + // surf.styles[maps] != (byte)255; maps++) + // { + // style = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF]; + // } + + // goto store; + throw new longjmpException(); + } + + // count the # of maps + for (nummaps = 0; nummaps < Defines.MAXLIGHTMAPS + && surf.styles[nummaps] != (byte) 255; nummaps++) + ; + + lightmap = surf.samples; + int lightmapIndex = 0; + + // add all the lightmaps + if (nummaps == 1) { + int maps; + + for (maps = 0; maps < Defines.MAXLIGHTMAPS + && surf.styles[maps] != (byte) 255; maps++) { + bl = s_blocklights; + int blp = 0; + + for (i = 0; i < 3; i++) + scale[i] = gl_modulate.value + * r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb[i]; + + if (scale[0] == 1.0F && scale[1] == 1.0F + && scale[2] == 1.0F) { + for (i = 0; i < size; i++) { + bl[blp++] = lightmap.get(lightmapIndex++) & 0xFF; + bl[blp++] = lightmap.get(lightmapIndex++) & 0xFF; + bl[blp++] = lightmap.get(lightmapIndex++) & 0xFF; + } + } else { + for (i = 0; i < size; i++) { + bl[blp++] = (lightmap.get(lightmapIndex++) & 0xFF) + * scale[0]; + bl[blp++] = (lightmap.get(lightmapIndex++) & 0xFF) + * scale[1]; + bl[blp++] = (lightmap.get(lightmapIndex++) & 0xFF) + * scale[2]; + } + } + //lightmap += size*3; // skip to next lightmap + } + } else { + int maps; + + // memset( s_blocklights, 0, sizeof( s_blocklights[0] ) * size * + // 3 ); + + Arrays.fill(s_blocklights, 0, size * 3, 0.0f); + + for (maps = 0; maps < Defines.MAXLIGHTMAPS + && surf.styles[maps] != (byte) 255; maps++) { + bl = s_blocklights; + int blp = 0; + + for (i = 0; i < 3; i++) + scale[i] = gl_modulate.value + * r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb[i]; + + if (scale[0] == 1.0F && scale[1] == 1.0F + && scale[2] == 1.0F) { + for (i = 0; i < size; i++) { + bl[blp++] += lightmap.get(lightmapIndex++) & 0xFF; + bl[blp++] += lightmap.get(lightmapIndex++) & 0xFF; + bl[blp++] += lightmap.get(lightmapIndex++) & 0xFF; + } + } else { + for (i = 0; i < size; i++) { + bl[blp++] += (lightmap.get(lightmapIndex++) & 0xFF) + * scale[0]; + bl[blp++] += (lightmap.get(lightmapIndex++) & 0xFF) + * scale[1]; + bl[blp++] += (lightmap.get(lightmapIndex++) & 0xFF) + * scale[2]; + } + } + //lightmap += size*3; // skip to next lightmap + } + } + + // add all the dynamic lights + if (surf.dlightframe == r_framecount) + R_AddDynamicLights(surf); + + // label store: + } catch (longjmpException store) { + } + + // put into texture format + stride -= smax; + bl = s_blocklights; + int blp = 0; + + int monolightmap = gl_monolightmap.string.charAt(0); + + int destp = 0; + + if (monolightmap == '0') { + for (i = 0; i < tmax; i++, destp += stride) { + //dest.position(destp); + + for (j = 0; j < smax; j++) { + + r = (int) bl[blp++]; + g = (int) bl[blp++]; + b = (int) bl[blp++]; + + // catch negative lights + if (r < 0) + r = 0; + if (g < 0) + g = 0; + if (b < 0) + b = 0; + + /* + * * determine the brightest of the three color components + */ + if (r > g) + max = r; + else + max = g; + if (b > max) + max = b; + + /* + * * alpha is ONLY used for the mono lightmap case. For this + * reason * we set it to the brightest of the color + * components so that * things don't get too dim. + */ + a = max; + + /* + * * rescale all the color components if the intensity of + * the greatest * channel exceeds 1.0 + */ + if (max > 255) { + float t = 255.0F / max; + + r = (int) (r * t); + g = (int) (g * t); + b = (int) (b * t); + a = (int) (a * t); + } + //r &= 0xFF; g &= 0xFF; b &= 0xFF; a &= 0xFF; + dest.put(destp++, (a << 24) | (b << 16) | (g << 8) + | (r << 0)); + } + } + } else { + for (i = 0; i < tmax; i++, destp += stride) { + //dest.position(destp); + + for (j = 0; j < smax; j++) { + + r = (int) bl[blp++]; + g = (int) bl[blp++]; + b = (int) bl[blp++]; + + // catch negative lights + if (r < 0) + r = 0; + if (g < 0) + g = 0; + if (b < 0) + b = 0; + + /* + * * determine the brightest of the three color components + */ + if (r > g) + max = r; + else + max = g; + if (b > max) + max = b; + + /* + * * alpha is ONLY used for the mono lightmap case. For this + * reason * we set it to the brightest of the color + * components so that * things don't get too dim. + */ + a = max; + + /* + * * rescale all the color components if the intensity of + * the greatest * channel exceeds 1.0 + */ + if (max > 255) { + float t = 255.0F / max; + + r = (int) (r * t); + g = (int) (g * t); + b = (int) (b * t); + a = (int) (a * t); + } + + /* + * * So if we are doing alpha lightmaps we need to set the + * R, G, and B * components to 0 and we need to set alpha to + * 1-alpha. + */ + switch (monolightmap) { + case 'L': + case 'I': + r = a; + g = b = 0; + break; + case 'C': + // try faking colored lighting + a = 255 - ((r + g + b) / 3); + r *= a / 255.0f; + g *= a / 255.0f; + b *= a / 255.0f; + break; + case 'A': + default: + r = g = b = 0; + a = 255 - a; + break; + } + //r &= 0xFF; g &= 0xFF; b &= 0xFF; a &= 0xFF; + dest.put(destp++, (a << 24) | (b << 16) | (g << 8) + | (r << 0)); + } + } + } + } +} \ No newline at end of file diff --git a/src/jake2/render/fastjogl/Mesh.java b/src/jake2/render/fastjogl/Mesh.java index bff8756..63c8ad4 100644 --- a/src/jake2/render/fastjogl/Mesh.java +++ b/src/jake2/render/fastjogl/Mesh.java @@ -2,27 +2,27 @@ * Mesh.java * Copyright (C) 2003 * - * $Id: Mesh.java,v 1.5 2004-07-19 19:39:57 hzi Exp $ + * $Id: Mesh.java,v 1.6 2004-09-22 19:22:11 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.render.fastjogl; import jake2.Defines; @@ -40,667 +40,659 @@ import net.java.games.jogl.util.BufferUtils; /** * Mesh - * + * * @author cwei */ public abstract class Mesh extends Light { - // g_mesh.c: triangle model functions - - /* - ============================================================= - - ALIAS MODELS - - ============================================================= - */ - - static final int NUMVERTEXNORMALS = 162; - - float[][] r_avertexnormals = Anorms.VERTEXNORMALS; - float[] shadevector = {0, 0, 0}; - float[] shadelight = {0, 0, 0}; - - // precalculated dot products for quantized angles - static final int SHADEDOT_QUANT = 16; - - float[][] r_avertexnormal_dots = Anorms.VERTEXNORMAL_DOTS; - - float[] shadedots = r_avertexnormal_dots[0]; - - void GL_LerpVerts(int nverts, qfiles.dtrivertx_t[] ov, qfiles.dtrivertx_t[] verts, float[] move, float[] frontv, float[] backv ) - { - int[] ovv; - int[] vv; - FloatBuffer lerp = vertexArrayBuf; - - //PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0 ) - { - float[] normal; - int j = 0; - for (int i=0 ; i < nverts; i++/* , v++, ov++, lerp+=4 */) - { - normal = r_avertexnormals[verts[i].lightnormalindex]; - ovv = ov[i].v; - vv = verts[i].v; - - lerp.put(j++, move[0] + ovv[0]*backv[0] + vv[0]*frontv[0] + normal[0] * Defines.POWERSUIT_SCALE); - lerp.put(j++, move[1] + ovv[1]*backv[1] + vv[1]*frontv[1] + normal[1] * Defines.POWERSUIT_SCALE); - lerp.put(j++, move[2] + ovv[2]*backv[2] + vv[2]*frontv[2] + normal[2] * Defines.POWERSUIT_SCALE); - } - } - else - { - int j = 0; - for (int i=0 ; i < nverts; i++ /* , v++, ov++, lerp+=4 */) - { - ovv = ov[i].v; - vv = verts[i].v; - - lerp.put(j++, move[0] + ovv[0]*backv[0] + vv[0]*frontv[0]); - lerp.put(j++, move[1] + ovv[1]*backv[1] + vv[1]*frontv[1]); - lerp.put(j++, move[2] + ovv[2]*backv[2] + vv[2]*frontv[2]); - } - } - } - - FloatBuffer colorArrayBuf = BufferUtils.newFloatBuffer(qfiles.MAX_VERTS * 4); - FloatBuffer vertexArrayBuf = BufferUtils.newFloatBuffer(qfiles.MAX_VERTS * 3); - FloatBuffer textureArrayBuf = BufferUtils.newFloatBuffer(qfiles.MAX_VERTS * 2); - boolean isFilled = false; - float[] tmpVec = {0, 0, 0}; - float[][] vectors = { - {0, 0, 0}, {0, 0, 0}, {0, 0, 0} // 3 mal vec3_t - }; - - /* - ============= - GL_DrawAliasFrameLerp - - interpolates between two frames and origins - FIXME: batch lerp all vertexes - ============= - */ - - void GL_DrawAliasFrameLerp(qfiles.dmdl_t paliashdr, float backlerp) - { - int count; - float alpha; - - float[] move = {0, 0, 0}; // vec3_t - float[] frontv = {0, 0, 0}; // vec3_t - float[] backv = {0, 0, 0}; // vec3_t - - qfiles.daliasframe_t frame = paliashdr.aliasFrames[currententity.frame]; - - qfiles.dtrivertx_t[] verts = frame.verts; - - qfiles.daliasframe_t oldframe = paliashdr.aliasFrames[currententity.oldframe]; - - qfiles.dtrivertx_t[] ov = oldframe.verts; - - if ((currententity.flags & Defines.RF_TRANSLUCENT) != 0) - alpha = currententity.alpha; - else - alpha = 1.0f; - - // PMM - added double shell - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) - gl.glDisable( GL.GL_TEXTURE_2D ); - - float frontlerp = 1.0f - backlerp; - - // move should be the delta back to the previous frame * backlerp - Math3D.VectorSubtract (currententity.oldorigin, currententity.origin, frontv); - Math3D.AngleVectors (currententity.angles, vectors[0], vectors[1], vectors[2]); - - move[0] = Math3D.DotProduct (frontv, vectors[0]); // forward - move[1] = -Math3D.DotProduct (frontv, vectors[1]); // left - move[2] = Math3D.DotProduct (frontv, vectors[2]); // up - - Math3D.VectorAdd (move, oldframe.translate, move); - - for (int i=0 ; i<3 ; i++) - { - move[i] = backlerp*move[i] + frontlerp*frame.translate[i]; - frontv[i] = frontlerp*frame.scale[i]; - backv[i] = backlerp*oldframe.scale[i]; - } - - // ab hier wird optimiert - - GL_LerpVerts( paliashdr.num_xyz, ov, verts, move, frontv, backv ); - - //gl.glEnableClientState( GL.GL_VERTEX_ARRAY ); - gl.glVertexPointer( 3, GL.GL_FLOAT, 0, vertexArrayBuf ); - - // PMM - added double damage shell - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) - { - gl.glColor4f( shadelight[0], shadelight[1], shadelight[2], alpha ); - } - else - { - gl.glEnableClientState( GL.GL_COLOR_ARRAY ); - gl.glColorPointer( 4, GL.GL_FLOAT, 0, colorArrayBuf ); - - // - // pre light everything - // - FloatBuffer color = colorArrayBuf; - int j = 0; - float l; - for (int i = 0; i < paliashdr.num_xyz; i++ ) - { - l = shadedots[verts[i].lightnormalindex]; - color.put(j++, l * shadelight[0]); - color.put(j++, l * shadelight[1]); - color.put(j++, l * shadelight[2]); - color.put(j++, alpha); - } - } - - gl.glClientActiveTextureARB(GL_TEXTURE0); - gl.glTexCoordPointer( 2, GL.GL_FLOAT, 0, textureArrayBuf); - //gl.glEnableClientState( GL.GL_TEXTURE_COORD_ARRAY); - - int pos = 0; - int[] counts = paliashdr.counts; - - IntBuffer srcIndexBuf = null; - - FloatBuffer dstTextureCoords = textureArrayBuf; - FloatBuffer srcTextureCoords = paliashdr.textureCoordBuf; - - int size = 0; - int dstIndex = 0; - int srcIndex = 0; - - for (int j = 0; j < counts.length; j++) { - - // get the vertex count and primitive type - count = counts[j]; - if (count == 0) - break; // done - - srcIndexBuf = paliashdr.indexElements[j]; - - int mode = GL.GL_TRIANGLE_STRIP; - if (count < 0) { - mode = GL.GL_TRIANGLE_FAN; - count = -count; - } - size = count + pos; - srcIndex = 2 * pos; - for (int k = pos; k < size; k++) { - dstIndex = 2 * srcIndexBuf.get(k-pos); - dstTextureCoords.put(dstIndex++, srcTextureCoords.get(srcIndex++)); - dstTextureCoords.put(dstIndex, srcTextureCoords.get(srcIndex++)); - } - - gl.glDrawElements(mode, count, GL.GL_UNSIGNED_INT, srcIndexBuf); - - pos += count; - } - - // PMM - added double damage shell - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0 ) - gl.glEnable( GL.GL_TEXTURE_2D ); - - gl.glDisableClientState( GL.GL_COLOR_ARRAY ); - - } - - /* - ============= - GL_DrawAliasShadow - ============= - */ - void GL_DrawAliasShadow(qfiles.dmdl_t paliashdr, int posenum) - { - qfiles.dtrivertx_t[] verts; - int[] order; - float[] point = {0, 0, 0}; - float height, lheight; - int count; - qfiles.daliasframe_t frame; - - lheight = currententity.origin[2] - lightspot[2]; - - frame = paliashdr.aliasFrames[currententity.frame]; - - verts = frame.verts; - - height = 0; - - order = paliashdr.glCmds; - - height = -lheight + 1.0f; - - int orderIndex = 0; - int index = 0; - - // TODO shadow drawing with vertex arrays - - while (true) - { - // get the vertex count and primitive type - count = order[orderIndex++]; - if (count == 0) - break; // done - if (count < 0) - { - count = -count; - gl.glBegin (GL.GL_TRIANGLE_FAN); - } - else - gl.glBegin (GL.GL_TRIANGLE_STRIP); - - do - { - index = order[orderIndex + 2] * 3; - point[0] = vertexArrayBuf.get(index); - point[1] = vertexArrayBuf.get(index + 1); - point[2] = vertexArrayBuf.get(index + 2); - - point[0] -= shadevector[0]*(point[2]+lheight); - point[1] -= shadevector[1]*(point[2]+lheight); - point[2] = height; - gl.glVertex3f(point[0], point[1], point[2]); - - orderIndex += 3; - - } while (--count != 0); - - gl.glEnd (); - } - } - - - /* - ** R_CullAliasModel - */ -// TODO sync with jogl renderer. hoz - boolean R_CullAliasModel(entity_t e) { - float[] mins = { 0, 0, 0 }; - float[] maxs = { 0, 0, 0 }; - - qfiles.dmdl_t paliashdr = (qfiles.dmdl_t) currentmodel.extradata; - - if ((e.frame >= paliashdr.num_frames) || (e.frame < 0)) { - VID.Printf(Defines.PRINT_ALL, "R_CullAliasModel " + currentmodel.name + ": no such frame " + e.frame + '\n'); - e.frame = 0; - } - if ((e.oldframe >= paliashdr.num_frames) || (e.oldframe < 0)) { - VID.Printf(Defines.PRINT_ALL, "R_CullAliasModel " + currentmodel.name + ": no such oldframe " + e.oldframe + '\n'); - e.oldframe = 0; - } - - qfiles.daliasframe_t pframe = paliashdr.aliasFrames[e.frame]; - qfiles.daliasframe_t poldframe = paliashdr.aliasFrames[e.oldframe]; - - /* - ** compute axially aligned mins and maxs - */ - if (pframe == poldframe) { - for (int i = 0; i < 3; i++) { - mins[i] = pframe.translate[i]; - maxs[i] = mins[i] + pframe.scale[i] * 255; - } - } else { - float thismaxs, oldmaxs; - for (int i = 0; i < 3; i++) { - thismaxs = pframe.translate[i] + pframe.scale[i] * 255; - - oldmaxs = poldframe.translate[i] + poldframe.scale[i] * 255; - - if (pframe.translate[i] < poldframe.translate[i]) - mins[i] = pframe.translate[i]; - else - mins[i] = poldframe.translate[i]; - - if (thismaxs > oldmaxs) - maxs[i] = thismaxs; - else - maxs[i] = oldmaxs; - } - } - - /* - ** compute a full bounding box - */ - float[] tmp; - for (int i = 0; i < 8; i++) { - tmp = bbox[i]; - if ((i & 1) != 0) - tmp[0] = mins[0]; - else - tmp[0] = maxs[0]; - - if ((i & 2) != 0) - tmp[1] = mins[1]; - else - tmp[1] = maxs[1]; - - if ((i & 4) != 0) - tmp[2] = mins[2]; - else - tmp[2] = maxs[2]; - } - - /* - ** rotate the bounding box - */ - tmp = mins; - Math3D.VectorCopy(e.angles, tmp); - tmp[YAW] = -tmp[YAW]; - Math3D.AngleVectors(tmp, vectors[0], vectors[1], vectors[2]); - - for (int i = 0; i < 8; i++) { - Math3D.VectorCopy(bbox[i], tmp); - - bbox[i][0] = Math3D.DotProduct(vectors[0], tmp); - bbox[i][1] = -Math3D.DotProduct(vectors[1], tmp); - bbox[i][2] = Math3D.DotProduct(vectors[2], tmp); - - Math3D.VectorAdd(e.origin, bbox[i], bbox[i]); - } - - int f, mask; - int aggregatemask = ~0; // 0xFFFFFFFF - - for (int p = 0; p < 8; p++) { - mask = 0; - - for (f = 0; f < 4; f++) { - float dp = Math3D.DotProduct(frustum[f].normal, bbox[p]); - - if ((dp - frustum[f].dist) < 0) { - mask |= (1 << f); - } - } - - aggregatemask &= mask; - } - - if (aggregatemask != 0) { - return true; - } - - return false; - } - - - // bounding box - float[][] bbox = { - {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, - {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0} - }; - - /* - ================= - R_DrawAliasModel - - ================= - */ -// TODO sync with jogl renderer. hoz - void R_DrawAliasModel(entity_t e) - { - int i; - //qfiles.dmdl_t paliashdr; - //float an; - - image_t skin; - - if ( ( e.flags & Defines.RF_WEAPONMODEL ) == 0) - { - if ( R_CullAliasModel(e) ) - return; - } - - if ( (e.flags & Defines.RF_WEAPONMODEL) != 0 ) - { - if ( r_lefthand.value == 2.0f ) - return; - } - - qfiles.dmdl_t paliashdr = (qfiles.dmdl_t)currentmodel.extradata; - - // - // get lighting information - // - // PMM - rewrote, reordered to handle new shells & mixing - // PMM - 3.20 code .. replaced with original way of doing it to keep mod authors happy - // - if ( (currententity.flags & ( Defines.RF_SHELL_HALF_DAM | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_RED | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE )) != 0 ) - { - Math3D.VectorClear(shadelight); - if ((currententity.flags & Defines.RF_SHELL_HALF_DAM) != 0) - { - shadelight[0] = 0.56f; - shadelight[1] = 0.59f; - shadelight[2] = 0.45f; - } - if ( (currententity.flags & Defines.RF_SHELL_DOUBLE) != 0 ) - { - shadelight[0] = 0.9f; - shadelight[1] = 0.7f; - } - if ( (currententity.flags & Defines.RF_SHELL_RED) != 0 ) - shadelight[0] = 1.0f; - if ( (currententity.flags & Defines.RF_SHELL_GREEN) != 0 ) - shadelight[1] = 1.0f; - if ( (currententity.flags & Defines.RF_SHELL_BLUE) != 0 ) - shadelight[2] = 1.0f; - } - - else if ( (currententity.flags & Defines.RF_FULLBRIGHT) != 0 ) - { - for (i=0 ; i<3 ; i++) - shadelight[i] = 1.0f; - } - else - { - R_LightPoint (currententity.origin, shadelight); - - // player lighting hack for communication back to server - // big hack! - if ( (currententity.flags & Defines.RF_WEAPONMODEL) != 0 ) - { - // pick the greatest component, which should be the same - // as the mono value returned by software - if (shadelight[0] > shadelight[1]) - { - if (shadelight[0] > shadelight[2]) - r_lightlevel.value = 150*shadelight[0]; - else - r_lightlevel.value = 150*shadelight[2]; - } - else - { - if (shadelight[1] > shadelight[2]) - r_lightlevel.value = 150*shadelight[1]; - else - r_lightlevel.value = 150*shadelight[2]; - } - } - - if ( gl_monolightmap.string.charAt(0) != '0' ) - { - float s = shadelight[0]; - - if ( s < shadelight[1] ) - s = shadelight[1]; - if ( s < shadelight[2] ) - s = shadelight[2]; - - shadelight[0] = s; - shadelight[1] = s; - shadelight[2] = s; - } - } - - if ( (currententity.flags & Defines.RF_MINLIGHT) != 0 ) - { - for (i=0 ; i<3 ; i++) - if (shadelight[i] > 0.1f) - break; - if (i == 3) - { - shadelight[0] = 0.1f; - shadelight[1] = 0.1f; - shadelight[2] = 0.1f; - } - } - - if ( (currententity.flags & Defines.RF_GLOW) != 0 ) - { // bonus items will pulse with time - float scale; - float min; - - scale = (float)(0.1f * Math.sin(r_newrefdef.time*7)); - for (i=0 ; i<3 ; i++) - { - min = shadelight[i] * 0.8f; - shadelight[i] += scale; - if (shadelight[i] < min) - shadelight[i] = min; - } - } - - // ================= - // PGM ir goggles color override - if ( (r_newrefdef.rdflags & Defines.RDF_IRGOGGLES) != 0 && (currententity.flags & Defines.RF_IR_VISIBLE) != 0) - { - shadelight[0] = 1.0f; - shadelight[1] = 0.0f; - shadelight[2] = 0.0f; - } - // PGM - // ================= - - shadedots = r_avertexnormal_dots[((int)(currententity.angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; - - float an = (float)(currententity.angles[1]/180*Math.PI); - shadevector[0] = (float)Math.cos(-an); - shadevector[1] = (float)Math.sin(-an); - shadevector[2] = 1; - Math3D.VectorNormalize(shadevector); - - // - // locate the proper data - // - - c_alias_polys += paliashdr.num_tris; - - // - // draw all the triangles - // - if ( (currententity.flags & Defines.RF_DEPTHHACK) != 0) // hack the depth range to prevent view model from poking into walls - gl.glDepthRange(gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); - - if ( (currententity.flags & Defines.RF_WEAPONMODEL) != 0 && (r_lefthand.value == 1.0f) ) - { - gl.glMatrixMode( GL.GL_PROJECTION ); - gl.glPushMatrix(); - gl.glLoadIdentity(); - gl.glScalef( -1, 1, 1 ); - MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height, 4, 4096); - gl.glMatrixMode( GL.GL_MODELVIEW ); - - gl.glCullFace( GL.GL_BACK ); - } - - gl.glPushMatrix (); - e.angles[PITCH] = -e.angles[PITCH]; // sigh. - R_RotateForEntity (e); - e.angles[PITCH] = -e.angles[PITCH]; // sigh. - - // select skin - if (currententity.skin != null) - skin = currententity.skin; // custom player skin - else - { - if (currententity.skinnum >= qfiles.MAX_MD2SKINS) - skin = currentmodel.skins[0]; - else - { - skin = currentmodel.skins[currententity.skinnum]; - if (skin == null) - skin = currentmodel.skins[0]; - } - } - if (skin == null) - skin = r_notexture; // fallback... - GL_Bind(skin.texnum); - - // draw it - - gl.glShadeModel (GL.GL_SMOOTH); - - GL_TexEnv( GL.GL_MODULATE ); - if ( (currententity.flags & Defines.RF_TRANSLUCENT) != 0 ) - { - gl.glEnable (GL.GL_BLEND); - } - - - if ( (currententity.frame >= paliashdr.num_frames) - || (currententity.frame < 0) ) - { - VID.Printf (Defines.PRINT_ALL, "R_DrawAliasModel " + currentmodel.name +": no such frame " + currententity.frame + '\n'); - currententity.frame = 0; - currententity.oldframe = 0; - } - - if ( (currententity.oldframe >= paliashdr.num_frames) - || (currententity.oldframe < 0)) - { - VID.Printf (Defines.PRINT_ALL, "R_DrawAliasModel " + currentmodel.name +": no such oldframe " + currententity.oldframe + '\n'); - currententity.frame = 0; - currententity.oldframe = 0; - } - - if ( r_lerpmodels.value == 0.0f) - currententity.backlerp = 0; - - GL_DrawAliasFrameLerp(paliashdr, currententity.backlerp); - - GL_TexEnv( GL.GL_REPLACE ); - gl.glShadeModel (GL.GL_FLAT); - - gl.glPopMatrix (); - - if ( ( currententity.flags & Defines.RF_WEAPONMODEL ) != 0 && ( r_lefthand.value == 1.0F ) ) - { - gl.glMatrixMode( GL.GL_PROJECTION ); - gl.glPopMatrix(); - gl.glMatrixMode( GL.GL_MODELVIEW ); - gl.glCullFace( GL.GL_FRONT ); - } - - if ( (currententity.flags & Defines.RF_TRANSLUCENT) != 0 ) - { - gl.glDisable (GL.GL_BLEND); - } - - if ( (currententity.flags & Defines.RF_DEPTHHACK) != 0) - gl.glDepthRange (gldepthmin, gldepthmax); - - if ( gl_shadows.value != 0.0f && (currententity.flags & (Defines.RF_TRANSLUCENT | Defines.RF_WEAPONMODEL)) == 0) - { - gl.glPushMatrix (); - R_RotateForEntity (e); - gl.glDisable (GL.GL_TEXTURE_2D); - gl.glEnable (GL.GL_BLEND); - gl.glColor4f (0,0,0,0.5f); - GL_DrawAliasShadow (paliashdr, currententity.frame ); - gl.glEnable (GL.GL_TEXTURE_2D); - gl.glDisable (GL.GL_BLEND); - gl.glPopMatrix (); - } - gl.glColor4f (1,1,1,1); - } - -} + // g_mesh.c: triangle model functions + + /* + * ============================================================= + * + * ALIAS MODELS + * + * ============================================================= + */ + + static final int NUMVERTEXNORMALS = 162; + + float[][] r_avertexnormals = Anorms.VERTEXNORMALS; + + float[] shadevector = { 0, 0, 0 }; + + float[] shadelight = { 0, 0, 0 }; + + // precalculated dot products for quantized angles + static final int SHADEDOT_QUANT = 16; + + float[][] r_avertexnormal_dots = Anorms.VERTEXNORMAL_DOTS; + + float[] shadedots = r_avertexnormal_dots[0]; + + void GL_LerpVerts(int nverts, qfiles.dtrivertx_t[] ov, + qfiles.dtrivertx_t[] verts, float[] move, float[] frontv, + float[] backv) { + int[] ovv; + int[] vv; + FloatBuffer lerp = vertexArrayBuf; + + //PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE + | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) { + float[] normal; + int j = 0; + for (int i = 0; i < nverts; i++ /* , v++, ov++, lerp+=4 */ + ) { + normal = r_avertexnormals[verts[i].lightnormalindex]; + ovv = ov[i].v; + vv = verts[i].v; + + lerp.put(j++, move[0] + ovv[0] * backv[0] + vv[0] * frontv[0] + + normal[0] * Defines.POWERSUIT_SCALE); + lerp.put(j++, move[1] + ovv[1] * backv[1] + vv[1] * frontv[1] + + normal[1] * Defines.POWERSUIT_SCALE); + lerp.put(j++, move[2] + ovv[2] * backv[2] + vv[2] * frontv[2] + + normal[2] * Defines.POWERSUIT_SCALE); + } + } else { + int j = 0; + for (int i = 0; i < nverts; i++ /* , v++, ov++, lerp+=4 */ + ) { + ovv = ov[i].v; + vv = verts[i].v; + + lerp.put(j++, move[0] + ovv[0] * backv[0] + vv[0] * frontv[0]); + lerp.put(j++, move[1] + ovv[1] * backv[1] + vv[1] * frontv[1]); + lerp.put(j++, move[2] + ovv[2] * backv[2] + vv[2] * frontv[2]); + } + } + } + + FloatBuffer colorArrayBuf = BufferUtils + .newFloatBuffer(qfiles.MAX_VERTS * 4); + + FloatBuffer vertexArrayBuf = BufferUtils + .newFloatBuffer(qfiles.MAX_VERTS * 3); + + FloatBuffer textureArrayBuf = BufferUtils + .newFloatBuffer(qfiles.MAX_VERTS * 2); + + boolean isFilled = false; + + float[] tmpVec = { 0, 0, 0 }; + + float[][] vectors = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } // 3 mal vec3_t + }; + + /* + * ============= GL_DrawAliasFrameLerp + * + * interpolates between two frames and origins FIXME: batch lerp all + * vertexes ============= + */ + + void GL_DrawAliasFrameLerp(qfiles.dmdl_t paliashdr, float backlerp) { + int count; + float alpha; + + float[] move = { 0, 0, 0 }; // vec3_t + float[] frontv = { 0, 0, 0 }; // vec3_t + float[] backv = { 0, 0, 0 }; // vec3_t + + qfiles.daliasframe_t frame = paliashdr.aliasFrames[currententity.frame]; + + qfiles.dtrivertx_t[] verts = frame.verts; + + qfiles.daliasframe_t oldframe = paliashdr.aliasFrames[currententity.oldframe]; + + qfiles.dtrivertx_t[] ov = oldframe.verts; + + if ((currententity.flags & Defines.RF_TRANSLUCENT) != 0) + alpha = currententity.alpha; + else + alpha = 1.0f; + + // PMM - added double shell + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE + | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) + gl.glDisable(GL.GL_TEXTURE_2D); + + float frontlerp = 1.0f - backlerp; + + // move should be the delta back to the previous frame * backlerp + Math3D.VectorSubtract(currententity.oldorigin, currententity.origin, + frontv); + Math3D.AngleVectors(currententity.angles, vectors[0], vectors[1], + vectors[2]); + + move[0] = Math3D.DotProduct(frontv, vectors[0]); // forward + move[1] = -Math3D.DotProduct(frontv, vectors[1]); // left + move[2] = Math3D.DotProduct(frontv, vectors[2]); // up + + Math3D.VectorAdd(move, oldframe.translate, move); + + for (int i = 0; i < 3; i++) { + move[i] = backlerp * move[i] + frontlerp * frame.translate[i]; + frontv[i] = frontlerp * frame.scale[i]; + backv[i] = backlerp * oldframe.scale[i]; + } + + // ab hier wird optimiert + + GL_LerpVerts(paliashdr.num_xyz, ov, verts, move, frontv, backv); + + //gl.glEnableClientState( GL.GL_VERTEX_ARRAY ); + gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertexArrayBuf); + + // PMM - added double damage shell + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE + | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) { + gl.glColor4f(shadelight[0], shadelight[1], shadelight[2], alpha); + } else { + gl.glEnableClientState(GL.GL_COLOR_ARRAY); + gl.glColorPointer(4, GL.GL_FLOAT, 0, colorArrayBuf); + + // + // pre light everything + // + FloatBuffer color = colorArrayBuf; + int j = 0; + float l; + for (int i = 0; i < paliashdr.num_xyz; i++) { + l = shadedots[verts[i].lightnormalindex]; + color.put(j++, l * shadelight[0]); + color.put(j++, l * shadelight[1]); + color.put(j++, l * shadelight[2]); + color.put(j++, alpha); + } + } + + gl.glClientActiveTextureARB(GL_TEXTURE0); + gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, textureArrayBuf); + //gl.glEnableClientState( GL.GL_TEXTURE_COORD_ARRAY); + + int pos = 0; + int[] counts = paliashdr.counts; + + IntBuffer srcIndexBuf = null; + + FloatBuffer dstTextureCoords = textureArrayBuf; + FloatBuffer srcTextureCoords = paliashdr.textureCoordBuf; + + int size = 0; + int dstIndex = 0; + int srcIndex = 0; + + for (int j = 0; j < counts.length; j++) { + + // get the vertex count and primitive type + count = counts[j]; + if (count == 0) + break; // done + + srcIndexBuf = paliashdr.indexElements[j]; + + int mode = GL.GL_TRIANGLE_STRIP; + if (count < 0) { + mode = GL.GL_TRIANGLE_FAN; + count = -count; + } + size = count + pos; + srcIndex = 2 * pos; + for (int k = pos; k < size; k++) { + dstIndex = 2 * srcIndexBuf.get(k - pos); + dstTextureCoords.put(dstIndex++, srcTextureCoords + .get(srcIndex++)); + dstTextureCoords + .put(dstIndex, srcTextureCoords.get(srcIndex++)); + } + + gl.glDrawElements(mode, count, GL.GL_UNSIGNED_INT, srcIndexBuf); + + pos += count; + } + + // PMM - added double damage shell + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE + | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) + gl.glEnable(GL.GL_TEXTURE_2D); + + gl.glDisableClientState(GL.GL_COLOR_ARRAY); + + } + + /* + * ============= GL_DrawAliasShadow ============= + */ + void GL_DrawAliasShadow(qfiles.dmdl_t paliashdr, int posenum) { + qfiles.dtrivertx_t[] verts; + int[] order; + float[] point = { 0, 0, 0 }; + float height, lheight; + int count; + qfiles.daliasframe_t frame; + + lheight = currententity.origin[2] - lightspot[2]; + + frame = paliashdr.aliasFrames[currententity.frame]; + + verts = frame.verts; + + height = 0; + + order = paliashdr.glCmds; + + height = -lheight + 1.0f; + + int orderIndex = 0; + int index = 0; + + // TODO shadow drawing with vertex arrays + + while (true) { + // get the vertex count and primitive type + count = order[orderIndex++]; + if (count == 0) + break; // done + if (count < 0) { + count = -count; + gl.glBegin(GL.GL_TRIANGLE_FAN); + } else + gl.glBegin(GL.GL_TRIANGLE_STRIP); + + do { + index = order[orderIndex + 2] * 3; + point[0] = vertexArrayBuf.get(index); + point[1] = vertexArrayBuf.get(index + 1); + point[2] = vertexArrayBuf.get(index + 2); + + point[0] -= shadevector[0] * (point[2] + lheight); + point[1] -= shadevector[1] * (point[2] + lheight); + point[2] = height; + gl.glVertex3f(point[0], point[1], point[2]); + + orderIndex += 3; + + } while (--count != 0); + + gl.glEnd(); + } + } + + /* + * * R_CullAliasModel + */ + // TODO sync with jogl renderer. hoz + boolean R_CullAliasModel(entity_t e) { + float[] mins = { 0, 0, 0 }; + float[] maxs = { 0, 0, 0 }; + + qfiles.dmdl_t paliashdr = (qfiles.dmdl_t) currentmodel.extradata; + + if ((e.frame >= paliashdr.num_frames) || (e.frame < 0)) { + VID.Printf(Defines.PRINT_ALL, "R_CullAliasModel " + + currentmodel.name + ": no such frame " + e.frame + '\n'); + e.frame = 0; + } + if ((e.oldframe >= paliashdr.num_frames) || (e.oldframe < 0)) { + VID.Printf(Defines.PRINT_ALL, "R_CullAliasModel " + + currentmodel.name + ": no such oldframe " + e.oldframe + + '\n'); + e.oldframe = 0; + } + + qfiles.daliasframe_t pframe = paliashdr.aliasFrames[e.frame]; + qfiles.daliasframe_t poldframe = paliashdr.aliasFrames[e.oldframe]; + + /* + * * compute axially aligned mins and maxs + */ + if (pframe == poldframe) { + for (int i = 0; i < 3; i++) { + mins[i] = pframe.translate[i]; + maxs[i] = mins[i] + pframe.scale[i] * 255; + } + } else { + float thismaxs, oldmaxs; + for (int i = 0; i < 3; i++) { + thismaxs = pframe.translate[i] + pframe.scale[i] * 255; + + oldmaxs = poldframe.translate[i] + poldframe.scale[i] * 255; + + if (pframe.translate[i] < poldframe.translate[i]) + mins[i] = pframe.translate[i]; + else + mins[i] = poldframe.translate[i]; + + if (thismaxs > oldmaxs) + maxs[i] = thismaxs; + else + maxs[i] = oldmaxs; + } + } + + /* + * * compute a full bounding box + */ + float[] tmp; + for (int i = 0; i < 8; i++) { + tmp = bbox[i]; + if ((i & 1) != 0) + tmp[0] = mins[0]; + else + tmp[0] = maxs[0]; + + if ((i & 2) != 0) + tmp[1] = mins[1]; + else + tmp[1] = maxs[1]; + + if ((i & 4) != 0) + tmp[2] = mins[2]; + else + tmp[2] = maxs[2]; + } + + /* + * * rotate the bounding box + */ + tmp = mins; + Math3D.VectorCopy(e.angles, tmp); + tmp[YAW] = -tmp[YAW]; + Math3D.AngleVectors(tmp, vectors[0], vectors[1], vectors[2]); + + for (int i = 0; i < 8; i++) { + Math3D.VectorCopy(bbox[i], tmp); + + bbox[i][0] = Math3D.DotProduct(vectors[0], tmp); + bbox[i][1] = -Math3D.DotProduct(vectors[1], tmp); + bbox[i][2] = Math3D.DotProduct(vectors[2], tmp); + + Math3D.VectorAdd(e.origin, bbox[i], bbox[i]); + } + + int f, mask; + int aggregatemask = ~0; // 0xFFFFFFFF + + for (int p = 0; p < 8; p++) { + mask = 0; + + for (f = 0; f < 4; f++) { + float dp = Math3D.DotProduct(frustum[f].normal, bbox[p]); + + if ((dp - frustum[f].dist) < 0) { + mask |= (1 << f); + } + } + + aggregatemask &= mask; + } + + if (aggregatemask != 0) { + return true; + } + + return false; + } + + // bounding box + float[][] bbox = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, + { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; + + /* + * ================= R_DrawAliasModel + * + * ================= + */ + // TODO sync with jogl renderer. hoz + void R_DrawAliasModel(entity_t e) { + int i; + //qfiles.dmdl_t paliashdr; + //float an; + + image_t skin; + + if ((e.flags & Defines.RF_WEAPONMODEL) == 0) { + if (R_CullAliasModel(e)) + return; + } + + if ((e.flags & Defines.RF_WEAPONMODEL) != 0) { + if (r_lefthand.value == 2.0f) + return; + } + + qfiles.dmdl_t paliashdr = (qfiles.dmdl_t) currentmodel.extradata; + + // + // get lighting information + // + // PMM - rewrote, reordered to handle new shells & mixing + // PMM - 3.20 code .. replaced with original way of doing it to keep mod + // authors happy + // + if ((currententity.flags & (Defines.RF_SHELL_HALF_DAM + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_RED + | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE)) != 0) { + Math3D.VectorClear(shadelight); + if ((currententity.flags & Defines.RF_SHELL_HALF_DAM) != 0) { + shadelight[0] = 0.56f; + shadelight[1] = 0.59f; + shadelight[2] = 0.45f; + } + if ((currententity.flags & Defines.RF_SHELL_DOUBLE) != 0) { + shadelight[0] = 0.9f; + shadelight[1] = 0.7f; + } + if ((currententity.flags & Defines.RF_SHELL_RED) != 0) + shadelight[0] = 1.0f; + if ((currententity.flags & Defines.RF_SHELL_GREEN) != 0) + shadelight[1] = 1.0f; + if ((currententity.flags & Defines.RF_SHELL_BLUE) != 0) + shadelight[2] = 1.0f; + } + + else if ((currententity.flags & Defines.RF_FULLBRIGHT) != 0) { + for (i = 0; i < 3; i++) + shadelight[i] = 1.0f; + } else { + R_LightPoint(currententity.origin, shadelight); + + // player lighting hack for communication back to server + // big hack! + if ((currententity.flags & Defines.RF_WEAPONMODEL) != 0) { + // pick the greatest component, which should be the same + // as the mono value returned by software + if (shadelight[0] > shadelight[1]) { + if (shadelight[0] > shadelight[2]) + r_lightlevel.value = 150 * shadelight[0]; + else + r_lightlevel.value = 150 * shadelight[2]; + } else { + if (shadelight[1] > shadelight[2]) + r_lightlevel.value = 150 * shadelight[1]; + else + r_lightlevel.value = 150 * shadelight[2]; + } + } + + if (gl_monolightmap.string.charAt(0) != '0') { + float s = shadelight[0]; + + if (s < shadelight[1]) + s = shadelight[1]; + if (s < shadelight[2]) + s = shadelight[2]; + + shadelight[0] = s; + shadelight[1] = s; + shadelight[2] = s; + } + } + + if ((currententity.flags & Defines.RF_MINLIGHT) != 0) { + for (i = 0; i < 3; i++) + if (shadelight[i] > 0.1f) + break; + if (i == 3) { + shadelight[0] = 0.1f; + shadelight[1] = 0.1f; + shadelight[2] = 0.1f; + } + } + + if ((currententity.flags & Defines.RF_GLOW) != 0) { // bonus items will + // pulse with time + float scale; + float min; + + scale = (float) (0.1f * Math.sin(r_newrefdef.time * 7)); + for (i = 0; i < 3; i++) { + min = shadelight[i] * 0.8f; + shadelight[i] += scale; + if (shadelight[i] < min) + shadelight[i] = min; + } + } + + // ================= + // PGM ir goggles color override + if ((r_newrefdef.rdflags & Defines.RDF_IRGOGGLES) != 0 + && (currententity.flags & Defines.RF_IR_VISIBLE) != 0) { + shadelight[0] = 1.0f; + shadelight[1] = 0.0f; + shadelight[2] = 0.0f; + } + // PGM + // ================= + + shadedots = r_avertexnormal_dots[((int) (currententity.angles[1] * (SHADEDOT_QUANT / 360.0))) + & (SHADEDOT_QUANT - 1)]; + + float an = (float) (currententity.angles[1] / 180 * Math.PI); + shadevector[0] = (float) Math.cos(-an); + shadevector[1] = (float) Math.sin(-an); + shadevector[2] = 1; + Math3D.VectorNormalize(shadevector); + + // + // locate the proper data + // + + c_alias_polys += paliashdr.num_tris; + + // + // draw all the triangles + // + if ((currententity.flags & Defines.RF_DEPTHHACK) != 0) + // hack the depth range to prevent view model from poking into walls + gl.glDepthRange(gldepthmin, gldepthmin + 0.3 + * (gldepthmax - gldepthmin)); + + if ((currententity.flags & Defines.RF_WEAPONMODEL) != 0 + && (r_lefthand.value == 1.0f)) { + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glPushMatrix(); + gl.glLoadIdentity(); + gl.glScalef(-1, 1, 1); + MYgluPerspective(r_newrefdef.fov_y, (float) r_newrefdef.width + / r_newrefdef.height, 4, 4096); + gl.glMatrixMode(GL.GL_MODELVIEW); + + gl.glCullFace(GL.GL_BACK); + } + + gl.glPushMatrix(); + e.angles[PITCH] = -e.angles[PITCH]; // sigh. + R_RotateForEntity(e); + e.angles[PITCH] = -e.angles[PITCH]; // sigh. + + // select skin + if (currententity.skin != null) + skin = currententity.skin; // custom player skin + else { + if (currententity.skinnum >= qfiles.MAX_MD2SKINS) + skin = currentmodel.skins[0]; + else { + skin = currentmodel.skins[currententity.skinnum]; + if (skin == null) + skin = currentmodel.skins[0]; + } + } + if (skin == null) + skin = r_notexture; // fallback... + GL_Bind(skin.texnum); + + // draw it + + gl.glShadeModel(GL.GL_SMOOTH); + + GL_TexEnv(GL.GL_MODULATE); + if ((currententity.flags & Defines.RF_TRANSLUCENT) != 0) { + gl.glEnable(GL.GL_BLEND); + } + + if ((currententity.frame >= paliashdr.num_frames) + || (currententity.frame < 0)) { + VID.Printf(Defines.PRINT_ALL, "R_DrawAliasModel " + + currentmodel.name + ": no such frame " + + currententity.frame + '\n'); + currententity.frame = 0; + currententity.oldframe = 0; + } + + if ((currententity.oldframe >= paliashdr.num_frames) + || (currententity.oldframe < 0)) { + VID.Printf(Defines.PRINT_ALL, "R_DrawAliasModel " + + currentmodel.name + ": no such oldframe " + + currententity.oldframe + '\n'); + currententity.frame = 0; + currententity.oldframe = 0; + } + + if (r_lerpmodels.value == 0.0f) + currententity.backlerp = 0; + + GL_DrawAliasFrameLerp(paliashdr, currententity.backlerp); + + GL_TexEnv(GL.GL_REPLACE); + gl.glShadeModel(GL.GL_FLAT); + + gl.glPopMatrix(); + + if ((currententity.flags & Defines.RF_WEAPONMODEL) != 0 + && (r_lefthand.value == 1.0F)) { + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glPopMatrix(); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glCullFace(GL.GL_FRONT); + } + + if ((currententity.flags & Defines.RF_TRANSLUCENT) != 0) { + gl.glDisable(GL.GL_BLEND); + } + + if ((currententity.flags & Defines.RF_DEPTHHACK) != 0) + gl.glDepthRange(gldepthmin, gldepthmax); + + if (gl_shadows.value != 0.0f + && (currententity.flags & (Defines.RF_TRANSLUCENT | Defines.RF_WEAPONMODEL)) == 0) { + gl.glPushMatrix(); + R_RotateForEntity(e); + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glEnable(GL.GL_BLEND); + gl.glColor4f(0, 0, 0, 0.5f); + GL_DrawAliasShadow(paliashdr, currententity.frame); + gl.glEnable(GL.GL_TEXTURE_2D); + gl.glDisable(GL.GL_BLEND); + gl.glPopMatrix(); + } + gl.glColor4f(1, 1, 1, 1); + } + +} \ No newline at end of file diff --git a/src/jake2/render/fastjogl/Misc.java b/src/jake2/render/fastjogl/Misc.java index dad5ae0..68e4ea4 100644 --- a/src/jake2/render/fastjogl/Misc.java +++ b/src/jake2/render/fastjogl/Misc.java @@ -2,7 +2,7 @@ * Misc.java * Copyright (C) 2003 * - * $Id: Misc.java,v 1.2 2004-07-16 10:11:35 cawe Exp $ + * $Id: Misc.java,v 1.3 2004-09-22 19:22:10 salomo Exp $ */ /* Copyright (C) 1997-2001 Id Software, Inc. @@ -25,11 +25,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package jake2.render.fastjogl; -import net.java.games.jogl.GL; -import net.java.games.jogl.WGL; - import jake2.Defines; import jake2.client.VID; +import net.java.games.jogl.GL; +import net.java.games.jogl.WGL; /** * Misc @@ -43,34 +42,28 @@ public abstract class Misc extends Mesh { R_InitParticleTexture ================== */ - byte[][] dottexture = - { - {0,0,0,0,0,0,0,0}, - {0,0,1,1,0,0,0,0}, - {0,1,1,1,1,0,0,0}, - {0,1,1,1,1,0,0,0}, - {0,0,1,1,0,0,0,0}, - {0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0}, - }; - - void R_InitParticleTexture() - { - int x,y; + byte[][] dottexture = { { 0, 0, 0, 0, 0, 0, 0, 0 }, { + 0, 0, 1, 1, 0, 0, 0, 0 }, { + 0, 1, 1, 1, 1, 0, 0, 0 }, + { 0, 1, 1, 1, 1, 0, 0, 0 }, { + 0, 0, 1, 1, 0, 0, 0, 0 }, { + 0, 0, 0, 0, 0, 0, 0, 0 }, { + 0, 0, 0, 0, 0, 0, 0, 0 }, { + 0, 0, 0, 0, 0, 0, 0, 0 }, }; + + void R_InitParticleTexture() { + int x, y; byte[] data = new byte[8 * 8 * 4]; // // particle texture // - for (x=0 ; x<8 ; x++) - { - for (y=0 ; y<8 ; y++) - { - data[y * 32 + x * 4 + 0] = (byte)255; - data[y * 32 + x * 4 + 1] = (byte)255; - data[y * 32 + x * 4 + 2] = (byte)255; - data[y * 32 + x * 4 + 3] = (byte)(dottexture[x][y]*255); + for (x = 0; x < 8; x++) { + for (y = 0; y < 8; y++) { + data[y * 32 + x * 4 + 0] = (byte) 255; + data[y * 32 + x * 4 + 1] = (byte) 255; + data[y * 32 + x * 4 + 2] = (byte) 255; + data[y * 32 + x * 4 + 3] = (byte) (dottexture[x][y] * 255); } } @@ -79,108 +72,103 @@ public abstract class Misc extends Mesh { // // also use this for bad textures, but without alpha // - for (x=0 ; x<8 ; x++) - { - for (y=0 ; y<8 ; y++) - { - data[y * 32 + x * 4 + 0] = (byte)(dottexture[x&3][y&3]*255); + for (x = 0; x < 8; x++) { + for (y = 0; y < 8; y++) { + data[y * 32 + x * 4 + 0] = (byte) (dottexture[x & 3][y & 3] * 255); data[y * 32 + x * 4 + 1] = 0; // dottexture[x&3][y&3]*255; data[y * 32 + x * 4 + 2] = 0; //dottexture[x&3][y&3]*255; - data[y * 32 + x * 4 + 3] = (byte)255; + data[y * 32 + x * 4 + 3] = (byte) 255; } } r_notexture = GL_LoadPic("***r_notexture***", data, 8, 8, it_wall, 32); } - -// /* -// ============================================================================== -// -// SCREEN SHOTS -// -// ============================================================================== -// */ -// -// typedef struct _TargaHeader { -// unsigned char id_length, colormap_type, image_type; -// unsigned short colormap_index, colormap_length; -// unsigned char colormap_size; -// unsigned short x_origin, y_origin, width, height; -// unsigned char pixel_size, attributes; -// } TargaHeader; - + // /* + // ============================================================================== + // + // SCREEN SHOTS + // + // ============================================================================== + // */ + // + // typedef struct _TargaHeader { + // unsigned char id_length, colormap_type, image_type; + // unsigned short colormap_index, colormap_length; + // unsigned char colormap_size; + // unsigned short x_origin, y_origin, width, height; + // unsigned char pixel_size, attributes; + // } TargaHeader; /* ================== GL_ScreenShot_f ================== - */ - void GL_ScreenShot_f() - { -// byte *buffer; -// char picname[80]; -// char checkname[MAX_OSPATH]; -// int i, c, temp; -// FILE *f; -// -// // create the scrnshots directory if it doesn't exist -// Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir()); -// Sys_Mkdir (checkname); -// -//// -//// find a file name to save it to -//// -// strcpy(picname,"quake00.tga"); -// -// for (i=0 ; i<=99 ; i++) -// { -// picname[5] = i/10 + '0'; -// picname[6] = i%10 + '0'; -// Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), picname); -// f = fopen (checkname, "r"); -// if (!f) -// break; // file doesn't exist -// fclose (f); -// } -// if (i==100) -// { -// VID.Printf (PRINT_ALL, "SCR_ScreenShot_f: Couldn't create a file\n"); -// return; -// } -// -// -// buffer = malloc(vid.width*vid.height*3 + 18); -// memset (buffer, 0, 18); -// buffer[2] = 2; // uncompressed type -// buffer[12] = vid.width&255; -// buffer[13] = vid.width>>8; -// buffer[14] = vid.height&255; -// buffer[15] = vid.height>>8; -// buffer[16] = 24; // pixel size -// -// qglReadPixels (0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); -// -// // swap rgb to bgr -// c = 18+vid.width*vid.height*3; -// for (i=18 ; i>8; + // buffer[14] = vid.height&255; + // buffer[15] = vid.height>>8; + // buffer[16] = 24; // pixel size + // + // qglReadPixels (0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); + // + // // swap rgb to bgr + // c = 18+vid.width*vid.height*3; + // for (i=18 ; i 0) - node = node.children[0]; - else - node = node.children[1]; - } - // never reached - } - - - byte[] decompressed = new byte[Defines.MAX_MAP_LEAFS / 8]; - byte[] model_visibility = new byte[Defines.MAX_MAP_VISIBILITY]; - - /* - =================== - Mod_DecompressVis - =================== - */ - byte[] Mod_DecompressVis(byte[] in, int offset, model_t model) - { - int c; - byte[] out; - int outp, inp; - int row; - - row = (model.vis.numclusters+7)>>3; - out = decompressed; - outp = 0; - inp = offset; - - if (in == null) - { // no vis info, so make all visible - while (row != 0) - { - out[outp++] = (byte)0xFF; - row--; - } - return decompressed; - } - - do - { - if (in[inp] != 0) - { - out[outp++] = in[inp++]; - continue; - } - - c = in[inp + 1] & 0xFF; - inp += 2; - while (c != 0) - { - out[outp++] = 0; - c--; - } - } while (outp < row); - - return decompressed; - } - - /* - ============== - Mod_ClusterPVS - ============== - */ - byte[] Mod_ClusterPVS(int cluster, model_t model) - { - if (cluster == -1 || model.vis == null) - return mod_novis; - //return Mod_DecompressVis( (byte *)model.vis + model.vis.bitofs[cluster][Defines.DVIS_PVS], model); - return Mod_DecompressVis(model_visibility, model.vis.bitofs[cluster][Defines.DVIS_PVS], model); - } - - -// =============================================================================== - - /* - ================ - Mod_Modellist_f - ================ - */ - void Mod_Modellist_f() - { - int i; - model_t mod; - int total; - - total = 0; - VID.Printf(Defines.PRINT_ALL,"Loaded models:\n"); - for (i=0; i < mod_numknown ; i++) - { - mod = mod_known[i]; - if (mod.name == "") - continue; - - VID.Printf (Defines.PRINT_ALL, "%8i : %s\n", new Vargs(2).add(mod.extradatasize).add(mod.name)); - total += mod.extradatasize; - } - VID.Printf (Defines.PRINT_ALL, "Total resident: " + total +'\n'); - } - - /* - =============== - Mod_Init - =============== - */ - void Mod_Init() - { - // init mod_known - for (int i=0; i < MAX_MOD_KNOWN; i++) { - mod_known[i] = new model_t(); - } - Arrays.fill(mod_novis, (byte)0xff); - } - - byte[] fileBuffer; - - /* - ================== - Mod_ForName - - Loads in a model for the given name - ================== - */ - model_t Mod_ForName(String name, boolean crash) - { - model_t mod = null; - int i; - - if (name == null || name.length() == 0) - Com.Error(Defines.ERR_DROP, "Mod_ForName: NULL name"); - - // - // inline models are grabbed only from worldmodel - // - if (name.charAt(0) == '*') - { - i = Integer.parseInt(name.substring(1)); - if (i < 1 || r_worldmodel == null || i >= r_worldmodel.numsubmodels) - Com.Error (Defines.ERR_DROP, "bad inline model number"); - return mod_inline[i]; - } - - // - // search the currently loaded models - // - for (i=0; i Math.abs(maxs[i]) ? Math.abs(mins[i]) : Math.abs(maxs[i]); - } - return Math3D.VectorLength(corner); - } - - - /* - ================= - Mod_LoadSubmodels - ================= - */ - void Mod_LoadSubmodels(lump_t l) - { - qfiles.dmodel_t in; - mmodel_t[] out; - int i, j, count; - - if ((l.filelen % qfiles.dmodel_t.SIZE) != 0) - Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name); - - count = l.filelen / qfiles.dmodel_t.SIZE; - // out = Hunk_Alloc ( count*sizeof(*out)); - out = new mmodel_t[count]; - - loadmodel.submodels = out; - loadmodel.numsubmodels = count; - - ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); - bb.order(ByteOrder.LITTLE_ENDIAN); - - for ( i=0 ; i 0) - out[i].next = loadmodel.texinfo[next]; - else - out[i].next = null; - - name = "textures/" + in.texture + ".wal"; - - out[i].image = GL_FindImage(name, it_wall); - if (out[i].image == null) { - VID.Printf(Defines.PRINT_ALL, "Couldn't load " + name + '\n'); - out[i].image = r_notexture; - } - } - - // count animation frames - for (i=0 ; i= 0) - v = loadmodel.vertexes[loadmodel.edges[e].v[0]]; - else - v = loadmodel.vertexes[loadmodel.edges[-e].v[1]]; - - for (j=0 ; j<2 ; j++) - { - val = v.position[0] * tex.vecs[j][0] + - v.position[1] * tex.vecs[j][1] + - v.position[2] * tex.vecs[j][2] + - tex.vecs[j][3]; - if (val < mins[j]) - mins[j] = val; - if (val > maxs[j]) - maxs[j] = val; - } - } - - for (int i=0 ; i<2 ; i++) - { - bmins[i] = (int)Math.floor(mins[i]/16); - bmaxs[i] = (int)Math.ceil(maxs[i]/16); - - s.texturemins[i] = (short)(bmins[i] * 16); - s.extents[i] = (short)((bmaxs[i] - bmins[i]) * 16); - - } - } - - /* - ================= - Mod_LoadFaces - ================= - */ - void Mod_LoadFaces (lump_t l) - { - qfiles.dface_t in; - msurface_t[] out; - int i, count, surfnum; - int planenum, side; - int ti; - - if ((l.filelen % qfiles.dface_t.SIZE) != 0) - Com.Error (Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name); - - count = l.filelen / qfiles.dface_t.SIZE; - // out = Hunk_Alloc ( count*sizeof(*out)); - out = new msurface_t[count]; - - loadmodel.surfaces = out; - loadmodel.numsurfaces = count; - - ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); - bb.order(ByteOrder.LITTLE_ENDIAN); - - currentmodel = loadmodel; - - GL_BeginBuildingLightmaps(loadmodel); - - for ( surfnum=0 ; surfnum= loadmodel.numtexinfo) - Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: bad texinfo number"); - - out[surfnum].texinfo = loadmodel.texinfo[ti]; - - CalcSurfaceExtents(out[surfnum]); - - // lighting info - - for (i=0 ; i= 0) - out[i].children[j] = loadmodel.nodes[p]; - else - out[i].children[j] = loadmodel.leafs[-1 - p]; // mleaf_t extends mnode_t - } - } - - Mod_SetParent(loadmodel.nodes[0], null); // sets nodes and leafs - } - - /* - ================= - Mod_LoadLeafs - ================= - */ - void Mod_LoadLeafs(lump_t l) - { - qfiles.dleaf_t in; - mleaf_t[] out; - int i, j, count, p; - - if ((l.filelen % qfiles.dleaf_t.SIZE) != 0) - Com.Error (Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name); - - count = l.filelen / qfiles.dleaf_t.SIZE; - // out = Hunk_Alloc ( count*sizeof(*out)); - out = new mleaf_t[count]; - - loadmodel.leafs = out; - loadmodel.numleafs = count; - - ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); - bb.order(ByteOrder.LITTLE_ENDIAN); - - for ( i=0 ; i= loadmodel.numsurfaces) - Com.Error(Defines.ERR_DROP, "Mod_ParseMarksurfaces: bad surface number"); - - out[i] = loadmodel.surfaces[j]; - } - } - - - /* - ================= - Mod_LoadSurfedges - ================= - */ - void Mod_LoadSurfedges(lump_t l) - { - int i, count; - int[] offsets; - - if ( (l.filelen % Defines.SIZE_OF_INT) != 0) - Com.Error (Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name); - - count = l.filelen / Defines.SIZE_OF_INT; - if (count < 1 || count >= Defines.MAX_MAP_SURFEDGES) - Com.Error (Defines.ERR_DROP, "MOD_LoadBmodel: bad surfedges count in " + loadmodel.name + ": " + count); - - offsets = new int[count]; - - loadmodel.surfedges = offsets; - loadmodel.numsurfedges = count; - - ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); - bb.order(ByteOrder.LITTLE_ENDIAN); - - for ( i=0 ; i= loadmodel.numnodes) - Com.Error(Defines.ERR_DROP, "Inline model " + i + " has bad firstnode"); - - Math3D.VectorCopy(bm.maxs, starmod.maxs); - Math3D.VectorCopy(bm.mins, starmod.mins); - starmod.radius = bm.radius; - - if (i == 0) - loadmodel = starmod.copy(); - - starmod.numleafs = bm.visleafs; - } - } - - /* - ============================================================================== - - ALIAS MODELS - - ============================================================================== - */ - - /* - ================= - Mod_LoadAliasModel - ================= - */ - void Mod_LoadAliasModel (model_t mod, ByteBuffer buffer) - { - int i, j; - qfiles.dmdl_t pheader; - qfiles.dstvert_t[] poutst; - qfiles.dtriangle_t[] pouttri; - qfiles.daliasframe_t[] poutframe; - int[] poutcmd; - - pheader = new qfiles.dmdl_t(buffer); - - if (pheader.version != qfiles.ALIAS_VERSION) - Com.Error(Defines.ERR_DROP, "%s has wrong version number (%i should be %i)", - new Vargs(3).add(mod.name).add(pheader.version).add(qfiles.ALIAS_VERSION)); - - if (pheader.skinheight > MAX_LBM_HEIGHT) - Com.Error(Defines.ERR_DROP, "model "+ mod.name +" has a skin taller than " + MAX_LBM_HEIGHT); - - if (pheader.num_xyz <= 0) - Com.Error(Defines.ERR_DROP, "model " + mod.name + " has no vertices"); - - if (pheader.num_xyz > qfiles.MAX_VERTS) - Com.Error(Defines.ERR_DROP, "model " + mod.name +" has too many vertices"); - - if (pheader.num_st <= 0) - Com.Error(Defines.ERR_DROP, "model " + mod.name + " has no st vertices"); - - if (pheader.num_tris <= 0) - Com.Error(Defines.ERR_DROP, "model " + mod.name + " has no triangles"); - - if (pheader.num_frames <= 0) - Com.Error(Defines.ERR_DROP, "model " + mod.name + " has no frames"); - - // - // load base s and t vertices (not used in gl version) - // - poutst = new qfiles.dstvert_t[pheader.num_st]; - buffer.position(pheader.ofs_st); - for (i=0 ; i -1) { - skinNames[i] = skinNames[i].substring(0, n); - } - mod.skins[i] = GL_FindImage(skinNames[i], it_skin); - } - - // set the model arrays - pheader.skinNames = skinNames; // skin names - pheader.stVerts = poutst; // textur koordinaten - pheader.triAngles = pouttri; // dreiecke - pheader.glCmds = poutcmd; // STRIP or FAN - pheader.aliasFrames = poutframe; // frames mit vertex array - - mod.extradata = pheader; - - mod.mins[0] = -32; - mod.mins[1] = -32; - mod.mins[2] = -32; - mod.maxs[0] = 32; - mod.maxs[1] = 32; - mod.maxs[2] = 32; - - precompileGLCmds(pheader); - } - - /* - ============================================================================== - - SPRITE MODELS - - ============================================================================== - */ - - /* - ================= - Mod_LoadSpriteModel - ================= - */ - void Mod_LoadSpriteModel(model_t mod, ByteBuffer buffer) - { - qfiles.dsprite_t sprout = new qfiles.dsprite_t(buffer); - - if (sprout.version != qfiles.SPRITE_VERSION) - Com.Error(Defines.ERR_DROP, "%s has wrong version number (%i should be %i)", - new Vargs(3).add(mod.name).add(sprout.version).add(qfiles.SPRITE_VERSION)); - - if (sprout.numframes > qfiles.MAX_MD2SKINS) - Com.Error(Defines.ERR_DROP, "%s has too many frames (%i > %i)", - new Vargs(3).add(mod.name).add(sprout.numframes).add(qfiles.MAX_MD2SKINS)); - - for (int i=0 ; i 0) + node = node.children[0]; + else + node = node.children[1]; + } + // never reached + } + + byte[] decompressed = new byte[Defines.MAX_MAP_LEAFS / 8]; + + byte[] model_visibility = new byte[Defines.MAX_MAP_VISIBILITY]; + + /* + * =================== Mod_DecompressVis =================== + */ + byte[] Mod_DecompressVis(byte[] in, int offset, model_t model) { + int c; + byte[] out; + int outp, inp; + int row; + + row = (model.vis.numclusters + 7) >> 3; + out = decompressed; + outp = 0; + inp = offset; + + if (in == null) { // no vis info, so make all visible + while (row != 0) { + out[outp++] = (byte) 0xFF; + row--; + } + return decompressed; + } + + do { + if (in[inp] != 0) { + out[outp++] = in[inp++]; + continue; + } + + c = in[inp + 1] & 0xFF; + inp += 2; + while (c != 0) { + out[outp++] = 0; + c--; + } + } while (outp < row); + + return decompressed; + } + + /* + * ============== Mod_ClusterPVS ============== + */ + byte[] Mod_ClusterPVS(int cluster, model_t model) { + if (cluster == -1 || model.vis == null) + return mod_novis; + //return Mod_DecompressVis( (byte *)model.vis + + // model.vis.bitofs[cluster][Defines.DVIS_PVS], model); + return Mod_DecompressVis(model_visibility, + model.vis.bitofs[cluster][Defines.DVIS_PVS], model); + } + + // =============================================================================== + + /* + * ================ Mod_Modellist_f ================ + */ + void Mod_Modellist_f() { + int i; + model_t mod; + int total; + + total = 0; + VID.Printf(Defines.PRINT_ALL, "Loaded models:\n"); + for (i = 0; i < mod_numknown; i++) { + mod = mod_known[i]; + if (mod.name == "") + continue; + + VID.Printf(Defines.PRINT_ALL, "%8i : %s\n", new Vargs(2).add( + mod.extradatasize).add(mod.name)); + total += mod.extradatasize; + } + VID.Printf(Defines.PRINT_ALL, "Total resident: " + total + '\n'); + } + + /* + * =============== Mod_Init =============== + */ + void Mod_Init() { + // init mod_known + for (int i = 0; i < MAX_MOD_KNOWN; i++) { + mod_known[i] = new model_t(); + } + Arrays.fill(mod_novis, (byte) 0xff); + } + + byte[] fileBuffer; + + /* + * ================== Mod_ForName + * + * Loads in a model for the given name ================== + */ + model_t Mod_ForName(String name, boolean crash) { + model_t mod = null; + int i; + + if (name == null || name.length() == 0) + Com.Error(Defines.ERR_DROP, "Mod_ForName: NULL name"); + + // + // inline models are grabbed only from worldmodel + // + if (name.charAt(0) == '*') { + i = Integer.parseInt(name.substring(1)); + if (i < 1 || r_worldmodel == null || i >= r_worldmodel.numsubmodels) + Com.Error(Defines.ERR_DROP, "bad inline model number"); + return mod_inline[i]; + } + + // + // search the currently loaded models + // + for (i = 0; i < mod_numknown; i++) { + mod = mod_known[i]; + + if (mod.name == "") + continue; + if (mod.name.equals(name)) + return mod; + } + + // + // find a free model slot spot + // + for (i = 0; i < mod_numknown; i++) { + mod = mod_known[i]; + + if (mod.name == "") + break; // free spot + } + if (i == mod_numknown) { + if (mod_numknown == MAX_MOD_KNOWN) + Com.Error(Defines.ERR_DROP, "mod_numknown == MAX_MOD_KNOWN"); + mod_numknown++; + mod = mod_known[i]; + } + + mod.name = name; + + // + // load the file + // + fileBuffer = FS.LoadFile(name); + + if (fileBuffer == null) { + if (crash) + Com.Error(Defines.ERR_DROP, "Mod_NumForName: " + mod.name + + " not found"); + + mod.name = ""; + return null; + } + + modfilelen = fileBuffer.length; + + loadmodel = mod; + + // + // fill it in + // + ByteBuffer bb = ByteBuffer.wrap(fileBuffer); + bb.order(ByteOrder.LITTLE_ENDIAN); + + // call the apropriate loader + + bb.mark(); + int ident = bb.getInt(); + + bb.reset(); + + switch (ident) { + case qfiles.IDALIASHEADER: + Mod_LoadAliasModel(mod, bb); + break; + case qfiles.IDSPRITEHEADER: + Mod_LoadSpriteModel(mod, bb); + break; + case qfiles.IDBSPHEADER: + Mod_LoadBrushModel(mod, bb); + break; + default: + Com.Error(Defines.ERR_DROP, "Mod_NumForName: unknown fileid for " + + mod.name); + break; + } + + this.fileBuffer = null; // free it for garbage collection + return mod; + } + + /* + * =============================================================================== + * + * BRUSHMODEL LOADING + * + * =============================================================================== + */ + + byte[] mod_base; + + /* + * ================= Mod_LoadLighting ================= + */ + void Mod_LoadLighting(lump_t l) { + if (l.filelen == 0) { + loadmodel.lightdata = null; + return; + } + // memcpy (loadmodel.lightdata, mod_base + l.fileofs, l.filelen); + loadmodel.lightdata = new byte[l.filelen]; + System + .arraycopy(mod_base, l.fileofs, loadmodel.lightdata, 0, + l.filelen); + } + + /* + * ================= Mod_LoadVisibility ================= + */ + void Mod_LoadVisibility(lump_t l) { + int i; + + if (l.filelen == 0) { + loadmodel.vis = null; + return; + } + + System.arraycopy(mod_base, l.fileofs, model_visibility, 0, l.filelen); + + ByteBuffer bb = ByteBuffer.wrap(model_visibility, 0, l.filelen); + + loadmodel.vis = new qfiles.dvis_t(bb.order(ByteOrder.LITTLE_ENDIAN)); + + /* + * done: memcpy (loadmodel.vis, mod_base + l.fileofs, l.filelen); + * + * loadmodel.vis.numclusters = LittleLong (loadmodel.vis.numclusters); + * for (i=0 ; i Math.abs(maxs[i]) ? Math + .abs(mins[i]) : Math.abs(maxs[i]); + } + return Math3D.VectorLength(corner); + } + + /* + * ================= Mod_LoadSubmodels ================= + */ + void Mod_LoadSubmodels(lump_t l) { + qfiles.dmodel_t in; + mmodel_t[] out; + int i, j, count; + + if ((l.filelen % qfiles.dmodel_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + + loadmodel.name); + + count = l.filelen / qfiles.dmodel_t.SIZE; + // out = Hunk_Alloc ( count*sizeof(*out)); + out = new mmodel_t[count]; + + loadmodel.submodels = out; + loadmodel.numsubmodels = count; + + ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + for (i = 0; i < count; i++) { + in = new qfiles.dmodel_t(bb); + out[i] = new mmodel_t(); + for (j = 0; j < 3; j++) { // spread the mins / maxs by a pixel + out[i].mins[j] = in.mins[j] - 1; + out[i].maxs[j] = in.maxs[j] + 1; + out[i].origin[j] = in.origin[j]; + } + out[i].radius = RadiusFromBounds(out[i].mins, out[i].maxs); + out[i].headnode = in.headnode; + out[i].firstface = in.firstface; + out[i].numfaces = in.numfaces; + } + } + + /* + * ================= Mod_LoadEdges ================= + */ + void Mod_LoadEdges(lump_t l) { + medge_t[] edges; + int i, count; + + if ((l.filelen % medge_t.DISK_SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + + loadmodel.name); + + count = l.filelen / medge_t.DISK_SIZE; + // out = Hunk_Alloc ( (count + 1) * sizeof(*out)); + edges = new medge_t[count + 1]; + + loadmodel.edges = edges; + loadmodel.numedges = count; + + ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + for (i = 0; i < count; i++) { + edges[i] = new medge_t(bb); + } + } + + /* + * ================= Mod_LoadTexinfo ================= + */ + void Mod_LoadTexinfo(lump_t l) { + texinfo_t in; + mtexinfo_t[] out; + mtexinfo_t step; + int i, j, count; + int next; + String name; + + if ((l.filelen % texinfo_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + + loadmodel.name); + + count = l.filelen / texinfo_t.SIZE; + // out = Hunk_Alloc ( count*sizeof(*out)); + out = new mtexinfo_t[count]; + for (i = 0; i < count; i++) { + out[i] = new mtexinfo_t(); + } + + loadmodel.texinfo = out; + loadmodel.numtexinfo = count; + + ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + for (i = 0; i < count; i++) { + + in = new texinfo_t(bb); + out[i].vecs = in.vecs; + out[i].flags = in.flags; + next = in.nexttexinfo; + if (next > 0) + out[i].next = loadmodel.texinfo[next]; + else + out[i].next = null; + + name = "textures/" + in.texture + ".wal"; + + out[i].image = GL_FindImage(name, it_wall); + if (out[i].image == null) { + VID.Printf(Defines.PRINT_ALL, "Couldn't load " + name + '\n'); + out[i].image = r_notexture; + } + } + + // count animation frames + for (i = 0; i < count; i++) { + out[i].numframes = 1; + for (step = out[i].next; (step != null) && (step != out[i]); step = step.next) + out[i].numframes++; + } + } + + /* + * ================ CalcSurfaceExtents + * + * Fills in s.texturemins[] and s.extents[] ================ + */ + void CalcSurfaceExtents(msurface_t s) { + float[] mins = { 0, 0 }; + float[] maxs = { 0, 0 }; + float val; + + int j, e; + mvertex_t v; + int[] bmins = { 0, 0 }; + int[] bmaxs = { 0, 0 }; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + mtexinfo_t tex = s.texinfo; + + for (int i = 0; i < s.numedges; i++) { + e = loadmodel.surfedges[s.firstedge + i]; + if (e >= 0) + v = loadmodel.vertexes[loadmodel.edges[e].v[0]]; + else + v = loadmodel.vertexes[loadmodel.edges[-e].v[1]]; + + for (j = 0; j < 2; j++) { + val = v.position[0] * tex.vecs[j][0] + v.position[1] + * tex.vecs[j][1] + v.position[2] * tex.vecs[j][2] + + tex.vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (int i = 0; i < 2; i++) { + bmins[i] = (int) Math.floor(mins[i] / 16); + bmaxs[i] = (int) Math.ceil(maxs[i] / 16); + + s.texturemins[i] = (short) (bmins[i] * 16); + s.extents[i] = (short) ((bmaxs[i] - bmins[i]) * 16); + + } + } + + /* + * ================= Mod_LoadFaces ================= + */ + void Mod_LoadFaces(lump_t l) { + qfiles.dface_t in; + msurface_t[] out; + int i, count, surfnum; + int planenum, side; + int ti; + + if ((l.filelen % qfiles.dface_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + + loadmodel.name); + + count = l.filelen / qfiles.dface_t.SIZE; + // out = Hunk_Alloc ( count*sizeof(*out)); + out = new msurface_t[count]; + + loadmodel.surfaces = out; + loadmodel.numsurfaces = count; + + ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + currentmodel = loadmodel; + + GL_BeginBuildingLightmaps(loadmodel); + + for (surfnum = 0; surfnum < count; surfnum++) { + in = new qfiles.dface_t(bb); + out[surfnum] = new msurface_t(); + out[surfnum].firstedge = in.firstedge; + out[surfnum].numedges = in.numedges; + out[surfnum].flags = 0; + out[surfnum].polys = null; + + planenum = in.planenum; + side = in.side; + if (side != 0) + out[surfnum].flags |= Defines.SURF_PLANEBACK; + + out[surfnum].plane = loadmodel.planes[planenum]; + + ti = in.texinfo; + if (ti < 0 || ti >= loadmodel.numtexinfo) + Com.Error(Defines.ERR_DROP, + "MOD_LoadBmodel: bad texinfo number"); + + out[surfnum].texinfo = loadmodel.texinfo[ti]; + + CalcSurfaceExtents(out[surfnum]); + + // lighting info + + for (i = 0; i < Defines.MAXLIGHTMAPS; i++) + out[surfnum].styles[i] = in.styles[i]; + + i = in.lightofs; + if (i == -1) + out[surfnum].samples = null; + else { + ByteBuffer pointer = ByteBuffer.wrap(loadmodel.lightdata); + pointer.position(i); + pointer = pointer.slice(); + pointer.mark(); + out[surfnum].samples = pointer; // subarray + } + + // set the drawing flags + + if ((out[surfnum].texinfo.flags & Defines.SURF_WARP) != 0) { + out[surfnum].flags |= Defines.SURF_DRAWTURB; + for (i = 0; i < 2; i++) { + out[surfnum].extents[i] = 16384; + out[surfnum].texturemins[i] = -8192; + } + GL_SubdivideSurface(out[surfnum]); // cut up polygon for warps + } + + // create lightmaps and polygons + if ((out[surfnum].texinfo.flags & (Defines.SURF_SKY + | Defines.SURF_TRANS33 | Defines.SURF_TRANS66 | Defines.SURF_WARP)) == 0) + GL_CreateSurfaceLightmap(out[surfnum]); + + if ((out[surfnum].texinfo.flags & Defines.SURF_WARP) == 0) + GL_BuildPolygonFromSurface(out[surfnum]); + + } + GL_EndBuildingLightmaps(); + } + + /* + * ================= Mod_SetParent ================= + */ + void Mod_SetParent(mnode_t node, mnode_t parent) { + node.parent = parent; + if (node.contents != -1) + return; + Mod_SetParent(node.children[0], node); + Mod_SetParent(node.children[1], node); + } + + /* + * ================= Mod_LoadNodes ================= + */ + void Mod_LoadNodes(lump_t l) { + int i, j, count, p; + qfiles.dnode_t in; + mnode_t[] out; + + if ((l.filelen % qfiles.dnode_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + + loadmodel.name); + + count = l.filelen / qfiles.dnode_t.SIZE; + // out = Hunk_Alloc ( count*sizeof(*out)); + out = new mnode_t[count]; + + loadmodel.nodes = out; + loadmodel.numnodes = count; + + ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + // initialize the tree array + for (i = 0; i < count; i++) + out[i] = new mnode_t(); // do first before linking + + // fill and link the nodes + for (i = 0; i < count; i++) { + in = new qfiles.dnode_t(bb); + for (j = 0; j < 3; j++) { + out[i].mins[j] = in.mins[j]; + out[i].maxs[j] = in.maxs[j]; + } + + p = in.planenum; + out[i].plane = loadmodel.planes[p]; + + out[i].firstsurface = in.firstface; + out[i].numsurfaces = in.numfaces; + out[i].contents = -1; // differentiate from leafs + + for (j = 0; j < 2; j++) { + p = in.children[j]; + if (p >= 0) + out[i].children[j] = loadmodel.nodes[p]; + else + out[i].children[j] = loadmodel.leafs[-1 - p]; // mleaf_t + // extends + // mnode_t + } + } + + Mod_SetParent(loadmodel.nodes[0], null); // sets nodes and leafs + } + + /* + * ================= Mod_LoadLeafs ================= + */ + void Mod_LoadLeafs(lump_t l) { + qfiles.dleaf_t in; + mleaf_t[] out; + int i, j, count, p; + + if ((l.filelen % qfiles.dleaf_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + + loadmodel.name); + + count = l.filelen / qfiles.dleaf_t.SIZE; + // out = Hunk_Alloc ( count*sizeof(*out)); + out = new mleaf_t[count]; + + loadmodel.leafs = out; + loadmodel.numleafs = count; + + ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + for (i = 0; i < count; i++) { + in = new qfiles.dleaf_t(bb); + out[i] = new mleaf_t(); + for (j = 0; j < 3; j++) { + out[i].mins[j] = in.mins[j]; + out[i].maxs[j] = in.maxs[j]; + + } + + out[i].contents = in.contents; + out[i].cluster = in.cluster; + out[i].area = in.area; + + out[i].setMarkSurface(in.firstleafface, loadmodel.marksurfaces); + out[i].nummarksurfaces = in.numleaffaces; + } + } + + /* + * ================= Mod_LoadMarksurfaces ================= + */ + void Mod_LoadMarksurfaces(lump_t l) { + int i, j, count; + + msurface_t[] out; + + if ((l.filelen % Defines.SIZE_OF_SHORT) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + + loadmodel.name); + count = l.filelen / Defines.SIZE_OF_SHORT; + // out = Hunk_Alloc ( count*sizeof(*out)); + out = new msurface_t[count]; + + loadmodel.marksurfaces = out; + loadmodel.nummarksurfaces = count; + + ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + for (i = 0; i < count; i++) { + j = bb.getShort(); + if (j < 0 || j >= loadmodel.numsurfaces) + Com.Error(Defines.ERR_DROP, + "Mod_ParseMarksurfaces: bad surface number"); + + out[i] = loadmodel.surfaces[j]; + } + } + + /* + * ================= Mod_LoadSurfedges ================= + */ + void Mod_LoadSurfedges(lump_t l) { + int i, count; + int[] offsets; + + if ((l.filelen % Defines.SIZE_OF_INT) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + + loadmodel.name); + + count = l.filelen / Defines.SIZE_OF_INT; + if (count < 1 || count >= Defines.MAX_MAP_SURFEDGES) + Com.Error(Defines.ERR_DROP, + "MOD_LoadBmodel: bad surfedges count in " + loadmodel.name + + ": " + count); + + offsets = new int[count]; + + loadmodel.surfedges = offsets; + loadmodel.numsurfedges = count; + + ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + for (i = 0; i < count; i++) + offsets[i] = bb.getInt(); + } + + /* + * ================= Mod_LoadPlanes ================= + */ + void Mod_LoadPlanes(lump_t l) { + int i, j; + cplane_t[] out; + qfiles.dplane_t in; + int count; + int bits; + + if ((l.filelen % qfiles.dplane_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + + loadmodel.name); + + count = l.filelen / qfiles.dplane_t.SIZE; + // out = Hunk_Alloc ( count*2*sizeof(*out)); + out = new cplane_t[count * 2]; + + loadmodel.planes = out; + loadmodel.numplanes = count; + + ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + for (i = 0; i < count; i++) { + bits = 0; + in = new qfiles.dplane_t(bb); + out[i] = new cplane_t(); + for (j = 0; j < 3; j++) { + out[i].normal[j] = in.normal[j]; + if (out[i].normal[j] < 0) + bits |= (1 << j); + } + + out[i].dist = in.dist; + out[i].type = (byte) in.type; + out[i].signbits = (byte) bits; + } + } + + /* + * ================= Mod_LoadBrushModel ================= + */ + void Mod_LoadBrushModel(model_t mod, ByteBuffer buffer) { + int i; + qfiles.dheader_t header; + mmodel_t bm; + + loadmodel.type = mod_brush; + if (loadmodel != mod_known[0]) + Com.Error(Defines.ERR_DROP, "Loaded a brush model after the world"); + + header = new qfiles.dheader_t(buffer); + + i = header.version; + if (i != Defines.BSPVERSION) + Com.Error(Defines.ERR_DROP, "Mod_LoadBrushModel: " + mod.name + + " has wrong version number (" + i + " should be " + + Defines.BSPVERSION + ")"); + + mod_base = fileBuffer; //(byte *)header; + + // load into heap + Mod_LoadVertexes(header.lumps[Defines.LUMP_VERTEXES]); // ok + Mod_LoadEdges(header.lumps[Defines.LUMP_EDGES]); // ok + Mod_LoadSurfedges(header.lumps[Defines.LUMP_SURFEDGES]); // ok + Mod_LoadLighting(header.lumps[Defines.LUMP_LIGHTING]); // ok + Mod_LoadPlanes(header.lumps[Defines.LUMP_PLANES]); // ok + Mod_LoadTexinfo(header.lumps[Defines.LUMP_TEXINFO]); // ok + Mod_LoadFaces(header.lumps[Defines.LUMP_FACES]); // ok + Mod_LoadMarksurfaces(header.lumps[Defines.LUMP_LEAFFACES]); + Mod_LoadVisibility(header.lumps[Defines.LUMP_VISIBILITY]); // ok + Mod_LoadLeafs(header.lumps[Defines.LUMP_LEAFS]); // ok + Mod_LoadNodes(header.lumps[Defines.LUMP_NODES]); // ok + Mod_LoadSubmodels(header.lumps[Defines.LUMP_MODELS]); + mod.numframes = 2; // regular and alternate animation + + // + // set up the submodels + // + model_t starmod; + + for (i = 0; i < mod.numsubmodels; i++) { + + bm = mod.submodels[i]; + starmod = mod_inline[i] = loadmodel.copy(); + + starmod.firstmodelsurface = bm.firstface; + starmod.nummodelsurfaces = bm.numfaces; + starmod.firstnode = bm.headnode; + if (starmod.firstnode >= loadmodel.numnodes) + Com.Error(Defines.ERR_DROP, "Inline model " + i + + " has bad firstnode"); + + Math3D.VectorCopy(bm.maxs, starmod.maxs); + Math3D.VectorCopy(bm.mins, starmod.mins); + starmod.radius = bm.radius; + + if (i == 0) + loadmodel = starmod.copy(); + + starmod.numleafs = bm.visleafs; + } + } + + /* + * ============================================================================== + * + * ALIAS MODELS + * + * ============================================================================== + */ + + /* + * ================= Mod_LoadAliasModel ================= + */ + void Mod_LoadAliasModel(model_t mod, ByteBuffer buffer) { + int i, j; + qfiles.dmdl_t pheader; + qfiles.dstvert_t[] poutst; + qfiles.dtriangle_t[] pouttri; + qfiles.daliasframe_t[] poutframe; + int[] poutcmd; + + pheader = new qfiles.dmdl_t(buffer); + + if (pheader.version != qfiles.ALIAS_VERSION) + Com.Error(Defines.ERR_DROP, + "%s has wrong version number (%i should be %i)", new Vargs( + 3).add(mod.name).add(pheader.version).add( + qfiles.ALIAS_VERSION)); + + if (pheader.skinheight > MAX_LBM_HEIGHT) + Com.Error(Defines.ERR_DROP, "model " + mod.name + + " has a skin taller than " + MAX_LBM_HEIGHT); + + if (pheader.num_xyz <= 0) + Com.Error(Defines.ERR_DROP, "model " + mod.name + + " has no vertices"); + + if (pheader.num_xyz > qfiles.MAX_VERTS) + Com.Error(Defines.ERR_DROP, "model " + mod.name + + " has too many vertices"); + + if (pheader.num_st <= 0) + Com.Error(Defines.ERR_DROP, "model " + mod.name + + " has no st vertices"); + + if (pheader.num_tris <= 0) + Com.Error(Defines.ERR_DROP, "model " + mod.name + + " has no triangles"); + + if (pheader.num_frames <= 0) + Com.Error(Defines.ERR_DROP, "model " + mod.name + " has no frames"); + + // + // load base s and t vertices (not used in gl version) + // + poutst = new qfiles.dstvert_t[pheader.num_st]; + buffer.position(pheader.ofs_st); + for (i = 0; i < pheader.num_st; i++) { + poutst[i] = new qfiles.dstvert_t(buffer); + } + + // + // load triangle lists + // + pouttri = new qfiles.dtriangle_t[pheader.num_tris]; + buffer.position(pheader.ofs_tris); + for (i = 0; i < pheader.num_tris; i++) { + pouttri[i] = new qfiles.dtriangle_t(buffer); + } + + // + // load the frames + // + poutframe = new qfiles.daliasframe_t[pheader.num_frames]; + buffer.position(pheader.ofs_frames); + for (i = 0; i < pheader.num_frames; i++) { + poutframe[i] = new qfiles.daliasframe_t(buffer); + // verts are all 8 bit, so no swapping needed + poutframe[i].verts = new qfiles.dtrivertx_t[pheader.num_xyz]; + for (int k = 0; k < pheader.num_xyz; k++) { + poutframe[i].verts[k] = new qfiles.dtrivertx_t(buffer); + } + } + + mod.type = mod_alias; + + // + // load the glcmds + // + poutcmd = new int[pheader.num_glcmds]; + buffer.position(pheader.ofs_glcmds); + for (i = 0; i < pheader.num_glcmds; i++) + poutcmd[i] = buffer.getInt(); // LittleLong (pincmd[i]); + + // register all skins + String[] skinNames = new String[pheader.num_skins]; + byte[] nameBuf = new byte[qfiles.MAX_SKINNAME]; + buffer.position(pheader.ofs_skins); + for (i = 0; i < pheader.num_skins; i++) { + buffer.get(nameBuf); + skinNames[i] = new String(nameBuf); + int n = skinNames[i].indexOf('\0'); + if (n > -1) { + skinNames[i] = skinNames[i].substring(0, n); + } + mod.skins[i] = GL_FindImage(skinNames[i], it_skin); + } + + // set the model arrays + pheader.skinNames = skinNames; // skin names + pheader.stVerts = poutst; // textur koordinaten + pheader.triAngles = pouttri; // dreiecke + pheader.glCmds = poutcmd; // STRIP or FAN + pheader.aliasFrames = poutframe; // frames mit vertex array + + mod.extradata = pheader; + + mod.mins[0] = -32; + mod.mins[1] = -32; + mod.mins[2] = -32; + mod.maxs[0] = 32; + mod.maxs[1] = 32; + mod.maxs[2] = 32; + + precompileGLCmds(pheader); + } + + /* + * ============================================================================== + * + * SPRITE MODELS + * + * ============================================================================== + */ + + /* + * ================= Mod_LoadSpriteModel ================= + */ + void Mod_LoadSpriteModel(model_t mod, ByteBuffer buffer) { + qfiles.dsprite_t sprout = new qfiles.dsprite_t(buffer); + + if (sprout.version != qfiles.SPRITE_VERSION) + Com.Error(Defines.ERR_DROP, + "%s has wrong version number (%i should be %i)", new Vargs( + 3).add(mod.name).add(sprout.version).add( + qfiles.SPRITE_VERSION)); + + if (sprout.numframes > qfiles.MAX_MD2SKINS) + Com.Error(Defines.ERR_DROP, "%s has too many frames (%i > %i)", + new Vargs(3).add(mod.name).add(sprout.numframes).add( + qfiles.MAX_MD2SKINS)); + + for (int i = 0; i < sprout.numframes; i++) { + mod.skins[i] = GL_FindImage(sprout.frames[i].name, it_sprite); + } + + mod.type = mod_sprite; + mod.extradata = sprout; + } + + // ============================================================================= + + /* + * @@@@@@@@@@@@@@@@@@@@@ R_BeginRegistration + * + * Specifies the model that will be used as the world @@@@@@@@@@@@@@@@@@@@@ + */ + protected void R_BeginRegistration(String model) { + resetModelArrays(); + resetPolygonArrays(); + + cvar_t flushmap; + + registration_sequence++; + r_oldviewcluster = -1; // force markleafs + + String fullname = "maps/" + model + ".bsp"; + + // explicitly free the old map if different + // this guarantees that mod_known[0] is the world map + flushmap = Cvar.Get("flushmap", "0", 0); + if (!mod_known[0].name.equals(fullname) || flushmap.value != 0.0f) + Mod_Free(mod_known[0]); + r_worldmodel = Mod_ForName(fullname, true); + + r_viewcluster = -1; + } + + /* + * @@@@@@@@@@@@@@@@@@@@@ R_RegisterModel + * + * @@@@@@@@@@@@@@@@@@@@@ + */ + protected model_t R_RegisterModel(String name) { + model_t mod = null; + int i; + qfiles.dsprite_t sprout; + qfiles.dmdl_t pheader; + + mod = Mod_ForName(name, false); + if (mod != null) { + mod.registration_sequence = registration_sequence; + + // register any images used by the models + if (mod.type == mod_sprite) { + sprout = (qfiles.dsprite_t) mod.extradata; + for (i = 0; i < sprout.numframes; i++) + mod.skins[i] = GL_FindImage(sprout.frames[i].name, + it_sprite); + } else if (mod.type == mod_alias) { + pheader = (qfiles.dmdl_t) mod.extradata; + for (i = 0; i < pheader.num_skins; i++) + mod.skins[i] = GL_FindImage(pheader.skinNames[i], it_skin); + // PGM + mod.numframes = pheader.num_frames; + // PGM + } else if (mod.type == mod_brush) { + for (i = 0; i < mod.numtexinfo; i++) + mod.texinfo[i].image.registration_sequence = registration_sequence; + } + } + return mod; + } + + /* + * @@@@@@@@@@@@@@@@@@@@@ R_EndRegistration + * + * @@@@@@@@@@@@@@@@@@@@@ + */ + protected void R_EndRegistration() { + model_t mod; + + for (int i = 0; i < mod_numknown; i++) { + mod = mod_known[i]; + if (mod.name == "") + continue; + if (mod.registration_sequence != registration_sequence) { // don't + // need + // this + // model + Mod_Free(mod); + } else { + // precompile AliasModels + if (mod.type == mod_alias) + precompileGLCmds((qfiles.dmdl_t) mod.extradata); + } + } + GL_FreeUnusedImages(); + + //modelMemoryUsage(); + } + + // ============================================================================= + + /* + * ================ Mod_Free ================ + */ + void Mod_Free(model_t mod) { + mod.clear(); + } + + /* + * ================ Mod_FreeAll ================ + */ + void Mod_FreeAll() { + for (int i = 0; i < mod_numknown; i++) { + if (mod_known[i].extradata != null) + Mod_Free(mod_known[i]); + } + } + + /* + * new functions for vertex array handling + */ + static final int MODEL_BUFFER_SIZE = 50000; + + static FloatBuffer globalModelTextureCoordBuf = BufferUtils + .newFloatBuffer(MODEL_BUFFER_SIZE * 2); + + static IntBuffer globalModelVertexIndexBuf = BufferUtils + .newIntBuffer(MODEL_BUFFER_SIZE); + + void precompileGLCmds(qfiles.dmdl_t model) { + model.textureCoordBuf = globalModelTextureCoordBuf.slice(); + model.vertexIndexBuf = globalModelVertexIndexBuf.slice(); + Vector tmp = new Vector(); + + int count = 0; + int[] order = model.glCmds; + int orderIndex = 0; + while (true) { + // get the vertex count and primitive type + count = order[orderIndex++]; + if (count == 0) + break; // done + + tmp.addElement(new Integer(count)); + + if (count < 0) { + count = -count; + //gl.glBegin (GL.GL_TRIANGLE_FAN); + } else { + //gl.glBegin (GL.GL_TRIANGLE_STRIP); + } + + do { + // texture coordinates come from the draw list + globalModelTextureCoordBuf.put(Float + .intBitsToFloat(order[orderIndex + 0])); + globalModelTextureCoordBuf.put(Float + .intBitsToFloat(order[orderIndex + 1])); + globalModelVertexIndexBuf.put(order[orderIndex + 2]); + + orderIndex += 3; + } while (--count != 0); + } + + int size = tmp.size(); + + model.counts = new int[size]; + model.indexElements = new IntBuffer[size]; + + count = 0; + int pos = 0; + for (int i = 0; i < model.counts.length; i++) { + count = ((Integer) tmp.get(i)).intValue(); + model.counts[i] = count; + + count = (count < 0) ? -count : count; + model.vertexIndexBuf.position(pos); + model.indexElements[i] = model.vertexIndexBuf.slice(); + pos += count; + } + } + + static void resetModelArrays() { + globalModelTextureCoordBuf.rewind(); + globalModelVertexIndexBuf.rewind(); + } + + static void modelMemoryUsage() { + System.out.println("AliasModels: globalVertexBuffer size " + + globalModelVertexIndexBuf.position()); + } +} \ No newline at end of file diff --git a/src/jake2/render/fastjogl/Surf.java b/src/jake2/render/fastjogl/Surf.java index 32f1a92..e15e1d8 100644 --- a/src/jake2/render/fastjogl/Surf.java +++ b/src/jake2/render/fastjogl/Surf.java @@ -2,38 +2,49 @@ * Surf.java * Copyright (C) 2003 * - * $Id: Surf.java,v 1.4 2004-07-19 19:39:57 hzi Exp $ + * $Id: Surf.java,v 1.5 2004-09-22 19:22:11 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.render.fastjogl; import jake2.Defines; -import jake2.client.*; +import jake2.client.dlight_t; +import jake2.client.entity_t; +import jake2.client.lightstyle_t; import jake2.game.cplane_t; import jake2.qcommon.Com; -import jake2.render.*; +import jake2.render.glpoly_t; +import jake2.render.image_t; +import jake2.render.medge_t; +import jake2.render.mleaf_t; +import jake2.render.mnode_t; +import jake2.render.model_t; +import jake2.render.msurface_t; +import jake2.render.mtexinfo_t; import jake2.util.Lib; import jake2.util.Math3D; -import java.nio.*; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; import java.util.Arrays; import net.java.games.jogl.GL; @@ -41,1423 +52,1310 @@ import net.java.games.jogl.util.BufferUtils; /** * Surf - * + * * @author cwei */ public abstract class Surf extends Draw { - // GL_RSURF.C: surface-related refresh code - float[] modelorg = {0, 0, 0}; // relative to viewpoint - - msurface_t r_alpha_surfaces; - - static final int DYNAMIC_LIGHT_WIDTH = 128; - static final int DYNAMIC_LIGHT_HEIGHT = 128; - - static final int LIGHTMAP_BYTES = 4; - - static final int BLOCK_WIDTH = 128; - static final int BLOCK_HEIGHT = 128; - - static final int MAX_LIGHTMAPS = 128; - - int c_visible_lightmaps; - int c_visible_textures; - - static final int GL_LIGHTMAP_FORMAT = GL.GL_RGBA; - - static class gllightmapstate_t - { - int internal_format; - int current_lightmap_texture; - - msurface_t[] lightmap_surfaces = new msurface_t[MAX_LIGHTMAPS]; - int[] allocated = new int[BLOCK_WIDTH]; - - // the lightmap texture data needs to be kept in - // main memory so texsubimage can update properly - //byte[] lightmap_buffer = new byte[4 * BLOCK_WIDTH * BLOCK_HEIGHT]; - IntBuffer lightmap_buffer = Lib.newIntBuffer(BLOCK_WIDTH * BLOCK_HEIGHT, ByteOrder.LITTLE_ENDIAN); - - public gllightmapstate_t() { - for (int i = 0; i < MAX_LIGHTMAPS; i++) - lightmap_surfaces[i] = new msurface_t(); - } - - public void clearLightmapSurfaces() { - for (int i = 0; i < MAX_LIGHTMAPS; i++) - // TODO lightmap_surfaces[i].clear(); - lightmap_surfaces[i] = new msurface_t(); - } - - } - - gllightmapstate_t gl_lms = new gllightmapstate_t(); - - // Model.java - abstract byte[] Mod_ClusterPVS(int cluster, model_t model); - // Warp.java - abstract void R_DrawSkyBox(); - abstract void R_AddSkySurface(msurface_t surface); - abstract void R_ClearSkyBox(); - abstract void EmitWaterPolys(msurface_t fa); - // Light.java - abstract void R_MarkLights (dlight_t light, int bit, mnode_t node); - abstract void R_SetCacheState( msurface_t surf ); - abstract void R_BuildLightMap(msurface_t surf, IntBuffer dest, int stride); - - /* - ============================================================= - - BRUSH MODELS - - ============================================================= - */ - - /* - =============== - R_TextureAnimation - - Returns the proper texture for a given time and base texture - =============== - */ - image_t R_TextureAnimation(mtexinfo_t tex) - { - int c; - - if (tex.next == null) - return tex.image; - - c = currententity.frame % tex.numframes; - while (c != 0) - { - tex = tex.next; - c--; - } - - return tex.image; - } - - /* - ================ - DrawGLPoly - ================ - */ - void DrawGLPoly(glpoly_t p) - { - gl.glDrawArrays(GL.GL_POLYGON, p.pos, p.numverts); - } - - // ============ - // PGM - /* - ================ - DrawGLFlowingPoly -- version of DrawGLPoly that handles scrolling texture - ================ - */ - void DrawGLFlowingPoly(glpoly_t p) - { - int i; - float scroll; - - scroll = -64 * ( (r_newrefdef.time / 40.0f) - (int)(r_newrefdef.time / 40.0f) ); - if(scroll == 0.0f) - scroll = -64.0f; - - FloatBuffer texCoord = globalPolygonInterleavedBuf; - float[][] v = p.verts; - int index = p.pos * POLYGON_STRIDE; - for (i=0 ; i= 32 || fa.styles[maps] == 0 ) && ( fa.dlightframe != r_framecount ) ) - { - // ist ersetzt durch temp2: unsigned temp[34*34]; - int smax, tmax; - - smax = (fa.extents[0]>>4)+1; - tmax = (fa.extents[1]>>4)+1; - - R_BuildLightMap( fa, temp2, smax); - R_SetCacheState( fa ); - - GL_Bind( gl_state.lightmap_textures + fa.lightmaptexturenum ); - - gl.glTexSubImage2D( GL.GL_TEXTURE_2D, 0, - fa.light_s, fa.light_t, - smax, tmax, - GL_LIGHTMAP_FORMAT, - GL.GL_UNSIGNED_BYTE, temp2 ); - - fa.lightmapchain = gl_lms.lightmap_surfaces[fa.lightmaptexturenum]; - gl_lms.lightmap_surfaces[fa.lightmaptexturenum] = fa; - } - else - { - fa.lightmapchain = gl_lms.lightmap_surfaces[0]; - gl_lms.lightmap_surfaces[0] = fa; - } - } - else - { - fa.lightmapchain = gl_lms.lightmap_surfaces[fa.lightmaptexturenum]; - gl_lms.lightmap_surfaces[fa.lightmaptexturenum] = fa; - } - } - - - /* - ================ - R_DrawAlphaSurfaces - - Draw water surfaces and windows. - The BSP tree is waled front to back, so unwinding the chain - of alpha_surfaces will draw back to front, giving proper ordering. - ================ - */ - void R_DrawAlphaSurfaces() - { - msurface_t s; - float intens; - - // - // go back to the world matrix - // - gl.glLoadMatrixf(r_world_matrix); - - gl.glEnable (GL.GL_BLEND); - GL_TexEnv(GL.GL_MODULATE ); - - - // the textures are prescaled up for a better lighting range, - // so scale it back down - intens = gl_state.inverse_intensity; - - gl.glInterleavedArrays(GL.GL_T2F_V3F, POLYGON_BYTE_STRIDE, globalPolygonInterleavedBuf); - - for (s=r_alpha_surfaces ; s != null ; s=s.texturechain) - { - GL_Bind(s.texinfo.image.texnum); - c_brush_polys++; - if ((s.texinfo.flags & Defines.SURF_TRANS33) != 0) - gl.glColor4f (intens, intens, intens, 0.33f); - else if ((s.texinfo.flags & Defines.SURF_TRANS66) != 0) - gl.glColor4f (intens, intens, intens, 0.66f); - else - gl.glColor4f (intens,intens,intens,1); - if ((s.flags & Defines.SURF_DRAWTURB) != 0) - EmitWaterPolys(s); - else if((s.texinfo.flags & Defines.SURF_FLOWING) != 0) // PGM 9/16/98 - DrawGLFlowingPoly(s.polys); // PGM - else - DrawGLPoly(s.polys); - } - - GL_TexEnv( GL.GL_REPLACE ); - gl.glColor4f (1,1,1,1); - gl.glDisable (GL.GL_BLEND); - - r_alpha_surfaces = null; - } - - /* - ================ - DrawTextureChains - ================ - */ - void DrawTextureChains() - { - int i; - msurface_t s; - image_t image; - - c_visible_textures = 0; - - for (i = 0; i < numgltextures ; i++) - { - image = gltextures[i]; - - if (image.registration_sequence == 0) - continue; - if (image.texturechain == null) - continue; - c_visible_textures++; - - for ( s = image.texturechain; s != null ; s=s.texturechain) - { - if ( ( s.flags & Defines.SURF_DRAWTURB) == 0 ) - R_RenderBrushPoly(s); - } - } - - GL_EnableMultitexture( false ); - for (i = 0; i < numgltextures ; i++) - { - image = gltextures[i]; - - if (image.registration_sequence == 0) - continue; - s = image.texturechain; - if (s == null) - continue; - - for ( ; s != null ; s=s.texturechain) - { - if ( (s.flags & Defines.SURF_DRAWTURB) != 0 ) - R_RenderBrushPoly(s); - } - - image.texturechain = null; - } - - GL_TexEnv( GL.GL_REPLACE ); - } - - // direct buffer - private IntBuffer temp = Lib.newIntBuffer(128 * 128, ByteOrder.LITTLE_ENDIAN); - - void GL_RenderLightmappedPoly( msurface_t surf ) - { - int i, nv = surf.polys.numverts; - int map = 0; - int index; - float[][] v; - FloatBuffer texCoord = globalPolygonInterleavedBuf; - image_t image = R_TextureAnimation( surf.texinfo ); - boolean is_dynamic = false; - int lmtex = surf.lightmaptexturenum; - glpoly_t p; - - // ersetzt goto - boolean gotoDynamic = false; - - for ( map = 0; map < Defines.MAXLIGHTMAPS && (surf.styles[map] != (byte)255); map++ ) - { - if ( r_newrefdef.lightstyles[surf.styles[map] & 0xFF].white != surf.cached_light[map] ) { - gotoDynamic = true; - break; - } - } - - // this is a hack from cwei - if (map == 4) map--; - - // dynamic this frame or dynamic previously - if ( gotoDynamic || ( surf.dlightframe == r_framecount ) ) - { - // label dynamic: - if ( gl_dynamic.value != 0 ) - { - if ( (surf.texinfo.flags & (Defines.SURF_SKY | Defines.SURF_TRANS33 | Defines.SURF_TRANS66 | Defines.SURF_WARP )) == 0 ) - { - is_dynamic = true; - } - } - } - - if ( is_dynamic ) - { - // ist raus gezogen worden int[] temp = new int[128*128]; - int smax, tmax; - - if ( ( (surf.styles[map] & 0xFF) >= 32 || surf.styles[map] == 0 ) && ( surf.dlightframe != r_framecount ) ) - { - smax = (surf.extents[0]>>4)+1; - tmax = (surf.extents[1]>>4)+1; - - R_BuildLightMap( surf, temp, smax); - R_SetCacheState( surf ); - - GL_MBind( GL_TEXTURE1, gl_state.lightmap_textures + surf.lightmaptexturenum ); - - lmtex = surf.lightmaptexturenum; - - gl.glTexSubImage2D( GL.GL_TEXTURE_2D, 0, - surf.light_s, surf.light_t, - smax, tmax, - GL_LIGHTMAP_FORMAT, - GL.GL_UNSIGNED_BYTE, temp ); - - } - else - { - smax = (surf.extents[0]>>4)+1; - tmax = (surf.extents[1]>>4)+1; - - R_BuildLightMap( surf, temp, smax); - - GL_MBind( GL_TEXTURE1, gl_state.lightmap_textures + 0 ); - - lmtex = 0; - - gl.glTexSubImage2D( GL.GL_TEXTURE_2D, 0, - surf.light_s, surf.light_t, - smax, tmax, - GL_LIGHTMAP_FORMAT, - GL.GL_UNSIGNED_BYTE, temp ); - - } - - c_brush_polys++; - - GL_MBind( GL_TEXTURE0, image.texnum ); - GL_MBind( GL_TEXTURE1, gl_state.lightmap_textures + lmtex ); - - // ========== - // PGM - if ((surf.texinfo.flags & Defines.SURF_FLOWING) != 0) - { - float scroll; - - scroll = -64 * ( (r_newrefdef.time / 40.0f) - (int)(r_newrefdef.time / 40.0f) ); - if(scroll == 0.0f) - scroll = -64.0f; - - for ( p = surf.polys; p != null; p = p.chain ) - { - v = p.verts; - index = p.pos * POLYGON_STRIDE; - for (i=0 ; isurfaces[currentmodel->firstmodelsurface]; - int psurfp = currentmodel.firstmodelsurface; - msurface_t[] surfaces; - surfaces = currentmodel.surfaces; - //psurf = surfaces[psurfp]; - - if ( (currententity.flags & Defines.RF_TRANSLUCENT) != 0 ) - { - gl.glEnable (GL.GL_BLEND); - gl.glColor4f (1,1,1,0.25f); - GL_TexEnv( GL.GL_MODULATE ); - } - - // - // draw texture - // - for (i=0 ; i BACKFACE_EPSILON))) - { - if ((psurf.texinfo.flags & (Defines.SURF_TRANS33 | Defines.SURF_TRANS66)) != 0 ) - { // add to the translucent chain - psurf.texturechain = r_alpha_surfaces; - r_alpha_surfaces = psurf; - } - else if ( (psurf.flags & Defines.SURF_DRAWTURB) == 0 ) - { - GL_RenderLightmappedPoly( psurf ); - } - else - { - GL_EnableMultitexture( false ); - R_RenderBrushPoly( psurf ); - GL_EnableMultitexture( true ); - } - } - } - - if ( (currententity.flags & Defines.RF_TRANSLUCENT) != 0 ) { - gl.glDisable (GL.GL_BLEND); - gl.glColor4f (1,1,1,1); - GL_TexEnv( GL.GL_REPLACE ); - } - } - - /* - ================= - R_DrawBrushModel - ================= - */ - void R_DrawBrushModel(entity_t e) - { - float[] mins = {0, 0, 0}; - float[] maxs = {0, 0, 0}; - int i; - boolean rotated; - - if (currentmodel.nummodelsurfaces == 0) - return; - - currententity = e; - gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1; - - if (e.angles[0] != 0 || e.angles[1] != 0 || e.angles[2] != 0) - { - rotated = true; - for (i=0 ; i<3 ; i++) - { - mins[i] = e.origin[i] - currentmodel.radius; - maxs[i] = e.origin[i] + currentmodel.radius; - } - } - else - { - rotated = false; - Math3D.VectorAdd(e.origin, currentmodel.mins, mins); - Math3D.VectorAdd(e.origin, currentmodel.maxs, maxs); - } - - if (R_CullBox(mins, maxs)) return; - - gl.glColor3f (1,1,1); - - // memset (gl_lms.lightmap_surfaces, 0, sizeof(gl_lms.lightmap_surfaces)); - - // TODO wird beim multitexturing nicht gebraucht - //gl_lms.clearLightmapSurfaces(); - - Math3D.VectorSubtract (r_newrefdef.vieworg, e.origin, modelorg); - if (rotated) - { - float[] temp = {0, 0, 0}; - float[] forward = {0, 0, 0}; - float[] right = {0, 0, 0}; - float[] up = {0, 0, 0}; - - Math3D.VectorCopy (modelorg, temp); - Math3D.AngleVectors (e.angles, forward, right, up); - modelorg[0] = Math3D.DotProduct (temp, forward); - modelorg[1] = -Math3D.DotProduct (temp, right); - modelorg[2] = Math3D.DotProduct (temp, up); - } - - gl.glPushMatrix(); - - e.angles[0] = -e.angles[0]; // stupid quake bug - e.angles[2] = -e.angles[2]; // stupid quake bug - R_RotateForEntity(e); - e.angles[0] = -e.angles[0]; // stupid quake bug - e.angles[2] = -e.angles[2]; // stupid quake bug - - GL_EnableMultitexture( true ); - GL_SelectTexture(GL_TEXTURE0); - GL_TexEnv( GL.GL_REPLACE ); - gl.glInterleavedArrays(GL.GL_T2F_V3F, POLYGON_BYTE_STRIDE, globalPolygonInterleavedBuf); - GL_SelectTexture(GL_TEXTURE1); - GL_TexEnv( GL.GL_MODULATE ); - gl.glTexCoordPointer(2, GL.GL_FLOAT, POLYGON_BYTE_STRIDE, globalPolygonTexCoord1Buf); - gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY); - - R_DrawInlineBModel(); - - gl.glClientActiveTextureARB(GL_TEXTURE1); - gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY); - - GL_EnableMultitexture( false ); - - gl.glPopMatrix(); - } - - /* - ============================================================= - - WORLD MODEL - - ============================================================= - */ - - /* - ================ - R_RecursiveWorldNode - ================ - */ - void R_RecursiveWorldNode (mnode_t node) - { - int c, side, sidebit; - cplane_t plane; - msurface_t surf; - msurface_t mark; - mleaf_t pleaf; - float dot = 0; - image_t image; - - if (node.contents == Defines.CONTENTS_SOLID) - return; // solid - - if (node.visframe != r_visframecount) - return; - - if (R_CullBox(node.mins, node.maxs)) - return; - - // if a leaf node, draw stuff - if (node.contents != -1) - { - pleaf = (mleaf_t)node; - - // check for door connected areas - if (r_newrefdef.areabits != null) - { - if ( ((r_newrefdef.areabits[pleaf.area >> 3] & 0xFF) & (1 << (pleaf.area & 7)) ) == 0 ) - return; // not visible - } - - int markp = 0; - - mark = pleaf.getMarkSurface(markp); // first marked surface - c = pleaf.nummarksurfaces; - - if (c != 0) - { - do - { - mark.visframe = r_framecount; - mark = pleaf.getMarkSurface(++markp); // next surface - } while (--c != 0); - } - - return; - } - - // node is just a decision point, so go down the apropriate sides - - // find which side of the node we are on - plane = node.plane; - - switch (plane.type) - { - case Defines.PLANE_X: - dot = modelorg[0] - plane.dist; - break; - case Defines.PLANE_Y: - dot = modelorg[1] - plane.dist; - break; - case Defines.PLANE_Z: - dot = modelorg[2] - plane.dist; - break; - default: - dot = Math3D.DotProduct(modelorg, plane.normal) - plane.dist; - break; - } - - if (dot >= 0.0f) - { - side = 0; - sidebit = 0; - } - else - { - side = 1; - sidebit = Defines.SURF_PLANEBACK; - } - - // recurse down the children, front side first - R_RecursiveWorldNode(node.children[side]); - - // draw stuff - //for ( c = node.numsurfaces, surf = r_worldmodel.surfaces[node.firstsurface]; c != 0 ; c--, surf++) - for ( c = 0; c < node.numsurfaces; c++) - { - surf = r_worldmodel.surfaces[node.firstsurface + c]; - if (surf.visframe != r_framecount) - continue; - - if ( (surf.flags & Defines.SURF_PLANEBACK) != sidebit ) - continue; // wrong side - - if ((surf.texinfo.flags & Defines.SURF_SKY) != 0) - { // just adds to visible sky bounds - R_AddSkySurface(surf); - } - else if ((surf.texinfo.flags & (Defines.SURF_TRANS33 | Defines.SURF_TRANS66)) != 0) - { // add to the translucent chain - surf.texturechain = r_alpha_surfaces; - r_alpha_surfaces = surf; - } - else - { - if ( ( surf.flags & Defines.SURF_DRAWTURB) == 0 ) - { - GL_RenderLightmappedPoly( surf ); - } - else - { - // the polygon is visible, so add it to the texture - // sorted chain - // FIXME: this is a hack for animation - image = R_TextureAnimation(surf.texinfo); - surf.texturechain = image.texturechain; - image.texturechain = surf; - } - } - } - - // recurse down the back side - R_RecursiveWorldNode(node.children[1 - side]); - } - - - /* - ============= - R_DrawWorld - ============= - */ - void R_DrawWorld() - { - entity_t ent = new entity_t(); - // auto cycle the world frame for texture animation - ent.frame = (int)(r_newrefdef.time*2); - currententity = ent; - - if (r_drawworld.value == 0) - return; - - if ( (r_newrefdef.rdflags & Defines.RDF_NOWORLDMODEL) != 0 ) - return; - - currentmodel = r_worldmodel; - - Math3D.VectorCopy(r_newrefdef.vieworg, modelorg); - - gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1; - - gl.glColor3f (1,1,1); - // memset (gl_lms.lightmap_surfaces, 0, sizeof(gl_lms.lightmap_surfaces)); - // TODO wird bei multitexture nicht gebraucht - //gl_lms.clearLightmapSurfaces(); - - R_ClearSkyBox(); - - GL_EnableMultitexture( true ); - - GL_SelectTexture( GL_TEXTURE0); - GL_TexEnv( GL.GL_REPLACE ); - gl.glInterleavedArrays(GL.GL_T2F_V3F, POLYGON_BYTE_STRIDE, globalPolygonInterleavedBuf); - GL_SelectTexture( GL_TEXTURE1); - gl.glTexCoordPointer(2, GL.GL_FLOAT, POLYGON_BYTE_STRIDE, globalPolygonTexCoord1Buf); - gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY); - - if ( gl_lightmap.value != 0) - GL_TexEnv( GL.GL_REPLACE ); - else - GL_TexEnv( GL.GL_MODULATE ); - - R_RecursiveWorldNode(r_worldmodel.nodes[0]); // root node - - gl.glClientActiveTextureARB(GL_TEXTURE1); - gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY); - - GL_EnableMultitexture( false ); - - DrawTextureChains(); - R_DrawSkyBox(); - R_DrawTriangleOutlines(); - } - - byte[] fatvis = new byte[Defines.MAX_MAP_LEAFS / 8]; - - /* - =============== - R_MarkLeaves - - Mark the leaves and nodes that are in the PVS for the current - cluster - =============== - */ - void R_MarkLeaves() - { - //byte[] vis; - //byte[] fatvis = new byte[Defines.MAX_MAP_LEAFS / 8]; - - //Arrays.fill(fatvis, (byte)0); - - mnode_t node; - int i, c; - mleaf_t leaf; - int cluster; - - if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2 && r_novis.value == 0 && r_viewcluster != -1) - return; - - // development aid to let you run around and see exactly where - // the pvs ends - if (gl_lockpvs.value != 0) - return; - - r_visframecount++; - r_oldviewcluster = r_viewcluster; - r_oldviewcluster2 = r_viewcluster2; - - if (r_novis.value != 0 || r_viewcluster == -1 || r_worldmodel.vis == null) - { - // mark everything - for (i=0 ; i>3] & 0xFF) & (1 << (cluster & 7))) != 0) - { - node = (mnode_t)leaf; - do - { - if (node.visframe == r_visframecount) - break; - node.visframe = r_visframecount; - node = node.parent; - } while (node != null); - } - } - } - - - - /* - ============================================================================= - - LIGHTMAP ALLOCATION - - ============================================================================= - */ - - void LM_InitBlock() - { - Arrays.fill(gl_lms.allocated, 0); - } - - void LM_UploadBlock( boolean dynamic ) - { - int texture; - int height = 0; - - if ( dynamic ) - { - texture = 0; - } - else - { - texture = gl_lms.current_lightmap_texture; - } - - GL_Bind( gl_state.lightmap_textures + texture ); - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); - - if ( dynamic ) - { - int i; - - for ( i = 0; i < BLOCK_WIDTH; i++ ) - { - if ( gl_lms.allocated[i] > height ) - height = gl_lms.allocated[i]; - } - - gl.glTexSubImage2D( GL.GL_TEXTURE_2D, - 0, - 0, 0, - BLOCK_WIDTH, height, - GL_LIGHTMAP_FORMAT, - GL.GL_UNSIGNED_BYTE, - gl_lms.lightmap_buffer ); - } - else - { - gl.glTexImage2D( GL.GL_TEXTURE_2D, - 0, - gl_lms.internal_format, - BLOCK_WIDTH, BLOCK_HEIGHT, - 0, - GL_LIGHTMAP_FORMAT, - GL.GL_UNSIGNED_BYTE, - gl_lms.lightmap_buffer ); - if ( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS ) - Com.Error( Defines.ERR_DROP, "LM_UploadBlock() - MAX_LIGHTMAPS exceeded\n" ); - - - //debugLightmap(gl_lms.lightmap_buffer, 128, 128, 4); - - } - } - - // returns a texture number and the position inside it - boolean LM_AllocBlock (int w, int h, pos_t pos) - { - int x = pos.x; - int y = pos.y; - int i, j; - int best, best2; - - best = BLOCK_HEIGHT; - - for (i=0 ; i= best) - break; - if (gl_lms.allocated[i+j] > best2) - best2 = gl_lms.allocated[i+j]; - } - if (j == w) - { // this is a valid spot - pos.x = x = i; - pos.y = y = best = best2; - } - } - - if (best + h > BLOCK_HEIGHT) - return false; - - for (i=0 ; i 0) - { - r_pedge = pedges[lindex]; - vec = currentmodel.vertexes[r_pedge.v[0]].position; - } - else - { - r_pedge = pedges[-lindex]; - vec = currentmodel.vertexes[r_pedge.v[1]].position; - } - s = Math3D.DotProduct (vec, fa.texinfo.vecs[0]) + fa.texinfo.vecs[0][3]; - s /= fa.texinfo.image.width; - - t = Math3D.DotProduct (vec, fa.texinfo.vecs[1]) + fa.texinfo.vecs[1][3]; - t /= fa.texinfo.image.height; - - Math3D.VectorAdd (total, vec, total); - Math3D.VectorCopy (vec, poly.verts[i]); - poly.verts[i][3] = s; - poly.verts[i][4] = t; - - // - // lightmap texture coordinates - // - s = Math3D.DotProduct (vec, fa.texinfo.vecs[0]) + fa.texinfo.vecs[0][3]; - s -= fa.texturemins[0]; - s += fa.light_s*16; - s += 8; - s /= BLOCK_WIDTH*16; //fa.texinfo.texture.width; - - t = Math3D.DotProduct (vec, fa.texinfo.vecs[1]) + fa.texinfo.vecs[1][3]; - t -= fa.texturemins[1]; - t += fa.light_t*16; - t += 8; - t /= BLOCK_HEIGHT*16; //fa.texinfo.texture.height; - - poly.verts[i][5] = s; - poly.verts[i][6] = t; - } - - poly.numverts = lnumverts; - - precompilePolygon(poly); - - } - - /* - ======================== - GL_CreateSurfaceLightmap - ======================== - */ - void GL_CreateSurfaceLightmap(msurface_t surf) - { - int smax, tmax; - IntBuffer base; - - if ( (surf.flags & (Defines.SURF_DRAWSKY | Defines.SURF_DRAWTURB)) != 0) - return; - - smax = (surf.extents[0]>>4)+1; - tmax = (surf.extents[1]>>4)+1; - - pos_t lightPos = new pos_t(surf.light_s, surf.light_t); - - if ( !LM_AllocBlock( smax, tmax, lightPos ) ) - { - LM_UploadBlock( false ); - LM_InitBlock(); - lightPos = new pos_t(surf.light_s, surf.light_t); - if ( !LM_AllocBlock( smax, tmax, lightPos ) ) - { - Com.Error( Defines.ERR_FATAL, "Consecutive calls to LM_AllocBlock(" + smax +"," + tmax +") failed\n"); - } - } - - // kopiere die koordinaten zurueck - surf.light_s = lightPos.x; - surf.light_t = lightPos.y; - - surf.lightmaptexturenum = gl_lms.current_lightmap_texture; - - base = gl_lms.lightmap_buffer; - base.position(surf.light_t * BLOCK_WIDTH + surf.light_s); - - R_SetCacheState( surf ); - R_BuildLightMap(surf, base.slice(), BLOCK_WIDTH); - } - - lightstyle_t[] lightstyles; - IntBuffer dummy = BufferUtils.newIntBuffer(128*128); - - /* - ================== - GL_BeginBuildingLightmaps - - ================== - */ - void GL_BeginBuildingLightmaps(model_t m) - { - // static lightstyle_t lightstyles[MAX_LIGHTSTYLES]; - int i; - - // init lightstyles - if ( lightstyles == null ) { - lightstyles = new lightstyle_t[Defines.MAX_LIGHTSTYLES]; - for (i = 0; i < lightstyles.length; i++) - { - lightstyles[i] = new lightstyle_t(); - } - } - - // memset( gl_lms.allocated, 0, sizeof(gl_lms.allocated) ); - Arrays.fill(gl_lms.allocated, 0); - - r_framecount = 1; // no dlightcache - - GL_EnableMultitexture( true ); - GL_SelectTexture( GL_TEXTURE1); - - /* - ** setup the base lightstyles so the lightmaps won't have to be regenerated - ** the first time they're seen - */ - for (i=0 ; i < Defines.MAX_LIGHTSTYLES ; i++) - { - lightstyles[i].rgb[0] = 1; - lightstyles[i].rgb[1] = 1; - lightstyles[i].rgb[2] = 1; - lightstyles[i].white = 3; - } - r_newrefdef.lightstyles = lightstyles; - - if (gl_state.lightmap_textures == 0) - { - gl_state.lightmap_textures = TEXNUM_LIGHTMAPS; - } - - gl_lms.current_lightmap_texture = 1; - - /* - ** if mono lightmaps are enabled and we want to use alpha - ** blending (a,1-a) then we're likely running on a 3DLabs - ** Permedia2. In a perfect world we'd use a GL_ALPHA lightmap - ** in order to conserve space and maximize bandwidth, however - ** this isn't a perfect world. - ** - ** So we have to use alpha lightmaps, but stored in GL_RGBA format, - ** which means we only get 1/16th the color resolution we should when - ** using alpha lightmaps. If we find another board that supports - ** only alpha lightmaps but that can at least support the GL_ALPHA - ** format then we should change this code to use real alpha maps. - */ - - char format = gl_monolightmap.string.toUpperCase().charAt(0); - - if ( format == 'A' ) - { - gl_lms.internal_format = gl_tex_alpha_format; - } - /* - ** try to do hacked colored lighting with a blended texture - */ - else if ( format == 'C' ) - { - gl_lms.internal_format = gl_tex_alpha_format; - } - else if ( format == 'I' ) - { - gl_lms.internal_format = GL.GL_INTENSITY8; - } - else if ( format == 'L' ) - { - gl_lms.internal_format = GL.GL_LUMINANCE8; - } - else - { - gl_lms.internal_format = gl_tex_solid_format; - } - - /* - ** initialize the dynamic lightmap texture - */ - GL_Bind( gl_state.lightmap_textures + 0 ); - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); - gl.glTexImage2D( GL.GL_TEXTURE_2D, - 0, - gl_lms.internal_format, - BLOCK_WIDTH, BLOCK_HEIGHT, - 0, - GL_LIGHTMAP_FORMAT, - GL.GL_UNSIGNED_BYTE, - dummy ); - } - - /* - ======================= - GL_EndBuildingLightmaps - ======================= - */ - void GL_EndBuildingLightmaps() - { - LM_UploadBlock( false ); - GL_EnableMultitexture( false ); - } - - /* - * new functions for vertex array handling - */ - static final int POLYGON_BUFFER_SIZE = 120000; - static final int POLYGON_STRIDE = 7; - static final int POLYGON_BYTE_STRIDE = POLYGON_STRIDE * BufferUtils.SIZEOF_FLOAT; - - static FloatBuffer globalPolygonInterleavedBuf = BufferUtils.newFloatBuffer(POLYGON_BUFFER_SIZE * 7); - static FloatBuffer globalPolygonTexCoord1Buf = null; - - static { - globalPolygonInterleavedBuf.position(POLYGON_STRIDE - 2); - globalPolygonTexCoord1Buf = globalPolygonInterleavedBuf.slice(); - globalPolygonInterleavedBuf.position(0); - }; - - void precompilePolygon(glpoly_t p) { - - p.pos = globalPolygonInterleavedBuf.position() / POLYGON_STRIDE; - - float[] v; - FloatBuffer buffer = globalPolygonInterleavedBuf; - - for (int i = 0; i < p.verts.length; i++) { - v = p.verts[i]; - // textureCoord0 - buffer.put(v[3]); - buffer.put(v[4]); - - // vertex - buffer.put(v[0]); - buffer.put(v[1]); - buffer.put(v[2]); - - // textureCoord1 - buffer.put(v[5]); - buffer.put(v[6]); - } - } - - public static void resetPolygonArrays() { - globalPolygonInterleavedBuf.rewind(); - } - - //ImageFrame frame; - -// void debugLightmap(byte[] buf, int w, int h, float scale) { -// IntBuffer pix = ByteBuffer.wrap(buf).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer(); -// -// int[] pixel = new int[w * h]; -// -// pix.get(pixel); -// -// BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR); -// image.setRGB(0, 0, w, h, pixel, 0, w); -// AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(scale, scale), AffineTransformOp.TYPE_NEAREST_NEIGHBOR); -// BufferedImage tmp = op.filter(image, null); -// -// if (frame == null) { -// frame = new ImageFrame(null); -// frame.show(); -// } -// frame.showImage(tmp); -// -// } - -} + // GL_RSURF.C: surface-related refresh code + float[] modelorg = { 0, 0, 0 }; // relative to viewpoint + + msurface_t r_alpha_surfaces; + + static final int DYNAMIC_LIGHT_WIDTH = 128; + + static final int DYNAMIC_LIGHT_HEIGHT = 128; + + static final int LIGHTMAP_BYTES = 4; + + static final int BLOCK_WIDTH = 128; + + static final int BLOCK_HEIGHT = 128; + + static final int MAX_LIGHTMAPS = 128; + + int c_visible_lightmaps; + + int c_visible_textures; + + static final int GL_LIGHTMAP_FORMAT = GL.GL_RGBA; + + static class gllightmapstate_t { + int internal_format; + + int current_lightmap_texture; + + msurface_t[] lightmap_surfaces = new msurface_t[MAX_LIGHTMAPS]; + + int[] allocated = new int[BLOCK_WIDTH]; + + // the lightmap texture data needs to be kept in + // main memory so texsubimage can update properly + //byte[] lightmap_buffer = new byte[4 * BLOCK_WIDTH * BLOCK_HEIGHT]; + IntBuffer lightmap_buffer = Lib.newIntBuffer( + BLOCK_WIDTH * BLOCK_HEIGHT, ByteOrder.LITTLE_ENDIAN); + + public gllightmapstate_t() { + for (int i = 0; i < MAX_LIGHTMAPS; i++) + lightmap_surfaces[i] = new msurface_t(); + } + + public void clearLightmapSurfaces() { + for (int i = 0; i < MAX_LIGHTMAPS; i++) + // TODO lightmap_surfaces[i].clear(); + lightmap_surfaces[i] = new msurface_t(); + } + + } + + gllightmapstate_t gl_lms = new gllightmapstate_t(); + + // Model.java + abstract byte[] Mod_ClusterPVS(int cluster, model_t model); + + // Warp.java + abstract void R_DrawSkyBox(); + + abstract void R_AddSkySurface(msurface_t surface); + + abstract void R_ClearSkyBox(); + + abstract void EmitWaterPolys(msurface_t fa); + + // Light.java + abstract void R_MarkLights(dlight_t light, int bit, mnode_t node); + + abstract void R_SetCacheState(msurface_t surf); + + abstract void R_BuildLightMap(msurface_t surf, IntBuffer dest, int stride); + + /* + * ============================================================= + * + * BRUSH MODELS + * + * ============================================================= + */ + + /* + * =============== R_TextureAnimation + * + * Returns the proper texture for a given time and base texture + * =============== + */ + image_t R_TextureAnimation(mtexinfo_t tex) { + int c; + + if (tex.next == null) + return tex.image; + + c = currententity.frame % tex.numframes; + while (c != 0) { + tex = tex.next; + c--; + } + + return tex.image; + } + + /* + * ================ DrawGLPoly ================ + */ + void DrawGLPoly(glpoly_t p) { + gl.glDrawArrays(GL.GL_POLYGON, p.pos, p.numverts); + } + + // ============ + // PGM + /* + * ================ DrawGLFlowingPoly -- version of DrawGLPoly that handles + * scrolling texture ================ + */ + void DrawGLFlowingPoly(glpoly_t p) { + int i; + float scroll; + + scroll = -64 + * ((r_newrefdef.time / 40.0f) - (int) (r_newrefdef.time / 40.0f)); + if (scroll == 0.0f) + scroll = -64.0f; + + FloatBuffer texCoord = globalPolygonInterleavedBuf; + float[][] v = p.verts; + int index = p.pos * POLYGON_STRIDE; + for (i = 0; i < p.numverts; i++) { + texCoord.put(index, v[i][3] + scroll); + index += POLYGON_STRIDE; + } + gl.glDrawArrays(GL.GL_POLYGON, p.pos, p.numverts); + } + + // PGM + // ============ + + /* + * * R_DrawTriangleOutlines + */ + void R_DrawTriangleOutlines() { + int i, j; + glpoly_t p; + + if (gl_showtris.value == 0) + return; + + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glDisable(GL.GL_DEPTH_TEST); + gl.glColor4f(1, 1, 1, 1); + + for (i = 0; i < MAX_LIGHTMAPS; i++) { + msurface_t surf; + + for (surf = gl_lms.lightmap_surfaces[i]; surf != null; surf = surf.lightmapchain) { + p = surf.polys; + for (; p != null; p = p.chain) { + for (j = 2; j < p.numverts; j++) { + gl.glBegin(GL.GL_LINE_STRIP); + gl.glVertex3fv(p.verts[0]); + gl.glVertex3fv(p.verts[j - 1]); + gl.glVertex3fv(p.verts[j]); + gl.glVertex3fv(p.verts[0]); + gl.glEnd(); + } + } + } + } + + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_TEXTURE_2D); + } + + private IntBuffer temp2 = Lib + .newIntBuffer(34 * 34, ByteOrder.LITTLE_ENDIAN); + + /* + * ================ R_RenderBrushPoly ================ + */ + void R_RenderBrushPoly(msurface_t fa) { + int maps; + image_t image; + boolean is_dynamic = false; + + c_brush_polys++; + + image = R_TextureAnimation(fa.texinfo); + + if ((fa.flags & Defines.SURF_DRAWTURB) != 0) { + GL_Bind(image.texnum); + + // warp texture, no lightmaps + GL_TexEnv(GL.GL_MODULATE); + gl.glColor4f(gl_state.inverse_intensity, + gl_state.inverse_intensity, gl_state.inverse_intensity, + 1.0F); + EmitWaterPolys(fa); + GL_TexEnv(GL.GL_REPLACE); + + return; + } else { + GL_Bind(image.texnum); + GL_TexEnv(GL.GL_REPLACE); + } + + // ====== + // PGM + if ((fa.texinfo.flags & Defines.SURF_FLOWING) != 0) + DrawGLFlowingPoly(fa.polys); + else + DrawGLPoly(fa.polys); + // PGM + // ====== + + // ersetzt goto + boolean gotoDynamic = false; + /* + * * check for lightmap modification + */ + for (maps = 0; maps < Defines.MAXLIGHTMAPS + && fa.styles[maps] != (byte) 255; maps++) { + if (r_newrefdef.lightstyles[fa.styles[maps] & 0xFF].white != fa.cached_light[maps]) { + gotoDynamic = true; + break; + } + } + + // this is a hack from cwei + if (maps == 4) + maps--; + + // dynamic this frame or dynamic previously + if (gotoDynamic || (fa.dlightframe == r_framecount)) { + // label dynamic: + if (gl_dynamic.value != 0) { + if ((fa.texinfo.flags & (Defines.SURF_SKY + | Defines.SURF_TRANS33 | Defines.SURF_TRANS66 | Defines.SURF_WARP)) == 0) { + is_dynamic = true; + } + } + } + + if (is_dynamic) { + if (((fa.styles[maps] & 0xFF) >= 32 || fa.styles[maps] == 0) + && (fa.dlightframe != r_framecount)) { + // ist ersetzt durch temp2: unsigned temp[34*34]; + int smax, tmax; + + smax = (fa.extents[0] >> 4) + 1; + tmax = (fa.extents[1] >> 4) + 1; + + R_BuildLightMap(fa, temp2, smax); + R_SetCacheState(fa); + + GL_Bind(gl_state.lightmap_textures + fa.lightmaptexturenum); + + gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, fa.light_s, fa.light_t, + smax, tmax, GL_LIGHTMAP_FORMAT, GL.GL_UNSIGNED_BYTE, + temp2); + + fa.lightmapchain = gl_lms.lightmap_surfaces[fa.lightmaptexturenum]; + gl_lms.lightmap_surfaces[fa.lightmaptexturenum] = fa; + } else { + fa.lightmapchain = gl_lms.lightmap_surfaces[0]; + gl_lms.lightmap_surfaces[0] = fa; + } + } else { + fa.lightmapchain = gl_lms.lightmap_surfaces[fa.lightmaptexturenum]; + gl_lms.lightmap_surfaces[fa.lightmaptexturenum] = fa; + } + } + + /* + * ================ R_DrawAlphaSurfaces + * + * Draw water surfaces and windows. The BSP tree is waled front to back, so + * unwinding the chain of alpha_surfaces will draw back to front, giving + * proper ordering. ================ + */ + void R_DrawAlphaSurfaces() { + msurface_t s; + float intens; + + // + // go back to the world matrix + // + gl.glLoadMatrixf(r_world_matrix); + + gl.glEnable(GL.GL_BLEND); + GL_TexEnv(GL.GL_MODULATE); + + // the textures are prescaled up for a better lighting range, + // so scale it back down + intens = gl_state.inverse_intensity; + + gl.glInterleavedArrays(GL.GL_T2F_V3F, POLYGON_BYTE_STRIDE, + globalPolygonInterleavedBuf); + + for (s = r_alpha_surfaces; s != null; s = s.texturechain) { + GL_Bind(s.texinfo.image.texnum); + c_brush_polys++; + if ((s.texinfo.flags & Defines.SURF_TRANS33) != 0) + gl.glColor4f(intens, intens, intens, 0.33f); + else if ((s.texinfo.flags & Defines.SURF_TRANS66) != 0) + gl.glColor4f(intens, intens, intens, 0.66f); + else + gl.glColor4f(intens, intens, intens, 1); + if ((s.flags & Defines.SURF_DRAWTURB) != 0) + EmitWaterPolys(s); + else if ((s.texinfo.flags & Defines.SURF_FLOWING) != 0) // PGM + // 9/16/98 + DrawGLFlowingPoly(s.polys); // PGM + else + DrawGLPoly(s.polys); + } + + GL_TexEnv(GL.GL_REPLACE); + gl.glColor4f(1, 1, 1, 1); + gl.glDisable(GL.GL_BLEND); + + r_alpha_surfaces = null; + } + + /* + * ================ DrawTextureChains ================ + */ + void DrawTextureChains() { + int i; + msurface_t s; + image_t image; + + c_visible_textures = 0; + + for (i = 0; i < numgltextures; i++) { + image = gltextures[i]; + + if (image.registration_sequence == 0) + continue; + if (image.texturechain == null) + continue; + c_visible_textures++; + + for (s = image.texturechain; s != null; s = s.texturechain) { + if ((s.flags & Defines.SURF_DRAWTURB) == 0) + R_RenderBrushPoly(s); + } + } + + GL_EnableMultitexture(false); + for (i = 0; i < numgltextures; i++) { + image = gltextures[i]; + + if (image.registration_sequence == 0) + continue; + s = image.texturechain; + if (s == null) + continue; + + for (; s != null; s = s.texturechain) { + if ((s.flags & Defines.SURF_DRAWTURB) != 0) + R_RenderBrushPoly(s); + } + + image.texturechain = null; + } + + GL_TexEnv(GL.GL_REPLACE); + } + + // direct buffer + private IntBuffer temp = Lib.newIntBuffer(128 * 128, + ByteOrder.LITTLE_ENDIAN); + + void GL_RenderLightmappedPoly(msurface_t surf) { + int i, nv = surf.polys.numverts; + int map = 0; + int index; + float[][] v; + FloatBuffer texCoord = globalPolygonInterleavedBuf; + image_t image = R_TextureAnimation(surf.texinfo); + boolean is_dynamic = false; + int lmtex = surf.lightmaptexturenum; + glpoly_t p; + + // ersetzt goto + boolean gotoDynamic = false; + + for (map = 0; map < Defines.MAXLIGHTMAPS + && (surf.styles[map] != (byte) 255); map++) { + if (r_newrefdef.lightstyles[surf.styles[map] & 0xFF].white != surf.cached_light[map]) { + gotoDynamic = true; + break; + } + } + + // this is a hack from cwei + if (map == 4) + map--; + + // dynamic this frame or dynamic previously + if (gotoDynamic || (surf.dlightframe == r_framecount)) { + // label dynamic: + if (gl_dynamic.value != 0) { + if ((surf.texinfo.flags & (Defines.SURF_SKY + | Defines.SURF_TRANS33 | Defines.SURF_TRANS66 | Defines.SURF_WARP)) == 0) { + is_dynamic = true; + } + } + } + + if (is_dynamic) { + // ist raus gezogen worden int[] temp = new int[128*128]; + int smax, tmax; + + if (((surf.styles[map] & 0xFF) >= 32 || surf.styles[map] == 0) + && (surf.dlightframe != r_framecount)) { + smax = (surf.extents[0] >> 4) + 1; + tmax = (surf.extents[1] >> 4) + 1; + + R_BuildLightMap(surf, temp, smax); + R_SetCacheState(surf); + + GL_MBind(GL_TEXTURE1, gl_state.lightmap_textures + + surf.lightmaptexturenum); + + lmtex = surf.lightmaptexturenum; + + gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, surf.light_s, + surf.light_t, smax, tmax, GL_LIGHTMAP_FORMAT, + GL.GL_UNSIGNED_BYTE, temp); + + } else { + smax = (surf.extents[0] >> 4) + 1; + tmax = (surf.extents[1] >> 4) + 1; + + R_BuildLightMap(surf, temp, smax); + + GL_MBind(GL_TEXTURE1, gl_state.lightmap_textures + 0); + + lmtex = 0; + + gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, surf.light_s, + surf.light_t, smax, tmax, GL_LIGHTMAP_FORMAT, + GL.GL_UNSIGNED_BYTE, temp); + + } + + c_brush_polys++; + + GL_MBind(GL_TEXTURE0, image.texnum); + GL_MBind(GL_TEXTURE1, gl_state.lightmap_textures + lmtex); + + // ========== + // PGM + if ((surf.texinfo.flags & Defines.SURF_FLOWING) != 0) { + float scroll; + + scroll = -64 + * ((r_newrefdef.time / 40.0f) - (int) (r_newrefdef.time / 40.0f)); + if (scroll == 0.0f) + scroll = -64.0f; + + for (p = surf.polys; p != null; p = p.chain) { + v = p.verts; + index = p.pos * POLYGON_STRIDE; + for (i = 0; i < p.numverts; i++) { + texCoord.put(index, v[i][3] + scroll); + index += POLYGON_STRIDE; + } + gl.glDrawArrays(GL.GL_POLYGON, p.pos, p.numverts); + } + } else { + for (p = surf.polys; p != null; p = p.chain) { + gl.glDrawArrays(GL.GL_POLYGON, p.pos, p.numverts); + } + } + // PGM + // ========== + } else { + c_brush_polys++; + + GL_MBind(GL_TEXTURE0, image.texnum); + GL_MBind(GL_TEXTURE1, gl_state.lightmap_textures + lmtex); + + // ========== + // PGM + if ((surf.texinfo.flags & Defines.SURF_FLOWING) != 0) { + float scroll; + + scroll = -64 + * ((r_newrefdef.time / 40.0f) - (int) (r_newrefdef.time / 40.0f)); + if (scroll == 0.0) + scroll = -64.0f; + + for (p = surf.polys; p != null; p = p.chain) { + v = p.verts; + index = p.pos * POLYGON_STRIDE; + for (i = 0; i < p.numverts; i++) { + texCoord.put(index, v[i][3] + scroll); + index += POLYGON_STRIDE; + } + gl.glDrawArrays(GL.GL_POLYGON, p.pos, p.numverts); + } + } else { + // PGM + // ========== + for (p = surf.polys; p != null; p = p.chain) { + gl.glDrawArrays(GL.GL_POLYGON, p.pos, p.numverts); + } + + // ========== + // PGM + } + // PGM + // ========== + } + } + + /* + * ================= R_DrawInlineBModel ================= + */ + void R_DrawInlineBModel() { + int i, k; + cplane_t pplane; + float dot; + msurface_t psurf; + dlight_t lt; + + // calculate dynamic lighting for bmodel + if (gl_flashblend.value == 0) { + for (k = 0; k < r_newrefdef.num_dlights; k++) { + lt = r_newrefdef.dlights[k]; + R_MarkLights(lt, 1 << k, + currentmodel.nodes[currentmodel.firstnode]); + } + } + + // psurf = ¤tmodel->surfaces[currentmodel->firstmodelsurface]; + int psurfp = currentmodel.firstmodelsurface; + msurface_t[] surfaces; + surfaces = currentmodel.surfaces; + //psurf = surfaces[psurfp]; + + if ((currententity.flags & Defines.RF_TRANSLUCENT) != 0) { + gl.glEnable(GL.GL_BLEND); + gl.glColor4f(1, 1, 1, 0.25f); + GL_TexEnv(GL.GL_MODULATE); + } + + // + // draw texture + // + for (i = 0; i < currentmodel.nummodelsurfaces; i++) { + psurf = surfaces[psurfp++]; + // find which side of the node we are on + pplane = psurf.plane; + + dot = Math3D.DotProduct(modelorg, pplane.normal) - pplane.dist; + + // draw the polygon + if (((psurf.flags & Defines.SURF_PLANEBACK) != 0 && (dot < -BACKFACE_EPSILON)) + || ((psurf.flags & Defines.SURF_PLANEBACK) == 0 && (dot > BACKFACE_EPSILON))) { + if ((psurf.texinfo.flags & (Defines.SURF_TRANS33 | Defines.SURF_TRANS66)) != 0) { + // add to the translucent chain + psurf.texturechain = r_alpha_surfaces; + r_alpha_surfaces = psurf; + } else if ((psurf.flags & Defines.SURF_DRAWTURB) == 0) { + GL_RenderLightmappedPoly(psurf); + } else { + GL_EnableMultitexture(false); + R_RenderBrushPoly(psurf); + GL_EnableMultitexture(true); + } + } + } + + if ((currententity.flags & Defines.RF_TRANSLUCENT) != 0) { + gl.glDisable(GL.GL_BLEND); + gl.glColor4f(1, 1, 1, 1); + GL_TexEnv(GL.GL_REPLACE); + } + } + + /* + * ================= R_DrawBrushModel ================= + */ + void R_DrawBrushModel(entity_t e) { + float[] mins = { 0, 0, 0 }; + float[] maxs = { 0, 0, 0 }; + int i; + boolean rotated; + + if (currentmodel.nummodelsurfaces == 0) + return; + + currententity = e; + gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1; + + if (e.angles[0] != 0 || e.angles[1] != 0 || e.angles[2] != 0) { + rotated = true; + for (i = 0; i < 3; i++) { + mins[i] = e.origin[i] - currentmodel.radius; + maxs[i] = e.origin[i] + currentmodel.radius; + } + } else { + rotated = false; + Math3D.VectorAdd(e.origin, currentmodel.mins, mins); + Math3D.VectorAdd(e.origin, currentmodel.maxs, maxs); + } + + if (R_CullBox(mins, maxs)) + return; + + gl.glColor3f(1, 1, 1); + + // memset (gl_lms.lightmap_surfaces, 0, + // sizeof(gl_lms.lightmap_surfaces)); + + // TODO wird beim multitexturing nicht gebraucht + //gl_lms.clearLightmapSurfaces(); + + Math3D.VectorSubtract(r_newrefdef.vieworg, e.origin, modelorg); + if (rotated) { + float[] temp = { 0, 0, 0 }; + float[] forward = { 0, 0, 0 }; + float[] right = { 0, 0, 0 }; + float[] up = { 0, 0, 0 }; + + Math3D.VectorCopy(modelorg, temp); + Math3D.AngleVectors(e.angles, forward, right, up); + modelorg[0] = Math3D.DotProduct(temp, forward); + modelorg[1] = -Math3D.DotProduct(temp, right); + modelorg[2] = Math3D.DotProduct(temp, up); + } + + gl.glPushMatrix(); + + e.angles[0] = -e.angles[0]; // stupid quake bug + e.angles[2] = -e.angles[2]; // stupid quake bug + R_RotateForEntity(e); + e.angles[0] = -e.angles[0]; // stupid quake bug + e.angles[2] = -e.angles[2]; // stupid quake bug + + GL_EnableMultitexture(true); + GL_SelectTexture(GL_TEXTURE0); + GL_TexEnv(GL.GL_REPLACE); + gl.glInterleavedArrays(GL.GL_T2F_V3F, POLYGON_BYTE_STRIDE, + globalPolygonInterleavedBuf); + GL_SelectTexture(GL_TEXTURE1); + GL_TexEnv(GL.GL_MODULATE); + gl.glTexCoordPointer(2, GL.GL_FLOAT, POLYGON_BYTE_STRIDE, + globalPolygonTexCoord1Buf); + gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY); + + R_DrawInlineBModel(); + + gl.glClientActiveTextureARB(GL_TEXTURE1); + gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY); + + GL_EnableMultitexture(false); + + gl.glPopMatrix(); + } + + /* + * ============================================================= + * + * WORLD MODEL + * + * ============================================================= + */ + + /* + * ================ R_RecursiveWorldNode ================ + */ + void R_RecursiveWorldNode(mnode_t node) { + int c, side, sidebit; + cplane_t plane; + msurface_t surf; + msurface_t mark; + mleaf_t pleaf; + float dot = 0; + image_t image; + + if (node.contents == Defines.CONTENTS_SOLID) + return; // solid + + if (node.visframe != r_visframecount) + return; + + if (R_CullBox(node.mins, node.maxs)) + return; + + // if a leaf node, draw stuff + if (node.contents != -1) { + pleaf = (mleaf_t) node; + + // check for door connected areas + if (r_newrefdef.areabits != null) { + if (((r_newrefdef.areabits[pleaf.area >> 3] & 0xFF) & (1 << (pleaf.area & 7))) == 0) + return; // not visible + } + + int markp = 0; + + mark = pleaf.getMarkSurface(markp); // first marked surface + c = pleaf.nummarksurfaces; + + if (c != 0) { + do { + mark.visframe = r_framecount; + mark = pleaf.getMarkSurface(++markp); // next surface + } while (--c != 0); + } + + return; + } + + // node is just a decision point, so go down the apropriate sides + + // find which side of the node we are on + plane = node.plane; + + switch (plane.type) { + case Defines.PLANE_X: + dot = modelorg[0] - plane.dist; + break; + case Defines.PLANE_Y: + dot = modelorg[1] - plane.dist; + break; + case Defines.PLANE_Z: + dot = modelorg[2] - plane.dist; + break; + default: + dot = Math3D.DotProduct(modelorg, plane.normal) - plane.dist; + break; + } + + if (dot >= 0.0f) { + side = 0; + sidebit = 0; + } else { + side = 1; + sidebit = Defines.SURF_PLANEBACK; + } + + // recurse down the children, front side first + R_RecursiveWorldNode(node.children[side]); + + // draw stuff + //for ( c = node.numsurfaces, surf = + // r_worldmodel.surfaces[node.firstsurface]; c != 0 ; c--, surf++) + for (c = 0; c < node.numsurfaces; c++) { + surf = r_worldmodel.surfaces[node.firstsurface + c]; + if (surf.visframe != r_framecount) + continue; + + if ((surf.flags & Defines.SURF_PLANEBACK) != sidebit) + continue; // wrong side + + if ((surf.texinfo.flags & Defines.SURF_SKY) != 0) { // just adds to + // visible sky + // bounds + R_AddSkySurface(surf); + } else if ((surf.texinfo.flags & (Defines.SURF_TRANS33 | Defines.SURF_TRANS66)) != 0) { + // add to the translucent chain + surf.texturechain = r_alpha_surfaces; + r_alpha_surfaces = surf; + } else { + if ((surf.flags & Defines.SURF_DRAWTURB) == 0) { + GL_RenderLightmappedPoly(surf); + } else { + // the polygon is visible, so add it to the texture + // sorted chain + // FIXME: this is a hack for animation + image = R_TextureAnimation(surf.texinfo); + surf.texturechain = image.texturechain; + image.texturechain = surf; + } + } + } + + // recurse down the back side + R_RecursiveWorldNode(node.children[1 - side]); + } + + /* + * ============= R_DrawWorld ============= + */ + void R_DrawWorld() { + entity_t ent = new entity_t(); + // auto cycle the world frame for texture animation + ent.frame = (int) (r_newrefdef.time * 2); + currententity = ent; + + if (r_drawworld.value == 0) + return; + + if ((r_newrefdef.rdflags & Defines.RDF_NOWORLDMODEL) != 0) + return; + + currentmodel = r_worldmodel; + + Math3D.VectorCopy(r_newrefdef.vieworg, modelorg); + + gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1; + + gl.glColor3f(1, 1, 1); + // memset (gl_lms.lightmap_surfaces, 0, + // sizeof(gl_lms.lightmap_surfaces)); + // TODO wird bei multitexture nicht gebraucht + //gl_lms.clearLightmapSurfaces(); + + R_ClearSkyBox(); + + GL_EnableMultitexture(true); + + GL_SelectTexture(GL_TEXTURE0); + GL_TexEnv(GL.GL_REPLACE); + gl.glInterleavedArrays(GL.GL_T2F_V3F, POLYGON_BYTE_STRIDE, + globalPolygonInterleavedBuf); + GL_SelectTexture(GL_TEXTURE1); + gl.glTexCoordPointer(2, GL.GL_FLOAT, POLYGON_BYTE_STRIDE, + globalPolygonTexCoord1Buf); + gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY); + + if (gl_lightmap.value != 0) + GL_TexEnv(GL.GL_REPLACE); + else + GL_TexEnv(GL.GL_MODULATE); + + R_RecursiveWorldNode(r_worldmodel.nodes[0]); // root node + + gl.glClientActiveTextureARB(GL_TEXTURE1); + gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY); + + GL_EnableMultitexture(false); + + DrawTextureChains(); + R_DrawSkyBox(); + R_DrawTriangleOutlines(); + } + + byte[] fatvis = new byte[Defines.MAX_MAP_LEAFS / 8]; + + /* + * =============== R_MarkLeaves + * + * Mark the leaves and nodes that are in the PVS for the current cluster + * =============== + */ + void R_MarkLeaves() { + //byte[] vis; + //byte[] fatvis = new byte[Defines.MAX_MAP_LEAFS / 8]; + + //Arrays.fill(fatvis, (byte)0); + + mnode_t node; + int i, c; + mleaf_t leaf; + int cluster; + + if (r_oldviewcluster == r_viewcluster + && r_oldviewcluster2 == r_viewcluster2 && r_novis.value == 0 + && r_viewcluster != -1) + return; + + // development aid to let you run around and see exactly where + // the pvs ends + if (gl_lockpvs.value != 0) + return; + + r_visframecount++; + r_oldviewcluster = r_viewcluster; + r_oldviewcluster2 = r_viewcluster2; + + if (r_novis.value != 0 || r_viewcluster == -1 + || r_worldmodel.vis == null) { + // mark everything + for (i = 0; i < r_worldmodel.numleafs; i++) + r_worldmodel.leafs[i].visframe = r_visframecount; + for (i = 0; i < r_worldmodel.numnodes; i++) + r_worldmodel.nodes[i].visframe = r_visframecount; + return; + } + + byte[] vis = Mod_ClusterPVS(r_viewcluster, r_worldmodel); + // may have to combine two clusters because of solid water boundaries + if (r_viewcluster2 != r_viewcluster) { + // memcpy (fatvis, vis, (r_worldmodel.numleafs+7)/8); + System + .arraycopy(vis, 0, fatvis, 0, + (r_worldmodel.numleafs + 7) / 8); + vis = Mod_ClusterPVS(r_viewcluster2, r_worldmodel); + c = (r_worldmodel.numleafs + 31) / 32; + int k = 0; + for (i = 0; i < c; i++) { + fatvis[k] |= vis[k++]; + fatvis[k] |= vis[k++]; + fatvis[k] |= vis[k++]; + fatvis[k] |= vis[k++]; + } + + vis = fatvis; + } + + for (i = 0; i < r_worldmodel.numleafs; i++) { + leaf = r_worldmodel.leafs[i]; + cluster = leaf.cluster; + if (cluster == -1) + continue; + if (((vis[cluster >> 3] & 0xFF) & (1 << (cluster & 7))) != 0) { + node = (mnode_t) leaf; + do { + if (node.visframe == r_visframecount) + break; + node.visframe = r_visframecount; + node = node.parent; + } while (node != null); + } + } + } + + /* + * ============================================================================= + * + * LIGHTMAP ALLOCATION + * + * ============================================================================= + */ + + void LM_InitBlock() { + Arrays.fill(gl_lms.allocated, 0); + } + + void LM_UploadBlock(boolean dynamic) { + int texture; + int height = 0; + + if (dynamic) { + texture = 0; + } else { + texture = gl_lms.current_lightmap_texture; + } + + GL_Bind(gl_state.lightmap_textures + texture); + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + GL.GL_LINEAR); + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_LINEAR); + + if (dynamic) { + int i; + + for (i = 0; i < BLOCK_WIDTH; i++) { + if (gl_lms.allocated[i] > height) + height = gl_lms.allocated[i]; + } + + gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, BLOCK_WIDTH, height, + GL_LIGHTMAP_FORMAT, GL.GL_UNSIGNED_BYTE, + gl_lms.lightmap_buffer); + } else { + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, gl_lms.internal_format, + BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_LIGHTMAP_FORMAT, + GL.GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer); + if (++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS) + Com.Error(Defines.ERR_DROP, + "LM_UploadBlock() - MAX_LIGHTMAPS exceeded\n"); + + //debugLightmap(gl_lms.lightmap_buffer, 128, 128, 4); + + } + } + + // returns a texture number and the position inside it + boolean LM_AllocBlock(int w, int h, pos_t pos) { + int x = pos.x; + int y = pos.y; + int i, j; + int best, best2; + + best = BLOCK_HEIGHT; + + for (i = 0; i < BLOCK_WIDTH - w; i++) { + best2 = 0; + + for (j = 0; j < w; j++) { + if (gl_lms.allocated[i + j] >= best) + break; + if (gl_lms.allocated[i + j] > best2) + best2 = gl_lms.allocated[i + j]; + } + if (j == w) { // this is a valid spot + pos.x = x = i; + pos.y = y = best = best2; + } + } + + if (best + h > BLOCK_HEIGHT) + return false; + + for (i = 0; i < w; i++) + gl_lms.allocated[x + i] = best + h; + + return true; + } + + /* + * ================ GL_BuildPolygonFromSurface ================ + */ + void GL_BuildPolygonFromSurface(msurface_t fa) { + int i, lindex, lnumverts; + medge_t[] pedges; + medge_t r_pedge; + int vertpage; + float[] vec; + float s, t; + glpoly_t poly; + float[] total = { 0, 0, 0 }; + + // reconstruct the polygon + pedges = currentmodel.edges; + lnumverts = fa.numedges; + vertpage = 0; + + Math3D.VectorClear(total); + // + // draw texture + // + // poly = Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * + // VERTEXSIZE*sizeof(float)); + poly = new glpoly_t(lnumverts); + + poly.next = fa.polys; + poly.flags = fa.flags; + fa.polys = poly; + poly.numverts = lnumverts; + + for (i = 0; i < lnumverts; i++) { + lindex = currentmodel.surfedges[fa.firstedge + i]; + + if (lindex > 0) { + r_pedge = pedges[lindex]; + vec = currentmodel.vertexes[r_pedge.v[0]].position; + } else { + r_pedge = pedges[-lindex]; + vec = currentmodel.vertexes[r_pedge.v[1]].position; + } + s = Math3D.DotProduct(vec, fa.texinfo.vecs[0]) + + fa.texinfo.vecs[0][3]; + s /= fa.texinfo.image.width; + + t = Math3D.DotProduct(vec, fa.texinfo.vecs[1]) + + fa.texinfo.vecs[1][3]; + t /= fa.texinfo.image.height; + + Math3D.VectorAdd(total, vec, total); + Math3D.VectorCopy(vec, poly.verts[i]); + poly.verts[i][3] = s; + poly.verts[i][4] = t; + + // + // lightmap texture coordinates + // + s = Math3D.DotProduct(vec, fa.texinfo.vecs[0]) + + fa.texinfo.vecs[0][3]; + s -= fa.texturemins[0]; + s += fa.light_s * 16; + s += 8; + s /= BLOCK_WIDTH * 16; //fa.texinfo.texture.width; + + t = Math3D.DotProduct(vec, fa.texinfo.vecs[1]) + + fa.texinfo.vecs[1][3]; + t -= fa.texturemins[1]; + t += fa.light_t * 16; + t += 8; + t /= BLOCK_HEIGHT * 16; //fa.texinfo.texture.height; + + poly.verts[i][5] = s; + poly.verts[i][6] = t; + } + + poly.numverts = lnumverts; + + precompilePolygon(poly); + + } + + /* + * ======================== GL_CreateSurfaceLightmap + * ======================== + */ + void GL_CreateSurfaceLightmap(msurface_t surf) { + int smax, tmax; + IntBuffer base; + + if ((surf.flags & (Defines.SURF_DRAWSKY | Defines.SURF_DRAWTURB)) != 0) + return; + + smax = (surf.extents[0] >> 4) + 1; + tmax = (surf.extents[1] >> 4) + 1; + + pos_t lightPos = new pos_t(surf.light_s, surf.light_t); + + if (!LM_AllocBlock(smax, tmax, lightPos)) { + LM_UploadBlock(false); + LM_InitBlock(); + lightPos = new pos_t(surf.light_s, surf.light_t); + if (!LM_AllocBlock(smax, tmax, lightPos)) { + Com.Error(Defines.ERR_FATAL, + "Consecutive calls to LM_AllocBlock(" + smax + "," + + tmax + ") failed\n"); + } + } + + // kopiere die koordinaten zurueck + surf.light_s = lightPos.x; + surf.light_t = lightPos.y; + + surf.lightmaptexturenum = gl_lms.current_lightmap_texture; + + base = gl_lms.lightmap_buffer; + base.position(surf.light_t * BLOCK_WIDTH + surf.light_s); + + R_SetCacheState(surf); + R_BuildLightMap(surf, base.slice(), BLOCK_WIDTH); + } + + lightstyle_t[] lightstyles; + + IntBuffer dummy = BufferUtils.newIntBuffer(128 * 128); + + /* + * ================== GL_BeginBuildingLightmaps + * + * ================== + */ + void GL_BeginBuildingLightmaps(model_t m) { + // static lightstyle_t lightstyles[MAX_LIGHTSTYLES]; + int i; + + // init lightstyles + if (lightstyles == null) { + lightstyles = new lightstyle_t[Defines.MAX_LIGHTSTYLES]; + for (i = 0; i < lightstyles.length; i++) { + lightstyles[i] = new lightstyle_t(); + } + } + + // memset( gl_lms.allocated, 0, sizeof(gl_lms.allocated) ); + Arrays.fill(gl_lms.allocated, 0); + + r_framecount = 1; // no dlightcache + + GL_EnableMultitexture(true); + GL_SelectTexture(GL_TEXTURE1); + + /* + * * setup the base lightstyles so the lightmaps won't have to be + * regenerated * the first time they're seen + */ + for (i = 0; i < Defines.MAX_LIGHTSTYLES; i++) { + lightstyles[i].rgb[0] = 1; + lightstyles[i].rgb[1] = 1; + lightstyles[i].rgb[2] = 1; + lightstyles[i].white = 3; + } + r_newrefdef.lightstyles = lightstyles; + + if (gl_state.lightmap_textures == 0) { + gl_state.lightmap_textures = TEXNUM_LIGHTMAPS; + } + + gl_lms.current_lightmap_texture = 1; + + /* + * * if mono lightmaps are enabled and we want to use alpha * blending + * (a,1-a) then we're likely running on a 3DLabs * Permedia2. In a + * perfect world we'd use a GL_ALPHA lightmap * in order to conserve + * space and maximize bandwidth, however * this isn't a perfect world. * * + * So we have to use alpha lightmaps, but stored in GL_RGBA format, * + * which means we only get 1/16th the color resolution we should when * + * using alpha lightmaps. If we find another board that supports * only + * alpha lightmaps but that can at least support the GL_ALPHA * format + * then we should change this code to use real alpha maps. + */ + + char format = gl_monolightmap.string.toUpperCase().charAt(0); + + if (format == 'A') { + gl_lms.internal_format = gl_tex_alpha_format; + } + /* + * * try to do hacked colored lighting with a blended texture + */ + else if (format == 'C') { + gl_lms.internal_format = gl_tex_alpha_format; + } else if (format == 'I') { + gl_lms.internal_format = GL.GL_INTENSITY8; + } else if (format == 'L') { + gl_lms.internal_format = GL.GL_LUMINANCE8; + } else { + gl_lms.internal_format = gl_tex_solid_format; + } + + /* + * * initialize the dynamic lightmap texture + */ + GL_Bind(gl_state.lightmap_textures + 0); + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + GL.GL_LINEAR); + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_LINEAR); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, gl_lms.internal_format, + BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_LIGHTMAP_FORMAT, + GL.GL_UNSIGNED_BYTE, dummy); + } + + /* + * ======================= GL_EndBuildingLightmaps ======================= + */ + void GL_EndBuildingLightmaps() { + LM_UploadBlock(false); + GL_EnableMultitexture(false); + } + + /* + * new functions for vertex array handling + */ + static final int POLYGON_BUFFER_SIZE = 120000; + + static final int POLYGON_STRIDE = 7; + + static final int POLYGON_BYTE_STRIDE = POLYGON_STRIDE + * BufferUtils.SIZEOF_FLOAT; + + static FloatBuffer globalPolygonInterleavedBuf = BufferUtils + .newFloatBuffer(POLYGON_BUFFER_SIZE * 7); + + static FloatBuffer globalPolygonTexCoord1Buf = null; + + static { + globalPolygonInterleavedBuf.position(POLYGON_STRIDE - 2); + globalPolygonTexCoord1Buf = globalPolygonInterleavedBuf.slice(); + globalPolygonInterleavedBuf.position(0); + }; + + void precompilePolygon(glpoly_t p) { + + p.pos = globalPolygonInterleavedBuf.position() / POLYGON_STRIDE; + + float[] v; + FloatBuffer buffer = globalPolygonInterleavedBuf; + + for (int i = 0; i < p.verts.length; i++) { + v = p.verts[i]; + // textureCoord0 + buffer.put(v[3]); + buffer.put(v[4]); + + // vertex + buffer.put(v[0]); + buffer.put(v[1]); + buffer.put(v[2]); + + // textureCoord1 + buffer.put(v[5]); + buffer.put(v[6]); + } + } + + public static void resetPolygonArrays() { + globalPolygonInterleavedBuf.rewind(); + } + + //ImageFrame frame; + + // void debugLightmap(byte[] buf, int w, int h, float scale) { + // IntBuffer pix = + // ByteBuffer.wrap(buf).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer(); + // + // int[] pixel = new int[w * h]; + // + // pix.get(pixel); + // + // BufferedImage image = new BufferedImage(w, h, + // BufferedImage.TYPE_4BYTE_ABGR); + // image.setRGB(0, 0, w, h, pixel, 0, w); + // AffineTransformOp op = new + // AffineTransformOp(AffineTransform.getScaleInstance(scale, scale), + // AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + // BufferedImage tmp = op.filter(image, null); + // + // if (frame == null) { + // frame = new ImageFrame(null); + // frame.show(); + // } + // frame.showImage(tmp); + // + // } + +} \ No newline at end of file diff --git a/src/jake2/render/fastjogl/Warp.java b/src/jake2/render/fastjogl/Warp.java index f6b1416..ca4e42e 100644 --- a/src/jake2/render/fastjogl/Warp.java +++ b/src/jake2/render/fastjogl/Warp.java @@ -2,33 +2,35 @@ * Warp.java * Copyright (C) 2003 * - * $Id: Warp.java,v 1.3 2004-07-16 10:11:35 cawe Exp $ + * $Id: Warp.java,v 1.4 2004-09-22 19:22:11 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.render.fastjogl; import jake2.Defines; import jake2.Globals; import jake2.qcommon.Com; -import jake2.render.*; +import jake2.render.glpoly_t; +import jake2.render.image_t; +import jake2.render.msurface_t; import jake2.util.Math3D; import java.nio.FloatBuffer; @@ -37,694 +39,639 @@ import net.java.games.jogl.GL; /** * Warp - * + * * @author cwei */ public abstract class Warp extends Model { - - - // warpsin.h - public static final float[] SIN = { - 0f, 0.19633f, 0.392541f, 0.588517f, 0.784137f, 0.979285f, 1.17384f, 1.3677f, - 1.56072f, 1.75281f, 1.94384f, 2.1337f, 2.32228f, 2.50945f, 2.69512f, 2.87916f, - 3.06147f, 3.24193f, 3.42044f, 3.59689f, 3.77117f, 3.94319f, 4.11282f, 4.27998f, - 4.44456f, 4.60647f, 4.76559f, 4.92185f, 5.07515f, 5.22538f, 5.37247f, 5.51632f, - 5.65685f, 5.79398f, 5.92761f, 6.05767f, 6.18408f, 6.30677f, 6.42566f, 6.54068f, - 6.65176f, 6.75883f, 6.86183f, 6.9607f, 7.05537f, 7.14579f, 7.23191f, 7.31368f, - 7.39104f, 7.46394f, 7.53235f, 7.59623f, 7.65552f, 7.71021f, 7.76025f, 7.80562f, - 7.84628f, 7.88222f, 7.91341f, 7.93984f, 7.96148f, 7.97832f, 7.99036f, 7.99759f, - 8f, 7.99759f, 7.99036f, 7.97832f, 7.96148f, 7.93984f, 7.91341f, 7.88222f, - 7.84628f, 7.80562f, 7.76025f, 7.71021f, 7.65552f, 7.59623f, 7.53235f, 7.46394f, - 7.39104f, 7.31368f, 7.23191f, 7.14579f, 7.05537f, 6.9607f, 6.86183f, 6.75883f, - 6.65176f, 6.54068f, 6.42566f, 6.30677f, 6.18408f, 6.05767f, 5.92761f, 5.79398f, - 5.65685f, 5.51632f, 5.37247f, 5.22538f, 5.07515f, 4.92185f, 4.76559f, 4.60647f, - 4.44456f, 4.27998f, 4.11282f, 3.94319f, 3.77117f, 3.59689f, 3.42044f, 3.24193f, - 3.06147f, 2.87916f, 2.69512f, 2.50945f, 2.32228f, 2.1337f, 1.94384f, 1.75281f, - 1.56072f, 1.3677f, 1.17384f, 0.979285f, 0.784137f, 0.588517f, 0.392541f, 0.19633f, - 9.79717e-16f, -0.19633f, -0.392541f, -0.588517f, -0.784137f, -0.979285f, -1.17384f, -1.3677f, - -1.56072f, -1.75281f, -1.94384f, -2.1337f, -2.32228f, -2.50945f, -2.69512f, -2.87916f, - -3.06147f, -3.24193f, -3.42044f, -3.59689f, -3.77117f, -3.94319f, -4.11282f, -4.27998f, - -4.44456f, -4.60647f, -4.76559f, -4.92185f, -5.07515f, -5.22538f, -5.37247f, -5.51632f, - -5.65685f, -5.79398f, -5.92761f, -6.05767f, -6.18408f, -6.30677f, -6.42566f, -6.54068f, - -6.65176f, -6.75883f, -6.86183f, -6.9607f, -7.05537f, -7.14579f, -7.23191f, -7.31368f, - -7.39104f, -7.46394f, -7.53235f, -7.59623f, -7.65552f, -7.71021f, -7.76025f, -7.80562f, - -7.84628f, -7.88222f, -7.91341f, -7.93984f, -7.96148f, -7.97832f, -7.99036f, -7.99759f, - -8f, -7.99759f, -7.99036f, -7.97832f, -7.96148f, -7.93984f, -7.91341f, -7.88222f, - -7.84628f, -7.80562f, -7.76025f, -7.71021f, -7.65552f, -7.59623f, -7.53235f, -7.46394f, - -7.39104f, -7.31368f, -7.23191f, -7.14579f, -7.05537f, -6.9607f, -6.86183f, -6.75883f, - -6.65176f, -6.54068f, -6.42566f, -6.30677f, -6.18408f, -6.05767f, -5.92761f, -5.79398f, - -5.65685f, -5.51632f, -5.37247f, -5.22538f, -5.07515f, -4.92185f, -4.76559f, -4.60647f, - -4.44456f, -4.27998f, -4.11282f, -3.94319f, -3.77117f, -3.59689f, -3.42044f, -3.24193f, - -3.06147f, -2.87916f, -2.69512f, -2.50945f, -2.32228f, -2.1337f, -1.94384f, -1.75281f, - -1.56072f, -1.3677f, -1.17384f, -0.979285f, -0.784137f, -0.588517f, -0.392541f, -0.19633f - }; - - // gl_warp.c -- sky and water polygons - //extern model_t *loadmodel; // Model.java - - String skyname; - float skyrotate; - float[] skyaxis = {0, 0, 0}; - image_t[] sky_images = new image_t[6]; - - msurface_t warpface; - - static final int SUBDIVIDE_SIZE = 64; - - void BoundPoly(int numverts, float[][] verts, float[] mins, float[] maxs) - { - int i, j; - float[] v; - - mins[0] = mins[1] = mins[2] = 9999; - maxs[0] = maxs[1] = maxs[2] = -9999; - for (i=0 ; i maxs[j]) - maxs[j] = v[j]; - } - } - } - - void SubdividePolygon(int numverts, float[][] verts) - { - int i, j, k; - float[] mins = {0, 0, 0}; - float[] maxs = {0, 0, 0}; - float m; - float[] v = {0, 0, 0}; - float[][] front = new float[64][3]; - float[][] back = new float[64][3]; - - int f, b; - float[] dist = new float[64]; - float frac; - float s, t; - float[] total = {0, 0, 0}; - float total_s, total_t; - - if (numverts > 60) - Com.Error(Defines.ERR_DROP, "numverts = " + numverts); - - BoundPoly(numverts, verts, mins, maxs); - - // x,y und z - for (i=0 ; i<3 ; i++) - { - m = (mins[i] + maxs[i]) * 0.5f; - m = SUBDIVIDE_SIZE * (float)Math.floor(m / SUBDIVIDE_SIZE + 0.5f); - if (maxs[i] - m < 8) - continue; - if (m - mins[i] < 8) - continue; - - // cut it - for (j=0 ; j= 0) - { - Math3D.VectorCopy(v, front[f]); - f++; - } - if (dist[j] <= 0) - { - Math3D.VectorCopy(v, back[b]); - b++; - } - if (dist[j] == 0 || dist[j+1] == 0) continue; - - if ( (dist[j] > 0) != (dist[j+1] > 0) ) - { - // clip point - frac = dist[j] / (dist[j] - dist[j+1]); - for (k=0 ; k<3 ; k++) - front[f][k] = back[b][k] = v[k] + frac*(verts[j+1][k] - v[k]); - - f++; - b++; - } - } - - SubdividePolygon(f, front); - SubdividePolygon(b, back); - return; - } - - // add a point in the center to help keep warp valid - - // wird im Konstruktor erschlagen - // poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * VERTEXSIZE*sizeof(float)); - - // init polys - glpoly_t poly = new glpoly_t(numverts + 2); - - poly.next = warpface.polys; - warpface.polys = poly; - poly.numverts = numverts + 2; - Math3D.VectorClear(total); - total_s = 0; - total_t = 0; - for (i=0 ; i 0) - vec = loadmodel.vertexes[loadmodel.edges[lindex].v[0]].position; - else - vec = loadmodel.vertexes[loadmodel.edges[-lindex].v[1]].position; - Math3D.VectorCopy(vec, verts[numverts]); - numverts++; - } - - SubdividePolygon(numverts, verts); - } - -// ========================================================= - - - -//// speed up sin calculations - Ed -// float r_turbsin[] = -// { -// #include "warpsin.h" -// }; - static final float TURBSCALE = (float)(256.0f / (2 * Math.PI)); - - /* - ============= - EmitWaterPolys - - Does a water warp on the pre-fragmented glpoly_t chain - ============= - */ - void EmitWaterPolys(msurface_t fa) - { - glpoly_t p, bp; - float[] v; - int i; - float s = 0; - float t = 0; - float os, ot; - float scroll; - float rdt = r_newrefdef.time; - - if ((fa.texinfo.flags & Defines.SURF_FLOWING) != 0) - scroll = -64 * ( (r_newrefdef.time*0.5f) - (int)(r_newrefdef.time*0.5f) ); - else - scroll = 0; - - int index; - FloatBuffer texCoord = globalPolygonInterleavedBuf; - for (bp=fa.polys ; bp != null ; bp=bp.next) - { - p = bp; - - index = p.pos * POLYGON_STRIDE; - for (i=0; i av[1] && av[0] > av[2]) - { - if (v[0] < 0) - axis = 1; - else - axis = 0; - } - else if (av[1] > av[2] && av[1] > av[0]) - { - if (v[1] < 0) - axis = 3; - else - axis = 2; - } - else - { - if (v[2] < 0) - axis = 5; - else - axis = 4; - } - - // project new texture coords - for (i=0 ; i 0) - dv = vecs[i][j - 1]; - else - dv = -vecs[i][-j - 1]; - if (dv < 0.001f) - continue; // don't divide by zero - j = vec_to_st[axis][0]; - if (j < 0) - s = -vecs[i][-j -1] / dv; - else - s = vecs[i][j-1] / dv; - j = vec_to_st[axis][1]; - if (j < 0) - t = -vecs[i][-j -1] / dv; - else - t = vecs[i][j-1] / dv; - - if (s < skymins[0][axis]) - skymins[0][axis] = s; - if (t < skymins[1][axis]) - skymins[1][axis] = t; - if (s > skymaxs[0][axis]) - skymaxs[0][axis] = s; - if (t > skymaxs[1][axis]) - skymaxs[1][axis] = t; - } - } - - static final float ON_EPSILON = 0.1f; // point on plane side epsilon - static final int MAX_CLIP_VERTS = 64; - - static final int SIDE_BACK = 1; - static final int SIDE_FRONT = 0; - static final int SIDE_ON = 2; - - float[] dists = new float[MAX_CLIP_VERTS]; - int[] sides = new int[MAX_CLIP_VERTS]; - float[][][][] newv = new float[6][2][MAX_CLIP_VERTS][3]; - - void ClipSkyPolygon(int nump, float[][] vecs, int stage) - { - float[] norm; - float[] v; - boolean front, back; - float d, e; - int[] newc = { 0, 0 }; - int i, j; - - if (nump > MAX_CLIP_VERTS-2) - Com.Error(Defines.ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); - if (stage == 6) - { // fully clipped, so draw it - DrawSkyPolygon(nump, vecs); - return; - } - - front = back = false; - norm = skyclip[stage]; - for (i=0 ; i ON_EPSILON) - { - front = true; - sides[i] = SIDE_FRONT; - } - else if (d < -ON_EPSILON) - { - back = true; - sides[i] = SIDE_BACK; - } - else - sides[i] = SIDE_ON; - dists[i] = d; - } - - if (!front || !back) - { // not clipped - ClipSkyPolygon (nump, vecs, stage+1); - return; - } - - // clip it - sides[i] = sides[0]; - dists[i] = dists[0]; - Math3D.VectorCopy(vecs[0], vecs[i]); - newc[0] = newc[1] = 0; - - for (i=0; i sky_max) - s = sky_max; - if (t < sky_min) - t = sky_min; - else if (t > sky_max) - t = sky_max; - - t = 1.0f - t; - gl.glTexCoord2f (s, t); - gl.glVertex3f(v[0], v[1], v[2]); - } - - /* - ============== - R_DrawSkyBox - ============== - */ - int[] skytexorder = {0,2,1,3,4,5}; - - void R_DrawSkyBox() - { - int i; - - if (skyrotate != 0) - { // check for no sky at all - for (i=0 ; i<6 ; i++) - if (skymins[0][i] < skymaxs[0][i] - && skymins[1][i] < skymaxs[1][i]) - break; - if (i == 6) - return; // nothing visible - } - - gl.glPushMatrix (); - gl.glTranslatef (r_origin[0], r_origin[1], r_origin[2]); - gl.glRotatef (r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]); - - for (i=0 ; i<6 ; i++) - { - if (skyrotate != 0) - { // hack, forces full sky to draw when rotating - skymins[0][i] = -1; - skymins[1][i] = -1; - skymaxs[0][i] = 1; - skymaxs[1][i] = 1; - } - - if (skymins[0][i] >= skymaxs[0][i] - || skymins[1][i] >= skymaxs[1][i]) - continue; - - GL_Bind(sky_images[skytexorder[i]].texnum); - - gl.glBegin(GL.GL_QUADS); - MakeSkyVec(skymins[0][i], skymins[1][i], i); - MakeSkyVec(skymins[0][i], skymaxs[1][i], i); - MakeSkyVec(skymaxs[0][i], skymaxs[1][i], i); - MakeSkyVec(skymaxs[0][i], skymins[1][i], i); - gl.glEnd (); - } - gl.glPopMatrix (); - } - - - /* - ============ - R_SetSky - ============ - */ - // 3dstudio environment map names - String[] suf = {"rt", "bk", "lf", "ft", "up", "dn"}; - - protected void R_SetSky(String name, float rotate, float[] axis) - { - assert (axis.length == 3) : "vec3_t bug"; - int i; - String pathname; - -// strncpy (skyname, name, sizeof(skyname)-1); - skyname = name; - - skyrotate = rotate; - Math3D.VectorCopy(axis, skyaxis); - - for (i=0 ; i<6 ; i++) - { - // chop down rotating skies for less memory - if (gl_skymip.value != 0 || skyrotate != 0) - gl_picmip.value++; - - if ( qglColorTableEXT && gl_ext_palettedtexture.value != 0) { - // Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[i]); - pathname = "env/" + skyname + suf[i] + ".pcx"; - } else { - // Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga", skyname, suf[i]); - pathname = "env/" + skyname + suf[i] + ".tga"; - } - - sky_images[i] = GL_FindImage(pathname, it_sky); - - if (sky_images[i] == null) - sky_images[i] = r_notexture; - - if (gl_skymip.value != 0 || skyrotate != 0) - { // take less memory - gl_picmip.value--; - sky_min = 1.0f / 256; - sky_max = 255.0f / 256; - } - else - { - sky_min = 1.0f / 512; - sky_max = 511.0f / 512; - } - } - } - - -} + + // warpsin.h + public static final float[] SIN = { 0f, 0.19633f, 0.392541f, 0.588517f, + 0.784137f, 0.979285f, 1.17384f, 1.3677f, 1.56072f, 1.75281f, + 1.94384f, 2.1337f, 2.32228f, 2.50945f, 2.69512f, 2.87916f, + 3.06147f, 3.24193f, 3.42044f, 3.59689f, 3.77117f, 3.94319f, + 4.11282f, 4.27998f, 4.44456f, 4.60647f, 4.76559f, 4.92185f, + 5.07515f, 5.22538f, 5.37247f, 5.51632f, 5.65685f, 5.79398f, + 5.92761f, 6.05767f, 6.18408f, 6.30677f, 6.42566f, 6.54068f, + 6.65176f, 6.75883f, 6.86183f, 6.9607f, 7.05537f, 7.14579f, + 7.23191f, 7.31368f, 7.39104f, 7.46394f, 7.53235f, 7.59623f, + 7.65552f, 7.71021f, 7.76025f, 7.80562f, 7.84628f, 7.88222f, + 7.91341f, 7.93984f, 7.96148f, 7.97832f, 7.99036f, 7.99759f, 8f, + 7.99759f, 7.99036f, 7.97832f, 7.96148f, 7.93984f, 7.91341f, + 7.88222f, 7.84628f, 7.80562f, 7.76025f, 7.71021f, 7.65552f, + 7.59623f, 7.53235f, 7.46394f, 7.39104f, 7.31368f, 7.23191f, + 7.14579f, 7.05537f, 6.9607f, 6.86183f, 6.75883f, 6.65176f, + 6.54068f, 6.42566f, 6.30677f, 6.18408f, 6.05767f, 5.92761f, + 5.79398f, 5.65685f, 5.51632f, 5.37247f, 5.22538f, 5.07515f, + 4.92185f, 4.76559f, 4.60647f, 4.44456f, 4.27998f, 4.11282f, + 3.94319f, 3.77117f, 3.59689f, 3.42044f, 3.24193f, 3.06147f, + 2.87916f, 2.69512f, 2.50945f, 2.32228f, 2.1337f, 1.94384f, + 1.75281f, 1.56072f, 1.3677f, 1.17384f, 0.979285f, 0.784137f, + 0.588517f, 0.392541f, 0.19633f, 9.79717e-16f, -0.19633f, + -0.392541f, -0.588517f, -0.784137f, -0.979285f, -1.17384f, + -1.3677f, -1.56072f, -1.75281f, -1.94384f, -2.1337f, -2.32228f, + -2.50945f, -2.69512f, -2.87916f, -3.06147f, -3.24193f, -3.42044f, + -3.59689f, -3.77117f, -3.94319f, -4.11282f, -4.27998f, -4.44456f, + -4.60647f, -4.76559f, -4.92185f, -5.07515f, -5.22538f, -5.37247f, + -5.51632f, -5.65685f, -5.79398f, -5.92761f, -6.05767f, -6.18408f, + -6.30677f, -6.42566f, -6.54068f, -6.65176f, -6.75883f, -6.86183f, + -6.9607f, -7.05537f, -7.14579f, -7.23191f, -7.31368f, -7.39104f, + -7.46394f, -7.53235f, -7.59623f, -7.65552f, -7.71021f, -7.76025f, + -7.80562f, -7.84628f, -7.88222f, -7.91341f, -7.93984f, -7.96148f, + -7.97832f, -7.99036f, -7.99759f, -8f, -7.99759f, -7.99036f, + -7.97832f, -7.96148f, -7.93984f, -7.91341f, -7.88222f, -7.84628f, + -7.80562f, -7.76025f, -7.71021f, -7.65552f, -7.59623f, -7.53235f, + -7.46394f, -7.39104f, -7.31368f, -7.23191f, -7.14579f, -7.05537f, + -6.9607f, -6.86183f, -6.75883f, -6.65176f, -6.54068f, -6.42566f, + -6.30677f, -6.18408f, -6.05767f, -5.92761f, -5.79398f, -5.65685f, + -5.51632f, -5.37247f, -5.22538f, -5.07515f, -4.92185f, -4.76559f, + -4.60647f, -4.44456f, -4.27998f, -4.11282f, -3.94319f, -3.77117f, + -3.59689f, -3.42044f, -3.24193f, -3.06147f, -2.87916f, -2.69512f, + -2.50945f, -2.32228f, -2.1337f, -1.94384f, -1.75281f, -1.56072f, + -1.3677f, -1.17384f, -0.979285f, -0.784137f, -0.588517f, + -0.392541f, -0.19633f }; + + // gl_warp.c -- sky and water polygons + //extern model_t *loadmodel; // Model.java + + String skyname; + + float skyrotate; + + float[] skyaxis = { 0, 0, 0 }; + + image_t[] sky_images = new image_t[6]; + + msurface_t warpface; + + static final int SUBDIVIDE_SIZE = 64; + + void BoundPoly(int numverts, float[][] verts, float[] mins, float[] maxs) { + int i, j; + float[] v; + + mins[0] = mins[1] = mins[2] = 9999; + maxs[0] = maxs[1] = maxs[2] = -9999; + for (i = 0; i < numverts; i++) { + v = verts[i]; + for (j = 0; j < 3; j++) { + if (v[j] < mins[j]) + mins[j] = v[j]; + if (v[j] > maxs[j]) + maxs[j] = v[j]; + } + } + } + + void SubdividePolygon(int numverts, float[][] verts) { + int i, j, k; + float[] mins = { 0, 0, 0 }; + float[] maxs = { 0, 0, 0 }; + float m; + float[] v = { 0, 0, 0 }; + float[][] front = new float[64][3]; + float[][] back = new float[64][3]; + + int f, b; + float[] dist = new float[64]; + float frac; + float s, t; + float[] total = { 0, 0, 0 }; + float total_s, total_t; + + if (numverts > 60) + Com.Error(Defines.ERR_DROP, "numverts = " + numverts); + + BoundPoly(numverts, verts, mins, maxs); + + // x,y und z + for (i = 0; i < 3; i++) { + m = (mins[i] + maxs[i]) * 0.5f; + m = SUBDIVIDE_SIZE * (float) Math.floor(m / SUBDIVIDE_SIZE + 0.5f); + if (maxs[i] - m < 8) + continue; + if (m - mins[i] < 8) + continue; + + // cut it + for (j = 0; j < numverts; j++) { + dist[j] = verts[j][i] - m; + } + + // wrap cases + dist[j] = dist[0]; + + Math3D.VectorCopy(verts[0], verts[numverts]); + + f = b = 0; + for (j = 0; j < numverts; j++) { + v = verts[j]; + if (dist[j] >= 0) { + Math3D.VectorCopy(v, front[f]); + f++; + } + if (dist[j] <= 0) { + Math3D.VectorCopy(v, back[b]); + b++; + } + if (dist[j] == 0 || dist[j + 1] == 0) + continue; + + if ((dist[j] > 0) != (dist[j + 1] > 0)) { + // clip point + frac = dist[j] / (dist[j] - dist[j + 1]); + for (k = 0; k < 3; k++) + front[f][k] = back[b][k] = v[k] + frac + * (verts[j + 1][k] - v[k]); + + f++; + b++; + } + } + + SubdividePolygon(f, front); + SubdividePolygon(b, back); + return; + } + + // add a point in the center to help keep warp valid + + // wird im Konstruktor erschlagen + // poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * + // VERTEXSIZE*sizeof(float)); + + // init polys + glpoly_t poly = new glpoly_t(numverts + 2); + + poly.next = warpface.polys; + warpface.polys = poly; + poly.numverts = numverts + 2; + Math3D.VectorClear(total); + total_s = 0; + total_t = 0; + for (i = 0; i < numverts; i++) { + Math3D.VectorCopy(verts[i], poly.verts[i + 1]); + s = Math3D.DotProduct(verts[i], warpface.texinfo.vecs[0]); + t = Math3D.DotProduct(verts[i], warpface.texinfo.vecs[1]); + + total_s += s; + total_t += t; + Math3D.VectorAdd(total, verts[i], total); + + poly.verts[i + 1][3] = s; + poly.verts[i + 1][4] = t; + } + + Math3D.VectorScale(total, (1.0f / numverts), poly.verts[0]); + poly.verts[0][3] = total_s / numverts; + poly.verts[0][4] = total_t / numverts; + + // memcpy (poly.verts[i+1], poly.verts[1], sizeof(poly.verts[0])); + System.arraycopy(poly.verts[1], 0, poly.verts[i + 1], 0, + poly.verts[1].length); // :-) + + precompilePolygon(poly); + } + + /* + * ================ GL_SubdivideSurface + * + * Breaks a polygon up along axial 64 unit boundaries so that turbulent and + * sky warps can be done reasonably. ================ + */ + void GL_SubdivideSurface(msurface_t fa) { + float[][] verts = new float[64][3]; + + int numverts; + int i; + int lindex; + float[] vec; + + warpface = fa; + + // + // convert edges back to a normal polygon + // + numverts = 0; + for (i = 0; i < fa.numedges; i++) { + lindex = loadmodel.surfedges[fa.firstedge + i]; + + if (lindex > 0) + vec = loadmodel.vertexes[loadmodel.edges[lindex].v[0]].position; + else + vec = loadmodel.vertexes[loadmodel.edges[-lindex].v[1]].position; + Math3D.VectorCopy(vec, verts[numverts]); + numverts++; + } + + SubdividePolygon(numverts, verts); + } + + // ========================================================= + + //// speed up sin calculations - Ed + // float r_turbsin[] = + // { + // #include "warpsin.h" + // }; + static final float TURBSCALE = (float) (256.0f / (2 * Math.PI)); + + /* + * ============= EmitWaterPolys + * + * Does a water warp on the pre-fragmented glpoly_t chain ============= + */ + void EmitWaterPolys(msurface_t fa) { + glpoly_t p, bp; + float[] v; + int i; + float s = 0; + float t = 0; + float os, ot; + float scroll; + float rdt = r_newrefdef.time; + + if ((fa.texinfo.flags & Defines.SURF_FLOWING) != 0) + scroll = -64 + * ((r_newrefdef.time * 0.5f) - (int) (r_newrefdef.time * 0.5f)); + else + scroll = 0; + + int index; + FloatBuffer texCoord = globalPolygonInterleavedBuf; + for (bp = fa.polys; bp != null; bp = bp.next) { + p = bp; + + index = p.pos * POLYGON_STRIDE; + for (i = 0; i < p.numverts; i++) { + v = p.verts[i]; + os = v[3]; + ot = v[4]; + + s = os + + Warp.SIN[(int) ((ot * 0.125f + r_newrefdef.time) * TURBSCALE) & 255]; + s += scroll; + s *= (1.0f / 64); + + t = ot + + Warp.SIN[(int) ((os * 0.125f + rdt) * TURBSCALE) & 255]; + t *= (1.0f / 64); + + texCoord.put(index, s); + texCoord.put(index + 1, t); + index += POLYGON_STRIDE; + } + gl.glDrawArrays(GL.GL_TRIANGLE_FAN, p.pos, p.numverts); + } + } + + // =================================================================== + + float[][] skyclip = { { 1, 1, 0 }, { 1, -1, 0 }, { 0, -1, 1 }, { 0, 1, 1 }, + { 1, 0, 1 }, { -1, 0, 1 } }; + + int c_sky; + + // 1 = s, 2 = t, 3 = 2048 + int[][] st_to_vec = { { 3, -1, 2 }, { -3, 1, 2 }, + + { 1, 3, 2 }, { -1, -3, 2 }, + + { -2, -1, 3 }, // 0 degrees yaw, look straight up + { 2, -1, -3 } // look straight down + + }; + + int[][] vec_to_st = { { -2, 3, 1 }, { 2, 3, -1 }, + + { 1, 3, 2 }, { -1, 3, -2 }, + + { -2, -1, 3 }, { -2, 1, -3 } + + }; + + float[][] skymins = new float[2][6]; + + float[][] skymaxs = new float[2][6]; + + float sky_min, sky_max; + + void DrawSkyPolygon(int nump, float[][] vecs) { + int i, j; + float[] v = { 0, 0, 0 }; + float[] av = { 0, 0, 0 }; + float s, t, dv; + int axis; + float[] vp; + + c_sky++; + // decide which face it maps to + Math3D.VectorCopy(Globals.vec3_origin, v); + for (i = 0; i < nump; i++) { + Math3D.VectorAdd(vecs[i], v, v); + } + av[0] = Math.abs(v[0]); + av[1] = Math.abs(v[1]); + av[2] = Math.abs(v[2]); + if (av[0] > av[1] && av[0] > av[2]) { + if (v[0] < 0) + axis = 1; + else + axis = 0; + } else if (av[1] > av[2] && av[1] > av[0]) { + if (v[1] < 0) + axis = 3; + else + axis = 2; + } else { + if (v[2] < 0) + axis = 5; + else + axis = 4; + } + + // project new texture coords + for (i = 0; i < nump; i++) { + j = vec_to_st[axis][2]; + if (j > 0) + dv = vecs[i][j - 1]; + else + dv = -vecs[i][-j - 1]; + if (dv < 0.001f) + continue; // don't divide by zero + j = vec_to_st[axis][0]; + if (j < 0) + s = -vecs[i][-j - 1] / dv; + else + s = vecs[i][j - 1] / dv; + j = vec_to_st[axis][1]; + if (j < 0) + t = -vecs[i][-j - 1] / dv; + else + t = vecs[i][j - 1] / dv; + + if (s < skymins[0][axis]) + skymins[0][axis] = s; + if (t < skymins[1][axis]) + skymins[1][axis] = t; + if (s > skymaxs[0][axis]) + skymaxs[0][axis] = s; + if (t > skymaxs[1][axis]) + skymaxs[1][axis] = t; + } + } + + static final float ON_EPSILON = 0.1f; // point on plane side epsilon + + static final int MAX_CLIP_VERTS = 64; + + static final int SIDE_BACK = 1; + + static final int SIDE_FRONT = 0; + + static final int SIDE_ON = 2; + + float[] dists = new float[MAX_CLIP_VERTS]; + + int[] sides = new int[MAX_CLIP_VERTS]; + + float[][][][] newv = new float[6][2][MAX_CLIP_VERTS][3]; + + void ClipSkyPolygon(int nump, float[][] vecs, int stage) { + float[] norm; + float[] v; + boolean front, back; + float d, e; + int[] newc = { 0, 0 }; + int i, j; + + if (nump > MAX_CLIP_VERTS - 2) + Com.Error(Defines.ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); + if (stage == 6) { // fully clipped, so draw it + DrawSkyPolygon(nump, vecs); + return; + } + + front = back = false; + norm = skyclip[stage]; + for (i = 0; i < nump; i++) { + d = Math3D.DotProduct(vecs[i], norm); + if (d > ON_EPSILON) { + front = true; + sides[i] = SIDE_FRONT; + } else if (d < -ON_EPSILON) { + back = true; + sides[i] = SIDE_BACK; + } else + sides[i] = SIDE_ON; + dists[i] = d; + } + + if (!front || !back) { // not clipped + ClipSkyPolygon(nump, vecs, stage + 1); + return; + } + + // clip it + sides[i] = sides[0]; + dists[i] = dists[0]; + Math3D.VectorCopy(vecs[0], vecs[i]); + newc[0] = newc[1] = 0; + + for (i = 0; i < nump; i++) { + v = vecs[i]; + switch (sides[i]) { + case SIDE_FRONT: + Math3D.VectorCopy(v, newv[stage][0][newc[0]]); + newc[0]++; + break; + case SIDE_BACK: + Math3D.VectorCopy(v, newv[stage][1][newc[1]]); + newc[1]++; + break; + case SIDE_ON: + Math3D.VectorCopy(v, newv[stage][0][newc[0]]); + newc[0]++; + Math3D.VectorCopy(v, newv[stage][1][newc[1]]); + newc[1]++; + break; + } + + if (sides[i] == SIDE_ON || sides[i + 1] == SIDE_ON + || sides[i + 1] == sides[i]) + continue; + + d = dists[i] / (dists[i] - dists[i + 1]); + for (j = 0; j < 3; j++) { + e = v[j] + d * (vecs[i + 1][j] - v[j]); + newv[stage][0][newc[0]][j] = e; + newv[stage][1][newc[1]][j] = e; + } + newc[0]++; + newc[1]++; + } + + // continue + ClipSkyPolygon(newc[0], newv[stage][0], stage + 1); + ClipSkyPolygon(newc[1], newv[stage][1], stage + 1); + } + + float[][] verts = new float[MAX_CLIP_VERTS][3]; + + /* + * ================= R_AddSkySurface ================= + */ + void R_AddSkySurface(msurface_t fa) { + int i; + glpoly_t p; + + // calculate vertex values for sky box + for (p = fa.polys; p != null; p = p.next) { + for (i = 0; i < p.numverts; i++) { + Math3D.VectorSubtract(p.verts[i], r_origin, verts[i]); + } + ClipSkyPolygon(p.numverts, verts, 0); + } + } + + /* + * ============== R_ClearSkyBox ============== + */ + void R_ClearSkyBox() { + int i; + + for (i = 0; i < 6; i++) { + skymins[0][i] = skymins[1][i] = 9999; + skymaxs[0][i] = skymaxs[1][i] = -9999; + } + } + + void MakeSkyVec(float s, float t, int axis) { + float[] v = { 0, 0, 0 }; + float[] b = { 0, 0, 0 }; + int j, k; + + b[0] = s * 2300; + b[1] = t * 2300; + b[2] = 2300; + + for (j = 0; j < 3; j++) { + k = st_to_vec[axis][j]; + if (k < 0) + v[j] = -b[-k - 1]; + else + v[j] = b[k - 1]; + } + + // avoid bilerp seam + s = (s + 1) * 0.5f; + t = (t + 1) * 0.5f; + + if (s < sky_min) + s = sky_min; + else if (s > sky_max) + s = sky_max; + if (t < sky_min) + t = sky_min; + else if (t > sky_max) + t = sky_max; + + t = 1.0f - t; + gl.glTexCoord2f(s, t); + gl.glVertex3f(v[0], v[1], v[2]); + } + + /* + * ============== R_DrawSkyBox ============== + */ + int[] skytexorder = { 0, 2, 1, 3, 4, 5 }; + + void R_DrawSkyBox() { + int i; + + if (skyrotate != 0) { // check for no sky at all + for (i = 0; i < 6; i++) + if (skymins[0][i] < skymaxs[0][i] + && skymins[1][i] < skymaxs[1][i]) + break; + if (i == 6) + return; // nothing visible + } + + gl.glPushMatrix(); + gl.glTranslatef(r_origin[0], r_origin[1], r_origin[2]); + gl.glRotatef(r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], + skyaxis[2]); + + for (i = 0; i < 6; i++) { + if (skyrotate != 0) { // hack, forces full sky to draw when rotating + skymins[0][i] = -1; + skymins[1][i] = -1; + skymaxs[0][i] = 1; + skymaxs[1][i] = 1; + } + + if (skymins[0][i] >= skymaxs[0][i] + || skymins[1][i] >= skymaxs[1][i]) + continue; + + GL_Bind(sky_images[skytexorder[i]].texnum); + + gl.glBegin(GL.GL_QUADS); + MakeSkyVec(skymins[0][i], skymins[1][i], i); + MakeSkyVec(skymins[0][i], skymaxs[1][i], i); + MakeSkyVec(skymaxs[0][i], skymaxs[1][i], i); + MakeSkyVec(skymaxs[0][i], skymins[1][i], i); + gl.glEnd(); + } + gl.glPopMatrix(); + } + + /* + * ============ R_SetSky ============ + */ + // 3dstudio environment map names + String[] suf = { "rt", "bk", "lf", "ft", "up", "dn" }; + + protected void R_SetSky(String name, float rotate, float[] axis) { + assert (axis.length == 3) : "vec3_t bug"; + int i; + String pathname; + + // strncpy (skyname, name, sizeof(skyname)-1); + skyname = name; + + skyrotate = rotate; + Math3D.VectorCopy(axis, skyaxis); + + for (i = 0; i < 6; i++) { + // chop down rotating skies for less memory + if (gl_skymip.value != 0 || skyrotate != 0) + gl_picmip.value++; + + if (qglColorTableEXT && gl_ext_palettedtexture.value != 0) { + // Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", + // skyname, suf[i]); + pathname = "env/" + skyname + suf[i] + ".pcx"; + } else { + // Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga", + // skyname, suf[i]); + pathname = "env/" + skyname + suf[i] + ".tga"; + } + + sky_images[i] = GL_FindImage(pathname, it_sky); + + if (sky_images[i] == null) + sky_images[i] = r_notexture; + + if (gl_skymip.value != 0 || skyrotate != 0) { // take less memory + gl_picmip.value--; + sky_min = 1.0f / 256; + sky_max = 255.0f / 256; + } else { + sky_min = 1.0f / 512; + sky_max = 511.0f / 512; + } + } + } + +} \ No newline at end of file diff --git a/src/jake2/render/jogl/Image.java b/src/jake2/render/jogl/Image.java index 64588ef..1edb8fe 100644 --- a/src/jake2/render/jogl/Image.java +++ b/src/jake2/render/jogl/Image.java @@ -2,34 +2,36 @@ * Image.java * Copyright (C) 2003 * - * $Id: Image.java,v 1.5 2004-07-16 10:11:35 cawe Exp $ + * $Id: Image.java,v 1.6 2004-09-22 19:22:16 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.render.jogl; import jake2.Defines; import jake2.client.VID; import jake2.client.particle_t; import jake2.game.cvar_t; -import jake2.qcommon.*; +import jake2.qcommon.Com; +import jake2.qcommon.Cvar; +import jake2.qcommon.FS; import jake2.qcommon.longjmpException; import jake2.qcommon.qfiles; import jake2.render.image_t; @@ -40,7 +42,9 @@ import java.awt.Dimension; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; -import java.nio.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; import java.util.Arrays; import net.java.games.jogl.GL; @@ -52,1643 +56,1615 @@ import net.java.games.jogl.GL; */ public abstract class Image extends Main { - image_t draw_chars; - - image_t[] gltextures = new image_t[MAX_GLTEXTURES]; - //Map gltextures = new Hashtable(MAX_GLTEXTURES); // image_t - int numgltextures; - int base_textureid; // gltextures[i] = base_textureid+i - - byte[] intensitytable = new byte[256]; - byte[] gammatable = new byte[256]; - - cvar_t intensity; - - // - // qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky ); - // qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap); - // - - int gl_solid_format = 3; - int gl_alpha_format = 4; - - int gl_tex_solid_format = 3; - int gl_tex_alpha_format = 4; - - int gl_filter_min = GL.GL_LINEAR_MIPMAP_NEAREST; - int gl_filter_max = GL.GL_LINEAR; - - Image() { - // init the texture cache - for (int i = 0; i < gltextures.length; i++) - { - gltextures[i] = new image_t(i); - } - numgltextures = 0; - } - - void GL_SetTexturePalette(int[] palette) { - - assert(palette != null && palette.length == 256) : "int palette[256] bug"; - - int i; - byte[] temptable = new byte[768]; - - if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f) { - for (i = 0; i < 256; i++) { - temptable[i * 3 + 0] = (byte) ((palette[i] >> 0) & 0xff); - temptable[i * 3 + 1] = (byte) ((palette[i] >> 8) & 0xff); - temptable[i * 3 + 2] = (byte) ((palette[i] >> 16) & 0xff); - } - - gl.glColorTableEXT(GL.GL_SHARED_TEXTURE_PALETTE_EXT, GL.GL_RGB, 256, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, temptable); - } - } - - void GL_EnableMultitexture(boolean enable) { - if (!qglSelectTextureSGIS && !qglActiveTextureARB) - return; - - if (enable) { - GL_SelectTexture(GL_TEXTURE1); - gl.glEnable(GL.GL_TEXTURE_2D); - GL_TexEnv(GL.GL_REPLACE); - } - else { - GL_SelectTexture(GL_TEXTURE1); - gl.glDisable(GL.GL_TEXTURE_2D); - GL_TexEnv(GL.GL_REPLACE); - } - GL_SelectTexture(GL_TEXTURE0); - GL_TexEnv(GL.GL_REPLACE); - } - - void GL_SelectTexture(int texture /* GLenum */) { - int tmu; - - if (!qglSelectTextureSGIS && !qglActiveTextureARB) - return; - - if (texture == GL_TEXTURE0) { - tmu = 0; - } - else { - tmu = 1; - } - - if (tmu == gl_state.currenttmu) { - return; - } - - gl_state.currenttmu = tmu; - - if (qglSelectTextureSGIS) { - // TODO handle this: gl.glSelectTextureSGIS(texture); - gl.glActiveTexture(texture); - } - else if (qglActiveTextureARB) { - gl.glActiveTextureARB(texture); - gl.glClientActiveTextureARB(texture); - } - } - - int[] lastmodes = { -1, -1 }; - - void GL_TexEnv(int mode /* GLenum */ - ) { - - if (mode != lastmodes[gl_state.currenttmu]) { - gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, mode); - lastmodes[gl_state.currenttmu] = mode; - } - } - - void GL_Bind(int texnum) { - - if ((gl_nobind.value != 0) && (draw_chars != null)) { - // performance evaluation option - texnum = draw_chars.texnum; - } - if (gl_state.currenttextures[gl_state.currenttmu] == texnum) - return; - - gl_state.currenttextures[gl_state.currenttmu] = texnum; - gl.glBindTexture(GL.GL_TEXTURE_2D, texnum); - } - - void GL_MBind(int target /* GLenum */ - , int texnum) { - GL_SelectTexture(target); - if (target == GL_TEXTURE0) { - if (gl_state.currenttextures[0] == texnum) - return; - } - else { - if (gl_state.currenttextures[1] == texnum) - return; - } - GL_Bind(texnum); - } - - // glmode_t - static class glmode_t { - String name; - int minimize, maximize; - - glmode_t(String name, int minimize, int maximze) { - this.name = name; - this.minimize = minimize; - this.maximize = maximze; - } - } - - static final glmode_t modes[] = - { - new glmode_t("GL_NEAREST", GL.GL_NEAREST, GL.GL_NEAREST), - new glmode_t("GL_LINEAR", GL.GL_LINEAR, GL.GL_LINEAR), - new glmode_t("GL_NEAREST_MIPMAP_NEAREST", GL.GL_NEAREST_MIPMAP_NEAREST, GL.GL_NEAREST), - new glmode_t("GL_LINEAR_MIPMAP_NEAREST", GL.GL_LINEAR_MIPMAP_NEAREST, GL.GL_LINEAR), - new glmode_t("GL_NEAREST_MIPMAP_LINEAR", GL.GL_NEAREST_MIPMAP_LINEAR, GL.GL_NEAREST), - new glmode_t("GL_LINEAR_MIPMAP_LINEAR", GL.GL_LINEAR_MIPMAP_LINEAR, GL.GL_LINEAR)}; - - static final int NUM_GL_MODES = modes.length; - - // gltmode_t - static class gltmode_t { - String name; - int mode; - - gltmode_t(String name, int mode) { - this.name = name; - this.mode = mode; - } - } - - static final gltmode_t[] gl_alpha_modes = - { - new gltmode_t("default", 4), - new gltmode_t("GL_RGBA", GL.GL_RGBA), - new gltmode_t("GL_RGBA8", GL.GL_RGBA8), - new gltmode_t("GL_RGB5_A1", GL.GL_RGB5_A1), - new gltmode_t("GL_RGBA4", GL.GL_RGBA4), - new gltmode_t("GL_RGBA2", GL.GL_RGBA2), - }; - - static final int NUM_GL_ALPHA_MODES = gl_alpha_modes.length; - - static final gltmode_t[] gl_solid_modes = - { - new gltmode_t("default", 3), - new gltmode_t("GL_RGB", GL.GL_RGB), - new gltmode_t("GL_RGB8", GL.GL_RGB8), - new gltmode_t("GL_RGB5", GL.GL_RGB5), - new gltmode_t("GL_RGB4", GL.GL_RGB4), - new gltmode_t("GL_R3_G3_B2", GL.GL_R3_G3_B2), - // #ifdef GL_RGB2_EXT - new gltmode_t("GL_RGB2", GL.GL_RGB2_EXT) - // #endif - }; - - static final int NUM_GL_SOLID_MODES = gl_solid_modes.length; - - /* - =============== - GL_TextureMode - =============== - */ - void GL_TextureMode(String string) { - - int i; - for (i = 0; i < NUM_GL_MODES; i++) { - if (modes[i].name.equalsIgnoreCase(string)) - break; - } - - if (i == NUM_GL_MODES) { - VID.Printf(Defines.PRINT_ALL, "bad filter name: [" + string + "]\n"); - return; - } - - gl_filter_min = modes[i].minimize; - gl_filter_max = modes[i].maximize; - - image_t glt; - // change all the existing mipmap texture objects - for (i = 0; i < numgltextures; i++) { - glt = gltextures[i]; - - if (glt.type != it_pic && glt.type != it_sky) { - GL_Bind(glt.texnum); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, gl_filter_min); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - } - } - - /* - =============== - GL_TextureAlphaMode - =============== - */ - void GL_TextureAlphaMode(String string) { - - int i; - for (i = 0; i < NUM_GL_ALPHA_MODES; i++) { - if (gl_alpha_modes[i].name.equalsIgnoreCase(string)) - break; - } - - if (i == NUM_GL_ALPHA_MODES) { - VID.Printf(Defines.PRINT_ALL, "bad alpha texture mode name: [" + string + "]\n"); - return; - } - - gl_tex_alpha_format = gl_alpha_modes[i].mode; - } - - /* - =============== - GL_TextureSolidMode - =============== - */ - void GL_TextureSolidMode(String string) { - int i; - for (i = 0; i < NUM_GL_SOLID_MODES; i++) { - if (gl_solid_modes[i].name.equalsIgnoreCase(string)) - break; - } - - if (i == NUM_GL_SOLID_MODES) { - VID.Printf(Defines.PRINT_ALL, "bad solid texture mode name: [" + string + "]\n"); - return; - } - - gl_tex_solid_format = gl_solid_modes[i].mode; - } - - /* - =============== - GL_ImageList_f - =============== - */ - void GL_ImageList_f() { - - image_t image; - int texels; - final String[] palstrings = { "RGB", "PAL" }; - - VID.Printf(Defines.PRINT_ALL, "------------------\n"); - texels = 0; - - for (int i = 0; i < numgltextures; i++) { - image = gltextures[i]; - if (image.texnum <= 0) - continue; - - texels += image.upload_width * image.upload_height; - switch (image.type) { - case it_skin : - VID.Printf(Defines.PRINT_ALL, "M"); - break; - case it_sprite : - VID.Printf(Defines.PRINT_ALL, "S"); - break; - case it_wall : - VID.Printf(Defines.PRINT_ALL, "W"); - break; - case it_pic : - VID.Printf(Defines.PRINT_ALL, "P"); - break; - default : - VID.Printf(Defines.PRINT_ALL, " "); - break; - } - - VID.Printf( - Defines.PRINT_ALL, - " %3i %3i %s: %s\n", - new Vargs(4).add(image.upload_width).add(image.upload_height).add(palstrings[(image.paletted) ? 1 : 0]).add( - image.name)); - } - VID.Printf(Defines.PRINT_ALL, "Total texel count (not counting mipmaps): " + texels + '\n'); - } - - /* - ============================================================================= - - scrap allocation - - Allocate all the little status bar objects into a single texture - to crutch up inefficient hardware / drivers - - ============================================================================= - */ - - static final int MAX_SCRAPS = 1; - static final int BLOCK_WIDTH = 256; - static final int BLOCK_HEIGHT = 256; - - int[][] scrap_allocated = new int[MAX_SCRAPS][BLOCK_WIDTH]; - byte[][] scrap_texels = new byte[MAX_SCRAPS][BLOCK_WIDTH * BLOCK_HEIGHT]; - boolean scrap_dirty; - - static class pos_t { - int x, y; - - pos_t(int x, int y) { - this.x = x; - this.y = y; - } - } - - // returns a texture number and the position inside it - int Scrap_AllocBlock(int w, int h, pos_t pos) { - int i, j; - int best, best2; - int texnum; - - for (texnum = 0; texnum < MAX_SCRAPS; texnum++) { - best = BLOCK_HEIGHT; - - for (i = 0; i < BLOCK_WIDTH - w; i++) { - best2 = 0; - - for (j = 0; j < w; j++) { - if (scrap_allocated[texnum][i + j] >= best) - break; - if (scrap_allocated[texnum][i + j] > best2) - best2 = scrap_allocated[texnum][i + j]; - } - if (j == w) { // this is a valid spot - pos.x = i; - pos.y = best = best2; - } - } - - if (best + h > BLOCK_HEIGHT) - continue; - - for (i = 0; i < w; i++) - scrap_allocated[texnum][pos.x + i] = best + h; - - return texnum; - } - - return -1; - // Sys_Error ("Scrap_AllocBlock: full"); - } - - int scrap_uploads = 0; - - void Scrap_Upload() { - scrap_uploads++; - GL_Bind(TEXNUM_SCRAPS); - GL_Upload8(scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, false); - scrap_dirty = false; - } - - /* - ================================================================= - - PCX LOADING - - ================================================================= - */ - - /* - ============== - LoadPCX - ============== - */ - byte[] LoadPCX(String filename, byte[][] palette, Dimension dim) { - qfiles.pcx_t pcx; - - // - // load the file - // - byte[] raw = FS.LoadFile(filename); - - if (raw == null) { - VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename + '\n'); - return null; - } - - // - // parse the PCX file - // - pcx = new qfiles.pcx_t(raw); - - if (pcx.manufacturer != 0x0a - || pcx.version != 5 - || pcx.encoding != 1 - || pcx.bits_per_pixel != 8 - || pcx.xmax >= 640 - || pcx.ymax >= 480) { - - VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n'); - return null; - } - - int width = pcx.xmax - pcx.xmin + 1; - int height = pcx.ymax - pcx.ymin + 1; - - byte[] pix = new byte[width * height]; - - if (palette != null) { - palette[0] = new byte[768]; - System.arraycopy(raw, raw.length - 768, palette[0], 0, 768); - } - - if (dim != null) { - dim.width = width; - dim.height = height; - } - - // - // decode pcx - // - int count = 0; - byte dataByte = 0; - int runLength = 0; - int x, y; - - for (y = 0; y < height; y++) { - for (x = 0; x < width;) { - - dataByte = pcx.data.get(); - - if ((dataByte & 0xC0) == 0xC0) { - runLength = dataByte & 0x3F; - dataByte = pcx.data.get(); - // write runLength pixel - while (runLength-- > 0) { - pix[count++] = dataByte; - x++; - } - } - else { - // write one pixel - pix[count++] = dataByte; - x++; - } - } - } - return pix; - } - - // /* - // ========================================================= - // - // TARGA LOADING - // - // ========================================================= - // */ - /* - ============= - LoadTGA - ============= - */ - byte[] LoadTGA(String name, Dimension dim) { - int columns, rows, numPixels; - int pixbuf; // index into pic - int row, column; - byte[] raw; - ByteBuffer buf_p; - int length; - qfiles.tga_t targa_header; - byte[] pic = null; - - // - // load the file - // - raw = FS.LoadFile (name); - - if (raw == null) - { - VID.Printf(Defines.PRINT_DEVELOPER, "Bad tga file "+ name +'\n'); - return null; - } - - targa_header = new qfiles.tga_t(raw); - - if (targa_header.image_type != 2 && targa_header.image_type != 10) - Com.Error(Defines.ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); - - if (targa_header.colormap_type != 0 || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24)) - Com.Error (Defines.ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); - - columns = targa_header.width; - rows = targa_header.height; - numPixels = columns * rows; - - if (dim != null) { - dim.width = columns; - dim.height = rows; - } - - pic = new byte[numPixels * 4]; // targa_rgba; - - if (targa_header.id_length != 0) - targa_header.data.position(targa_header.id_length); // skip TARGA image comment - - buf_p = targa_header.data; - - byte red,green,blue,alphabyte; - red = green = blue = alphabyte = 0; - int packetHeader, packetSize, j; - - if (targa_header.image_type==2) { // Uncompressed, RGB images - for(row=rows-1; row>=0; row--) { - - pixbuf = row * columns * 4; - - for(column=0; column=0; row--) { - - pixbuf = row * columns * 4; - try { - - for(column=0; column0) - row--; - else - // goto label breakOut; - throw new longjmpException(); - - pixbuf = row * columns * 4; - } - } - } - else { // non run-length packet - for(j=0;j0) - row--; - else - // goto label breakOut; - throw new longjmpException(); - - pixbuf = row * columns * 4; - } - } - } - } - } catch (longjmpException e){ - // label breakOut: - } - } - } - return pic; - } - - /* - ==================================================================== - - IMAGE FLOOD FILLING - - ==================================================================== - */ - - /* - ================= - Mod_FloodFillSkin - - Fill background pixels so mipmapping doesn't have haloes - ================= - */ - - static class floodfill_t { - short x, y; - } - - // must be a power of 2 - static final int FLOODFILL_FIFO_SIZE = 0x1000; - static final int FLOODFILL_FIFO_MASK = FLOODFILL_FIFO_SIZE - 1; - // - // #define FLOODFILL_STEP( off, dx, dy ) \ - // { \ - // if (pos[off] == fillcolor) \ - // { \ - // pos[off] = 255; \ - // fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ - // inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ - // } \ - // else if (pos[off] != 255) fdc = pos[off]; \ - // } - - // void FLOODFILL_STEP( int off, int dx, int dy ) - // { - // if (pos[off] == fillcolor) - // { - // pos[off] = 255; - // fifo[inpt].x = x + dx; fifo[inpt].y = y + dy; - // inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - // } - // else if (pos[off] != 255) fdc = pos[off]; - // } - static floodfill_t[] fifo = new floodfill_t[FLOODFILL_FIFO_SIZE]; - static { - for (int j = 0; j < fifo.length; j++) { - fifo[j] = new floodfill_t(); - } - } - // TODO check this: R_FloodFillSkin( byte[] skin, int skinwidth, int skinheight) - void R_FloodFillSkin(byte[] skin, int skinwidth, int skinheight) { - // byte fillcolor = *skin; // assume this is the pixel to fill - int fillcolor = skin[0] & 0xff; - int inpt = 0, outpt = 0; - int filledcolor = -1; - int i; - - if (filledcolor == -1) { - filledcolor = 0; - // attempt to find opaque black - for (i = 0; i < 256; ++i) - // TODO check this - if (d_8to24table[i] == 0xFF000000) { // alpha 1.0 - //if (d_8to24table[i] == (255 << 0)) // alpha 1.0 - filledcolor = i; - break; - } - } - - // can't fill to filled color or to transparent color (used as visited marker) - if ((fillcolor == filledcolor) || (fillcolor == 255)) { - return; - } - - fifo[inpt].x = 0; - fifo[inpt].y = 0; - inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - - while (outpt != inpt) { - int x = fifo[outpt].x; - int y = fifo[outpt].y; - int fdc = filledcolor; - // byte *pos = &skin[x + skinwidth * y]; - int pos = x + skinwidth * y; - // - outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; - - int off, dx, dy; - - if (x > 0) { - // FLOODFILL_STEP( -1, -1, 0 ); - off = -1; - dx = -1; - dy = 0; - if (skin[pos + off] == (byte) fillcolor) { - skin[pos + off] = (byte) 255; - fifo[inpt].x = (short) (x + dx); - fifo[inpt].y = (short) (y + dy); - inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - } - else if (skin[pos + off] != (byte) 255) - fdc = skin[pos + off] & 0xff; - } - - if (x < skinwidth - 1) { - // FLOODFILL_STEP( 1, 1, 0 ); - off = 1; - dx = 1; - dy = 0; - if (skin[pos + off] == (byte) fillcolor) { - skin[pos + off] = (byte) 255; - fifo[inpt].x = (short) (x + dx); - fifo[inpt].y = (short) (y + dy); - inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - } - else if (skin[pos + off] != (byte) 255) - fdc = skin[pos + off] & 0xff; - } - - if (y > 0) { - // FLOODFILL_STEP( -skinwidth, 0, -1 ); - off = -skinwidth; - dx = 0; - dy = -1; - if (skin[pos + off] == (byte) fillcolor) { - skin[pos + off] = (byte) 255; - fifo[inpt].x = (short) (x + dx); - fifo[inpt].y = (short) (y + dy); - inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - } - else if (skin[pos + off] != (byte) 255) - fdc = skin[pos + off] & 0xff; - } - - if (y < skinheight - 1) { - // FLOODFILL_STEP( skinwidth, 0, 1 ); - off = skinwidth; - dx = 0; - dy = 1; - if (skin[pos + off] == (byte) fillcolor) { - skin[pos + off] = (byte) 255; - fifo[inpt].x = (short) (x + dx); - fifo[inpt].y = (short) (y + dy); - inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; - } - else if (skin[pos + off] != (byte) 255) - fdc = skin[pos + off] & 0xff; - - } - - skin[x + skinwidth * y] = (byte) fdc; - } - } - - // ======================================================= - - /* - ================ - GL_ResampleTexture - ================ - */ - // cwei :-) - void GL_ResampleTexture(int[] in, int inwidth, int inheight, int[] out, int outwidth, int outheight) { - // int i, j; - // unsigned *inrow, *inrow2; - // int frac, fracstep; - // int[] p1 = new int[1024]; - // int[] p2 = new int[1024]; - // - - // *** this source do the same *** - BufferedImage image = new BufferedImage(inwidth, inheight, BufferedImage.TYPE_INT_ARGB); - - image.setRGB(0, 0, inwidth, inheight, in, 0, inwidth); - - AffineTransformOp op = - new AffineTransformOp( - AffineTransform.getScaleInstance(outwidth * 1.0 / inwidth, outheight * 1.0 / inheight), - AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - BufferedImage tmp = op.filter(image, null); - - tmp.getRGB(0, 0, outwidth, outheight, out, 0, outwidth); - - // *** end *** - - // byte *pix1, *pix2, *pix3, *pix4; - // - // fracstep = inwidth*0x10000/outwidth; - // - // frac = fracstep>>2; - // for (i=0 ; i>16); - // frac += fracstep; - // } - // frac = 3*(fracstep>>2); - // for (i=0 ; i>16); - // frac += fracstep; - // } - // - // for (i=0 ; i> 1; - // for (j=0 ; j>2; - // ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; - // ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; - // ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; - // } - // } - } - - /* - ================ - GL_LightScaleTexture - - Scale up the pixel values in a texture to increase the - lighting range - ================ - */ - void GL_LightScaleTexture(int[] in, int inwidth, int inheight, boolean only_gamma) { - if (only_gamma) { - int i, c; - int r, g, b, color; - - c = inwidth * inheight; - for (i = 0; i < c; i++) { - color = in[i]; - r = (color >> 0) & 0xFF; - g = (color >> 8) & 0xFF; - b = (color >> 16) & 0xFF; - - r = gammatable[r] & 0xFF; - g = gammatable[g] & 0xFF; - b = gammatable[b] & 0xFF; - - in[i] = (r << 0) | (g << 8) | (b << 16) | (color & 0xFF000000); - } - } - else { - int i, c; - int r, g, b, color; - - c = inwidth * inheight; - for (i = 0; i < c; i++) { - color = in[i]; - r = (color >> 0) & 0xFF; - g = (color >> 8) & 0xFF; - b = (color >> 16) & 0xFF; - - r = gammatable[intensitytable[r] & 0xFF] & 0xFF; - g = gammatable[intensitytable[g] & 0xFF] & 0xFF; - b = gammatable[intensitytable[b] & 0xFF] & 0xFF; - - in[i] = (r << 0) | (g << 8) | (b << 16) | (color & 0xFF000000); - } - - } - } - - /* - ================ - GL_MipMap - - Operates in place, quartering the size of the texture - ================ - */ - void GL_MipMap(int[] in, int width, int height) { - int i, j; - int[] out; - - out = in; - - int inIndex = 0; - int outIndex = 0; - - int r, g, b, a; - int p1, p2, p3, p4; - - for (i = 0; i < height; i += 2, inIndex += width) { - for (j = 0; j < width; j += 2, outIndex += 1, inIndex += 2) { - - p1 = in[inIndex + 0]; - p2 = in[inIndex + 1]; - p3 = in[inIndex + width + 0]; - p4 = in[inIndex + width + 1]; - - r = (((p1 >> 0) & 0xFF) + ((p2 >> 0) & 0xFF) + ((p3 >> 0) & 0xFF) + ((p4 >> 0) & 0xFF)) >> 2; - g = (((p1 >> 8) & 0xFF) + ((p2 >> 8) & 0xFF) + ((p3 >> 8) & 0xFF) + ((p4 >> 8) & 0xFF)) >> 2; - b = (((p1 >> 16) & 0xFF) + ((p2 >> 16) & 0xFF) + ((p3 >> 16) & 0xFF) + ((p4 >> 16) & 0xFF)) >> 2; - a = (((p1 >> 24) & 0xFF) + ((p2 >> 24) & 0xFF) + ((p3 >> 24) & 0xFF) + ((p4 >> 24) & 0xFF)) >> 2; - - out[outIndex] = (r << 0) | (g << 8) | (b << 16) | (a << 24); - } - } - } - - /* - =============== - GL_Upload32 - - Returns has_alpha - =============== - */ - void GL_BuildPalettedTexture(byte[] paletted_texture, int[] scaled, int scaled_width, int scaled_height) { - - int r, g, b, c; - int size = scaled_width * scaled_height; - - for (int i = 0; i < size; i++) { - - r = (scaled[i] >> 3) & 31; - g = (scaled[i] >> 10) & 63; - b = (scaled[i] >> 19) & 31; - - c = r | (g << 5) | (b << 11); - - paletted_texture[i] = gl_state.d_16to8table[c]; - } - } - - int upload_width, upload_height; - boolean uploaded_paletted; - - /* - =============== - GL_Upload32 - - Returns has_alpha - =============== - */ - int[] scaled = new int[256 * 256]; - byte[] paletted_texture = new byte[256 * 256]; - IntBuffer tex = Lib.newIntBuffer(512 * 256, ByteOrder.LITTLE_ENDIAN); - - boolean GL_Upload32(int[] data, int width, int height, boolean mipmap) { - int samples; - int scaled_width, scaled_height; - int i, c; - int comp; - - Arrays.fill(scaled, 0); - Arrays.fill(paletted_texture, (byte)0); - - uploaded_paletted = false; - - for (scaled_width = 1; scaled_width < width; scaled_width <<= 1); - if (gl_round_down.value > 0.0f && scaled_width > width && mipmap) - scaled_width >>= 1; - for (scaled_height = 1; scaled_height < height; scaled_height <<= 1); - if (gl_round_down.value > 0.0f && scaled_height > height && mipmap) - scaled_height >>= 1; - - // let people sample down the world textures for speed - if (mipmap) { - scaled_width >>= (int) gl_picmip.value; - scaled_height >>= (int) gl_picmip.value; - } - - // don't ever bother with >256 textures - if (scaled_width > 256) - scaled_width = 256; - if (scaled_height > 256) - scaled_height = 256; - - if (scaled_width < 1) - scaled_width = 1; - if (scaled_height < 1) - scaled_height = 1; - - upload_width = scaled_width; - upload_height = scaled_height; - - if (scaled_width * scaled_height > 256 * 256) - Com.Error(Defines.ERR_DROP, "GL_Upload32: too big"); - - // scan the texture for any non-255 alpha - c = width * height; - samples = gl_solid_format; - - for (i = 0; i < c; i++) { - if ((data[i] & 0xff000000) != 0xff000000) { - samples = gl_alpha_format; - break; - } - } - - if (samples == gl_solid_format) - comp = gl_tex_solid_format; - else if (samples == gl_alpha_format) - comp = gl_tex_alpha_format; - else { - VID.Printf(Defines.PRINT_ALL, "Unknown number of texture components " + samples + '\n'); - comp = samples; - } - - // simulates a goto - try { - if (scaled_width == width && scaled_height == height) { - if (!mipmap) { - if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && samples == gl_solid_format) { - uploaded_paletted = true; - GL_BuildPalettedTexture(paletted_texture, data, scaled_width, scaled_height); - gl.glTexImage2D( - GL.GL_TEXTURE_2D, - 0, - GL_COLOR_INDEX8_EXT, - scaled_width, - scaled_height, - 0, - GL.GL_COLOR_INDEX, - GL.GL_UNSIGNED_BYTE, - paletted_texture); - } - else { - tex.rewind(); tex.put(data); - gl.glTexImage2D( - GL.GL_TEXTURE_2D, - 0, - comp, - scaled_width, - scaled_height, - 0, - GL.GL_RGBA, - GL.GL_UNSIGNED_BYTE, - tex); - } - //goto done; - throw new longjmpException(); - } - //memcpy (scaled, data, width*height*4); were bytes - System.arraycopy(data, 0, scaled, 0, width * height); - - } - else - GL_ResampleTexture(data, width, height, scaled, scaled_width, scaled_height); - - GL_LightScaleTexture(scaled, scaled_width, scaled_height, !mipmap); - - if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && (samples == gl_solid_format)) { - uploaded_paletted = true; - GL_BuildPalettedTexture(paletted_texture, scaled, scaled_width, scaled_height); - gl.glTexImage2D( - GL.GL_TEXTURE_2D, - 0, - GL_COLOR_INDEX8_EXT, - scaled_width, - scaled_height, - 0, - GL.GL_COLOR_INDEX, - GL.GL_UNSIGNED_BYTE, - paletted_texture); - } - else { - tex.rewind(); tex.put(scaled); - gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, tex); - } - - if (mipmap) { - int miplevel; - miplevel = 0; - while (scaled_width > 1 || scaled_height > 1) { - GL_MipMap(scaled, scaled_width, scaled_height); - scaled_width >>= 1; - scaled_height >>= 1; - if (scaled_width < 1) - scaled_width = 1; - if (scaled_height < 1) - scaled_height = 1; - - miplevel++; - if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && samples == gl_solid_format) { - uploaded_paletted = true; - GL_BuildPalettedTexture(paletted_texture, scaled, scaled_width, scaled_height); - gl.glTexImage2D( - GL.GL_TEXTURE_2D, - miplevel, - GL_COLOR_INDEX8_EXT, - scaled_width, - scaled_height, - 0, - GL.GL_COLOR_INDEX, - GL.GL_UNSIGNED_BYTE, - paletted_texture); - } - else { - tex.rewind(); tex.put(scaled); - gl.glTexImage2D( - GL.GL_TEXTURE_2D, - miplevel, - comp, - scaled_width, - scaled_height, - 0, - GL.GL_RGBA, - GL.GL_UNSIGNED_BYTE, - tex); - } - } - } - // label done: - } - catch (longjmpException e) { - ; // replaces label done - } - - if (mipmap) { - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, gl_filter_min); - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - else { - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, gl_filter_max); - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - - return (samples == gl_alpha_format); - } - - /* - =============== - GL_Upload8 - - Returns has_alpha - =============== - */ - - int[] trans = new int[512 * 256]; - - boolean GL_Upload8(byte[] data, int width, int height, boolean mipmap, boolean is_sky) { - - Arrays.fill(trans, 0); - - int s = width * height; - - if (s > trans.length) - Com.Error(Defines.ERR_DROP, "GL_Upload8: too large"); - - if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && is_sky) { - gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, width, height, 0, GL.GL_COLOR_INDEX, GL.GL_UNSIGNED_BYTE, data); - - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, gl_filter_max); - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, gl_filter_max); - - // TODO check this - return false; - } - else { - int p; - int rgb; - for (int i = 0; i < s; i++) { - p = data[i] & 0xff; - trans[i] = d_8to24table[p]; - - if (p == 255) { // transparent, so scan around for another color - // to avoid alpha fringes - // FIXME: do a full flood fill so mips work... - if (i > width && (data[i - width] & 0xff) != 255) - p = data[i - width] & 0xff; - else if (i < s - width && (data[i + width] & 0xff) != 255) - p = data[i + width] & 0xff; - else if (i > 0 && (data[i - 1] & 0xff) != 255) - p = data[i - 1] & 0xff; - else if (i < s - 1 && (data[i + 1] & 0xff) != 255) - p = data[i + 1] & 0xff; - else - p = 0; - // copy rgb components - - // ((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0]; - // ((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1]; - // ((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2]; - - trans[i] = d_8to24table[p] & 0x00FFFFFF; // only rgb - } - } - - return GL_Upload32(trans, width, height, mipmap); - } - } - - /* - ================ - GL_LoadPic - - This is also used as an entry point for the generated r_notexture - ================ - */ - image_t GL_LoadPic(String name, byte[] pic, int width, int height, int type, int bits) { - image_t image; - int i; - - // find a free image_t - for (i = 0; i Defines.MAX_QPATH) - Com.Error(Defines.ERR_DROP, "Draw_LoadPic: \"" + name + "\" is too long"); - - image.name = name; - image.registration_sequence = registration_sequence; - - image.width = width; - image.height = height; - image.type = type; - - - if (type == it_skin && bits == 8) - R_FloodFillSkin(pic, width, height); - - // load little pics into the scrap - if (image.type == it_pic && bits == 8 && image.width < 64 && image.height < 64) { - pos_t pos = new pos_t(0, 0); - int j, k; - - int texnum = Scrap_AllocBlock(image.width, image.height, pos); - - if (texnum == -1) { - // replace goto nonscrap - - image.scrap = false; - - image.texnum = TEXNUM_IMAGES + image.getId(); // image pos in array - GL_Bind(image.texnum); - - if (bits == 8) { - image.has_alpha = - GL_Upload8(pic, width, height, (image.type != it_pic && image.type != it_sky), image.type == it_sky); - } - else { - int[] tmp = new int[pic.length / 4]; - - for (i = 0; i < tmp.length; i++) { - tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0); // & 0x000000FF; - tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8); // & 0x0000FF00; - tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16); // & 0x00FF0000; - tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24); // & 0xFF000000; - } - - image.has_alpha = GL_Upload32(tmp, width, height, (image.type != it_pic && image.type != it_sky)); - } - - image.upload_width = upload_width; // after power of 2 and scales - image.upload_height = upload_height; - image.paletted = uploaded_paletted; - image.sl = 0; - image.sh = 1; - image.tl = 0; - image.th = 1; - - return image; - } - - scrap_dirty = true; - - // copy the texels into the scrap block - k = 0; - for (i = 0; i < image.height; i++) - for (j = 0; j < image.width; j++, k++) - scrap_texels[texnum][(pos.y + i) * BLOCK_WIDTH + pos.x + j] = pic[k]; - - image.texnum = TEXNUM_SCRAPS + texnum; - image.scrap = true; - image.has_alpha = true; - image.sl = (pos.x + 0.01f) / (float) BLOCK_WIDTH; - image.sh = (pos.x + image.width - 0.01f) / (float) BLOCK_WIDTH; - image.tl = (pos.y + 0.01f) / (float) BLOCK_WIDTH; - image.th = (pos.y + image.height - 0.01f) / (float) BLOCK_WIDTH; - - } - else { - // this was label nonscrap - - image.scrap = false; - - image.texnum = TEXNUM_IMAGES + image.getId(); //image pos in array - GL_Bind(image.texnum); - - if (bits == 8) { - image.has_alpha = GL_Upload8(pic, width, height, (image.type != it_pic && image.type != it_sky), image.type == it_sky); - } - else { - int[] tmp = new int[pic.length / 4]; - - for (i = 0; i < tmp.length; i++) { - tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0); // & 0x000000FF; - tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8); // & 0x0000FF00; - tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16); // & 0x00FF0000; - tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24); // & 0xFF000000; - } - - image.has_alpha = GL_Upload32(tmp, width, height, (image.type != it_pic && image.type != it_sky)); - } - image.upload_width = upload_width; // after power of 2 and scales - image.upload_height = upload_height; - image.paletted = uploaded_paletted; - image.sl = 0; - image.sh = 1; - image.tl = 0; - image.th = 1; - } - return image; - } - - /* - ================ - GL_LoadWal - ================ - */ - image_t GL_LoadWal(String name) { - - image_t image = null; - - byte[] raw = FS.LoadFile(name); - if (raw == null) { - VID.Printf(Defines.PRINT_ALL, "GL_FindImage: can't load " + name + '\n'); - return r_notexture; - } - - qfiles.miptex_t mt = new qfiles.miptex_t(raw); - - byte[] pix = new byte[mt.width * mt.height]; - System.arraycopy(raw, mt.offsets[0], pix, 0, pix.length); - - image = GL_LoadPic(name, pix, mt.width, mt.height, it_wall, 8); - - return image; - } - - /* - =============== - GL_FindImage - - Finds or loads the given image - =============== - */ - image_t GL_FindImage(String name, int type) { - image_t image = null; - - // TODO loest das grossschreibungs problem - name = name.toLowerCase(); - // bughack for bad strings (fuck \0) - int index = name.indexOf('\0'); - if (index != -1) - name = name.substring(0, index); - - if (name == null || name.length() < 5) - return null; // Com.Error (ERR_DROP, "GL_FindImage: NULL name"); - // Com.Error (ERR_DROP, "GL_FindImage: bad name: %s", name); - - // look for it - for (int i = 0; i < numgltextures; i++) - { - image = gltextures[i]; - if (name.equals(image.name)) - { - image.registration_sequence = registration_sequence; - return image; - } - } - - // - // load the pic from disk - // - byte[] pic = null; - Dimension dim = new Dimension(); - - if (name.endsWith(".pcx")) { - - pic = LoadPCX(name, null, dim); - if (pic == null) - return null; - image = GL_LoadPic(name, pic, dim.width, dim.height, type, 8); - - } - else if (name.endsWith(".wal")) { - - image = GL_LoadWal(name); - - } - else if (name.endsWith(".tga")) { - - pic = LoadTGA(name, dim); - - if (pic == null) - return null; - - image = GL_LoadPic(name, pic, dim.width, dim.height, type, 32); - - } - else - return null; - - return image; - } - - /* - =============== - R_RegisterSkin - =============== - */ - protected image_t R_RegisterSkin(String name) { - return GL_FindImage(name, it_skin); - } - - /* - ================ - GL_FreeUnusedImages - - Any image that was not touched on this registration sequence - will be freed. - ================ - */ - void GL_FreeUnusedImages() { - - // never free r_notexture or particle texture - r_notexture.registration_sequence = registration_sequence; - r_particletexture.registration_sequence = registration_sequence; - - image_t image = null; - - for (int i = 0; i < numgltextures; i++) { - image = gltextures[i]; - // used this sequence - if (image.registration_sequence == registration_sequence) - continue; - // free image_t slot - if (image.registration_sequence == 0) - continue; - // don't free pics - if (image.type == it_pic) - continue; - - // free it - // TODO jogl bug - gl.glDeleteTextures(1, new int[] {image.texnum}); - image.clear(); - } - } - - /* - =============== - Draw_GetPalette - =============== - */ - protected void Draw_GetPalette() { - int r, g, b; - Dimension dim; - byte[] pic; - byte[][] palette = new byte[1][]; //new byte[768]; - - // get the palette - - pic = LoadPCX("pics/colormap.pcx", palette, dim = new Dimension()); - - if (palette[0] == null || palette[0].length != 768) - Com.Error(Defines.ERR_FATAL, "Couldn't load pics/colormap.pcx"); - - byte[] pal = palette[0]; - - int j = 0; - for (int i = 0; i < 256; i++) { - r = pal[j++] & 0xFF; - g = pal[j++] & 0xFF; - b = pal[j++] & 0xFF; - - d_8to24table[i] = (255 << 24) | (b << 16) | (g << 8) | (r << 0); - } - - d_8to24table[255] &= 0x00FFFFFF; // 255 is transparent - - particle_t.setColorPalette(d_8to24table); - } - - /* - =============== - GL_InitImages - =============== - */ - void GL_InitImages() { - int i, j; - float g = vid_gamma.value; - - registration_sequence = 1; - - // init intensity conversions - intensity = Cvar.Get("intensity", "2", 0); - - if (intensity.value <= 1) - Cvar.Set("intensity", "1"); - - gl_state.inverse_intensity = 1 / intensity.value; - - Draw_GetPalette(); - - if (qglColorTableEXT) { - gl_state.d_16to8table = FS.LoadFile("pics/16to8.dat"); - if (gl_state.d_16to8table == null) - Com.Error(Defines.ERR_FATAL, "Couldn't load pics/16to8.pcx"); - } - - if ((gl_config.renderer & (GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2)) != 0) { - g = 1.0F; - } - - for (i = 0; i < 256; i++) { - - if (g == 1.0f) { - gammatable[i] = (byte) i; - } - else { - - int inf = (int) (255.0f * Math.pow((i + 0.5) / 255.5, g) + 0.5); - if (inf < 0) - inf = 0; - if (inf > 255) - inf = 255; - gammatable[i] = (byte) inf; - } - } - - for (i = 0; i < 256; i++) { - j = (int) (i * intensity.value); - if (j > 255) - j = 255; - intensitytable[i] = (byte) j; - } - } - - /* - =============== - GL_ShutdownImages - =============== - */ - void GL_ShutdownImages() { - image_t image; - - for (int i=0; i < numgltextures ; i++) - { - image = gltextures[i]; - - if (image.registration_sequence == 0) - continue; // free image_t slot - // free it - // TODO jogl bug - gl.glDeleteTextures(1, new int[] {image.texnum}); - image.clear(); - } - } - -} + image_t draw_chars; + + image_t[] gltextures = new image_t[MAX_GLTEXTURES]; + + //Map gltextures = new Hashtable(MAX_GLTEXTURES); // image_t + int numgltextures; + + int base_textureid; // gltextures[i] = base_textureid+i + + byte[] intensitytable = new byte[256]; + + byte[] gammatable = new byte[256]; + + cvar_t intensity; + + // + // qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, + // qboolean is_sky ); + // qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean + // mipmap); + // + + int gl_solid_format = 3; + + int gl_alpha_format = 4; + + int gl_tex_solid_format = 3; + + int gl_tex_alpha_format = 4; + + int gl_filter_min = GL.GL_LINEAR_MIPMAP_NEAREST; + + int gl_filter_max = GL.GL_LINEAR; + + Image() { + // init the texture cache + for (int i = 0; i < gltextures.length; i++) { + gltextures[i] = new image_t(i); + } + numgltextures = 0; + } + + void GL_SetTexturePalette(int[] palette) { + + assert (palette != null && palette.length == 256) : "int palette[256] bug"; + + int i; + byte[] temptable = new byte[768]; + + if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f) { + for (i = 0; i < 256; i++) { + temptable[i * 3 + 0] = (byte) ((palette[i] >> 0) & 0xff); + temptable[i * 3 + 1] = (byte) ((palette[i] >> 8) & 0xff); + temptable[i * 3 + 2] = (byte) ((palette[i] >> 16) & 0xff); + } + + gl.glColorTableEXT(GL.GL_SHARED_TEXTURE_PALETTE_EXT, GL.GL_RGB, + 256, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, temptable); + } + } + + void GL_EnableMultitexture(boolean enable) { + if (!qglSelectTextureSGIS && !qglActiveTextureARB) + return; + + if (enable) { + GL_SelectTexture(GL_TEXTURE1); + gl.glEnable(GL.GL_TEXTURE_2D); + GL_TexEnv(GL.GL_REPLACE); + } else { + GL_SelectTexture(GL_TEXTURE1); + gl.glDisable(GL.GL_TEXTURE_2D); + GL_TexEnv(GL.GL_REPLACE); + } + GL_SelectTexture(GL_TEXTURE0); + GL_TexEnv(GL.GL_REPLACE); + } + + void GL_SelectTexture(int texture /* GLenum */) { + int tmu; + + if (!qglSelectTextureSGIS && !qglActiveTextureARB) + return; + + if (texture == GL_TEXTURE0) { + tmu = 0; + } else { + tmu = 1; + } + + if (tmu == gl_state.currenttmu) { + return; + } + + gl_state.currenttmu = tmu; + + if (qglSelectTextureSGIS) { + // TODO handle this: gl.glSelectTextureSGIS(texture); + gl.glActiveTexture(texture); + } else if (qglActiveTextureARB) { + gl.glActiveTextureARB(texture); + gl.glClientActiveTextureARB(texture); + } + } + + int[] lastmodes = { -1, -1 }; + + void GL_TexEnv(int mode /* GLenum */ + ) { + + if (mode != lastmodes[gl_state.currenttmu]) { + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, mode); + lastmodes[gl_state.currenttmu] = mode; + } + } + + void GL_Bind(int texnum) { + + if ((gl_nobind.value != 0) && (draw_chars != null)) { + // performance evaluation option + texnum = draw_chars.texnum; + } + if (gl_state.currenttextures[gl_state.currenttmu] == texnum) + return; + + gl_state.currenttextures[gl_state.currenttmu] = texnum; + gl.glBindTexture(GL.GL_TEXTURE_2D, texnum); + } + + void GL_MBind(int target /* GLenum */ + , int texnum) { + GL_SelectTexture(target); + if (target == GL_TEXTURE0) { + if (gl_state.currenttextures[0] == texnum) + return; + } else { + if (gl_state.currenttextures[1] == texnum) + return; + } + GL_Bind(texnum); + } + + // glmode_t + static class glmode_t { + String name; + + int minimize, maximize; + + glmode_t(String name, int minimize, int maximze) { + this.name = name; + this.minimize = minimize; + this.maximize = maximze; + } + } + + static final glmode_t modes[] = { + new glmode_t("GL_NEAREST", GL.GL_NEAREST, GL.GL_NEAREST), + new glmode_t("GL_LINEAR", GL.GL_LINEAR, GL.GL_LINEAR), + new glmode_t("GL_NEAREST_MIPMAP_NEAREST", + GL.GL_NEAREST_MIPMAP_NEAREST, GL.GL_NEAREST), + new glmode_t("GL_LINEAR_MIPMAP_NEAREST", + GL.GL_LINEAR_MIPMAP_NEAREST, GL.GL_LINEAR), + new glmode_t("GL_NEAREST_MIPMAP_LINEAR", + GL.GL_NEAREST_MIPMAP_LINEAR, GL.GL_NEAREST), + new glmode_t("GL_LINEAR_MIPMAP_LINEAR", GL.GL_LINEAR_MIPMAP_LINEAR, + GL.GL_LINEAR) }; + + static final int NUM_GL_MODES = modes.length; + + // gltmode_t + static class gltmode_t { + String name; + + int mode; + + gltmode_t(String name, int mode) { + this.name = name; + this.mode = mode; + } + } + + static final gltmode_t[] gl_alpha_modes = { new gltmode_t("default", 4), + new gltmode_t("GL_RGBA", GL.GL_RGBA), + new gltmode_t("GL_RGBA8", GL.GL_RGBA8), + new gltmode_t("GL_RGB5_A1", GL.GL_RGB5_A1), + new gltmode_t("GL_RGBA4", GL.GL_RGBA4), + new gltmode_t("GL_RGBA2", GL.GL_RGBA2), }; + + static final int NUM_GL_ALPHA_MODES = gl_alpha_modes.length; + + static final gltmode_t[] gl_solid_modes = { new gltmode_t("default", 3), + new gltmode_t("GL_RGB", GL.GL_RGB), + new gltmode_t("GL_RGB8", GL.GL_RGB8), + new gltmode_t("GL_RGB5", GL.GL_RGB5), + new gltmode_t("GL_RGB4", GL.GL_RGB4), + new gltmode_t("GL_R3_G3_B2", GL.GL_R3_G3_B2), + // #ifdef GL_RGB2_EXT + new gltmode_t("GL_RGB2", GL.GL_RGB2_EXT) + // #endif + }; + + static final int NUM_GL_SOLID_MODES = gl_solid_modes.length; + + /* + * =============== GL_TextureMode =============== + */ + void GL_TextureMode(String string) { + + int i; + for (i = 0; i < NUM_GL_MODES; i++) { + if (modes[i].name.equalsIgnoreCase(string)) + break; + } + + if (i == NUM_GL_MODES) { + VID + .Printf(Defines.PRINT_ALL, "bad filter name: [" + string + + "]\n"); + return; + } + + gl_filter_min = modes[i].minimize; + gl_filter_max = modes[i].maximize; + + image_t glt; + // change all the existing mipmap texture objects + for (i = 0; i < numgltextures; i++) { + glt = gltextures[i]; + + if (glt.type != it_pic && glt.type != it_sky) { + GL_Bind(glt.texnum); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + gl_filter_min); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + gl_filter_max); + } + } + } + + /* + * =============== GL_TextureAlphaMode =============== + */ + void GL_TextureAlphaMode(String string) { + + int i; + for (i = 0; i < NUM_GL_ALPHA_MODES; i++) { + if (gl_alpha_modes[i].name.equalsIgnoreCase(string)) + break; + } + + if (i == NUM_GL_ALPHA_MODES) { + VID.Printf(Defines.PRINT_ALL, "bad alpha texture mode name: [" + + string + "]\n"); + return; + } + + gl_tex_alpha_format = gl_alpha_modes[i].mode; + } + + /* + * =============== GL_TextureSolidMode =============== + */ + void GL_TextureSolidMode(String string) { + int i; + for (i = 0; i < NUM_GL_SOLID_MODES; i++) { + if (gl_solid_modes[i].name.equalsIgnoreCase(string)) + break; + } + + if (i == NUM_GL_SOLID_MODES) { + VID.Printf(Defines.PRINT_ALL, "bad solid texture mode name: [" + + string + "]\n"); + return; + } + + gl_tex_solid_format = gl_solid_modes[i].mode; + } + + /* + * =============== GL_ImageList_f =============== + */ + void GL_ImageList_f() { + + image_t image; + int texels; + final String[] palstrings = { "RGB", "PAL" }; + + VID.Printf(Defines.PRINT_ALL, "------------------\n"); + texels = 0; + + for (int i = 0; i < numgltextures; i++) { + image = gltextures[i]; + if (image.texnum <= 0) + continue; + + texels += image.upload_width * image.upload_height; + switch (image.type) { + case it_skin: + VID.Printf(Defines.PRINT_ALL, "M"); + break; + case it_sprite: + VID.Printf(Defines.PRINT_ALL, "S"); + break; + case it_wall: + VID.Printf(Defines.PRINT_ALL, "W"); + break; + case it_pic: + VID.Printf(Defines.PRINT_ALL, "P"); + break; + default: + VID.Printf(Defines.PRINT_ALL, " "); + break; + } + + VID.Printf(Defines.PRINT_ALL, " %3i %3i %s: %s\n", new Vargs(4) + .add(image.upload_width).add(image.upload_height).add( + palstrings[(image.paletted) ? 1 : 0]).add( + image.name)); + } + VID.Printf(Defines.PRINT_ALL, + "Total texel count (not counting mipmaps): " + texels + '\n'); + } + + /* + * ============================================================================= + * + * scrap allocation + * + * Allocate all the little status bar objects into a single texture to + * crutch up inefficient hardware / drivers + * + * ============================================================================= + */ + + static final int MAX_SCRAPS = 1; + + static final int BLOCK_WIDTH = 256; + + static final int BLOCK_HEIGHT = 256; + + int[][] scrap_allocated = new int[MAX_SCRAPS][BLOCK_WIDTH]; + + byte[][] scrap_texels = new byte[MAX_SCRAPS][BLOCK_WIDTH * BLOCK_HEIGHT]; + + boolean scrap_dirty; + + static class pos_t { + int x, y; + + pos_t(int x, int y) { + this.x = x; + this.y = y; + } + } + + // returns a texture number and the position inside it + int Scrap_AllocBlock(int w, int h, pos_t pos) { + int i, j; + int best, best2; + int texnum; + + for (texnum = 0; texnum < MAX_SCRAPS; texnum++) { + best = BLOCK_HEIGHT; + + for (i = 0; i < BLOCK_WIDTH - w; i++) { + best2 = 0; + + for (j = 0; j < w; j++) { + if (scrap_allocated[texnum][i + j] >= best) + break; + if (scrap_allocated[texnum][i + j] > best2) + best2 = scrap_allocated[texnum][i + j]; + } + if (j == w) { // this is a valid spot + pos.x = i; + pos.y = best = best2; + } + } + + if (best + h > BLOCK_HEIGHT) + continue; + + for (i = 0; i < w; i++) + scrap_allocated[texnum][pos.x + i] = best + h; + + return texnum; + } + + return -1; + // Sys_Error ("Scrap_AllocBlock: full"); + } + + int scrap_uploads = 0; + + void Scrap_Upload() { + scrap_uploads++; + GL_Bind(TEXNUM_SCRAPS); + GL_Upload8(scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, false); + scrap_dirty = false; + } + + /* + * ================================================================= + * + * PCX LOADING + * + * ================================================================= + */ + + /* + * ============== LoadPCX ============== + */ + byte[] LoadPCX(String filename, byte[][] palette, Dimension dim) { + qfiles.pcx_t pcx; + + // + // load the file + // + byte[] raw = FS.LoadFile(filename); + + if (raw == null) { + VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename + + '\n'); + return null; + } + + // + // parse the PCX file + // + pcx = new qfiles.pcx_t(raw); + + if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 + || pcx.bits_per_pixel != 8 || pcx.xmax >= 640 + || pcx.ymax >= 480) { + + VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n'); + return null; + } + + int width = pcx.xmax - pcx.xmin + 1; + int height = pcx.ymax - pcx.ymin + 1; + + byte[] pix = new byte[width * height]; + + if (palette != null) { + palette[0] = new byte[768]; + System.arraycopy(raw, raw.length - 768, palette[0], 0, 768); + } + + if (dim != null) { + dim.width = width; + dim.height = height; + } + + // + // decode pcx + // + int count = 0; + byte dataByte = 0; + int runLength = 0; + int x, y; + + for (y = 0; y < height; y++) { + for (x = 0; x < width;) { + + dataByte = pcx.data.get(); + + if ((dataByte & 0xC0) == 0xC0) { + runLength = dataByte & 0x3F; + dataByte = pcx.data.get(); + // write runLength pixel + while (runLength-- > 0) { + pix[count++] = dataByte; + x++; + } + } else { + // write one pixel + pix[count++] = dataByte; + x++; + } + } + } + return pix; + } + + // /* + // ========================================================= + // + // TARGA LOADING + // + // ========================================================= + // */ + /* + * ============= LoadTGA ============= + */ + byte[] LoadTGA(String name, Dimension dim) { + int columns, rows, numPixels; + int pixbuf; // index into pic + int row, column; + byte[] raw; + ByteBuffer buf_p; + int length; + qfiles.tga_t targa_header; + byte[] pic = null; + + // + // load the file + // + raw = FS.LoadFile(name); + + if (raw == null) { + VID.Printf(Defines.PRINT_DEVELOPER, "Bad tga file " + name + '\n'); + return null; + } + + targa_header = new qfiles.tga_t(raw); + + if (targa_header.image_type != 2 && targa_header.image_type != 10) + Com.Error(Defines.ERR_DROP, + "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); + + if (targa_header.colormap_type != 0 + || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24)) + Com + .Error(Defines.ERR_DROP, + "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (dim != null) { + dim.width = columns; + dim.height = rows; + } + + pic = new byte[numPixels * 4]; // targa_rgba; + + if (targa_header.id_length != 0) + targa_header.data.position(targa_header.id_length); // skip TARGA + // image comment + + buf_p = targa_header.data; + + byte red, green, blue, alphabyte; + red = green = blue = alphabyte = 0; + int packetHeader, packetSize, j; + + if (targa_header.image_type == 2) { // Uncompressed, RGB images + for (row = rows - 1; row >= 0; row--) { + + pixbuf = row * columns * 4; + + for (column = 0; column < columns; column++) { + switch (targa_header.pixel_size) { + case 24: + + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + pic[pixbuf++] = red; + pic[pixbuf++] = green; + pic[pixbuf++] = blue; + pic[pixbuf++] = (byte) 255; + break; + case 32: + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + alphabyte = buf_p.get(); + pic[pixbuf++] = red; + pic[pixbuf++] = green; + pic[pixbuf++] = blue; + pic[pixbuf++] = alphabyte; + break; + } + } + } + } else if (targa_header.image_type == 10) { // Runlength encoded RGB + // images + for (row = rows - 1; row >= 0; row--) { + + pixbuf = row * columns * 4; + try { + + for (column = 0; column < columns;) { + + packetHeader = buf_p.get() & 0xFF; + packetSize = 1 + (packetHeader & 0x7f); + + if ((packetHeader & 0x80) != 0) { // run-length packet + switch (targa_header.pixel_size) { + case 24: + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + alphabyte = (byte) 255; + break; + case 32: + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + alphabyte = buf_p.get(); + break; + } + + for (j = 0; j < packetSize; j++) { + pic[pixbuf++] = red; + pic[pixbuf++] = green; + pic[pixbuf++] = blue; + pic[pixbuf++] = alphabyte; + column++; + if (column == columns) { // run spans across + // rows + column = 0; + if (row > 0) + row--; + else + // goto label breakOut; + throw new longjmpException(); + + pixbuf = row * columns * 4; + } + } + } else { // non run-length packet + for (j = 0; j < packetSize; j++) { + switch (targa_header.pixel_size) { + case 24: + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + pic[pixbuf++] = red; + pic[pixbuf++] = green; + pic[pixbuf++] = blue; + pic[pixbuf++] = (byte) 255; + break; + case 32: + blue = buf_p.get(); + green = buf_p.get(); + red = buf_p.get(); + alphabyte = buf_p.get(); + pic[pixbuf++] = red; + pic[pixbuf++] = green; + pic[pixbuf++] = blue; + pic[pixbuf++] = alphabyte; + break; + } + column++; + if (column == columns) { // pixel packet run + // spans across rows + column = 0; + if (row > 0) + row--; + else + // goto label breakOut; + throw new longjmpException(); + + pixbuf = row * columns * 4; + } + } + } + } + } catch (longjmpException e) { + // label breakOut: + } + } + } + return pic; + } + + /* + * ==================================================================== + * + * IMAGE FLOOD FILLING + * + * ==================================================================== + */ + + /* + * ================= Mod_FloodFillSkin + * + * Fill background pixels so mipmapping doesn't have haloes + * ================= + */ + + static class floodfill_t { + short x, y; + } + + // must be a power of 2 + static final int FLOODFILL_FIFO_SIZE = 0x1000; + + static final int FLOODFILL_FIFO_MASK = FLOODFILL_FIFO_SIZE - 1; + + // + // #define FLOODFILL_STEP( off, dx, dy ) \ + // { \ + // if (pos[off] == fillcolor) \ + // { \ + // pos[off] = 255; \ + // fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ + // inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ + // } \ + // else if (pos[off] != 255) fdc = pos[off]; \ + // } + + // void FLOODFILL_STEP( int off, int dx, int dy ) + // { + // if (pos[off] == fillcolor) + // { + // pos[off] = 255; + // fifo[inpt].x = x + dx; fifo[inpt].y = y + dy; + // inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + // } + // else if (pos[off] != 255) fdc = pos[off]; + // } + static floodfill_t[] fifo = new floodfill_t[FLOODFILL_FIFO_SIZE]; + static { + for (int j = 0; j < fifo.length; j++) { + fifo[j] = new floodfill_t(); + } + } + + // TODO check this: R_FloodFillSkin( byte[] skin, int skinwidth, int + // skinheight) + void R_FloodFillSkin(byte[] skin, int skinwidth, int skinheight) { + // byte fillcolor = *skin; // assume this is the pixel to fill + int fillcolor = skin[0] & 0xff; + int inpt = 0, outpt = 0; + int filledcolor = -1; + int i; + + if (filledcolor == -1) { + filledcolor = 0; + // attempt to find opaque black + for (i = 0; i < 256; ++i) + // TODO check this + if (d_8to24table[i] == 0xFF000000) { // alpha 1.0 + //if (d_8to24table[i] == (255 << 0)) // alpha 1.0 + filledcolor = i; + break; + } + } + + // can't fill to filled color or to transparent color (used as visited + // marker) + if ((fillcolor == filledcolor) || (fillcolor == 255)) { + return; + } + + fifo[inpt].x = 0; + fifo[inpt].y = 0; + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + + while (outpt != inpt) { + int x = fifo[outpt].x; + int y = fifo[outpt].y; + int fdc = filledcolor; + // byte *pos = &skin[x + skinwidth * y]; + int pos = x + skinwidth * y; + // + outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; + + int off, dx, dy; + + if (x > 0) { + // FLOODFILL_STEP( -1, -1, 0 ); + off = -1; + dx = -1; + dy = 0; + if (skin[pos + off] == (byte) fillcolor) { + skin[pos + off] = (byte) 255; + fifo[inpt].x = (short) (x + dx); + fifo[inpt].y = (short) (y + dy); + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + } else if (skin[pos + off] != (byte) 255) + fdc = skin[pos + off] & 0xff; + } + + if (x < skinwidth - 1) { + // FLOODFILL_STEP( 1, 1, 0 ); + off = 1; + dx = 1; + dy = 0; + if (skin[pos + off] == (byte) fillcolor) { + skin[pos + off] = (byte) 255; + fifo[inpt].x = (short) (x + dx); + fifo[inpt].y = (short) (y + dy); + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + } else if (skin[pos + off] != (byte) 255) + fdc = skin[pos + off] & 0xff; + } + + if (y > 0) { + // FLOODFILL_STEP( -skinwidth, 0, -1 ); + off = -skinwidth; + dx = 0; + dy = -1; + if (skin[pos + off] == (byte) fillcolor) { + skin[pos + off] = (byte) 255; + fifo[inpt].x = (short) (x + dx); + fifo[inpt].y = (short) (y + dy); + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + } else if (skin[pos + off] != (byte) 255) + fdc = skin[pos + off] & 0xff; + } + + if (y < skinheight - 1) { + // FLOODFILL_STEP( skinwidth, 0, 1 ); + off = skinwidth; + dx = 0; + dy = 1; + if (skin[pos + off] == (byte) fillcolor) { + skin[pos + off] = (byte) 255; + fifo[inpt].x = (short) (x + dx); + fifo[inpt].y = (short) (y + dy); + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + } else if (skin[pos + off] != (byte) 255) + fdc = skin[pos + off] & 0xff; + + } + + skin[x + skinwidth * y] = (byte) fdc; + } + } + + // ======================================================= + + /* + * ================ GL_ResampleTexture ================ + */ + // cwei :-) + void GL_ResampleTexture(int[] in, int inwidth, int inheight, int[] out, + int outwidth, int outheight) { + // int i, j; + // unsigned *inrow, *inrow2; + // int frac, fracstep; + // int[] p1 = new int[1024]; + // int[] p2 = new int[1024]; + // + + // *** this source do the same *** + BufferedImage image = new BufferedImage(inwidth, inheight, + BufferedImage.TYPE_INT_ARGB); + + image.setRGB(0, 0, inwidth, inheight, in, 0, inwidth); + + AffineTransformOp op = new AffineTransformOp(AffineTransform + .getScaleInstance(outwidth * 1.0 / inwidth, outheight * 1.0 + / inheight), AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + BufferedImage tmp = op.filter(image, null); + + tmp.getRGB(0, 0, outwidth, outheight, out, 0, outwidth); + + // *** end *** + + // byte *pix1, *pix2, *pix3, *pix4; + // + // fracstep = inwidth*0x10000/outwidth; + // + // frac = fracstep>>2; + // for (i=0 ; i>16); + // frac += fracstep; + // } + // frac = 3*(fracstep>>2); + // for (i=0 ; i>16); + // frac += fracstep; + // } + // + // for (i=0 ; i> 1; + // for (j=0 ; j>2; + // ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; + // ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; + // ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; + // } + // } + } + + /* + * ================ GL_LightScaleTexture + * + * Scale up the pixel values in a texture to increase the lighting range + * ================ + */ + void GL_LightScaleTexture(int[] in, int inwidth, int inheight, + boolean only_gamma) { + if (only_gamma) { + int i, c; + int r, g, b, color; + + c = inwidth * inheight; + for (i = 0; i < c; i++) { + color = in[i]; + r = (color >> 0) & 0xFF; + g = (color >> 8) & 0xFF; + b = (color >> 16) & 0xFF; + + r = gammatable[r] & 0xFF; + g = gammatable[g] & 0xFF; + b = gammatable[b] & 0xFF; + + in[i] = (r << 0) | (g << 8) | (b << 16) | (color & 0xFF000000); + } + } else { + int i, c; + int r, g, b, color; + + c = inwidth * inheight; + for (i = 0; i < c; i++) { + color = in[i]; + r = (color >> 0) & 0xFF; + g = (color >> 8) & 0xFF; + b = (color >> 16) & 0xFF; + + r = gammatable[intensitytable[r] & 0xFF] & 0xFF; + g = gammatable[intensitytable[g] & 0xFF] & 0xFF; + b = gammatable[intensitytable[b] & 0xFF] & 0xFF; + + in[i] = (r << 0) | (g << 8) | (b << 16) | (color & 0xFF000000); + } + + } + } + + /* + * ================ GL_MipMap + * + * Operates in place, quartering the size of the texture ================ + */ + void GL_MipMap(int[] in, int width, int height) { + int i, j; + int[] out; + + out = in; + + int inIndex = 0; + int outIndex = 0; + + int r, g, b, a; + int p1, p2, p3, p4; + + for (i = 0; i < height; i += 2, inIndex += width) { + for (j = 0; j < width; j += 2, outIndex += 1, inIndex += 2) { + + p1 = in[inIndex + 0]; + p2 = in[inIndex + 1]; + p3 = in[inIndex + width + 0]; + p4 = in[inIndex + width + 1]; + + r = (((p1 >> 0) & 0xFF) + ((p2 >> 0) & 0xFF) + + ((p3 >> 0) & 0xFF) + ((p4 >> 0) & 0xFF)) >> 2; + g = (((p1 >> 8) & 0xFF) + ((p2 >> 8) & 0xFF) + + ((p3 >> 8) & 0xFF) + ((p4 >> 8) & 0xFF)) >> 2; + b = (((p1 >> 16) & 0xFF) + ((p2 >> 16) & 0xFF) + + ((p3 >> 16) & 0xFF) + ((p4 >> 16) & 0xFF)) >> 2; + a = (((p1 >> 24) & 0xFF) + ((p2 >> 24) & 0xFF) + + ((p3 >> 24) & 0xFF) + ((p4 >> 24) & 0xFF)) >> 2; + + out[outIndex] = (r << 0) | (g << 8) | (b << 16) | (a << 24); + } + } + } + + /* + * =============== GL_Upload32 + * + * Returns has_alpha =============== + */ + void GL_BuildPalettedTexture(byte[] paletted_texture, int[] scaled, + int scaled_width, int scaled_height) { + + int r, g, b, c; + int size = scaled_width * scaled_height; + + for (int i = 0; i < size; i++) { + + r = (scaled[i] >> 3) & 31; + g = (scaled[i] >> 10) & 63; + b = (scaled[i] >> 19) & 31; + + c = r | (g << 5) | (b << 11); + + paletted_texture[i] = gl_state.d_16to8table[c]; + } + } + + int upload_width, upload_height; + + boolean uploaded_paletted; + + /* + * =============== GL_Upload32 + * + * Returns has_alpha =============== + */ + int[] scaled = new int[256 * 256]; + + byte[] paletted_texture = new byte[256 * 256]; + + IntBuffer tex = Lib.newIntBuffer(512 * 256, ByteOrder.LITTLE_ENDIAN); + + boolean GL_Upload32(int[] data, int width, int height, boolean mipmap) { + int samples; + int scaled_width, scaled_height; + int i, c; + int comp; + + Arrays.fill(scaled, 0); + Arrays.fill(paletted_texture, (byte) 0); + + uploaded_paletted = false; + + for (scaled_width = 1; scaled_width < width; scaled_width <<= 1) + ; + if (gl_round_down.value > 0.0f && scaled_width > width && mipmap) + scaled_width >>= 1; + for (scaled_height = 1; scaled_height < height; scaled_height <<= 1) + ; + if (gl_round_down.value > 0.0f && scaled_height > height && mipmap) + scaled_height >>= 1; + + // let people sample down the world textures for speed + if (mipmap) { + scaled_width >>= (int) gl_picmip.value; + scaled_height >>= (int) gl_picmip.value; + } + + // don't ever bother with >256 textures + if (scaled_width > 256) + scaled_width = 256; + if (scaled_height > 256) + scaled_height = 256; + + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + upload_width = scaled_width; + upload_height = scaled_height; + + if (scaled_width * scaled_height > 256 * 256) + Com.Error(Defines.ERR_DROP, "GL_Upload32: too big"); + + // scan the texture for any non-255 alpha + c = width * height; + samples = gl_solid_format; + + for (i = 0; i < c; i++) { + if ((data[i] & 0xff000000) != 0xff000000) { + samples = gl_alpha_format; + break; + } + } + + if (samples == gl_solid_format) + comp = gl_tex_solid_format; + else if (samples == gl_alpha_format) + comp = gl_tex_alpha_format; + else { + VID.Printf(Defines.PRINT_ALL, + "Unknown number of texture components " + samples + '\n'); + comp = samples; + } + + // simulates a goto + try { + if (scaled_width == width && scaled_height == height) { + if (!mipmap) { + if (qglColorTableEXT + && gl_ext_palettedtexture.value != 0.0f + && samples == gl_solid_format) { + uploaded_paletted = true; + GL_BuildPalettedTexture(paletted_texture, data, + scaled_width, scaled_height); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, + GL_COLOR_INDEX8_EXT, scaled_width, + scaled_height, 0, GL.GL_COLOR_INDEX, + GL.GL_UNSIGNED_BYTE, paletted_texture); + } else { + tex.rewind(); + tex.put(data); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, comp, + scaled_width, scaled_height, 0, GL.GL_RGBA, + GL.GL_UNSIGNED_BYTE, tex); + } + //goto done; + throw new longjmpException(); + } + //memcpy (scaled, data, width*height*4); were bytes + System.arraycopy(data, 0, scaled, 0, width * height); + + } else + GL_ResampleTexture(data, width, height, scaled, scaled_width, + scaled_height); + + GL_LightScaleTexture(scaled, scaled_width, scaled_height, !mipmap); + + if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f + && (samples == gl_solid_format)) { + uploaded_paletted = true; + GL_BuildPalettedTexture(paletted_texture, scaled, scaled_width, + scaled_height); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, + scaled_width, scaled_height, 0, GL.GL_COLOR_INDEX, + GL.GL_UNSIGNED_BYTE, paletted_texture); + } else { + tex.rewind(); + tex.put(scaled); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, comp, scaled_width, + scaled_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, tex); + } + + if (mipmap) { + int miplevel; + miplevel = 0; + while (scaled_width > 1 || scaled_height > 1) { + GL_MipMap(scaled, scaled_width, scaled_height); + scaled_width >>= 1; + scaled_height >>= 1; + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + miplevel++; + if (qglColorTableEXT + && gl_ext_palettedtexture.value != 0.0f + && samples == gl_solid_format) { + uploaded_paletted = true; + GL_BuildPalettedTexture(paletted_texture, scaled, + scaled_width, scaled_height); + gl.glTexImage2D(GL.GL_TEXTURE_2D, miplevel, + GL_COLOR_INDEX8_EXT, scaled_width, + scaled_height, 0, GL.GL_COLOR_INDEX, + GL.GL_UNSIGNED_BYTE, paletted_texture); + } else { + tex.rewind(); + tex.put(scaled); + gl.glTexImage2D(GL.GL_TEXTURE_2D, miplevel, comp, + scaled_width, scaled_height, 0, GL.GL_RGBA, + GL.GL_UNSIGNED_BYTE, tex); + } + } + } + // label done: + } catch (longjmpException e) { + ; // replaces label done + } + + if (mipmap) { + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + gl_filter_min); + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + gl_filter_max); + } else { + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + gl_filter_max); + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + gl_filter_max); + } + + return (samples == gl_alpha_format); + } + + /* + * =============== GL_Upload8 + * + * Returns has_alpha =============== + */ + + int[] trans = new int[512 * 256]; + + boolean GL_Upload8(byte[] data, int width, int height, boolean mipmap, + boolean is_sky) { + + Arrays.fill(trans, 0); + + int s = width * height; + + if (s > trans.length) + Com.Error(Defines.ERR_DROP, "GL_Upload8: too large"); + + if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && is_sky) { + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, width, + height, 0, GL.GL_COLOR_INDEX, GL.GL_UNSIGNED_BYTE, data); + + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + gl_filter_max); + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + gl_filter_max); + + // TODO check this + return false; + } else { + int p; + int rgb; + for (int i = 0; i < s; i++) { + p = data[i] & 0xff; + trans[i] = d_8to24table[p]; + + if (p == 255) { // transparent, so scan around for another color + // to avoid alpha fringes + // FIXME: do a full flood fill so mips work... + if (i > width && (data[i - width] & 0xff) != 255) + p = data[i - width] & 0xff; + else if (i < s - width && (data[i + width] & 0xff) != 255) + p = data[i + width] & 0xff; + else if (i > 0 && (data[i - 1] & 0xff) != 255) + p = data[i - 1] & 0xff; + else if (i < s - 1 && (data[i + 1] & 0xff) != 255) + p = data[i + 1] & 0xff; + else + p = 0; + // copy rgb components + + // ((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0]; + // ((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1]; + // ((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2]; + + trans[i] = d_8to24table[p] & 0x00FFFFFF; // only rgb + } + } + + return GL_Upload32(trans, width, height, mipmap); + } + } + + /* + * ================ GL_LoadPic + * + * This is also used as an entry point for the generated r_notexture + * ================ + */ + image_t GL_LoadPic(String name, byte[] pic, int width, int height, + int type, int bits) { + image_t image; + int i; + + // find a free image_t + for (i = 0; i < numgltextures; i++) { + image = gltextures[i]; + if (image.texnum == 0) + break; + } + + if (i == numgltextures) { + if (numgltextures == MAX_GLTEXTURES) + Com.Error(Defines.ERR_DROP, "MAX_GLTEXTURES"); + + numgltextures++; + } + image = gltextures[i]; + + if (name.length() > Defines.MAX_QPATH) + Com.Error(Defines.ERR_DROP, "Draw_LoadPic: \"" + name + + "\" is too long"); + + image.name = name; + image.registration_sequence = registration_sequence; + + image.width = width; + image.height = height; + image.type = type; + + if (type == it_skin && bits == 8) + R_FloodFillSkin(pic, width, height); + + // load little pics into the scrap + if (image.type == it_pic && bits == 8 && image.width < 64 + && image.height < 64) { + pos_t pos = new pos_t(0, 0); + int j, k; + + int texnum = Scrap_AllocBlock(image.width, image.height, pos); + + if (texnum == -1) { + // replace goto nonscrap + + image.scrap = false; + + image.texnum = TEXNUM_IMAGES + image.getId(); // image pos in + // array + GL_Bind(image.texnum); + + if (bits == 8) { + image.has_alpha = GL_Upload8(pic, width, height, + (image.type != it_pic && image.type != it_sky), + image.type == it_sky); + } else { + int[] tmp = new int[pic.length / 4]; + + for (i = 0; i < tmp.length; i++) { + tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0); // & + // 0x000000FF; + tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8); // & + // 0x0000FF00; + tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16); // & + // 0x00FF0000; + tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24); // & + // 0xFF000000; + } + + image.has_alpha = GL_Upload32(tmp, width, height, + (image.type != it_pic && image.type != it_sky)); + } + + image.upload_width = upload_width; // after power of 2 and + // scales + image.upload_height = upload_height; + image.paletted = uploaded_paletted; + image.sl = 0; + image.sh = 1; + image.tl = 0; + image.th = 1; + + return image; + } + + scrap_dirty = true; + + // copy the texels into the scrap block + k = 0; + for (i = 0; i < image.height; i++) + for (j = 0; j < image.width; j++, k++) + scrap_texels[texnum][(pos.y + i) * BLOCK_WIDTH + pos.x + j] = pic[k]; + + image.texnum = TEXNUM_SCRAPS + texnum; + image.scrap = true; + image.has_alpha = true; + image.sl = (pos.x + 0.01f) / (float) BLOCK_WIDTH; + image.sh = (pos.x + image.width - 0.01f) / (float) BLOCK_WIDTH; + image.tl = (pos.y + 0.01f) / (float) BLOCK_WIDTH; + image.th = (pos.y + image.height - 0.01f) / (float) BLOCK_WIDTH; + + } else { + // this was label nonscrap + + image.scrap = false; + + image.texnum = TEXNUM_IMAGES + image.getId(); //image pos in array + GL_Bind(image.texnum); + + if (bits == 8) { + image.has_alpha = GL_Upload8(pic, width, height, + (image.type != it_pic && image.type != it_sky), + image.type == it_sky); + } else { + int[] tmp = new int[pic.length / 4]; + + for (i = 0; i < tmp.length; i++) { + tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0); // & 0x000000FF; + tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8); // & 0x0000FF00; + tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16); // & 0x00FF0000; + tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24); // & 0xFF000000; + } + + image.has_alpha = GL_Upload32(tmp, width, height, + (image.type != it_pic && image.type != it_sky)); + } + image.upload_width = upload_width; // after power of 2 and scales + image.upload_height = upload_height; + image.paletted = uploaded_paletted; + image.sl = 0; + image.sh = 1; + image.tl = 0; + image.th = 1; + } + return image; + } + + /* + * ================ GL_LoadWal ================ + */ + image_t GL_LoadWal(String name) { + + image_t image = null; + + byte[] raw = FS.LoadFile(name); + if (raw == null) { + VID.Printf(Defines.PRINT_ALL, "GL_FindImage: can't load " + name + + '\n'); + return r_notexture; + } + + qfiles.miptex_t mt = new qfiles.miptex_t(raw); + + byte[] pix = new byte[mt.width * mt.height]; + System.arraycopy(raw, mt.offsets[0], pix, 0, pix.length); + + image = GL_LoadPic(name, pix, mt.width, mt.height, it_wall, 8); + + return image; + } + + /* + * =============== GL_FindImage + * + * Finds or loads the given image =============== + */ + image_t GL_FindImage(String name, int type) { + image_t image = null; + + // TODO loest das grossschreibungs problem + name = name.toLowerCase(); + // bughack for bad strings (fuck \0) + int index = name.indexOf('\0'); + if (index != -1) + name = name.substring(0, index); + + if (name == null || name.length() < 5) + return null; // Com.Error (ERR_DROP, "GL_FindImage: NULL name"); + // Com.Error (ERR_DROP, "GL_FindImage: bad name: %s", name); + + // look for it + for (int i = 0; i < numgltextures; i++) { + image = gltextures[i]; + if (name.equals(image.name)) { + image.registration_sequence = registration_sequence; + return image; + } + } + + // + // load the pic from disk + // + byte[] pic = null; + Dimension dim = new Dimension(); + + if (name.endsWith(".pcx")) { + + pic = LoadPCX(name, null, dim); + if (pic == null) + return null; + image = GL_LoadPic(name, pic, dim.width, dim.height, type, 8); + + } else if (name.endsWith(".wal")) { + + image = GL_LoadWal(name); + + } else if (name.endsWith(".tga")) { + + pic = LoadTGA(name, dim); + + if (pic == null) + return null; + + image = GL_LoadPic(name, pic, dim.width, dim.height, type, 32); + + } else + return null; + + return image; + } + + /* + * =============== R_RegisterSkin =============== + */ + protected image_t R_RegisterSkin(String name) { + return GL_FindImage(name, it_skin); + } + + /* + * ================ GL_FreeUnusedImages + * + * Any image that was not touched on this registration sequence will be + * freed. ================ + */ + void GL_FreeUnusedImages() { + + // never free r_notexture or particle texture + r_notexture.registration_sequence = registration_sequence; + r_particletexture.registration_sequence = registration_sequence; + + image_t image = null; + + for (int i = 0; i < numgltextures; i++) { + image = gltextures[i]; + // used this sequence + if (image.registration_sequence == registration_sequence) + continue; + // free image_t slot + if (image.registration_sequence == 0) + continue; + // don't free pics + if (image.type == it_pic) + continue; + + // free it + // TODO jogl bug + gl.glDeleteTextures(1, new int[] { image.texnum }); + image.clear(); + } + } + + /* + * =============== Draw_GetPalette =============== + */ + protected void Draw_GetPalette() { + int r, g, b; + Dimension dim; + byte[] pic; + byte[][] palette = new byte[1][]; //new byte[768]; + + // get the palette + + pic = LoadPCX("pics/colormap.pcx", palette, dim = new Dimension()); + + if (palette[0] == null || palette[0].length != 768) + Com.Error(Defines.ERR_FATAL, "Couldn't load pics/colormap.pcx"); + + byte[] pal = palette[0]; + + int j = 0; + for (int i = 0; i < 256; i++) { + r = pal[j++] & 0xFF; + g = pal[j++] & 0xFF; + b = pal[j++] & 0xFF; + + d_8to24table[i] = (255 << 24) | (b << 16) | (g << 8) | (r << 0); + } + + d_8to24table[255] &= 0x00FFFFFF; // 255 is transparent + + particle_t.setColorPalette(d_8to24table); + } + + /* + * =============== GL_InitImages =============== + */ + void GL_InitImages() { + int i, j; + float g = vid_gamma.value; + + registration_sequence = 1; + + // init intensity conversions + intensity = Cvar.Get("intensity", "2", 0); + + if (intensity.value <= 1) + Cvar.Set("intensity", "1"); + + gl_state.inverse_intensity = 1 / intensity.value; + + Draw_GetPalette(); + + if (qglColorTableEXT) { + gl_state.d_16to8table = FS.LoadFile("pics/16to8.dat"); + if (gl_state.d_16to8table == null) + Com.Error(Defines.ERR_FATAL, "Couldn't load pics/16to8.pcx"); + } + + if ((gl_config.renderer & (GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2)) != 0) { + g = 1.0F; + } + + for (i = 0; i < 256; i++) { + + if (g == 1.0f) { + gammatable[i] = (byte) i; + } else { + + int inf = (int) (255.0f * Math.pow((i + 0.5) / 255.5, g) + 0.5); + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + gammatable[i] = (byte) inf; + } + } + + for (i = 0; i < 256; i++) { + j = (int) (i * intensity.value); + if (j > 255) + j = 255; + intensitytable[i] = (byte) j; + } + } + + /* + * =============== GL_ShutdownImages =============== + */ + void GL_ShutdownImages() { + image_t image; + + for (int i = 0; i < numgltextures; i++) { + image = gltextures[i]; + + if (image.registration_sequence == 0) + continue; // free image_t slot + // free it + // TODO jogl bug + gl.glDeleteTextures(1, new int[] { image.texnum }); + image.clear(); + } + } + +} \ No newline at end of file diff --git a/src/jake2/render/jogl/Light.java b/src/jake2/render/jogl/Light.java index de23629..f6b8e10 100644 --- a/src/jake2/render/jogl/Light.java +++ b/src/jake2/render/jogl/Light.java @@ -2,38 +2,39 @@ * Light.java * Copyright (C) 2003 * - * $Id: Light.java,v 1.6 2004-07-16 10:11:35 cawe Exp $ + * $Id: Light.java,v 1.7 2004-09-22 19:22:16 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.render.jogl; import jake2.Defines; import jake2.Globals; import jake2.client.dlight_t; import jake2.client.lightstyle_t; -import jake2.game.GameBase; import jake2.game.cplane_t; import jake2.qcommon.Com; import jake2.qcommon.longjmpException; -import jake2.render.*; +import jake2.render.mnode_t; +import jake2.render.msurface_t; +import jake2.render.mtexinfo_t; import jake2.util.Math3D; import java.nio.ByteBuffer; @@ -44,730 +45,687 @@ import net.java.games.jogl.GL; /** * Light - * + * * @author cwei */ public abstract class Light extends Warp { - // r_light.c - - int r_dlightframecount; - - static final int DLIGHT_CUTOFF = 64; - - /* - ============================================================================= - - DYNAMIC LIGHTS BLEND RENDERING - - ============================================================================= - */ - - void R_RenderDlight (dlight_t light) - { - int i, j; - float a; - float[] v = {0, 0, 0}; - float rad; - - rad = light.intensity * 0.35f; - - Math3D.VectorSubtract (light.origin, r_origin, v); - - gl.glBegin (GL.GL_TRIANGLE_FAN); - gl.glColor3f (light.color[0]*0.2f, light.color[1]*0.2f, light.color[2]*0.2f); - for (i=0 ; i<3 ; i++) - v[i] = light.origin[i] - vpn[i]*rad; - gl.glVertex3f(v[0], v[1], v[2]); - gl.glColor3f (0,0,0); - for (i=16 ; i>=0 ; i--) - { - a = (float)(i/16.0f * Math.PI*2); - for (j=0 ; j<3 ; j++) - v[j] = (float)(light.origin[j] + vright[j]*Math.cos(a)*rad - + vup[j]*Math.sin(a)*rad); - gl.glVertex3f(v[0], v[1], v[2]); - } - gl.glEnd (); - } - - /* - ============= - R_RenderDlights - ============= - */ - void R_RenderDlights() - { - int i; - dlight_t l; - - if (gl_flashblend.value == 0) - return; - - r_dlightframecount = r_framecount + 1; // because the count hasn't - // advanced yet for this frame - gl.glDepthMask(false); - gl.glDisable(GL.GL_TEXTURE_2D); - gl.glShadeModel (GL.GL_SMOOTH); - gl.glEnable (GL.GL_BLEND); - gl.glBlendFunc (GL.GL_ONE, GL.GL_ONE); - - for (i=0 ; i light.intensity - DLIGHT_CUTOFF) - { - R_MarkLights (light, bit, node.children[0]); - return; - } - if (dist < -light.intensity + DLIGHT_CUTOFF) - { - R_MarkLights (light, bit, node.children[1]); - return; - } - - // mark the polygons - for (i=0 ; i= 0) ? 0 : Defines.SURF_PLANEBACK; - if ( (surf.flags & Defines.SURF_PLANEBACK) != sidebit ) - continue; - /* - * cwei - * bugfix end - */ - - if (surf.dlightframe != r_dlightframecount) - { - surf.dlightbits = 0; - surf.dlightframe = r_dlightframecount; - } - surf.dlightbits |= bit; - } - - R_MarkLights (light, bit, node.children[0]); - R_MarkLights (light, bit, node.children[1]); - } - - - /* - ============= - R_PushDlights - ============= - */ - void R_PushDlights() - { - int i; - dlight_t l; - - if (gl_flashblend.value != 0) - return; - - r_dlightframecount = r_framecount + 1; // because the count hasn't - // advanced yet for this frame - for (i=0 ; i= 0) - return r; // hit something - - if ( (back < 0) == side ) - return -1; // didn't hit anuthing - - // check for impact on this node - Math3D.VectorCopy (mid, lightspot); - lightplane = plane; - - int surfIndex = node.firstsurface; - float[] scale = {0, 0, 0}; - for (i=0 ; i surf.extents[0] || dt > surf.extents[1] ) - continue; - - if (surf.samples == null) - return 0; - - ds >>= 4; - dt >>= 4; - - lightmap = surf.samples; - int lightmapIndex = 0; - - Math3D.VectorCopy (Globals.vec3_origin, pointcolor); - if (lightmap != null) - { - //float[] scale = {0, 0, 0}; - float[] rgb; - lightmapIndex += 3 * (dt * ((surf.extents[0] >> 4) + 1) + ds); - - for (maps = 0 ; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255; maps++) - { - rgb = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb; - scale[0] = gl_modulate.value * rgb[0]; - scale[1] = gl_modulate.value * rgb[1]; - scale[2] = gl_modulate.value * rgb[2]; - - pointcolor[0] += (lightmap.get(lightmapIndex + 0) & 0xFF) * scale[0] * (1.0f/255); - pointcolor[1] += (lightmap.get(lightmapIndex + 1) & 0xFF) * scale[1] * (1.0f/255); - pointcolor[2] += (lightmap.get(lightmapIndex + 2) & 0xFF) * scale[2] * (1.0f/255); - lightmapIndex += 3 * ((surf.extents[0] >> 4) + 1) * ((surf.extents[1] >> 4) + 1); - } - } - return 1; - } - - // go down back side - return RecursiveLightPoint (node.children[1 - sideIndex], mid, end); - } - - /* - =============== - R_LightPoint - =============== - */ - void R_LightPoint (float[] p, float[] color) - { - assert (p.length == 3) : "vec3_t bug"; - assert (color.length == 3) : "rgb bug"; - - float[] end = {0, 0, 0}; - dlight_t dl; - float add; - - if (r_worldmodel.lightdata == null) - { - color[0] = color[1] = color[2] = 1.0f; - return; - } - - end[0] = p[0]; - end[1] = p[1]; - end[2] = p[2] - 2048; - - float r = RecursiveLightPoint(r_worldmodel.nodes[0], p, end); - - if (r == -1) - { - Math3D.VectorCopy (GameBase.vec3_origin, color); - } - else - { - Math3D.VectorCopy (pointcolor, color); - } - - // - // add dynamic lights - // - for (int lnum=0 ; lnum 0) - { - Math3D.VectorMA (color, add, dl.color, color); - } - } - - Math3D.VectorScale (color, gl_modulate.value, color); - } - -// =================================================================== - - float[] s_blocklights = new float[34 * 34 * 3]; - - /* - =============== - R_AddDynamicLights - =============== - */ - void R_AddDynamicLights(msurface_t surf) - { - int lnum; - int sd, td; - float fdist, frad, fminlight; - float[] impact = {0, 0, 0}; - float[] local = {0, 0, 0}; - int s, t; - int i; - int smax, tmax; - mtexinfo_t tex; - dlight_t dl; - float[] pfBL; - float fsacc, ftacc; - - smax = (surf.extents[0]>>4)+1; - tmax = (surf.extents[1]>>4)+1; - tex = surf.texinfo; - - for (lnum=0 ; lnum td) - fdist = sd + (td>>1); - else - fdist = td + (sd>>1); - - if ( fdist < fminlight ) - { - pfBL[pfBLindex + 0] += ( frad - fdist ) * dl.color[0]; - pfBL[pfBLindex + 1] += ( frad - fdist ) * dl.color[1]; - pfBL[pfBLindex + 2] += ( frad - fdist ) * dl.color[2]; - } - } - } - } - } - - - /* - ** R_SetCacheState - */ - void R_SetCacheState( msurface_t surf ) - { - int maps; - - for (maps = 0 ; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255 ; - maps++) - { - surf.cached_light[maps] = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].white; - } - } - - /* - =============== - R_BuildLightMap - - Combine and scale multiple lightmaps into the floating format in blocklights - =============== - */ - void R_BuildLightMap(msurface_t surf, IntBuffer dest, int stride) - { - int smax, tmax; - int r, g, b, a, max; - int i, j, size; - ByteBuffer lightmap; - float[] scale = {0, 0, 0, 0}; - int nummaps; - float[] bl; - lightstyle_t style; - int monolightmap; - - if ( (surf.texinfo.flags & (Defines.SURF_SKY | Defines.SURF_TRANS33 | Defines.SURF_TRANS66 | Defines.SURF_WARP)) != 0 ) - Com.Error(Defines.ERR_DROP, "R_BuildLightMap called for non-lit surface"); - - smax = (surf.extents[0] >> 4) + 1; - tmax = (surf.extents[1] >> 4) + 1; - size = smax * tmax; - if (size > ((s_blocklights.length * Defines.SIZE_OF_FLOAT) >> 4) ) - Com.Error(Defines.ERR_DROP, "Bad s_blocklights size"); - - try { - // set to full bright if no light data - if (surf.samples == null) - { - int maps; - - for (i=0 ; i g) - max = r; - else - max = g; - if (b > max) - max = b; - - /* - ** alpha is ONLY used for the mono lightmap case. For this reason - ** we set it to the brightest of the color components so that - ** things don't get too dim. - */ - a = max; - - /* - ** rescale all the color components if the intensity of the greatest - ** channel exceeds 1.0 - */ - if (max > 255) - { - float t = 255.0F / max; - - r = (int)(r*t); - g = (int)(g*t); - b = (int)(b*t); - a = (int)(a*t); - } - r &= 0xFF; g &= 0xFF; b &= 0xFF; a &= 0xFF; - dest.put(destp++, (a << 24) | (b << 16) | (g << 8) | (r << 0)); - } - } - } - else - { - for (i=0 ; i g) - max = r; - else - max = g; - if (b > max) - max = b; - - /* - ** alpha is ONLY used for the mono lightmap case. For this reason - ** we set it to the brightest of the color components so that - ** things don't get too dim. - */ - a = max; - - /* - ** rescale all the color components if the intensity of the greatest - ** channel exceeds 1.0 - */ - if (max > 255) - { - float t = 255.0F / max; - - r = (int)(r*t); - g = (int)(g*t); - b = (int)(b*t); - a = (int)(a*t); - } - - /* - ** So if we are doing alpha lightmaps we need to set the R, G, and B - ** components to 0 and we need to set alpha to 1-alpha. - */ - switch ( monolightmap ) - { - case 'L': - case 'I': - r = a; - g = b = 0; - break; - case 'C': - // try faking colored lighting - a = 255 - ((r+g+b)/3); - r *= a/255.0f; - g *= a/255.0f; - b *= a/255.0f; - break; - case 'A': - default: - r = g = b = 0; - a = 255 - a; - break; - } - r &= 0xFF; g &= 0xFF; b &= 0xFF; a &= 0xFF; - dest.put(destp++, (a << 24) | (b << 16) | (g << 8) | (r << 0)); - } - } - } - } - -} + // r_light.c + + int r_dlightframecount; + + static final int DLIGHT_CUTOFF = 64; + + /* + * ============================================================================= + * + * DYNAMIC LIGHTS BLEND RENDERING + * + * ============================================================================= + */ + + void R_RenderDlight(dlight_t light) { + int i, j; + float a; + float[] v = { 0, 0, 0 }; + float rad; + + rad = light.intensity * 0.35f; + + Math3D.VectorSubtract(light.origin, r_origin, v); + + gl.glBegin(GL.GL_TRIANGLE_FAN); + gl.glColor3f(light.color[0] * 0.2f, light.color[1] * 0.2f, + light.color[2] * 0.2f); + for (i = 0; i < 3; i++) + v[i] = light.origin[i] - vpn[i] * rad; + gl.glVertex3f(v[0], v[1], v[2]); + gl.glColor3f(0, 0, 0); + for (i = 16; i >= 0; i--) { + a = (float) (i / 16.0f * Math.PI * 2); + for (j = 0; j < 3; j++) + v[j] = (float) (light.origin[j] + vright[j] * Math.cos(a) * rad + vup[j] + * Math.sin(a) * rad); + gl.glVertex3f(v[0], v[1], v[2]); + } + gl.glEnd(); + } + + /* + * ============= R_RenderDlights ============= + */ + void R_RenderDlights() { + int i; + dlight_t l; + + if (gl_flashblend.value == 0) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + gl.glDepthMask(false); + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glShadeModel(GL.GL_SMOOTH); + gl.glEnable(GL.GL_BLEND); + gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE); + + for (i = 0; i < r_newrefdef.num_dlights; i++) { + l = r_newrefdef.dlights[i]; + R_RenderDlight(l); + } + + gl.glColor3f(1, 1, 1); + gl.glDisable(GL.GL_BLEND); + gl.glEnable(GL.GL_TEXTURE_2D); + gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); + gl.glDepthMask(true); + } + + /* + * ============================================================================= + * + * DYNAMIC LIGHTS + * + * ============================================================================= + */ + + /* + * ============= R_MarkLights ============= + */ + void R_MarkLights(dlight_t light, int bit, mnode_t node) { + cplane_t splitplane; + float dist; + msurface_t surf; + int i; + int sidebit; + + if (node.contents != -1) + return; + + splitplane = node.plane; + dist = Math3D.DotProduct(light.origin, splitplane.normal) + - splitplane.dist; + + if (dist > light.intensity - DLIGHT_CUTOFF) { + R_MarkLights(light, bit, node.children[0]); + return; + } + if (dist < -light.intensity + DLIGHT_CUTOFF) { + R_MarkLights(light, bit, node.children[1]); + return; + } + + // mark the polygons + for (i = 0; i < node.numsurfaces; i++) { + + surf = r_worldmodel.surfaces[node.firstsurface + i]; + + /* + * cwei bugfix for dlight behind the walls + */ + dist = Math3D.DotProduct(light.origin, surf.plane.normal) + - surf.plane.dist; + sidebit = (dist >= 0) ? 0 : Defines.SURF_PLANEBACK; + if ((surf.flags & Defines.SURF_PLANEBACK) != sidebit) + continue; + /* + * cwei bugfix end + */ + + if (surf.dlightframe != r_dlightframecount) { + surf.dlightbits = 0; + surf.dlightframe = r_dlightframecount; + } + surf.dlightbits |= bit; + } + + R_MarkLights(light, bit, node.children[0]); + R_MarkLights(light, bit, node.children[1]); + } + + /* + * ============= R_PushDlights ============= + */ + void R_PushDlights() { + int i; + dlight_t l; + + if (gl_flashblend.value != 0) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + for (i = 0; i < r_newrefdef.num_dlights; i++) { + l = r_newrefdef.dlights[i]; + R_MarkLights(l, 1 << i, r_worldmodel.nodes[0]); + } + } + + /* + * ============================================================================= + * + * LIGHT SAMPLING + * + * ============================================================================= + */ + + float[] pointcolor = { 0, 0, 0 }; // vec3_t + + cplane_t lightplane; // used as shadow plane + + float[] lightspot = { 0, 0, 0 }; // vec3_t + + int RecursiveLightPoint(mnode_t node, float[] start, float[] end) { + if (node.contents != -1) + return -1; // didn't hit anything + + msurface_t surf; + int s, t, ds, dt; + int i; + mtexinfo_t tex; + ByteBuffer lightmap; + int maps; + float[] mid = { 0, 0, 0 }; + + // calculate mid point + + // FIXME: optimize for axial + cplane_t plane = node.plane; + float front = Math3D.DotProduct(start, plane.normal) - plane.dist; + float back = Math3D.DotProduct(end, plane.normal) - plane.dist; + boolean side = (front < 0); + int sideIndex = (side) ? 1 : 0; + + if ((back < 0) == side) + return RecursiveLightPoint(node.children[sideIndex], start, end); + + float frac = front / (front - back); + mid[0] = start[0] + (end[0] - start[0]) * frac; + mid[1] = start[1] + (end[1] - start[1]) * frac; + mid[2] = start[2] + (end[2] - start[2]) * frac; + + // go down front side + int r = RecursiveLightPoint(node.children[sideIndex], start, mid); + if (r >= 0) + return r; // hit something + + if ((back < 0) == side) + return -1; // didn't hit anuthing + + // check for impact on this node + Math3D.VectorCopy(mid, lightspot); + lightplane = plane; + + int surfIndex = node.firstsurface; + float[] scale = { 0, 0, 0 }; + for (i = 0; i < node.numsurfaces; i++, surfIndex++) { + surf = r_worldmodel.surfaces[surfIndex]; + + if ((surf.flags & (Defines.SURF_DRAWTURB | Defines.SURF_DRAWSKY)) != 0) + continue; // no lightmaps + + tex = surf.texinfo; + + s = (int) (Math3D.DotProduct(mid, tex.vecs[0]) + tex.vecs[0][3]); + t = (int) (Math3D.DotProduct(mid, tex.vecs[1]) + tex.vecs[1][3]); + + if (s < surf.texturemins[0] || t < surf.texturemins[1]) + continue; + + ds = s - surf.texturemins[0]; + dt = t - surf.texturemins[1]; + + if (ds > surf.extents[0] || dt > surf.extents[1]) + continue; + + if (surf.samples == null) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf.samples; + int lightmapIndex = 0; + + Math3D.VectorCopy(Globals.vec3_origin, pointcolor); + if (lightmap != null) { + //float[] scale = {0, 0, 0}; + float[] rgb; + lightmapIndex += 3 * (dt * ((surf.extents[0] >> 4) + 1) + ds); + + for (maps = 0; maps < Defines.MAXLIGHTMAPS + && surf.styles[maps] != (byte) 255; maps++) { + rgb = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb; + scale[0] = gl_modulate.value * rgb[0]; + scale[1] = gl_modulate.value * rgb[1]; + scale[2] = gl_modulate.value * rgb[2]; + + pointcolor[0] += (lightmap.get(lightmapIndex + 0) & 0xFF) + * scale[0] * (1.0f / 255); + pointcolor[1] += (lightmap.get(lightmapIndex + 1) & 0xFF) + * scale[1] * (1.0f / 255); + pointcolor[2] += (lightmap.get(lightmapIndex + 2) & 0xFF) + * scale[2] * (1.0f / 255); + lightmapIndex += 3 * ((surf.extents[0] >> 4) + 1) + * ((surf.extents[1] >> 4) + 1); + } + } + return 1; + } + + // go down back side + return RecursiveLightPoint(node.children[1 - sideIndex], mid, end); + } + + /* + * =============== R_LightPoint =============== + */ + void R_LightPoint(float[] p, float[] color) { + assert (p.length == 3) : "vec3_t bug"; + assert (color.length == 3) : "rgb bug"; + + float[] end = { 0, 0, 0 }; + dlight_t dl; + float add; + + if (r_worldmodel.lightdata == null) { + color[0] = color[1] = color[2] = 1.0f; + return; + } + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 2048; + + float r = RecursiveLightPoint(r_worldmodel.nodes[0], p, end); + + if (r == -1) { + Math3D.VectorCopy(Globals.vec3_origin, color); + } else { + Math3D.VectorCopy(pointcolor, color); + } + + // + // add dynamic lights + // + for (int lnum = 0; lnum < r_newrefdef.num_dlights; lnum++) { + dl = r_newrefdef.dlights[lnum]; + + Math3D.VectorSubtract(currententity.origin, dl.origin, end); + add = dl.intensity - Math3D.VectorLength(end); + add *= (1.0f / 256); + if (add > 0) { + Math3D.VectorMA(color, add, dl.color, color); + } + } + + Math3D.VectorScale(color, gl_modulate.value, color); + } + + // =================================================================== + + float[] s_blocklights = new float[34 * 34 * 3]; + + /* + * =============== R_AddDynamicLights =============== + */ + void R_AddDynamicLights(msurface_t surf) { + int lnum; + int sd, td; + float fdist, frad, fminlight; + float[] impact = { 0, 0, 0 }; + float[] local = { 0, 0, 0 }; + int s, t; + int i; + int smax, tmax; + mtexinfo_t tex; + dlight_t dl; + float[] pfBL; + float fsacc, ftacc; + + smax = (surf.extents[0] >> 4) + 1; + tmax = (surf.extents[1] >> 4) + 1; + tex = surf.texinfo; + + for (lnum = 0; lnum < r_newrefdef.num_dlights; lnum++) { + if ((surf.dlightbits & (1 << lnum)) == 0) + continue; // not lit by this light + + dl = r_newrefdef.dlights[lnum]; + frad = dl.intensity; + fdist = Math3D.DotProduct(dl.origin, surf.plane.normal) + - surf.plane.dist; + frad -= Math.abs(fdist); + // rad is now the highest intensity on the plane + + fminlight = DLIGHT_CUTOFF; // FIXME: make configurable? + if (frad < fminlight) + continue; + fminlight = frad - fminlight; + + for (i = 0; i < 3; i++) { + impact[i] = dl.origin[i] - surf.plane.normal[i] * fdist; + } + + local[0] = Math3D.DotProduct(impact, tex.vecs[0]) + tex.vecs[0][3] + - surf.texturemins[0]; + local[1] = Math3D.DotProduct(impact, tex.vecs[1]) + tex.vecs[1][3] + - surf.texturemins[1]; + + pfBL = s_blocklights; + int pfBLindex = 0; + for (t = 0, ftacc = 0; t < tmax; t++, ftacc += 16) { + td = (int) (local[1] - ftacc); + if (td < 0) + td = -td; + + for (s = 0, fsacc = 0; s < smax; s++, fsacc += 16, pfBLindex += 3) { + sd = (int) (local[0] - fsacc); + + if (sd < 0) + sd = -sd; + + if (sd > td) + fdist = sd + (td >> 1); + else + fdist = td + (sd >> 1); + + if (fdist < fminlight) { + pfBL[pfBLindex + 0] += (frad - fdist) * dl.color[0]; + pfBL[pfBLindex + 1] += (frad - fdist) * dl.color[1]; + pfBL[pfBLindex + 2] += (frad - fdist) * dl.color[2]; + } + } + } + } + } + + /* + * * R_SetCacheState + */ + void R_SetCacheState(msurface_t surf) { + int maps; + + for (maps = 0; maps < Defines.MAXLIGHTMAPS + && surf.styles[maps] != (byte) 255; maps++) { + surf.cached_light[maps] = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].white; + } + } + + /* + * =============== R_BuildLightMap + * + * Combine and scale multiple lightmaps into the floating format in + * blocklights =============== + */ + void R_BuildLightMap(msurface_t surf, IntBuffer dest, int stride) { + int smax, tmax; + int r, g, b, a, max; + int i, j, size; + ByteBuffer lightmap; + float[] scale = { 0, 0, 0, 0 }; + int nummaps; + float[] bl; + lightstyle_t style; + int monolightmap; + + if ((surf.texinfo.flags & (Defines.SURF_SKY | Defines.SURF_TRANS33 + | Defines.SURF_TRANS66 | Defines.SURF_WARP)) != 0) + Com.Error(Defines.ERR_DROP, + "R_BuildLightMap called for non-lit surface"); + + smax = (surf.extents[0] >> 4) + 1; + tmax = (surf.extents[1] >> 4) + 1; + size = smax * tmax; + if (size > ((s_blocklights.length * Defines.SIZE_OF_FLOAT) >> 4)) + Com.Error(Defines.ERR_DROP, "Bad s_blocklights size"); + + try { + // set to full bright if no light data + if (surf.samples == null) { + int maps; + + for (i = 0; i < size * 3; i++) + s_blocklights[i] = 255; + + for (maps = 0; maps < Defines.MAXLIGHTMAPS + && surf.styles[maps] != (byte) 255; maps++) { + style = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF]; + } + // goto store; + throw new longjmpException(); + } + + // count the # of maps + for (nummaps = 0; nummaps < Defines.MAXLIGHTMAPS + && surf.styles[nummaps] != (byte) 255; nummaps++) + ; + + lightmap = surf.samples; + int lightmapIndex = 0; + + // add all the lightmaps + if (nummaps == 1) { + int maps; + + for (maps = 0; maps < Defines.MAXLIGHTMAPS + && surf.styles[maps] != (byte) 255; maps++) { + bl = s_blocklights; + int blp = 0; + + for (i = 0; i < 3; i++) + scale[i] = gl_modulate.value + * r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb[i]; + + if (scale[0] == 1.0F && scale[1] == 1.0F + && scale[2] == 1.0F) { + for (i = 0; i < size; i++) { + bl[blp++] = lightmap.get(lightmapIndex++) & 0xFF; + bl[blp++] = lightmap.get(lightmapIndex++) & 0xFF; + bl[blp++] = lightmap.get(lightmapIndex++) & 0xFF; + } + } else { + for (i = 0; i < size; i++) { + bl[blp++] = (lightmap.get(lightmapIndex++) & 0xFF) + * scale[0]; + bl[blp++] = (lightmap.get(lightmapIndex++) & 0xFF) + * scale[1]; + bl[blp++] = (lightmap.get(lightmapIndex++) & 0xFF) + * scale[2]; + } + } + //lightmap += size*3; // skip to next lightmap + } + } else { + int maps; + + // memset( s_blocklights, 0, sizeof( s_blocklights[0] ) * size * + // 3 ); + + Arrays.fill(s_blocklights, 0, size * 3, 0.0f); + + for (maps = 0; maps < Defines.MAXLIGHTMAPS + && surf.styles[maps] != (byte) 255; maps++) { + bl = s_blocklights; + int blp = 0; + + for (i = 0; i < 3; i++) + scale[i] = gl_modulate.value + * r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb[i]; + + if (scale[0] == 1.0F && scale[1] == 1.0F + && scale[2] == 1.0F) { + for (i = 0; i < size; i++) { + bl[blp++] += lightmap.get(lightmapIndex++) & 0xFF; + bl[blp++] += lightmap.get(lightmapIndex++) & 0xFF; + bl[blp++] += lightmap.get(lightmapIndex++) & 0xFF; + } + } else { + for (i = 0; i < size; i++) { + bl[blp++] += (lightmap.get(lightmapIndex++) & 0xFF) + * scale[0]; + bl[blp++] += (lightmap.get(lightmapIndex++) & 0xFF) + * scale[1]; + bl[blp++] += (lightmap.get(lightmapIndex++) & 0xFF) + * scale[2]; + } + } + //lightmap += size*3; // skip to next lightmap + } + } + + // add all the dynamic lights + if (surf.dlightframe == r_framecount) + R_AddDynamicLights(surf); + + // label store: + } catch (longjmpException store) { + } + + // put into texture format + stride -= smax; + bl = s_blocklights; + int blp = 0; + + monolightmap = gl_monolightmap.string.charAt(0); + + int destp = 0; + + if (monolightmap == '0') { + for (i = 0; i < tmax; i++, destp += stride) { + dest.position(destp); + + for (j = 0; j < smax; j++) { + + r = (int) bl[blp++]; + g = (int) bl[blp++]; + b = (int) bl[blp++]; + + // catch negative lights + if (r < 0) + r = 0; + if (g < 0) + g = 0; + if (b < 0) + b = 0; + + /* + * * determine the brightest of the three color components + */ + if (r > g) + max = r; + else + max = g; + if (b > max) + max = b; + + /* + * * alpha is ONLY used for the mono lightmap case. For this + * reason * we set it to the brightest of the color + * components so that * things don't get too dim. + */ + a = max; + + /* + * * rescale all the color components if the intensity of + * the greatest * channel exceeds 1.0 + */ + if (max > 255) { + float t = 255.0F / max; + + r = (int) (r * t); + g = (int) (g * t); + b = (int) (b * t); + a = (int) (a * t); + } + r &= 0xFF; + g &= 0xFF; + b &= 0xFF; + a &= 0xFF; + dest.put(destp++, (a << 24) | (b << 16) | (g << 8) + | (r << 0)); + } + } + } else { + for (i = 0; i < tmax; i++, destp += stride) { + dest.position(destp); + + for (j = 0; j < smax; j++) { + + r = (int) bl[blp++]; + g = (int) bl[blp++]; + b = (int) bl[blp++]; + + // catch negative lights + if (r < 0) + r = 0; + if (g < 0) + g = 0; + if (b < 0) + b = 0; + + /* + * * determine the brightest of the three color components + */ + if (r > g) + max = r; + else + max = g; + if (b > max) + max = b; + + /* + * * alpha is ONLY used for the mono lightmap case. For this + * reason * we set it to the brightest of the color + * components so that * things don't get too dim. + */ + a = max; + + /* + * * rescale all the color components if the intensity of + * the greatest * channel exceeds 1.0 + */ + if (max > 255) { + float t = 255.0F / max; + + r = (int) (r * t); + g = (int) (g * t); + b = (int) (b * t); + a = (int) (a * t); + } + + /* + * * So if we are doing alpha lightmaps we need to set the + * R, G, and B * components to 0 and we need to set alpha to + * 1-alpha. + */ + switch (monolightmap) { + case 'L': + case 'I': + r = a; + g = b = 0; + break; + case 'C': + // try faking colored lighting + a = 255 - ((r + g + b) / 3); + r *= a / 255.0f; + g *= a / 255.0f; + b *= a / 255.0f; + break; + case 'A': + default: + r = g = b = 0; + a = 255 - a; + break; + } + r &= 0xFF; + g &= 0xFF; + b &= 0xFF; + a &= 0xFF; + dest.put(destp++, (a << 24) | (b << 16) | (g << 8) + | (r << 0)); + } + } + } + } + +} \ No newline at end of file diff --git a/src/jake2/render/jogl/Mesh.java b/src/jake2/render/jogl/Mesh.java index 4a8aed3..d6dc90c 100644 --- a/src/jake2/render/jogl/Mesh.java +++ b/src/jake2/render/jogl/Mesh.java @@ -2,27 +2,27 @@ * Mesh.java * Copyright (C) 2003 * - * $Id: Mesh.java,v 1.6 2004-07-16 10:11:35 cawe Exp $ + * $Id: Mesh.java,v 1.7 2004-09-22 19:22:16 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.render.jogl; import jake2.Defines; @@ -39,828 +39,795 @@ import net.java.games.jogl.util.BufferUtils; /** * Mesh - * + * * @author cwei */ public abstract class Mesh extends Light { - // g_mesh.c: triangle model functions - - /* - ============================================================= - - ALIAS MODELS - - ============================================================= - */ - - static final int NUMVERTEXNORMALS = 162; - - float[][] r_avertexnormals = Anorms.VERTEXNORMALS; - - float[][] s_lerped = new float[qfiles.MAX_VERTS][4]; - - - float[] shadevector = {0, 0, 0}; - float[] shadelight = {0, 0, 0}; - - // precalculated dot products for quantized angles - static final int SHADEDOT_QUANT = 16; - - float[][] r_avertexnormal_dots = Anorms.VERTEXNORMAL_DOTS; - - float[] shadedots = r_avertexnormal_dots[0]; - - void GL_LerpVerts( int nverts, qfiles.dtrivertx_t[] v, qfiles.dtrivertx_t[] ov, qfiles.dtrivertx_t[] verts, float[][] lerp, float[] move, float[] frontv, float[] backv ) - { - int i; - int lerpIndex = 0; - - //PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0 ) - { - float[] normal; - for (i=0 ; i < nverts; i++/* , v++, ov++, lerp+=4 */) - { - normal = r_avertexnormals[verts[i].lightnormalindex]; - - lerp[i][0] = move[0] + ov[i].v[0]*backv[0] + v[i].v[0]*frontv[0] + normal[0] * Defines.POWERSUIT_SCALE; - lerp[i][1] = move[1] + ov[i].v[1]*backv[1] + v[i].v[1]*frontv[1] + normal[1] * Defines.POWERSUIT_SCALE; - lerp[i][2] = move[2] + ov[i].v[2]*backv[2] + v[i].v[2]*frontv[2] + normal[2] * Defines.POWERSUIT_SCALE; - } - } - else - { - for (i=0 ; i < nverts; i++ /* , v++, ov++, lerp+=4 */) - { - lerp[i][0] = move[0] + ov[i].v[0]*backv[0] + v[i].v[0]*frontv[0]; - lerp[i][1] = move[1] + ov[i].v[1]*backv[1] + v[i].v[1]*frontv[1]; - lerp[i][2] = move[2] + ov[i].v[2]*backv[2] + v[i].v[2]*frontv[2]; - } - } - } - - void GL_LerpVerts( int nverts, qfiles.dtrivertx_t[] v, qfiles.dtrivertx_t[] ov, qfiles.dtrivertx_t[] verts, float[] move, float[] frontv, float[] backv ) - { - int lerpIndex = 0; - - int[] ovv; - int[] vv; - FloatBuffer lerp = vertexArrayBuf; - - //PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0 ) - { - float[] normal; - int j = 0; - for (int i=0 ; i < nverts; i++/* , v++, ov++, lerp+=4 */) - { - normal = r_avertexnormals[verts[i].lightnormalindex]; - ovv = ov[i].v; - vv = v[i].v; - - lerp.put(j, move[0] + ovv[0]*backv[0] + vv[0]*frontv[0] + normal[0] * Defines.POWERSUIT_SCALE); - lerp.put(j + 1, move[1] + ovv[1]*backv[1] + vv[1]*frontv[1] + normal[1] * Defines.POWERSUIT_SCALE); - lerp.put(j + 2, move[2] + ovv[2]*backv[2] + vv[2]*frontv[2] + normal[2] * Defines.POWERSUIT_SCALE); - j+=3; - } - } - else - { - int j = 0; - for (int i=0 ; i < nverts; i++ /* , v++, ov++, lerp+=4 */) - { - ovv = ov[i].v; - vv = v[i].v; - - lerp.put(j, move[0] + ovv[0]*backv[0] + vv[0]*frontv[0]); - lerp.put(j + 1, move[1] + ovv[1]*backv[1] + vv[1]*frontv[1]); - lerp.put(j + 2, move[2] + ovv[2]*backv[2] + vv[2]*frontv[2]); - j+=3; - } - } - } - - FloatBuffer colorArrayBuf = BufferUtils.newFloatBuffer(qfiles.MAX_VERTS * 4); - FloatBuffer vertexArrayBuf = BufferUtils.newFloatBuffer(qfiles.MAX_VERTS * 3); - boolean isFilled = false; - float[] tmpVec = {0, 0, 0}; - - /* - ============= - GL_DrawAliasFrameLerp - - interpolates between two frames and origins - FIXME: batch lerp all vertexes - ============= - */ - void GL_DrawAliasFrameLerp (qfiles.dmdl_t paliashdr, float backlerp) - { - float l; - qfiles.daliasframe_t frame, oldframe; - qfiles.dtrivertx_t[] v, ov, verts; - - int[] order; - int orderIndex = 0; - int count; - - float frontlerp; - float alpha; - - float[] move = {0, 0, 0}; // vec3_t - float[][] vectors = { - {0, 0, 0}, {0, 0, 0}, {0, 0, 0} // 3 mal vec3_t - }; - - float[] frontv = {0, 0, 0}; // vec3_t - float[] backv = {0, 0, 0}; // vec3_t - - int i; - int index_xyz; - //float[][] lerp; - - frame = paliashdr.aliasFrames[currententity.frame]; - - verts = v = frame.verts; - - oldframe = paliashdr.aliasFrames[currententity.oldframe]; - - ov = oldframe.verts; - - order = paliashdr.glCmds; - - if ((currententity.flags & Defines.RF_TRANSLUCENT) != 0) - alpha = currententity.alpha; - else - alpha = 1.0f; - - // PMM - added double shell - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) - gl.glDisable( GL.GL_TEXTURE_2D ); - - frontlerp = 1.0f - backlerp; - - // move should be the delta back to the previous frame * backlerp - Math3D.VectorSubtract (currententity.oldorigin, currententity.origin, frontv); - Math3D.AngleVectors (currententity.angles, vectors[0], vectors[1], vectors[2]); - - move[0] = Math3D.DotProduct(frontv, vectors[0]); // forward - move[1] = -Math3D.DotProduct(frontv, vectors[1]); // left - move[2] = Math3D.DotProduct(frontv, vectors[2]); // up - - Math3D.VectorAdd (move, oldframe.translate, move); - - for (i=0 ; i<3 ; i++) - { - move[i] = backlerp*move[i] + frontlerp*frame.translate[i]; - frontv[i] = frontlerp*frame.scale[i]; - backv[i] = backlerp*oldframe.scale[i]; - } - - if ( gl_vertex_arrays.value != 0.0f ) - { - GL_LerpVerts( paliashdr.num_xyz, v, ov, verts, move, frontv, backv ); - - gl.glEnableClientState( GL.GL_VERTEX_ARRAY ); - gl.glVertexPointer( 3, GL.GL_FLOAT, 0, vertexArrayBuf ); - - // PMM - added double damage shell - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) - { - gl.glColor4f( shadelight[0], shadelight[1], shadelight[2], alpha ); - } - else - { - gl.glEnableClientState( GL.GL_COLOR_ARRAY ); - gl.glColorPointer( 4, GL.GL_FLOAT, 0, colorArrayBuf ); - - // - // pre light everything - // - FloatBuffer color = colorArrayBuf; - int j = 0; - for ( i = 0; i < paliashdr.num_xyz; i++ ) - { - l = shadedots[verts[i].lightnormalindex]; - color.put(j++, l * shadelight[0]); - color.put(j++, l * shadelight[1]); - color.put(j++, l * shadelight[2]); - color.put(j++, alpha); - } - } - - if ( qglLockArraysEXT ) - gl.glLockArraysEXT( 0, paliashdr.num_xyz ); - - while (true) - { - // get the vertex count and primitive type - count = order[orderIndex++]; - if (count == 0) - break; // done - if (count < 0) - { - count = -count; - gl.glBegin (GL.GL_TRIANGLE_FAN); - } - else - { - gl.glBegin (GL.GL_TRIANGLE_STRIP); - } - - // PMM - added double damage shell - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0 ) - { - do - { - index_xyz = order[orderIndex + 2]; - orderIndex += 3; - /* - vertexArrayBuf.position(4 * index_xyz); - vertexArrayBuf.get(tmpVec); - gl.glVertex3fv( tmpVec ); - */ - gl.glArrayElement( index_xyz ); - - } while (--count != 0); - } - else - { - do - { - // texture coordinates come from the draw list - gl.glTexCoord2f (Float.intBitsToFloat(order[orderIndex + 0]), Float.intBitsToFloat(order[orderIndex + 1])); - - index_xyz = order[orderIndex + 2]; - orderIndex += 3; - - // normals and vertexes come from the frame list - gl.glArrayElement( index_xyz ); - - } while (--count != 0); - } - gl.glEnd (); - } - - if ( qglLockArraysEXT ) - gl.glUnlockArraysEXT(); - } - else - { - GL_LerpVerts( paliashdr.num_xyz, v, ov, verts, s_lerped, move, frontv, backv ); - - float[] tmp; - - while (true) - { - // get the vertex count and primitive type - count = order[orderIndex++]; - if (count == 0) - break; // done - if (count < 0) - { - count = -count; - gl.glBegin (GL.GL_TRIANGLE_FAN); - } - else - { - gl.glBegin (GL.GL_TRIANGLE_STRIP); - } - - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE )) != 0 ) - { - do - { - index_xyz = order[orderIndex + 2]; - orderIndex += 3; - - gl.glColor4f( shadelight[0], shadelight[1], shadelight[2], alpha); - tmp = s_lerped[index_xyz]; - gl.glVertex3f(tmp[0], tmp[1], tmp[2]); - - } while (--count != 0); - } - else - { - do - { - // texture coordinates come from the draw list - // gl.glTexCoord2f (((float *)order)[0], ((float *)order)[1]); - - gl.glTexCoord2f (Float.intBitsToFloat(order[orderIndex + 0]), Float.intBitsToFloat(order[orderIndex + 1])); - index_xyz = order[orderIndex + 2]; - orderIndex += 3; - - // normals and vertexes come from the frame list - l = shadedots[verts[index_xyz].lightnormalindex]; - - gl.glColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); - tmp = s_lerped[index_xyz]; - gl.glVertex3f(tmp[0], tmp[1], tmp[2]); - } while (--count != 0); - } - gl.glEnd (); - } - } - - // PMM - added double damage shell - if ( (currententity.flags & ( Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0 ) - gl.glEnable( GL.GL_TEXTURE_2D ); - } - - - /* - ============= - GL_DrawAliasShadow - ============= - */ - void GL_DrawAliasShadow(qfiles.dmdl_t paliashdr, int posenum) - { - qfiles.dtrivertx_t[] verts; - int[] order; - float[] point = {0, 0, 0}; - float height, lheight; - int count; - qfiles.daliasframe_t frame; - - lheight = currententity.origin[2] - lightspot[2]; - - frame = paliashdr.aliasFrames[currententity.frame]; - - verts = frame.verts; - - height = 0; - - order = paliashdr.glCmds; - - height = -lheight + 1.0f; - - int orderIndex = 0; - int index = 0; - - while (true) - { - // get the vertex count and primitive type - count = order[orderIndex++]; - if (count == 0) - break; // done - if (count < 0) - { - count = -count; - gl.glBegin (GL.GL_TRIANGLE_FAN); - } - else - gl.glBegin (GL.GL_TRIANGLE_STRIP); - - do - { - // normals and vertexes come from the frame list - /* - point[0] = verts[order[2]].v[0] * frame.scale[0] + frame.translate[0]; - point[1] = verts[order[2]].v[1] * frame.scale[1] + frame.translate[1]; - point[2] = verts[order[2]].v[2] * frame.scale[2] + frame.translate[2]; - */ - - if ( gl_vertex_arrays.value != 0.0f ) - { - index = order[orderIndex + 2] * 3; - point[0] = vertexArrayBuf.get(index); - point[1] = vertexArrayBuf.get(index + 1); - point[2] = vertexArrayBuf.get(index + 2); - } - else - { - Math3D.VectorCopy(s_lerped[order[orderIndex + 2]], point); - } - - point[0] -= shadevector[0]*(point[2]+lheight); - point[1] -= shadevector[1]*(point[2]+lheight); - point[2] = height; - gl.glVertex3f(point[0], point[1], point[2]); - - orderIndex += 3; - - } while (--count != 0); - - gl.glEnd (); - } - } - - - /* - ** R_CullAliasModel - */ - boolean R_CullAliasModel( float[][] bbox, entity_t e ) - { - int i; - float[] mins = {0, 0, 0}; - float[] maxs = {0, 0, 0}; - - qfiles.dmdl_t paliashdr; - - float[][] vectors = { - {0, 0, 0}, - {0, 0, 0}, - {0, 0, 0} - }; - - float[] thismins = {0, 0, 0}; - float[] oldmins = {0, 0, 0}; - float[] thismaxs = {0, 0, 0}; - float[] oldmaxs = {0, 0, 0}; - qfiles.daliasframe_t pframe, poldframe; - float[] angles = {0, 0, 0}; - - paliashdr = (qfiles.dmdl_t)currentmodel.extradata; - - if ( ( e.frame >= paliashdr.num_frames ) || ( e.frame < 0 ) ) - { - VID.Printf (Defines.PRINT_ALL, "R_CullAliasModel " + currentmodel.name +": no such frame " + e.frame + '\n'); - e.frame = 0; - } - if ( ( e.oldframe >= paliashdr.num_frames ) || ( e.oldframe < 0 ) ) - { - VID.Printf (Defines.PRINT_ALL, "R_CullAliasModel " + currentmodel.name + ": no such oldframe " + e.oldframe + '\n'); - e.oldframe = 0; - } - - pframe = paliashdr.aliasFrames[e.frame]; - poldframe = paliashdr.aliasFrames[e.oldframe]; - - /* - ** compute axially aligned mins and maxs - */ - if ( pframe == poldframe ) - { - for ( i = 0; i < 3; i++ ) - { - mins[i] = pframe.translate[i]; - maxs[i] = mins[i] + pframe.scale[i]*255; - } - } - else - { - for ( i = 0; i < 3; i++ ) - { - thismins[i] = pframe.translate[i]; - thismaxs[i] = thismins[i] + pframe.scale[i]*255; - - oldmins[i] = poldframe.translate[i]; - oldmaxs[i] = oldmins[i] + poldframe.scale[i]*255; - - if ( thismins[i] < oldmins[i] ) - mins[i] = thismins[i]; - else - mins[i] = oldmins[i]; - - if ( thismaxs[i] > oldmaxs[i] ) - maxs[i] = thismaxs[i]; - else - maxs[i] = oldmaxs[i]; - } - } - - /* - ** compute a full bounding box - */ - for ( i = 0; i < 8; i++ ) - { - float[] tmp = {0, 0, 0}; - - if ( (i & 1) != 0 ) - tmp[0] = mins[0]; - else - tmp[0] = maxs[0]; - - if ( (i & 2) != 0) - tmp[1] = mins[1]; - else - tmp[1] = maxs[1]; - - if ( (i & 4) != 0) - tmp[2] = mins[2]; - else - tmp[2] = maxs[2]; - - Math3D.VectorCopy( tmp, bbox[i] ); - } - - /* - ** rotate the bounding box - */ - Math3D.VectorCopy( e.angles, angles ); - angles[YAW] = -angles[YAW]; - Math3D.AngleVectors( angles, vectors[0], vectors[1], vectors[2] ); - - for ( i = 0; i < 8; i++ ) - { - float[] tmp = {0, 0, 0}; - - Math3D.VectorCopy( bbox[i], tmp ); - - bbox[i][0] = Math3D.DotProduct( vectors[0], tmp ); - bbox[i][1] = -Math3D.DotProduct( vectors[1], tmp ); - bbox[i][2] = Math3D.DotProduct( vectors[2], tmp ); - - Math3D.VectorAdd( e.origin, bbox[i], bbox[i] ); - } - - { - int p, f; - int aggregatemask = ~0; // 0xFFFFFFFF - - for ( p = 0; p < 8; p++ ) - { - int mask = 0; - - for ( f = 0; f < 4; f++ ) - { - float dp = Math3D.DotProduct( frustum[f].normal, bbox[p] ); - - if ( ( dp - frustum[f].dist ) < 0 ) - { - mask |= ( 1 << f ); - } - } - - aggregatemask &= mask; - } - - if ( aggregatemask != 0 ) - { - return true; - } - - return false; - } - } - - /* - ================= - R_DrawAliasModel - - ================= - */ - void R_DrawAliasModel(entity_t e) - { - int i; - qfiles.dmdl_t paliashdr; - float an; - - // bounding box - float[][] bbox = { - {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, - {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0} - }; - image_t skin; - - if ( ( e.flags & Defines.RF_WEAPONMODEL ) == 0) - { - if ( R_CullAliasModel( bbox, e ) ) - return; - } - - if ( (e.flags & Defines.RF_WEAPONMODEL) != 0 ) - { - if ( r_lefthand.value == 2.0f ) - return; - } - - paliashdr = (qfiles.dmdl_t)currentmodel.extradata; - - // - // get lighting information - // - // PMM - rewrote, reordered to handle new shells & mixing - // PMM - 3.20 code .. replaced with original way of doing it to keep mod authors happy - // - if ( (currententity.flags & ( Defines.RF_SHELL_HALF_DAM | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_RED | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE )) != 0 ) - { - Math3D.VectorClear(shadelight); - if ((currententity.flags & Defines.RF_SHELL_HALF_DAM) != 0) - { - shadelight[0] = 0.56f; - shadelight[1] = 0.59f; - shadelight[2] = 0.45f; - } - if ( (currententity.flags & Defines.RF_SHELL_DOUBLE) != 0 ) - { - shadelight[0] = 0.9f; - shadelight[1] = 0.7f; - } - if ( (currententity.flags & Defines.RF_SHELL_RED) != 0 ) - shadelight[0] = 1.0f; - if ( (currententity.flags & Defines.RF_SHELL_GREEN) != 0 ) - shadelight[1] = 1.0f; - if ( (currententity.flags & Defines.RF_SHELL_BLUE) != 0 ) - shadelight[2] = 1.0f; - } - - else if ( (currententity.flags & Defines.RF_FULLBRIGHT) != 0 ) - { - for (i=0 ; i<3 ; i++) - shadelight[i] = 1.0f; - } - else - { - R_LightPoint (currententity.origin, shadelight); - - // player lighting hack for communication back to server - // big hack! - if ( (currententity.flags & Defines.RF_WEAPONMODEL) != 0 ) - { - // pick the greatest component, which should be the same - // as the mono value returned by software - if (shadelight[0] > shadelight[1]) - { - if (shadelight[0] > shadelight[2]) - r_lightlevel.value = 150*shadelight[0]; - else - r_lightlevel.value = 150*shadelight[2]; - } - else - { - if (shadelight[1] > shadelight[2]) - r_lightlevel.value = 150*shadelight[1]; - else - r_lightlevel.value = 150*shadelight[2]; - } - } - - if ( gl_monolightmap.string.charAt(0) != '0' ) - { - float s = shadelight[0]; - - if ( s < shadelight[1] ) - s = shadelight[1]; - if ( s < shadelight[2] ) - s = shadelight[2]; - - shadelight[0] = s; - shadelight[1] = s; - shadelight[2] = s; - } - } - - if ( (currententity.flags & Defines.RF_MINLIGHT) != 0 ) - { - for (i=0 ; i<3 ; i++) - if (shadelight[i] > 0.1f) - break; - if (i == 3) - { - shadelight[0] = 0.1f; - shadelight[1] = 0.1f; - shadelight[2] = 0.1f; - } - } - - if ( (currententity.flags & Defines.RF_GLOW) != 0 ) - { // bonus items will pulse with time - float scale; - float min; - - scale = (float)(0.1f * Math.sin(r_newrefdef.time*7)); - for (i=0 ; i<3 ; i++) - { - min = shadelight[i] * 0.8f; - shadelight[i] += scale; - if (shadelight[i] < min) - shadelight[i] = min; - } - } - - // ================= - // PGM ir goggles color override - if ( (r_newrefdef.rdflags & Defines.RDF_IRGOGGLES) != 0 && (currententity.flags & Defines.RF_IR_VISIBLE) != 0) - { - shadelight[0] = 1.0f; - shadelight[1] = 0.0f; - shadelight[2] = 0.0f; - } - // PGM - // ================= - - shadedots = r_avertexnormal_dots[((int)(currententity.angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; - - an = (float)(currententity.angles[1]/180*Math.PI); - shadevector[0] = (float)Math.cos(-an); - shadevector[1] = (float)Math.sin(-an); - shadevector[2] = 1; - Math3D.VectorNormalize(shadevector); - - // - // locate the proper data - // - - c_alias_polys += paliashdr.num_tris; - - // - // draw all the triangles - // - if ( (currententity.flags & Defines.RF_DEPTHHACK) != 0) // hack the depth range to prevent view model from poking into walls - gl.glDepthRange(gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); - - if ( (currententity.flags & Defines.RF_WEAPONMODEL) != 0 && (r_lefthand.value == 1.0f) ) - { - gl.glMatrixMode( GL.GL_PROJECTION ); - gl.glPushMatrix(); - gl.glLoadIdentity(); - gl.glScalef( -1, 1, 1 ); - MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height, 4, 4096); - gl.glMatrixMode( GL.GL_MODELVIEW ); - - gl.glCullFace( GL.GL_BACK ); - } - - gl.glPushMatrix (); - e.angles[PITCH] = -e.angles[PITCH]; // sigh. - R_RotateForEntity (e); - e.angles[PITCH] = -e.angles[PITCH]; // sigh. - - // select skin - if (currententity.skin != null) - skin = currententity.skin; // custom player skin - else - { - if (currententity.skinnum >= qfiles.MAX_MD2SKINS) - skin = currentmodel.skins[0]; - else - { - skin = currentmodel.skins[currententity.skinnum]; - if (skin == null) - skin = currentmodel.skins[0]; - } - } - if (skin == null) - skin = r_notexture; // fallback... - GL_Bind(skin.texnum); - - // draw it - - gl.glShadeModel (GL.GL_SMOOTH); - - GL_TexEnv( GL.GL_MODULATE ); - if ( (currententity.flags & Defines.RF_TRANSLUCENT) != 0 ) - { - gl.glEnable (GL.GL_BLEND); - } - - - if ( (currententity.frame >= paliashdr.num_frames) - || (currententity.frame < 0) ) - { - VID.Printf (Defines.PRINT_ALL, "R_DrawAliasModel " + currentmodel.name +": no such frame " + currententity.frame + '\n'); - currententity.frame = 0; - currententity.oldframe = 0; - } - - if ( (currententity.oldframe >= paliashdr.num_frames) - || (currententity.oldframe < 0)) - { - VID.Printf (Defines.PRINT_ALL, "R_DrawAliasModel " + currentmodel.name +": no such oldframe " + currententity.oldframe + '\n'); - currententity.frame = 0; - currententity.oldframe = 0; - } - - if ( r_lerpmodels.value == 0.0f) - currententity.backlerp = 0; - GL_DrawAliasFrameLerp (paliashdr, currententity.backlerp); - - GL_TexEnv( GL.GL_REPLACE ); - gl.glShadeModel (GL.GL_FLAT); - - gl.glPopMatrix (); - - if ( ( currententity.flags & Defines.RF_WEAPONMODEL ) != 0 && ( r_lefthand.value == 1.0F ) ) - { - gl.glMatrixMode( GL.GL_PROJECTION ); - gl.glPopMatrix(); - gl.glMatrixMode( GL.GL_MODELVIEW ); - gl.glCullFace( GL.GL_FRONT ); - } - - if ( (currententity.flags & Defines.RF_TRANSLUCENT) != 0 ) - { - gl.glDisable (GL.GL_BLEND); - } - - if ( (currententity.flags & Defines.RF_DEPTHHACK) != 0) - gl.glDepthRange (gldepthmin, gldepthmax); - - if ( gl_shadows.value != 0.0f && (currententity.flags & (Defines.RF_TRANSLUCENT | Defines.RF_WEAPONMODEL)) == 0) - { - gl.glPushMatrix (); - R_RotateForEntity (e); - gl.glDisable (GL.GL_TEXTURE_2D); - gl.glEnable (GL.GL_BLEND); - gl.glColor4f (0,0,0,0.5f); - GL_DrawAliasShadow (paliashdr, currententity.frame ); - gl.glEnable (GL.GL_TEXTURE_2D); - gl.glDisable (GL.GL_BLEND); - gl.glPopMatrix (); - } - gl.glColor4f (1,1,1,1); - } - -} + // g_mesh.c: triangle model functions + + /* + * ============================================================= + * + * ALIAS MODELS + * + * ============================================================= + */ + + static final int NUMVERTEXNORMALS = 162; + + float[][] r_avertexnormals = Anorms.VERTEXNORMALS; + + float[][] s_lerped = new float[qfiles.MAX_VERTS][4]; + + float[] shadevector = { 0, 0, 0 }; + + float[] shadelight = { 0, 0, 0 }; + + // precalculated dot products for quantized angles + static final int SHADEDOT_QUANT = 16; + + float[][] r_avertexnormal_dots = Anorms.VERTEXNORMAL_DOTS; + + float[] shadedots = r_avertexnormal_dots[0]; + + void GL_LerpVerts(int nverts, qfiles.dtrivertx_t[] v, + qfiles.dtrivertx_t[] ov, qfiles.dtrivertx_t[] verts, + float[][] lerp, float[] move, float[] frontv, float[] backv) { + int i; + int lerpIndex = 0; + + //PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE + | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) { + float[] normal; + for (i = 0; i < nverts; i++ /* , v++, ov++, lerp+=4 */ + ) { + normal = r_avertexnormals[verts[i].lightnormalindex]; + + lerp[i][0] = move[0] + ov[i].v[0] * backv[0] + v[i].v[0] + * frontv[0] + normal[0] * Defines.POWERSUIT_SCALE; + lerp[i][1] = move[1] + ov[i].v[1] * backv[1] + v[i].v[1] + * frontv[1] + normal[1] * Defines.POWERSUIT_SCALE; + lerp[i][2] = move[2] + ov[i].v[2] * backv[2] + v[i].v[2] + * frontv[2] + normal[2] * Defines.POWERSUIT_SCALE; + } + } else { + for (i = 0; i < nverts; i++ /* , v++, ov++, lerp+=4 */ + ) { + lerp[i][0] = move[0] + ov[i].v[0] * backv[0] + v[i].v[0] + * frontv[0]; + lerp[i][1] = move[1] + ov[i].v[1] * backv[1] + v[i].v[1] + * frontv[1]; + lerp[i][2] = move[2] + ov[i].v[2] * backv[2] + v[i].v[2] + * frontv[2]; + } + } + } + + void GL_LerpVerts(int nverts, qfiles.dtrivertx_t[] v, + qfiles.dtrivertx_t[] ov, qfiles.dtrivertx_t[] verts, float[] move, + float[] frontv, float[] backv) { + int lerpIndex = 0; + + int[] ovv; + int[] vv; + FloatBuffer lerp = vertexArrayBuf; + + //PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE + | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) { + float[] normal; + int j = 0; + for (int i = 0; i < nverts; i++ /* , v++, ov++, lerp+=4 */ + ) { + normal = r_avertexnormals[verts[i].lightnormalindex]; + ovv = ov[i].v; + vv = v[i].v; + + lerp.put(j, move[0] + ovv[0] * backv[0] + vv[0] * frontv[0] + + normal[0] * Defines.POWERSUIT_SCALE); + lerp.put(j + 1, move[1] + ovv[1] * backv[1] + vv[1] * frontv[1] + + normal[1] * Defines.POWERSUIT_SCALE); + lerp.put(j + 2, move[2] + ovv[2] * backv[2] + vv[2] * frontv[2] + + normal[2] * Defines.POWERSUIT_SCALE); + j += 3; + } + } else { + int j = 0; + for (int i = 0; i < nverts; i++ /* , v++, ov++, lerp+=4 */ + ) { + ovv = ov[i].v; + vv = v[i].v; + + lerp.put(j, move[0] + ovv[0] * backv[0] + vv[0] * frontv[0]); + lerp + .put(j + 1, move[1] + ovv[1] * backv[1] + vv[1] + * frontv[1]); + lerp + .put(j + 2, move[2] + ovv[2] * backv[2] + vv[2] + * frontv[2]); + j += 3; + } + } + } + + FloatBuffer colorArrayBuf = BufferUtils + .newFloatBuffer(qfiles.MAX_VERTS * 4); + + FloatBuffer vertexArrayBuf = BufferUtils + .newFloatBuffer(qfiles.MAX_VERTS * 3); + + boolean isFilled = false; + + float[] tmpVec = { 0, 0, 0 }; + + /* + * ============= GL_DrawAliasFrameLerp + * + * interpolates between two frames and origins FIXME: batch lerp all + * vertexes ============= + */ + void GL_DrawAliasFrameLerp(qfiles.dmdl_t paliashdr, float backlerp) { + float l; + qfiles.daliasframe_t frame, oldframe; + qfiles.dtrivertx_t[] v, ov, verts; + + int[] order; + int orderIndex = 0; + int count; + + float frontlerp; + float alpha; + + float[] move = { 0, 0, 0 }; // vec3_t + float[][] vectors = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } // 3 mal + // vec3_t + }; + + float[] frontv = { 0, 0, 0 }; // vec3_t + float[] backv = { 0, 0, 0 }; // vec3_t + + int i; + int index_xyz; + //float[][] lerp; + + frame = paliashdr.aliasFrames[currententity.frame]; + + verts = v = frame.verts; + + oldframe = paliashdr.aliasFrames[currententity.oldframe]; + + ov = oldframe.verts; + + order = paliashdr.glCmds; + + if ((currententity.flags & Defines.RF_TRANSLUCENT) != 0) + alpha = currententity.alpha; + else + alpha = 1.0f; + + // PMM - added double shell + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE + | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) + gl.glDisable(GL.GL_TEXTURE_2D); + + frontlerp = 1.0f - backlerp; + + // move should be the delta back to the previous frame * backlerp + Math3D.VectorSubtract(currententity.oldorigin, currententity.origin, + frontv); + Math3D.AngleVectors(currententity.angles, vectors[0], vectors[1], + vectors[2]); + + move[0] = Math3D.DotProduct(frontv, vectors[0]); // forward + move[1] = -Math3D.DotProduct(frontv, vectors[1]); // left + move[2] = Math3D.DotProduct(frontv, vectors[2]); // up + + Math3D.VectorAdd(move, oldframe.translate, move); + + for (i = 0; i < 3; i++) { + move[i] = backlerp * move[i] + frontlerp * frame.translate[i]; + frontv[i] = frontlerp * frame.scale[i]; + backv[i] = backlerp * oldframe.scale[i]; + } + + if (gl_vertex_arrays.value != 0.0f) { + GL_LerpVerts(paliashdr.num_xyz, v, ov, verts, move, frontv, backv); + + gl.glEnableClientState(GL.GL_VERTEX_ARRAY); + gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertexArrayBuf); + + // PMM - added double damage shell + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE + | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) { + gl + .glColor4f(shadelight[0], shadelight[1], shadelight[2], + alpha); + } else { + gl.glEnableClientState(GL.GL_COLOR_ARRAY); + gl.glColorPointer(4, GL.GL_FLOAT, 0, colorArrayBuf); + + // + // pre light everything + // + FloatBuffer color = colorArrayBuf; + int j = 0; + for (i = 0; i < paliashdr.num_xyz; i++) { + l = shadedots[verts[i].lightnormalindex]; + color.put(j++, l * shadelight[0]); + color.put(j++, l * shadelight[1]); + color.put(j++, l * shadelight[2]); + color.put(j++, alpha); + } + } + + if (qglLockArraysEXT) + gl.glLockArraysEXT(0, paliashdr.num_xyz); + + while (true) { + // get the vertex count and primitive type + count = order[orderIndex++]; + if (count == 0) + break; // done + if (count < 0) { + count = -count; + gl.glBegin(GL.GL_TRIANGLE_FAN); + } else { + gl.glBegin(GL.GL_TRIANGLE_STRIP); + } + + // PMM - added double damage shell + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE + | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) { + do { + index_xyz = order[orderIndex + 2]; + orderIndex += 3; + /* + * vertexArrayBuf.position(4 * index_xyz); + * vertexArrayBuf.get(tmpVec); gl.glVertex3fv( tmpVec ); + */ + gl.glArrayElement(index_xyz); + + } while (--count != 0); + } else { + do { + // texture coordinates come from the draw list + gl.glTexCoord2f(Float + .intBitsToFloat(order[orderIndex + 0]), Float + .intBitsToFloat(order[orderIndex + 1])); + + index_xyz = order[orderIndex + 2]; + orderIndex += 3; + + // normals and vertexes come from the frame list + gl.glArrayElement(index_xyz); + + } while (--count != 0); + } + gl.glEnd(); + } + + if (qglLockArraysEXT) + gl.glUnlockArraysEXT(); + } else { + GL_LerpVerts(paliashdr.num_xyz, v, ov, verts, s_lerped, move, + frontv, backv); + + float[] tmp; + + while (true) { + // get the vertex count and primitive type + count = order[orderIndex++]; + if (count == 0) + break; // done + if (count < 0) { + count = -count; + gl.glBegin(GL.GL_TRIANGLE_FAN); + } else { + gl.glBegin(GL.GL_TRIANGLE_STRIP); + } + + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE)) != 0) { + do { + index_xyz = order[orderIndex + 2]; + orderIndex += 3; + + gl.glColor4f(shadelight[0], shadelight[1], + shadelight[2], alpha); + tmp = s_lerped[index_xyz]; + gl.glVertex3f(tmp[0], tmp[1], tmp[2]); + + } while (--count != 0); + } else { + do { + // texture coordinates come from the draw list + // gl.glTexCoord2f (((float *)order)[0], ((float + // *)order)[1]); + + gl.glTexCoord2f(Float + .intBitsToFloat(order[orderIndex + 0]), Float + .intBitsToFloat(order[orderIndex + 1])); + index_xyz = order[orderIndex + 2]; + orderIndex += 3; + + // normals and vertexes come from the frame list + l = shadedots[verts[index_xyz].lightnormalindex]; + + gl.glColor4f(l * shadelight[0], l * shadelight[1], l + * shadelight[2], alpha); + tmp = s_lerped[index_xyz]; + gl.glVertex3f(tmp[0], tmp[1], tmp[2]); + } while (--count != 0); + } + gl.glEnd(); + } + } + + // PMM - added double damage shell + if ((currententity.flags & (Defines.RF_SHELL_RED + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE + | Defines.RF_SHELL_DOUBLE | Defines.RF_SHELL_HALF_DAM)) != 0) + gl.glEnable(GL.GL_TEXTURE_2D); + } + + /* + * ============= GL_DrawAliasShadow ============= + */ + void GL_DrawAliasShadow(qfiles.dmdl_t paliashdr, int posenum) { + qfiles.dtrivertx_t[] verts; + int[] order; + float[] point = { 0, 0, 0 }; + float height, lheight; + int count; + qfiles.daliasframe_t frame; + + lheight = currententity.origin[2] - lightspot[2]; + + frame = paliashdr.aliasFrames[currententity.frame]; + + verts = frame.verts; + + height = 0; + + order = paliashdr.glCmds; + + height = -lheight + 1.0f; + + int orderIndex = 0; + int index = 0; + + while (true) { + // get the vertex count and primitive type + count = order[orderIndex++]; + if (count == 0) + break; // done + if (count < 0) { + count = -count; + gl.glBegin(GL.GL_TRIANGLE_FAN); + } else + gl.glBegin(GL.GL_TRIANGLE_STRIP); + + do { + // normals and vertexes come from the frame list + /* + * point[0] = verts[order[2]].v[0] * frame.scale[0] + + * frame.translate[0]; point[1] = verts[order[2]].v[1] * + * frame.scale[1] + frame.translate[1]; point[2] = + * verts[order[2]].v[2] * frame.scale[2] + frame.translate[2]; + */ + + if (gl_vertex_arrays.value != 0.0f) { + index = order[orderIndex + 2] * 3; + point[0] = vertexArrayBuf.get(index); + point[1] = vertexArrayBuf.get(index + 1); + point[2] = vertexArrayBuf.get(index + 2); + } else { + Math3D.VectorCopy(s_lerped[order[orderIndex + 2]], point); + } + + point[0] -= shadevector[0] * (point[2] + lheight); + point[1] -= shadevector[1] * (point[2] + lheight); + point[2] = height; + gl.glVertex3f(point[0], point[1], point[2]); + + orderIndex += 3; + + } while (--count != 0); + + gl.glEnd(); + } + } + + /* + * * R_CullAliasModel + */ + boolean R_CullAliasModel(float[][] bbox, entity_t e) { + int i; + float[] mins = { 0, 0, 0 }; + float[] maxs = { 0, 0, 0 }; + + qfiles.dmdl_t paliashdr; + + float[][] vectors = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; + + float[] thismins = { 0, 0, 0 }; + float[] oldmins = { 0, 0, 0 }; + float[] thismaxs = { 0, 0, 0 }; + float[] oldmaxs = { 0, 0, 0 }; + qfiles.daliasframe_t pframe, poldframe; + float[] angles = { 0, 0, 0 }; + + paliashdr = (qfiles.dmdl_t) currentmodel.extradata; + + if ((e.frame >= paliashdr.num_frames) || (e.frame < 0)) { + VID.Printf(Defines.PRINT_ALL, "R_CullAliasModel " + + currentmodel.name + ": no such frame " + e.frame + '\n'); + e.frame = 0; + } + if ((e.oldframe >= paliashdr.num_frames) || (e.oldframe < 0)) { + VID.Printf(Defines.PRINT_ALL, "R_CullAliasModel " + + currentmodel.name + ": no such oldframe " + e.oldframe + + '\n'); + e.oldframe = 0; + } + + pframe = paliashdr.aliasFrames[e.frame]; + poldframe = paliashdr.aliasFrames[e.oldframe]; + + /* + * * compute axially aligned mins and maxs + */ + if (pframe == poldframe) { + for (i = 0; i < 3; i++) { + mins[i] = pframe.translate[i]; + maxs[i] = mins[i] + pframe.scale[i] * 255; + } + } else { + for (i = 0; i < 3; i++) { + thismins[i] = pframe.translate[i]; + thismaxs[i] = thismins[i] + pframe.scale[i] * 255; + + oldmins[i] = poldframe.translate[i]; + oldmaxs[i] = oldmins[i] + poldframe.scale[i] * 255; + + if (thismins[i] < oldmins[i]) + mins[i] = thismins[i]; + else + mins[i] = oldmins[i]; + + if (thismaxs[i] > oldmaxs[i]) + maxs[i] = thismaxs[i]; + else + maxs[i] = oldmaxs[i]; + } + } + + /* + * * compute a full bounding box + */ + for (i = 0; i < 8; i++) { + float[] tmp = { 0, 0, 0 }; + + if ((i & 1) != 0) + tmp[0] = mins[0]; + else + tmp[0] = maxs[0]; + + if ((i & 2) != 0) + tmp[1] = mins[1]; + else + tmp[1] = maxs[1]; + + if ((i & 4) != 0) + tmp[2] = mins[2]; + else + tmp[2] = maxs[2]; + + Math3D.VectorCopy(tmp, bbox[i]); + } + + /* + * * rotate the bounding box + */ + Math3D.VectorCopy(e.angles, angles); + angles[YAW] = -angles[YAW]; + Math3D.AngleVectors(angles, vectors[0], vectors[1], vectors[2]); + + for (i = 0; i < 8; i++) { + float[] tmp = { 0, 0, 0 }; + + Math3D.VectorCopy(bbox[i], tmp); + + bbox[i][0] = Math3D.DotProduct(vectors[0], tmp); + bbox[i][1] = -Math3D.DotProduct(vectors[1], tmp); + bbox[i][2] = Math3D.DotProduct(vectors[2], tmp); + + Math3D.VectorAdd(e.origin, bbox[i], bbox[i]); + } + + { + int p, f; + int aggregatemask = ~0; // 0xFFFFFFFF + + for (p = 0; p < 8; p++) { + int mask = 0; + + for (f = 0; f < 4; f++) { + float dp = Math3D.DotProduct(frustum[f].normal, bbox[p]); + + if ((dp - frustum[f].dist) < 0) { + mask |= (1 << f); + } + } + + aggregatemask &= mask; + } + + if (aggregatemask != 0) { + return true; + } + + return false; + } + } + + /* + * ================= R_DrawAliasModel + * + * ================= + */ + void R_DrawAliasModel(entity_t e) { + int i; + qfiles.dmdl_t paliashdr; + float an; + + // bounding box + float[][] bbox = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, + { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; + image_t skin; + + if ((e.flags & Defines.RF_WEAPONMODEL) == 0) { + if (R_CullAliasModel(bbox, e)) + return; + } + + if ((e.flags & Defines.RF_WEAPONMODEL) != 0) { + if (r_lefthand.value == 2.0f) + return; + } + + paliashdr = (qfiles.dmdl_t) currentmodel.extradata; + + // + // get lighting information + // + // PMM - rewrote, reordered to handle new shells & mixing + // PMM - 3.20 code .. replaced with original way of doing it to keep mod + // authors happy + // + if ((currententity.flags & (Defines.RF_SHELL_HALF_DAM + | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_RED + | Defines.RF_SHELL_BLUE | Defines.RF_SHELL_DOUBLE)) != 0) { + Math3D.VectorClear(shadelight); + if ((currententity.flags & Defines.RF_SHELL_HALF_DAM) != 0) { + shadelight[0] = 0.56f; + shadelight[1] = 0.59f; + shadelight[2] = 0.45f; + } + if ((currententity.flags & Defines.RF_SHELL_DOUBLE) != 0) { + shadelight[0] = 0.9f; + shadelight[1] = 0.7f; + } + if ((currententity.flags & Defines.RF_SHELL_RED) != 0) + shadelight[0] = 1.0f; + if ((currententity.flags & Defines.RF_SHELL_GREEN) != 0) + shadelight[1] = 1.0f; + if ((currententity.flags & Defines.RF_SHELL_BLUE) != 0) + shadelight[2] = 1.0f; + } + + else if ((currententity.flags & Defines.RF_FULLBRIGHT) != 0) { + for (i = 0; i < 3; i++) + shadelight[i] = 1.0f; + } else { + R_LightPoint(currententity.origin, shadelight); + + // player lighting hack for communication back to server + // big hack! + if ((currententity.flags & Defines.RF_WEAPONMODEL) != 0) { + // pick the greatest component, which should be the same + // as the mono value returned by software + if (shadelight[0] > shadelight[1]) { + if (shadelight[0] > shadelight[2]) + r_lightlevel.value = 150 * shadelight[0]; + else + r_lightlevel.value = 150 * shadelight[2]; + } else { + if (shadelight[1] > shadelight[2]) + r_lightlevel.value = 150 * shadelight[1]; + else + r_lightlevel.value = 150 * shadelight[2]; + } + } + + if (gl_monolightmap.string.charAt(0) != '0') { + float s = shadelight[0]; + + if (s < shadelight[1]) + s = shadelight[1]; + if (s < shadelight[2]) + s = shadelight[2]; + + shadelight[0] = s; + shadelight[1] = s; + shadelight[2] = s; + } + } + + if ((currententity.flags & Defines.RF_MINLIGHT) != 0) { + for (i = 0; i < 3; i++) + if (shadelight[i] > 0.1f) + break; + if (i == 3) { + shadelight[0] = 0.1f; + shadelight[1] = 0.1f; + shadelight[2] = 0.1f; + } + } + + if ((currententity.flags & Defines.RF_GLOW) != 0) { // bonus items will + // pulse with time + float scale; + float min; + + scale = (float) (0.1f * Math.sin(r_newrefdef.time * 7)); + for (i = 0; i < 3; i++) { + min = shadelight[i] * 0.8f; + shadelight[i] += scale; + if (shadelight[i] < min) + shadelight[i] = min; + } + } + + // ================= + // PGM ir goggles color override + if ((r_newrefdef.rdflags & Defines.RDF_IRGOGGLES) != 0 + && (currententity.flags & Defines.RF_IR_VISIBLE) != 0) { + shadelight[0] = 1.0f; + shadelight[1] = 0.0f; + shadelight[2] = 0.0f; + } + // PGM + // ================= + + shadedots = r_avertexnormal_dots[((int) (currententity.angles[1] * (SHADEDOT_QUANT / 360.0))) + & (SHADEDOT_QUANT - 1)]; + + an = (float) (currententity.angles[1] / 180 * Math.PI); + shadevector[0] = (float) Math.cos(-an); + shadevector[1] = (float) Math.sin(-an); + shadevector[2] = 1; + Math3D.VectorNormalize(shadevector); + + // + // locate the proper data + // + + c_alias_polys += paliashdr.num_tris; + + // + // draw all the triangles + // + if ((currententity.flags & Defines.RF_DEPTHHACK) != 0) + // hack the depth range to prevent view model from poking into walls + gl.glDepthRange(gldepthmin, gldepthmin + 0.3 + * (gldepthmax - gldepthmin)); + + if ((currententity.flags & Defines.RF_WEAPONMODEL) != 0 + && (r_lefthand.value == 1.0f)) { + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glPushMatrix(); + gl.glLoadIdentity(); + gl.glScalef(-1, 1, 1); + MYgluPerspective(r_newrefdef.fov_y, (float) r_newrefdef.width + / r_newrefdef.height, 4, 4096); + gl.glMatrixMode(GL.GL_MODELVIEW); + + gl.glCullFace(GL.GL_BACK); + } + + gl.glPushMatrix(); + e.angles[PITCH] = -e.angles[PITCH]; // sigh. + R_RotateForEntity(e); + e.angles[PITCH] = -e.angles[PITCH]; // sigh. + + // select skin + if (currententity.skin != null) + skin = currententity.skin; // custom player skin + else { + if (currententity.skinnum >= qfiles.MAX_MD2SKINS) + skin = currentmodel.skins[0]; + else { + skin = currentmodel.skins[currententity.skinnum]; + if (skin == null) + skin = currentmodel.skins[0]; + } + } + if (skin == null) + skin = r_notexture; // fallback... + GL_Bind(skin.texnum); + + // draw it + + gl.glShadeModel(GL.GL_SMOOTH); + + GL_TexEnv(GL.GL_MODULATE); + if ((currententity.flags & Defines.RF_TRANSLUCENT) != 0) { + gl.glEnable(GL.GL_BLEND); + } + + if ((currententity.frame >= paliashdr.num_frames) + || (currententity.frame < 0)) { + VID.Printf(Defines.PRINT_ALL, "R_DrawAliasModel " + + currentmodel.name + ": no such frame " + + currententity.frame + '\n'); + currententity.frame = 0; + currententity.oldframe = 0; + } + + if ((currententity.oldframe >= paliashdr.num_frames) + || (currententity.oldframe < 0)) { + VID.Printf(Defines.PRINT_ALL, "R_DrawAliasModel " + + currentmodel.name + ": no such oldframe " + + currententity.oldframe + '\n'); + currententity.frame = 0; + currententity.oldframe = 0; + } + + if (r_lerpmodels.value == 0.0f) + currententity.backlerp = 0; + GL_DrawAliasFrameLerp(paliashdr, currententity.backlerp); + + GL_TexEnv(GL.GL_REPLACE); + gl.glShadeModel(GL.GL_FLAT); + + gl.glPopMatrix(); + + if ((currententity.flags & Defines.RF_WEAPONMODEL) != 0 + && (r_lefthand.value == 1.0F)) { + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glPopMatrix(); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glCullFace(GL.GL_FRONT); + } + + if ((currententity.flags & Defines.RF_TRANSLUCENT) != 0) { + gl.glDisable(GL.GL_BLEND); + } + + if ((currententity.flags & Defines.RF_DEPTHHACK) != 0) + gl.glDepthRange(gldepthmin, gldepthmax); + + if (gl_shadows.value != 0.0f + && (currententity.flags & (Defines.RF_TRANSLUCENT | Defines.RF_WEAPONMODEL)) == 0) { + gl.glPushMatrix(); + R_RotateForEntity(e); + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glEnable(GL.GL_BLEND); + gl.glColor4f(0, 0, 0, 0.5f); + GL_DrawAliasShadow(paliashdr, currententity.frame); + gl.glEnable(GL.GL_TEXTURE_2D); + gl.glDisable(GL.GL_BLEND); + gl.glPopMatrix(); + } + gl.glColor4f(1, 1, 1, 1); + } + +} \ No newline at end of file diff --git a/src/jake2/render/jogl/Warp.java b/src/jake2/render/jogl/Warp.java index cd926c6..bde9697 100644 --- a/src/jake2/render/jogl/Warp.java +++ b/src/jake2/render/jogl/Warp.java @@ -2,720 +2,667 @@ * Warp.java * Copyright (C) 2003 * - * $Id: Warp.java,v 1.6 2004-07-16 10:11:35 cawe Exp $ + * $Id: Warp.java,v 1.7 2004-09-22 19:22:16 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.render.jogl; import jake2.Defines; import jake2.Globals; import jake2.qcommon.Com; -import jake2.render.*; +import jake2.render.glpoly_t; +import jake2.render.image_t; +import jake2.render.msurface_t; import jake2.util.Math3D; import net.java.games.jogl.GL; /** * Warp - * + * * @author cwei */ public abstract class Warp extends Model { - - - // warpsin.h - public static final float[] SIN = { - 0f, 0.19633f, 0.392541f, 0.588517f, 0.784137f, 0.979285f, 1.17384f, 1.3677f, - 1.56072f, 1.75281f, 1.94384f, 2.1337f, 2.32228f, 2.50945f, 2.69512f, 2.87916f, - 3.06147f, 3.24193f, 3.42044f, 3.59689f, 3.77117f, 3.94319f, 4.11282f, 4.27998f, - 4.44456f, 4.60647f, 4.76559f, 4.92185f, 5.07515f, 5.22538f, 5.37247f, 5.51632f, - 5.65685f, 5.79398f, 5.92761f, 6.05767f, 6.18408f, 6.30677f, 6.42566f, 6.54068f, - 6.65176f, 6.75883f, 6.86183f, 6.9607f, 7.05537f, 7.14579f, 7.23191f, 7.31368f, - 7.39104f, 7.46394f, 7.53235f, 7.59623f, 7.65552f, 7.71021f, 7.76025f, 7.80562f, - 7.84628f, 7.88222f, 7.91341f, 7.93984f, 7.96148f, 7.97832f, 7.99036f, 7.99759f, - 8f, 7.99759f, 7.99036f, 7.97832f, 7.96148f, 7.93984f, 7.91341f, 7.88222f, - 7.84628f, 7.80562f, 7.76025f, 7.71021f, 7.65552f, 7.59623f, 7.53235f, 7.46394f, - 7.39104f, 7.31368f, 7.23191f, 7.14579f, 7.05537f, 6.9607f, 6.86183f, 6.75883f, - 6.65176f, 6.54068f, 6.42566f, 6.30677f, 6.18408f, 6.05767f, 5.92761f, 5.79398f, - 5.65685f, 5.51632f, 5.37247f, 5.22538f, 5.07515f, 4.92185f, 4.76559f, 4.60647f, - 4.44456f, 4.27998f, 4.11282f, 3.94319f, 3.77117f, 3.59689f, 3.42044f, 3.24193f, - 3.06147f, 2.87916f, 2.69512f, 2.50945f, 2.32228f, 2.1337f, 1.94384f, 1.75281f, - 1.56072f, 1.3677f, 1.17384f, 0.979285f, 0.784137f, 0.588517f, 0.392541f, 0.19633f, - 9.79717e-16f, -0.19633f, -0.392541f, -0.588517f, -0.784137f, -0.979285f, -1.17384f, -1.3677f, - -1.56072f, -1.75281f, -1.94384f, -2.1337f, -2.32228f, -2.50945f, -2.69512f, -2.87916f, - -3.06147f, -3.24193f, -3.42044f, -3.59689f, -3.77117f, -3.94319f, -4.11282f, -4.27998f, - -4.44456f, -4.60647f, -4.76559f, -4.92185f, -5.07515f, -5.22538f, -5.37247f, -5.51632f, - -5.65685f, -5.79398f, -5.92761f, -6.05767f, -6.18408f, -6.30677f, -6.42566f, -6.54068f, - -6.65176f, -6.75883f, -6.86183f, -6.9607f, -7.05537f, -7.14579f, -7.23191f, -7.31368f, - -7.39104f, -7.46394f, -7.53235f, -7.59623f, -7.65552f, -7.71021f, -7.76025f, -7.80562f, - -7.84628f, -7.88222f, -7.91341f, -7.93984f, -7.96148f, -7.97832f, -7.99036f, -7.99759f, - -8f, -7.99759f, -7.99036f, -7.97832f, -7.96148f, -7.93984f, -7.91341f, -7.88222f, - -7.84628f, -7.80562f, -7.76025f, -7.71021f, -7.65552f, -7.59623f, -7.53235f, -7.46394f, - -7.39104f, -7.31368f, -7.23191f, -7.14579f, -7.05537f, -6.9607f, -6.86183f, -6.75883f, - -6.65176f, -6.54068f, -6.42566f, -6.30677f, -6.18408f, -6.05767f, -5.92761f, -5.79398f, - -5.65685f, -5.51632f, -5.37247f, -5.22538f, -5.07515f, -4.92185f, -4.76559f, -4.60647f, - -4.44456f, -4.27998f, -4.11282f, -3.94319f, -3.77117f, -3.59689f, -3.42044f, -3.24193f, - -3.06147f, -2.87916f, -2.69512f, -2.50945f, -2.32228f, -2.1337f, -1.94384f, -1.75281f, - -1.56072f, -1.3677f, -1.17384f, -0.979285f, -0.784137f, -0.588517f, -0.392541f, -0.19633f - }; - - // gl_warp.c -- sky and water polygons - //extern model_t *loadmodel; // Model.java - - String skyname; - float skyrotate; - float[] skyaxis = {0, 0, 0}; - image_t[] sky_images = new image_t[6]; - - msurface_t warpface; - - static final int SUBDIVIDE_SIZE = 64; - - void BoundPoly(int numverts, float[][] verts, float[] mins, float[] maxs) - { - int i, j; - float[] v; - - mins[0] = mins[1] = mins[2] = 9999; - maxs[0] = maxs[1] = maxs[2] = -9999; - for (i=0 ; i maxs[j]) - maxs[j] = v[j]; - } - } - } - - void SubdividePolygon(int numverts, float[][] verts) - { - int i, j, k; - float[] mins = {0, 0, 0}; - float[] maxs = {0, 0, 0}; - float m; - float[] v = {0, 0, 0}; - float[][] front = new float[64][3]; - float[][] back = new float[64][3]; - - int f, b; - float[] dist = new float[64]; - float frac; - float s, t; - float[] total = {0, 0, 0}; - float total_s, total_t; - - if (numverts > 60) - Com.Error(Defines.ERR_DROP, "numverts = " + numverts); - - BoundPoly(numverts, verts, mins, maxs); - - // x,y und z - for (i=0 ; i<3 ; i++) - { - m = (mins[i] + maxs[i]) * 0.5f; - m = SUBDIVIDE_SIZE * (float)Math.floor(m / SUBDIVIDE_SIZE + 0.5f); - if (maxs[i] - m < 8) - continue; - if (m - mins[i] < 8) - continue; - - // cut it - for (j=0 ; j= 0) - { - Math3D.VectorCopy(v, front[f]); - f++; - } - if (dist[j] <= 0) - { - Math3D.VectorCopy(v, back[b]); - b++; - } - if (dist[j] == 0 || dist[j+1] == 0) continue; - - if ( (dist[j] > 0) != (dist[j+1] > 0) ) - { - // clip point - frac = dist[j] / (dist[j] - dist[j+1]); - for (k=0 ; k<3 ; k++) - front[f][k] = back[b][k] = v[k] + frac*(verts[j+1][k] - v[k]); - - f++; - b++; - } - } - - SubdividePolygon(f, front); - SubdividePolygon(b, back); - return; - } - - // add a point in the center to help keep warp valid - - // wird im Konstruktor erschlagen - // poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * VERTEXSIZE*sizeof(float)); - - // init polys - glpoly_t poly = new glpoly_t(numverts + 2); - - poly.next = warpface.polys; - warpface.polys = poly; - poly.numverts = numverts + 2; - Math3D.VectorClear(total); - total_s = 0; - total_t = 0; - for (i=0 ; i 0) - vec = loadmodel.vertexes[loadmodel.edges[lindex].v[0]].position; - else - vec = loadmodel.vertexes[loadmodel.edges[-lindex].v[1]].position; - Math3D.VectorCopy(vec, verts[numverts]); - numverts++; - } - - SubdividePolygon(numverts, verts); - } - -// ========================================================= - - - -//// speed up sin calculations - Ed -// float r_turbsin[] = -// { -// #include "warpsin.h" -// }; - static final float TURBSCALE = (float)(256.0f / (2 * Math.PI)); - - /* - ============= - EmitWaterPolys - - Does a water warp on the pre-fragmented glpoly_t chain - ============= - */ - void EmitWaterPolys(msurface_t fa) - { - glpoly_t p, bp; - float[] v; - int i; - float s = 0; - float t = 0; - float os, ot; - float scroll; - float rdt = r_newrefdef.time; - - if ((fa.texinfo.flags & Defines.SURF_FLOWING) != 0) - scroll = -64 * ( (r_newrefdef.time*0.5f) - (int)(r_newrefdef.time*0.5f) ); - else - scroll = 0; - for (bp=fa.polys ; bp != null ; bp=bp.next) - { - p = bp; - - gl.glBegin(GL.GL_TRIANGLE_FAN); - for (i=0; i av[1] && av[0] > av[2]) - { - if (v[0] < 0) - axis = 1; - else - axis = 0; - } - else if (av[1] > av[2] && av[1] > av[0]) - { - if (v[1] < 0) - axis = 3; - else - axis = 2; - } - else - { - if (v[2] < 0) - axis = 5; - else - axis = 4; - } - - // project new texture coords - for (i=0 ; i 0) - dv = vecs[i][j - 1]; - else - dv = -vecs[i][-j - 1]; - if (dv < 0.001f) - continue; // don't divide by zero - j = vec_to_st[axis][0]; - if (j < 0) - s = -vecs[i][-j -1] / dv; - else - s = vecs[i][j-1] / dv; - j = vec_to_st[axis][1]; - if (j < 0) - t = -vecs[i][-j -1] / dv; - else - t = vecs[i][j-1] / dv; - - if (s < skymins[0][axis]) - skymins[0][axis] = s; - if (t < skymins[1][axis]) - skymins[1][axis] = t; - if (s > skymaxs[0][axis]) - skymaxs[0][axis] = s; - if (t > skymaxs[1][axis]) - skymaxs[1][axis] = t; - } - } - - static final float ON_EPSILON = 0.1f; // point on plane side epsilon - static final int MAX_CLIP_VERTS = 64; - - static final int SIDE_BACK = 1; - static final int SIDE_FRONT = 0; - static final int SIDE_ON = 2; - - float[] dists = new float[MAX_CLIP_VERTS]; - int[] sides = new int[MAX_CLIP_VERTS]; - float[][][][] newv = new float[6][2][MAX_CLIP_VERTS][3]; - - void ClipSkyPolygon(int nump, float[][] vecs, int stage) - { - float[] norm; - float[] v; - boolean front, back; - float d, e; - int[] newc = { 0, 0 }; - int i, j; - - if (nump > MAX_CLIP_VERTS-2) - Com.Error(Defines.ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); - if (stage == 6) - { // fully clipped, so draw it - DrawSkyPolygon(nump, vecs); - return; - } - - front = back = false; - norm = skyclip[stage]; - for (i=0 ; i ON_EPSILON) - { - front = true; - sides[i] = SIDE_FRONT; - } - else if (d < -ON_EPSILON) - { - back = true; - sides[i] = SIDE_BACK; - } - else - sides[i] = SIDE_ON; - dists[i] = d; - } - - if (!front || !back) - { // not clipped - ClipSkyPolygon (nump, vecs, stage+1); - return; - } - - // clip it - sides[i] = sides[0]; - dists[i] = dists[0]; - Math3D.VectorCopy(vecs[0], vecs[i]); - newc[0] = newc[1] = 0; - - for (i=0; i sky_max) - s = sky_max; - if (t < sky_min) - t = sky_min; - else if (t > sky_max) - t = sky_max; - - t = 1.0f - t; - gl.glTexCoord2f (s, t); - gl.glVertex3f(v[0], v[1], v[2]); - } - - /* - ============== - R_DrawSkyBox - ============== - */ - int[] skytexorder = {0,2,1,3,4,5}; - - void R_DrawSkyBox() - { - int i; - - if (skyrotate != 0) - { // check for no sky at all - for (i=0 ; i<6 ; i++) - if (skymins[0][i] < skymaxs[0][i] - && skymins[1][i] < skymaxs[1][i]) - break; - if (i == 6) - return; // nothing visible - } - - gl.glPushMatrix (); - gl.glTranslatef (r_origin[0], r_origin[1], r_origin[2]); - gl.glRotatef (r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]); - - for (i=0 ; i<6 ; i++) - { - if (skyrotate != 0) - { // hack, forces full sky to draw when rotating - skymins[0][i] = -1; - skymins[1][i] = -1; - skymaxs[0][i] = 1; - skymaxs[1][i] = 1; - } - - if (skymins[0][i] >= skymaxs[0][i] - || skymins[1][i] >= skymaxs[1][i]) - continue; - - GL_Bind(sky_images[skytexorder[i]].texnum); - - gl.glBegin(GL.GL_QUADS); - MakeSkyVec(skymins[0][i], skymins[1][i], i); - MakeSkyVec(skymins[0][i], skymaxs[1][i], i); - MakeSkyVec(skymaxs[0][i], skymaxs[1][i], i); - MakeSkyVec(skymaxs[0][i], skymins[1][i], i); - gl.glEnd (); - } - gl.glPopMatrix (); - } - - - /* - ============ - R_SetSky - ============ - */ - // 3dstudio environment map names - String[] suf = {"rt", "bk", "lf", "ft", "up", "dn"}; - - protected void R_SetSky(String name, float rotate, float[] axis) - { - assert (axis.length == 3) : "vec3_t bug"; - int i; - String pathname; - -// strncpy (skyname, name, sizeof(skyname)-1); - skyname = name; - - skyrotate = rotate; - Math3D.VectorCopy(axis, skyaxis); - - for (i=0 ; i<6 ; i++) - { - // chop down rotating skies for less memory - if (gl_skymip.value != 0 || skyrotate != 0) - gl_picmip.value++; - - if ( qglColorTableEXT && gl_ext_palettedtexture.value != 0) { - // Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[i]); - pathname = "env/" + skyname + suf[i] + ".pcx"; - } else { - // Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga", skyname, suf[i]); - pathname = "env/" + skyname + suf[i] + ".tga"; - } - - sky_images[i] = GL_FindImage(pathname, it_sky); - - if (sky_images[i] == null) - sky_images[i] = r_notexture; - - if (gl_skymip.value != 0 || skyrotate != 0) - { // take less memory - gl_picmip.value--; - sky_min = 1.0f / 256; - sky_max = 255.0f / 256; - } - else - { - sky_min = 1.0f / 512; - sky_max = 511.0f / 512; - } - } - } - - -} + + // warpsin.h + public static final float[] SIN = { 0f, 0.19633f, 0.392541f, 0.588517f, + 0.784137f, 0.979285f, 1.17384f, 1.3677f, 1.56072f, 1.75281f, + 1.94384f, 2.1337f, 2.32228f, 2.50945f, 2.69512f, 2.87916f, + 3.06147f, 3.24193f, 3.42044f, 3.59689f, 3.77117f, 3.94319f, + 4.11282f, 4.27998f, 4.44456f, 4.60647f, 4.76559f, 4.92185f, + 5.07515f, 5.22538f, 5.37247f, 5.51632f, 5.65685f, 5.79398f, + 5.92761f, 6.05767f, 6.18408f, 6.30677f, 6.42566f, 6.54068f, + 6.65176f, 6.75883f, 6.86183f, 6.9607f, 7.05537f, 7.14579f, + 7.23191f, 7.31368f, 7.39104f, 7.46394f, 7.53235f, 7.59623f, + 7.65552f, 7.71021f, 7.76025f, 7.80562f, 7.84628f, 7.88222f, + 7.91341f, 7.93984f, 7.96148f, 7.97832f, 7.99036f, 7.99759f, 8f, + 7.99759f, 7.99036f, 7.97832f, 7.96148f, 7.93984f, 7.91341f, + 7.88222f, 7.84628f, 7.80562f, 7.76025f, 7.71021f, 7.65552f, + 7.59623f, 7.53235f, 7.46394f, 7.39104f, 7.31368f, 7.23191f, + 7.14579f, 7.05537f, 6.9607f, 6.86183f, 6.75883f, 6.65176f, + 6.54068f, 6.42566f, 6.30677f, 6.18408f, 6.05767f, 5.92761f, + 5.79398f, 5.65685f, 5.51632f, 5.37247f, 5.22538f, 5.07515f, + 4.92185f, 4.76559f, 4.60647f, 4.44456f, 4.27998f, 4.11282f, + 3.94319f, 3.77117f, 3.59689f, 3.42044f, 3.24193f, 3.06147f, + 2.87916f, 2.69512f, 2.50945f, 2.32228f, 2.1337f, 1.94384f, + 1.75281f, 1.56072f, 1.3677f, 1.17384f, 0.979285f, 0.784137f, + 0.588517f, 0.392541f, 0.19633f, 9.79717e-16f, -0.19633f, + -0.392541f, -0.588517f, -0.784137f, -0.979285f, -1.17384f, + -1.3677f, -1.56072f, -1.75281f, -1.94384f, -2.1337f, -2.32228f, + -2.50945f, -2.69512f, -2.87916f, -3.06147f, -3.24193f, -3.42044f, + -3.59689f, -3.77117f, -3.94319f, -4.11282f, -4.27998f, -4.44456f, + -4.60647f, -4.76559f, -4.92185f, -5.07515f, -5.22538f, -5.37247f, + -5.51632f, -5.65685f, -5.79398f, -5.92761f, -6.05767f, -6.18408f, + -6.30677f, -6.42566f, -6.54068f, -6.65176f, -6.75883f, -6.86183f, + -6.9607f, -7.05537f, -7.14579f, -7.23191f, -7.31368f, -7.39104f, + -7.46394f, -7.53235f, -7.59623f, -7.65552f, -7.71021f, -7.76025f, + -7.80562f, -7.84628f, -7.88222f, -7.91341f, -7.93984f, -7.96148f, + -7.97832f, -7.99036f, -7.99759f, -8f, -7.99759f, -7.99036f, + -7.97832f, -7.96148f, -7.93984f, -7.91341f, -7.88222f, -7.84628f, + -7.80562f, -7.76025f, -7.71021f, -7.65552f, -7.59623f, -7.53235f, + -7.46394f, -7.39104f, -7.31368f, -7.23191f, -7.14579f, -7.05537f, + -6.9607f, -6.86183f, -6.75883f, -6.65176f, -6.54068f, -6.42566f, + -6.30677f, -6.18408f, -6.05767f, -5.92761f, -5.79398f, -5.65685f, + -5.51632f, -5.37247f, -5.22538f, -5.07515f, -4.92185f, -4.76559f, + -4.60647f, -4.44456f, -4.27998f, -4.11282f, -3.94319f, -3.77117f, + -3.59689f, -3.42044f, -3.24193f, -3.06147f, -2.87916f, -2.69512f, + -2.50945f, -2.32228f, -2.1337f, -1.94384f, -1.75281f, -1.56072f, + -1.3677f, -1.17384f, -0.979285f, -0.784137f, -0.588517f, + -0.392541f, -0.19633f }; + + // gl_warp.c -- sky and water polygons + //extern model_t *loadmodel; // Model.java + + String skyname; + + float skyrotate; + + float[] skyaxis = { 0, 0, 0 }; + + image_t[] sky_images = new image_t[6]; + + msurface_t warpface; + + static final int SUBDIVIDE_SIZE = 64; + + void BoundPoly(int numverts, float[][] verts, float[] mins, float[] maxs) { + int i, j; + float[] v; + + mins[0] = mins[1] = mins[2] = 9999; + maxs[0] = maxs[1] = maxs[2] = -9999; + for (i = 0; i < numverts; i++) { + v = verts[i]; + for (j = 0; j < 3; j++) { + if (v[j] < mins[j]) + mins[j] = v[j]; + if (v[j] > maxs[j]) + maxs[j] = v[j]; + } + } + } + + void SubdividePolygon(int numverts, float[][] verts) { + int i, j, k; + float[] mins = { 0, 0, 0 }; + float[] maxs = { 0, 0, 0 }; + float m; + float[] v = { 0, 0, 0 }; + float[][] front = new float[64][3]; + float[][] back = new float[64][3]; + + int f, b; + float[] dist = new float[64]; + float frac; + float s, t; + float[] total = { 0, 0, 0 }; + float total_s, total_t; + + if (numverts > 60) + Com.Error(Defines.ERR_DROP, "numverts = " + numverts); + + BoundPoly(numverts, verts, mins, maxs); + + // x,y und z + for (i = 0; i < 3; i++) { + m = (mins[i] + maxs[i]) * 0.5f; + m = SUBDIVIDE_SIZE * (float) Math.floor(m / SUBDIVIDE_SIZE + 0.5f); + if (maxs[i] - m < 8) + continue; + if (m - mins[i] < 8) + continue; + + // cut it + for (j = 0; j < numverts; j++) { + dist[j] = verts[j][i] - m; + } + + // wrap cases + dist[j] = dist[0]; + + Math3D.VectorCopy(verts[0], verts[numverts]); + + f = b = 0; + for (j = 0; j < numverts; j++) { + v = verts[j]; + if (dist[j] >= 0) { + Math3D.VectorCopy(v, front[f]); + f++; + } + if (dist[j] <= 0) { + Math3D.VectorCopy(v, back[b]); + b++; + } + if (dist[j] == 0 || dist[j + 1] == 0) + continue; + + if ((dist[j] > 0) != (dist[j + 1] > 0)) { + // clip point + frac = dist[j] / (dist[j] - dist[j + 1]); + for (k = 0; k < 3; k++) + front[f][k] = back[b][k] = v[k] + frac + * (verts[j + 1][k] - v[k]); + + f++; + b++; + } + } + + SubdividePolygon(f, front); + SubdividePolygon(b, back); + return; + } + + // add a point in the center to help keep warp valid + + // wird im Konstruktor erschlagen + // poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * + // VERTEXSIZE*sizeof(float)); + + // init polys + glpoly_t poly = new glpoly_t(numverts + 2); + + poly.next = warpface.polys; + warpface.polys = poly; + poly.numverts = numverts + 2; + Math3D.VectorClear(total); + total_s = 0; + total_t = 0; + for (i = 0; i < numverts; i++) { + Math3D.VectorCopy(verts[i], poly.verts[i + 1]); + s = Math3D.DotProduct(verts[i], warpface.texinfo.vecs[0]); + t = Math3D.DotProduct(verts[i], warpface.texinfo.vecs[1]); + + total_s += s; + total_t += t; + Math3D.VectorAdd(total, verts[i], total); + + poly.verts[i + 1][3] = s; + poly.verts[i + 1][4] = t; + } + + Math3D.VectorScale(total, (1.0f / numverts), poly.verts[0]); + poly.verts[0][3] = total_s / numverts; + poly.verts[0][4] = total_t / numverts; + + // memcpy (poly.verts[i+1], poly.verts[1], sizeof(poly.verts[0])); + System.arraycopy(poly.verts[1], 0, poly.verts[i + 1], 0, + poly.verts[1].length); // :-) + } + + /* + * ================ GL_SubdivideSurface + * + * Breaks a polygon up along axial 64 unit boundaries so that turbulent and + * sky warps can be done reasonably. ================ + */ + void GL_SubdivideSurface(msurface_t fa) { + float[][] verts = new float[64][3]; + + int numverts; + int i; + int lindex; + float[] vec; + + warpface = fa; + + // + // convert edges back to a normal polygon + // + numverts = 0; + for (i = 0; i < fa.numedges; i++) { + lindex = loadmodel.surfedges[fa.firstedge + i]; + + if (lindex > 0) + vec = loadmodel.vertexes[loadmodel.edges[lindex].v[0]].position; + else + vec = loadmodel.vertexes[loadmodel.edges[-lindex].v[1]].position; + Math3D.VectorCopy(vec, verts[numverts]); + numverts++; + } + + SubdividePolygon(numverts, verts); + } + + // ========================================================= + + //// speed up sin calculations - Ed + // float r_turbsin[] = + // { + // #include "warpsin.h" + // }; + static final float TURBSCALE = (float) (256.0f / (2 * Math.PI)); + + /* + * ============= EmitWaterPolys + * + * Does a water warp on the pre-fragmented glpoly_t chain ============= + */ + void EmitWaterPolys(msurface_t fa) { + glpoly_t p, bp; + float[] v; + int i; + float s = 0; + float t = 0; + float os, ot; + float scroll; + float rdt = r_newrefdef.time; + + if ((fa.texinfo.flags & Defines.SURF_FLOWING) != 0) + scroll = -64 + * ((r_newrefdef.time * 0.5f) - (int) (r_newrefdef.time * 0.5f)); + else + scroll = 0; + for (bp = fa.polys; bp != null; bp = bp.next) { + p = bp; + + gl.glBegin(GL.GL_TRIANGLE_FAN); + for (i = 0; i < p.numverts; i++) { + v = p.verts[i]; + os = v[3]; + ot = v[4]; + + s = os + + Warp.SIN[(int) ((ot * 0.125f + r_newrefdef.time) * TURBSCALE) & 255]; + s += scroll; + s *= (1.0f / 64); + + t = ot + + Warp.SIN[(int) ((os * 0.125f + rdt) * TURBSCALE) & 255]; + t *= (1.0f / 64); + + gl.glTexCoord2f(s, t); + gl.glVertex3f(v[0], v[1], v[2]); + } + gl.glEnd(); + } + } + + // =================================================================== + + float[][] skyclip = { { 1, 1, 0 }, { 1, -1, 0 }, { 0, -1, 1 }, { 0, 1, 1 }, + { 1, 0, 1 }, { -1, 0, 1 } }; + + int c_sky; + + // 1 = s, 2 = t, 3 = 2048 + int[][] st_to_vec = { { 3, -1, 2 }, { -3, 1, 2 }, + + { 1, 3, 2 }, { -1, -3, 2 }, + + { -2, -1, 3 }, // 0 degrees yaw, look straight up + { 2, -1, -3 } // look straight down + + }; + + int[][] vec_to_st = { { -2, 3, 1 }, { 2, 3, -1 }, + + { 1, 3, 2 }, { -1, 3, -2 }, + + { -2, -1, 3 }, { -2, 1, -3 } + + }; + + float[][] skymins = new float[2][6]; + + float[][] skymaxs = new float[2][6]; + + float sky_min, sky_max; + + void DrawSkyPolygon(int nump, float[][] vecs) { + int i, j; + float[] v = { 0, 0, 0 }; + float[] av = { 0, 0, 0 }; + float s, t, dv; + int axis; + float[] vp; + + c_sky++; + // decide which face it maps to + Math3D.VectorCopy(Globals.vec3_origin, v); + for (i = 0; i < nump; i++) { + Math3D.VectorAdd(vecs[i], v, v); + } + av[0] = Math.abs(v[0]); + av[1] = Math.abs(v[1]); + av[2] = Math.abs(v[2]); + if (av[0] > av[1] && av[0] > av[2]) { + if (v[0] < 0) + axis = 1; + else + axis = 0; + } else if (av[1] > av[2] && av[1] > av[0]) { + if (v[1] < 0) + axis = 3; + else + axis = 2; + } else { + if (v[2] < 0) + axis = 5; + else + axis = 4; + } + + // project new texture coords + for (i = 0; i < nump; i++) { + j = vec_to_st[axis][2]; + if (j > 0) + dv = vecs[i][j - 1]; + else + dv = -vecs[i][-j - 1]; + if (dv < 0.001f) + continue; // don't divide by zero + j = vec_to_st[axis][0]; + if (j < 0) + s = -vecs[i][-j - 1] / dv; + else + s = vecs[i][j - 1] / dv; + j = vec_to_st[axis][1]; + if (j < 0) + t = -vecs[i][-j - 1] / dv; + else + t = vecs[i][j - 1] / dv; + + if (s < skymins[0][axis]) + skymins[0][axis] = s; + if (t < skymins[1][axis]) + skymins[1][axis] = t; + if (s > skymaxs[0][axis]) + skymaxs[0][axis] = s; + if (t > skymaxs[1][axis]) + skymaxs[1][axis] = t; + } + } + + static final float ON_EPSILON = 0.1f; // point on plane side epsilon + + static final int MAX_CLIP_VERTS = 64; + + static final int SIDE_BACK = 1; + + static final int SIDE_FRONT = 0; + + static final int SIDE_ON = 2; + + float[] dists = new float[MAX_CLIP_VERTS]; + + int[] sides = new int[MAX_CLIP_VERTS]; + + float[][][][] newv = new float[6][2][MAX_CLIP_VERTS][3]; + + void ClipSkyPolygon(int nump, float[][] vecs, int stage) { + float[] norm; + float[] v; + boolean front, back; + float d, e; + int[] newc = { 0, 0 }; + int i, j; + + if (nump > MAX_CLIP_VERTS - 2) + Com.Error(Defines.ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); + if (stage == 6) { // fully clipped, so draw it + DrawSkyPolygon(nump, vecs); + return; + } + + front = back = false; + norm = skyclip[stage]; + for (i = 0; i < nump; i++) { + d = Math3D.DotProduct(vecs[i], norm); + if (d > ON_EPSILON) { + front = true; + sides[i] = SIDE_FRONT; + } else if (d < -ON_EPSILON) { + back = true; + sides[i] = SIDE_BACK; + } else + sides[i] = SIDE_ON; + dists[i] = d; + } + + if (!front || !back) { // not clipped + ClipSkyPolygon(nump, vecs, stage + 1); + return; + } + + // clip it + sides[i] = sides[0]; + dists[i] = dists[0]; + Math3D.VectorCopy(vecs[0], vecs[i]); + newc[0] = newc[1] = 0; + + for (i = 0; i < nump; i++) { + v = vecs[i]; + switch (sides[i]) { + case SIDE_FRONT: + Math3D.VectorCopy(v, newv[stage][0][newc[0]]); + newc[0]++; + break; + case SIDE_BACK: + Math3D.VectorCopy(v, newv[stage][1][newc[1]]); + newc[1]++; + break; + case SIDE_ON: + Math3D.VectorCopy(v, newv[stage][0][newc[0]]); + newc[0]++; + Math3D.VectorCopy(v, newv[stage][1][newc[1]]); + newc[1]++; + break; + } + + if (sides[i] == SIDE_ON || sides[i + 1] == SIDE_ON + || sides[i + 1] == sides[i]) + continue; + + d = dists[i] / (dists[i] - dists[i + 1]); + for (j = 0; j < 3; j++) { + e = v[j] + d * (vecs[i + 1][j] - v[j]); + newv[stage][0][newc[0]][j] = e; + newv[stage][1][newc[1]][j] = e; + } + newc[0]++; + newc[1]++; + } + + // continue + ClipSkyPolygon(newc[0], newv[stage][0], stage + 1); + ClipSkyPolygon(newc[1], newv[stage][1], stage + 1); + } + + float[][] verts = new float[MAX_CLIP_VERTS][3]; + + /* + * ================= R_AddSkySurface ================= + */ + void R_AddSkySurface(msurface_t fa) { + int i; + glpoly_t p; + + // calculate vertex values for sky box + for (p = fa.polys; p != null; p = p.next) { + for (i = 0; i < p.numverts; i++) { + Math3D.VectorSubtract(p.verts[i], r_origin, verts[i]); + } + ClipSkyPolygon(p.numverts, verts, 0); + } + } + + /* + * ============== R_ClearSkyBox ============== + */ + void R_ClearSkyBox() { + int i; + + for (i = 0; i < 6; i++) { + skymins[0][i] = skymins[1][i] = 9999; + skymaxs[0][i] = skymaxs[1][i] = -9999; + } + } + + void MakeSkyVec(float s, float t, int axis) { + float[] v = { 0, 0, 0 }; + float[] b = { 0, 0, 0 }; + int j, k; + + b[0] = s * 2300; + b[1] = t * 2300; + b[2] = 2300; + + for (j = 0; j < 3; j++) { + k = st_to_vec[axis][j]; + if (k < 0) + v[j] = -b[-k - 1]; + else + v[j] = b[k - 1]; + } + + // avoid bilerp seam + s = (s + 1) * 0.5f; + t = (t + 1) * 0.5f; + + if (s < sky_min) + s = sky_min; + else if (s > sky_max) + s = sky_max; + if (t < sky_min) + t = sky_min; + else if (t > sky_max) + t = sky_max; + + t = 1.0f - t; + gl.glTexCoord2f(s, t); + gl.glVertex3f(v[0], v[1], v[2]); + } + + /* + * ============== R_DrawSkyBox ============== + */ + int[] skytexorder = { 0, 2, 1, 3, 4, 5 }; + + void R_DrawSkyBox() { + int i; + + if (skyrotate != 0) { // check for no sky at all + for (i = 0; i < 6; i++) + if (skymins[0][i] < skymaxs[0][i] + && skymins[1][i] < skymaxs[1][i]) + break; + if (i == 6) + return; // nothing visible + } + + gl.glPushMatrix(); + gl.glTranslatef(r_origin[0], r_origin[1], r_origin[2]); + gl.glRotatef(r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], + skyaxis[2]); + + for (i = 0; i < 6; i++) { + if (skyrotate != 0) { // hack, forces full sky to draw when rotating + skymins[0][i] = -1; + skymins[1][i] = -1; + skymaxs[0][i] = 1; + skymaxs[1][i] = 1; + } + + if (skymins[0][i] >= skymaxs[0][i] + || skymins[1][i] >= skymaxs[1][i]) + continue; + + GL_Bind(sky_images[skytexorder[i]].texnum); + + gl.glBegin(GL.GL_QUADS); + MakeSkyVec(skymins[0][i], skymins[1][i], i); + MakeSkyVec(skymins[0][i], skymaxs[1][i], i); + MakeSkyVec(skymaxs[0][i], skymaxs[1][i], i); + MakeSkyVec(skymaxs[0][i], skymins[1][i], i); + gl.glEnd(); + } + gl.glPopMatrix(); + } + + /* + * ============ R_SetSky ============ + */ + // 3dstudio environment map names + String[] suf = { "rt", "bk", "lf", "ft", "up", "dn" }; + + protected void R_SetSky(String name, float rotate, float[] axis) { + assert (axis.length == 3) : "vec3_t bug"; + int i; + String pathname; + + // strncpy (skyname, name, sizeof(skyname)-1); + skyname = name; + + skyrotate = rotate; + Math3D.VectorCopy(axis, skyaxis); + + for (i = 0; i < 6; i++) { + // chop down rotating skies for less memory + if (gl_skymip.value != 0 || skyrotate != 0) + gl_picmip.value++; + + if (qglColorTableEXT && gl_ext_palettedtexture.value != 0) { + // Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", + // skyname, suf[i]); + pathname = "env/" + skyname + suf[i] + ".pcx"; + } else { + // Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga", + // skyname, suf[i]); + pathname = "env/" + skyname + suf[i] + ".tga"; + } + + sky_images[i] = GL_FindImage(pathname, it_sky); + + if (sky_images[i] == null) + sky_images[i] = r_notexture; + + if (gl_skymip.value != 0 || skyrotate != 0) { // take less memory + gl_picmip.value--; + sky_min = 1.0f / 256; + sky_max = 255.0f / 256; + } else { + sky_min = 1.0f / 512; + sky_max = 511.0f / 512; + } + } + } + +} \ No newline at end of file diff --git a/src/jake2/render/medge_t.java b/src/jake2/render/medge_t.java index 7244efe..c5fb65d 100644 --- a/src/jake2/render/medge_t.java +++ b/src/jake2/render/medge_t.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 20.11.2003 by RST. -// $Id: medge_t.java,v 1.1 2004-07-07 19:59:35 hzi Exp $ - +// $Id: medge_t.java,v 1.2 2004-09-22 19:22:15 salomo Exp $ package jake2.render; import jake2.Defines; @@ -28,16 +27,18 @@ import jake2.Defines; import java.nio.ByteBuffer; public class medge_t { - - public static final int DISK_SIZE = 2 * Defines.SIZE_OF_SHORT; - public static final int MEM_SIZE = 3 * Defines.SIZE_OF_INT; - - // unsigned short - public int[] v = new int[2]; - public int cachededgeoffset; - - public medge_t(ByteBuffer b) { - v[0] = b.getShort() & 0xFFFF; - v[1] = b.getShort() & 0xFFFF; - } -} + + public static final int DISK_SIZE = 2 * Defines.SIZE_OF_SHORT; + + public static final int MEM_SIZE = 3 * Defines.SIZE_OF_INT; + + // unsigned short + public int[] v = new int[2]; + + public int cachededgeoffset; + + public medge_t(ByteBuffer b) { + v[0] = b.getShort() & 0xFFFF; + v[1] = b.getShort() & 0xFFFF; + } +} \ No newline at end of file diff --git a/src/jake2/render/mvertex_t.java b/src/jake2/render/mvertex_t.java index 12b2a32..29bd454 100644 --- a/src/jake2/render/mvertex_t.java +++ b/src/jake2/render/mvertex_t.java @@ -1,26 +1,25 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 20.11.2003 by RST. -// $Id: mvertex_t.java,v 1.1 2004-07-07 19:59:35 hzi Exp $ - +// $Id: mvertex_t.java,v 1.2 2004-09-22 19:22:15 salomo Exp $ package jake2.render; import jake2.Defines; @@ -28,14 +27,15 @@ import jake2.Defines; import java.nio.ByteBuffer; public class mvertex_t { - public static final int DISK_SIZE = 3 * Defines.SIZE_OF_FLOAT; - public static final int MEM_SIZE = 3 * Defines.SIZE_OF_FLOAT; + public static final int DISK_SIZE = 3 * Defines.SIZE_OF_FLOAT; + + public static final int MEM_SIZE = 3 * Defines.SIZE_OF_FLOAT; - public float[] position = {0, 0, 0}; + public float[] position = { 0, 0, 0 }; - public mvertex_t(ByteBuffer b) { - position[0] = b.getFloat(); - position[1] = b.getFloat(); - position[2] = b.getFloat(); - } -} + public mvertex_t(ByteBuffer b) { + position[0] = b.getFloat(); + position[1] = b.getFloat(); + position[2] = b.getFloat(); + } +} \ No newline at end of file diff --git a/src/jake2/server/SV.java b/src/jake2/server/SV.java index 701f767..a046ef4 100644 --- a/src/jake2/server/SV.java +++ b/src/jake2/server/SV.java @@ -2,32 +2,36 @@ * SV.java * Copyright (C) 2003 * - * $Id: SV.java,v 1.9 2004-08-29 21:39:25 hzi Exp $ + * $Id: SV.java,v 1.10 2004-09-22 19:22:12 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.server; import jake2.Defines; +import jake2.Globals; import jake2.client.M; -import jake2.game.*; +import jake2.game.GameBase; +import jake2.game.edict_t; +import jake2.game.pushed_t; +import jake2.game.trace_t; import jake2.qcommon.Com; import jake2.util.Lib; import jake2.util.Math3D; @@ -35,1175 +39,1095 @@ import jake2.util.Math3D; /** * SV */ -public final class SV -{ - - //file_io - //===================================================================== - //g_phys - - /////////////////////////////////////// - public static edict_t[] SV_TestEntityPosition(edict_t ent) - { - trace_t trace; - int mask; - - if (ent.clipmask != 0) - mask= ent.clipmask; - else - mask= Defines.MASK_SOLID; - - trace= GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, ent.s.origin, ent, mask); - - if (trace.startsolid) - return GameBase.g_edicts; - - return null; - } - - /////////////////////////////////////// - public static void SV_CheckVelocity(edict_t ent) - { - int i; - - // - // bound velocity - // - for (i= 0; i < 3; i++) - { - if (ent.velocity[i] > GameBase.sv_maxvelocity.value) - ent.velocity[i]= GameBase.sv_maxvelocity.value; - else if (ent.velocity[i] < -GameBase.sv_maxvelocity.value) - ent.velocity[i]= -GameBase.sv_maxvelocity.value; - } - } - - /** - * Runs thinking code for this frame if necessary. - */ - public static boolean SV_RunThink(edict_t ent) - { - float thinktime; - - thinktime= ent.nextthink; - if (thinktime <= 0) - return true; - if (thinktime > GameBase.level.time + 0.001) - return true; - - ent.nextthink= 0; - - if (ent.think == null) - Com.Error(Defines.ERR_FATAL, "NULL ent.think"); - - ent.think.think(ent); - - return false; - } - - /** - * Two entities have touched, so run their touch functions. - */ - public static void SV_Impact(edict_t e1, trace_t trace) - { - edict_t e2; - - e2= trace.ent; - - if (e1.touch != null && e1.solid != Defines.SOLID_NOT) - e1.touch.touch(e1, e2, trace.plane, trace.surface); - - if (e2.touch != null && e2.solid != Defines.SOLID_NOT) - e2.touch.touch(e2, e1, GameBase.dummyplane, null); - } - - public static int SV_FlyMove(edict_t ent, float time, int mask) - { - edict_t hit; - int bumpcount, numbumps; - float[] dir= { 0.0f, 0.0f, 0.0f }; - float d; - int numplanes; - float[][] planes= new float[GameBase.MAX_CLIP_PLANES][3]; - float[] primal_velocity= { 0.0f, 0.0f, 0.0f }; - float[] original_velocity= { 0.0f, 0.0f, 0.0f }; - float[] new_velocity= { 0.0f, 0.0f, 0.0f }; - int i, j; - trace_t trace; - float[] end= { 0.0f, 0.0f, 0.0f }; - float time_left; - int blocked; - - numbumps= 4; - - blocked= 0; - Math3D.VectorCopy(ent.velocity, original_velocity); - Math3D.VectorCopy(ent.velocity, primal_velocity); - numplanes= 0; - - time_left= time; - - ent.groundentity= null; - for (bumpcount= 0; bumpcount < numbumps; bumpcount++) - { - for (i= 0; i < 3; i++) - end[i]= ent.s.origin[i] + time_left * ent.velocity[i]; - - trace= GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end, ent, mask); - - if (trace.allsolid) - { // entity is trapped in another solid - Math3D.VectorCopy(GameBase.vec3_origin, ent.velocity); - return 3; - } - - if (trace.fraction > 0) - { // actually covered some distance - Math3D.VectorCopy(trace.endpos, ent.s.origin); - Math3D.VectorCopy(ent.velocity, original_velocity); - numplanes= 0; - } - - if (trace.fraction == 1) - break; // moved the entire distance - - hit= trace.ent; - - if (trace.plane.normal[2] > 0.7) - { - blocked |= 1; // floor - if (hit.solid == Defines.SOLID_BSP) - { - ent.groundentity= hit; - ent.groundentity_linkcount= hit.linkcount; - } - } - if (trace.plane.normal[2] == 0.0f) - { - blocked |= 2; // step - } - - // - // run the impact function - // - SV_Impact(ent, trace); - if (!ent.inuse) - break; // removed by the impact function - - time_left -= time_left * trace.fraction; - - // cliped to another plane - if (numplanes >= GameBase.MAX_CLIP_PLANES) - { // this shouldn't really happen - Math3D.VectorCopy(GameBase.vec3_origin, ent.velocity); - return 3; - } - - Math3D.VectorCopy(trace.plane.normal, planes[numplanes]); - numplanes++; - - // - // modify original_velocity so it parallels all of the clip planes - // - for (i= 0; i < numplanes; i++) - { - GameBase.ClipVelocity(original_velocity, planes[i], new_velocity, 1); - - for (j= 0; j < numplanes; j++) - if ((j != i) && Math3D.VectorCompare(planes[i], planes[j]) == 0.0f) - { - if (Math3D.DotProduct(new_velocity, planes[j]) < 0) - break; // not ok - } - if (j == numplanes) - break; - } - - if (i != numplanes) - { // go along this plane - Math3D.VectorCopy(new_velocity, ent.velocity); - } - else - { // go along the crease - if (numplanes != 2) - { - // gi.dprintf ("clip velocity, numplanes == %i\n",numplanes); - Math3D.VectorCopy(GameBase.vec3_origin, ent.velocity); - return 7; - } - Math3D.CrossProduct(planes[0], planes[1], dir); - d= Math3D.DotProduct(dir, ent.velocity); - Math3D.VectorScale(dir, d, ent.velocity); - } - - // - // if original velocity is against the original velocity, stop dead - // to avoid tiny occilations in sloping corners - // - if (Math3D.DotProduct(ent.velocity, primal_velocity) <= 0) - { - Math3D.VectorCopy(GameBase.vec3_origin, ent.velocity); - return blocked; - } - } - - return blocked; - } - - /* - ============ - SV_AddGravity - - ============ - */ - public static void SV_AddGravity(edict_t ent) - { - ent.velocity[2] -= ent.gravity * GameBase.sv_gravity.value * Defines.FRAMETIME; - } - - /** - * Does not change the entities velocity at all - */ - public static trace_t SV_PushEntity(edict_t ent, float[] push) - { - trace_t trace; - float[] start= { 0, 0, 0 }; - float[] end= { 0, 0, 0 }; - int mask; - - Math3D.VectorCopy(ent.s.origin, start); - Math3D.VectorAdd(start, push, end); - - // FIXME: test this - // a goto statement was replaced. - boolean retry= false; - - do - { - if (ent.clipmask != 0) - mask= ent.clipmask; - else - mask= Defines.MASK_SOLID; - - trace= GameBase.gi.trace(start, ent.mins, ent.maxs, end, ent, mask); - - Math3D.VectorCopy(trace.endpos, ent.s.origin); - GameBase.gi.linkentity(ent); - - retry= false; - if (trace.fraction != 1.0) - { - SV_Impact(ent, trace); - - // if the pushed entity went away and the pusher is still there - if (!trace.ent.inuse && ent.inuse) - { - // move the pusher back and try again - Math3D.VectorCopy(start, ent.s.origin); - GameBase.gi.linkentity(ent); - //goto retry; - retry= true; - } - } - } - while (retry); - - if (ent.inuse) - GameBase.G_TouchTriggers(ent); - - return trace; - } - - /* - ============ - SV_Push - - Objects need to be moved back on a failed push, - otherwise riders would continue to slide. - ============ - */ - public static boolean SV_Push(edict_t pusher, float[] move, float[] amove) - { - int i, e; - edict_t check, block[]; - float[] mins= { 0, 0, 0 }; - float[] maxs= { 0, 0, 0 }; - pushed_t p; - float[] org= { 0, 0, 0 }; - float[] org2= { 0, 0, 0 }; - float[] move2= { 0, 0, 0 }; - float[] forward= { 0, 0, 0 }; - float[] right= { 0, 0, 0 }; - float[] up= { 0, 0, 0 }; - - // clamp the move to 1/8 units, so the position will - // be accurate for client side prediction - for (i= 0; i < 3; i++) - { - float temp; - temp= move[i] * 8.0f; - if (temp > 0.0) - temp += 0.5; - else - temp -= 0.5; - move[i]= 0.125f * (int) temp; - } - - // find the bounding box - for (i= 0; i < 3; i++) - { - mins[i]= pusher.absmin[i] + move[i]; - maxs[i]= pusher.absmax[i] + move[i]; - } - - // we need this for pushing things later - Math3D.VectorSubtract(GameBase.vec3_origin, amove, org); - Math3D.AngleVectors(org, forward, right, up); - - // save the pusher's original position - GameBase.pushed[GameBase.pushed_p].ent= pusher; - Math3D.VectorCopy(pusher.s.origin, GameBase.pushed[GameBase.pushed_p].origin); - Math3D.VectorCopy(pusher.s.angles, GameBase.pushed[GameBase.pushed_p].angles); - - if (pusher.client != null) - GameBase.pushed[GameBase.pushed_p].deltayaw= pusher.client.ps.pmove.delta_angles[Defines.YAW]; - - GameBase.pushed_p++; - - // move the pusher to it's final position - Math3D.VectorAdd(pusher.s.origin, move, pusher.s.origin); - Math3D.VectorAdd(pusher.s.angles, amove, pusher.s.angles); - GameBase.gi.linkentity(pusher); - - // see if any solid entities are inside the final position - - //check= g_edicts + 1; - for (e= 1; e < GameBase.num_edicts; e++) - { - check= GameBase.g_edicts[e]; - if (!check.inuse) - continue; - if (check.movetype == Defines.MOVETYPE_PUSH - || check.movetype == Defines.MOVETYPE_STOP - || check.movetype == Defines.MOVETYPE_NONE - || check.movetype == Defines.MOVETYPE_NOCLIP) - continue; - - if (check.area.prev == null) - continue; // not linked in anywhere - - // if the entity is standing on the pusher, it will definitely be moved - if (check.groundentity != pusher) - { - // see if the ent needs to be tested - if (check.absmin[0] >= maxs[0] - || check.absmin[1] >= maxs[1] - || check.absmin[2] >= maxs[2] - || check.absmax[0] <= mins[0] - || check.absmax[1] <= mins[1] - || check.absmax[2] <= mins[2]) - continue; - - // see if the ent's bbox is inside the pusher's final position - if (SV_TestEntityPosition(check) == null) - continue; - } - - if ((pusher.movetype == Defines.MOVETYPE_PUSH) || (check.groundentity == pusher)) - { - // move this entity - GameBase.pushed[GameBase.pushed_p].ent= check; - Math3D.VectorCopy(check.s.origin, GameBase.pushed[GameBase.pushed_p].origin); - Math3D.VectorCopy(check.s.angles, GameBase.pushed[GameBase.pushed_p].angles); - GameBase.pushed_p++; - - // try moving the contacted entity - Math3D.VectorAdd(check.s.origin, move, check.s.origin); - if (check.client != null) - { // FIXME: doesn't rotate monsters? - check.client.ps.pmove.delta_angles[Defines.YAW] += amove[Defines.YAW]; - } - - // figure movement due to the pusher's amove - Math3D.VectorSubtract(check.s.origin, pusher.s.origin, org); - org2[0]= Math3D.DotProduct(org, forward); - org2[1]= -Math3D.DotProduct(org, right); - org2[2]= Math3D.DotProduct(org, up); - Math3D.VectorSubtract(org2, org, move2); - Math3D.VectorAdd(check.s.origin, move2, check.s.origin); - - // may have pushed them off an edge - if (check.groundentity != pusher) - check.groundentity= null; - - block= SV_TestEntityPosition(check); - if (block == null) - { // pushed ok - GameBase.gi.linkentity(check); - // impact? - continue; - } - - // if it is ok to leave in the old position, do it - // this is only relevent for riding entities, not pushed - // FIXME: this doesn't acount for rotation - Math3D.VectorSubtract(check.s.origin, move, check.s.origin); - block= SV_TestEntityPosition(check); - - if (block == null) - { - GameBase.pushed_p--; - continue; - } - } - - // save off the obstacle so we can call the block function - GameBase.obstacle= check; - - // move back any entities we already moved - // go backwards, so if the same entity was pushed - // twice, it goes back to the original position - for (int ip= GameBase.pushed_p - 1; ip >= 0; ip--) - { - p= GameBase.pushed[ip]; - Math3D.VectorCopy(p.origin, p.ent.s.origin); - Math3D.VectorCopy(p.angles, p.ent.s.angles); - if (p.ent.client != null) - { - p.ent.client.ps.pmove.delta_angles[Defines.YAW]= (short) p.deltayaw; - } - GameBase.gi.linkentity(p.ent); - } - return false; - } - - // FIXME: is there a better way to handle this? - // see if anything we moved has touched a trigger - for (int ip= GameBase.pushed_p - 1; ip >= 0; ip--) - GameBase.G_TouchTriggers(GameBase.pushed[ip].ent); - - return true; - } - - /* - ================ - SV_Physics_Pusher - - Bmodel objects don't interact with each other, but - push all box objects - ================ - */ - public static void SV_Physics_Pusher(edict_t ent) - { - float[] move= { 0, 0, 0 }; - float[] amove= { 0, 0, 0 }; - edict_t part, mv; - - // if not a team captain, so movement will be handled elsewhere - if ((ent.flags & Defines.FL_TEAMSLAVE) != 0) - return; - - // make sure all team slaves can move before commiting - // any moves or calling any think functions - // if the move is blocked, all moved objects will be backed out - // retry: - GameBase.pushed_p= 0; - for (part= ent; part != null; part= part.teamchain) - { - if (part.velocity[0] != 0 - || part.velocity[1] != 0 - || part.velocity[2] != 0 - || part.avelocity[0] != 0 - || part.avelocity[1] != 0 - || part.avelocity[2] != 0) - { // object is moving - Math3D.VectorScale(part.velocity, Defines.FRAMETIME, move); - Math3D.VectorScale(part.avelocity, Defines.FRAMETIME, amove); - - if (!SV_Push(part, move, amove)) - break; // move was blocked - } - } - if (GameBase.pushed_p > Defines.MAX_EDICTS) - - SV_GAME.PF_error(Defines.ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted"); - - if (part != null) { - // the move failed, bump all nextthink times and back out moves - for (mv= ent; mv != null; mv= mv.teamchain) - { - if (mv.nextthink > 0) - mv.nextthink += Defines.FRAMETIME; - } - - // if the pusher has a "blocked" function, call it - // otherwise, just stay in place until the obstacle is gone - if (part.blocked != null) - part.blocked.blocked(part, GameBase.obstacle); - } - else - { // the move succeeded, so call all think functions - for (part= ent; part != null; part= part.teamchain) - { - SV_RunThink(part); - } - } - } - - // ================================================================== - - /* - ============= - SV_Physics_None - - Non moving objects can only think - ============= - */ - public static void SV_Physics_None(edict_t ent) - { - // regular thinking - SV_RunThink(ent); - } - - /* - ============= - SV_Physics_Noclip - - A moving object that doesn't obey physics - ============= - */ - public static void SV_Physics_Noclip(edict_t ent) - { - // regular thinking - if (!SV_RunThink(ent)) - return; - - Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, ent.s.angles); - Math3D.VectorMA(ent.s.origin, Defines.FRAMETIME, ent.velocity, ent.s.origin); - - GameBase.gi.linkentity(ent); - } - - /* - ============================================================================== - - TOSS / BOUNCE - - ============================================================================== - */ - - /* - ============= - SV_Physics_Toss - - Toss, bounce, and fly movement. When onground, do nothing. - ============= - */ - public static void SV_Physics_Toss(edict_t ent) - { - - trace_t trace; - float[] move= { 0, 0, 0 }; - float backoff; - edict_t slave; - boolean wasinwater; - boolean isinwater; - float[] old_origin= { 0, 0, 0 }; - - // regular thinking - SV_RunThink(ent); - - // if not a team captain, so movement will be handled elsewhere - if ((ent.flags & Defines.FL_TEAMSLAVE) != 0) - return; - - if (ent.velocity[2] > 0) - ent.groundentity= null; - - // check for the groundentity going away - if (ent.groundentity != null) - if (!ent.groundentity.inuse) - ent.groundentity= null; - - // if onground, return without moving - if (ent.groundentity != null) - return; - - Math3D.VectorCopy(ent.s.origin, old_origin); - - SV_CheckVelocity(ent); - - // add gravity - if (ent.movetype != Defines.MOVETYPE_FLY && ent.movetype != Defines.MOVETYPE_FLYMISSILE) - SV_AddGravity(ent); - - // move angles - Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, ent.s.angles); - - // move origin - Math3D.VectorScale(ent.velocity, Defines.FRAMETIME, move); - trace= SV_PushEntity(ent, move); - if (!ent.inuse) - return; - - if (trace.fraction < 1) - { - if (ent.movetype == Defines.MOVETYPE_BOUNCE) - backoff= 1.5f; - else - backoff= 1; - - GameBase.ClipVelocity(ent.velocity, trace.plane.normal, ent.velocity, backoff); - - // stop if on ground - if (trace.plane.normal[2] > 0.7) - { - if (ent.velocity[2] < 60 || ent.movetype != Defines.MOVETYPE_BOUNCE) - { - ent.groundentity= trace.ent; - ent.groundentity_linkcount= trace.ent.linkcount; - Math3D.VectorCopy(GameBase.vec3_origin, ent.velocity); - Math3D.VectorCopy(GameBase.vec3_origin, ent.avelocity); - } - } - - // if (ent.touch) - // ent.touch (ent, trace.ent, &trace.plane, trace.surface); - } - - // check for water transition - wasinwater= (ent.watertype & Defines.MASK_WATER) != 0; - ent.watertype= GameBase.gi.pointcontents.pointcontents(ent.s.origin); - isinwater= (ent.watertype & Defines.MASK_WATER) != 0; - - if (isinwater) - ent.waterlevel= 1; - else - ent.waterlevel= 0; - - if (!wasinwater && isinwater) - GameBase.gi.positioned_sound(old_origin, ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); - else if (wasinwater && !isinwater) - GameBase.gi.positioned_sound(ent.s.origin, ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); - - // move teamslaves - for (slave= ent.teamchain; slave != null; slave= slave.teamchain) - { - Math3D.VectorCopy(ent.s.origin, slave.s.origin); - GameBase.gi.linkentity(slave); - } - } - - /* - =============================================================================== - - STEPPING MOVEMENT - - =============================================================================== - */ - - /* - ============= - SV_Physics_Step - - Monsters freefall when they don't have a ground entity, otherwise - all movement is done with discrete steps. - - This is also used for objects that have become still on the ground, but - will fall if the floor is pulled out from under them. - FIXME: is this true? - ============= - */ - - // FIXME: hacked in for E3 demo - - public static void SV_AddRotationalFriction(edict_t ent) - { - int n; - float adjustment; - - Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, ent.s.angles); - adjustment= Defines.FRAMETIME * Defines.sv_stopspeed * Defines.sv_friction; - for (n= 0; n < 3; n++) - { - if (ent.avelocity[n] > 0) - { - ent.avelocity[n] -= adjustment; - if (ent.avelocity[n] < 0) - ent.avelocity[n]= 0; - } - else - { - ent.avelocity[n] += adjustment; - if (ent.avelocity[n] > 0) - ent.avelocity[n]= 0; - } - } - } - - public static void SV_Physics_Step(edict_t ent) - { - boolean wasonground; - boolean hitsound= false; - float vel[]; - float speed, newspeed, control; - float friction; - edict_t groundentity; - int mask; - - // airborn monsters should always check for ground - if (ent.groundentity == null) - M.M_CheckGround(ent); - - groundentity= ent.groundentity; - - SV_CheckVelocity(ent); - - if (groundentity != null) - wasonground= true; - else - wasonground= false; - - if (ent.avelocity[0] != 0 || ent.avelocity[1] != 0 || ent.avelocity[2] != 0) - SV_AddRotationalFriction(ent); - - // add gravity except: - // flying monsters - // swimming monsters who are in the water - if (!wasonground) - if (0 == (ent.flags & Defines.FL_FLY)) - if (!((ent.flags & Defines.FL_SWIM) != 0 && (ent.waterlevel > 2))) - { - if (ent.velocity[2] < GameBase.sv_gravity.value * -0.1) - hitsound= true; - if (ent.waterlevel == 0) - SV_AddGravity(ent); - } - - // friction for flying monsters that have been given vertical velocity - if ((ent.flags & Defines.FL_FLY) != 0 && (ent.velocity[2] != 0)) - { - speed= Math.abs(ent.velocity[2]); - control= speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; - friction= Defines.sv_friction / 3; - newspeed= speed - (Defines.FRAMETIME * control * friction); - if (newspeed < 0) - newspeed= 0; - newspeed /= speed; - ent.velocity[2] *= newspeed; - } - - // friction for flying monsters that have been given vertical velocity - if ((ent.flags & Defines.FL_SWIM) != 0 && (ent.velocity[2] != 0)) - { - speed= Math.abs(ent.velocity[2]); - control= speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; - newspeed= speed - (Defines.FRAMETIME * control * Defines.sv_waterfriction * ent.waterlevel); - if (newspeed < 0) - newspeed= 0; - newspeed /= speed; - ent.velocity[2] *= newspeed; - } - - if (ent.velocity[2] != 0 || ent.velocity[1] != 0 || ent.velocity[0] != 0) - { - // apply friction - // let dead monsters who aren't completely onground slide - if ((wasonground) || 0 != (ent.flags & (Defines.FL_SWIM | Defines.FL_FLY))) - if (!(ent.health <= 0.0 && !M.M_CheckBottom(ent))) - { - vel= ent.velocity; - speed= (float) Math.sqrt(vel[0] * vel[0] + vel[1] * vel[1]); - if (speed != 0) - { - friction= Defines.sv_friction; - - control= speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; - newspeed= speed - Defines.FRAMETIME * control * friction; - - if (newspeed < 0) - newspeed= 0; - newspeed /= speed; - - vel[0] *= newspeed; - vel[1] *= newspeed; - } - } - - if ((ent.svflags & Defines.SVF_MONSTER) != 0) - mask= Defines.MASK_MONSTERSOLID; - else - mask= Defines.MASK_SOLID; - - SV_FlyMove(ent, Defines.FRAMETIME, mask); - - GameBase.gi.linkentity(ent); - GameBase.G_TouchTriggers(ent); - if (!ent.inuse) - return; - - if (ent.groundentity != null) - if (!wasonground) - if (hitsound) - GameBase.gi.sound(ent, 0, GameBase.gi.soundindex("world/land.wav"), 1, 1, 0); - } - - // regular thinking - SV_RunThink(ent); - } - - /* - ============= - SV_movestep - - Called by monster program code. - The move will be adjusted for slopes and stairs, but if the move isn't - possible, no move is done, false is returned, and - pr_global_struct.trace_normal is set to the normal of the blocking wall - ============= - */ - // FIXME since we need to test end position contents here, can we avoid doing - // it again later in catagorize position? - public static boolean SV_movestep(edict_t ent, float[] move, boolean relink) - { - float dz; - float[] oldorg= { 0, 0, 0 }; - float[] neworg= { 0, 0, 0 }; - float[] end= { 0, 0, 0 }; - - trace_t trace= null; // = new trace_t(); - int i; - float stepsize; - float[] test= { 0, 0, 0 }; - int contents; - - // try the move - Math3D.VectorCopy(ent.s.origin, oldorg); - Math3D.VectorAdd(ent.s.origin, move, neworg); - - // flying monsters don't step up - if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0) - { - // try one move with vertical motion, then one without - for (i= 0; i < 2; i++) - { - Math3D.VectorAdd(ent.s.origin, move, neworg); - if (i == 0 && ent.enemy != null) - { - if (ent.goalentity == null) - ent.goalentity= ent.enemy; - dz= ent.s.origin[2] - ent.goalentity.s.origin[2]; - if (ent.goalentity.client != null) - { - if (dz > 40) - neworg[2] -= 8; - if (!((ent.flags & Defines.FL_SWIM) != 0 && (ent.waterlevel < 2))) - if (dz < 30) - neworg[2] += 8; - } - else - { - if (dz > 8) - neworg[2] -= 8; - else if (dz > 0) - neworg[2] -= dz; - else if (dz < -8) - neworg[2] += 8; - else - neworg[2] += dz; - } - } - trace= GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, neworg, ent, Defines.MASK_MONSTERSOLID); - - // fly monsters don't enter water voluntarily - if ((ent.flags & Defines.FL_FLY) != 0) - { - if (ent.waterlevel == 0) - { - test[0]= trace.endpos[0]; - test[1]= trace.endpos[1]; - test[2]= trace.endpos[2] + ent.mins[2] + 1; - contents= GameBase.gi.pointcontents.pointcontents(test); - if ((contents & Defines.MASK_WATER) != 0) - return false; - } - } - - // swim monsters don't exit water voluntarily - if ((ent.flags & Defines.FL_SWIM) != 0) - { - if (ent.waterlevel < 2) - { - test[0]= trace.endpos[0]; - test[1]= trace.endpos[1]; - test[2]= trace.endpos[2] + ent.mins[2] + 1; - contents= GameBase.gi.pointcontents.pointcontents(test); - if ((contents & Defines.MASK_WATER) == 0) - return false; - } - } - - if (trace.fraction == 1) - { - Math3D.VectorCopy(trace.endpos, ent.s.origin); - if (relink) - { - GameBase.gi.linkentity(ent); - GameBase.G_TouchTriggers(ent); - } - return true; - } - - if (ent.enemy == null) - break; - } - - return false; - } - - // push down from a step height above the wished position - if ((ent.monsterinfo.aiflags & Defines.AI_NOSTEP) == 0) - stepsize= GameBase.STEPSIZE; - else - stepsize= 1; - - neworg[2] += stepsize; - Math3D.VectorCopy(neworg, end); - end[2] -= stepsize * 2; - - trace= GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID); - - if (trace.allsolid) - return false; - - if (trace.startsolid) - { - neworg[2] -= stepsize; - trace= GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID); - if (trace.allsolid || trace.startsolid) - return false; - } - - // don't go in to water - if (ent.waterlevel == 0) - { - test[0]= trace.endpos[0]; - test[1]= trace.endpos[1]; - test[2]= trace.endpos[2] + ent.mins[2] + 1; - contents= GameBase.gi.pointcontents.pointcontents(test); - - if ((contents & Defines.MASK_WATER) != 0) - return false; - } - - if (trace.fraction == 1) - { - // if monster had the ground pulled out, go ahead and fall - if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) - { - Math3D.VectorAdd(ent.s.origin, move, ent.s.origin); - if (relink) - { - GameBase.gi.linkentity(ent); - GameBase.G_TouchTriggers(ent); - } - ent.groundentity= null; - return true; - } - - return false; // walked off an edge - } - - // check point traces down for dangling corners - Math3D.VectorCopy(trace.endpos, ent.s.origin); - - if (!M.M_CheckBottom(ent)) - { - if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) - { - // entity had floor mostly pulled out from underneath it - // and is trying to correct - if (relink) - { - GameBase.gi.linkentity(ent); - GameBase.G_TouchTriggers(ent); - } - return true; - } - Math3D.VectorCopy(oldorg, ent.s.origin); - return false; - } - - if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) - { - ent.flags &= ~Defines.FL_PARTIALGROUND; - } - ent.groundentity= trace.ent; - ent.groundentity_linkcount= trace.ent.linkcount; - - // the move is ok - if (relink) - { - GameBase.gi.linkentity(ent); - GameBase.G_TouchTriggers(ent); - } - return true; - } - - /* - ====================== - SV_StepDirection - - Turns to the movement direction, and walks the current distance if - facing it. - - ====================== - */ - public static boolean SV_StepDirection(edict_t ent, float yaw, float dist) - { - float[] move= { 0, 0, 0 }; - float[] oldorigin= { 0, 0, 0 }; - float delta; - - ent.ideal_yaw= yaw; - M.M_ChangeYaw(ent); - - yaw= (float) (yaw * Math.PI * 2 / 360); - move[0]= (float) Math.cos(yaw) * dist; - move[1]= (float) Math.sin(yaw) * dist; - move[2]= 0; - - Math3D.VectorCopy(ent.s.origin, oldorigin); - if (SV_movestep(ent, move, false)) - { - delta= ent.s.angles[Defines.YAW] - ent.ideal_yaw; - if (delta > 45 && delta < 315) - { // not turned far enough, so don't take the step - Math3D.VectorCopy(oldorigin, ent.s.origin); - } - GameBase.gi.linkentity(ent); - GameBase.G_TouchTriggers(ent); - return true; - } - GameBase.gi.linkentity(ent); - GameBase.G_TouchTriggers(ent); - return false; - } - - /* - ====================== - SV_FixCheckBottom - - ====================== - */ - public static void SV_FixCheckBottom(edict_t ent) - { - ent.flags |= Defines.FL_PARTIALGROUND; - } - - public static void SV_NewChaseDir(edict_t actor, edict_t enemy, float dist) - { - float deltax, deltay; - float d[]= { 0, 0, 0 }; - float tdir, olddir, turnaround; - - //FIXME: how did we get here with no enemy - if (enemy == null) - { - Com.DPrintf("SV_NewChaseDir without enemy!\n"); - return; - } - olddir= Math3D.anglemod((int) (actor.ideal_yaw / 45) * 45); - turnaround= Math3D.anglemod(olddir - 180); - - deltax= enemy.s.origin[0] - actor.s.origin[0]; - deltay= enemy.s.origin[1] - actor.s.origin[1]; - if (deltax > 10) - d[1]= 0; - else if (deltax < -10) - d[1]= 180; - else - d[1]= GameBase.DI_NODIR; - if (deltay < -10) - d[2]= 270; - else if (deltay > 10) - d[2]= 90; - else - d[2]= GameBase.DI_NODIR; - - // try direct route - if (d[1] != GameBase.DI_NODIR && d[2] != GameBase.DI_NODIR) - { - if (d[1] == 0) - tdir= d[2] == 90 ? 45 : 315; - else - tdir= d[2] == 90 ? 135 : 215; - - if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) - return; - } - - // try other directions - if (((Lib.rand() & 3) & 1) != 0 || Math.abs(deltay) > Math.abs(deltax)) - { - tdir= d[1]; - d[1]= d[2]; - d[2]= tdir; - } - - if (d[1] != GameBase.DI_NODIR && d[1] != turnaround && SV_StepDirection(actor, d[1], dist)) - return; - - if (d[2] != GameBase.DI_NODIR && d[2] != turnaround && SV_StepDirection(actor, d[2], dist)) - return; - - /* there is no direct path to the player, so pick another direction */ - - if (olddir != GameBase.DI_NODIR && SV_StepDirection(actor, olddir, dist)) - return; - - if ((Lib.rand() & 1) != 0) /*randomly determine direction of search*/ - { - for (tdir= 0; tdir <= 315; tdir += 45) - if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) - return; - } - else - { - for (tdir= 315; tdir >= 0; tdir -= 45) - if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) - return; - } - - if (turnaround != GameBase.DI_NODIR && SV_StepDirection(actor, turnaround, dist)) - return; - - actor.ideal_yaw= olddir; // can't move - - // if a bridge was pulled out from underneath a monster, it may not have - // a valid standing position at all - - if (!M.M_CheckBottom(actor)) - SV_FixCheckBottom(actor); - } - - /* - ====================== - SV_CloseEnough - - ====================== - */ //ok - public static boolean SV_CloseEnough(edict_t ent, edict_t goal, float dist) - { - int i; - - for (i= 0; i < 3; i++) - { - if (goal.absmin[i] > ent.absmax[i] + dist) - return false; - if (goal.absmax[i] < ent.absmin[i] - dist) - return false; - } - return true; - } -} +public final class SV { + + /////////////////////////////////////// + public static edict_t[] SV_TestEntityPosition(edict_t ent) { + trace_t trace; + int mask; + + if (ent.clipmask != 0) + mask = ent.clipmask; + else + mask = Defines.MASK_SOLID; + + trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, + ent.s.origin, ent, mask); + + if (trace.startsolid) + return GameBase.g_edicts; + + return null; + } + + /////////////////////////////////////// + public static void SV_CheckVelocity(edict_t ent) { + int i; + + // + // bound velocity + // + for (i = 0; i < 3; i++) { + if (ent.velocity[i] > GameBase.sv_maxvelocity.value) + ent.velocity[i] = GameBase.sv_maxvelocity.value; + else if (ent.velocity[i] < -GameBase.sv_maxvelocity.value) + ent.velocity[i] = -GameBase.sv_maxvelocity.value; + } + } + + /** + * Runs thinking code for this frame if necessary. + */ + public static boolean SV_RunThink(edict_t ent) { + float thinktime; + + thinktime = ent.nextthink; + if (thinktime <= 0) + return true; + if (thinktime > GameBase.level.time + 0.001) + return true; + + ent.nextthink = 0; + + if (ent.think == null) + Com.Error(Defines.ERR_FATAL, "NULL ent.think"); + + ent.think.think(ent); + + return false; + } + + /** + * Two entities have touched, so run their touch functions. + */ + public static void SV_Impact(edict_t e1, trace_t trace) { + edict_t e2; + + e2 = trace.ent; + + if (e1.touch != null && e1.solid != Defines.SOLID_NOT) + e1.touch.touch(e1, e2, trace.plane, trace.surface); + + if (e2.touch != null && e2.solid != Defines.SOLID_NOT) + e2.touch.touch(e2, e1, GameBase.dummyplane, null); + } + + public static int SV_FlyMove(edict_t ent, float time, int mask) { + edict_t hit; + int bumpcount, numbumps; + float[] dir = { 0.0f, 0.0f, 0.0f }; + float d; + int numplanes; + float[][] planes = new float[GameBase.MAX_CLIP_PLANES][3]; + float[] primal_velocity = { 0.0f, 0.0f, 0.0f }; + float[] original_velocity = { 0.0f, 0.0f, 0.0f }; + float[] new_velocity = { 0.0f, 0.0f, 0.0f }; + int i, j; + trace_t trace; + float[] end = { 0.0f, 0.0f, 0.0f }; + float time_left; + int blocked; + + numbumps = 4; + + blocked = 0; + Math3D.VectorCopy(ent.velocity, original_velocity); + Math3D.VectorCopy(ent.velocity, primal_velocity); + numplanes = 0; + + time_left = time; + + ent.groundentity = null; + for (bumpcount = 0; bumpcount < numbumps; bumpcount++) { + for (i = 0; i < 3; i++) + end[i] = ent.s.origin[i] + time_left * ent.velocity[i]; + + trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end, + ent, mask); + + if (trace.allsolid) { // entity is trapped in another solid + Math3D.VectorCopy(Globals.vec3_origin, ent.velocity); + return 3; + } + + if (trace.fraction > 0) { // actually covered some distance + Math3D.VectorCopy(trace.endpos, ent.s.origin); + Math3D.VectorCopy(ent.velocity, original_velocity); + numplanes = 0; + } + + if (trace.fraction == 1) + break; // moved the entire distance + + hit = trace.ent; + + if (trace.plane.normal[2] > 0.7) { + blocked |= 1; // floor + if (hit.solid == Defines.SOLID_BSP) { + ent.groundentity = hit; + ent.groundentity_linkcount = hit.linkcount; + } + } + if (trace.plane.normal[2] == 0.0f) { + blocked |= 2; // step + } + + // + // run the impact function + // + SV_Impact(ent, trace); + if (!ent.inuse) + break; // removed by the impact function + + time_left -= time_left * trace.fraction; + + // cliped to another plane + if (numplanes >= GameBase.MAX_CLIP_PLANES) { // this shouldn't + // really happen + Math3D.VectorCopy(Globals.vec3_origin, ent.velocity); + return 3; + } + + Math3D.VectorCopy(trace.plane.normal, planes[numplanes]); + numplanes++; + + // + // modify original_velocity so it parallels all of the clip planes + // + for (i = 0; i < numplanes; i++) { + GameBase.ClipVelocity(original_velocity, planes[i], + new_velocity, 1); + + for (j = 0; j < numplanes; j++) + if ((j != i) + && Math3D.VectorCompare(planes[i], planes[j]) == 0.0f) { + if (Math3D.DotProduct(new_velocity, planes[j]) < 0) + break; // not ok + } + if (j == numplanes) + break; + } + + if (i != numplanes) { // go along this plane + Math3D.VectorCopy(new_velocity, ent.velocity); + } else { // go along the crease + if (numplanes != 2) { + // gi.dprintf ("clip velocity, numplanes == + // %i\n",numplanes); + Math3D.VectorCopy(Globals.vec3_origin, ent.velocity); + return 7; + } + Math3D.CrossProduct(planes[0], planes[1], dir); + d = Math3D.DotProduct(dir, ent.velocity); + Math3D.VectorScale(dir, d, ent.velocity); + } + + // + // if original velocity is against the original velocity, stop dead + // to avoid tiny occilations in sloping corners + // + if (Math3D.DotProduct(ent.velocity, primal_velocity) <= 0) { + Math3D.VectorCopy(Globals.vec3_origin, ent.velocity); + return blocked; + } + } + + return blocked; + } + + /* + * ============ SV_AddGravity + * + * ============ + */ + public static void SV_AddGravity(edict_t ent) { + ent.velocity[2] -= ent.gravity * GameBase.sv_gravity.value + * Defines.FRAMETIME; + } + + /** + * Does not change the entities velocity at all + */ + public static trace_t SV_PushEntity(edict_t ent, float[] push) { + trace_t trace; + float[] start = { 0, 0, 0 }; + float[] end = { 0, 0, 0 }; + int mask; + + Math3D.VectorCopy(ent.s.origin, start); + Math3D.VectorAdd(start, push, end); + + // FIXME: test this + // a goto statement was replaced. + boolean retry = false; + + do { + if (ent.clipmask != 0) + mask = ent.clipmask; + else + mask = Defines.MASK_SOLID; + + trace = GameBase.gi + .trace(start, ent.mins, ent.maxs, end, ent, mask); + + Math3D.VectorCopy(trace.endpos, ent.s.origin); + GameBase.gi.linkentity(ent); + + retry = false; + if (trace.fraction != 1.0) { + SV_Impact(ent, trace); + + // if the pushed entity went away and the pusher is still there + if (!trace.ent.inuse && ent.inuse) { + // move the pusher back and try again + Math3D.VectorCopy(start, ent.s.origin); + GameBase.gi.linkentity(ent); + //goto retry; + retry = true; + } + } + } while (retry); + + if (ent.inuse) + GameBase.G_TouchTriggers(ent); + + return trace; + } + + /* + * ============ SV_Push + * + * Objects need to be moved back on a failed push, otherwise riders would + * continue to slide. ============ + */ + public static boolean SV_Push(edict_t pusher, float[] move, float[] amove) { + int i, e; + edict_t check, block[]; + float[] mins = { 0, 0, 0 }; + float[] maxs = { 0, 0, 0 }; + pushed_t p; + float[] org = { 0, 0, 0 }; + float[] org2 = { 0, 0, 0 }; + float[] move2 = { 0, 0, 0 }; + float[] forward = { 0, 0, 0 }; + float[] right = { 0, 0, 0 }; + float[] up = { 0, 0, 0 }; + + // clamp the move to 1/8 units, so the position will + // be accurate for client side prediction + for (i = 0; i < 3; i++) { + float temp; + temp = move[i] * 8.0f; + if (temp > 0.0) + temp += 0.5; + else + temp -= 0.5; + move[i] = 0.125f * (int) temp; + } + + // find the bounding box + for (i = 0; i < 3; i++) { + mins[i] = pusher.absmin[i] + move[i]; + maxs[i] = pusher.absmax[i] + move[i]; + } + + // we need this for pushing things later + Math3D.VectorSubtract(Globals.vec3_origin, amove, org); + Math3D.AngleVectors(org, forward, right, up); + + // save the pusher's original position + GameBase.pushed[GameBase.pushed_p].ent = pusher; + Math3D.VectorCopy(pusher.s.origin, + GameBase.pushed[GameBase.pushed_p].origin); + Math3D.VectorCopy(pusher.s.angles, + GameBase.pushed[GameBase.pushed_p].angles); + + if (pusher.client != null) + GameBase.pushed[GameBase.pushed_p].deltayaw = pusher.client.ps.pmove.delta_angles[Defines.YAW]; + + GameBase.pushed_p++; + + // move the pusher to it's final position + Math3D.VectorAdd(pusher.s.origin, move, pusher.s.origin); + Math3D.VectorAdd(pusher.s.angles, amove, pusher.s.angles); + GameBase.gi.linkentity(pusher); + + // see if any solid entities are inside the final position + + //check= g_edicts + 1; + for (e = 1; e < GameBase.num_edicts; e++) { + check = GameBase.g_edicts[e]; + if (!check.inuse) + continue; + if (check.movetype == Defines.MOVETYPE_PUSH + || check.movetype == Defines.MOVETYPE_STOP + || check.movetype == Defines.MOVETYPE_NONE + || check.movetype == Defines.MOVETYPE_NOCLIP) + continue; + + if (check.area.prev == null) + continue; // not linked in anywhere + + // if the entity is standing on the pusher, it will definitely be + // moved + if (check.groundentity != pusher) { + // see if the ent needs to be tested + if (check.absmin[0] >= maxs[0] || check.absmin[1] >= maxs[1] + || check.absmin[2] >= maxs[2] + || check.absmax[0] <= mins[0] + || check.absmax[1] <= mins[1] + || check.absmax[2] <= mins[2]) + continue; + + // see if the ent's bbox is inside the pusher's final position + if (SV_TestEntityPosition(check) == null) + continue; + } + + if ((pusher.movetype == Defines.MOVETYPE_PUSH) + || (check.groundentity == pusher)) { + // move this entity + GameBase.pushed[GameBase.pushed_p].ent = check; + Math3D.VectorCopy(check.s.origin, + GameBase.pushed[GameBase.pushed_p].origin); + Math3D.VectorCopy(check.s.angles, + GameBase.pushed[GameBase.pushed_p].angles); + GameBase.pushed_p++; + + // try moving the contacted entity + Math3D.VectorAdd(check.s.origin, move, check.s.origin); + if (check.client != null) { // FIXME: doesn't rotate monsters? + check.client.ps.pmove.delta_angles[Defines.YAW] += amove[Defines.YAW]; + } + + // figure movement due to the pusher's amove + Math3D.VectorSubtract(check.s.origin, pusher.s.origin, org); + org2[0] = Math3D.DotProduct(org, forward); + org2[1] = -Math3D.DotProduct(org, right); + org2[2] = Math3D.DotProduct(org, up); + Math3D.VectorSubtract(org2, org, move2); + Math3D.VectorAdd(check.s.origin, move2, check.s.origin); + + // may have pushed them off an edge + if (check.groundentity != pusher) + check.groundentity = null; + + block = SV_TestEntityPosition(check); + if (block == null) { // pushed ok + GameBase.gi.linkentity(check); + // impact? + continue; + } + + // if it is ok to leave in the old position, do it + // this is only relevent for riding entities, not pushed + // FIXME: this doesn't acount for rotation + Math3D.VectorSubtract(check.s.origin, move, check.s.origin); + block = SV_TestEntityPosition(check); + + if (block == null) { + GameBase.pushed_p--; + continue; + } + } + + // save off the obstacle so we can call the block function + GameBase.obstacle = check; + + // move back any entities we already moved + // go backwards, so if the same entity was pushed + // twice, it goes back to the original position + for (int ip = GameBase.pushed_p - 1; ip >= 0; ip--) { + p = GameBase.pushed[ip]; + Math3D.VectorCopy(p.origin, p.ent.s.origin); + Math3D.VectorCopy(p.angles, p.ent.s.angles); + if (p.ent.client != null) { + p.ent.client.ps.pmove.delta_angles[Defines.YAW] = (short) p.deltayaw; + } + GameBase.gi.linkentity(p.ent); + } + return false; + } + + // FIXME: is there a better way to handle this? + // see if anything we moved has touched a trigger + for (int ip = GameBase.pushed_p - 1; ip >= 0; ip--) + GameBase.G_TouchTriggers(GameBase.pushed[ip].ent); + + return true; + } + + /* + * ================ SV_Physics_Pusher + * + * Bmodel objects don't interact with each other, but push all box objects + * ================ + */ + public static void SV_Physics_Pusher(edict_t ent) { + float[] move = { 0, 0, 0 }; + float[] amove = { 0, 0, 0 }; + edict_t part, mv; + + // if not a team captain, so movement will be handled elsewhere + if ((ent.flags & Defines.FL_TEAMSLAVE) != 0) + return; + + // make sure all team slaves can move before commiting + // any moves or calling any think functions + // if the move is blocked, all moved objects will be backed out + // retry: + GameBase.pushed_p = 0; + for (part = ent; part != null; part = part.teamchain) { + if (part.velocity[0] != 0 || part.velocity[1] != 0 + || part.velocity[2] != 0 || part.avelocity[0] != 0 + || part.avelocity[1] != 0 || part.avelocity[2] != 0) { // object + // is + // moving + Math3D.VectorScale(part.velocity, Defines.FRAMETIME, move); + Math3D.VectorScale(part.avelocity, Defines.FRAMETIME, amove); + + if (!SV_Push(part, move, amove)) + break; // move was blocked + } + } + if (GameBase.pushed_p > Defines.MAX_EDICTS) + SV_GAME.PF_error(Defines.ERR_FATAL, + "pushed_p > &pushed[MAX_EDICTS], memory corrupted"); + + if (part != null) { + // the move failed, bump all nextthink times and back out moves + for (mv = ent; mv != null; mv = mv.teamchain) { + if (mv.nextthink > 0) + mv.nextthink += Defines.FRAMETIME; + } + + // if the pusher has a "blocked" function, call it + // otherwise, just stay in place until the obstacle is gone + if (part.blocked != null) + part.blocked.blocked(part, GameBase.obstacle); + } else { // the move succeeded, so call all think functions + for (part = ent; part != null; part = part.teamchain) { + SV_RunThink(part); + } + } + } + + // ================================================================== + + /* + * ============= SV_Physics_None + * + * Non moving objects can only think ============= + */ + public static void SV_Physics_None(edict_t ent) { + // regular thinking + SV_RunThink(ent); + } + + /* + * ============= SV_Physics_Noclip + * + * A moving object that doesn't obey physics ============= + */ + public static void SV_Physics_Noclip(edict_t ent) { + // regular thinking + if (!SV_RunThink(ent)) + return; + + Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, + ent.s.angles); + Math3D.VectorMA(ent.s.origin, Defines.FRAMETIME, ent.velocity, + ent.s.origin); + + GameBase.gi.linkentity(ent); + } + + /* + * ============================================================================== + * + * TOSS / BOUNCE + * + * ============================================================================== + */ + + /* + * ============= SV_Physics_Toss + * + * Toss, bounce, and fly movement. When onground, do nothing. ============= + */ + public static void SV_Physics_Toss(edict_t ent) { + + trace_t trace; + float[] move = { 0, 0, 0 }; + float backoff; + edict_t slave; + boolean wasinwater; + boolean isinwater; + float[] old_origin = { 0, 0, 0 }; + + // regular thinking + SV_RunThink(ent); + + // if not a team captain, so movement will be handled elsewhere + if ((ent.flags & Defines.FL_TEAMSLAVE) != 0) + return; + + if (ent.velocity[2] > 0) + ent.groundentity = null; + + // check for the groundentity going away + if (ent.groundentity != null) + if (!ent.groundentity.inuse) + ent.groundentity = null; + + // if onground, return without moving + if (ent.groundentity != null) + return; + + Math3D.VectorCopy(ent.s.origin, old_origin); + + SV_CheckVelocity(ent); + + // add gravity + if (ent.movetype != Defines.MOVETYPE_FLY + && ent.movetype != Defines.MOVETYPE_FLYMISSILE) + SV_AddGravity(ent); + + // move angles + Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, + ent.s.angles); + + // move origin + Math3D.VectorScale(ent.velocity, Defines.FRAMETIME, move); + trace = SV_PushEntity(ent, move); + if (!ent.inuse) + return; + + if (trace.fraction < 1) { + if (ent.movetype == Defines.MOVETYPE_BOUNCE) + backoff = 1.5f; + else + backoff = 1; + + GameBase.ClipVelocity(ent.velocity, trace.plane.normal, + ent.velocity, backoff); + + // stop if on ground + if (trace.plane.normal[2] > 0.7) { + if (ent.velocity[2] < 60 + || ent.movetype != Defines.MOVETYPE_BOUNCE) { + ent.groundentity = trace.ent; + ent.groundentity_linkcount = trace.ent.linkcount; + Math3D.VectorCopy(Globals.vec3_origin, ent.velocity); + Math3D.VectorCopy(Globals.vec3_origin, ent.avelocity); + } + } + + // if (ent.touch) + // ent.touch (ent, trace.ent, &trace.plane, trace.surface); + } + + // check for water transition + wasinwater = (ent.watertype & Defines.MASK_WATER) != 0; + ent.watertype = GameBase.gi.pointcontents.pointcontents(ent.s.origin); + isinwater = (ent.watertype & Defines.MASK_WATER) != 0; + + if (isinwater) + ent.waterlevel = 1; + else + ent.waterlevel = 0; + + if (!wasinwater && isinwater) + GameBase.gi.positioned_sound(old_origin, ent, Defines.CHAN_AUTO, + GameBase.gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); + else if (wasinwater && !isinwater) + GameBase.gi.positioned_sound(ent.s.origin, ent, Defines.CHAN_AUTO, + GameBase.gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); + + // move teamslaves + for (slave = ent.teamchain; slave != null; slave = slave.teamchain) { + Math3D.VectorCopy(ent.s.origin, slave.s.origin); + GameBase.gi.linkentity(slave); + } + } + + /* + * =============================================================================== + * + * STEPPING MOVEMENT + * + * =============================================================================== + */ + + /* + * ============= SV_Physics_Step + * + * Monsters freefall when they don't have a ground entity, otherwise all + * movement is done with discrete steps. + * + * This is also used for objects that have become still on the ground, but + * will fall if the floor is pulled out from under them. FIXME: is this + * true? ============= + */ + + // FIXME: hacked in for E3 demo + public static void SV_AddRotationalFriction(edict_t ent) { + int n; + float adjustment; + + Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, + ent.s.angles); + adjustment = Defines.FRAMETIME * Defines.sv_stopspeed + * Defines.sv_friction; + for (n = 0; n < 3; n++) { + if (ent.avelocity[n] > 0) { + ent.avelocity[n] -= adjustment; + if (ent.avelocity[n] < 0) + ent.avelocity[n] = 0; + } else { + ent.avelocity[n] += adjustment; + if (ent.avelocity[n] > 0) + ent.avelocity[n] = 0; + } + } + } + + public static void SV_Physics_Step(edict_t ent) { + boolean wasonground; + boolean hitsound = false; + float vel[]; + float speed, newspeed, control; + float friction; + edict_t groundentity; + int mask; + + // airborn monsters should always check for ground + if (ent.groundentity == null) + M.M_CheckGround(ent); + + groundentity = ent.groundentity; + + SV_CheckVelocity(ent); + + if (groundentity != null) + wasonground = true; + else + wasonground = false; + + if (ent.avelocity[0] != 0 || ent.avelocity[1] != 0 + || ent.avelocity[2] != 0) + SV_AddRotationalFriction(ent); + + // add gravity except: + // flying monsters + // swimming monsters who are in the water + if (!wasonground) + if (0 == (ent.flags & Defines.FL_FLY)) + if (!((ent.flags & Defines.FL_SWIM) != 0 && (ent.waterlevel > 2))) { + if (ent.velocity[2] < GameBase.sv_gravity.value * -0.1) + hitsound = true; + if (ent.waterlevel == 0) + SV_AddGravity(ent); + } + + // friction for flying monsters that have been given vertical velocity + if ((ent.flags & Defines.FL_FLY) != 0 && (ent.velocity[2] != 0)) { + speed = Math.abs(ent.velocity[2]); + control = speed < Defines.sv_stopspeed ? Defines.sv_stopspeed + : speed; + friction = Defines.sv_friction / 3; + newspeed = speed - (Defines.FRAMETIME * control * friction); + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + ent.velocity[2] *= newspeed; + } + + // friction for flying monsters that have been given vertical velocity + if ((ent.flags & Defines.FL_SWIM) != 0 && (ent.velocity[2] != 0)) { + speed = Math.abs(ent.velocity[2]); + control = speed < Defines.sv_stopspeed ? Defines.sv_stopspeed + : speed; + newspeed = speed + - (Defines.FRAMETIME * control * Defines.sv_waterfriction * ent.waterlevel); + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + ent.velocity[2] *= newspeed; + } + + if (ent.velocity[2] != 0 || ent.velocity[1] != 0 + || ent.velocity[0] != 0) { + // apply friction + // let dead monsters who aren't completely onground slide + if ((wasonground) + || 0 != (ent.flags & (Defines.FL_SWIM | Defines.FL_FLY))) + if (!(ent.health <= 0.0 && !M.M_CheckBottom(ent))) { + vel = ent.velocity; + speed = (float) Math + .sqrt(vel[0] * vel[0] + vel[1] * vel[1]); + if (speed != 0) { + friction = Defines.sv_friction; + + control = speed < Defines.sv_stopspeed ? Defines.sv_stopspeed + : speed; + newspeed = speed - Defines.FRAMETIME * control + * friction; + + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + vel[0] *= newspeed; + vel[1] *= newspeed; + } + } + + if ((ent.svflags & Defines.SVF_MONSTER) != 0) + mask = Defines.MASK_MONSTERSOLID; + else + mask = Defines.MASK_SOLID; + + SV_FlyMove(ent, Defines.FRAMETIME, mask); + + GameBase.gi.linkentity(ent); + GameBase.G_TouchTriggers(ent); + if (!ent.inuse) + return; + + if (ent.groundentity != null) + if (!wasonground) + if (hitsound) + GameBase.gi.sound(ent, 0, GameBase.gi + .soundindex("world/land.wav"), 1, 1, 0); + } + + // regular thinking + SV_RunThink(ent); + } + + /* + * ============= SV_movestep + * + * Called by monster program code. The move will be adjusted for slopes and + * stairs, but if the move isn't possible, no move is done, false is + * returned, and pr_global_struct.trace_normal is set to the normal of the + * blocking wall ============= + */ + // FIXME since we need to test end position contents here, can we avoid + // doing + // it again later in catagorize position? + public static boolean SV_movestep(edict_t ent, float[] move, boolean relink) { + float dz; + float[] oldorg = { 0, 0, 0 }; + float[] neworg = { 0, 0, 0 }; + float[] end = { 0, 0, 0 }; + + trace_t trace = null; // = new trace_t(); + int i; + float stepsize; + float[] test = { 0, 0, 0 }; + int contents; + + // try the move + Math3D.VectorCopy(ent.s.origin, oldorg); + Math3D.VectorAdd(ent.s.origin, move, neworg); + + // flying monsters don't step up + if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0) { + // try one move with vertical motion, then one without + for (i = 0; i < 2; i++) { + Math3D.VectorAdd(ent.s.origin, move, neworg); + if (i == 0 && ent.enemy != null) { + if (ent.goalentity == null) + ent.goalentity = ent.enemy; + dz = ent.s.origin[2] - ent.goalentity.s.origin[2]; + if (ent.goalentity.client != null) { + if (dz > 40) + neworg[2] -= 8; + if (!((ent.flags & Defines.FL_SWIM) != 0 && (ent.waterlevel < 2))) + if (dz < 30) + neworg[2] += 8; + } else { + if (dz > 8) + neworg[2] -= 8; + else if (dz > 0) + neworg[2] -= dz; + else if (dz < -8) + neworg[2] += 8; + else + neworg[2] += dz; + } + } + trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, + neworg, ent, Defines.MASK_MONSTERSOLID); + + // fly monsters don't enter water voluntarily + if ((ent.flags & Defines.FL_FLY) != 0) { + if (ent.waterlevel == 0) { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + ent.mins[2] + 1; + contents = GameBase.gi.pointcontents + .pointcontents(test); + if ((contents & Defines.MASK_WATER) != 0) + return false; + } + } + + // swim monsters don't exit water voluntarily + if ((ent.flags & Defines.FL_SWIM) != 0) { + if (ent.waterlevel < 2) { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + ent.mins[2] + 1; + contents = GameBase.gi.pointcontents + .pointcontents(test); + if ((contents & Defines.MASK_WATER) == 0) + return false; + } + } + + if (trace.fraction == 1) { + Math3D.VectorCopy(trace.endpos, ent.s.origin); + if (relink) { + GameBase.gi.linkentity(ent); + GameBase.G_TouchTriggers(ent); + } + return true; + } + + if (ent.enemy == null) + break; + } + + return false; + } + + // push down from a step height above the wished position + if ((ent.monsterinfo.aiflags & Defines.AI_NOSTEP) == 0) + stepsize = GameBase.STEPSIZE; + else + stepsize = 1; + + neworg[2] += stepsize; + Math3D.VectorCopy(neworg, end); + end[2] -= stepsize * 2; + + trace = GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, + Defines.MASK_MONSTERSOLID); + + if (trace.allsolid) + return false; + + if (trace.startsolid) { + neworg[2] -= stepsize; + trace = GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, + Defines.MASK_MONSTERSOLID); + if (trace.allsolid || trace.startsolid) + return false; + } + + // don't go in to water + if (ent.waterlevel == 0) { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + ent.mins[2] + 1; + contents = GameBase.gi.pointcontents.pointcontents(test); + + if ((contents & Defines.MASK_WATER) != 0) + return false; + } + + if (trace.fraction == 1) { + // if monster had the ground pulled out, go ahead and fall + if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { + Math3D.VectorAdd(ent.s.origin, move, ent.s.origin); + if (relink) { + GameBase.gi.linkentity(ent); + GameBase.G_TouchTriggers(ent); + } + ent.groundentity = null; + return true; + } + + return false; // walked off an edge + } + + // check point traces down for dangling corners + Math3D.VectorCopy(trace.endpos, ent.s.origin); + + if (!M.M_CheckBottom(ent)) { + if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { + // entity had floor mostly pulled out from underneath it + // and is trying to correct + if (relink) { + GameBase.gi.linkentity(ent); + GameBase.G_TouchTriggers(ent); + } + return true; + } + Math3D.VectorCopy(oldorg, ent.s.origin); + return false; + } + + if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { + ent.flags &= ~Defines.FL_PARTIALGROUND; + } + ent.groundentity = trace.ent; + ent.groundentity_linkcount = trace.ent.linkcount; + + // the move is ok + if (relink) { + GameBase.gi.linkentity(ent); + GameBase.G_TouchTriggers(ent); + } + return true; + } + + /* + * ====================== SV_StepDirection + * + * Turns to the movement direction, and walks the current distance if facing + * it. + * + * ====================== + */ + public static boolean SV_StepDirection(edict_t ent, float yaw, float dist) { + float[] move = { 0, 0, 0 }; + float[] oldorigin = { 0, 0, 0 }; + float delta; + + ent.ideal_yaw = yaw; + M.M_ChangeYaw(ent); + + yaw = (float) (yaw * Math.PI * 2 / 360); + move[0] = (float) Math.cos(yaw) * dist; + move[1] = (float) Math.sin(yaw) * dist; + move[2] = 0; + + Math3D.VectorCopy(ent.s.origin, oldorigin); + if (SV_movestep(ent, move, false)) { + delta = ent.s.angles[Defines.YAW] - ent.ideal_yaw; + if (delta > 45 && delta < 315) { // not turned far enough, so don't + // take the step + Math3D.VectorCopy(oldorigin, ent.s.origin); + } + GameBase.gi.linkentity(ent); + GameBase.G_TouchTriggers(ent); + return true; + } + GameBase.gi.linkentity(ent); + GameBase.G_TouchTriggers(ent); + return false; + } + + /* + * ====================== SV_FixCheckBottom + * + * ====================== + */ + public static void SV_FixCheckBottom(edict_t ent) { + ent.flags |= Defines.FL_PARTIALGROUND; + } + + public static void SV_NewChaseDir(edict_t actor, edict_t enemy, float dist) { + float deltax, deltay; + float d[] = { 0, 0, 0 }; + float tdir, olddir, turnaround; + + //FIXME: how did we get here with no enemy + if (enemy == null) { + Com.DPrintf("SV_NewChaseDir without enemy!\n"); + return; + } + olddir = Math3D.anglemod((int) (actor.ideal_yaw / 45) * 45); + turnaround = Math3D.anglemod(olddir - 180); + + deltax = enemy.s.origin[0] - actor.s.origin[0]; + deltay = enemy.s.origin[1] - actor.s.origin[1]; + if (deltax > 10) + d[1] = 0; + else if (deltax < -10) + d[1] = 180; + else + d[1] = GameBase.DI_NODIR; + if (deltay < -10) + d[2] = 270; + else if (deltay > 10) + d[2] = 90; + else + d[2] = GameBase.DI_NODIR; + + // try direct route + if (d[1] != GameBase.DI_NODIR && d[2] != GameBase.DI_NODIR) { + if (d[1] == 0) + tdir = d[2] == 90 ? 45 : 315; + else + tdir = d[2] == 90 ? 135 : 215; + + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + + // try other directions + if (((Lib.rand() & 3) & 1) != 0 || Math.abs(deltay) > Math.abs(deltax)) { + tdir = d[1]; + d[1] = d[2]; + d[2] = tdir; + } + + if (d[1] != GameBase.DI_NODIR && d[1] != turnaround + && SV_StepDirection(actor, d[1], dist)) + return; + + if (d[2] != GameBase.DI_NODIR && d[2] != turnaround + && SV_StepDirection(actor, d[2], dist)) + return; + + /* there is no direct path to the player, so pick another direction */ + + if (olddir != GameBase.DI_NODIR + && SV_StepDirection(actor, olddir, dist)) + return; + + if ((Lib.rand() & 1) != 0) /* randomly determine direction of search */{ + for (tdir = 0; tdir <= 315; tdir += 45) + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } else { + for (tdir = 315; tdir >= 0; tdir -= 45) + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + + if (turnaround != GameBase.DI_NODIR + && SV_StepDirection(actor, turnaround, dist)) + return; + + actor.ideal_yaw = olddir; // can't move + + // if a bridge was pulled out from underneath a monster, it may not have + // a valid standing position at all + + if (!M.M_CheckBottom(actor)) + SV_FixCheckBottom(actor); + } + + /* + * ====================== SV_CloseEnough + * + * ====================== + *///ok + public static boolean SV_CloseEnough(edict_t ent, edict_t goal, float dist) { + int i; + + for (i = 0; i < 3; i++) { + if (goal.absmin[i] > ent.absmax[i] + dist) + return false; + if (goal.absmax[i] < ent.absmin[i] - dist) + return false; + } + return true; + } +} \ No newline at end of file diff --git a/src/jake2/server/SV_CCMDS.java b/src/jake2/server/SV_CCMDS.java index e6fd004..38e296e 100644 --- a/src/jake2/server/SV_CCMDS.java +++ b/src/jake2/server/SV_CCMDS.java @@ -19,22 +19,41 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Created on 18.01.2004 by RST. -// $Id: SV_CCMDS.java,v 1.11 2004-09-10 19:02:56 salomo Exp $ +// $Id: SV_CCMDS.java,v 1.12 2004-09-22 19:22:12 salomo Exp $ package jake2.server; +import jake2.Defines; import jake2.Globals; -import jake2.game.*; -import jake2.qcommon.*; +import jake2.game.Cmd; +import jake2.game.EndianHandler; +import jake2.game.GameSVCmds; +import jake2.game.GameSave; +import jake2.game.Info; +import jake2.game.cvar_t; +import jake2.qcommon.CM; +import jake2.qcommon.Com; +import jake2.qcommon.Cvar; +import jake2.qcommon.FS; +import jake2.qcommon.MSG; +import jake2.qcommon.Netchan; +import jake2.qcommon.SZ; +import jake2.qcommon.netadr_t; +import jake2.qcommon.sizebuf_t; +import jake2.qcommon.xcommand_t; import jake2.sys.NET; import jake2.sys.Sys; +import jake2.util.Lib; import jake2.util.QuakeFile; import jake2.util.Vargs; -import java.io.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; import java.util.Calendar; -public class SV_CCMDS extends SV_ENTS { +public class SV_CCMDS { /* =============================================================================== @@ -56,7 +75,7 @@ public class SV_CCMDS extends SV_ENTS { int i, slot; // only dedicated servers send heartbeats - if (dedicated.value == 0) { + if (Globals.dedicated.value == 0) { Com.Printf("Only dedicated servers use masters.\n"); return; } @@ -64,34 +83,31 @@ public class SV_CCMDS extends SV_ENTS { // make sure the server is listed public Cvar.Set("public", "1"); - for (i= 1; i < MAX_MASTERS; i++) - master_adr[i]= new netadr_t(); + for (i = 1; i < Defines.MAX_MASTERS; i++) + SV_MAIN.master_adr[i] = new netadr_t(); - slot= 1; // slot 0 will always contain the id master - for (i= 1; i < Cmd.Argc(); i++) { - if (slot == MAX_MASTERS) + slot = 1; // slot 0 will always contain the id master + for (i = 1; i < Cmd.Argc(); i++) { + if (slot == Defines.MAX_MASTERS) break; - if (!NET.StringToAdr(Cmd.Argv(i), master_adr[i])) { + if (!NET.StringToAdr(Cmd.Argv(i), SV_MAIN.master_adr[i])) { Com.Printf("Bad address: " + Cmd.Argv(i) + "\n"); continue; } - if (master_adr[slot].port == 0) - master_adr[slot].port= //BigShort (PORT_MASTER); - PORT_MASTER; - - Com.Printf("Master server at " + NET.AdrToString(master_adr[slot]) + "\n"); + if (SV_MAIN.master_adr[slot].port == 0) + SV_MAIN.master_adr[slot].port = Defines.PORT_MASTER; + Com.Printf("Master server at " + NET.AdrToString(SV_MAIN.master_adr[slot]) + "\n"); Com.Printf("Sending a ping.\n"); - Netchan.OutOfBandPrint(NS_SERVER, master_adr[slot], "ping"); + Netchan.OutOfBandPrint(Defines.NS_SERVER, SV_MAIN.master_adr[slot], "ping"); slot++; } - svs.last_heartbeat= -9999999; + SV_INIT.svs.last_heartbeat = -9999999; } - /* ================== SV_SetPlayer @@ -108,19 +124,19 @@ public class SV_CCMDS extends SV_ENTS { if (Cmd.Argc() < 2) return false; - s= Cmd.Argv(1); + s = Cmd.Argv(1); // numeric values are just slot numbers if (s.charAt(0) >= '0' && s.charAt(0) <= '9') { - idnum= atoi(Cmd.Argv(1)); - if (idnum < 0 || idnum >= maxclients.value) { + idnum = Lib.atoi(Cmd.Argv(1)); + if (idnum < 0 || idnum >= SV_MAIN.maxclients.value) { Com.Printf("Bad client slot: " + idnum + "\n"); return false; } - sv_client= svs.clients[idnum]; - sv_player= sv_client.edict; - if (0 == sv_client.state) { + SV_MAIN.sv_client = SV_INIT.svs.clients[idnum]; + SV_USER.sv_player = SV_MAIN.sv_client.edict; + if (0 == SV_MAIN.sv_client.state) { Com.Printf("Client " + idnum + " is not active\n"); return false; } @@ -128,13 +144,13 @@ public class SV_CCMDS extends SV_ENTS { } // check for a name match - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; if (0 == cl.state) continue; - if (0 == strcmp(cl.name, s)) { - sv_client= cl; - sv_player= sv_client.edict; + if (0 == Lib.strcmp(cl.name, s)) { + SV_MAIN.sv_client = cl; + SV_USER.sv_player = SV_MAIN.sv_client.edict; return true; } } @@ -142,7 +158,6 @@ public class SV_CCMDS extends SV_ENTS { Com.Printf("Userid " + s + " is not on the server\n"); return false; } - /* =============================================================================== @@ -158,7 +173,6 @@ public class SV_CCMDS extends SV_ENTS { catch (Exception e) { } } - /* ===================== SV_WipeSavegame @@ -172,32 +186,31 @@ public class SV_CCMDS extends SV_ENTS { Com.DPrintf("SV_WipeSaveGame(" + savename + ")\n"); - name= FS.Gamedir() + "/save/" + savename + "/server.ssv"; + name = FS.Gamedir() + "/save/" + savename + "/server.ssv"; remove(name); - name= FS.Gamedir() + "/save/" + savename + "/game.ssv"; + name = FS.Gamedir() + "/save/" + savename + "/game.ssv"; remove(name); - name= FS.Gamedir() + "/save/" + savename + "/*.sav"; + name = FS.Gamedir() + "/save/" + savename + "/*.sav"; - File f= Sys.FindFirst(name, 0, 0); + File f = Sys.FindFirst(name, 0, 0); while (f != null) { f.delete(); - f= Sys.FindNext(); + f = Sys.FindNext(); } Sys.FindClose(); - name= FS.Gamedir() + "/save/" + savename + "/*.sv2"; + name = FS.Gamedir() + "/save/" + savename + "/*.sv2"; - f= Sys.FindFirst(name, 0, 0); + f = Sys.FindFirst(name, 0, 0); while (f != null) { f.delete(); - f= Sys.FindNext(); + f = Sys.FindNext(); } Sys.FindClose(); } - /* ================ CopyFile @@ -205,18 +218,18 @@ public class SV_CCMDS extends SV_ENTS { */ public static void CopyFile(String src, String dst) { RandomAccessFile f1, f2; - int l= -1; - byte buffer[]= new byte[65536]; + int l = -1; + byte buffer[] = new byte[65536]; //Com.DPrintf("CopyFile (" + src + ", " + dst + ")\n"); try { - f1= new RandomAccessFile(src, "r"); + f1 = new RandomAccessFile(src, "r"); } catch (Exception e) { return; } try { - f2= new RandomAccessFile(dst, "rw"); + f2 = new RandomAccessFile(dst, "rw"); } catch (Exception e) { try { @@ -231,7 +244,7 @@ public class SV_CCMDS extends SV_ENTS { while (true) { try { - l= f1.read(buffer, 0, 65536); + l = f1.read(buffer, 0, 65536); } catch (IOException e1) { @@ -263,7 +276,6 @@ public class SV_CCMDS extends SV_ENTS { e2.printStackTrace(); } } - /* ================ SV_CopySaveGame @@ -281,38 +293,37 @@ public class SV_CCMDS extends SV_ENTS { SV_WipeSavegame(dst); // copy the savegame over - name= FS.Gamedir() + "/save/" + src + "/server.ssv"; - name2= FS.Gamedir() + "/save/" + dst + "/server.ssv"; + name = FS.Gamedir() + "/save/" + src + "/server.ssv"; + name2 = FS.Gamedir() + "/save/" + dst + "/server.ssv"; FS.CreatePath(name2); CopyFile(name, name2); - name= FS.Gamedir() + "/save/" + src + "/game.ssv"; - name2= FS.Gamedir() + "/save/" + dst + "/game.ssv"; + name = FS.Gamedir() + "/save/" + src + "/game.ssv"; + name2 = FS.Gamedir() + "/save/" + dst + "/game.ssv"; CopyFile(name, name2); - String name1= FS.Gamedir() + "/save/" + src + "/"; - len= name1.length(); - name= FS.Gamedir() + "/save/" + src + "/*.sav"; + String name1 = FS.Gamedir() + "/save/" + src + "/"; + len = name1.length(); + name = FS.Gamedir() + "/save/" + src + "/*.sav"; - found= Sys.FindFirst(name, 0, 0); + found = Sys.FindFirst(name, 0, 0); while (found != null) { - name= name1 + found.getName(); - name2= FS.Gamedir() + "/save/" + dst + "/" + found.getName(); + name = name1 + found.getName(); + name2 = FS.Gamedir() + "/save/" + dst + "/" + found.getName(); CopyFile(name, name2); // change sav to sv2 - name= name.substring(0, name.length() - 3) + "sv2"; - name2= name2.substring(0, name2.length() - 3) + "sv2"; + name = name.substring(0, name.length() - 3) + "sv2"; + name2 = name2.substring(0, name2.length() - 3) + "sv2"; CopyFile(name, name2); - found= Sys.FindNext(); + found = Sys.FindNext(); } Sys.FindClose(); } - /* ============== SV_WriteLevelFile @@ -326,13 +337,13 @@ public class SV_CCMDS extends SV_ENTS { Com.DPrintf("SV_WriteLevelFile()\n"); - name= FS.Gamedir() + "/save/current/" + sv.name + ".sv2"; + name = FS.Gamedir() + "/save/current/" + SV_INIT.sv.name + ".sv2"; try { - f= new QuakeFile(name, "rw"); + f = new QuakeFile(name, "rw"); - for (int i= 0; i < MAX_CONFIGSTRINGS; i++) - f.writeString(sv.configstrings[i]); + for (int i = 0; i < Defines.MAX_CONFIGSTRINGS; i++) + f.writeString(SV_INIT.sv.configstrings[i]); CM.CM_WritePortalState(f); f.close(); @@ -342,10 +353,9 @@ public class SV_CCMDS extends SV_ENTS { e.printStackTrace(); } - name= FS.Gamedir() + "/save/current/" + sv.name + ".sav"; + name = FS.Gamedir() + "/save/current/" + SV_INIT.sv.name + ".sav"; GameSave.WriteLevel(name); } - /* ============== SV_ReadLevelFile @@ -359,12 +369,12 @@ public class SV_CCMDS extends SV_ENTS { Com.DPrintf("SV_ReadLevelFile()\n"); - name= FS.Gamedir() + "/save/current/" + sv.name + ".sv2"; + name = FS.Gamedir() + "/save/current/" + SV_INIT.sv.name + ".sv2"; try { - f= new QuakeFile(name, "r"); + f = new QuakeFile(name, "r"); - for (int n= 0; n < MAX_CONFIGSTRINGS; n++) - sv.configstrings[n]= f.readString(); + for (int n = 0; n < Defines.MAX_CONFIGSTRINGS; n++) + SV_INIT.sv.configstrings[n] = f.readString(); CM.CM_ReadPortalState(f); @@ -375,10 +385,9 @@ public class SV_CCMDS extends SV_ENTS { e1.printStackTrace(); } - name= FS.Gamedir() + "/save/current/" + sv.name + ".sav"; + name = FS.Gamedir() + "/save/current/" + SV_INIT.sv.name + ".sav"; GameSave.ReadLevel(name); } - /* ============== SV_WriteServerFile @@ -393,41 +402,42 @@ public class SV_CCMDS extends SV_ENTS { Com.DPrintf("SV_WriteServerFile(" + (autosave ? "true" : "false") + ")\n"); - filename= FS.Gamedir() + "/save/current/server.ssv"; + filename = FS.Gamedir() + "/save/current/server.ssv"; try { - f= new QuakeFile(filename, "rw"); + f = new QuakeFile(filename, "rw"); if (!autosave) { - Calendar c= Calendar.getInstance(); - comment= + Calendar c = Calendar.getInstance(); + comment = Com.sprintf( "%2i:%2i %2i/%2i ", - new Vargs().add(c.get(Calendar.HOUR_OF_DAY)).add(c.get(Calendar.MINUTE)).add(c.get(Calendar.MONTH) + 1).add( + new Vargs().add(c.get(Calendar.HOUR_OF_DAY)).add(c.get(Calendar.MINUTE)).add( + c.get(Calendar.MONTH) + 1).add( c.get(Calendar.DAY_OF_MONTH))); - comment += sv.configstrings[CS_NAME]; + comment += SV_INIT.sv.configstrings[Defines.CS_NAME]; } else { // autosaved - comment= "ENTERING " + sv.configstrings[CS_NAME]; + comment = "ENTERING " + SV_INIT.sv.configstrings[Defines.CS_NAME]; } f.writeString(comment); - f.writeString(svs.mapcmd); + f.writeString(SV_INIT.svs.mapcmd); // write the mapcmd // write all CVAR_LATCH cvars // these will be things like coop, skill, deathmatch, etc - for (var= Globals.cvar_vars; var != null; var= var.next) { - if (0 == (var.flags & CVAR_LATCH)) + for (var = Globals.cvar_vars; var != null; var = var.next) { + if (0 == (var.flags & Defines.CVAR_LATCH)) continue; - if (var.name.length() >= MAX_OSPATH - 1 || var.string.length() >= 128 - 1) { + if (var.name.length() >= Defines.MAX_OSPATH - 1 || var.string.length() >= 128 - 1) { Com.Printf("Cvar too long: " + var.name + " = " + var.string + "\n"); continue; } - name= var.name; - string= var.string; + name = var.name; + string = var.string; try { f.writeString(name); f.writeString(string); @@ -445,10 +455,9 @@ public class SV_CCMDS extends SV_ENTS { } // write game state - filename= FS.Gamedir() + "/save/current/game.ssv"; + filename = FS.Gamedir() + "/save/current/game.ssv"; GameSave.WriteGame(filename, autosave); } - /* ============== SV_ReadServerFile @@ -456,31 +465,31 @@ public class SV_CCMDS extends SV_ENTS { ============== */ public static void SV_ReadServerFile() { - String filename, name= "", string, comment, mapcmd; + String filename, name = "", string, comment, mapcmd; try { QuakeFile f; - mapcmd= ""; + mapcmd = ""; Com.DPrintf("SV_ReadServerFile()\n"); - filename= FS.Gamedir() + "/save/current/server.ssv"; + filename = FS.Gamedir() + "/save/current/server.ssv"; - f= new QuakeFile(filename, "r"); + f = new QuakeFile(filename, "r"); // read the comment field - comment= f.readString(); + comment = f.readString(); // read the mapcmd - mapcmd= f.readString(); + mapcmd = f.readString(); // read all CVAR_LATCH cvars // these will be things like coop, skill, deathmatch, etc while (true) { - name= f.readString(); + name = f.readString(); if (name == null) break; - string= f.readString(); + string = f.readString(); Com.DPrintf("Set " + name + " = " + string + "\n"); Cvar.ForceSet(name, string); @@ -489,12 +498,12 @@ public class SV_CCMDS extends SV_ENTS { f.close(); // start a new game fresh with new cvars - SV_InitGame(); + SV_INIT.SV_InitGame(); - svs.mapcmd= mapcmd; + SV_INIT.svs.mapcmd = mapcmd; // read game state - filename= FS.Gamedir() + "/save/current/game.ssv"; + filename = FS.Gamedir() + "/save/current/game.ssv"; GameSave.ReadGame(filename); } catch (Exception e) { @@ -502,7 +511,6 @@ public class SV_CCMDS extends SV_ENTS { e.printStackTrace(); } } - //========================================================= /* @@ -513,9 +521,8 @@ public class SV_CCMDS extends SV_ENTS { ================== */ public static void SV_DemoMap_f() { - SV_Map(true, Cmd.Argv(1), false); + SV_INIT.SV_Map(true, Cmd.Argv(1), false); } - /* ================== SV_GameMap_f @@ -550,48 +557,47 @@ public class SV_CCMDS extends SV_ENTS { FS.CreatePath(FS.Gamedir() + "/save/current/"); // check for clearing the current savegame - map= Cmd.Argv(1); + map = Cmd.Argv(1); if (map.charAt(0) == '*') { // wipe all the *.sav files SV_WipeSavegame("current"); } else { // save the map just exited - if (sv.state == ss_game) { + if (SV_INIT.sv.state == Defines.ss_game) { // clear all the client inuse flags before saving so that // when the level is re-entered, the clients will spawn // at spawn points instead of occupying body shells - savedInuse= new boolean[(int) maxclients.value]; - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - savedInuse[i]= cl.edict.inuse; - cl.edict.inuse= false; + savedInuse = new boolean[(int) SV_MAIN.maxclients.value]; + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + savedInuse[i] = cl.edict.inuse; + cl.edict.inuse = false; } SV_WriteLevelFile(); // we must restore these for clients to transfer over correctly - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - cl.edict.inuse= savedInuse[i]; + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + cl.edict.inuse = savedInuse[i]; } - savedInuse= null; + savedInuse = null; } } // start up the next map - SV_Map(false, Cmd.Argv(1), false); + SV_INIT.SV_Map(false, Cmd.Argv(1), false); // archive server state - svs.mapcmd= Cmd.Argv(1); + SV_INIT.svs.mapcmd = Cmd.Argv(1); // copy off the level to the autosave slot - if (0 == dedicated.value) { + if (0 == Globals.dedicated.value) { SV_WriteServerFile(true); SV_CopySaveGame("current", "save0"); } } - /* ================== SV_Map_f @@ -606,9 +612,9 @@ public class SV_CCMDS extends SV_ENTS { String expanded; // if not a pcx, demo, or cinematic, check to make sure the level exists - map= Cmd.Argv(1); + map = Cmd.Argv(1); if (map.indexOf(".") < 0) { - expanded= "maps/" + map + ".bsp"; + expanded = "maps/" + map + ".bsp"; if (FS.LoadFile(expanded) == null) { Com.Printf("Can't find " + expanded + "\n"); @@ -616,12 +622,11 @@ public class SV_CCMDS extends SV_ENTS { } } - sv.state= ss_dead; // don't save current level when changing + SV_INIT.sv.state = Defines.ss_dead; // don't save current level when changing SV_WipeSavegame("current"); SV_GameMap_f(); } - /* ===================================================================== @@ -649,15 +654,15 @@ public class SV_CCMDS extends SV_ENTS { Com.Printf("Loading game...\n"); - dir= Cmd.Argv(1); - if (strstr(dir, "..") || strstr(dir, "/") || strstr(dir, "\\")) { + dir = Cmd.Argv(1); + if (Lib.strstr(dir, "..") || Lib.strstr(dir, "/") || Lib.strstr(dir, "\\")) { Com.Printf("Bad savedir.\n"); } // make sure the server.ssv file exists - name= FS.Gamedir() + "/save/" + Cmd.Argv(1) + "/server.ssv"; + name = FS.Gamedir() + "/save/" + Cmd.Argv(1) + "/server.ssv"; try { - f= new RandomAccessFile(name, "r"); + f = new RandomAccessFile(name, "r"); } catch (FileNotFoundException e) { Com.Printf("No such savegame: " + name + "\n"); @@ -675,10 +680,9 @@ public class SV_CCMDS extends SV_ENTS { SV_ReadServerFile(); // go to the map - sv.state= ss_dead; // don't save current level when changing - SV_INIT.SV_Map(false, svs.mapcmd, true); + SV_INIT.sv.state = Defines.ss_dead; // don't save current level when changing + SV_INIT.SV_Map(false, SV_INIT.svs.mapcmd, true); } - /* ============== SV_Savegame_f @@ -688,7 +692,7 @@ public class SV_CCMDS extends SV_ENTS { public static void SV_Savegame_f() { String dir; - if (sv.state != ss_game) { + if (SV_INIT.sv.state != Defines.ss_game) { Com.Printf("You must be in a game to save.\n"); return; } @@ -703,18 +707,18 @@ public class SV_CCMDS extends SV_ENTS { return; } - if (0 == strcmp(Cmd.Argv(1), "current")) { + if (0 == Lib.strcmp(Cmd.Argv(1), "current")) { Com.Printf("Can't save to 'current'\n"); return; } - if (maxclients.value == 1 && svs.clients[0].edict.client.ps.stats[STAT_HEALTH] <= 0) { + if (SV_MAIN.maxclients.value == 1 && SV_INIT.svs.clients[0].edict.client.ps.stats[Defines.STAT_HEALTH] <= 0) { Com.Printf("\nCan't savegame while dead!\n"); return; } - dir= Cmd.Argv(1); - if (strstr(dir, "..") || strstr(dir, "/") || strstr(dir, "\\")) { + dir = Cmd.Argv(1); + if (Lib.strstr(dir, "..") || Lib.strstr(dir, "/") || Lib.strstr(dir, "\\")) { Com.Printf("Bad savedir.\n"); } @@ -737,7 +741,6 @@ public class SV_CCMDS extends SV_ENTS { SV_CopySaveGame("current", dir); Com.Printf("Done.\n"); } - //=============================================================== /* ================== @@ -747,7 +750,7 @@ public class SV_CCMDS extends SV_ENTS { ================== */ public static void SV_Kick_f() { - if (!svs.initialized) { + if (!SV_INIT.svs.initialized) { Com.Printf("No server running.\n"); return; } @@ -760,14 +763,13 @@ public class SV_CCMDS extends SV_ENTS { if (!SV_SetPlayer()) return; - SV_BroadcastPrintf(PRINT_HIGH, sv_client.name + " was kicked\n"); + SV_SEND.SV_BroadcastPrintf(Defines.PRINT_HIGH, SV_MAIN.sv_client.name + " was kicked\n"); // print directly, because the dropped client won't get the // SV_BroadcastPrintf message - SV_ClientPrintf(sv_client, PRINT_HIGH, "You were kicked from the game\n"); - SV_DropClient(sv_client); - sv_client.lastmessage= svs.realtime; // min case there is a funny zombie + SV_SEND.SV_ClientPrintf(SV_MAIN.sv_client, Defines.PRINT_HIGH, "You were kicked from the game\n"); + SV_MAIN.SV_DropClient(SV_MAIN.sv_client); + SV_MAIN.sv_client.lastmessage = SV_INIT.svs.realtime; // min case there is a funny zombie } - /* ================ SV_Status_f @@ -778,42 +780,42 @@ public class SV_CCMDS extends SV_ENTS { client_t cl; String s; int ping; - if (svs.clients == null) { + if (SV_INIT.svs.clients == null) { Com.Printf("No server running.\n"); return; } - Com.Printf("map : " + sv.name + "\n"); + Com.Printf("map : " + SV_INIT.sv.name + "\n"); Com.Printf("num score ping name lastmsg address qport \n"); Com.Printf("--- ----- ---- --------------- ------- --------------------- ------\n"); - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; if (0 == cl.state) continue; Com.Printf("%3i ", new Vargs().add(i)); - Com.Printf("%5i ", new Vargs().add(cl.edict.client.ps.stats[STAT_FRAGS])); + Com.Printf("%5i ", new Vargs().add(cl.edict.client.ps.stats[Defines.STAT_FRAGS])); - if (cl.state == cs_connected) + if (cl.state == Defines.cs_connected) Com.Printf("CNCT "); - else if (cl.state == cs_zombie) + else if (cl.state == Defines.cs_zombie) Com.Printf("ZMBI "); else { - ping= cl.ping < 9999 ? cl.ping : 9999; + ping = cl.ping < 9999 ? cl.ping : 9999; Com.Printf("%4i ", new Vargs().add(ping)); } Com.Printf("%s", new Vargs().add(cl.name)); - l= 16 - cl.name.length(); - for (j= 0; j < l; j++) + l = 16 - cl.name.length(); + for (j = 0; j < l; j++) Com.Printf(" "); - Com.Printf("%7i ", new Vargs().add(svs.realtime - cl.lastmessage)); + Com.Printf("%7i ", new Vargs().add(SV_INIT.svs.realtime - cl.lastmessage)); - s= NET.AdrToString(cl.netchan.remote_address); + s = NET.AdrToString(cl.netchan.remote_address); Com.Printf(s); - l= 22 - s.length(); - for (j= 0; j < l; j++) + l = 22 - s.length(); + for (j = 0; j < l; j++) Com.Printf(" "); Com.Printf("%5i", new Vargs().add(cl.netchan.qport)); @@ -822,7 +824,6 @@ public class SV_CCMDS extends SV_ENTS { } Com.Printf("\n"); } - /* ================== SV_ConSay_f @@ -837,32 +838,30 @@ public class SV_CCMDS extends SV_ENTS { if (Cmd.Argc() < 2) return; - text= "console: "; - p= Cmd.Args(); + text = "console: "; + p = Cmd.Args(); if (p.charAt(0) == '"') { - p= p.substring(1, p.length() - 1); + p = p.substring(1, p.length() - 1); } text += p; - for (j= 0; j < maxclients.value; j++) { - client= svs.clients[j]; - if (client.state != cs_spawned) + for (j = 0; j < SV_MAIN.maxclients.value; j++) { + client = SV_INIT.svs.clients[j]; + if (client.state != Defines.cs_spawned) continue; - SV_ClientPrintf(client, PRINT_CHAT, text + "\n"); + SV_SEND.SV_ClientPrintf(client, Defines.PRINT_CHAT, text + "\n"); } } - /* ================== SV_Heartbeat_f ================== */ public static void SV_Heartbeat_f() { - svs.last_heartbeat= -9999999; + SV_INIT.svs.last_heartbeat = -9999999; } - /* =========== SV_Serverinfo_f @@ -874,7 +873,6 @@ public class SV_CCMDS extends SV_ENTS { Com.Printf("Server info settings:\n"); Info.Print(Cvar.Serverinfo()); } - /* =========== SV_DumpUser_f @@ -893,10 +891,9 @@ public class SV_CCMDS extends SV_ENTS { Com.Printf("userinfo\n"); Com.Printf("--------\n"); - Info.Print(sv_client.userinfo); + Info.Print(SV_MAIN.sv_client.userinfo); } - /* ============== SV_ServerRecord_f @@ -908,8 +905,8 @@ public class SV_CCMDS extends SV_ENTS { public static void SV_ServerRecord_f() { //char name[MAX_OSPATH]; String name; - byte buf_data[]= new byte[32768]; - sizebuf_t buf= new sizebuf_t(); + byte buf_data[] = new byte[32768]; + sizebuf_t buf = new sizebuf_t(); int len; int i; @@ -918,12 +915,12 @@ public class SV_CCMDS extends SV_ENTS { return; } - if (svs.demofile != null) { + if (SV_INIT.svs.demofile != null) { Com.Printf("Already recording.\n"); return; } - if (sv.state != ss_game) { + if (SV_INIT.sv.state != Defines.ss_game) { Com.Printf("You must be in a level to record.\n"); return; } @@ -931,12 +928,12 @@ public class SV_CCMDS extends SV_ENTS { // // open the demo file // - name= FS.Gamedir() + "/demos/" + Cmd.Argv(1) + ".dm2"; + name = FS.Gamedir() + "/demos/" + Cmd.Argv(1) + ".dm2"; Com.Printf("recording to " + name + ".\n"); FS.CreatePath(name); try { - svs.demofile= new RandomAccessFile(name, "rw"); + SV_INIT.svs.demofile = new RandomAccessFile(name, "rw"); } catch (Exception e) { Com.Printf("ERROR: couldn't open.\n"); @@ -944,7 +941,7 @@ public class SV_CCMDS extends SV_ENTS { } // setup a buffer to catch all multicasts - SZ.Init(svs.demo_multicast, svs.demo_multicast_buf, svs.demo_multicast_buf.length); + SZ.Init(SV_INIT.svs.demo_multicast, SV_INIT.svs.demo_multicast_buf, SV_INIT.svs.demo_multicast_buf.length); // // write a single giant fake message with all the startup info @@ -956,31 +953,31 @@ public class SV_CCMDS extends SV_ENTS { // to make sure the protocol is right, and to set the gamedir // // send the serverdata - MSG.WriteByte(buf, svc_serverdata); - MSG.WriteLong(buf, PROTOCOL_VERSION); - MSG.WriteLong(buf, svs.spawncount); + MSG.WriteByte(buf, Defines.svc_serverdata); + MSG.WriteLong(buf, Defines.PROTOCOL_VERSION); + MSG.WriteLong(buf, SV_INIT.svs.spawncount); // 2 means server demo MSG.WriteByte(buf, 2); // demos are always attract loops MSG.WriteString(buf, Cvar.VariableString("gamedir")); MSG.WriteShort(buf, -1); // send full levelname - MSG.WriteString(buf, sv.configstrings[CS_NAME]); + MSG.WriteString(buf, SV_INIT.sv.configstrings[Defines.CS_NAME]); - for (i= 0; i < MAX_CONFIGSTRINGS; i++) - if (sv.configstrings[i].length() == 0) { - MSG.WriteByte(buf, svc_configstring); + for (i = 0; i < Defines.MAX_CONFIGSTRINGS; i++) + if (SV_INIT.sv.configstrings[i].length() == 0) { + MSG.WriteByte(buf, Defines.svc_configstring); MSG.WriteShort(buf, i); - MSG.WriteString(buf, sv.configstrings[i]); + MSG.WriteString(buf, SV_INIT.sv.configstrings[i]); } // write it to the demo file Com.DPrintf("signon message length: " + buf.cursize + "\n"); - len= EndianHandler.swapInt(buf.cursize); + len = EndianHandler.swapInt(buf.cursize); //fwrite(len, 4, 1, svs.demofile); //fwrite(buf.data, buf.cursize, 1, svs.demofile); try { - svs.demofile.writeInt(len); - svs.demofile.write(buf.data,0, buf.cursize); + SV_INIT.svs.demofile.writeInt(len); + SV_INIT.svs.demofile.write(buf.data, 0, buf.cursize); } catch (IOException e1) { // TODO: do quake2 error handling! @@ -989,7 +986,6 @@ public class SV_CCMDS extends SV_ENTS { // the rest of the demo file will be individual frames } - /* ============== SV_ServerStop_f @@ -998,20 +994,19 @@ public class SV_CCMDS extends SV_ENTS { ============== */ public static void SV_ServerStop_f() { - if (svs.demofile == null) { + if (SV_INIT.svs.demofile == null) { Com.Printf("Not doing a serverrecord.\n"); return; } try { - svs.demofile.close(); + SV_INIT.svs.demofile.close(); } catch (IOException e) { e.printStackTrace(); } - svs.demofile= null; + SV_INIT.svs.demofile = null; Com.Printf("Recording completed.\n"); } - /* =============== SV_KillServer_f @@ -1021,12 +1016,11 @@ public class SV_CCMDS extends SV_ENTS { =============== */ public static void SV_KillServer_f() { - if (!svs.initialized) + if (!SV_INIT.svs.initialized) return; - SV_Shutdown("Server was killed.\n", false); + SV_MAIN.SV_Shutdown("Server was killed.\n", false); NET.Config(false); // close network sockets } - /* =============== SV_ServerCommand_f @@ -1036,9 +1030,8 @@ public class SV_CCMDS extends SV_ENTS { */ public static void SV_ServerCommand_f() { - Game.ServerCommand(); + GameSVCmds.ServerCommand(); } - //=========================================================== /* @@ -1094,7 +1087,7 @@ public class SV_CCMDS extends SV_ENTS { } }); - if (dedicated.value != 0) + if (Globals.dedicated.value != 0) Cmd.AddCommand("say", new xcommand_t() { public void execute() { SV_ConSay_f(); @@ -1135,5 +1128,4 @@ public class SV_CCMDS extends SV_ENTS { } }); } - } diff --git a/src/jake2/server/SV_ENTS.java b/src/jake2/server/SV_ENTS.java index 8b3db67..706fc27 100644 --- a/src/jake2/server/SV_ENTS.java +++ b/src/jake2/server/SV_ENTS.java @@ -1,603 +1,620 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 17.01.2004 by RST. -// $Id: SV_ENTS.java,v 1.4 2004-08-29 21:39:25 hzi Exp $ - +// $Id: SV_ENTS.java,v 1.5 2004-09-22 19:22:12 salomo Exp $ package jake2.server; +import jake2.Defines; import jake2.game.*; import jake2.qcommon.*; +import jake2.util.Math3D; import java.io.IOException; -public class SV_ENTS extends SV_USER { - - /* - ============================================================================= - - Encode a client frame onto the network channel - - ============================================================================= - */ - - /* - ============= - SV_EmitPacketEntities - - Writes a delta update of an entity_state_t list to the message. - ============= - */ - static void SV_EmitPacketEntities(client_frame_t from, client_frame_t to, sizebuf_t msg) { - entity_state_t oldent = null, newent = null; - int oldindex, newindex; - int oldnum, newnum; - int from_num_entities; - int bits; - - MSG.WriteByte(msg, svc_packetentities); - - if (from == null) - from_num_entities = 0; - else - from_num_entities = from.num_entities; - - newindex = 0; - oldindex = 0; - while (newindex < to.num_entities || oldindex < from_num_entities) { - if (newindex >= to.num_entities) - newnum = 9999; - else { - newent = svs.client_entities[(to.first_entity + newindex) % svs.num_client_entities]; - newnum = newent.number; - } - - if (oldindex >= from_num_entities) - oldnum = 9999; - else { - oldent = svs.client_entities[(from.first_entity + oldindex) % svs.num_client_entities]; - oldnum = oldent.number; - } - - if (newnum == oldnum) { // delta update from old position - // because the force parm is false, this will not result - // in any bytes being emited if the entity has not changed at all - // note that players are always 'newentities', this updates their oldorigin always - // and prevents warping - MSG.WriteDeltaEntity(oldent, newent, msg, false, newent.number <= maxclients.value); - oldindex++; - newindex++; - continue; - } - - if (newnum < oldnum) { // this is a new entity, send it from the baseline - MSG.WriteDeltaEntity(sv.baselines[newnum], newent, msg, true, true); - newindex++; - continue; - } - - if (newnum > oldnum) { // the old entity isn't present in the new message - bits = U_REMOVE; - if (oldnum >= 256) - bits |= U_NUMBER16 | U_MOREBITS1; - - MSG.WriteByte(msg, bits & 255); - if ((bits & 0x0000ff00) != 0) - MSG.WriteByte(msg, (bits >> 8) & 255); - - if ((bits & U_NUMBER16) != 0) - MSG.WriteShort(msg, oldnum); - else - MSG.WriteByte(msg, oldnum); - - oldindex++; - continue; - } - } - - MSG.WriteShort(msg, 0); // end of packetentities - - } - - /* - ============= - SV_WritePlayerstateToClient - - ============= - */ - static void SV_WritePlayerstateToClient(client_frame_t from, client_frame_t to, sizebuf_t msg) { - int i; - int pflags; - // ptr - player_state_t ps, ops; - // mem - player_state_t dummy; - int statbits; - - ps = to.ps; - if (from == null) { - //memset (dummy, 0, sizeof(dummy)); - dummy = new player_state_t(); - ops = dummy; - } - else - ops = from.ps; - - // - // determine what needs to be sent - // - pflags = 0; - - if (ps.pmove.pm_type != ops.pmove.pm_type) - pflags |= PS_M_TYPE; - - if (ps.pmove.origin[0] != ops.pmove.origin[0] - || ps.pmove.origin[1] != ops.pmove.origin[1] - || ps.pmove.origin[2] != ops.pmove.origin[2]) - pflags |= PS_M_ORIGIN; - - if (ps.pmove.velocity[0] != ops.pmove.velocity[0] - || ps.pmove.velocity[1] != ops.pmove.velocity[1] - || ps.pmove.velocity[2] != ops.pmove.velocity[2]) - pflags |= PS_M_VELOCITY; - - if (ps.pmove.pm_time != ops.pmove.pm_time) - pflags |= PS_M_TIME; - - if (ps.pmove.pm_flags != ops.pmove.pm_flags) - pflags |= PS_M_FLAGS; - - if (ps.pmove.gravity != ops.pmove.gravity) - pflags |= PS_M_GRAVITY; - - if (ps.pmove.delta_angles[0] != ops.pmove.delta_angles[0] - || ps.pmove.delta_angles[1] != ops.pmove.delta_angles[1] - || ps.pmove.delta_angles[2] != ops.pmove.delta_angles[2]) - pflags |= PS_M_DELTA_ANGLES; - - if (ps.viewoffset[0] != ops.viewoffset[0] || ps.viewoffset[1] != ops.viewoffset[1] || ps.viewoffset[2] != ops.viewoffset[2]) - pflags |= PS_VIEWOFFSET; - - if (ps.viewangles[0] != ops.viewangles[0] || ps.viewangles[1] != ops.viewangles[1] || ps.viewangles[2] != ops.viewangles[2]) - pflags |= PS_VIEWANGLES; - - if (ps.kick_angles[0] != ops.kick_angles[0] - || ps.kick_angles[1] != ops.kick_angles[1] - || ps.kick_angles[2] != ops.kick_angles[2]) - pflags |= PS_KICKANGLES; - - if (ps.blend[0] != ops.blend[0] || ps.blend[1] != ops.blend[1] || ps.blend[2] != ops.blend[2] || ps.blend[3] != ops.blend[3]) - pflags |= PS_BLEND; - - if (ps.fov != ops.fov) - pflags |= PS_FOV; - - if (ps.rdflags != ops.rdflags) - pflags |= PS_RDFLAGS; - - if (ps.gunframe != ops.gunframe) - pflags |= PS_WEAPONFRAME; - - pflags |= PS_WEAPONINDEX; - - // - // write it - // - MSG.WriteByte(msg, svc_playerinfo); - MSG.WriteShort(msg, pflags); - - // - // write the pmove_state_t - // - if ((pflags & PS_M_TYPE) != 0) - MSG.WriteByte(msg, ps.pmove.pm_type); - - if ((pflags & PS_M_ORIGIN) != 0) { - MSG.WriteShort(msg, ps.pmove.origin[0]); - MSG.WriteShort(msg, ps.pmove.origin[1]); - MSG.WriteShort(msg, ps.pmove.origin[2]); - } - - if ((pflags & PS_M_VELOCITY) != 0) { - MSG.WriteShort(msg, ps.pmove.velocity[0]); - MSG.WriteShort(msg, ps.pmove.velocity[1]); - MSG.WriteShort(msg, ps.pmove.velocity[2]); - } - - if ((pflags & PS_M_TIME) != 0) - MSG.WriteByte(msg, ps.pmove.pm_time); - - if ((pflags & PS_M_FLAGS) != 0) - MSG.WriteByte(msg, ps.pmove.pm_flags); - - if ((pflags & PS_M_GRAVITY) != 0) - MSG.WriteShort(msg, ps.pmove.gravity); - - if ((pflags & PS_M_DELTA_ANGLES) != 0) { - MSG.WriteShort(msg, ps.pmove.delta_angles[0]); - MSG.WriteShort(msg, ps.pmove.delta_angles[1]); - MSG.WriteShort(msg, ps.pmove.delta_angles[2]); - } - - // - // write the rest of the player_state_t - // - if ((pflags & PS_VIEWOFFSET) != 0) { - MSG.WriteChar(msg, ps.viewoffset[0] * 4); - MSG.WriteChar(msg, ps.viewoffset[1] * 4); - MSG.WriteChar(msg, ps.viewoffset[2] * 4); - } - - if ((pflags & PS_VIEWANGLES) != 0) { - MSG.WriteAngle16(msg, ps.viewangles[0]); - MSG.WriteAngle16(msg, ps.viewangles[1]); - MSG.WriteAngle16(msg, ps.viewangles[2]); - } - - if ((pflags & PS_KICKANGLES) != 0) { - MSG.WriteChar(msg, ps.kick_angles[0] * 4); - MSG.WriteChar(msg, ps.kick_angles[1] * 4); - MSG.WriteChar(msg, ps.kick_angles[2] * 4); - } - - if ((pflags & PS_WEAPONINDEX) != 0) { - MSG.WriteByte(msg, ps.gunindex); - } - - if ((pflags & PS_WEAPONFRAME) != 0) { - MSG.WriteByte(msg, ps.gunframe); - MSG.WriteChar(msg, ps.gunoffset[0] * 4); - MSG.WriteChar(msg, ps.gunoffset[1] * 4); - MSG.WriteChar(msg, ps.gunoffset[2] * 4); - MSG.WriteChar(msg, ps.gunangles[0] * 4); - MSG.WriteChar(msg, ps.gunangles[1] * 4); - MSG.WriteChar(msg, ps.gunangles[2] * 4); - } - - if ((pflags & PS_BLEND) != 0) { - MSG.WriteByte(msg, ps.blend[0] * 255); - MSG.WriteByte(msg, ps.blend[1] * 255); - MSG.WriteByte(msg, ps.blend[2] * 255); - MSG.WriteByte(msg, ps.blend[3] * 255); - } - if ((pflags & PS_FOV) != 0) - MSG.WriteByte(msg, ps.fov); - if ((pflags & PS_RDFLAGS) != 0) - MSG.WriteByte(msg, ps.rdflags); - - // send stats - statbits = 0; - for (i = 0; i < MAX_STATS; i++) - if (ps.stats[i] != ops.stats[i]) - statbits |= 1 << i; - MSG.WriteLong(msg, statbits); - for (i = 0; i < MAX_STATS; i++) - if ((statbits & (1 << i)) != 0) - MSG.WriteShort(msg, ps.stats[i]); - } - - /* - ================== - SV_WriteFrameToClient - ================== - */ - public static void SV_WriteFrameToClient(client_t client, sizebuf_t msg) { - //ptr - client_frame_t frame, oldframe; - int lastframe; - - //Com.Printf ("%i . %i\n", new Vargs().add(client.lastframe).add(sv.framenum)); - // this is the frame we are creating - frame = client.frames[sv.framenum & UPDATE_MASK]; - if (client.lastframe <= 0) { // client is asking for a retransmit - oldframe = null; - lastframe = -1; - } - else if ( - sv.framenum - client.lastframe >= (UPDATE_BACKUP - 3)) { // client hasn't gotten a good message through in a long time - // Com_Printf ("%s: Delta request from out-of-date packet.\n", client.name); - oldframe = null; - lastframe = -1; - } - else { // we have a valid message to delta from - oldframe = client.frames[client.lastframe & UPDATE_MASK]; - lastframe = client.lastframe; - } - - MSG.WriteByte(msg, svc_frame); - MSG.WriteLong(msg, sv.framenum); - MSG.WriteLong(msg, lastframe); // what we are delta'ing from - MSG.WriteByte(msg, client.surpressCount); // rate dropped packets - client.surpressCount = 0; - - // send over the areabits - MSG.WriteByte(msg, frame.areabytes); - SZ.Write(msg, frame.areabits, frame.areabytes); - - // delta encode the playerstate - SV_WritePlayerstateToClient(oldframe, frame, msg); - - // delta encode the entities - SV_EmitPacketEntities(oldframe, frame, msg); - } - - /* - ============================================================================= - - Build a client frame structure - - ============================================================================= - */ - - static byte fatpvs[] = new byte[65536 / 8]; // 32767 is MAX_MAP_LEAFS - - /* - ============ - SV_FatPVS - - The client will interpolate the view position, - so we can't use a single PVS point - =========== - */ - public static void SV_FatPVS(float[] org) { - int leafs[] = new int[64]; - int i, j, count; - int longs; - byte src[]; - float[] mins = { 0, 0, 0 }, maxs = { 0, 0, 0 }; - - for (i = 0; i < 3; i++) { - mins[i] = org[i] - 8; - maxs[i] = org[i] + 8; - } - - count = CM.CM_BoxLeafnums(mins, maxs, leafs, 64, null); - - if (count < 1) - Com.Error(ERR_FATAL, "SV_FatPVS: count < 1"); - - longs = (CM.CM_NumClusters() + 31) >> 5; - - // convert leafs to clusters - for (i = 0; i < count; i++) - leafs[i] = CM.CM_LeafCluster(leafs[i]); - - System.arraycopy(CM.CM_ClusterPVS(leafs[0]), 0, fatpvs, 0, longs << 2); - // or in all the other leaf bits - for (i = 1; i < count; i++) { - for (j = 0; j < i; j++) - if (leafs[i] == leafs[j]) - break; - if (j != i) - continue; // already have the cluster we want - - src = CM.CM_ClusterPVS(leafs[i]); - - //for (j=0 ; j> 3] & (1 << (l & 7)))) - continue; - } - else { - // FIXME: if an ent has a model and a sound, but isn't - // in the PVS, only the PHS, clear the model - if (ent.s.sound == 0) { - bitvector = fatpvs; //clientphs; - } - else - bitvector = fatpvs; - - if (ent.num_clusters == -1) { // too many leafs for individual check, go by headnode - if (!CM.CM_HeadnodeVisible(ent.headnode, bitvector)) - continue; - c_fullsend++; - } - else { // check individual leafs - for (i = 0; i < ent.num_clusters; i++) { - l = ent.clusternums[i]; - if ((bitvector[l >> 3] & (1 << (l & 7))) != 0) - break; - } - if (i == ent.num_clusters) - continue; // not visible - } - - if (ent.s.modelindex == 0) { // don't send sounds if they will be attenuated away - float[] delta = { 0, 0, 0 }; - float len; - - VectorSubtract(org, ent.s.origin, delta); - len = VectorLength(delta); - if (len > 400) - continue; - } - } - } - - // add it to the circular client_entities array - int ix = svs.next_client_entities % svs.num_client_entities; - state = svs.client_entities[ix]; - if (ent.s.number != e) { - Com.DPrintf("FIXING ENT.S.NUMBER!!!\n"); - ent.s.number = e; - } - - //*state = ent.s; - svs.client_entities[ix].set(ent.s); - - // don't mark players missiles as solid - if (ent.owner == client.edict) - state.solid = 0; - - svs.next_client_entities++; - frame.num_entities++; - } - } - - /* - ================== - SV_RecordDemoMessage - - Save everything in the world out without deltas. - Used for recording footage for merged or assembled demos - ================== - */ - public static void SV_RecordDemoMessage() { - int e; - edict_t ent; - entity_state_t nostate = new entity_state_t(null); - sizebuf_t buf = new sizebuf_t(); - byte buf_data[] = new byte[32768]; - int len; - - if (svs.demofile == null) - return; - - //memset (nostate, 0, sizeof(nostate)); - SZ.Init(buf, buf_data, buf_data.length); - - // write a frame message that doesn't contain a player_state_t - MSG.WriteByte(buf, svc_frame); - MSG.WriteLong(buf, sv.framenum); - - MSG.WriteByte(buf, svc_packetentities); - - e = 1; - ent = GameBase.g_edicts[e]; - - while (e < GameBase.num_edicts) { - // ignore ents without visible models unless they have an effect - if (ent.inuse - && ent.s.number != 0 - && (ent.s.modelindex != 0 || ent.s.effects != 0 || ent.s.sound != 0 || ent.s.event != 0) - && 0 == (ent.svflags & SVF_NOCLIENT)) - MSG.WriteDeltaEntity(nostate, ent.s, buf, false, true); - - e++; - ent = GameBase.g_edicts[e]; - } - - MSG.WriteShort(buf, 0); // end of packetentities - - // now add the accumulated multicast information - SZ.Write(buf, svs.demo_multicast.data, svs.demo_multicast.cursize); - SZ.Clear(svs.demo_multicast); - - // now write the entire message to the file, prefixed by the length - len = EndianHandler.swapInt(buf.cursize); - - try { - //fwrite (len, 4, 1, svs.demofile); - svs.demofile.writeInt(len); - //fwrite (buf.data, buf.cursize, 1, svs.demofile); - svs.demofile.write(buf.data, 0, buf.cursize); - } - catch (IOException e1) { - Com.Printf("Error writing demo file:" + e); - } - } -} +public class SV_ENTS { + + /* + * ============================================================================= + * + * Build a client frame structure + * + * ============================================================================= + */ + + public static byte fatpvs[] = new byte[65536 / 8]; // 32767 is MAX_MAP_LEAFS + + /* + * ============================================================================= + * + * Encode a client frame onto the network channel + * + * ============================================================================= + */ + + /* + * ============= SV_EmitPacketEntities + * + * Writes a delta update of an entity_state_t list to the message. + * ============= + */ + static void SV_EmitPacketEntities(client_frame_t from, client_frame_t to, + sizebuf_t msg) { + entity_state_t oldent = null, newent = null; + int oldindex, newindex; + int oldnum, newnum; + int from_num_entities; + int bits; + + MSG.WriteByte(msg, Defines.svc_packetentities); + + if (from == null) + from_num_entities = 0; + else + from_num_entities = from.num_entities; + + newindex = 0; + oldindex = 0; + while (newindex < to.num_entities || oldindex < from_num_entities) { + if (newindex >= to.num_entities) + newnum = 9999; + else { + newent = SV_INIT.svs.client_entities[(to.first_entity + newindex) + % SV_INIT.svs.num_client_entities]; + newnum = newent.number; + } + + if (oldindex >= from_num_entities) + oldnum = 9999; + else { + oldent = SV_INIT.svs.client_entities[(from.first_entity + oldindex) + % SV_INIT.svs.num_client_entities]; + oldnum = oldent.number; + } + + if (newnum == oldnum) { // delta update from old position + // because the force parm is false, this will not result + // in any bytes being emited if the entity has not changed at + // all + // note that players are always 'newentities', this updates + // their oldorigin always + // and prevents warping + MSG.WriteDeltaEntity(oldent, newent, msg, false, + newent.number <= SV_MAIN.maxclients.value); + oldindex++; + newindex++; + continue; + } + + if (newnum < oldnum) { // this is a new entity, send it from the + // baseline + MSG.WriteDeltaEntity(SV_INIT.sv.baselines[newnum], newent, msg, + true, true); + newindex++; + continue; + } + + if (newnum > oldnum) { // the old entity isn't present in the new + // message + bits = Defines.U_REMOVE; + if (oldnum >= 256) + bits |= Defines.U_NUMBER16 | Defines.U_MOREBITS1; + + MSG.WriteByte(msg, bits & 255); + if ((bits & 0x0000ff00) != 0) + MSG.WriteByte(msg, (bits >> 8) & 255); + + if ((bits & Defines.U_NUMBER16) != 0) + MSG.WriteShort(msg, oldnum); + else + MSG.WriteByte(msg, oldnum); + + oldindex++; + continue; + } + } + + MSG.WriteShort(msg, 0); // end of packetentities + + } + + /* + * ============= SV_WritePlayerstateToClient + * + * ============= + */ + static void SV_WritePlayerstateToClient(client_frame_t from, + client_frame_t to, sizebuf_t msg) { + int i; + int pflags; + // ptr + player_state_t ps, ops; + // mem + player_state_t dummy; + int statbits; + + ps = to.ps; + if (from == null) { + //memset (dummy, 0, sizeof(dummy)); + dummy = new player_state_t(); + ops = dummy; + } else + ops = from.ps; + + // + // determine what needs to be sent + // + pflags = 0; + + if (ps.pmove.pm_type != ops.pmove.pm_type) + pflags |= Defines.PS_M_TYPE; + + if (ps.pmove.origin[0] != ops.pmove.origin[0] + || ps.pmove.origin[1] != ops.pmove.origin[1] + || ps.pmove.origin[2] != ops.pmove.origin[2]) + pflags |= Defines.PS_M_ORIGIN; + + if (ps.pmove.velocity[0] != ops.pmove.velocity[0] + || ps.pmove.velocity[1] != ops.pmove.velocity[1] + || ps.pmove.velocity[2] != ops.pmove.velocity[2]) + pflags |= Defines.PS_M_VELOCITY; + + if (ps.pmove.pm_time != ops.pmove.pm_time) + pflags |= Defines.PS_M_TIME; + + if (ps.pmove.pm_flags != ops.pmove.pm_flags) + pflags |= Defines.PS_M_FLAGS; + + if (ps.pmove.gravity != ops.pmove.gravity) + pflags |= Defines.PS_M_GRAVITY; + + if (ps.pmove.delta_angles[0] != ops.pmove.delta_angles[0] + || ps.pmove.delta_angles[1] != ops.pmove.delta_angles[1] + || ps.pmove.delta_angles[2] != ops.pmove.delta_angles[2]) + pflags |= Defines.PS_M_DELTA_ANGLES; + + if (ps.viewoffset[0] != ops.viewoffset[0] + || ps.viewoffset[1] != ops.viewoffset[1] + || ps.viewoffset[2] != ops.viewoffset[2]) + pflags |= Defines.PS_VIEWOFFSET; + + if (ps.viewangles[0] != ops.viewangles[0] + || ps.viewangles[1] != ops.viewangles[1] + || ps.viewangles[2] != ops.viewangles[2]) + pflags |= Defines.PS_VIEWANGLES; + + if (ps.kick_angles[0] != ops.kick_angles[0] + || ps.kick_angles[1] != ops.kick_angles[1] + || ps.kick_angles[2] != ops.kick_angles[2]) + pflags |= Defines.PS_KICKANGLES; + + if (ps.blend[0] != ops.blend[0] || ps.blend[1] != ops.blend[1] + || ps.blend[2] != ops.blend[2] || ps.blend[3] != ops.blend[3]) + pflags |= Defines.PS_BLEND; + + if (ps.fov != ops.fov) + pflags |= Defines.PS_FOV; + + if (ps.rdflags != ops.rdflags) + pflags |= Defines.PS_RDFLAGS; + + if (ps.gunframe != ops.gunframe) + pflags |= Defines.PS_WEAPONFRAME; + + pflags |= Defines.PS_WEAPONINDEX; + + // + // write it + // + MSG.WriteByte(msg, Defines.svc_playerinfo); + MSG.WriteShort(msg, pflags); + + // + // write the pmove_state_t + // + if ((pflags & Defines.PS_M_TYPE) != 0) + MSG.WriteByte(msg, ps.pmove.pm_type); + + if ((pflags & Defines.PS_M_ORIGIN) != 0) { + MSG.WriteShort(msg, ps.pmove.origin[0]); + MSG.WriteShort(msg, ps.pmove.origin[1]); + MSG.WriteShort(msg, ps.pmove.origin[2]); + } + + if ((pflags & Defines.PS_M_VELOCITY) != 0) { + MSG.WriteShort(msg, ps.pmove.velocity[0]); + MSG.WriteShort(msg, ps.pmove.velocity[1]); + MSG.WriteShort(msg, ps.pmove.velocity[2]); + } + + if ((pflags & Defines.PS_M_TIME) != 0) + MSG.WriteByte(msg, ps.pmove.pm_time); + + if ((pflags & Defines.PS_M_FLAGS) != 0) + MSG.WriteByte(msg, ps.pmove.pm_flags); + + if ((pflags & Defines.PS_M_GRAVITY) != 0) + MSG.WriteShort(msg, ps.pmove.gravity); + + if ((pflags & Defines.PS_M_DELTA_ANGLES) != 0) { + MSG.WriteShort(msg, ps.pmove.delta_angles[0]); + MSG.WriteShort(msg, ps.pmove.delta_angles[1]); + MSG.WriteShort(msg, ps.pmove.delta_angles[2]); + } + + // + // write the rest of the player_state_t + // + if ((pflags & Defines.PS_VIEWOFFSET) != 0) { + MSG.WriteChar(msg, ps.viewoffset[0] * 4); + MSG.WriteChar(msg, ps.viewoffset[1] * 4); + MSG.WriteChar(msg, ps.viewoffset[2] * 4); + } + + if ((pflags & Defines.PS_VIEWANGLES) != 0) { + MSG.WriteAngle16(msg, ps.viewangles[0]); + MSG.WriteAngle16(msg, ps.viewangles[1]); + MSG.WriteAngle16(msg, ps.viewangles[2]); + } + + if ((pflags & Defines.PS_KICKANGLES) != 0) { + MSG.WriteChar(msg, ps.kick_angles[0] * 4); + MSG.WriteChar(msg, ps.kick_angles[1] * 4); + MSG.WriteChar(msg, ps.kick_angles[2] * 4); + } + + if ((pflags & Defines.PS_WEAPONINDEX) != 0) { + MSG.WriteByte(msg, ps.gunindex); + } + + if ((pflags & Defines.PS_WEAPONFRAME) != 0) { + MSG.WriteByte(msg, ps.gunframe); + MSG.WriteChar(msg, ps.gunoffset[0] * 4); + MSG.WriteChar(msg, ps.gunoffset[1] * 4); + MSG.WriteChar(msg, ps.gunoffset[2] * 4); + MSG.WriteChar(msg, ps.gunangles[0] * 4); + MSG.WriteChar(msg, ps.gunangles[1] * 4); + MSG.WriteChar(msg, ps.gunangles[2] * 4); + } + + if ((pflags & Defines.PS_BLEND) != 0) { + MSG.WriteByte(msg, ps.blend[0] * 255); + MSG.WriteByte(msg, ps.blend[1] * 255); + MSG.WriteByte(msg, ps.blend[2] * 255); + MSG.WriteByte(msg, ps.blend[3] * 255); + } + if ((pflags & Defines.PS_FOV) != 0) + MSG.WriteByte(msg, ps.fov); + if ((pflags & Defines.PS_RDFLAGS) != 0) + MSG.WriteByte(msg, ps.rdflags); + + // send stats + statbits = 0; + for (i = 0; i < Defines.MAX_STATS; i++) + if (ps.stats[i] != ops.stats[i]) + statbits |= 1 << i; + MSG.WriteLong(msg, statbits); + for (i = 0; i < Defines.MAX_STATS; i++) + if ((statbits & (1 << i)) != 0) + MSG.WriteShort(msg, ps.stats[i]); + } + + /* + * ================== SV_WriteFrameToClient ================== + */ + public static void SV_WriteFrameToClient(client_t client, sizebuf_t msg) { + //ptr + client_frame_t frame, oldframe; + int lastframe; + + //Com.Printf ("%i . %i\n", new + // Vargs().add(client.lastframe).add(sv.framenum)); + // this is the frame we are creating + frame = client.frames[SV_INIT.sv.framenum & Defines.UPDATE_MASK]; + if (client.lastframe <= 0) { // client is asking for a retransmit + oldframe = null; + lastframe = -1; + } else if (SV_INIT.sv.framenum - client.lastframe >= (Defines.UPDATE_BACKUP - 3)) { + // client hasn't gotten a good message through in a long time + // Com_Printf ("%s: Delta request from out-of-date packet.\n", + // client.name); + oldframe = null; + lastframe = -1; + } else { // we have a valid message to delta from + oldframe = client.frames[client.lastframe & Defines.UPDATE_MASK]; + lastframe = client.lastframe; + } + + MSG.WriteByte(msg, Defines.svc_frame); + MSG.WriteLong(msg, SV_INIT.sv.framenum); + MSG.WriteLong(msg, lastframe); // what we are delta'ing from + MSG.WriteByte(msg, client.surpressCount); // rate dropped packets + client.surpressCount = 0; + + // send over the areabits + MSG.WriteByte(msg, frame.areabytes); + SZ.Write(msg, frame.areabits, frame.areabytes); + + // delta encode the playerstate + SV_WritePlayerstateToClient(oldframe, frame, msg); + + // delta encode the entities + SV_EmitPacketEntities(oldframe, frame, msg); + } + + /* + * ============ SV_FatPVS + * + * The client will interpolate the view position, so we can't use a single + * PVS point =========== + */ + public static void SV_FatPVS(float[] org) { + int leafs[] = new int[64]; + int i, j, count; + int longs; + byte src[]; + float[] mins = { 0, 0, 0 }, maxs = { 0, 0, 0 }; + + for (i = 0; i < 3; i++) { + mins[i] = org[i] - 8; + maxs[i] = org[i] + 8; + } + + count = CM.CM_BoxLeafnums(mins, maxs, leafs, 64, null); + + if (count < 1) + Com.Error(Defines.ERR_FATAL, "SV_FatPVS: count < 1"); + + longs = (CM.CM_NumClusters() + 31) >> 5; + + // convert leafs to clusters + for (i = 0; i < count; i++) + leafs[i] = CM.CM_LeafCluster(leafs[i]); + + System.arraycopy(CM.CM_ClusterPVS(leafs[0]), 0, SV_ENTS.fatpvs, 0, + longs << 2); + // or in all the other leaf bits + for (i = 1; i < count; i++) { + for (j = 0; j < i; j++) + if (leafs[i] == leafs[j]) + break; + if (j != i) + continue; // already have the cluster we want + + src = CM.CM_ClusterPVS(leafs[i]); + + //for (j=0 ; j> 3] & (1 << (l & 7)))) + continue; + } else { + // FIXME: if an ent has a model and a sound, but isn't + // in the PVS, only the PHS, clear the model + if (ent.s.sound == 0) { + bitvector = SV_ENTS.fatpvs; //clientphs; + } else + bitvector = SV_ENTS.fatpvs; + + if (ent.num_clusters == -1) { // too many leafs for + // individual check, go by + // headnode + if (!CM.CM_HeadnodeVisible(ent.headnode, bitvector)) + continue; + c_fullsend++; + } else { // check individual leafs + for (i = 0; i < ent.num_clusters; i++) { + l = ent.clusternums[i]; + if ((bitvector[l >> 3] & (1 << (l & 7))) != 0) + break; + } + if (i == ent.num_clusters) + continue; // not visible + } + + if (ent.s.modelindex == 0) { // don't send sounds if they + // will be attenuated away + float[] delta = { 0, 0, 0 }; + float len; + + Math3D.VectorSubtract(org, ent.s.origin, delta); + len = Math3D.VectorLength(delta); + if (len > 400) + continue; + } + } + } + + // add it to the circular client_entities array + int ix = SV_INIT.svs.next_client_entities + % SV_INIT.svs.num_client_entities; + state = SV_INIT.svs.client_entities[ix]; + if (ent.s.number != e) { + Com.DPrintf("FIXING ENT.S.NUMBER!!!\n"); + ent.s.number = e; + } + + //*state = ent.s; + SV_INIT.svs.client_entities[ix].set(ent.s); + + // don't mark players missiles as solid + if (ent.owner == client.edict) + state.solid = 0; + + SV_INIT.svs.next_client_entities++; + frame.num_entities++; + } + } + + /* + * ================== SV_RecordDemoMessage + * + * Save everything in the world out without deltas. Used for recording + * footage for merged or assembled demos ================== + */ + public static void SV_RecordDemoMessage() { + int e; + edict_t ent; + entity_state_t nostate = new entity_state_t(null); + sizebuf_t buf = new sizebuf_t(); + byte buf_data[] = new byte[32768]; + int len; + + if (SV_INIT.svs.demofile == null) + return; + + //memset (nostate, 0, sizeof(nostate)); + SZ.Init(buf, buf_data, buf_data.length); + + // write a frame message that doesn't contain a player_state_t + MSG.WriteByte(buf, Defines.svc_frame); + MSG.WriteLong(buf, SV_INIT.sv.framenum); + + MSG.WriteByte(buf, Defines.svc_packetentities); + + e = 1; + ent = GameBase.g_edicts[e]; + + while (e < GameBase.num_edicts) { + // ignore ents without visible models unless they have an effect + if (ent.inuse + && ent.s.number != 0 + && (ent.s.modelindex != 0 || ent.s.effects != 0 + || ent.s.sound != 0 || ent.s.event != 0) + && 0 == (ent.svflags & Defines.SVF_NOCLIENT)) + MSG.WriteDeltaEntity(nostate, ent.s, buf, false, true); + + e++; + ent = GameBase.g_edicts[e]; + } + + MSG.WriteShort(buf, 0); // end of packetentities + + // now add the accumulated multicast information + SZ.Write(buf, SV_INIT.svs.demo_multicast.data, + SV_INIT.svs.demo_multicast.cursize); + SZ.Clear(SV_INIT.svs.demo_multicast); + + // now write the entire message to the file, prefixed by the length + len = EndianHandler.swapInt(buf.cursize); + + try { + //fwrite (len, 4, 1, svs.demofile); + SV_INIT.svs.demofile.writeInt(len); + //fwrite (buf.data, buf.cursize, 1, svs.demofile); + SV_INIT.svs.demofile.write(buf.data, 0, buf.cursize); + } catch (IOException e1) { + Com.Printf("Error writing demo file:" + e); + } + } +} \ No newline at end of file diff --git a/src/jake2/server/SV_GAME.java b/src/jake2/server/SV_GAME.java index 844aacb..33f35b4 100644 --- a/src/jake2/server/SV_GAME.java +++ b/src/jake2/server/SV_GAME.java @@ -1,318 +1,313 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 14.01.2004 by RST. -// $Id: SV_GAME.java,v 1.7 2004-08-29 21:39:25 hzi Exp $ - +// $Id: SV_GAME.java,v 1.8 2004-09-22 19:22:12 salomo Exp $ package jake2.server; +import jake2.Defines; +import jake2.Globals; import jake2.game.*; import jake2.qcommon.*; - -public class SV_GAME extends SV_INIT { - - - /* - =============== - PF_Unicast - - Sends the contents of the mutlicast buffer to a single client - =============== - */ - public static void PF_Unicast(edict_t ent, boolean reliable) { - int p; - client_t client; - - if (ent == null) - return; - - p = ent.index; - if (p < 1 || p > SV_MAIN.maxclients.value) - return; - - client = SV_INIT.svs.clients[p - 1]; - - if (reliable) - SZ.Write(client.netchan.message, SV_INIT.sv.multicast.data, SV_INIT.sv.multicast.cursize); - else - SZ.Write(client.datagram, sv.multicast.data, sv.multicast.cursize); - - SZ.Clear(sv.multicast); - } - - /* - =============== - PF_dprintf - - Debug print to server console - =============== - */ - public static void PF_dprintf(String fmt) { - Com.Printf(fmt); - } - - /* - =============== - PF_cprintf - - Print to a single client - =============== - */ - public static void PF_cprintf(edict_t ent, int level, String fmt) { - - int n = 0; - - if (ent != null) { - n = ent.index; - if (n < 1 || n > SV_MAIN.maxclients.value) - Com.Error(ERR_DROP, "cprintf to a non-client"); - } - - if (ent != null) - SV_SEND.SV_ClientPrintf(svs.clients[n - 1], level, fmt); - else - Com.Printf(fmt); - } - - /* - =============== - PF_centerprintf - - centerprint to a single client - =============== - */ - public static void PF_centerprintf(edict_t ent, String fmt) { - int n; - - n = ent.index; - if (n < 1 || n > SV_MAIN.maxclients.value) - return; // Com_Error (ERR_DROP, "centerprintf to a non-client"); - - MSG.WriteByte(sv.multicast, svc_centerprint); - MSG.WriteString(sv.multicast, fmt); - PF_Unicast(ent, true); - } - - /* - =============== - PF_error - - Abort the server with a game error - =============== - */ - public static void PF_error(String fmt) { - Com.Error(ERR_DROP, "Game Error: " + fmt); - } - - public static void PF_error(int level, String fmt) { - Com.Error(level, fmt); - } - - /* - ================= - PF_setmodel - - Also sets mins and maxs for inline bmodels - ================= - */ - public static void PF_setmodel(edict_t ent, String name) { - int i; - cmodel_t mod; - - if (name == null) - Com.Error(ERR_DROP, "PF_setmodel: NULL"); - - i = SV_ModelIndex(name); - - ent.s.modelindex = i; - - // if it is an inline model, get the size information for it - if (name.startsWith("*")) { - mod = CM.InlineModel(name); - VectorCopy(mod.mins, ent.mins); - VectorCopy(mod.maxs, ent.maxs); - SV_WORLD.SV_LinkEdict(ent); - } - } - - /* - =============== - PF_Configstring - - =============== - */ - public static void PF_Configstring(int index, String val) { - if (index < 0 || index >= MAX_CONFIGSTRINGS) - Com.Error(ERR_DROP, "configstring: bad index " + index + "\n"); - - if (val == null) - val = ""; - - // change the string in sv - sv.configstrings[index] = val; - - if (sv.state != ss_loading) { // send the update to everyone - SZ.Clear(sv.multicast); - MSG.WriteChar(sv.multicast, svc_configstring); - MSG.WriteShort(sv.multicast, index); - MSG.WriteString(sv.multicast, val); - - SV_SEND.SV_Multicast(vec3_origin, MULTICAST_ALL_R); - } - } - - public static void PF_WriteChar(int c) { - MSG.WriteChar(sv.multicast, c); - } - public static void PF_WriteByte(int c) { - MSG.WriteByte(sv.multicast, c); - } - public static void PF_WriteShort(int c) { - MSG.WriteShort(sv.multicast, c); - } - public static void PF_WriteLong(int c) { - MSG.WriteLong(sv.multicast, c); - } - public static void PF_WriteFloat(float f) { - MSG.WriteFloat(sv.multicast, f); - } - public static void PF_WriteString(String s) { - MSG.WriteString(sv.multicast, s); - } - public static void PF_WritePos(float[] pos) { - MSG.WritePos(sv.multicast, pos); - } - public static void PF_WriteDir(float[] dir) { - MSG.WriteDir(sv.multicast, dir); - } - public static void PF_WriteAngle(float f) { - MSG.WriteAngle(sv.multicast, f); - } - - /* - ================= - PF_inPVS - - Also checks portalareas so that doors block sight - ================= - */ - public static boolean PF_inPVS(float[] p1, float[] p2) { - int leafnum; - int cluster; - int area1, area2; - byte mask[]; - - leafnum = CM.CM_PointLeafnum(p1); - cluster = CM.CM_LeafCluster(leafnum); - area1 = CM.CM_LeafArea(leafnum); - mask = CM.CM_ClusterPVS(cluster); - - leafnum = CM.CM_PointLeafnum(p2); - cluster = CM.CM_LeafCluster(leafnum); - area2 = CM.CM_LeafArea(leafnum); - - // quake2 bugfix - if (cluster == -1) - return false; - if (mask != null && (0 == (mask[cluster >>> 3] & (1 << (cluster & 7))))) - return false; - - if (!CM.CM_AreasConnected(area1, area2)) - return false; // a door blocks sight - - return true; - } - - /* - ================= - PF_inPHS - - Also checks portalareas so that doors block sound - ================= - */ - public static boolean PF_inPHS(float[] p1, float[] p2) { - int leafnum; - int cluster; - int area1, area2; - byte mask[]; - - leafnum = CM.CM_PointLeafnum(p1); - cluster = CM.CM_LeafCluster(leafnum); - area1 = CM.CM_LeafArea(leafnum); - mask = CM.CM_ClusterPHS(cluster); - - leafnum = CM.CM_PointLeafnum(p2); - cluster = CM.CM_LeafCluster(leafnum); - area2 = CM.CM_LeafArea(leafnum); - - // quake2 bugfix - if (cluster == -1) - return false; - if (mask != null && (0 == (mask[cluster >> 3] & (1 << (cluster & 7))))) - return false; // more than one bounce away - if (!CM.CM_AreasConnected(area1, area2)) - return false; // a door blocks hearing - - return true; - } - - public static void PF_StartSound(edict_t entity, int channel, int sound_num, float volume, float attenuation, float timeofs) { - - if (null == entity) - return; - SV_SEND.SV_StartSound (null, entity, channel, sound_num, volume, attenuation, timeofs); - - } - - //============================================== - - /* - =============== - SV_ShutdownGameProgs - - Called when either the entire server is being killed, or - it is changing to a different game directory. - =============== - */ - public static void SV_ShutdownGameProgs() { - Game.ShutdownGame(); - } - - /* - =============== - SV_InitGameProgs - - Init the game subsystem for a new map - =============== - */ - - public static void SV_InitGameProgs() { - - // unload anything we have now - SV_ShutdownGameProgs(); - - game_import_t gimport = new game_import_t(); - - // all functions set in game_export_t (rst) - GameBase.GetGameApi(gimport); - - Game.InitGame(); - } -} +import jake2.util.Math3D; + +public class SV_GAME { + + /* + * =============== PF_Unicast + * + * Sends the contents of the mutlicast buffer to a single client + * =============== + */ + public static void PF_Unicast(edict_t ent, boolean reliable) { + int p; + client_t client; + + if (ent == null) + return; + + p = ent.index; + if (p < 1 || p > SV_MAIN.maxclients.value) + return; + + client = SV_INIT.svs.clients[p - 1]; + + if (reliable) + SZ.Write(client.netchan.message, SV_INIT.sv.multicast.data, + SV_INIT.sv.multicast.cursize); + else + SZ.Write(client.datagram, SV_INIT.sv.multicast.data, + SV_INIT.sv.multicast.cursize); + + SZ.Clear(SV_INIT.sv.multicast); + } + + /* + * =============== PF_dprintf + * + * Debug print to server console =============== + */ + public static void PF_dprintf(String fmt) { + Com.Printf(fmt); + } + + /* + * =============== PF_cprintf + * + * Print to a single client =============== + */ + public static void PF_cprintf(edict_t ent, int level, String fmt) { + + int n = 0; + + if (ent != null) { + n = ent.index; + if (n < 1 || n > SV_MAIN.maxclients.value) + Com.Error(Defines.ERR_DROP, "cprintf to a non-client"); + } + + if (ent != null) + SV_SEND.SV_ClientPrintf(SV_INIT.svs.clients[n - 1], level, fmt); + else + Com.Printf(fmt); + } + + /* + * =============== PF_centerprintf + * + * centerprint to a single client =============== + */ + public static void PF_centerprintf(edict_t ent, String fmt) { + int n; + + n = ent.index; + if (n < 1 || n > SV_MAIN.maxclients.value) + return; // Com_Error (ERR_DROP, "centerprintf to a non-client"); + + MSG.WriteByte(SV_INIT.sv.multicast, Defines.svc_centerprint); + MSG.WriteString(SV_INIT.sv.multicast, fmt); + PF_Unicast(ent, true); + } + + /* + * =============== PF_error + * + * Abort the server with a game error =============== + */ + public static void PF_error(String fmt) { + Com.Error(Defines.ERR_DROP, "Game Error: " + fmt); + } + + public static void PF_error(int level, String fmt) { + Com.Error(level, fmt); + } + + /* + * ================= PF_setmodel + * + * Also sets mins and maxs for inline bmodels ================= + */ + public static void PF_setmodel(edict_t ent, String name) { + int i; + cmodel_t mod; + + if (name == null) + Com.Error(Defines.ERR_DROP, "PF_setmodel: NULL"); + + i = SV_INIT.SV_ModelIndex(name); + + ent.s.modelindex = i; + + // if it is an inline model, get the size information for it + if (name.startsWith("*")) { + mod = CM.InlineModel(name); + Math3D.VectorCopy(mod.mins, ent.mins); + Math3D.VectorCopy(mod.maxs, ent.maxs); + SV_WORLD.SV_LinkEdict(ent); + } + } + + /* + * =============== PF_Configstring + * + * =============== + */ + public static void PF_Configstring(int index, String val) { + if (index < 0 || index >= Defines.MAX_CONFIGSTRINGS) + Com.Error(Defines.ERR_DROP, "configstring: bad index " + index + + "\n"); + + if (val == null) + val = ""; + + // change the string in sv + SV_INIT.sv.configstrings[index] = val; + + if (SV_INIT.sv.state != Defines.ss_loading) { // send the update to + // everyone + SZ.Clear(SV_INIT.sv.multicast); + MSG.WriteChar(SV_INIT.sv.multicast, Defines.svc_configstring); + MSG.WriteShort(SV_INIT.sv.multicast, index); + MSG.WriteString(SV_INIT.sv.multicast, val); + + SV_SEND.SV_Multicast(Globals.vec3_origin, Defines.MULTICAST_ALL_R); + } + } + + public static void PF_WriteChar(int c) { + MSG.WriteChar(SV_INIT.sv.multicast, c); + } + + public static void PF_WriteByte(int c) { + MSG.WriteByte(SV_INIT.sv.multicast, c); + } + + public static void PF_WriteShort(int c) { + MSG.WriteShort(SV_INIT.sv.multicast, c); + } + + public static void PF_WriteLong(int c) { + MSG.WriteLong(SV_INIT.sv.multicast, c); + } + + public static void PF_WriteFloat(float f) { + MSG.WriteFloat(SV_INIT.sv.multicast, f); + } + + public static void PF_WriteString(String s) { + MSG.WriteString(SV_INIT.sv.multicast, s); + } + + public static void PF_WritePos(float[] pos) { + MSG.WritePos(SV_INIT.sv.multicast, pos); + } + + public static void PF_WriteDir(float[] dir) { + MSG.WriteDir(SV_INIT.sv.multicast, dir); + } + + public static void PF_WriteAngle(float f) { + MSG.WriteAngle(SV_INIT.sv.multicast, f); + } + + /* + * ================= PF_inPVS + * + * Also checks portalareas so that doors block sight ================= + */ + public static boolean PF_inPVS(float[] p1, float[] p2) { + int leafnum; + int cluster; + int area1, area2; + byte mask[]; + + leafnum = CM.CM_PointLeafnum(p1); + cluster = CM.CM_LeafCluster(leafnum); + area1 = CM.CM_LeafArea(leafnum); + mask = CM.CM_ClusterPVS(cluster); + + leafnum = CM.CM_PointLeafnum(p2); + cluster = CM.CM_LeafCluster(leafnum); + area2 = CM.CM_LeafArea(leafnum); + + // quake2 bugfix + if (cluster == -1) + return false; + if (mask != null && (0 == (mask[cluster >>> 3] & (1 << (cluster & 7))))) + return false; + + if (!CM.CM_AreasConnected(area1, area2)) + return false; // a door blocks sight + + return true; + } + + /* + * ================= PF_inPHS + * + * Also checks portalareas so that doors block sound ================= + */ + public static boolean PF_inPHS(float[] p1, float[] p2) { + int leafnum; + int cluster; + int area1, area2; + byte mask[]; + + leafnum = CM.CM_PointLeafnum(p1); + cluster = CM.CM_LeafCluster(leafnum); + area1 = CM.CM_LeafArea(leafnum); + mask = CM.CM_ClusterPHS(cluster); + + leafnum = CM.CM_PointLeafnum(p2); + cluster = CM.CM_LeafCluster(leafnum); + area2 = CM.CM_LeafArea(leafnum); + + // quake2 bugfix + if (cluster == -1) + return false; + if (mask != null && (0 == (mask[cluster >> 3] & (1 << (cluster & 7))))) + return false; // more than one bounce away + if (!CM.CM_AreasConnected(area1, area2)) + return false; // a door blocks hearing + + return true; + } + + public static void PF_StartSound(edict_t entity, int channel, + int sound_num, float volume, float attenuation, float timeofs) { + + if (null == entity) + return; + SV_SEND.SV_StartSound(null, entity, channel, sound_num, volume, + attenuation, timeofs); + + } + + //============================================== + + /* + * =============== SV_ShutdownGameProgs + * + * Called when either the entire server is being killed, or it is changing + * to a different game directory. =============== + */ + public static void SV_ShutdownGameProgs() { + GameBase.ShutdownGame(); + } + + /* + * =============== SV_InitGameProgs + * + * Init the game subsystem for a new map =============== + */ + + public static void SV_InitGameProgs() { + + // unload anything we have now + SV_ShutdownGameProgs(); + + game_import_t gimport = new game_import_t(); + + // all functions set in game_export_t (rst) + GameBase.GetGameApi(gimport); + + GameSave.InitGame(); + } +} \ No newline at end of file diff --git a/src/jake2/server/SV_INIT.java b/src/jake2/server/SV_INIT.java index 2325f22..0c1c5ae 100644 --- a/src/jake2/server/SV_INIT.java +++ b/src/jake2/server/SV_INIT.java @@ -1,493 +1,499 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 14.01.2004 by RST. -// $Id: SV_INIT.java,v 1.8 2004-08-29 21:39:25 hzi Exp $ - +// $Id: SV_INIT.java,v 1.9 2004-09-22 19:22:12 salomo Exp $ package jake2.server; +import jake2.Defines; import jake2.Globals; import jake2.client.CL; import jake2.client.SCR; import jake2.game.*; import jake2.qcommon.*; import jake2.sys.NET; +import jake2.util.Lib; +import jake2.util.Math3D; import java.io.IOException; import java.io.RandomAccessFile; -public class SV_INIT extends Globals { - - public static server_static_t svs= new server_static_t(); // persistant server info - public static server_t sv= new server_t(); // local server - - /* - ================ - SV_FindIndex - - ================ - */ - public static int SV_FindIndex(String name, int start, int max, boolean create) { - int i; - - if (name == null || name.length() == 0) - return 0; - - for (i= 1; i < max && sv.configstrings[start + i] != null; i++) - if (0 == strcmp(sv.configstrings[start + i], name)) - return i; - - if (!create) - return 0; - - if (i == max) - Com.Error(ERR_DROP, "*Index: overflow"); - - //strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i])); - sv.configstrings[start + i]= name; - - if (sv.state != ss_loading) { // send the update to everyone - SZ.Clear(sv.multicast); - MSG.WriteChar(sv.multicast, svc_configstring); - MSG.WriteShort(sv.multicast, start + i); - MSG.WriteString(sv.multicast, name); - SV_SEND.SV_Multicast(Game.vec3_origin, MULTICAST_ALL_R); - } - - return i; - } - - public static int SV_ModelIndex(String name) { - return SV_FindIndex(name, CS_MODELS, MAX_MODELS, true); - } - - public static int SV_SoundIndex(String name) { - return SV_FindIndex(name, CS_SOUNDS, MAX_SOUNDS, true); - } - - public static int SV_ImageIndex(String name) { - return SV_FindIndex(name, CS_IMAGES, MAX_IMAGES, true); - } - - /* - ================ - SV_CreateBaseline - - Entity baselines are used to compress the update messages - to the clients -- only the fields that differ from the - baseline will be transmitted - ================ - */ - public static void SV_CreateBaseline() { - edict_t svent; - int entnum; - - for (entnum= 1; entnum < GameBase.num_edicts; entnum++) { - //svent = EDICT_NUM(entnum); - svent= GameBase.g_edicts[entnum]; - - if (!svent.inuse) - continue; - if (0 == svent.s.modelindex && 0 == svent.s.sound && 0 == svent.s.effects) - continue; - svent.s.number= entnum; - - // - // take current state as baseline - // - VectorCopy(svent.s.origin, svent.s.old_origin); - // rst: bugfix - sv.baselines[entnum].set(svent.s); // = svent.s.getClone(); - } - } - - /* - ================= - SV_CheckForSavegame - ================= - */ - public static void SV_CheckForSavegame() { - - String name; - RandomAccessFile f; - - int i; - - if (SV_MAIN.sv_noreload.value != 0) - return; - - if (Cvar.VariableValue("deathmatch") != 0) - return; - - name= FS.Gamedir() + "/save/current/" + sv.name + ".sav"; - try { - f= new RandomAccessFile(name, "r"); - } - - catch (Exception e) { - return; - } - - try { - f.close(); - } - catch (IOException e1) { - e1.printStackTrace(); - } - - SV_WORLD.SV_ClearWorld(); - - // get configstrings and areaportals - SV_CCMDS.SV_ReadLevelFile(); - - if (!sv.loadgame) { // coming back to a level after being in a different - // level, so run it for ten seconds - - // rlava2 was sending too many lightstyles, and overflowing the - // reliable data. temporarily changing the server state to loading - // prevents these from being passed down. - int previousState; // PGM - - previousState= sv.state; // PGM - sv.state= ss_loading; // PGM - for (i= 0; i < 100; i++) - Game.G_RunFrame(); - - sv.state= previousState; // PGM - } - } - - /* - ================ - SV_SpawnServer - - Change the server to a new map, taking all connected - clients along with it. - - ================ - */ - public static void SV_SpawnServer(String server, String spawnpoint, int serverstate, boolean attractloop, boolean loadgame) { - int i; - int checksum= 0; - - if (attractloop) - Cvar.Set("paused", "0"); - - Com.Printf("------- Server Initialization -------\n"); - - Com.DPrintf("SpawnServer: " + server + "\n"); - if (sv.demofile != null) - try { - sv.demofile.close(); - } - catch (Exception e) { - } - - svs.spawncount++; // any partially connected client will be - // restarted - - sv.state= ss_dead; - - Globals.server_state= sv.state; - - // wipe the entire per-level structure - //memset(sv, 0, sizeof(sv)); - sv= new server_t(); - - svs.realtime= 0; - sv.loadgame= loadgame; - sv.attractloop= attractloop; - - // save name for levels that don't set message - sv.configstrings[CS_NAME]= server; - - if (Cvar.VariableValue("deathmatch") != 0) { - sv.configstrings[CS_AIRACCEL]= "" + SV_MAIN.sv_airaccelerate.value; - PMove.pm_airaccelerate= SV_MAIN.sv_airaccelerate.value; - } - else { - sv.configstrings[CS_AIRACCEL]= "0"; - PMove.pm_airaccelerate= 0; - } - - SZ.Init(sv.multicast, sv.multicast_buf, sv.multicast_buf.length); - - sv.name= server; - - // leave slots at start for clients only - for (i= 0; i < SV_MAIN.maxclients.value; i++) { - // needs to reconnect - if (svs.clients[i].state > cs_connected) - svs.clients[i].state= cs_connected; - svs.clients[i].lastframe= -1; - } - - sv.time= 1000; - - sv.name= server; - sv.configstrings[CS_NAME]= server; - - int iw[]= { checksum }; - - if (serverstate != ss_game) { - sv.models[1]= CM.CM_LoadMap("", false, iw); // no real map - } - else { - sv.configstrings[CS_MODELS + 1]= "maps/" + server + ".bsp"; - sv.models[1]= CM.CM_LoadMap(sv.configstrings[CS_MODELS + 1], false, iw); - } - checksum= iw[0]; - sv.configstrings[CS_MAPCHECKSUM]= "" + checksum; - - // - // clear physics interaction links - // - SV_WORLD.SV_ClearWorld(); - - for (i= 1; i < CM.CM_NumInlineModels(); i++) { - sv.configstrings[CS_MODELS + 1 + i]= "*" + i; - // copy references - sv.models[i + 1]= CM.InlineModel(sv.configstrings[CS_MODELS + 1 + i]); - } - - // - // spawn the rest of the entities on the map - // - - // precache and static commands can be issued during - // map initialization - - sv.state= ss_loading; - Globals.server_state= sv.state; - - // load and spawn all other entities - Game.SpawnEntities(sv.name, CM.CM_EntityString(), spawnpoint); - - // run two frames to allow everything to settle - Game.G_RunFrame(); - Game.G_RunFrame(); - - // all precaches are complete - sv.state= serverstate; - Globals.server_state= sv.state; - - // create a baseline for more efficient communications - SV_CreateBaseline(); - - // check for a savegame - SV_CheckForSavegame(); - - // set serverinfo variable - Cvar.FullSet("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET); - - //Com.Printf("-------------------------------------\n"); - } - - /* - ============== - SV_InitGame - - A brand new game has been started - ============== - */ - public static void SV_InitGame() { - int i; - edict_t ent; - //char idmaster[32]; - String idmaster; - - if (svs.initialized) { - // cause any connected clients to reconnect - SV_MAIN.SV_Shutdown("Server restarted\n", true); - } - else { - // make sure the client is down - CL.Drop(); - SCR.BeginLoadingPlaque(); - } - - // get any latched variable changes (maxclients, etc) - Cvar.GetLatchedVars(); - - svs.initialized= true; - - if (Cvar.VariableValue("coop") != 0 && Cvar.VariableValue("deathmatch") != 0) { - Com.Printf("Deathmatch and Coop both set, disabling Coop\n"); - Cvar.FullSet("coop", "0", CVAR_SERVERINFO | CVAR_LATCH); - } - - // dedicated servers are can't be single player and are usually DM - // so unless they explicity set coop, force it to deathmatch - if (dedicated.value != 0) { - if (0 == Cvar.VariableValue("coop")) - Cvar.FullSet("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH); - } - - // init clients - if (Cvar.VariableValue("deathmatch") != 0) { - if (SV_MAIN.maxclients.value <= 1) - Cvar.FullSet("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH); - else if (SV_MAIN.maxclients.value > MAX_CLIENTS) - Cvar.FullSet("maxclients", "" + MAX_CLIENTS, CVAR_SERVERINFO | CVAR_LATCH); - } - else if (Cvar.VariableValue("coop") != 0) { - if (SV_MAIN.maxclients.value <= 1 || SV_MAIN.maxclients.value > 4) - Cvar.FullSet("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); - - } - else // non-deathmatch, non-coop is one player - { - Cvar.FullSet("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH); - } - - svs.spawncount= rand(); - //svs.clients = Z_Malloc(sizeof(client_t) * maxclients.value); - svs.clients= new client_t[(int) SV_MAIN.maxclients.value]; - for (int n= 0; n < svs.clients.length; n++) - svs.clients[n]= new client_t(); - - svs.num_client_entities= ((int) SV_MAIN.maxclients.value) * UPDATE_BACKUP * 64; //ok. - - //svs.client_entities = Z_Malloc(sizeof(entity_state_t) * svs.num_client_entities); - svs.client_entities= new entity_state_t[svs.num_client_entities]; - for (int n= 0; n < svs.client_entities.length; n++) - svs.client_entities[n]= new entity_state_t(null); - - // init network stuff - NET.Config((SV_MAIN.maxclients.value > 1)); //ok! - - // heartbeats will always be sent to the id master - svs.last_heartbeat= -99999; // send immediately - idmaster= "192.246.40.37:" + PORT_MASTER; - NET.StringToAdr(idmaster, SV_MAIN.master_adr[0]); - - // init game - SV_GAME.SV_InitGameProgs(); // bis hier alles ok! - - for (i= 0; i < SV_MAIN.maxclients.value; i++) { - ent= GameBase.g_edicts[i + 1]; - - //ent.s.number = i + 1; //dont need this, ent.s.number already set. - svs.clients[i].edict= ent; - //memset(& svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd)); - svs.clients[i].lastcmd= new usercmd_t(); - } - } - - /* - ====================== - SV_Map - - the full syntax is: - - map [*]$+ - - command from the console or progs. - Map can also be a.cin, .pcx, or .dm2 file - Nextserver is used to allow a cinematic to play, then proceed to - another level: - - map tram.cin+jail_e3 - ====================== - */ - public static void SV_Map(boolean attractloop, String levelstring, boolean loadgame) { - //char level[MAX_QPATH]; - //char *ch; - int l; - //char spawnpoint[MAX_QPATH]; - - String level, ch, spawnpoint; - - sv.loadgame= loadgame; - sv.attractloop= attractloop; - - if (sv.state == ss_dead && !sv.loadgame) - SV_InitGame(); // the game is just starting - - level= levelstring; // bis hier her ok. - - // if there is a + in the map, set nextserver to the remainder - - //was: - // ch = strstr(level, "+"); - // if (ch) - // { - // *ch = 0; - // Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1)); - // } - // else - // Cvar_Set ("nextserver", ""); - - int c= level.indexOf('+'); - if (c != -1) { - Cvar.Set("nextserver", "gamemap \"" + level.substring(c + 1) + "\""); - level= level.substring(0, c); - } - else { - Cvar.Set("nextserver", ""); - } - - //ZOID special hack for end game screen in coop mode - if (Cvar.VariableValue("coop") != 0 && !level.equals("victory.pcx")) - Cvar.Set("nextserver", "gamemap \"*base1\""); - - // if there is a $, use the remainder as a spawnpoint - int pos= level.indexOf('$'); - if (pos != -1) { - //* ch = 0; - spawnpoint= level.substring(pos + 1); - level= level.substring(0, pos); - - } - else - //spawnpoint[0] = 0; - spawnpoint= ""; - - // skip the end-of-unit flag if necessary - if (level.charAt(0) == '*') - level= level.substring(1); - - l= level.length(); - if (l > 4 && level.endsWith(".cin")) { - SCR.BeginLoadingPlaque(); // for local system - SV_SEND.SV_BroadcastCommand("changing\n"); - SV_SpawnServer(level, spawnpoint, ss_cinematic, attractloop, loadgame); - } - else if (l > 4 && level.endsWith(".dm2")) { - SCR.BeginLoadingPlaque(); // for local system - SV_SEND.SV_BroadcastCommand("changing\n"); - SV_SpawnServer(level, spawnpoint, ss_demo, attractloop, loadgame); - } - else if (l > 4 && level.endsWith(".pcx")) { - SCR.BeginLoadingPlaque(); // for local system - SV_SEND.SV_BroadcastCommand("changing\n"); - SV_SpawnServer(level, spawnpoint, ss_pic, attractloop, loadgame); - } - else { - SCR.BeginLoadingPlaque(); // for local system - SV_SEND.SV_BroadcastCommand("changing\n"); - SV_SEND.SV_SendClientMessages(); - SV_SpawnServer(level, spawnpoint, ss_game, attractloop, loadgame); - Cbuf.CopyToDefer(); - } - - SV_SEND.SV_BroadcastCommand("reconnect\n"); - } -} +public class SV_INIT { + + /* + * ================ SV_FindIndex + * + * ================ + */ + public static int SV_FindIndex(String name, int start, int max, + boolean create) { + int i; + + if (name == null || name.length() == 0) + return 0; + + for (i = 1; i < max && sv.configstrings[start + i] != null; i++) + if (0 == Lib.strcmp(sv.configstrings[start + i], name)) + return i; + + if (!create) + return 0; + + if (i == max) + Com.Error(Defines.ERR_DROP, "*Index: overflow"); + + //strncpy (sv.configstrings[start+i], name, + // sizeof(sv.configstrings[i])); + sv.configstrings[start + i] = name; + + if (sv.state != Defines.ss_loading) { // send the update to everyone + SZ.Clear(sv.multicast); + MSG.WriteChar(sv.multicast, Defines.svc_configstring); + MSG.WriteShort(sv.multicast, start + i); + MSG.WriteString(sv.multicast, name); + SV_SEND.SV_Multicast(Globals.vec3_origin, Defines.MULTICAST_ALL_R); + } + + return i; + } + + public static int SV_ModelIndex(String name) { + return SV_FindIndex(name, Defines.CS_MODELS, Defines.MAX_MODELS, true); + } + + public static int SV_SoundIndex(String name) { + return SV_FindIndex(name, Defines.CS_SOUNDS, Defines.MAX_SOUNDS, true); + } + + public static int SV_ImageIndex(String name) { + return SV_FindIndex(name, Defines.CS_IMAGES, Defines.MAX_IMAGES, true); + } + + /* + * ================ SV_CreateBaseline + * + * Entity baselines are used to compress the update messages to the clients -- + * only the fields that differ from the baseline will be transmitted + * ================ + */ + public static void SV_CreateBaseline() { + edict_t svent; + int entnum; + + for (entnum = 1; entnum < GameBase.num_edicts; entnum++) { + //svent = EDICT_NUM(entnum); + svent = GameBase.g_edicts[entnum]; + + if (!svent.inuse) + continue; + if (0 == svent.s.modelindex && 0 == svent.s.sound + && 0 == svent.s.effects) + continue; + svent.s.number = entnum; + + // + // take current state as baseline + // + Math3D.VectorCopy(svent.s.origin, svent.s.old_origin); + // rst: bugfix + sv.baselines[entnum].set(svent.s); // = svent.s.getClone(); + } + } + + /* + * ================= SV_CheckForSavegame ================= + */ + public static void SV_CheckForSavegame() { + + String name; + RandomAccessFile f; + + int i; + + if (SV_MAIN.sv_noreload.value != 0) + return; + + if (Cvar.VariableValue("deathmatch") != 0) + return; + + name = FS.Gamedir() + "/save/current/" + sv.name + ".sav"; + try { + f = new RandomAccessFile(name, "r"); + } + + catch (Exception e) { + return; + } + + try { + f.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + + SV_WORLD.SV_ClearWorld(); + + // get configstrings and areaportals + SV_CCMDS.SV_ReadLevelFile(); + + if (!sv.loadgame) { // coming back to a level after being in a different + // level, so run it for ten seconds + + // rlava2 was sending too many lightstyles, and overflowing the + // reliable data. temporarily changing the server state to loading + // prevents these from being passed down. + int previousState; // PGM + + previousState = sv.state; // PGM + sv.state = Defines.ss_loading; // PGM + for (i = 0; i < 100; i++) + GameBase.G_RunFrame(); + + sv.state = previousState; // PGM + } + } + + /* + * ================ SV_SpawnServer + * + * Change the server to a new map, taking all connected clients along with + * it. + * + * ================ + */ + public static void SV_SpawnServer(String server, String spawnpoint, + int serverstate, boolean attractloop, boolean loadgame) { + int i; + int checksum = 0; + + if (attractloop) + Cvar.Set("paused", "0"); + + Com.Printf("------- Server Initialization -------\n"); + + Com.DPrintf("SpawnServer: " + server + "\n"); + if (sv.demofile != null) + try { + sv.demofile.close(); + } catch (Exception e) { + } + + svs.spawncount++; // any partially connected client will be + // restarted + + sv.state = Defines.ss_dead; + + Globals.server_state = sv.state; + + // wipe the entire per-level structure + //memset(sv, 0, sizeof(sv)); + sv = new server_t(); + + svs.realtime = 0; + sv.loadgame = loadgame; + sv.attractloop = attractloop; + + // save name for levels that don't set message + sv.configstrings[Defines.CS_NAME] = server; + + if (Cvar.VariableValue("deathmatch") != 0) { + sv.configstrings[Defines.CS_AIRACCEL] = "" + + SV_MAIN.sv_airaccelerate.value; + PMove.pm_airaccelerate = SV_MAIN.sv_airaccelerate.value; + } else { + sv.configstrings[Defines.CS_AIRACCEL] = "0"; + PMove.pm_airaccelerate = 0; + } + + SZ.Init(sv.multicast, sv.multicast_buf, sv.multicast_buf.length); + + sv.name = server; + + // leave slots at start for clients only + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + // needs to reconnect + if (svs.clients[i].state > Defines.cs_connected) + svs.clients[i].state = Defines.cs_connected; + svs.clients[i].lastframe = -1; + } + + sv.time = 1000; + + sv.name = server; + sv.configstrings[Defines.CS_NAME] = server; + + int iw[] = { checksum }; + + if (serverstate != Defines.ss_game) { + sv.models[1] = CM.CM_LoadMap("", false, iw); // no real map + } else { + sv.configstrings[Defines.CS_MODELS + 1] = "maps/" + server + ".bsp"; + sv.models[1] = CM.CM_LoadMap( + sv.configstrings[Defines.CS_MODELS + 1], false, iw); + } + checksum = iw[0]; + sv.configstrings[Defines.CS_MAPCHECKSUM] = "" + checksum; + + // + // clear physics interaction links + // + SV_WORLD.SV_ClearWorld(); + + for (i = 1; i < CM.CM_NumInlineModels(); i++) { + sv.configstrings[Defines.CS_MODELS + 1 + i] = "*" + i; + // copy references + sv.models[i + 1] = CM + .InlineModel(sv.configstrings[Defines.CS_MODELS + 1 + i]); + } + + // + // spawn the rest of the entities on the map + // + + // precache and static commands can be issued during + // map initialization + + sv.state = Defines.ss_loading; + Globals.server_state = sv.state; + + // load and spawn all other entities + GameSpawn.SpawnEntities(sv.name, CM.CM_EntityString(), spawnpoint); + + // run two frames to allow everything to settle + GameBase.G_RunFrame(); + GameBase.G_RunFrame(); + + // all precaches are complete + sv.state = serverstate; + Globals.server_state = sv.state; + + // create a baseline for more efficient communications + SV_CreateBaseline(); + + // check for a savegame + SV_CheckForSavegame(); + + // set serverinfo variable + Cvar.FullSet("mapname", sv.name, Defines.CVAR_SERVERINFO + | Defines.CVAR_NOSET); + + //Com.Printf("-------------------------------------\n"); + } + + /* + * ============== SV_InitGame + * + * A brand new game has been started ============== + */ + public static void SV_InitGame() { + int i; + edict_t ent; + //char idmaster[32]; + String idmaster; + + if (svs.initialized) { + // cause any connected clients to reconnect + SV_MAIN.SV_Shutdown("Server restarted\n", true); + } else { + // make sure the client is down + CL.Drop(); + SCR.BeginLoadingPlaque(); + } + + // get any latched variable changes (maxclients, etc) + Cvar.GetLatchedVars(); + + svs.initialized = true; + + if (Cvar.VariableValue("coop") != 0 + && Cvar.VariableValue("deathmatch") != 0) { + Com.Printf("Deathmatch and Coop both set, disabling Coop\n"); + Cvar.FullSet("coop", "0", Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + } + + // dedicated servers are can't be single player and are usually DM + // so unless they explicity set coop, force it to deathmatch + if (Globals.dedicated.value != 0) { + if (0 == Cvar.VariableValue("coop")) + Cvar.FullSet("deathmatch", "1", Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + } + + // init clients + if (Cvar.VariableValue("deathmatch") != 0) { + if (SV_MAIN.maxclients.value <= 1) + Cvar.FullSet("maxclients", "8", Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + else if (SV_MAIN.maxclients.value > Defines.MAX_CLIENTS) + Cvar.FullSet("maxclients", "" + Defines.MAX_CLIENTS, + Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH); + } else if (Cvar.VariableValue("coop") != 0) { + if (SV_MAIN.maxclients.value <= 1 || SV_MAIN.maxclients.value > 4) + Cvar.FullSet("maxclients", "4", Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + + } else // non-deathmatch, non-coop is one player + { + Cvar.FullSet("maxclients", "1", Defines.CVAR_SERVERINFO + | Defines.CVAR_LATCH); + } + + svs.spawncount = Lib.rand(); + //svs.clients = Z_Malloc(sizeof(client_t) * maxclients.value); + svs.clients = new client_t[(int) SV_MAIN.maxclients.value]; + for (int n = 0; n < svs.clients.length; n++) + svs.clients[n] = new client_t(); + + svs.num_client_entities = ((int) SV_MAIN.maxclients.value) + * Defines.UPDATE_BACKUP * 64; //ok. + + //svs.client_entities = Z_Malloc(sizeof(entity_state_t) * + // svs.num_client_entities); + svs.client_entities = new entity_state_t[svs.num_client_entities]; + for (int n = 0; n < svs.client_entities.length; n++) + svs.client_entities[n] = new entity_state_t(null); + + // init network stuff + NET.Config((SV_MAIN.maxclients.value > 1)); //ok! + + // heartbeats will always be sent to the id master + svs.last_heartbeat = -99999; // send immediately + idmaster = "192.246.40.37:" + Defines.PORT_MASTER; + NET.StringToAdr(idmaster, SV_MAIN.master_adr[0]); + + // init game + SV_GAME.SV_InitGameProgs(); // bis hier alles ok! + + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + ent = GameBase.g_edicts[i + 1]; + + //ent.s.number = i + 1; //dont need this, ent.s.number already set. + svs.clients[i].edict = ent; + //memset(& svs.clients[i].lastcmd, 0, + // sizeof(svs.clients[i].lastcmd)); + svs.clients[i].lastcmd = new usercmd_t(); + } + } + + /* + * ====================== SV_Map + * + * the full syntax is: + * + * map [*] $ + + * + * command from the console or progs. Map can also be a.cin, .pcx, or .dm2 + * file Nextserver is used to allow a cinematic to play, then proceed to + * another level: + * + * map tram.cin+jail_e3 ====================== + */ + public static void SV_Map(boolean attractloop, String levelstring, + boolean loadgame) { + //char level[MAX_QPATH]; + //char *ch; + int l; + //char spawnpoint[MAX_QPATH]; + + String level, ch, spawnpoint; + + sv.loadgame = loadgame; + sv.attractloop = attractloop; + + if (sv.state == Defines.ss_dead && !sv.loadgame) + SV_InitGame(); // the game is just starting + + level = levelstring; // bis hier her ok. + + // if there is a + in the map, set nextserver to the remainder + + //was: + // ch = strstr(level, "+"); + // if (ch) + // { + // *ch = 0; + // Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1)); + // } + // else + // Cvar_Set ("nextserver", ""); + + int c = level.indexOf('+'); + if (c != -1) { + Cvar + .Set("nextserver", "gamemap \"" + level.substring(c + 1) + + "\""); + level = level.substring(0, c); + } else { + Cvar.Set("nextserver", ""); + } + + //ZOID special hack for end game screen in coop mode + if (Cvar.VariableValue("coop") != 0 && !level.equals("victory.pcx")) + Cvar.Set("nextserver", "gamemap \"*base1\""); + + // if there is a $, use the remainder as a spawnpoint + int pos = level.indexOf('$'); + if (pos != -1) { + //* ch = 0; + spawnpoint = level.substring(pos + 1); + level = level.substring(0, pos); + + } else + //spawnpoint[0] = 0; + spawnpoint = ""; + + // skip the end-of-unit flag if necessary + if (level.charAt(0) == '*') + level = level.substring(1); + + l = level.length(); + if (l > 4 && level.endsWith(".cin")) { + SCR.BeginLoadingPlaque(); // for local system + SV_SEND.SV_BroadcastCommand("changing\n"); + SV_SpawnServer(level, spawnpoint, Defines.ss_cinematic, + attractloop, loadgame); + } else if (l > 4 && level.endsWith(".dm2")) { + SCR.BeginLoadingPlaque(); // for local system + SV_SEND.SV_BroadcastCommand("changing\n"); + SV_SpawnServer(level, spawnpoint, Defines.ss_demo, attractloop, + loadgame); + } else if (l > 4 && level.endsWith(".pcx")) { + SCR.BeginLoadingPlaque(); // for local system + SV_SEND.SV_BroadcastCommand("changing\n"); + SV_SpawnServer(level, spawnpoint, Defines.ss_pic, attractloop, + loadgame); + } else { + SCR.BeginLoadingPlaque(); // for local system + SV_SEND.SV_BroadcastCommand("changing\n"); + SV_SEND.SV_SendClientMessages(); + SV_SpawnServer(level, spawnpoint, Defines.ss_game, attractloop, + loadgame); + Cbuf.CopyToDefer(); + } + + SV_SEND.SV_BroadcastCommand("reconnect\n"); + } + + public static server_static_t svs = new server_static_t(); // persistant + // server info + + public static server_t sv = new server_t(); // local server +} \ No newline at end of file diff --git a/src/jake2/server/SV_MAIN.java b/src/jake2/server/SV_MAIN.java index 5800a73..41d5789 100644 --- a/src/jake2/server/SV_MAIN.java +++ b/src/jake2/server/SV_MAIN.java @@ -1,1015 +1,1045 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 13.01.2004 by RST. -// $Id: SV_MAIN.java,v 1.7 2004-09-10 19:02:56 salomo Exp $ - +// $Id: SV_MAIN.java,v 1.8 2004-09-22 19:22:12 salomo Exp $ package jake2.server; import jake2.Defines; import jake2.Globals; -import jake2.game.*; -import jake2.qcommon.*; +import jake2.game.Cmd; +import jake2.game.GameBase; +import jake2.game.Info; +import jake2.game.PlayerClient; +import jake2.game.cvar_t; +import jake2.game.edict_t; +import jake2.qcommon.Com; +import jake2.qcommon.Cvar; +import jake2.qcommon.FS; +import jake2.qcommon.MSG; +import jake2.qcommon.Netchan; +import jake2.qcommon.SZ; +import jake2.qcommon.netadr_t; import jake2.sys.NET; import jake2.sys.Sys; import jake2.util.Lib; import java.io.IOException; -public class SV_MAIN extends SV_GAME { - - static netadr_t master_adr[]= new netadr_t[MAX_MASTERS]; // address of group servers - static { - for (int i= 0; i < MAX_MASTERS; i++) { - master_adr[i]= new netadr_t(); - } - } - public static client_t sv_client; // current client - - public static cvar_t sv_paused; - public static cvar_t sv_timedemo; - - public static cvar_t sv_enforcetime; - - public static cvar_t timeout; // seconds without any message - public static cvar_t zombietime; // seconds to sink messages after disconnect - - public static cvar_t rcon_password; // password for remote server commands - - public static cvar_t allow_download; - public static cvar_t allow_download_players; - public static cvar_t allow_download_models; - public static cvar_t allow_download_sounds; - public static cvar_t allow_download_maps; - - public static cvar_t sv_airaccelerate; - - public static cvar_t sv_noreload; // don't reload level state when reentering - - public static cvar_t maxclients; // FIXME: rename sv_maxclients - public static cvar_t sv_showclamp; - - public static cvar_t hostname; - public static cvar_t public_server; // should heartbeats be sent - - public static cvar_t sv_reconnect_limit; // minimum seconds between connect messages - - //============================================================================ - - /* - ===================== - SV_DropClient - - Called when the player is totally leaving the server, either willingly - or unwillingly. This is NOT called if the entire server is quiting - or crashing. - ===================== - */ - public static void SV_DropClient(client_t drop) { - // add the disconnect - MSG.WriteByte(drop.netchan.message, Defines.svc_disconnect); - - if (drop.state == Defines.cs_spawned) { - // call the prog function for removing a client - // this will remove the body, among other things - PlayerClient.ClientDisconnect(drop.edict); - } - - if (drop.download != null) { - FS.FreeFile(drop.download); - drop.download= null; - } - - drop.state= Defines.cs_zombie; // become free in a few seconds - drop.name= ""; - } - - /* - ============================================================================== - - CONNECTIONLESS COMMANDS - - ============================================================================== - */ - - /* - =============== - SV_StatusString - - Builds the string that is sent as heartbeats and status replies - =============== - */ - public static String SV_StatusString() { - String player; - String status= ""; - int i; - client_t cl; - int statusLength; - int playerLength; - - status= Cvar.Serverinfo() + "\n"; - - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - if (cl.state == Defines.cs_connected || cl.state == Defines.cs_spawned) { - player= "" + cl.edict.client.ps.stats[Defines.STAT_FRAGS] + " " + cl.ping + "\"" + cl.name + "\"\n"; - - playerLength= player.length(); - statusLength= status.length(); - - if (statusLength + playerLength >= 1024) - break; // can't hold any more - - status += player; - } - } - - return status; - } - - /* - ================ - SVC_Status - - Responds with all the info that qplug or qspy can see - ================ - */ - public static void SVC_Status() { - Netchan.OutOfBandPrint(NS_SERVER, Netchan.net_from, "print\n" + SV_StatusString()); - } - - /* - ================ - SVC_Ack - - ================ - */ - public static void SVC_Ack() { - Com.Printf("Ping acknowledge from " + NET.AdrToString(Netchan.net_from) + "\n"); - } - - /* - ================ - SVC_Info - - Responds with short info for broadcast scans - The second parameter should be the current protocol version number. - ================ - */ - public static void SVC_Info() { - String string; - int i, count; - int version; - - if (maxclients.value == 1) - return; // ignore in single player - - version= atoi(Cmd.Argv(1)); - - if (version != PROTOCOL_VERSION) - string= hostname.string + ": wrong version\n"; - else { - count= 0; - for (i= 0; i < maxclients.value; i++) - if (svs.clients[i].state >= cs_connected) - count++; - - string= hostname.string + " " + sv.name + " " + count + "/" + (int) maxclients.value + "\n"; - } - - Netchan.OutOfBandPrint(NS_SERVER, Netchan.net_from, "info\n" + string); - } - - /* - ================ - SVC_Ping - - Just responds with an acknowledgement - ================ - */ - public static void SVC_Ping() { - Netchan.OutOfBandPrint(NS_SERVER, Netchan.net_from, "ack"); - } - - /* - ================= - SVC_GetChallenge - - Returns a challenge number that can be used - in a subsequent client_connect command. - We do this to prevent denial of service attacks that - flood the server with invalid connection IPs. With a - challenge, they must give a valid IP address. - ================= - */ - public static void SVC_GetChallenge() { - int i; - int oldest; - int oldestTime; - - oldest= 0; - oldestTime= 0x7fffffff; - - // see if we already have a challenge for this ip - for (i= 0; i < MAX_CHALLENGES; i++) { - if (NET.NET_CompareBaseAdr(Netchan.net_from, svs.challenges[i].adr)) - break; - if (svs.challenges[i].time < oldestTime) { - oldestTime= svs.challenges[i].time; - oldest= i; - } - } - - if (i == MAX_CHALLENGES) { - // overwrite the oldest - svs.challenges[oldest].challenge= rand() & 0x7fff; - svs.challenges[oldest].adr= Netchan.net_from; - svs.challenges[oldest].time= (int) Globals.curtime; - i= oldest; - } - - // send it back - Netchan.OutOfBandPrint(NS_SERVER, Netchan.net_from, "challenge " + svs.challenges[i].challenge); - } - - /* - ================== - SVC_DirectConnect - - A connection request that did not come from the master - ================== - */ - public static void SVC_DirectConnect() { - String userinfo; - netadr_t adr; - int i; - client_t cl; - - edict_t ent; - int edictnum; - int version; - int qport; - - adr= Netchan.net_from; - - Com.DPrintf("SVC_DirectConnect ()\n"); - - version= atoi(Cmd.Argv(1)); - if (version != PROTOCOL_VERSION) { - Netchan.OutOfBandPrint(NS_SERVER, adr, "print\nServer is version " + VERSION + "\n"); - Com.DPrintf(" rejected connect from version " + version + "\n"); - return; - } - - qport= atoi(Cmd.Argv(2)); - int challenge= atoi(Cmd.Argv(3)); - userinfo= Cmd.Argv(4); - - //userinfo[sizeof(userinfo) - 1] = 0; - - // force the IP key/value pair so the game can filter based on ip - userinfo= Info.Info_SetValueForKey1(userinfo, "ip", NET.AdrToString(Netchan.net_from)); - - // attractloop servers are ONLY for local clients - if (sv.attractloop) { - if (!NET.IsLocalAddress(adr)) { - Com.Printf("Remote connect in attract loop. Ignored.\n"); - Netchan.OutOfBandPrint(NS_SERVER, adr, "print\nConnection refused.\n"); - return; - } - } - - // see if the challenge is valid - if (!NET.IsLocalAddress(adr)) { - for (i= 0; i < MAX_CHALLENGES; i++) { - if (NET.NET_CompareBaseAdr(Netchan.net_from, svs.challenges[i].adr)) { - if (challenge == svs.challenges[i].challenge) - break; // good - Netchan.OutOfBandPrint(NS_SERVER, adr, "print\nBad challenge.\n"); - return; - } - } - if (i == MAX_CHALLENGES) { - Netchan.OutOfBandPrint(NS_SERVER, adr, "print\nNo challenge for address.\n"); - return; - } - } - - // if there is already a slot for this ip, reuse it - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - - if (cl.state == cs_free) - continue; - if (NET.NET_CompareBaseAdr(adr, cl.netchan.remote_address) - && (cl.netchan.qport == qport || adr.port == cl.netchan.remote_address.port)) { - if (!NET.IsLocalAddress(adr) && (svs.realtime - cl.lastconnect) < ((int) sv_reconnect_limit.value * 1000)) { - Com.DPrintf(NET.AdrToString(adr) + ":reconnect rejected : too soon\n"); - return; - } - Com.Printf(NET.AdrToString(adr) + ":reconnect\n"); - - gotnewcl(i, challenge, userinfo, adr, qport); - return; - } - } - - // find a client slot - //newcl = null; - int index= -1; - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - if (cl.state == cs_free) { - index= i; - break; - } - } - if (index == -1) { - Netchan.OutOfBandPrint(NS_SERVER, adr, "print\nServer is full.\n"); - Com.DPrintf("Rejected a connection.\n"); - return; - } - gotnewcl(index, challenge, userinfo, adr, qport); - } - - public static void gotnewcl(int i, int challenge, String userinfo, netadr_t adr, int qport) { - // build a new connection - // accept the new client - // this is the only place a client_t is ever initialized - //*newcl = temp; - - sv_client= svs.clients[i]; - //edictnum = (newcl-svs.clients)+1; - int edictnum= i + 1; - edict_t ent= GameBase.g_edicts[edictnum]; - svs.clients[i].edict= ent; - svs.clients[i].challenge= challenge; // save challenge for checksumming - - // get the game a chance to reject this connection or modify the userinfo - if (!(PlayerClient.ClientConnect(ent, userinfo))) { - if (Info.Info_ValueForKey(userinfo, "rejmsg") != null) - Netchan.OutOfBandPrint( - NS_SERVER, - adr, - "print\n" + Info.Info_ValueForKey(userinfo, "rejmsg") + "\nConnection refused.\n"); - else - Netchan.OutOfBandPrint(NS_SERVER, adr, "print\nConnection refused.\n"); - Com.DPrintf("Game rejected a connection.\n"); - return; - } - - // parse some info from the info strings - svs.clients[i].userinfo= userinfo; - SV_UserinfoChanged(svs.clients[i]); - - // send the connect packet to the client - Netchan.OutOfBandPrint(NS_SERVER, adr, "client_connect"); - - Netchan.Setup(NS_SERVER, svs.clients[i].netchan, adr, qport); - - svs.clients[i].state= cs_connected; - - SZ.Init(svs.clients[i].datagram, svs.clients[i].datagram_buf, svs.clients[i].datagram_buf.length); - svs.clients[i].datagram.allowoverflow= true; - svs.clients[i].lastmessage= svs.realtime; // don't timeout - svs.clients[i].lastconnect= svs.realtime; - Com.DPrintf("new client added.\n"); - } - - public static int Rcon_Validate() { - if (0 == rcon_password.string.length()) - return 0; - - if (0 != strcmp(Cmd.Argv(1), rcon_password.string)) - return 0; - - return 1; - } - - /* - =============== - SVC_RemoteCommand - - A client issued an rcon command. - Shift down the remaining args - Redirect all printfs - =============== - */ - public static void SVC_RemoteCommand() { - int i; - //char remaining[1024]; - String remaining; - - i= Rcon_Validate(); - - String msg= new String(net_message.data, 4, -1); - - if (i == 0) - Com.Printf("Bad rcon from " + NET.AdrToString(Netchan.net_from) + ":\n" + msg + "\n"); - else - Com.Printf("Rcon from " + NET.AdrToString(Netchan.net_from) + ":\n" + msg + "\n"); - - Com.BeginRedirect(RD_PACKET, SV_SEND.sv_outputbuf, SV_OUTPUTBUF_LENGTH, new Com.RD_Flusher() { - public void rd_flush(int target, byte[] buffer) { - SV_SEND.SV_FlushRedirect(target, buffer); - } - }); - - if (0 == Rcon_Validate()) { - Com.Printf("Bad rcon_password.\n"); - } - else { - remaining= ""; - - for (i= 2; i < Cmd.Argc(); i++) { - remaining += Cmd.Argv(i); - remaining += " "; - } - - Cmd.ExecuteString(remaining); - } - - Com.EndRedirect(); - } - - /* - ================= - SV_ConnectionlessPacket - - A connectionless packet has four leading 0xff - characters to distinguish it from a game channel. - Clients that are in the game can still send - connectionless packets. - ================= - */ - public static void SV_ConnectionlessPacket() { - String s; - String c; - - MSG.BeginReading(net_message); - MSG.ReadLong(net_message); // skip the -1 marker - - s= MSG.ReadStringLine(net_message); - - Cmd.TokenizeString(s.toCharArray(), false); - - c= Cmd.Argv(0); - //Com.Printf("Packet " + NET.AdrToString(Netchan.net_from) + " : " + c + "\n"); - //Com.Printf(Lib.hexDump(net_message.data, 64, false) + "\n"); - - if (0 == strcmp(c, "ping")) - SVC_Ping(); - else if (0 == strcmp(c, "ack")) - SVC_Ack(); - else if (0 == strcmp(c, "status")) - SVC_Status(); - else if (0 == strcmp(c, "info")) - SVC_Info(); - else if (0 == strcmp(c, "getchallenge")) - SVC_GetChallenge(); - else if (0 == strcmp(c, "connect")) - SVC_DirectConnect(); - else if (0 == strcmp(c, "rcon")) - SVC_RemoteCommand(); - else { - Com.Printf("bad connectionless packet from " + NET.AdrToString(Netchan.net_from) + "\n"); - Com.Printf("[" + s + "]\n"); - Com.Printf("" + Lib.hexDump(net_message.data, 128, false)); - } - } - - //============================================================================ - - /* - =================== - SV_CalcPings - - Updates the cl.ping variables - =================== - */ - public static void SV_CalcPings() { - int i, j; - client_t cl; - int total, count; - - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - if (cl.state != cs_spawned) - continue; - - total= 0; - count= 0; - for (j= 0; j < LATENCY_COUNTS; j++) { - if (cl.frame_latency[j] > 0) { - count++; - total += cl.frame_latency[j]; - } - } - if (0 == count) - cl.ping= 0; - else - cl.ping= total / count; - - // let the game dll know about the ping - cl.edict.client.ping= cl.ping; - } - } - - /* - =================== - SV_GiveMsec - - Every few frames, gives all clients an allotment of milliseconds - for their command moves. If they exceed it, assume cheating. - =================== - */ - public static void SV_GiveMsec() { - int i; - client_t cl; - - if ((sv.framenum & 15) != 0) - return; - - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - if (cl.state == cs_free) - continue; - - cl.commandMsec= 1800; // 1600 + some slop - } - } - - /* - ================= - SV_ReadPackets - ================= - */ - public static void SV_ReadPackets() { - int i; - client_t cl; - int qport= 0; - - while (NET.GetPacket(NS_SERVER, Netchan.net_from, net_message)) { - - // check for connectionless packet (0xffffffff) first - if ((net_message.data[0] == -1) - && (net_message.data[1] == -1) - && (net_message.data[2] == -1) - && (net_message.data[3] == -1)) { - SV_ConnectionlessPacket(); - continue; - } - - // read the qport out of the message so we can fix up - // stupid address translating routers - MSG.BeginReading(net_message); - MSG.ReadLong(net_message); // sequence number - MSG.ReadLong(net_message); // sequence number - qport= MSG.ReadShort(net_message) & 0xffff; - - // check for packets from connected clients - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - if (cl.state == cs_free) - continue; - if (!NET.NET_CompareBaseAdr(Netchan.net_from, cl.netchan.remote_address)) - continue; - if (cl.netchan.qport != qport) - continue; - if (cl.netchan.remote_address.port != Netchan.net_from.port) { - Com.Printf("SV_ReadPackets: fixing up a translated port\n"); - cl.netchan.remote_address.port= Netchan.net_from.port; - } - - if (Netchan.Process(cl.netchan, net_message)) { // this is a valid, sequenced packet, so process it - if (cl.state != cs_zombie) { - cl.lastmessage= svs.realtime; // don't timeout - SV_USER.SV_ExecuteClientMessage(cl); - } - } - break; - } - - if (i != maxclients.value) - continue; - } - } - - /* - ================== - SV_CheckTimeouts - - If a packet has not been received from a client for timeout.value - seconds, drop the conneciton. Server frames are used instead of - realtime to avoid dropping the local client while debugging. - - When a client is normally dropped, the client_t goes into a zombie state - for a few seconds to make sure any final reliable message gets resent - if necessary - ================== - */ - public static void SV_CheckTimeouts() { - int i; - client_t cl; - int droppoint; - int zombiepoint; - - droppoint= (int) (svs.realtime - 1000 * timeout.value); - zombiepoint= (int) (svs.realtime - 1000 * zombietime.value); - - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - // message times may be wrong across a changelevel - if (cl.lastmessage > svs.realtime) - cl.lastmessage= svs.realtime; - - if (cl.state == cs_zombie && cl.lastmessage < zombiepoint) { - cl.state= cs_free; // can now be reused - continue; - } - if ((cl.state == cs_connected || cl.state == cs_spawned) && cl.lastmessage < droppoint) { - SV_SEND.SV_BroadcastPrintf(PRINT_HIGH, cl.name + " timed out\n"); - SV_DropClient(cl); - cl.state= cs_free; // don't bother with zombie state - } - } - } - - /* - ================ - SV_PrepWorldFrame - - This has to be done before the world logic, because - player processing happens outside RunWorldFrame - ================ - */ - public static void SV_PrepWorldFrame() { - edict_t ent; - int i; - - for (i= 0; i < GameBase.num_edicts; i++) { - ent= GameBase.g_edicts[i]; - // events only last for a single message - ent.s.event= 0; - } - - } - - /* - ================= - SV_RunGameFrame - ================= - */ - public static void SV_RunGameFrame() { - if (host_speeds.value != 0) - time_before_game= Sys.Milliseconds(); - - // we always need to bump framenum, even if we - // don't run the world, otherwise the delta - // compression can get confused when a client - // has the "current" frame - sv.framenum++; - sv.time= sv.framenum * 100; - - // don't run if paused - if (0 == sv_paused.value || maxclients.value > 1) { - Game.G_RunFrame(); - - // never get more than one tic behind - if (sv.time < svs.realtime) { - if (sv_showclamp.value != 0) - Com.Printf("sv highclamp\n"); - svs.realtime= sv.time; - } - } - - if (host_speeds.value != 0) - time_after_game= Sys.Milliseconds(); - - } - - /* - ================== - SV_Frame - - ================== - */ - public static void SV_Frame(long msec) { - Globals.time_before_game= Globals.time_after_game= 0; - - // if server is not active, do nothing - if (!svs.initialized) - return; - - svs.realtime += msec; - - // keep the random time dependent - Lib.rand(); - - // check timeouts - SV_CheckTimeouts(); - - // get packets from clients - SV_ReadPackets(); - - //if (Game.g_edicts[1] !=null) - // Com.p("player at:" + Lib.vtofsbeaty(Game.g_edicts[1].s.origin )); - - // move autonomous things around if enough time has passed - if (0 == sv_timedemo.value && svs.realtime < sv.time) { - // never let the time get too far off - if (sv.time - svs.realtime > 100) { - if (sv_showclamp.value != 0) - Com.Printf("sv lowclamp\n"); - svs.realtime= sv.time - 100; - } - NET.NET_Sleep(sv.time - svs.realtime); - return; - } - - // update ping based on the last known frame from all clients - //TODO: dont need yet - SV_CalcPings(); - - // give the clients some timeslices - //TODO: dont need yet - SV_GiveMsec(); - - // let everything in the world think and move - SV_RunGameFrame(); - - // send messages back to the clients that had packets read this frame - SV_SEND.SV_SendClientMessages(); - - // save the entire world state if recording a serverdemo - //TODO: dont need yet - //SV_WORLD.SV_RecordDemoMessage(); - - // send a heartbeat to the master if needed - //TODO: dont need yet - Master_Heartbeat(); - - // clear teleport flags, etc for next frame - SV_PrepWorldFrame(); - - } - - //============================================================================ - - /* - ================ - Master_Heartbeat - - Send a message to the master every few minutes to - let it know we are alive, and log information - ================ - */ - public static final int HEARTBEAT_SECONDS= 300; - public static void Master_Heartbeat() { - String string; - int i; - - // pgm post3.19 change, cvar pointer not validated before dereferencing - if (dedicated == null || 0 == dedicated.value) - return; // only dedicated servers send heartbeats - - // pgm post3.19 change, cvar pointer not validated before dereferencing - if (null == public_server || 0 == public_server.value) - return; // a private dedicated game - - // check for time wraparound - if (svs.last_heartbeat > svs.realtime) - svs.last_heartbeat= svs.realtime; - - if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS * 1000) - return; // not time to send yet - - svs.last_heartbeat= svs.realtime; - - // send the same string that we would give for a status OOB command - string= SV_StatusString(); - - // send to group master - for (i= 0; i < MAX_MASTERS; i++) - if (master_adr[i].port != 0) { - Com.Printf("Sending heartbeat to " + NET.AdrToString(master_adr[i]) + "\n"); - Netchan.OutOfBandPrint(NS_SERVER, master_adr[i], "heartbeat\n" + string); - } - } - - /* - ================= - Master_Shutdown - - Informs all masters that this server is going down - ================= - */ - static void Master_Shutdown() { - int i; - - // pgm post3.19 change, cvar pointer not validated before dereferencing - if (null == dedicated || 0 == dedicated.value) - return; // only dedicated servers send heartbeats - - // pgm post3.19 change, cvar pointer not validated before dereferencing - if (null == public_server || 0 == public_server.value) - return; // a private dedicated game - - // send to group master - for (i= 0; i < MAX_MASTERS; i++) - if (master_adr[i].port != 0) { - if (i > 0) - Com.Printf("Sending heartbeat to " + NET.AdrToString(master_adr[i]) + "\n"); - Netchan.OutOfBandPrint(NS_SERVER, master_adr[i], "shutdown"); - } - } - - //============================================================================ - - /* - ================= - SV_UserinfoChanged - - Pull specific info from a newly changed userinfo string - into a more C freindly form. - ================= - */ - public static void SV_UserinfoChanged(client_t cl) { - String val; - int i; - - // call prog code to allow overrides - PlayerClient.ClientUserinfoChanged(cl.edict, cl.userinfo); - - // name for C code - cl.name= Info.Info_ValueForKey(cl.userinfo, "name"); - - // mask off high bit - //TODO: masking for german umlaute - //for (i=0 ; i 0) { - i= atoi(val); - cl.rate= i; - if (cl.rate < 100) - cl.rate= 100; - if (cl.rate > 15000) - cl.rate= 15000; - } - else - cl.rate= 5000; - - // msg command - val= Info.Info_ValueForKey(cl.userinfo, "msg"); - if (val.length() > 0) { - cl.messagelevel= atoi(val); - } - - } - - //============================================================================ - - /* - =============== - SV_Init - - Only called at quake2.exe startup, not for each game - =============== - */ - public static void SV_Init() { - SV_CCMDS.SV_InitOperatorCommands(); //ok. - - rcon_password= Cvar.Get("rcon_password", "", 0); - Cvar.Get("skill", "1", 0); - Cvar.Get("deathmatch", "0", CVAR_LATCH); - Cvar.Get("coop", "0", CVAR_LATCH); - Cvar.Get("dmflags", "" + DF_INSTANT_ITEMS, CVAR_SERVERINFO); - Cvar.Get("fraglimit", "0", CVAR_SERVERINFO); - Cvar.Get("timelimit", "0", CVAR_SERVERINFO); - //TODO: set cheats 0 - Cvar.Get("cheats", "1", CVAR_SERVERINFO | CVAR_LATCH); - Cvar.Get("protocol", "" + PROTOCOL_VERSION, CVAR_SERVERINFO | CVAR_NOSET); - - SV_MAIN.maxclients= Cvar.Get("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH); - hostname= Cvar.Get("hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE); - timeout= Cvar.Get("timeout", "125", 0); - zombietime= Cvar.Get("zombietime", "2", 0); - sv_showclamp= Cvar.Get("showclamp", "0", 0); - sv_paused= Cvar.Get("paused", "0", 0); - sv_timedemo= Cvar.Get("timedemo", "0", 0); - sv_enforcetime= Cvar.Get("sv_enforcetime", "0", 0); - - // TODO: carsten, re-allow downloads per default - allow_download= Cvar.Get("allow_download", "0", CVAR_ARCHIVE); - allow_download_players= Cvar.Get("allow_download_players", "0", CVAR_ARCHIVE); - allow_download_models= Cvar.Get("allow_download_models", "1", CVAR_ARCHIVE); - allow_download_sounds= Cvar.Get("allow_download_sounds", "1", CVAR_ARCHIVE); - allow_download_maps= Cvar.Get("allow_download_maps", "1", CVAR_ARCHIVE); - - sv_noreload= Cvar.Get("sv_noreload", "0", 0); - sv_airaccelerate= Cvar.Get("sv_airaccelerate", "0", CVAR_LATCH); - public_server= Cvar.Get("public", "0", 0); - sv_reconnect_limit= Cvar.Get("sv_reconnect_limit", "3", CVAR_ARCHIVE); - - SZ.Init(net_message, net_message_buffer, net_message_buffer.length); - } - - /* - ================== - SV_FinalMessage - - Used by SV_Shutdown to send a final message to all - connected clients before the server goes down. The messages are sent immediately, - not just stuck on the outgoing message list, because the server is going - to totally exit after returning from this function. - ================== - */ - public static void SV_FinalMessage(String message, boolean reconnect) { - int i; - client_t cl; - - SZ.Clear(net_message); - MSG.WriteByte(net_message, svc_print); - MSG.WriteByte(net_message, PRINT_HIGH); - MSG.WriteString(net_message, message); - - if (reconnect) - MSG.WriteByte(net_message, svc_reconnect); - else - MSG.WriteByte(net_message, svc_disconnect); - - // send it twice - // stagger the packets to crutch operating system limited buffers - - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - if (cl.state >= cs_connected) - Netchan.Transmit(cl.netchan, net_message.cursize, net_message.data); - } - for (i= 0; i < maxclients.value; i++) { - cl= svs.clients[i]; - if (cl.state >= cs_connected) - Netchan.Transmit(cl.netchan, net_message.cursize, net_message.data); - } - } - - /* - ================ - SV_Shutdown - - Called when each game quits, - before Sys_Quit or Sys_Error - ================ - */ - public static void SV_Shutdown(String finalmsg, boolean reconnect) { - if (svs.clients != null) - SV_FinalMessage(finalmsg, reconnect); - - Master_Shutdown(); - - SV_GAME.SV_ShutdownGameProgs(); - - // free current level - if (sv.demofile != null) - try { - sv.demofile.close(); - } - catch (IOException e) { - e.printStackTrace(); - } - - sv= new server_t(); - - Globals.server_state= sv.state; - - if (svs.demofile != null) - try { - svs.demofile.close(); - } - catch (IOException e1) { - e1.printStackTrace(); - } - - svs= new server_static_t(); - } -} +public class SV_MAIN { + + public static netadr_t master_adr[] = new netadr_t[Defines.MAX_MASTERS]; // address + // of + // group + // servers + static { + for (int i = 0; i < Defines.MAX_MASTERS; i++) { + master_adr[i] = new netadr_t(); + } + } + + public static client_t sv_client; // current client + + public static cvar_t sv_paused; + + public static cvar_t sv_timedemo; + + public static cvar_t sv_enforcetime; + + public static cvar_t timeout; // seconds without any message + + public static cvar_t zombietime; // seconds to sink messages after + // disconnect + + public static cvar_t rcon_password; // password for remote server commands + + public static cvar_t allow_download; + + public static cvar_t allow_download_players; + + public static cvar_t allow_download_models; + + public static cvar_t allow_download_sounds; + + public static cvar_t allow_download_maps; + + public static cvar_t sv_airaccelerate; + + public static cvar_t sv_noreload; // don't reload level state when + // reentering + + public static cvar_t maxclients; // FIXME: rename sv_maxclients + + public static cvar_t sv_showclamp; + + public static cvar_t hostname; + + public static cvar_t public_server; // should heartbeats be sent + + public static cvar_t sv_reconnect_limit; // minimum seconds between connect + // messages + + //============================================================================ + + /* + * ================ Master_Heartbeat + * + * Send a message to the master every few minutes to let it know we are + * alive, and log information ================ + */ + public static final int HEARTBEAT_SECONDS = 300; + + //============================================================================ + + /* + * ===================== SV_DropClient + * + * Called when the player is totally leaving the server, either willingly or + * unwillingly. This is NOT called if the entire server is quiting or + * crashing. ===================== + */ + public static void SV_DropClient(client_t drop) { + // add the disconnect + MSG.WriteByte(drop.netchan.message, Defines.svc_disconnect); + + if (drop.state == Defines.cs_spawned) { + // call the prog function for removing a client + // this will remove the body, among other things + PlayerClient.ClientDisconnect(drop.edict); + } + + if (drop.download != null) { + FS.FreeFile(drop.download); + drop.download = null; + } + + drop.state = Defines.cs_zombie; // become free in a few seconds + drop.name = ""; + } + + /* + * ============================================================================== + * + * CONNECTIONLESS COMMANDS + * + * ============================================================================== + */ + + /* + * =============== SV_StatusString + * + * Builds the string that is sent as heartbeats and status replies + * =============== + */ + public static String SV_StatusString() { + String player; + String status = ""; + int i; + client_t cl; + int statusLength; + int playerLength; + + status = Cvar.Serverinfo() + "\n"; + + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + if (cl.state == Defines.cs_connected + || cl.state == Defines.cs_spawned) { + player = "" + cl.edict.client.ps.stats[Defines.STAT_FRAGS] + + " " + cl.ping + "\"" + cl.name + "\"\n"; + + playerLength = player.length(); + statusLength = status.length(); + + if (statusLength + playerLength >= 1024) + break; // can't hold any more + + status += player; + } + } + + return status; + } + + /* + * ================ SVC_Status + * + * Responds with all the info that qplug or qspy can see ================ + */ + public static void SVC_Status() { + Netchan.OutOfBandPrint(Defines.NS_SERVER, Globals.net_from, "print\n" + + SV_StatusString()); + } + + /* + * ================ SVC_Ack + * + * ================ + */ + public static void SVC_Ack() { + Com.Printf("Ping acknowledge from " + NET.AdrToString(Globals.net_from) + + "\n"); + } + + /* + * ================ SVC_Info + * + * Responds with short info for broadcast scans The second parameter should + * be the current protocol version number. ================ + */ + public static void SVC_Info() { + String string; + int i, count; + int version; + + if (SV_MAIN.maxclients.value == 1) + return; // ignore in single player + + version = Lib.atoi(Cmd.Argv(1)); + + if (version != Defines.PROTOCOL_VERSION) + string = SV_MAIN.hostname.string + ": wrong version\n"; + else { + count = 0; + for (i = 0; i < SV_MAIN.maxclients.value; i++) + if (SV_INIT.svs.clients[i].state >= Defines.cs_connected) + count++; + + string = SV_MAIN.hostname.string + " " + SV_INIT.sv.name + " " + + count + "/" + (int) SV_MAIN.maxclients.value + "\n"; + } + + Netchan.OutOfBandPrint(Defines.NS_SERVER, Globals.net_from, "info\n" + + string); + } + + /* + * ================ SVC_Ping + * + * Just responds with an acknowledgement ================ + */ + public static void SVC_Ping() { + Netchan.OutOfBandPrint(Defines.NS_SERVER, Globals.net_from, "ack"); + } + + /* + * ================= SVC_GetChallenge + * + * Returns a challenge number that can be used in a subsequent + * client_connect command. We do this to prevent denial of service attacks + * that flood the server with invalid connection IPs. With a challenge, they + * must give a valid IP address. ================= + */ + public static void SVC_GetChallenge() { + int i; + int oldest; + int oldestTime; + + oldest = 0; + oldestTime = 0x7fffffff; + + // see if we already have a challenge for this ip + for (i = 0; i < Defines.MAX_CHALLENGES; i++) { + if (NET.NET_CompareBaseAdr(Globals.net_from, + SV_INIT.svs.challenges[i].adr)) + break; + if (SV_INIT.svs.challenges[i].time < oldestTime) { + oldestTime = SV_INIT.svs.challenges[i].time; + oldest = i; + } + } + + if (i == Defines.MAX_CHALLENGES) { + // overwrite the oldest + SV_INIT.svs.challenges[oldest].challenge = Lib.rand() & 0x7fff; + SV_INIT.svs.challenges[oldest].adr = Globals.net_from; + SV_INIT.svs.challenges[oldest].time = (int) Globals.curtime; + i = oldest; + } + + // send it back + Netchan.OutOfBandPrint(Defines.NS_SERVER, Globals.net_from, + "challenge " + SV_INIT.svs.challenges[i].challenge); + } + + /* + * ================== SVC_DirectConnect + * + * A connection request that did not come from the master ================== + */ + public static void SVC_DirectConnect() { + String userinfo; + netadr_t adr; + int i; + client_t cl; + + edict_t ent; + int edictnum; + int version; + int qport; + + adr = Globals.net_from; + + Com.DPrintf("SVC_DirectConnect ()\n"); + + version = Lib.atoi(Cmd.Argv(1)); + if (version != Defines.PROTOCOL_VERSION) { + Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, + "print\nServer is version " + Globals.VERSION + "\n"); + Com.DPrintf(" rejected connect from version " + version + "\n"); + return; + } + + qport = Lib.atoi(Cmd.Argv(2)); + int challenge = Lib.atoi(Cmd.Argv(3)); + userinfo = Cmd.Argv(4); + + //userinfo[sizeof(userinfo) - 1] = 0; + + // force the IP key/value pair so the game can filter based on ip + userinfo = Info.Info_SetValueForKey1(userinfo, "ip", NET + .AdrToString(Globals.net_from)); + + // attractloop servers are ONLY for local clients + if (SV_INIT.sv.attractloop) { + if (!NET.IsLocalAddress(adr)) { + Com.Printf("Remote connect in attract loop. Ignored.\n"); + Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, + "print\nConnection refused.\n"); + return; + } + } + + // see if the challenge is valid + if (!NET.IsLocalAddress(adr)) { + for (i = 0; i < Defines.MAX_CHALLENGES; i++) { + if (NET.NET_CompareBaseAdr(Globals.net_from, + SV_INIT.svs.challenges[i].adr)) { + if (challenge == SV_INIT.svs.challenges[i].challenge) + break; // good + Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, + "print\nBad challenge.\n"); + return; + } + } + if (i == Defines.MAX_CHALLENGES) { + Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, + "print\nNo challenge for address.\n"); + return; + } + } + + // if there is already a slot for this ip, reuse it + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + + if (cl.state == Defines.cs_free) + continue; + if (NET.NET_CompareBaseAdr(adr, cl.netchan.remote_address) + && (cl.netchan.qport == qport || adr.port == cl.netchan.remote_address.port)) { + if (!NET.IsLocalAddress(adr) + && (SV_INIT.svs.realtime - cl.lastconnect) < ((int) SV_MAIN.sv_reconnect_limit.value * 1000)) { + Com.DPrintf(NET.AdrToString(adr) + + ":reconnect rejected : too soon\n"); + return; + } + Com.Printf(NET.AdrToString(adr) + ":reconnect\n"); + + gotnewcl(i, challenge, userinfo, adr, qport); + return; + } + } + + // find a client slot + //newcl = null; + int index = -1; + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + if (cl.state == Defines.cs_free) { + index = i; + break; + } + } + if (index == -1) { + Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, + "print\nServer is full.\n"); + Com.DPrintf("Rejected a connection.\n"); + return; + } + gotnewcl(index, challenge, userinfo, adr, qport); + } + + public static void gotnewcl(int i, int challenge, String userinfo, + netadr_t adr, int qport) { + // build a new connection + // accept the new client + // this is the only place a client_t is ever initialized + //*newcl = temp; + + SV_MAIN.sv_client = SV_INIT.svs.clients[i]; + //edictnum = (newcl-svs.clients)+1; + int edictnum = i + 1; + edict_t ent = GameBase.g_edicts[edictnum]; + SV_INIT.svs.clients[i].edict = ent; + SV_INIT.svs.clients[i].challenge = challenge; // save challenge for + // checksumming + + // get the game a chance to reject this connection or modify the + // userinfo + if (!(PlayerClient.ClientConnect(ent, userinfo))) { + if (Info.Info_ValueForKey(userinfo, "rejmsg") != null) + Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\n" + + Info.Info_ValueForKey(userinfo, "rejmsg") + + "\nConnection refused.\n"); + else + Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, + "print\nConnection refused.\n"); + Com.DPrintf("Game rejected a connection.\n"); + return; + } + + // parse some info from the info strings + SV_INIT.svs.clients[i].userinfo = userinfo; + SV_UserinfoChanged(SV_INIT.svs.clients[i]); + + // send the connect packet to the client + Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "client_connect"); + + Netchan.Setup(Defines.NS_SERVER, SV_INIT.svs.clients[i].netchan, adr, + qport); + + SV_INIT.svs.clients[i].state = Defines.cs_connected; + + SZ.Init(SV_INIT.svs.clients[i].datagram, + SV_INIT.svs.clients[i].datagram_buf, + SV_INIT.svs.clients[i].datagram_buf.length); + SV_INIT.svs.clients[i].datagram.allowoverflow = true; + SV_INIT.svs.clients[i].lastmessage = SV_INIT.svs.realtime; // don't + // timeout + SV_INIT.svs.clients[i].lastconnect = SV_INIT.svs.realtime; + Com.DPrintf("new client added.\n"); + } + + public static int Rcon_Validate() { + if (0 == SV_MAIN.rcon_password.string.length()) + return 0; + + if (0 != Lib.strcmp(Cmd.Argv(1), SV_MAIN.rcon_password.string)) + return 0; + + return 1; + } + + /* + * =============== SVC_RemoteCommand + * + * A client issued an rcon command. Shift down the remaining args Redirect + * all printfs =============== + */ + public static void SVC_RemoteCommand() { + int i; + //char remaining[1024]; + String remaining; + + i = Rcon_Validate(); + + String msg = new String(Globals.net_message.data, 4, -1); + + if (i == 0) + Com.Printf("Bad rcon from " + NET.AdrToString(Globals.net_from) + + ":\n" + msg + "\n"); + else + Com.Printf("Rcon from " + NET.AdrToString(Globals.net_from) + ":\n" + + msg + "\n"); + + Com.BeginRedirect(Defines.RD_PACKET, SV_SEND.sv_outputbuf, + Defines.SV_OUTPUTBUF_LENGTH, new Com.RD_Flusher() { + public void rd_flush(int target, byte[] buffer) { + SV_SEND.SV_FlushRedirect(target, buffer); + } + }); + + if (0 == Rcon_Validate()) { + Com.Printf("Bad rcon_password.\n"); + } else { + remaining = ""; + + for (i = 2; i < Cmd.Argc(); i++) { + remaining += Cmd.Argv(i); + remaining += " "; + } + + Cmd.ExecuteString(remaining); + } + + Com.EndRedirect(); + } + + /* + * ================= SV_ConnectionlessPacket + * + * A connectionless packet has four leading 0xff characters to distinguish + * it from a game channel. Clients that are in the game can still send + * connectionless packets. ================= + */ + public static void SV_ConnectionlessPacket() { + String s; + String c; + + MSG.BeginReading(Globals.net_message); + MSG.ReadLong(Globals.net_message); // skip the -1 marker + + s = MSG.ReadStringLine(Globals.net_message); + + Cmd.TokenizeString(s.toCharArray(), false); + + c = Cmd.Argv(0); + //Com.Printf("Packet " + NET.AdrToString(Netchan.net_from) + " : " + c + // + "\n"); + //Com.Printf(Lib.hexDump(net_message.data, 64, false) + "\n"); + + if (0 == Lib.strcmp(c, "ping")) + SVC_Ping(); + else if (0 == Lib.strcmp(c, "ack")) + SVC_Ack(); + else if (0 == Lib.strcmp(c, "status")) + SVC_Status(); + else if (0 == Lib.strcmp(c, "info")) + SVC_Info(); + else if (0 == Lib.strcmp(c, "getchallenge")) + SVC_GetChallenge(); + else if (0 == Lib.strcmp(c, "connect")) + SVC_DirectConnect(); + else if (0 == Lib.strcmp(c, "rcon")) + SVC_RemoteCommand(); + else { + Com.Printf("bad connectionless packet from " + + NET.AdrToString(Globals.net_from) + "\n"); + Com.Printf("[" + s + "]\n"); + Com.Printf("" + Lib.hexDump(Globals.net_message.data, 128, false)); + } + } + + //============================================================================ + + /* + * =================== SV_CalcPings + * + * Updates the cl.ping variables =================== + */ + public static void SV_CalcPings() { + int i, j; + client_t cl; + int total, count; + + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + if (cl.state != Defines.cs_spawned) + continue; + + total = 0; + count = 0; + for (j = 0; j < Defines.LATENCY_COUNTS; j++) { + if (cl.frame_latency[j] > 0) { + count++; + total += cl.frame_latency[j]; + } + } + if (0 == count) + cl.ping = 0; + else + cl.ping = total / count; + + // let the game dll know about the ping + cl.edict.client.ping = cl.ping; + } + } + + /* + * =================== SV_GiveMsec + * + * Every few frames, gives all clients an allotment of milliseconds for + * their command moves. If they exceed it, assume cheating. + * =================== + */ + public static void SV_GiveMsec() { + int i; + client_t cl; + + if ((SV_INIT.sv.framenum & 15) != 0) + return; + + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + if (cl.state == Defines.cs_free) + continue; + + cl.commandMsec = 1800; // 1600 + some slop + } + } + + /* + * ================= SV_ReadPackets ================= + */ + public static void SV_ReadPackets() { + int i; + client_t cl; + int qport = 0; + + while (NET.GetPacket(Defines.NS_SERVER, Globals.net_from, + Globals.net_message)) { + + // check for connectionless packet (0xffffffff) first + if ((Globals.net_message.data[0] == -1) + && (Globals.net_message.data[1] == -1) + && (Globals.net_message.data[2] == -1) + && (Globals.net_message.data[3] == -1)) { + SV_ConnectionlessPacket(); + continue; + } + + // read the qport out of the message so we can fix up + // stupid address translating routers + MSG.BeginReading(Globals.net_message); + MSG.ReadLong(Globals.net_message); // sequence number + MSG.ReadLong(Globals.net_message); // sequence number + qport = MSG.ReadShort(Globals.net_message) & 0xffff; + + // check for packets from connected clients + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + if (cl.state == Defines.cs_free) + continue; + if (!NET.NET_CompareBaseAdr(Globals.net_from, + cl.netchan.remote_address)) + continue; + if (cl.netchan.qport != qport) + continue; + if (cl.netchan.remote_address.port != Globals.net_from.port) { + Com.Printf("SV_ReadPackets: fixing up a translated port\n"); + cl.netchan.remote_address.port = Globals.net_from.port; + } + + if (Netchan.Process(cl.netchan, Globals.net_message)) { + // this is a valid, sequenced packet, so process it + if (cl.state != Defines.cs_zombie) { + cl.lastmessage = SV_INIT.svs.realtime; // don't timeout + SV_USER.SV_ExecuteClientMessage(cl); + } + } + break; + } + + if (i != SV_MAIN.maxclients.value) + continue; + } + } + + /* + * ================== SV_CheckTimeouts + * + * If a packet has not been received from a client for timeout.value + * seconds, drop the conneciton. Server frames are used instead of realtime + * to avoid dropping the local client while debugging. + * + * When a client is normally dropped, the client_t goes into a zombie state + * for a few seconds to make sure any final reliable message gets resent if + * necessary ================== + */ + public static void SV_CheckTimeouts() { + int i; + client_t cl; + int droppoint; + int zombiepoint; + + droppoint = (int) (SV_INIT.svs.realtime - 1000 * SV_MAIN.timeout.value); + zombiepoint = (int) (SV_INIT.svs.realtime - 1000 * SV_MAIN.zombietime.value); + + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + // message times may be wrong across a changelevel + if (cl.lastmessage > SV_INIT.svs.realtime) + cl.lastmessage = SV_INIT.svs.realtime; + + if (cl.state == Defines.cs_zombie && cl.lastmessage < zombiepoint) { + cl.state = Defines.cs_free; // can now be reused + continue; + } + if ((cl.state == Defines.cs_connected || cl.state == Defines.cs_spawned) + && cl.lastmessage < droppoint) { + SV_SEND.SV_BroadcastPrintf(Defines.PRINT_HIGH, cl.name + + " timed out\n"); + SV_DropClient(cl); + cl.state = Defines.cs_free; // don't bother with zombie state + } + } + } + + /* + * ================ SV_PrepWorldFrame + * + * This has to be done before the world logic, because player processing + * happens outside RunWorldFrame ================ + */ + public static void SV_PrepWorldFrame() { + edict_t ent; + int i; + + for (i = 0; i < GameBase.num_edicts; i++) { + ent = GameBase.g_edicts[i]; + // events only last for a single message + ent.s.event = 0; + } + + } + + /* + * ================= SV_RunGameFrame ================= + */ + public static void SV_RunGameFrame() { + if (Globals.host_speeds.value != 0) + Globals.time_before_game = Sys.Milliseconds(); + + // we always need to bump framenum, even if we + // don't run the world, otherwise the delta + // compression can get confused when a client + // has the "current" frame + SV_INIT.sv.framenum++; + SV_INIT.sv.time = SV_INIT.sv.framenum * 100; + + // don't run if paused + if (0 == SV_MAIN.sv_paused.value || SV_MAIN.maxclients.value > 1) { + GameBase.G_RunFrame(); + + // never get more than one tic behind + if (SV_INIT.sv.time < SV_INIT.svs.realtime) { + if (SV_MAIN.sv_showclamp.value != 0) + Com.Printf("sv highclamp\n"); + SV_INIT.svs.realtime = SV_INIT.sv.time; + } + } + + if (Globals.host_speeds.value != 0) + Globals.time_after_game = Sys.Milliseconds(); + + } + + /* + * ================== SV_Frame + * + * ================== + */ + public static void SV_Frame(long msec) { + Globals.time_before_game = Globals.time_after_game = 0; + + // if server is not active, do nothing + if (!SV_INIT.svs.initialized) + return; + + SV_INIT.svs.realtime += msec; + + // keep the random time dependent + Lib.rand(); + + // check timeouts + SV_CheckTimeouts(); + + // get packets from clients + SV_ReadPackets(); + + //if (Game.g_edicts[1] !=null) + // Com.p("player at:" + Lib.vtofsbeaty(Game.g_edicts[1].s.origin )); + + // move autonomous things around if enough time has passed + if (0 == SV_MAIN.sv_timedemo.value + && SV_INIT.svs.realtime < SV_INIT.sv.time) { + // never let the time get too far off + if (SV_INIT.sv.time - SV_INIT.svs.realtime > 100) { + if (SV_MAIN.sv_showclamp.value != 0) + Com.Printf("sv lowclamp\n"); + SV_INIT.svs.realtime = SV_INIT.sv.time - 100; + } + NET.NET_Sleep(SV_INIT.sv.time - SV_INIT.svs.realtime); + return; + } + + // update ping based on the last known frame from all clients + //TODO: dont need yet + SV_CalcPings(); + + // give the clients some timeslices + //TODO: dont need yet + SV_GiveMsec(); + + // let everything in the world think and move + SV_RunGameFrame(); + + // send messages back to the clients that had packets read this frame + SV_SEND.SV_SendClientMessages(); + + // save the entire world state if recording a serverdemo + //TODO: dont need yet + //SV_WORLD.SV_RecordDemoMessage(); + + // send a heartbeat to the master if needed + //TODO: dont need yet + Master_Heartbeat(); + + // clear teleport flags, etc for next frame + SV_PrepWorldFrame(); + + } + + public static void Master_Heartbeat() { + String string; + int i; + + // pgm post3.19 change, cvar pointer not validated before dereferencing + if (Globals.dedicated == null || 0 == Globals.dedicated.value) + return; // only dedicated servers send heartbeats + + // pgm post3.19 change, cvar pointer not validated before dereferencing + if (null == SV_MAIN.public_server || 0 == SV_MAIN.public_server.value) + return; // a private dedicated game + + // check for time wraparound + if (SV_INIT.svs.last_heartbeat > SV_INIT.svs.realtime) + SV_INIT.svs.last_heartbeat = SV_INIT.svs.realtime; + + if (SV_INIT.svs.realtime - SV_INIT.svs.last_heartbeat < SV_MAIN.HEARTBEAT_SECONDS * 1000) + return; // not time to send yet + + SV_INIT.svs.last_heartbeat = SV_INIT.svs.realtime; + + // send the same string that we would give for a status OOB command + string = SV_StatusString(); + + // send to group master + for (i = 0; i < Defines.MAX_MASTERS; i++) + if (SV_MAIN.master_adr[i].port != 0) { + Com.Printf("Sending heartbeat to " + + NET.AdrToString(SV_MAIN.master_adr[i]) + "\n"); + Netchan.OutOfBandPrint(Defines.NS_SERVER, + SV_MAIN.master_adr[i], "heartbeat\n" + string); + } + } + + /* + * ================= Master_Shutdown + * + * Informs all masters that this server is going down ================= + */ + public static void Master_Shutdown() { + int i; + + // pgm post3.19 change, cvar pointer not validated before dereferencing + if (null == Globals.dedicated || 0 == Globals.dedicated.value) + return; // only dedicated servers send heartbeats + + // pgm post3.19 change, cvar pointer not validated before dereferencing + if (null == SV_MAIN.public_server || 0 == SV_MAIN.public_server.value) + return; // a private dedicated game + + // send to group master + for (i = 0; i < Defines.MAX_MASTERS; i++) + if (SV_MAIN.master_adr[i].port != 0) { + if (i > 0) + Com.Printf("Sending heartbeat to " + + NET.AdrToString(SV_MAIN.master_adr[i]) + "\n"); + Netchan.OutOfBandPrint(Defines.NS_SERVER, + SV_MAIN.master_adr[i], "shutdown"); + } + } + + //============================================================================ + + /* + * ================= SV_UserinfoChanged + * + * Pull specific info from a newly changed userinfo string into a more C + * freindly form. ================= + */ + public static void SV_UserinfoChanged(client_t cl) { + String val; + int i; + + // call prog code to allow overrides + PlayerClient.ClientUserinfoChanged(cl.edict, cl.userinfo); + + // name for C code + cl.name = Info.Info_ValueForKey(cl.userinfo, "name"); + + // mask off high bit + //TODO: masking for german umlaute + //for (i=0 ; i 0) { + i = Lib.atoi(val); + cl.rate = i; + if (cl.rate < 100) + cl.rate = 100; + if (cl.rate > 15000) + cl.rate = 15000; + } else + cl.rate = 5000; + + // msg command + val = Info.Info_ValueForKey(cl.userinfo, "msg"); + if (val.length() > 0) { + cl.messagelevel = Lib.atoi(val); + } + + } + + //============================================================================ + + /* + * =============== SV_Init + * + * Only called at quake2.exe startup, not for each game =============== + */ + public static void SV_Init() { + SV_CCMDS.SV_InitOperatorCommands(); //ok. + + SV_MAIN.rcon_password = Cvar.Get("rcon_password", "", 0); + Cvar.Get("skill", "1", 0); + Cvar.Get("deathmatch", "0", Defines.CVAR_LATCH); + Cvar.Get("coop", "0", Defines.CVAR_LATCH); + Cvar.Get("dmflags", "" + Defines.DF_INSTANT_ITEMS, + Defines.CVAR_SERVERINFO); + Cvar.Get("fraglimit", "0", Defines.CVAR_SERVERINFO); + Cvar.Get("timelimit", "0", Defines.CVAR_SERVERINFO); + //TODO: set cheats 0 + Cvar.Get("cheats", "1", Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH); + Cvar.Get("protocol", "" + Defines.PROTOCOL_VERSION, + Defines.CVAR_SERVERINFO | Defines.CVAR_NOSET); + + SV_MAIN.maxclients = Cvar.Get("maxclients", "1", + Defines.CVAR_SERVERINFO | Defines.CVAR_LATCH); + SV_MAIN.hostname = Cvar.Get("hostname", "noname", + Defines.CVAR_SERVERINFO | Defines.CVAR_ARCHIVE); + SV_MAIN.timeout = Cvar.Get("timeout", "125", 0); + SV_MAIN.zombietime = Cvar.Get("zombietime", "2", 0); + SV_MAIN.sv_showclamp = Cvar.Get("showclamp", "0", 0); + SV_MAIN.sv_paused = Cvar.Get("paused", "0", 0); + SV_MAIN.sv_timedemo = Cvar.Get("timedemo", "0", 0); + SV_MAIN.sv_enforcetime = Cvar.Get("sv_enforcetime", "0", 0); + + // TODO: carsten, re-allow downloads per default + SV_MAIN.allow_download = Cvar.Get("allow_download", "0", + Defines.CVAR_ARCHIVE); + SV_MAIN.allow_download_players = Cvar.Get("allow_download_players", + "0", Defines.CVAR_ARCHIVE); + SV_MAIN.allow_download_models = Cvar.Get("allow_download_models", "1", + Defines.CVAR_ARCHIVE); + SV_MAIN.allow_download_sounds = Cvar.Get("allow_download_sounds", "1", + Defines.CVAR_ARCHIVE); + SV_MAIN.allow_download_maps = Cvar.Get("allow_download_maps", "1", + Defines.CVAR_ARCHIVE); + + SV_MAIN.sv_noreload = Cvar.Get("sv_noreload", "0", 0); + SV_MAIN.sv_airaccelerate = Cvar.Get("sv_airaccelerate", "0", + Defines.CVAR_LATCH); + SV_MAIN.public_server = Cvar.Get("public", "0", 0); + SV_MAIN.sv_reconnect_limit = Cvar.Get("sv_reconnect_limit", "3", + Defines.CVAR_ARCHIVE); + + SZ.Init(Globals.net_message, Globals.net_message_buffer, + Globals.net_message_buffer.length); + } + + /* + * ================== SV_FinalMessage + * + * Used by SV_Shutdown to send a final message to all connected clients + * before the server goes down. The messages are sent immediately, not just + * stuck on the outgoing message list, because the server is going to + * totally exit after returning from this function. ================== + */ + public static void SV_FinalMessage(String message, boolean reconnect) { + int i; + client_t cl; + + SZ.Clear(Globals.net_message); + MSG.WriteByte(Globals.net_message, Defines.svc_print); + MSG.WriteByte(Globals.net_message, Defines.PRINT_HIGH); + MSG.WriteString(Globals.net_message, message); + + if (reconnect) + MSG.WriteByte(Globals.net_message, Defines.svc_reconnect); + else + MSG.WriteByte(Globals.net_message, Defines.svc_disconnect); + + // send it twice + // stagger the packets to crutch operating system limited buffers + + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + if (cl.state >= Defines.cs_connected) + Netchan.Transmit(cl.netchan, Globals.net_message.cursize, + Globals.net_message.data); + } + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; + if (cl.state >= Defines.cs_connected) + Netchan.Transmit(cl.netchan, Globals.net_message.cursize, + Globals.net_message.data); + } + } + + /* + * ================ SV_Shutdown + * + * Called when each game quits, before Sys_Quit or Sys_Error + * ================ + */ + public static void SV_Shutdown(String finalmsg, boolean reconnect) { + if (SV_INIT.svs.clients != null) + SV_FinalMessage(finalmsg, reconnect); + + Master_Shutdown(); + + SV_GAME.SV_ShutdownGameProgs(); + + // free current level + if (SV_INIT.sv.demofile != null) + try { + SV_INIT.sv.demofile.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + SV_INIT.sv = new server_t(); + + Globals.server_state = SV_INIT.sv.state; + + if (SV_INIT.svs.demofile != null) + try { + SV_INIT.svs.demofile.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + + SV_INIT.svs = new server_static_t(); + } +} \ No newline at end of file diff --git a/src/jake2/server/SV_SEND.java b/src/jake2/server/SV_SEND.java index 9b30a99..8488954 100644 --- a/src/jake2/server/SV_SEND.java +++ b/src/jake2/server/SV_SEND.java @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Created on 17.01.2004 by RST. -// $Id: SV_SEND.java,v 1.5 2004-09-10 19:02:56 salomo Exp $ +// $Id: SV_SEND.java,v 1.6 2004-09-22 19:22:12 salomo Exp $ package jake2.server; @@ -30,8 +30,9 @@ import jake2.client.*; import jake2.game.*; import jake2.qcommon.*; import jake2.render.*; +import jake2.util.Math3D; -public class SV_SEND extends SV_MAIN { +public class SV_SEND { /* ============================================================================= @@ -40,20 +41,19 @@ public class SV_SEND extends SV_MAIN { ============================================================================= */ - public static byte sv_outputbuf[]= new byte[SV_OUTPUTBUF_LENGTH]; + public static byte sv_outputbuf[] = new byte[Defines.SV_OUTPUTBUF_LENGTH]; public static void SV_FlushRedirect(int sv_redirected, byte outputbuf[]) { - if (sv_redirected == RD_PACKET) { - String s= ("print\n" + outputbuf); - Netchan.Netchan_OutOfBand(NS_SERVER, Netchan.net_from, s.length(), s.getBytes()); + if (sv_redirected == Defines.RD_PACKET) { + String s = ("print\n" + outputbuf); + Netchan.Netchan_OutOfBand(Defines.NS_SERVER, Globals.net_from, s.length(), s.getBytes()); } - else if (sv_redirected == RD_CLIENT) { - MSG.WriteByte(SV_MAIN.sv_client.netchan.message, svc_print); - MSG.WriteByte(SV_MAIN.sv_client.netchan.message, PRINT_HIGH); + else if (sv_redirected == Defines.RD_CLIENT) { + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, Defines.svc_print); + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, Defines.PRINT_HIGH); MSG.WriteString(SV_MAIN.sv_client.netchan.message, outputbuf); - } + } } - /* ============================================================================= @@ -74,11 +74,10 @@ public class SV_SEND extends SV_MAIN { if (level < cl.messagelevel) return; - MSG.WriteByte(cl.netchan.message, svc_print); + MSG.WriteByte(cl.netchan.message, Defines.svc_print); MSG.WriteByte(cl.netchan.message, level); MSG.WriteString(cl.netchan.message, s); } - /* ================= SV_BroadcastPrintf @@ -91,23 +90,22 @@ public class SV_SEND extends SV_MAIN { client_t cl; // echo to console - if (dedicated.value != 0) { + if (Globals.dedicated.value != 0) { Com.Printf(s); } - for (int i= 0; i < SV_MAIN.maxclients.value; i++) { - cl= SV_MAIN.svs.clients[i]; + for (int i = 0; i < SV_MAIN.maxclients.value; i++) { + cl = SV_INIT.svs.clients[i]; if (level < cl.messagelevel) continue; - if (cl.state != cs_spawned) + if (cl.state != Defines.cs_spawned) continue; - MSG.WriteByte(cl.netchan.message, svc_print); + MSG.WriteByte(cl.netchan.message, Defines.svc_print); MSG.WriteByte(cl.netchan.message, level); MSG.WriteString(cl.netchan.message, s); } } - /* ================= SV_BroadcastCommand @@ -117,14 +115,13 @@ public class SV_SEND extends SV_MAIN { */ public static void SV_BroadcastCommand(String s) { - if (sv.state == 0) + if (SV_INIT.sv.state == 0) return; - MSG.WriteByte(sv.multicast, svc_stufftext); - MSG.WriteString(sv.multicast, s); - SV_Multicast(null, MULTICAST_ALL_R); + MSG.WriteByte(SV_INIT.sv.multicast, Defines.svc_stufftext); + MSG.WriteString(SV_INIT.sv.multicast, s); + SV_Multicast(null, Defines.MULTICAST_ALL_R); } - /* ================= SV_Multicast @@ -145,63 +142,63 @@ public class SV_SEND extends SV_MAIN { boolean reliable; int area1, area2; - reliable= false; + reliable = false; - if (to != MULTICAST_ALL_R && to != MULTICAST_ALL) { - leafnum= CM.CM_PointLeafnum(origin); - area1= CM.CM_LeafArea(leafnum); + if (to != Defines.MULTICAST_ALL_R && to != Defines.MULTICAST_ALL) { + leafnum = CM.CM_PointLeafnum(origin); + area1 = CM.CM_LeafArea(leafnum); } else { - leafnum= 0; // just to avoid compiler warnings - area1= 0; + leafnum = 0; // just to avoid compiler warnings + area1 = 0; } // if doing a serverrecord, store everything - if (svs.demofile != null) - SZ.Write(svs.demo_multicast, sv.multicast.data, sv.multicast.cursize); + if (SV_INIT.svs.demofile != null) + SZ.Write(SV_INIT.svs.demo_multicast, SV_INIT.sv.multicast.data, SV_INIT.sv.multicast.cursize); switch (to) { - case MULTICAST_ALL_R : - reliable= true; // intentional fallthrough, no break here - case MULTICAST_ALL : - leafnum= 0; - mask= null; + case Defines.MULTICAST_ALL_R : + reliable = true; // intentional fallthrough, no break here + case Defines.MULTICAST_ALL : + leafnum = 0; + mask = null; break; - case MULTICAST_PHS_R : - reliable= true; // intentional fallthrough - case MULTICAST_PHS : - leafnum= CM.CM_PointLeafnum(origin); - cluster= CM.CM_LeafCluster(leafnum); - mask= CM.CM_ClusterPHS(cluster); + case Defines.MULTICAST_PHS_R : + reliable = true; // intentional fallthrough + case Defines.MULTICAST_PHS : + leafnum = CM.CM_PointLeafnum(origin); + cluster = CM.CM_LeafCluster(leafnum); + mask = CM.CM_ClusterPHS(cluster); break; - case MULTICAST_PVS_R : - reliable= true; // intentional fallthrough - case MULTICAST_PVS : - leafnum= CM.CM_PointLeafnum(origin); - cluster= CM.CM_LeafCluster(leafnum); - mask= CM.CM_ClusterPVS(cluster); + case Defines.MULTICAST_PVS_R : + reliable = true; // intentional fallthrough + case Defines.MULTICAST_PVS : + leafnum = CM.CM_PointLeafnum(origin); + cluster = CM.CM_LeafCluster(leafnum); + mask = CM.CM_ClusterPVS(cluster); break; default : - mask= null; - Com.Error(ERR_FATAL, "SV_Multicast: bad to:" + to + "\n"); + mask = null; + Com.Error(Defines.ERR_FATAL, "SV_Multicast: bad to:" + to + "\n"); } // send the data to all relevent clients - for (j= 0; j < maxclients.value; j++) { - client= svs.clients[j]; + for (j = 0; j < SV_MAIN.maxclients.value; j++) { + client = SV_INIT.svs.clients[j]; - if (client.state == cs_free || client.state == cs_zombie) + if (client.state == Defines.cs_free || client.state == Defines.cs_zombie) continue; - if (client.state != cs_spawned && !reliable) + if (client.state != Defines.cs_spawned && !reliable) continue; if (mask != null) { - leafnum= CM.CM_PointLeafnum(client.edict.s.origin); - cluster= CM.CM_LeafCluster(leafnum); - area2= CM.CM_LeafArea(leafnum); + leafnum = CM.CM_PointLeafnum(client.edict.s.origin); + cluster = CM.CM_LeafCluster(leafnum); + area2 = CM.CM_LeafArea(leafnum); if (!CM.CM_AreasConnected(area1, area2)) continue; @@ -213,14 +210,13 @@ public class SV_SEND extends SV_MAIN { } if (reliable) - SZ.Write(client.netchan.message, sv.multicast.data, sv.multicast.cursize); + SZ.Write(client.netchan.message, SV_INIT.sv.multicast.data, SV_INIT.sv.multicast.cursize); else - SZ.Write(client.datagram, sv.multicast.data, sv.multicast.cursize); + SZ.Write(client.datagram, SV_INIT.sv.multicast.data, SV_INIT.sv.multicast.cursize); } - SZ.Clear(sv.multicast); + SZ.Clear(SV_INIT.sv.multicast); } - /* ================== SV_StartSound @@ -259,98 +255,97 @@ public class SV_SEND extends SV_MAIN { int flags; int i; int ent; - float[] origin_v= { 0, 0, 0 }; + float[] origin_v = { 0, 0, 0 }; boolean use_phs; if (volume < 0 || volume > 1.0) - Com.Error(ERR_FATAL, "SV_StartSound: volume = " + volume); + Com.Error(Defines.ERR_FATAL, "SV_StartSound: volume = " + volume); if (attenuation < 0 || attenuation > 4) - Com.Error(ERR_FATAL, "SV_StartSound: attenuation = " + attenuation); + Com.Error(Defines.ERR_FATAL, "SV_StartSound: attenuation = " + attenuation); // if (channel < 0 || channel > 15) // Com_Error (ERR_FATAL, "SV_StartSound: channel = %i", channel); if (timeofs < 0 || timeofs > 0.255) - Com.Error(ERR_FATAL, "SV_StartSound: timeofs = " + timeofs); + Com.Error(Defines.ERR_FATAL, "SV_StartSound: timeofs = " + timeofs); - ent= entity.index; + ent = entity.index; // no PHS flag if ((channel & 8) != 0) { - use_phs= false; + use_phs = false; channel &= 7; } else - use_phs= true; + use_phs = true; - sendchan= (ent << 3) | (channel & 7); + sendchan = (ent << 3) | (channel & 7); - flags= 0; + flags = 0; if (volume != Defines.DEFAULT_SOUND_PACKET_VOLUME) - flags |= SND_VOLUME; - if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) - flags |= SND_ATTENUATION; + flags |= Defines.SND_VOLUME; + if (attenuation != Defines.DEFAULT_SOUND_PACKET_ATTENUATION) + flags |= Defines.SND_ATTENUATION; // the client doesn't know that bmodels have weird origins // the origin can also be explicitly set - if ((entity.svflags & SVF_NOCLIENT) != 0 || (entity.solid == SOLID_BSP) || origin != null) - flags |= SND_POS; + if ((entity.svflags & Defines.SVF_NOCLIENT) != 0 || (entity.solid == Defines.SOLID_BSP) || origin != null) + flags |= Defines.SND_POS; // always send the entity number for channel overrides - flags |= SND_ENT; + flags |= Defines.SND_ENT; if (timeofs != 0) - flags |= SND_OFFSET; + flags |= Defines.SND_OFFSET; // use the entity origin unless it is a bmodel or explicitly specified if (origin == null) { - origin= origin_v; - if (entity.solid == SOLID_BSP) { - for (i= 0; i < 3; i++) - origin_v[i]= entity.s.origin[i] + 0.5f * (entity.mins[i] + entity.maxs[i]); + origin = origin_v; + if (entity.solid == Defines.SOLID_BSP) { + for (i = 0; i < 3; i++) + origin_v[i] = entity.s.origin[i] + 0.5f * (entity.mins[i] + entity.maxs[i]); } else { - VectorCopy(entity.s.origin, origin_v); + Math3D.VectorCopy(entity.s.origin, origin_v); } } - MSG.WriteByte(sv.multicast, svc_sound); - MSG.WriteByte(sv.multicast, flags); - MSG.WriteByte(sv.multicast, soundindex); + MSG.WriteByte(SV_INIT.sv.multicast, Defines.svc_sound); + MSG.WriteByte(SV_INIT.sv.multicast, flags); + MSG.WriteByte(SV_INIT.sv.multicast, soundindex); - if ((flags & SND_VOLUME) != 0) - MSG.WriteByte(sv.multicast, volume * 255); - if ((flags & SND_ATTENUATION) != 0) - MSG.WriteByte(sv.multicast, attenuation * 64); - if ((flags & SND_OFFSET) != 0) - MSG.WriteByte(sv.multicast, timeofs * 1000); + if ((flags & Defines.SND_VOLUME) != 0) + MSG.WriteByte(SV_INIT.sv.multicast, volume * 255); + if ((flags & Defines.SND_ATTENUATION) != 0) + MSG.WriteByte(SV_INIT.sv.multicast, attenuation * 64); + if ((flags & Defines.SND_OFFSET) != 0) + MSG.WriteByte(SV_INIT.sv.multicast, timeofs * 1000); - if ((flags & SND_ENT) != 0) - MSG.WriteShort(sv.multicast, sendchan); + if ((flags & Defines.SND_ENT) != 0) + MSG.WriteShort(SV_INIT.sv.multicast, sendchan); - if ((flags & SND_POS) != 0) - MSG.WritePos(sv.multicast, origin); + if ((flags & Defines.SND_POS) != 0) + MSG.WritePos(SV_INIT.sv.multicast, origin); // if the sound doesn't attenuate,send it to everyone // (global radio chatter, voiceovers, etc) - if (attenuation == ATTN_NONE) - use_phs= false; + if (attenuation == Defines.ATTN_NONE) + use_phs = false; - if ((channel & CHAN_RELIABLE) != 0) { + if ((channel & Defines.CHAN_RELIABLE) != 0) { if (use_phs) - SV_Multicast(origin, MULTICAST_PHS_R); + SV_Multicast(origin, Defines.MULTICAST_PHS_R); else - SV_Multicast(origin, MULTICAST_ALL_R); + SV_Multicast(origin, Defines.MULTICAST_ALL_R); } else { if (use_phs) - SV_Multicast(origin, MULTICAST_PHS); + SV_Multicast(origin, Defines.MULTICAST_PHS); else - SV_Multicast(origin, MULTICAST_ALL); + SV_Multicast(origin, Defines.MULTICAST_ALL); } } - /* =============================================================================== @@ -365,17 +360,17 @@ public class SV_SEND extends SV_MAIN { ======================= */ public static boolean SV_SendClientDatagram(client_t client) { - byte msg_buf[]= new byte[MAX_MSGLEN]; - sizebuf_t msg= new sizebuf_t(); + byte msg_buf[] = new byte[Defines.MAX_MSGLEN]; + sizebuf_t msg = new sizebuf_t(); SV_ENTS.SV_BuildClientFrame(client); SZ.Init(msg, msg_buf, msg_buf.length); - msg.allowoverflow= true; + msg.allowoverflow = true; // send over all the relevant entity_state_t // and the player_state_t - SV_CCMDS.SV_WriteFrameToClient(client, msg); + SV_ENTS.SV_WriteFrameToClient(client, msg); // copy the accumulated multicast datagram // for this client out to the message @@ -396,29 +391,27 @@ public class SV_SEND extends SV_MAIN { Netchan.Transmit(client.netchan, msg.cursize, msg.data); // record the size for rate estimation - client.message_size[sv.framenum % RATE_MESSAGES]= msg.cursize; + client.message_size[SV_INIT.sv.framenum % Defines.RATE_MESSAGES] = msg.cursize; return true; } - /* ================== SV_DemoCompleted ================== */ public static void SV_DemoCompleted() { - if (sv.demofile != null) { + if (SV_INIT.sv.demofile != null) { try { - sv.demofile.close(); + SV_INIT.sv.demofile.close(); } catch (IOException e) { Com.Printf("IOError closing d9emo fiele:" + e); } - sv.demofile= null; + SV_INIT.sv.demofile = null; } - SV_ENTS.SV_Nextserver(); + SV_USER.SV_Nextserver(); } - /* ======================= SV_RateDrop @@ -432,24 +425,23 @@ public class SV_SEND extends SV_MAIN { int i; // never drop over the loopback - if (c.netchan.remote_address.type == NA_LOOPBACK) + if (c.netchan.remote_address.type == Defines.NA_LOOPBACK) return false; - total= 0; + total = 0; - for (i= 0; i < RATE_MESSAGES; i++) { + for (i = 0; i < Defines.RATE_MESSAGES; i++) { total += c.message_size[i]; } if (total > c.rate) { c.surpressCount++; - c.message_size[sv.framenum % RATE_MESSAGES]= 0; + c.message_size[SV_INIT.sv.framenum % Defines.RATE_MESSAGES] = 0; return true; } return false; } - /* ======================= SV_SendClientMessages @@ -459,20 +451,20 @@ public class SV_SEND extends SV_MAIN { int i; client_t c; int msglen; - byte msgbuf[]= new byte[MAX_MSGLEN]; + byte msgbuf[] = new byte[Defines.MAX_MSGLEN]; int r; - msglen= 0; + msglen = 0; // read the next demo message if needed - if (sv.state == ss_demo && sv.demofile != null) { - if (sv_paused.value != 0) - msglen= 0; + if (SV_INIT.sv.state == Defines.ss_demo && SV_INIT.sv.demofile != null) { + if (SV_MAIN.sv_paused.value != 0) + msglen = 0; else { // get the next message //r = fread (&msglen, 4, 1, sv.demofile); try { - msglen= EndianHandler.swapInt(sv.demofile.readInt()); + msglen = EndianHandler.swapInt(SV_INIT.sv.demofile.readInt()); } catch (Exception e) { SV_DemoCompleted(); @@ -484,13 +476,13 @@ public class SV_SEND extends SV_MAIN { SV_DemoCompleted(); return; } - if (msglen > MAX_MSGLEN) - Com.Error(ERR_DROP, "SV_SendClientMessages: msglen > MAX_MSGLEN"); + if (msglen > Defines.MAX_MSGLEN) + Com.Error(Defines.ERR_DROP, "SV_SendClientMessages: msglen > MAX_MSGLEN"); //r = fread (msgbuf, msglen, 1, sv.demofile); - r= 0; + r = 0; try { - r= sv.demofile.read(msgbuf, 0, msglen); + r = SV_INIT.sv.demofile.read(msgbuf, 0, msglen); } catch (IOException e1) { Com.Printf("IOError: reading demo file, " + e1); @@ -503,8 +495,8 @@ public class SV_SEND extends SV_MAIN { } // send a message to each connected client - for (i= 0; i < maxclients.value; i++) { - c= svs.clients[i]; + for (i = 0; i < SV_MAIN.maxclients.value; i++) { + c = SV_INIT.svs.clients[i]; if (c.state == 0) continue; @@ -513,13 +505,15 @@ public class SV_SEND extends SV_MAIN { if (c.netchan.message.overflowed) { SZ.Clear(c.netchan.message); SZ.Clear(c.datagram); - SV_BroadcastPrintf(PRINT_HIGH, c.name + " overflowed\n"); - SV_DropClient(c); + SV_BroadcastPrintf(Defines.PRINT_HIGH, c.name + " overflowed\n"); + SV_MAIN.SV_DropClient(c); } - if (sv.state == ss_cinematic || sv.state == ss_demo || sv.state == ss_pic) + if (SV_INIT.sv.state == Defines.ss_cinematic + || SV_INIT.sv.state == Defines.ss_demo + || SV_INIT.sv.state == Defines.ss_pic) Netchan.Transmit(c.netchan, msglen, msgbuf); - else if (c.state == cs_spawned) { + else if (c.state == Defines.cs_spawned) { // don't overrun bandwidth if (SV_RateDrop(c)) continue; diff --git a/src/jake2/server/SV_USER.java b/src/jake2/server/SV_USER.java index 5a31de8..c03cacf 100644 --- a/src/jake2/server/SV_USER.java +++ b/src/jake2/server/SV_USER.java @@ -1,735 +1,691 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 17.01.2004 by RST. -// $Id: SV_USER.java,v 1.5 2004-08-29 21:39:25 hzi Exp $ - +// $Id: SV_USER.java,v 1.6 2004-09-22 19:22:12 salomo Exp $ package jake2.server; -import jake2.game.*; -import jake2.qcommon.*; +import jake2.Defines; +import jake2.Globals; +import jake2.game.Cmd; +import jake2.game.GameAI; +import jake2.game.GameBase; +import jake2.game.Info; +import jake2.game.PlayerClient; +import jake2.game.edict_t; +import jake2.game.entity_state_t; +import jake2.game.usercmd_t; +import jake2.qcommon.Cbuf; +import jake2.qcommon.Com; +import jake2.qcommon.Cvar; +import jake2.qcommon.FS; +import jake2.qcommon.MSG; +import jake2.qcommon.SZ; import jake2.util.Lib; import java.io.IOException; -public class SV_USER extends SV_SEND -{ - - static edict_t sv_player; - - /* - ============================================================ - - USER STRINGCMD EXECUTION - - sv_client and sv_player will be valid. - ============================================================ - */ - - /* - ================== - SV_BeginDemoServer - ================== - */ - public static void SV_BeginDemoserver() - { - String name; - - name= "demos/" + sv.name; - try - { - sv.demofile= FS.FOpenFile(name); - } - catch (IOException e) - { - Com.Error(ERR_DROP, "Couldn't open " + name + "\n"); - } - if (sv.demofile == null) - Com.Error(ERR_DROP, "Couldn't open " + name + "\n"); - } - - /* - ================ - SV_New_f - - Sends the first message from the server to a connected client. - This will be sent on the initial connection and upon each server load. - ================ - */ - public static void SV_New_f() - { - String gamedir; - int playernum; - edict_t ent; - - Com.DPrintf("New() from " + sv_client.name + "\n"); - - if (sv_client.state != cs_connected) - { - Com.Printf("New not valid -- already spawned\n"); - return; - } - - // demo servers just dump the file message - if (sv.state == ss_demo) - { - SV_BeginDemoserver(); - return; - } - - // - // serverdata needs to go over for all types of servers - // to make sure the protocol is right, and to set the gamedir - // - gamedir= Cvar.VariableString("gamedir"); - - // send the serverdata - MSG.WriteByte(sv_client.netchan.message, svc_serverdata); - MSG.WriteInt(sv_client.netchan.message, PROTOCOL_VERSION); - MSG.WriteLong(sv_client.netchan.message, svs.spawncount); - MSG.WriteByte(sv_client.netchan.message, sv.attractloop ? 1 : 0); - MSG.WriteString(sv_client.netchan.message, gamedir); - - if (sv.state == ss_cinematic || sv.state == ss_pic) - playernum= -1; - else - //playernum = sv_client - svs.clients; - playernum= sv_client.serverindex; - - MSG.WriteShort(sv_client.netchan.message, playernum); - - // send full levelname - MSG.WriteString(sv_client.netchan.message, sv.configstrings[CS_NAME]); - - // - // game server - // - if (sv.state == ss_game) - { - // set up the entity for the client - ent= GameBase.g_edicts[playernum + 1]; - ent.s.number= playernum + 1; - sv_client.edict= ent; - sv_client.lastcmd= new usercmd_t(); - - // begin fetching configstrings - MSG.WriteByte(sv_client.netchan.message, svc_stufftext); - MSG.WriteString(sv_client.netchan.message, "cmd configstrings " + svs.spawncount + " 0\n"); - } - - } - - /* - ================== - SV_Configstrings_f - ================== - */ - public static void SV_Configstrings_f() - { - int start; - - Com.DPrintf("Configstrings() from " + sv_client.name + "\n"); - - if (sv_client.state != cs_connected) - { - Com.Printf("configstrings not valid -- already spawned\n"); - return; - } - - // handle the case of a level changing while a client was connecting - if (atoi(Cmd.Argv(1)) != svs.spawncount) - { - Com.Printf("SV_Configstrings_f from different level\n"); - SV_New_f(); - return; - } - - start= atoi(Cmd.Argv(2)); - - // write a packet full of data - - while (sv_client.netchan.message.cursize < MAX_MSGLEN / 2 && start < MAX_CONFIGSTRINGS) - { - if (sv.configstrings[start] != null && sv.configstrings[start].length() != 0) - { - MSG.WriteByte(sv_client.netchan.message, svc_configstring); - MSG.WriteShort(sv_client.netchan.message, start); - MSG.WriteString(sv_client.netchan.message, sv.configstrings[start]); - } - start++; - } - - // send next command - - if (start == MAX_CONFIGSTRINGS) - { - MSG.WriteByte(sv_client.netchan.message, svc_stufftext); - MSG.WriteString(sv_client.netchan.message, "cmd baselines " + svs.spawncount + " 0\n"); - } - else - { - MSG.WriteByte(sv_client.netchan.message, svc_stufftext); - MSG.WriteString(sv_client.netchan.message, "cmd configstrings " + svs.spawncount + " " + start + "\n"); - } - } - - /* - ================== - SV_Baselines_f - ================== - */ - public static void SV_Baselines_f() - { - int start; - entity_state_t nullstate; - entity_state_t base; - - Com.DPrintf("Baselines() from " + sv_client.name + "\n"); - - if (sv_client.state != cs_connected) - { - Com.Printf("baselines not valid -- already spawned\n"); - return; - } - - // handle the case of a level changing while a client was connecting - if (atoi(Cmd.Argv(1)) != svs.spawncount) - { - Com.Printf("SV_Baselines_f from different level\n"); - SV_New_f(); - return; - } - - start= atoi(Cmd.Argv(2)); - - //memset (&nullstate, 0, sizeof(nullstate)); - nullstate= new entity_state_t(null); - - // write a packet full of data - - while (sv_client.netchan.message.cursize < MAX_MSGLEN / 2 && start < MAX_EDICTS) - { - base= sv.baselines[start]; - if (base.modelindex != 0 || base.sound != 0 || base.effects != 0) - { - MSG.WriteByte(sv_client.netchan.message, svc_spawnbaseline); - MSG.WriteDeltaEntity(nullstate, base, sv_client.netchan.message, true, true); - } - start++; - } - - // send next command - - if (start == MAX_EDICTS) - { - MSG.WriteByte(sv_client.netchan.message, svc_stufftext); - MSG.WriteString(sv_client.netchan.message, "precache " + svs.spawncount + "\n"); - } - else - { - MSG.WriteByte(sv_client.netchan.message, svc_stufftext); - MSG.WriteString(sv_client.netchan.message, "cmd baselines " + svs.spawncount + " " + start + "\n"); - } - } - - /* - ================== - SV_Begin_f - ================== - */ - public static void SV_Begin_f() - { - Com.DPrintf("Begin() from " + sv_client.name + "\n"); - - // handle the case of a level changing while a client was connecting - if (atoi(Cmd.Argv(1)) != svs.spawncount) - { - Com.Printf("SV_Begin_f from different level\n"); - SV_New_f(); - return; - } - - sv_client.state= cs_spawned; - - // call the game begin function - PlayerClient.ClientBegin(sv_player); - - Cbuf.InsertFromDefer(); - } - - //============================================================================= - - /* - ================== - SV_NextDownload_f - ================== - */ - public static void SV_NextDownload_f() - { - int r; - int percent; - int size; - - if (sv_client.download == null) - return; - - r= sv_client.downloadsize - sv_client.downloadcount; - if (r > 1024) - r= 1024; - - MSG.WriteByte(sv_client.netchan.message, svc_download); - MSG.WriteShort(sv_client.netchan.message, r); - - sv_client.downloadcount += r; - size= sv_client.downloadsize; - if (size == 0) - size= 1; - percent= sv_client.downloadcount * 100 / size; - MSG.WriteByte(sv_client.netchan.message, percent); - SZ.Write(sv_client.netchan.message, sv_client.download, sv_client.downloadcount - r, r); - - if (sv_client.downloadcount != sv_client.downloadsize) - return; - - FS.FreeFile(sv_client.download); - sv_client.download= null; - } - - /* - ================== - SV_BeginDownload_f - ================== - */ - public static void SV_BeginDownload_f() - { - String name; - int offset= 0; - - name= Cmd.Argv(1); - - if (Cmd.Argc() > 2) - offset= atoi(Cmd.Argv(2)); // downloaded offset - - // hacked by zoid to allow more conrol over download - // first off, no .. or global allow check - - if (name.indexOf("..") != -1 - || allow_download.value == 0 // leading dot is no good - || name.charAt(0) == '.' // leading slash bad as well, must be in subdir - || name.charAt(0) == '/' // next up, skin check - || (name.startsWith("players/") && 0 == allow_download_players.value) // now models - || (name.startsWith("models/") && 0 == allow_download_models.value) // now sounds - || (name.startsWith("sound/") - && 0 == allow_download_sounds.value) // now maps (note special case for maps, must not be in pak) - || (name.startsWith("maps/") && 0 == allow_download_maps.value) // MUST be in a subdirectory - || name.indexOf('/') == -1) - { // don't allow anything with .. path - MSG.WriteByte(sv_client.netchan.message, svc_download); - MSG.WriteShort(sv_client.netchan.message, -1); - MSG.WriteByte(sv_client.netchan.message, 0); - return; - } - - if (sv_client.download != null) - FS.FreeFile(sv_client.download); - - sv_client.download= FS.LoadFile(name); - sv_client.downloadsize= sv_client.download.length; - sv_client.downloadcount= offset; - - if (offset > sv_client.downloadsize) - sv_client.downloadcount= sv_client.downloadsize; - - if (sv_client.download == null // special check for maps, if it came from a pak file, don't allow - // download ZOID - || (name.startsWith("maps/") && FS.file_from_pak != 0)) - { - Com.DPrintf("Couldn't download " + name + " to " + sv_client.name + "\n"); - if (sv_client.download != null) - { - FS.FreeFile(sv_client.download); - sv_client.download= null; - } - - MSG.WriteByte(sv_client.netchan.message, svc_download); - MSG.WriteShort(sv_client.netchan.message, -1); - MSG.WriteByte(sv_client.netchan.message, 0); - return; - } - - SV_NextDownload_f(); - Com.DPrintf("Downloading " + name + " to " + sv_client.name + "\n"); - } - - //============================================================================ - - /* - ================= - SV_Disconnect_f - - The client is going to disconnect, so remove the connection immediately - ================= - */ - public static void SV_Disconnect_f() - { - // SV_EndRedirect (); - SV_DropClient(sv_client); - } - - /* - ================== - SV_ShowServerinfo_f - - Dumps the serverinfo info string - ================== - */ - public static void SV_ShowServerinfo_f() - { - Info.Print(Cvar.Serverinfo()); - } - - public static void SV_Nextserver() - { - String v; - - //ZOID, ss_pic can be nextserver'd in coop mode - if (sv.state == ss_game || (sv.state == ss_pic && 0 == Cvar.VariableValue("coop"))) - return; // can't nextserver while playing a normal game - - svs.spawncount++; // make sure another doesn't sneak in - v= Cvar.VariableString("nextserver"); - //if (!v[0]) - if (v.length() == 0) - Cbuf.AddText("killserver\n"); - else - { - Cbuf.AddText(v); - Cbuf.AddText("\n"); - } - Cvar.Set("nextserver", ""); - } - - /* - ================== - SV_Nextserver_f - - A cinematic has completed or been aborted by a client, so move - to the next server, - ================== - */ - public static void SV_Nextserver_f() - { - if (Lib.atoi(Cmd.Argv(1)) != svs.spawncount) - { - Com.DPrintf("Nextserver() from wrong level, from " + sv_client.name + "\n"); - return; // leftover from last server - } - - Com.DPrintf("Nextserver() from " + sv_client.name + "\n"); - - SV_Nextserver(); - } - - public static class ucmd_t - { - public ucmd_t(String n, Runnable r) - { - name= n; - this.r= r; - } - String name; - Runnable r; - } - - static ucmd_t u1= new ucmd_t("new", new Runnable() - { - public void run() - { - SV_New_f(); - } - }); - - static ucmd_t ucmds[]= { - // auto issued - new ucmd_t("new", new Runnable() - { public void run() - { SV_New_f(); - } - }), new ucmd_t("configstrings", new Runnable() - { - public void run() - { - SV_Configstrings_f(); - } - }), new ucmd_t("baselines", new Runnable() - { - public void run() - { - SV_Baselines_f(); - } - }), new ucmd_t("begin", new Runnable() - { - public void run() - { - SV_Begin_f(); - } - }), new ucmd_t("nextserver", new Runnable() - { - public void run() - { - SV_Nextserver_f(); - } - }), new ucmd_t("disconnect", new Runnable() - { - public void run() - { - SV_Disconnect_f(); - } - }), - - // issued by hand at client consoles - new ucmd_t("info", new Runnable() - { - public void run() - { - SV_ShowServerinfo_f(); - } - }), new ucmd_t("download", new Runnable() - { - public void run() - { - SV_BeginDownload_f(); - } - }), new ucmd_t("nextdl", new Runnable() - { - public void run() - { - SV_NextDownload_f(); - } - }) - }; - - /* - ================== - SV_ExecuteUserCommand - ================== - */ - public static void SV_ExecuteUserCommand(String s) - { - ucmd_t u= null; - - Cmd.TokenizeString(s.toCharArray(), true); - sv_player= sv_client.edict; - - // SV_BeginRedirect (RD_CLIENT); - - int i= 0; - for (; i < ucmds.length; i++) - { - u= ucmds[i]; - if (0 == strcmp(Cmd.Argv(0), u.name)) - { - u.r.run(); - break; - } - } - - if (i == ucmds.length && sv.state == ss_game) - PlayerClient.ClientCommand(sv_player); - - // SV_EndRedirect (); - } - - /* - =========================================================================== - - USER CMD EXECUTION - - =========================================================================== - */ - - public static void SV_ClientThink(client_t cl, usercmd_t cmd) - { - cl.commandMsec -= cmd.msec & 0xFF; - - if (cl.commandMsec < 0 && sv_enforcetime.value != 0) - { - Com.DPrintf("commandMsec underflow from " + cl.name + "\n"); - return; - } - - PlayerClient.ClientThink(cl.edict, cmd); - } - - public static final int MAX_STRINGCMDS= 8; - /* - =================== - SV_ExecuteClientMessage - - The current net_message is parsed for the given client - =================== - */ - public static void SV_ExecuteClientMessage(client_t cl) - { - int c; - String s; - - usercmd_t nullcmd= new usercmd_t(); - usercmd_t oldest= new usercmd_t(), oldcmd= new usercmd_t(), newcmd= new usercmd_t(); - int net_drop; - int stringCmdCount; - int checksum, calculatedChecksum; - int checksumIndex; - boolean move_issued; - int lastframe; - - sv_client= cl; - sv_player= sv_client.edict; - - // only allow one move command - move_issued= false; - stringCmdCount= 0; - - while (true) - { - if (net_message.readcount > net_message.cursize) - { - Com.Printf("SV_ReadClientMessage: bad read:\n"); - Com.Printf(Lib.hexDump(net_message.data, 32, false)); - SV_DropClient(cl); - return; - } - - c= MSG.ReadByte(net_message); - if (c == -1) - break; - - switch (c) - { - default : - Com.Printf("SV_ReadClientMessage: unknown command char\n"); - SV_DropClient(cl); - return; - - case clc_nop : - break; - - case clc_userinfo : - cl.userinfo= MSG.ReadString(net_message); - SV_MAIN.SV_UserinfoChanged(cl); - break; - - case clc_move : - if (move_issued) - return; // someone is trying to cheat... - - move_issued= true; - checksumIndex= net_message.readcount; - checksum= MSG.ReadByte(net_message); - lastframe= MSG.ReadLong(net_message); - - if (lastframe != cl.lastframe) - { - cl.lastframe= lastframe; - if (cl.lastframe > 0) - { - cl.frame_latency[cl.lastframe & (LATENCY_COUNTS - 1)]= - svs.realtime - cl.frames[cl.lastframe & UPDATE_MASK].senttime; - } - } - - //memset (nullcmd, 0, sizeof(nullcmd)); - nullcmd= new usercmd_t(); - MSG.ReadDeltaUsercmd(net_message, nullcmd, oldest); - MSG.ReadDeltaUsercmd(net_message, oldest, oldcmd); - MSG.ReadDeltaUsercmd(net_message, oldcmd, newcmd); - - if (cl.state != cs_spawned) - { - cl.lastframe= -1; - break; - } - - // if the checksum fails, ignore the rest of the packet - - calculatedChecksum= - Com.BlockSequenceCRCByte( - net_message.data, checksumIndex + 1, - net_message.readcount - checksumIndex - 1, - cl.netchan.incoming_sequence); - - if ((calculatedChecksum &0xff) != checksum) - { - Com.DPrintf( - "Failed command checksum for " - + cl.name - + " (" - + calculatedChecksum - + " != " - + checksum - + ")/" - + cl.netchan.incoming_sequence - + "\n"); - return; - } - - if (0 == sv_paused.value) - { - net_drop= cl.netchan.dropped; - if (net_drop < 20) - { - - //if (net_drop > 2) - - // Com.Printf ("drop %i\n", net_drop); - while (net_drop > 2) - { - SV_ClientThink(cl, cl.lastcmd); - - net_drop--; - } - if (net_drop > 1) - SV_ClientThink(cl, oldest); - - if (net_drop > 0) - SV_ClientThink(cl, oldcmd); - - } - SV_ClientThink(cl, newcmd); - } - - // copy. - cl.lastcmd.set(newcmd); - break; - - case clc_stringcmd : - s= MSG.ReadString(net_message); - - // malicious users may try using too many string commands - if (++stringCmdCount < MAX_STRINGCMDS) - SV_ExecuteUserCommand(s); - - if (cl.state == cs_zombie) - return; // disconnect command - break; - } - } - } -} +public class SV_USER { + + static edict_t sv_player; + + public static class ucmd_t { + public ucmd_t(String n, Runnable r) { + name = n; + this.r = r; + } + + String name; + + Runnable r; + } + + static ucmd_t u1 = new ucmd_t("new", new Runnable() { + public void run() { + SV_USER.SV_New_f(); + } + }); + + static ucmd_t ucmds[] = { + // auto issued + new ucmd_t("new", new Runnable() { + public void run() { + SV_USER.SV_New_f(); + } + }), new ucmd_t("configstrings", new Runnable() { + public void run() { + SV_USER.SV_Configstrings_f(); + } + }), new ucmd_t("baselines", new Runnable() { + public void run() { + SV_USER.SV_Baselines_f(); + } + }), new ucmd_t("begin", new Runnable() { + public void run() { + SV_USER.SV_Begin_f(); + } + }), new ucmd_t("nextserver", new Runnable() { + public void run() { + SV_USER.SV_Nextserver_f(); + } + }), new ucmd_t("disconnect", new Runnable() { + public void run() { + SV_USER.SV_Disconnect_f(); + } + }), + + // issued by hand at client consoles + new ucmd_t("info", new Runnable() { + public void run() { + SV_USER.SV_ShowServerinfo_f(); + } + }), new ucmd_t("download", new Runnable() { + public void run() { + SV_USER.SV_BeginDownload_f(); + } + }), new ucmd_t("nextdl", new Runnable() { + public void run() { + SV_USER.SV_NextDownload_f(); + } + }) }; + + public static final int MAX_STRINGCMDS = 8; + + /* + * ============================================================ + * + * USER STRINGCMD EXECUTION + * + * sv_client and sv_player will be valid. + * ============================================================ + */ + + /* + * ================== SV_BeginDemoServer ================== + */ + public static void SV_BeginDemoserver() { + String name; + + name = "demos/" + SV_INIT.sv.name; + try { + SV_INIT.sv.demofile = FS.FOpenFile(name); + } catch (IOException e) { + Com.Error(Defines.ERR_DROP, "Couldn't open " + name + "\n"); + } + if (SV_INIT.sv.demofile == null) + Com.Error(Defines.ERR_DROP, "Couldn't open " + name + "\n"); + } + + /* + * ================ SV_New_f + * + * Sends the first message from the server to a connected client. This will + * be sent on the initial connection and upon each server load. + * ================ + */ + public static void SV_New_f() { + String gamedir; + int playernum; + edict_t ent; + + Com.DPrintf("New() from " + SV_MAIN.sv_client.name + "\n"); + + if (SV_MAIN.sv_client.state != Defines.cs_connected) { + Com.Printf("New not valid -- already spawned\n"); + return; + } + + // demo servers just dump the file message + if (SV_INIT.sv.state == Defines.ss_demo) { + SV_BeginDemoserver(); + return; + } + + // + // serverdata needs to go over for all types of servers + // to make sure the protocol is right, and to set the gamedir + // + gamedir = Cvar.VariableString("gamedir"); + + // send the serverdata + MSG + .WriteByte(SV_MAIN.sv_client.netchan.message, + Defines.svc_serverdata); + MSG.WriteInt(SV_MAIN.sv_client.netchan.message, + Defines.PROTOCOL_VERSION); + MSG + .WriteLong(SV_MAIN.sv_client.netchan.message, + SV_INIT.svs.spawncount); + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, + SV_INIT.sv.attractloop ? 1 : 0); + MSG.WriteString(SV_MAIN.sv_client.netchan.message, gamedir); + + if (SV_INIT.sv.state == Defines.ss_cinematic + || SV_INIT.sv.state == Defines.ss_pic) + playernum = -1; + else + //playernum = sv_client - svs.clients; + playernum = SV_MAIN.sv_client.serverindex; + + MSG.WriteShort(SV_MAIN.sv_client.netchan.message, playernum); + + // send full levelname + MSG.WriteString(SV_MAIN.sv_client.netchan.message, + SV_INIT.sv.configstrings[Defines.CS_NAME]); + + // + // game server + // + if (SV_INIT.sv.state == Defines.ss_game) { + // set up the entity for the client + ent = GameBase.g_edicts[playernum + 1]; + ent.s.number = playernum + 1; + SV_MAIN.sv_client.edict = ent; + SV_MAIN.sv_client.lastcmd = new usercmd_t(); + + // begin fetching configstrings + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, + Defines.svc_stufftext); + MSG.WriteString(SV_MAIN.sv_client.netchan.message, + "cmd configstrings " + SV_INIT.svs.spawncount + " 0\n"); + } + + } + + /* + * ================== SV_Configstrings_f ================== + */ + public static void SV_Configstrings_f() { + int start; + + Com.DPrintf("Configstrings() from " + SV_MAIN.sv_client.name + "\n"); + + if (SV_MAIN.sv_client.state != Defines.cs_connected) { + Com.Printf("configstrings not valid -- already spawned\n"); + return; + } + + // handle the case of a level changing while a client was connecting + if (Lib.atoi(Cmd.Argv(1)) != SV_INIT.svs.spawncount) { + Com.Printf("SV_Configstrings_f from different level\n"); + SV_New_f(); + return; + } + + start = Lib.atoi(Cmd.Argv(2)); + + // write a packet full of data + + while (SV_MAIN.sv_client.netchan.message.cursize < Defines.MAX_MSGLEN / 2 + && start < Defines.MAX_CONFIGSTRINGS) { + if (SV_INIT.sv.configstrings[start] != null + && SV_INIT.sv.configstrings[start].length() != 0) { + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, + Defines.svc_configstring); + MSG.WriteShort(SV_MAIN.sv_client.netchan.message, start); + MSG.WriteString(SV_MAIN.sv_client.netchan.message, + SV_INIT.sv.configstrings[start]); + } + start++; + } + + // send next command + + if (start == Defines.MAX_CONFIGSTRINGS) { + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, + Defines.svc_stufftext); + MSG.WriteString(SV_MAIN.sv_client.netchan.message, "cmd baselines " + + SV_INIT.svs.spawncount + " 0\n"); + } else { + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, + Defines.svc_stufftext); + MSG.WriteString(SV_MAIN.sv_client.netchan.message, + "cmd configstrings " + SV_INIT.svs.spawncount + " " + start + + "\n"); + } + } + + /* + * ================== SV_Baselines_f ================== + */ + public static void SV_Baselines_f() { + int start; + entity_state_t nullstate; + entity_state_t base; + + Com.DPrintf("Baselines() from " + SV_MAIN.sv_client.name + "\n"); + + if (SV_MAIN.sv_client.state != Defines.cs_connected) { + Com.Printf("baselines not valid -- already spawned\n"); + return; + } + + // handle the case of a level changing while a client was connecting + if (Lib.atoi(Cmd.Argv(1)) != SV_INIT.svs.spawncount) { + Com.Printf("SV_Baselines_f from different level\n"); + SV_New_f(); + return; + } + + start = Lib.atoi(Cmd.Argv(2)); + + //memset (&nullstate, 0, sizeof(nullstate)); + nullstate = new entity_state_t(null); + + // write a packet full of data + + while (SV_MAIN.sv_client.netchan.message.cursize < Defines.MAX_MSGLEN / 2 + && start < Defines.MAX_EDICTS) { + base = SV_INIT.sv.baselines[start]; + if (base.modelindex != 0 || base.sound != 0 || base.effects != 0) { + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, + Defines.svc_spawnbaseline); + MSG.WriteDeltaEntity(nullstate, base, + SV_MAIN.sv_client.netchan.message, true, true); + } + start++; + } + + // send next command + + if (start == Defines.MAX_EDICTS) { + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, + Defines.svc_stufftext); + MSG.WriteString(SV_MAIN.sv_client.netchan.message, "precache " + + SV_INIT.svs.spawncount + "\n"); + } else { + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, + Defines.svc_stufftext); + MSG.WriteString(SV_MAIN.sv_client.netchan.message, "cmd baselines " + + SV_INIT.svs.spawncount + " " + start + "\n"); + } + } + + /* + * ================== SV_Begin_f ================== + */ + public static void SV_Begin_f() { + Com.DPrintf("Begin() from " + SV_MAIN.sv_client.name + "\n"); + + // handle the case of a level changing while a client was connecting + if (Lib.atoi(Cmd.Argv(1)) != SV_INIT.svs.spawncount) { + Com.Printf("SV_Begin_f from different level\n"); + SV_New_f(); + return; + } + + SV_MAIN.sv_client.state = Defines.cs_spawned; + + // call the game begin function + PlayerClient.ClientBegin(SV_USER.sv_player); + + Cbuf.InsertFromDefer(); + } + + //============================================================================= + + /* + * ================== SV_NextDownload_f ================== + */ + public static void SV_NextDownload_f() { + int r; + int percent; + int size; + + if (SV_MAIN.sv_client.download == null) + return; + + r = SV_MAIN.sv_client.downloadsize - SV_MAIN.sv_client.downloadcount; + if (r > 1024) + r = 1024; + + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, Defines.svc_download); + MSG.WriteShort(SV_MAIN.sv_client.netchan.message, r); + + SV_MAIN.sv_client.downloadcount += r; + size = SV_MAIN.sv_client.downloadsize; + if (size == 0) + size = 1; + percent = SV_MAIN.sv_client.downloadcount * 100 / size; + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, percent); + SZ.Write(SV_MAIN.sv_client.netchan.message, SV_MAIN.sv_client.download, + SV_MAIN.sv_client.downloadcount - r, r); + + if (SV_MAIN.sv_client.downloadcount != SV_MAIN.sv_client.downloadsize) + return; + + FS.FreeFile(SV_MAIN.sv_client.download); + SV_MAIN.sv_client.download = null; + } + + /* + * ================== SV_BeginDownload_f ================== + */ + public static void SV_BeginDownload_f() { + String name; + int offset = 0; + + name = Cmd.Argv(1); + + if (Cmd.Argc() > 2) + offset = Lib.atoi(Cmd.Argv(2)); // downloaded offset + + // hacked by zoid to allow more conrol over download + // first off, no .. or global allow check + + if (name.indexOf("..") != -1 + || SV_MAIN.allow_download.value == 0 // leading dot is no good + || name.charAt(0) == '.' // leading slash bad as well, must be + // in subdir + || name.charAt(0) == '/' // next up, skin check + || (name.startsWith("players/") && 0 == SV_MAIN.allow_download_players.value) // now + // models + || (name.startsWith("models/") && 0 == SV_MAIN.allow_download_models.value) // now + // sounds + || (name.startsWith("sound/") && 0 == SV_MAIN.allow_download_sounds.value) + // now maps (note special case for maps, must not be in pak) + || (name.startsWith("maps/") && 0 == SV_MAIN.allow_download_maps.value) // MUST + // be + // in a + // subdirectory + || name.indexOf('/') == -1) { // don't allow anything with .. + // path + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, + Defines.svc_download); + MSG.WriteShort(SV_MAIN.sv_client.netchan.message, -1); + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, 0); + return; + } + + if (SV_MAIN.sv_client.download != null) + FS.FreeFile(SV_MAIN.sv_client.download); + + SV_MAIN.sv_client.download = FS.LoadFile(name); + SV_MAIN.sv_client.downloadsize = SV_MAIN.sv_client.download.length; + SV_MAIN.sv_client.downloadcount = offset; + + if (offset > SV_MAIN.sv_client.downloadsize) + SV_MAIN.sv_client.downloadcount = SV_MAIN.sv_client.downloadsize; + + if (SV_MAIN.sv_client.download == null // special check for maps, if it + // came from a pak file, don't + // allow + // download ZOID + || (name.startsWith("maps/") && FS.file_from_pak != 0)) { + Com.DPrintf("Couldn't download " + name + " to " + + SV_MAIN.sv_client.name + "\n"); + if (SV_MAIN.sv_client.download != null) { + FS.FreeFile(SV_MAIN.sv_client.download); + SV_MAIN.sv_client.download = null; + } + + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, + Defines.svc_download); + MSG.WriteShort(SV_MAIN.sv_client.netchan.message, -1); + MSG.WriteByte(SV_MAIN.sv_client.netchan.message, 0); + return; + } + + SV_NextDownload_f(); + Com.DPrintf("Downloading " + name + " to " + SV_MAIN.sv_client.name + + "\n"); + } + + //============================================================================ + + /* + * ================= SV_Disconnect_f + * + * The client is going to disconnect, so remove the connection immediately + * ================= + */ + public static void SV_Disconnect_f() { + // SV_EndRedirect (); + SV_MAIN.SV_DropClient(SV_MAIN.sv_client); + } + + /* + * ================== SV_ShowServerinfo_f + * + * Dumps the serverinfo info string ================== + */ + public static void SV_ShowServerinfo_f() { + Info.Print(Cvar.Serverinfo()); + } + + public static void SV_Nextserver() { + String v; + + //ZOID, ss_pic can be nextserver'd in coop mode + if (SV_INIT.sv.state == Defines.ss_game + || (SV_INIT.sv.state == Defines.ss_pic && 0 == Cvar + .VariableValue("coop"))) + return; // can't nextserver while playing a normal game + + SV_INIT.svs.spawncount++; // make sure another doesn't sneak in + v = Cvar.VariableString("nextserver"); + //if (!v[0]) + if (v.length() == 0) + Cbuf.AddText("killserver\n"); + else { + Cbuf.AddText(v); + Cbuf.AddText("\n"); + } + Cvar.Set("nextserver", ""); + } + + /* + * ================== SV_Nextserver_f + * + * A cinematic has completed or been aborted by a client, so move to the + * next server, ================== + */ + public static void SV_Nextserver_f() { + if (Lib.atoi(Cmd.Argv(1)) != SV_INIT.svs.spawncount) { + Com.DPrintf("Nextserver() from wrong level, from " + + SV_MAIN.sv_client.name + "\n"); + return; // leftover from last server + } + + Com.DPrintf("Nextserver() from " + SV_MAIN.sv_client.name + "\n"); + + SV_Nextserver(); + } + + /* + * ================== SV_ExecuteUserCommand ================== + */ + public static void SV_ExecuteUserCommand(String s) { + SV_USER.ucmd_t u = null; + + Cmd.TokenizeString(s.toCharArray(), true); + SV_USER.sv_player = SV_MAIN.sv_client.edict; + + // SV_BeginRedirect (RD_CLIENT); + + int i = 0; + for (; i < SV_USER.ucmds.length; i++) { + u = SV_USER.ucmds[i]; + if (0 == Lib.strcmp(Cmd.Argv(0), u.name)) { + u.r.run(); + break; + } + } + + if (i == SV_USER.ucmds.length && SV_INIT.sv.state == Defines.ss_game) + GameAI.ClientCommand(SV_USER.sv_player); + + // SV_EndRedirect (); + } + + /* + * =========================================================================== + * + * USER CMD EXECUTION + * + * =========================================================================== + */ + + public static void SV_ClientThink(client_t cl, usercmd_t cmd) { + cl.commandMsec -= cmd.msec & 0xFF; + + if (cl.commandMsec < 0 && SV_MAIN.sv_enforcetime.value != 0) { + Com.DPrintf("commandMsec underflow from " + cl.name + "\n"); + return; + } + + PlayerClient.ClientThink(cl.edict, cmd); + } + + /* + * =================== SV_ExecuteClientMessage + * + * The current net_message is parsed for the given client + * =================== + */ + public static void SV_ExecuteClientMessage(client_t cl) { + int c; + String s; + + usercmd_t nullcmd = new usercmd_t(); + usercmd_t oldest = new usercmd_t(), oldcmd = new usercmd_t(), newcmd = new usercmd_t(); + int net_drop; + int stringCmdCount; + int checksum, calculatedChecksum; + int checksumIndex; + boolean move_issued; + int lastframe; + + SV_MAIN.sv_client = cl; + SV_USER.sv_player = SV_MAIN.sv_client.edict; + + // only allow one move command + move_issued = false; + stringCmdCount = 0; + + while (true) { + if (Globals.net_message.readcount > Globals.net_message.cursize) { + Com.Printf("SV_ReadClientMessage: bad read:\n"); + Com.Printf(Lib.hexDump(Globals.net_message.data, 32, false)); + SV_MAIN.SV_DropClient(cl); + return; + } + + c = MSG.ReadByte(Globals.net_message); + if (c == -1) + break; + + switch (c) { + default: + Com.Printf("SV_ReadClientMessage: unknown command char\n"); + SV_MAIN.SV_DropClient(cl); + return; + + case Defines.clc_nop: + break; + + case Defines.clc_userinfo: + cl.userinfo = MSG.ReadString(Globals.net_message); + SV_MAIN.SV_UserinfoChanged(cl); + break; + + case Defines.clc_move: + if (move_issued) + return; // someone is trying to cheat... + + move_issued = true; + checksumIndex = Globals.net_message.readcount; + checksum = MSG.ReadByte(Globals.net_message); + lastframe = MSG.ReadLong(Globals.net_message); + + if (lastframe != cl.lastframe) { + cl.lastframe = lastframe; + if (cl.lastframe > 0) { + cl.frame_latency[cl.lastframe + & (Defines.LATENCY_COUNTS - 1)] = SV_INIT.svs.realtime + - cl.frames[cl.lastframe & Defines.UPDATE_MASK].senttime; + } + } + + //memset (nullcmd, 0, sizeof(nullcmd)); + nullcmd = new usercmd_t(); + MSG.ReadDeltaUsercmd(Globals.net_message, nullcmd, oldest); + MSG.ReadDeltaUsercmd(Globals.net_message, oldest, oldcmd); + MSG.ReadDeltaUsercmd(Globals.net_message, oldcmd, newcmd); + + if (cl.state != Defines.cs_spawned) { + cl.lastframe = -1; + break; + } + + // if the checksum fails, ignore the rest of the packet + + calculatedChecksum = Com.BlockSequenceCRCByte( + Globals.net_message.data, checksumIndex + 1, + Globals.net_message.readcount - checksumIndex - 1, + cl.netchan.incoming_sequence); + + if ((calculatedChecksum & 0xff) != checksum) { + Com.DPrintf("Failed command checksum for " + cl.name + " (" + + calculatedChecksum + " != " + checksum + ")/" + + cl.netchan.incoming_sequence + "\n"); + return; + } + + if (0 == SV_MAIN.sv_paused.value) { + net_drop = cl.netchan.dropped; + if (net_drop < 20) { + + //if (net_drop > 2) + + // Com.Printf ("drop %i\n", net_drop); + while (net_drop > 2) { + SV_ClientThink(cl, cl.lastcmd); + + net_drop--; + } + if (net_drop > 1) + SV_ClientThink(cl, oldest); + + if (net_drop > 0) + SV_ClientThink(cl, oldcmd); + + } + SV_ClientThink(cl, newcmd); + } + + // copy. + cl.lastcmd.set(newcmd); + break; + + case Defines.clc_stringcmd: + s = MSG.ReadString(Globals.net_message); + + // malicious users may try using too many string commands + if (++stringCmdCount < SV_USER.MAX_STRINGCMDS) + SV_ExecuteUserCommand(s); + + if (cl.state == Defines.cs_zombie) + return; // disconnect command + break; + } + } + } +} \ No newline at end of file diff --git a/src/jake2/server/SV_WORLD.java b/src/jake2/server/SV_WORLD.java index 46caf89..1d5fbb9 100644 --- a/src/jake2/server/SV_WORLD.java +++ b/src/jake2/server/SV_WORLD.java @@ -1,682 +1,528 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ // Created on 07.01.2000 by RST. -// $Id: SV_WORLD.java,v 1.6 2004-08-29 21:39:25 hzi Exp $ - +// $Id: SV_WORLD.java,v 1.7 2004-09-22 19:22:12 salomo Exp $ package jake2.server; -import jake2.game.*; +import jake2.Defines; +import jake2.Globals; +import jake2.game.GameBase; +import jake2.game.cmodel_t; +import jake2.game.edict_t; +import jake2.game.link_t; +import jake2.game.trace_t; import jake2.qcommon.CM; import jake2.qcommon.Com; - -public class SV_WORLD extends SV_CCMDS -{ - - // world.c -- world query functions - - // - // - //=============================================================================== - // - //ENTITY AREA CHECKING - // - //FIXME: this use of "area" is different from the bsp file use - //=============================================================================== - // - - public static void initNodes() - { - for (int n= 0; n < AREA_NODES; n++) - sv_areanodes[n]= new areanode_t(); - } - - public static areanode_t sv_areanodes[]= new areanode_t[AREA_NODES]; - - static { - initNodes(); - } - public static int sv_numareanodes; - - public static float area_mins[], area_maxs[]; - public static edict_t area_list[]; - public static int area_count, area_maxcount; - public static int area_type; - - // ClearLink is used for new headnodes - public static void ClearLink(link_t l) - { - l.prev= l.next= l; - } - - public static void RemoveLink(link_t l) - { - l.next.prev= l.prev; - l.prev.next= l.next; - } - - public static void InsertLinkBefore(link_t l, link_t before) - { - l.next= before; - l.prev= before.prev; - l.prev.next= l; - l.next.prev= l; - } - - /* - =============== - SV_CreateAreaNode - - Builds a uniformly subdivided tree for the given world size - =============== - */ - public static areanode_t SV_CreateAreaNode(int depth, float[] mins, float[] maxs) - { - areanode_t anode; - float[] size= { 0, 0, 0 }; - float[] mins1= { 0, 0, 0 }, maxs1= { 0, 0, 0 }, mins2= { 0, 0, 0 }, maxs2= { 0, 0, 0 }; - - anode= sv_areanodes[sv_numareanodes]; - - // just for debugging (rst) - VectorCopy(mins, anode.mins_rst); - VectorCopy(maxs, anode.maxs_rst); - - sv_numareanodes++; - - ClearLink(anode.trigger_edicts); - ClearLink(anode.solid_edicts); - - if (depth == AREA_DEPTH) - { - anode.axis= -1; - anode.children[0]= anode.children[1]= null; - return anode; - } - - VectorSubtract(maxs, mins, size); - if (size[0] > size[1]) - anode.axis= 0; - else - anode.axis= 1; - - anode.dist= 0.5f * (maxs[anode.axis] + mins[anode.axis]); - VectorCopy(mins, mins1); - VectorCopy(mins, mins2); - VectorCopy(maxs, maxs1); - VectorCopy(maxs, maxs2); - - maxs1[anode.axis]= mins2[anode.axis]= anode.dist; - - anode.children[0]= SV_CreateAreaNode(depth + 1, mins2, maxs2); - anode.children[1]= SV_CreateAreaNode(depth + 1, mins1, maxs1); - - return anode; - } - - /* - =============== - SV_ClearWorld - - =============== - */ - public static void SV_ClearWorld() - { - initNodes(); - sv_numareanodes= 0; - SV_CreateAreaNode(0, sv.models[1].mins, sv.models[1].maxs); - - /* - Com.p("areanodes:" + sv_numareanodes + " (sollten 32 sein)."); - for (int n = 0; n < sv_numareanodes; n++) { - Com.Printf( - "|%3i|%2i|%8.2f |%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n", - new Vargs() - .add(n) - .add(sv_areanodes[n].axis) - .add(sv_areanodes[n].dist) - .add(sv_areanodes[n].mins_rst[0]) - .add(sv_areanodes[n].mins_rst[1]) - .add(sv_areanodes[n].mins_rst[2]) - .add(sv_areanodes[n].maxs_rst[0]) - .add(sv_areanodes[n].maxs_rst[1]) - .add(sv_areanodes[n].maxs_rst[2])); - } - */ - } - /* - =============== - SV_UnlinkEdict - =============== - */ - public static void SV_UnlinkEdict(edict_t ent) - { - if (null == ent.area.prev) - return; // not linked in anywhere - - RemoveLink(ent.area); - ent.area.prev= ent.area.next= null; - } - - /* - =============== - SV_LinkEdict - =============== - */ - public static final int MAX_TOTAL_ENT_LEAFS= 128; - private static int leafs[]= new int[MAX_TOTAL_ENT_LEAFS]; - private static int clusters[]= new int[MAX_TOTAL_ENT_LEAFS]; - - public static void SV_LinkEdict(edict_t ent) - { - areanode_t node; - - int num_leafs; - int j, k; - int area; - int topnode= 0; - - if (ent.area.prev != null) - SV_UnlinkEdict(ent); // unlink from old position - - if (ent == GameBase.g_edicts[0]) - return; // don't add the world - - if (!ent.inuse) - return; - - // set the size - VectorSubtract(ent.maxs, ent.mins, ent.size); - - // encode the size into the entity_state for client prediction - if (ent.solid == SOLID_BBOX && 0 == (ent.svflags & SVF_DEADMONSTER)) - { - // assume that x/y are equal and symetric - int i= (int) (ent.maxs[0] / 8); - if (i < 1) - i= 1; - if (i > 31) - i= 31; - - // z is not symetric - j= (int) ((-ent.mins[2]) / 8); - if (j < 1) - j= 1; - if (j > 31) - j= 31; - - // and z maxs can be negative... - k= (int) ((ent.maxs[2] + 32) / 8); - if (k < 1) - k= 1; - if (k > 63) - k= 63; - - ent.s.solid= (k << 10) | (j << 5) | i; - } - else if (ent.solid == SOLID_BSP) - { - ent.s.solid= 31; // a solid_bbox will never create this value - } - else - ent.s.solid= 0; - - // set the abs box - if (ent.solid == SOLID_BSP && (ent.s.angles[0] != 0 || ent.s.angles[1] != 0 || ent.s.angles[2] != 0)) - { - // expand for rotation - float max, v; - - max= 0; - for (int i= 0; i < 3; i++) - { - v= Math.abs(ent.mins[i]); - if (v > max) - max= v; - v= Math.abs(ent.maxs[i]); - if (v > max) - max= v; - } - for (int i= 0; i < 3; i++) - { - ent.absmin[i]= ent.s.origin[i] - max; - ent.absmax[i]= ent.s.origin[i] + max; - } - } - else - { - // normal - VectorAdd(ent.s.origin, ent.mins, ent.absmin); - VectorAdd(ent.s.origin, ent.maxs, ent.absmax); - } - - // because movement is clipped an epsilon away from an actual edge, - // we must fully check even when bounding boxes don't quite touch - - ent.absmin[0]--; - ent.absmin[1]--; - ent.absmin[2]--; - ent.absmax[0]++; - ent.absmax[1]++; - ent.absmax[2]++; - - // link to PVS leafs - ent.num_clusters= 0; - ent.areanum= 0; - ent.areanum2= 0; - - // get all leafs, including solids - - int iw[] = {topnode}; - - num_leafs= CM.CM_BoxLeafnums(ent.absmin, ent.absmax, leafs, MAX_TOTAL_ENT_LEAFS, iw); - - topnode= iw[0]; - - // set areas - for (int i= 0; i < num_leafs; i++) - { - clusters[i]= CM.CM_LeafCluster(leafs[i]); - area= CM.CM_LeafArea(leafs[i]); - if (area != 0) - { - // doors may legally straggle two areas, - // but nothing should evern need more than that - if (ent.areanum != 0 && ent.areanum != area) - { - if (ent.areanum2 != 0 && ent.areanum2 != area && sv.state == ss_loading) - Com.DPrintf("Object touching 3 areas at " + ent.absmin[0] + " " + ent.absmin[1] + " " + ent.absmin[2] + "\n"); - ent.areanum2= area; - } - else - ent.areanum= area; - } - } - - if (num_leafs >= MAX_TOTAL_ENT_LEAFS) - { - // assume we missed some leafs, and mark by headnode - ent.num_clusters= -1; - ent.headnode= topnode; - } - else - { - ent.num_clusters= 0; - for (int i= 0; i < num_leafs; i++) - { - if (clusters[i] == -1) - continue; // not a visible leaf - for (j= 0; j < i; j++) - if (clusters[j] == clusters[i]) - break; - if (j == i) - { - if (ent.num_clusters == MAX_ENT_CLUSTERS) - { - // assume we missed some leafs, and mark by headnode - ent.num_clusters= -1; - ent.headnode= topnode; - break; - } - - ent.clusternums[ent.num_clusters++]= clusters[i]; - } - } - } - - // if first time, make sure old_origin is valid - if (0 == ent.linkcount) - { - VectorCopy(ent.s.origin, ent.s.old_origin); - } - ent.linkcount++; - - if (ent.solid == SOLID_NOT) - return; - - // find the first node that the ent's box crosses - node= sv_areanodes[0]; - - while (true) - { - if (node.axis == -1) - break; - if (ent.absmin[node.axis] > node.dist) - node= node.children[0]; - else if (ent.absmax[node.axis] < node.dist) - node= node.children[1]; - else - break; // crosses the node - } - - // link it in - if (ent.solid == SOLID_TRIGGER) - InsertLinkBefore(ent.area, node.trigger_edicts); - else - InsertLinkBefore(ent.area, node.solid_edicts); - - } - - /* - ==================== - SV_AreaEdicts_r - - ==================== - */ - public static void SV_AreaEdicts_r(areanode_t node) - { - link_t l, next, start; - edict_t check; - int count; - - count= 0; - - // touch linked edicts - if (area_type == AREA_SOLID) - start= node.solid_edicts; - else - start= node.trigger_edicts; - - for (l= start.next; l != start; l= next) - { - next= l.next; - check= (edict_t) l.o; - - if (check.solid == SOLID_NOT) - continue; // deactivated - if (check.absmin[0] > area_maxs[0] - || check.absmin[1] > area_maxs[1] - || check.absmin[2] > area_maxs[2] - || check.absmax[0] < area_mins[0] - || check.absmax[1] < area_mins[1] - || check.absmax[2] < area_mins[2]) - continue; // not touching - - if (area_count == area_maxcount) - { - Com.Printf("SV_AreaEdicts: MAXCOUNT\n"); - return; - } - - area_list[area_count]= check; - area_count++; - } - - if (node.axis == -1) - return; // terminal node - - // recurse down both sides - if (area_maxs[node.axis] > node.dist) - SV_AreaEdicts_r(node.children[0]); - - if (area_mins[node.axis] < node.dist) - SV_AreaEdicts_r(node.children[1]); - } - - /* - ================ - SV_AreaEdicts - ================ - */ - public static int SV_AreaEdicts(float[] mins, float[] maxs, edict_t list[], int maxcount, int areatype) - { - area_mins= mins; - area_maxs= maxs; - area_list= list; - area_count= 0; - area_maxcount= maxcount; - area_type= areatype; - - SV_AreaEdicts_r(sv_areanodes[0]); - - return area_count; - } - - //=========================================================================== - - private static edict_t touch[]= new edict_t[MAX_EDICTS]; - /* - ============= - SV_PointContents - ============= - */ - - public static int SV_PointContents(float[] p) - { - edict_t hit; - - int i, num; - int contents, c2; - int headnode; - float angles[]; - - // get base contents from world - contents= CM.PointContents(p, sv.models[1].headnode); - - // or in contents from all the other entities - num= SV_AreaEdicts(p, p, touch, MAX_EDICTS, AREA_SOLID); - - for (i= 0; i < num; i++) - { - hit= touch[i]; - - // might intersect, so do an exact clip - headnode= SV_HullForEntity(hit); - angles= hit.s.angles; - if (hit.solid != SOLID_BSP) - angles= vec3_origin; // boxes don't rotate - - c2= CM.TransformedPointContents(p, headnode, hit.s.origin, hit.s.angles); - - contents |= c2; - } - - return contents; - } - - /* - ================ - SV_HullForEntity - - Returns a headnode that can be used for testing or clipping an - object of mins/maxs size. - Offset is filled in to contain the adjustment that must be added to the - testing object's origin to get a point to use with the returned hull. - ================ - */ - public static int SV_HullForEntity(edict_t ent) - { - - cmodel_t model; - - // decide which clipping hull to use, based on the size - if (ent.solid == SOLID_BSP) - { // explicit hulls in the BSP model - model= sv.models[ent.s.modelindex]; - - if (null == model) - Com.Error(ERR_FATAL, "MOVETYPE_PUSH with a non bsp model"); - - return model.headnode; - } - - // create a temp hull from bounding box sizes - - return CM.HeadnodeForBox(ent.mins, ent.maxs); - } - - //=========================================================================== - - /* - ==================== - SV_ClipMoveToEntities - - ==================== - */ - private static edict_t touchlist[]= new edict_t[MAX_EDICTS]; - public static void SV_ClipMoveToEntities(moveclip_t clip) - { - int i, num; - - edict_t touch; - trace_t trace; - int headnode; - float angles[]; - - num= SV_AreaEdicts(clip.boxmins, clip.boxmaxs, touchlist, 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++) - { - touch= touchlist[i]; - if (touch.solid == SOLID_NOT) - continue; - if (touch == clip.passedict) - continue; - if (clip.trace.allsolid) - return; - if (clip.passedict != null) - { - if (touch.owner == clip.passedict) - continue; // don't clip against own missiles - if (clip.passedict.owner == touch) - continue; // don't clip against owner - } - - if (0 == (clip.contentmask & CONTENTS_DEADMONSTER) && 0 != (touch.svflags & SVF_DEADMONSTER)) - continue; - - // might intersect, so do an exact clip - headnode= SV_HullForEntity(touch); - angles= touch.s.angles; - if (touch.solid != SOLID_BSP) - angles= vec3_origin; // boxes don't rotate - - if ((touch.svflags & SVF_MONSTER) != 0) - trace= - CM.TransformedBoxTrace( - clip.start, - clip.end, - clip.mins2, - clip.maxs2, - headnode, - clip.contentmask, - touch.s.origin, - angles); - else - trace= - CM.TransformedBoxTrace( - clip.start, - clip.end, - clip.mins, - clip.maxs, - headnode, - clip.contentmask, - touch.s.origin, - angles); - - if (trace.allsolid || trace.startsolid || trace.fraction < clip.trace.fraction) - { - trace.ent= touch; - if (clip.trace.startsolid) - { - clip.trace= trace; - clip.trace.startsolid= true; - } - else - clip.trace.set(trace); - } - else if (trace.startsolid) - clip.trace.startsolid= true; - } - } - - /* - ================== - SV_TraceBounds - ================== - */ - public static void SV_TraceBounds(float[] start, float[] mins, float[] maxs, float[] end, float[] boxmins, float[] boxmaxs) - { - int i; - - for (i= 0; i < 3; i++) - { - if (end[i] > start[i]) - { - boxmins[i]= start[i] + mins[i] - 1; - boxmaxs[i]= end[i] + maxs[i] + 1; - } - else - { - boxmins[i]= end[i] + mins[i] - 1; - boxmaxs[i]= start[i] + maxs[i] + 1; - } - } - - } - - /* - ================== - SV_Trace - - Moves the given mins/maxs volume through the world from start to end. - - Passedict and edicts owned by passedict are explicitly not checked. - - ================== - */ - public static trace_t SV_Trace(float[] start, float[] mins, float[] maxs, float[] end, edict_t passedict, int contentmask) - { - moveclip_t clip= new moveclip_t(); - - if (mins == null) - mins= vec3_origin; - if (maxs == null) - maxs= vec3_origin; - - //memset ( clip, 0, sizeof ( moveclip_t ) ); - - // clip to world - clip.trace= CM.BoxTrace(start, end, mins, maxs, 0, contentmask); - clip.trace.ent= GameBase.g_edicts[0]; - if (clip.trace.fraction == 0) - return clip.trace; // blocked by the world - - clip.contentmask= contentmask; - clip.start= start; - clip.end= end; - clip.mins= mins; - clip.maxs= maxs; - clip.passedict= passedict; - - VectorCopy(mins, clip.mins2); - VectorCopy(maxs, clip.maxs2); - - // create the bounding box of the entire move - SV_TraceBounds(start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs); - - // clip to other solid entities - SV_ClipMoveToEntities(clip); - - return clip.trace; - } -} +import jake2.util.Math3D; + +public class SV_WORLD { + // world.c -- world query functions + // + // + //=============================================================================== + // + //ENTITY AREA CHECKING + // + //FIXME: this use of "area" is different from the bsp file use + //=============================================================================== + public static areanode_t sv_areanodes[] = new areanode_t[Defines.AREA_NODES]; + static { + SV_WORLD.initNodes(); + } + + public static int sv_numareanodes; + + public static float area_mins[], area_maxs[]; + + public static edict_t area_list[]; + + public static int area_count, area_maxcount; + + public static int area_type; + + public static final int MAX_TOTAL_ENT_LEAFS = 128; + + static int leafs[] = new int[MAX_TOTAL_ENT_LEAFS]; + + static int clusters[] = new int[MAX_TOTAL_ENT_LEAFS]; + + //=========================================================================== + static edict_t touch[] = new edict_t[Defines.MAX_EDICTS]; + + //=========================================================================== + static edict_t touchlist[] = new edict_t[Defines.MAX_EDICTS]; + + public static void initNodes() { + for (int n = 0; n < Defines.AREA_NODES; n++) + SV_WORLD.sv_areanodes[n] = new areanode_t(); + } + + // ClearLink is used for new headnodes + public static void ClearLink(link_t l) { + l.prev = l.next = l; + } + + public static void RemoveLink(link_t l) { + l.next.prev = l.prev; + l.prev.next = l.next; + } + + public static void InsertLinkBefore(link_t l, link_t before) { + l.next = before; + l.prev = before.prev; + l.prev.next = l; + l.next.prev = l; + } + + /* + * =============== SV_CreateAreaNode + * + * Builds a uniformly subdivided tree for the given world size + * =============== + */ + public static areanode_t SV_CreateAreaNode(int depth, float[] mins, + float[] maxs) { + areanode_t anode; + float[] size = { 0, 0, 0 }; + float[] mins1 = { 0, 0, 0 }, maxs1 = { 0, 0, 0 }, mins2 = { 0, 0, 0 }, maxs2 = { + 0, 0, 0 }; + anode = SV_WORLD.sv_areanodes[SV_WORLD.sv_numareanodes]; + // just for debugging (rst) + Math3D.VectorCopy(mins, anode.mins_rst); + Math3D.VectorCopy(maxs, anode.maxs_rst); + SV_WORLD.sv_numareanodes++; + ClearLink(anode.trigger_edicts); + ClearLink(anode.solid_edicts); + if (depth == Defines.AREA_DEPTH) { + anode.axis = -1; + anode.children[0] = anode.children[1] = null; + return anode; + } + Math3D.VectorSubtract(maxs, mins, size); + if (size[0] > size[1]) + anode.axis = 0; + else + anode.axis = 1; + anode.dist = 0.5f * (maxs[anode.axis] + mins[anode.axis]); + Math3D.VectorCopy(mins, mins1); + Math3D.VectorCopy(mins, mins2); + Math3D.VectorCopy(maxs, maxs1); + Math3D.VectorCopy(maxs, maxs2); + maxs1[anode.axis] = mins2[anode.axis] = anode.dist; + anode.children[0] = SV_CreateAreaNode(depth + 1, mins2, maxs2); + anode.children[1] = SV_CreateAreaNode(depth + 1, mins1, maxs1); + return anode; + } + + /* + * =============== SV_ClearWorld + * + * =============== + */ + public static void SV_ClearWorld() { + initNodes(); + SV_WORLD.sv_numareanodes = 0; + SV_CreateAreaNode(0, SV_INIT.sv.models[1].mins, + SV_INIT.sv.models[1].maxs); + /* + * Com.p("areanodes:" + sv_numareanodes + " (sollten 32 sein)."); for + * (int n = 0; n < sv_numareanodes; n++) { Com.Printf( "|%3i|%2i|%8.2f + * |%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n", new Vargs() .add(n) + * .add(sv_areanodes[n].axis) .add(sv_areanodes[n].dist) + * .add(sv_areanodes[n].mins_rst[0]) .add(sv_areanodes[n].mins_rst[1]) + * .add(sv_areanodes[n].mins_rst[2]) .add(sv_areanodes[n].maxs_rst[0]) + * .add(sv_areanodes[n].maxs_rst[1]) .add(sv_areanodes[n].maxs_rst[2])); } + */ + } + + /* + * =============== SV_UnlinkEdict =============== + */ + public static void SV_UnlinkEdict(edict_t ent) { + if (null == ent.area.prev) + return; // not linked in anywhere + RemoveLink(ent.area); + ent.area.prev = ent.area.next = null; + } + + public static void SV_LinkEdict(edict_t ent) { + areanode_t node; + int num_leafs; + int j, k; + int area; + int topnode = 0; + if (ent.area.prev != null) + SV_UnlinkEdict(ent); // unlink from old position + if (ent == GameBase.g_edicts[0]) + return; // don't add the world + if (!ent.inuse) + return; + // set the size + Math3D.VectorSubtract(ent.maxs, ent.mins, ent.size); + // encode the size into the entity_state for client prediction + if (ent.solid == Defines.SOLID_BBOX + && 0 == (ent.svflags & Defines.SVF_DEADMONSTER)) { + // assume that x/y are equal and symetric + int i = (int) (ent.maxs[0] / 8); + if (i < 1) + i = 1; + if (i > 31) + i = 31; + // z is not symetric + j = (int) ((-ent.mins[2]) / 8); + if (j < 1) + j = 1; + if (j > 31) + j = 31; + // and z maxs can be negative... + k = (int) ((ent.maxs[2] + 32) / 8); + if (k < 1) + k = 1; + if (k > 63) + k = 63; + ent.s.solid = (k << 10) | (j << 5) | i; + } else if (ent.solid == Defines.SOLID_BSP) { + ent.s.solid = 31; // a solid_bbox will never create this value + } else + ent.s.solid = 0; + // set the abs box + if (ent.solid == Defines.SOLID_BSP + && (ent.s.angles[0] != 0 || ent.s.angles[1] != 0 || ent.s.angles[2] != 0)) { + // expand for rotation + float max, v; + max = 0; + for (int i = 0; i < 3; i++) { + v = Math.abs(ent.mins[i]); + if (v > max) + max = v; + v = Math.abs(ent.maxs[i]); + if (v > max) + max = v; + } + for (int i = 0; i < 3; i++) { + ent.absmin[i] = ent.s.origin[i] - max; + ent.absmax[i] = ent.s.origin[i] + max; + } + } else { + // normal + Math3D.VectorAdd(ent.s.origin, ent.mins, ent.absmin); + Math3D.VectorAdd(ent.s.origin, ent.maxs, ent.absmax); + } + // because movement is clipped an epsilon away from an actual edge, + // we must fully check even when bounding boxes don't quite touch + ent.absmin[0]--; + ent.absmin[1]--; + ent.absmin[2]--; + ent.absmax[0]++; + ent.absmax[1]++; + ent.absmax[2]++; + // link to PVS leafs + ent.num_clusters = 0; + ent.areanum = 0; + ent.areanum2 = 0; + // get all leafs, including solids + int iw[] = { topnode }; + num_leafs = CM.CM_BoxLeafnums(ent.absmin, ent.absmax, SV_WORLD.leafs, + SV_WORLD.MAX_TOTAL_ENT_LEAFS, iw); + topnode = iw[0]; + // set areas + for (int i = 0; i < num_leafs; i++) { + SV_WORLD.clusters[i] = CM.CM_LeafCluster(SV_WORLD.leafs[i]); + area = CM.CM_LeafArea(SV_WORLD.leafs[i]); + if (area != 0) { + // doors may legally straggle two areas, + // but nothing should evern need more than that + if (ent.areanum != 0 && ent.areanum != area) { + if (ent.areanum2 != 0 && ent.areanum2 != area + && SV_INIT.sv.state == Defines.ss_loading) + Com.DPrintf("Object touching 3 areas at " + + ent.absmin[0] + " " + ent.absmin[1] + " " + + ent.absmin[2] + "\n"); + ent.areanum2 = area; + } else + ent.areanum = area; + } + } + if (num_leafs >= SV_WORLD.MAX_TOTAL_ENT_LEAFS) { + // assume we missed some leafs, and mark by headnode + ent.num_clusters = -1; + ent.headnode = topnode; + } else { + ent.num_clusters = 0; + for (int i = 0; i < num_leafs; i++) { + if (SV_WORLD.clusters[i] == -1) + continue; // not a visible leaf + for (j = 0; j < i; j++) + if (SV_WORLD.clusters[j] == SV_WORLD.clusters[i]) + break; + if (j == i) { + if (ent.num_clusters == Defines.MAX_ENT_CLUSTERS) { + // assume we missed some leafs, and mark by headnode + ent.num_clusters = -1; + ent.headnode = topnode; + break; + } + ent.clusternums[ent.num_clusters++] = SV_WORLD.clusters[i]; + } + } + } + // if first time, make sure old_origin is valid + if (0 == ent.linkcount) { + Math3D.VectorCopy(ent.s.origin, ent.s.old_origin); + } + ent.linkcount++; + if (ent.solid == Defines.SOLID_NOT) + return; + // find the first node that the ent's box crosses + node = SV_WORLD.sv_areanodes[0]; + while (true) { + if (node.axis == -1) + break; + if (ent.absmin[node.axis] > node.dist) + node = node.children[0]; + else if (ent.absmax[node.axis] < node.dist) + node = node.children[1]; + else + break; // crosses the node + } + // link it in + if (ent.solid == Defines.SOLID_TRIGGER) + InsertLinkBefore(ent.area, node.trigger_edicts); + else + InsertLinkBefore(ent.area, node.solid_edicts); + } + + /* + * ==================== SV_AreaEdicts_r + * + * ==================== + */ + public static void SV_AreaEdicts_r(areanode_t node) { + link_t l, next, start; + edict_t check; + int count; + count = 0; + // touch linked edicts + if (SV_WORLD.area_type == Defines.AREA_SOLID) + start = node.solid_edicts; + else + start = node.trigger_edicts; + for (l = start.next; l != start; l = next) { + next = l.next; + check = (edict_t) l.o; + if (check.solid == Defines.SOLID_NOT) + continue; // deactivated + if (check.absmin[0] > SV_WORLD.area_maxs[0] + || check.absmin[1] > SV_WORLD.area_maxs[1] + || check.absmin[2] > SV_WORLD.area_maxs[2] + || check.absmax[0] < SV_WORLD.area_mins[0] + || check.absmax[1] < SV_WORLD.area_mins[1] + || check.absmax[2] < SV_WORLD.area_mins[2]) + continue; // not touching + if (SV_WORLD.area_count == SV_WORLD.area_maxcount) { + Com.Printf("SV_AreaEdicts: MAXCOUNT\n"); + return; + } + SV_WORLD.area_list[SV_WORLD.area_count] = check; + SV_WORLD.area_count++; + } + if (node.axis == -1) + return; // terminal node + // recurse down both sides + if (SV_WORLD.area_maxs[node.axis] > node.dist) + SV_AreaEdicts_r(node.children[0]); + if (SV_WORLD.area_mins[node.axis] < node.dist) + SV_AreaEdicts_r(node.children[1]); + } + + /* + * ================ SV_AreaEdicts ================ + */ + public static int SV_AreaEdicts(float[] mins, float[] maxs, edict_t list[], + int maxcount, int areatype) { + SV_WORLD.area_mins = mins; + SV_WORLD.area_maxs = maxs; + SV_WORLD.area_list = list; + SV_WORLD.area_count = 0; + SV_WORLD.area_maxcount = maxcount; + SV_WORLD.area_type = areatype; + SV_AreaEdicts_r(SV_WORLD.sv_areanodes[0]); + return SV_WORLD.area_count; + } + + /* + * ============= SV_PointContents ============= + */ + public static int SV_PointContents(float[] p) { + edict_t hit; + int i, num; + int contents, c2; + int headnode; + float angles[]; + // get base contents from world + contents = CM.PointContents(p, SV_INIT.sv.models[1].headnode); + // or in contents from all the other entities + num = SV_AreaEdicts(p, p, SV_WORLD.touch, Defines.MAX_EDICTS, + Defines.AREA_SOLID); + for (i = 0; i < num; i++) { + hit = SV_WORLD.touch[i]; + // might intersect, so do an exact clip + headnode = SV_HullForEntity(hit); + angles = hit.s.angles; + if (hit.solid != Defines.SOLID_BSP) + angles = Globals.vec3_origin; // boxes don't rotate + c2 = CM.TransformedPointContents(p, headnode, hit.s.origin, + hit.s.angles); + contents |= c2; + } + return contents; + } + + /* + * ================ SV_HullForEntity + * + * Returns a headnode that can be used for testing or clipping an object of + * mins/maxs size. Offset is filled in to contain the adjustment that must + * be added to the testing object's origin to get a point to use with the + * returned hull. ================ + */ + public static int SV_HullForEntity(edict_t ent) { + cmodel_t model; + // decide which clipping hull to use, based on the size + if (ent.solid == Defines.SOLID_BSP) { + // explicit hulls in the BSP model + model = SV_INIT.sv.models[ent.s.modelindex]; + if (null == model) + Com.Error(Defines.ERR_FATAL, + "MOVETYPE_PUSH with a non bsp model"); + return model.headnode; + } + // create a temp hull from bounding box sizes + return CM.HeadnodeForBox(ent.mins, ent.maxs); + } + + public static void SV_ClipMoveToEntities(moveclip_t clip) { + int i, num; + edict_t touch; + trace_t trace; + int headnode; + float angles[]; + num = SV_AreaEdicts(clip.boxmins, clip.boxmaxs, SV_WORLD.touchlist, + Defines.MAX_EDICTS, Defines.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++) { + touch = SV_WORLD.touchlist[i]; + if (touch.solid == Defines.SOLID_NOT) + continue; + if (touch == clip.passedict) + continue; + if (clip.trace.allsolid) + return; + if (clip.passedict != null) { + if (touch.owner == clip.passedict) + continue; // don't clip against own missiles + if (clip.passedict.owner == touch) + continue; // don't clip against owner + } + if (0 == (clip.contentmask & Defines.CONTENTS_DEADMONSTER) + && 0 != (touch.svflags & Defines.SVF_DEADMONSTER)) + continue; + // might intersect, so do an exact clip + headnode = SV_HullForEntity(touch); + angles = touch.s.angles; + if (touch.solid != Defines.SOLID_BSP) + angles = Globals.vec3_origin; // boxes don't rotate + if ((touch.svflags & Defines.SVF_MONSTER) != 0) + trace = CM.TransformedBoxTrace(clip.start, clip.end, + clip.mins2, clip.maxs2, headnode, clip.contentmask, + touch.s.origin, angles); + else + trace = CM.TransformedBoxTrace(clip.start, clip.end, clip.mins, + clip.maxs, headnode, clip.contentmask, touch.s.origin, + angles); + if (trace.allsolid || trace.startsolid + || trace.fraction < clip.trace.fraction) { + trace.ent = touch; + if (clip.trace.startsolid) { + clip.trace = trace; + clip.trace.startsolid = true; + } else + clip.trace.set(trace); + } else if (trace.startsolid) + clip.trace.startsolid = true; + } + } + + /* + * ================== SV_TraceBounds ================== + */ + public static void SV_TraceBounds(float[] start, float[] mins, + float[] maxs, float[] end, float[] boxmins, float[] boxmaxs) { + int i; + for (i = 0; i < 3; i++) { + if (end[i] > start[i]) { + boxmins[i] = start[i] + mins[i] - 1; + boxmaxs[i] = end[i] + maxs[i] + 1; + } else { + boxmins[i] = end[i] + mins[i] - 1; + boxmaxs[i] = start[i] + maxs[i] + 1; + } + } + } + + /* + * ================== SV_Trace + * + * Moves the given mins/maxs volume through the world from start to end. + * + * Passedict and edicts owned by passedict are explicitly not checked. + * + * ================== + */ + public static trace_t SV_Trace(float[] start, float[] mins, float[] maxs, + float[] end, edict_t passedict, int contentmask) { + moveclip_t clip = new moveclip_t(); + if (mins == null) + mins = Globals.vec3_origin; + if (maxs == null) + maxs = Globals.vec3_origin; + + // clip to world + clip.trace = CM.BoxTrace(start, end, mins, maxs, 0, contentmask); + clip.trace.ent = GameBase.g_edicts[0]; + if (clip.trace.fraction == 0) + return clip.trace; // blocked by the world + clip.contentmask = contentmask; + clip.start = start; + clip.end = end; + clip.mins = mins; + clip.maxs = maxs; + clip.passedict = passedict; + Math3D.VectorCopy(mins, clip.mins2); + Math3D.VectorCopy(maxs, clip.maxs2); + // create the bounding box of the entire move + SV_TraceBounds(start, clip.mins2, clip.maxs2, end, clip.boxmins, + clip.boxmaxs); + // clip to other solid entities + SV_ClipMoveToEntities(clip); + return clip.trace; + } +} \ No newline at end of file diff --git a/src/jake2/server/server_static_t.java b/src/jake2/server/server_static_t.java index c9f94a2..fffc9e9 100644 --- a/src/jake2/server/server_static_t.java +++ b/src/jake2/server/server_static_t.java @@ -1,65 +1,71 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 14.01.2004 by RST. +// $Id: server_static_t.java,v 1.2 2004-09-22 19:22:12 salomo Exp $ +package jake2.server; -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. +import jake2.Defines; +import jake2.game.entity_state_t; +import jake2.qcommon.sizebuf_t; -See the GNU General Public License for more details. +import java.io.RandomAccessFile; -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. +public class server_static_t { + public server_static_t() { + for (int n = 0; n < Defines.MAX_CHALLENGES; n++) { + challenges[n] = new challenge_t(); + } + } -*/ + boolean initialized; // sv_init has completed -// Created on 14.01.2004 by RST. -// $Id: server_static_t.java,v 1.1 2004-07-07 19:59:51 hzi Exp $ + int realtime; // always increasing, no clamping, etc -package jake2.server; + String mapcmd = ""; // ie: *intro.cin+base -import jake2.*; -import jake2.client.*; -import jake2.game.*; -import jake2.qcommon.*; -import jake2.render.*; -import jake2.server.*; + int spawncount; // incremented each server start -import java.io.*; + // used to check late spawns -public class server_static_t { - public server_static_t() { - for (int n = 0; n < Defines.MAX_CHALLENGES; n++) { - challenges[n] = new challenge_t(); - } - } + client_t clients[]; // [maxclients->value]; - boolean initialized; // sv_init has completed - int realtime; // always increasing, no clamping, etc + int num_client_entities; // maxclients->value*UPDATE_BACKUP*MAX_PACKET_ENTITIES - //char mapcmd[MAX_TOKEN_CHARS]; // ie: *intro.cin+base - String mapcmd = ""; // ie: *intro.cin+base + int next_client_entities; // next client_entity to use - int spawncount; // incremented each server start - // used to check late spawns + entity_state_t client_entities[]; // [num_client_entities] - client_t clients[]; // [maxclients->value]; + int last_heartbeat; - int num_client_entities; // maxclients->value*UPDATE_BACKUP*MAX_PACKET_ENTITIES - int next_client_entities; // next client_entity to use - entity_state_t client_entities[]; // [num_client_entities] + challenge_t challenges[] = new challenge_t[Defines.MAX_CHALLENGES]; // to + // prevent + // invalid + // IPs + // from + // connecting - int last_heartbeat; + // serverrecord values + RandomAccessFile demofile; - challenge_t challenges[] = new challenge_t[Defines.MAX_CHALLENGES]; // to prevent invalid IPs from connecting + sizebuf_t demo_multicast = new sizebuf_t(); - // serverrecord values - RandomAccessFile demofile; - sizebuf_t demo_multicast = new sizebuf_t(); - byte demo_multicast_buf[] = new byte[Defines.MAX_MSGLEN]; -} + byte demo_multicast_buf[] = new byte[Defines.MAX_MSGLEN]; +} \ No newline at end of file diff --git a/src/jake2/server/server_t.java b/src/jake2/server/server_t.java index 8e260a2..d67e384 100644 --- a/src/jake2/server/server_t.java +++ b/src/jake2/server/server_t.java @@ -1,76 +1,72 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + * 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. + * + */ -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. +// Created on 14.01.2004 by RST. +// $Id: server_t.java,v 1.2 2004-09-22 19:22:12 salomo Exp $ +package jake2.server; -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. +import jake2.Defines; +import jake2.game.cmodel_t; +import jake2.game.entity_state_t; +import jake2.qcommon.sizebuf_t; -See the GNU General Public License for more details. +import java.io.RandomAccessFile; -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. +public class server_t { -*/ + public server_t() { + models = new cmodel_t[Defines.MAX_MODELS]; + for (int n = 0; n < Defines.MAX_MODELS; n++) + models[n] = new cmodel_t(); -// Created on 14.01.2004 by RST. -// $Id: server_t.java,v 1.1 2004-07-07 19:59:51 hzi Exp $ + for (int n = 0; n < Defines.MAX_EDICTS; n++) + baselines[n] = new entity_state_t(null); + } -package jake2.server; + int state; // precache commands are only valid during load -import java.io.File; -import java.io.RandomAccessFile; + boolean attractloop; // running cinematics and demos for the local system + // only -import jake2.*; -import jake2.client.*; -import jake2.game.*; -import jake2.qcommon.*; -import jake2.render.*; + boolean loadgame; // client begins should reuse existing entity -public class server_t { + int time; // always sv.framenum * 100 msec + + int framenum; + + String name = ""; // map name, or cinematic name + + cmodel_t models[]; + + String configstrings[] = new String[Defines.MAX_CONFIGSTRINGS]; + + entity_state_t baselines[] = new entity_state_t[Defines.MAX_EDICTS]; + + // the multicast buffer is used to send a message to a set of clients + // it is only used to marshall data until SV_Multicast is called + sizebuf_t multicast = new sizebuf_t(); + + byte multicast_buf[] = new byte[Defines.MAX_MSGLEN]; + + // demo server information + RandomAccessFile demofile; - public server_t() { - models = new cmodel_t[Defines.MAX_MODELS]; - for (int n = 0; n < Defines.MAX_MODELS; n++) - models[n] = new cmodel_t(); - - for (int n=0; n < Defines.MAX_EDICTS; n++) - baselines[n] = new entity_state_t(null); - - //for (int n=0; n < Defines.MAX_CONFIGSTRINGS; n++) - //configstrings[n] = ""; - - } - //server_state_t state; - int state; // precache commands are only valid during load - - boolean attractloop; // running cinematics and demos for the local system only - boolean loadgame; // client begins should reuse existing entity - - int time; // always sv.framenum * 100 msec - int framenum; - - //char name[MAX_QPATH]; - String name = ""; // map name, or cinematic name - - //struct cmodel_s *models[MAX_MODELS]; - cmodel_t models[]; - - //char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]; - String configstrings[] = new String[Defines.MAX_CONFIGSTRINGS]; - entity_state_t baselines[] = new entity_state_t[Defines.MAX_EDICTS]; - - // the multicast buffer is used to send a message to a set of clients - // it is only used to marshall data until SV_Multicast is called - sizebuf_t multicast = new sizebuf_t(); - byte multicast_buf[] = new byte[Defines.MAX_MSGLEN]; - - // demo server information - RandomAccessFile demofile; - boolean timedemo; // don't time sync -} + boolean timedemo; // don't time sync +} \ No newline at end of file diff --git a/src/jake2/sound/joal/JOALSoundImpl.java b/src/jake2/sound/joal/JOALSoundImpl.java index 3072c6b..72a36cc 100644 --- a/src/jake2/sound/joal/JOALSoundImpl.java +++ b/src/jake2/sound/joal/JOALSoundImpl.java @@ -2,13 +2,14 @@ * JOALSoundImpl.java * Copyright (C) 2004 * - * $Id: JOALSoundImpl.java,v 1.4 2004-09-19 09:12:20 hzi Exp $ + * $Id: JOALSoundImpl.java,v 1.5 2004-09-22 19:22:15 salomo Exp $ */ package jake2.sound.joal; import jake2.Defines; import jake2.Globals; import jake2.client.CL; +import jake2.client.CL_ents; import jake2.game.*; import jake2.qcommon.*; import jake2.sound.*; @@ -357,7 +358,7 @@ public final class JOALSoundImpl implements Sound { changeEnv = true; } - if ((Game.gi.pointcontents.pointcontents(origin)& Defines.MASK_WATER)!= 0) { + if ((GameBase.gi.pointcontents.pointcontents(origin)& Defines.MASK_WATER)!= 0) { changeEnv = currentEnv != EAX.EAX_ENVIRONMENT_UNDERWATER; currentEnv = EAX.EAX_ENVIRONMENT_UNDERWATER; } else { @@ -483,7 +484,7 @@ public final class JOALSoundImpl implements Sound { Math3D.VectorCopy(listenerOrigin, sourceOrigin); break; case Channel.DYNAMIC: - CL.GetEntitySoundOrigin(ch.entity, entityOrigin); + CL_ents.GetEntitySoundOrigin(ch.entity, entityOrigin); convertVector(entityOrigin, sourceOrigin); break; case Channel.FIXED: diff --git a/src/jake2/sound/jsound/SND_DMA.java b/src/jake2/sound/jsound/SND_DMA.java index 9fe7930..daadb57 100644 --- a/src/jake2/sound/jsound/SND_DMA.java +++ b/src/jake2/sound/jsound/SND_DMA.java @@ -2,1196 +2,1158 @@ * S_DMA.java * Copyright (C) 2004 * - * $Id: SND_DMA.java,v 1.1 2004-07-09 06:50:48 hzi Exp $ + * $Id: SND_DMA.java,v 1.2 2004-09-22 19:22:09 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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 26.01.2004 by RST. - package jake2.sound.jsound; import jake2.Defines; -import jake2.client.CL; -import jake2.game.*; -import jake2.qcommon.*; -import jake2.sound.*; +import jake2.client.CL_ents; +import jake2.game.Cmd; +import jake2.game.cvar_t; +import jake2.game.entity_state_t; +import jake2.qcommon.Com; +import jake2.qcommon.Cvar; +import jake2.qcommon.FS; +import jake2.qcommon.xcommand_t; +import jake2.sound.WaveLoader; +import jake2.sound.sfx_t; +import jake2.sound.sfxcache_t; +import jake2.util.Math3D; import jake2.util.Vargs; import java.io.IOException; import java.io.RandomAccessFile; - - /** - * SND_DMA - * TODO implement sound system + * SND_DMA TODO implement sound system */ public class SND_DMA extends SND_MIX { -//// ======================================================================= -//// Internal sound data & structures -//// ======================================================================= -// -//// only begin attenuating sound volumes when outside the FULLVOLUME range - static final int SOUND_FULLVOLUME = 80; - static final float SOUND_LOOPATTENUATE = 0.003f; - static int s_registration_sequence; - - static boolean sound_started = false; - - static float[] listener_origin = {0, 0, 0}; - static float[] listener_forward = {0, 0, 0}; - static float[] listener_right = {0, 0, 0}; - static float[] listener_up = {0, 0, 0}; - - static boolean s_registering; - - static int soundtime; // sample PAIRS - - // during registration it is possible to have more sounds - // than could actually be referenced during gameplay, - // because we don't want to free anything until we are - // sure we won't need it. - static final int MAX_SFX = (MAX_SOUNDS*2); - static sfx_t[] known_sfx = new sfx_t[MAX_SFX]; - static { - for (int i = 0; i< known_sfx.length; i++) - known_sfx[i] = new sfx_t(); - } - static int num_sfx; - - static final int MAX_PLAYSOUNDS = 128; - static playsound_t[] s_playsounds = new playsound_t[MAX_PLAYSOUNDS]; - static { - for( int i = 0; i < MAX_PLAYSOUNDS; i++) { - s_playsounds[i] = new playsound_t(); - } - } - static playsound_t s_freeplays = new playsound_t(); - - static int s_beginofs; - - static cvar_t s_testsound; - static cvar_t s_loadas8bit; - static cvar_t s_khz; - static cvar_t s_show; - static cvar_t s_mixahead; - static cvar_t s_primary; -// -// -// int s_rawend; -// portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]; -// -// -// ==================================================================== -// User-setable variables -// ==================================================================== - - - static void SoundInfo_f() { - if (!sound_started) { - Com.Printf("sound system not started\n"); - return; - } - - Com.Printf("%5d stereo\n", new Vargs(1).add(dma.channels - 1)); - Com.Printf("%5d samples\n", new Vargs(1).add(dma.samples)); - //Com.Printf("%5d samplepos\n", new Vargs(1).add(dma.samplepos)); - Com.Printf("%5d samplebits\n", new Vargs(1).add(dma.samplebits)); - Com.Printf("%5d submission_chunk\n", new Vargs(1).add(dma.submission_chunk)); - Com.Printf("%5d speed\n", new Vargs(1).add(dma.speed)); - } - - /* - ================ - S_Init - ================ - */ - public static void Init() { - cvar_t cv; - - Com.Printf("\n------- sound initialization -------\n"); - - cv = Cvar.Get("s_initsound", "0", 0); - if (cv.value == 0.0f) - Com.Printf("not initializing.\n"); - else { - s_volume = Cvar.Get("s_volume", "0.7", CVAR_ARCHIVE); - s_khz = Cvar.Get("s_khz", "11", CVAR_ARCHIVE); - s_loadas8bit = Cvar.Get("s_loadas8bit", "1", CVAR_ARCHIVE); - s_mixahead = Cvar.Get("s_mixahead", "0.2", CVAR_ARCHIVE); - s_show = Cvar.Get("s_show", "0", 0); - s_testsound = Cvar.Get("s_testsound", "0", 0); - s_primary = Cvar.Get("s_primary", "0", CVAR_ARCHIVE); // win32 specific - - Cmd.AddCommand("play", new xcommand_t() { - public void execute() { - Play(); - } - }); - Cmd.AddCommand("stopsound", new xcommand_t() { - public void execute() { - StopAllSounds(); - } - }); - Cmd.AddCommand("soundlist", new xcommand_t() { - public void execute() { - SoundList(); - } - }); - Cmd.AddCommand("soundinfo", new xcommand_t() { - public void execute() { - SoundInfo_f(); - } - }); - - if (!SNDDMA_Init()) - return; - - InitScaletable(); - - sound_started = true; - num_sfx = 0; - - soundtime = 0; - paintedtime = 0; - - Com.Printf("sound sampling rate: " + dma.speed + "\n"); - - StopAllSounds(); - } - Com.Printf("------------------------------------\n"); - } - - -// ======================================================================= -// Shutdown sound engine -// ======================================================================= - - public static void Shutdown() { - int i; - sfx_t[] sfx; - - if (!sound_started) - return; - - SNDDMA_Shutdown(); - - sound_started = false; - - Cmd.RemoveCommand("play"); - Cmd.RemoveCommand("stopsound"); - Cmd.RemoveCommand("soundlist"); - Cmd.RemoveCommand("soundinfo"); - - // free all sounds - for (i = 0, sfx = known_sfx; i < num_sfx; i++) { - if (sfx[i].name == null) - continue; - - //memset (sfx, 0, sizeof(*sfx)); - sfx[i].clear(); - } - - num_sfx = 0; - } - -// ======================================================================= -// Load a sound -// ======================================================================= - - /* - ================== - S_FindName - - ================== - */ - static sfx_t FindName(String name, boolean create) { - int i; - sfx_t sfx = null; - - if (name == null) - Com.Error(ERR_FATAL, "S_FindName: NULL\n"); - if (name.length() == 0) - Com.Error(ERR_FATAL, "S_FindName: empty name\n"); - - if (name.length() >= MAX_QPATH) - Com.Error(ERR_FATAL, "Sound name too long: " + name); - - // see if already loaded - for (i = 0; i < num_sfx; i++) - if (name.equals(known_sfx[i].name)) { - return known_sfx[i]; - } - - if (!create) - return null; - - // find a free sfx - for (i = 0; i < num_sfx; i++) - if (known_sfx[i].name == null) - // registration_sequence < s_registration_sequence) - break; - - if (i == num_sfx) { - if (num_sfx == MAX_SFX) - Com.Error(ERR_FATAL, "S_FindName: out of sfx_t"); - num_sfx++; - } - - sfx = known_sfx[i]; - //memset (sfx, 0, sizeof(*sfx)); - sfx.clear(); - sfx.name = name; - sfx.registration_sequence = s_registration_sequence; - - return sfx; - } - - /* - ================== - S_AliasName - - ================== - */ - static sfx_t AliasName(String aliasname, String truename) - { - sfx_t sfx = null; -// char *s; - int i; - -// s = Z_Malloc (MAX_QPATH); -// strcpy (s, truename); - - // find a free sfx - for (i=0 ; i < num_sfx ; i++) - if (known_sfx[i].name == null) - break; - - if (i == num_sfx) - { - if (num_sfx == MAX_SFX) - Com.Error(ERR_FATAL, "S_FindName: out of sfx_t"); - num_sfx++; - } - - sfx = known_sfx[i]; - //memset (sfx, 0, sizeof(*sfx)); - //strcpy (sfx->name, aliasname); - sfx.name = aliasname; - sfx.registration_sequence = s_registration_sequence; - sfx.truename = truename; - - return sfx; - } - - - /* - ===================== - S_BeginRegistration - - ===================== - */ - public static void BeginRegistration() { - s_registration_sequence++; - s_registering = true; - } - - /* - ================== - S_RegisterSound - - ================== - */ - public static sfx_t RegisterSound(String name) { - sfx_t sfx = null; - - if (!sound_started) - return null; - - sfx = FindName(name, true); - sfx.registration_sequence = s_registration_sequence; - - if (!s_registering) - WaveLoader.LoadSound(sfx); - - return sfx; - } - - - /* - ===================== - S_EndRegistration - - ===================== - */ - public static void EndRegistration() { - int i; - sfx_t sfx; - int size; - - // free any sounds not from this registration sequence - for (i = 0; i < num_sfx; i++) { - sfx = known_sfx[i]; - if (sfx.name == null) - continue; - if (sfx.registration_sequence != s_registration_sequence) { // don't need this sound - //memset (sfx, 0, sizeof(*sfx)); - sfx.clear(); - } else { - // make sure it is paged in - // if (sfx->cache) - // { - // size = sfx->cache->length*sfx->cache->width; - // Com_PageInMemory ((byte *)sfx->cache, size); - // } - } - - } - - // load everything in - for (i = 0; i < num_sfx; i++) { - sfx = known_sfx[i]; - if (sfx.name == null) - continue; - WaveLoader.LoadSound(sfx); - } - - s_registering = false; - } - - -// ============================================================================= - - /* - ================= - S_PickChannel - ================= - */ - static channel_t PickChannel(int entnum, int entchannel) - { - int ch_idx; - int first_to_die; - int life_left; - channel_t ch; - - if (entchannel<0) - Com.Error(ERR_DROP, "S_PickChannel: entchannel<0"); - - // Check for replacement sound, or find the best one to replace - first_to_die = -1; - life_left = 0x7fffffff; - for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++) - { - if (entchannel != 0 // channel 0 never overrides - && channels[ch_idx].entnum == entnum - && channels[ch_idx].entchannel == entchannel) - { // always override sound from same entity - first_to_die = ch_idx; - break; - } - - // don't let monster sounds override player sounds - if ((channels[ch_idx].entnum == cl.playernum+1) && (entnum != cl.playernum+1) && channels[ch_idx].sfx != null) - continue; - - if (channels[ch_idx].end - paintedtime < life_left) - { - life_left = channels[ch_idx].end - paintedtime; - first_to_die = ch_idx; - } - } - - if (first_to_die == -1) - return null; - - ch = channels[first_to_die]; - //memset (ch, 0, sizeof(*ch)); - ch.clear(); - - return ch; - } - - /* - ================= - S_SpatializeOrigin - - Used for spatializing channels and autosounds - ================= - */ - static void SpatializeOrigin(float[] origin, float master_vol, float dist_mult, channel_t ch) - { - float dot; - float dist; - float lscale, rscale, scale; - float[] source_vec = {0, 0, 0}; - - if (cls.state != ca_active) - { - ch.leftvol = ch.rightvol = 255; - return; - } - -// calculate stereo seperation and distance attenuation - VectorSubtract(origin, listener_origin, source_vec); - - dist = VectorNormalize(source_vec); - dist -= SOUND_FULLVOLUME; - if (dist < 0) - dist = 0; // close enough to be at full volume - dist *= dist_mult; // different attenuation levels - - dot = DotProduct(listener_right, source_vec); - - if (dma.channels == 1 || dist_mult == 0.0f) - { // no attenuation = no spatialization - rscale = 1.0f; - lscale = 1.0f; - } - else - { - rscale = 0.5f * (1.0f + dot); - lscale = 0.5f * (1.0f - dot); - } - - // add in distance effect - scale = (1.0f - dist) * rscale; - ch.rightvol = (int) (master_vol * scale); - if (ch.rightvol < 0) - ch.rightvol = 0; - - scale = (1.0f - dist) * lscale; - ch.leftvol = (int) (master_vol * scale); - if (ch.leftvol < 0) - ch.leftvol = 0; - } - - /* - ================= - S_Spatialize - ================= - */ - static void Spatialize(channel_t ch) - { - float[] origin = {0, 0, 0}; - - // anything coming from the view entity will always be full volume - if (ch.entnum == cl.playernum+1) - { - ch.leftvol = ch.master_vol; - ch.rightvol = ch.master_vol; - return; - } - - if (ch.fixed_origin) - { - VectorCopy(ch.origin, origin); - } - else - CL.GetEntitySoundOrigin(ch.entnum, origin); - - SpatializeOrigin(origin, (float)ch.master_vol, ch.dist_mult, ch); - } - - /* - ================= - S_AllocPlaysound - ================= - */ - static playsound_t AllocPlaysound () - { - playsound_t ps; - - ps = s_freeplays.next; - if (ps == s_freeplays) - return null; // no free playsounds - - // unlink from freelist - ps.prev.next = ps.next; - ps.next.prev = ps.prev; - - return ps; - } - - - /* - ================= - S_FreePlaysound - ================= - */ - static void FreePlaysound(playsound_t ps) - { - // unlink from channel - ps.prev.next = ps.next; - ps.next.prev = ps.prev; - - // add to free list - ps.next = s_freeplays.next; - s_freeplays.next.prev = ps; - ps.prev = s_freeplays; - s_freeplays.next = ps; - } - - /* - =============== - S_IssuePlaysound - - Take the next playsound and begin it on the channel - This is never called directly by S_Play*, but only - by the update loop. - =============== - */ - static void IssuePlaysound (playsound_t ps) - { - channel_t ch; - sfxcache_t sc; - - if (s_show.value != 0.0f) - Com.Printf("Issue " + ps.begin + "\n"); - // pick a channel to play on - ch = PickChannel(ps.entnum, ps.entchannel); - if (ch == null) - { - FreePlaysound(ps); - return; - } - - // spatialize - if (ps.attenuation == ATTN_STATIC) - ch.dist_mult = ps.attenuation * 0.001f; - else - ch.dist_mult = ps.attenuation * 0.0005f; - ch.master_vol = (int)ps.volume; - ch.entnum = ps.entnum; - ch.entchannel = ps.entchannel; - ch.sfx = ps.sfx; - VectorCopy (ps.origin, ch.origin); - ch.fixed_origin = ps.fixed_origin; - - Spatialize(ch); - - ch.pos = 0; - sc = WaveLoader.LoadSound(ch.sfx); - ch.end = paintedtime + sc.length; - - // free the playsound - FreePlaysound(ps); - } - - static sfx_t RegisterSexedSound(entity_state_t ent, String base) { - sfx_t sfx = null; - - // determine what model the client is using - String model = "male"; - int n = CS_PLAYERSKINS + ent.number - 1; - if (cl.configstrings[n] != null) { - int p = cl.configstrings[n].indexOf('\\'); - if (p >= 0) { - p++; - model = cl.configstrings[n].substring(p); - //strcpy(model, p); - p = model.indexOf('/'); - if (p > 0) - model = model.substring(0, p - 1); - } - } - // if we can't figure it out, they're male - if (model == null || model.length() == 0) - model = "male"; - - // see if we already know of the model specific sound - String sexedFilename = "#players/" + model + "/" + base.substring(1); - //Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1); - sfx = FindName(sexedFilename, false); - - if (sfx == null) { - // no, so see if it exists - RandomAccessFile f = null; - try { - f = FS.FOpenFile(sexedFilename.substring(1)); - } catch (IOException e) {} - if (f != null) { - // yes, close the file and register it - try { - FS.FCloseFile(f); - } catch (IOException e1) {} - sfx = RegisterSound(sexedFilename); - } else { - // no, revert to the male sound in the pak0.pak - //Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1); - String maleFilename = "player/male/" + base.substring(1); - sfx = AliasName(sexedFilename, maleFilename); - } - } - - return sfx; - } - - -// ======================================================================= -// Start a sound effect -// ======================================================================= - - /* - ==================== - S_StartSound - - Validates the parms and ques the sound up - if pos is NULL, the sound will be dynamically sourced from the entity - Entchannel 0 will never override a playing sound - ==================== - */ - public static void StartSound(float[] origin, int entnum, int entchannel, sfx_t sfx, float fvol, float attenuation, float timeofs) { - - if (!sound_started) - return; - - if (sfx == null) - return; - - if (sfx.name.charAt(0) == '*') - sfx = RegisterSexedSound(cl_entities[entnum].current, sfx.name); - - // make sure the sound is loaded - sfxcache_t sc = WaveLoader.LoadSound(sfx); - if (sc == null) - return; // couldn't load the sound's data - - int vol = (int) (fvol * 255); - - // make the playsound_t - playsound_t ps = AllocPlaysound(); - if (ps == null) - return; - - if (origin != null) { - VectorCopy(origin, ps.origin); - ps.fixed_origin = true; - } else - ps.fixed_origin = false; - - ps.entnum = entnum; - ps.entchannel = entchannel; - ps.attenuation = attenuation; - ps.volume = vol; - ps.sfx = sfx; - - // drift s_beginofs - int start = (int) (cl.frame.servertime * 0.001f * dma.speed + s_beginofs); - if (start < paintedtime) { - start = paintedtime; - s_beginofs = (int) (start - (cl.frame.servertime * 0.001f * dma.speed)); - } else if (start > paintedtime + 0.3f * dma.speed) { - start = (int) (paintedtime + 0.1f * dma.speed); - s_beginofs = (int) (start - (cl.frame.servertime * 0.001f * dma.speed)); - } else { - s_beginofs -= 10; - } - - if (timeofs == 0.0f) - ps.begin = paintedtime; - else - ps.begin = (long) (start + timeofs * dma.speed); - - // sort into the pending sound list - playsound_t sort; - for (sort = s_pendingplays.next; sort != s_pendingplays && sort.begin < ps.begin; sort = sort.next); - - ps.next = sort; - ps.prev = sort.prev; - - ps.next.prev = ps; - ps.prev.next = ps; - } - - /* - ================== - S_StartLocalSound - ================== - */ - public static void StartLocalSound(String sound) { - sfx_t sfx; - - if (!sound_started) - return; - - sfx = RegisterSound(sound); - if (sfx == null) { - Com.Printf("S_StartLocalSound: can't cache " + sound + "\n"); - return; - } - StartSound(null, cl.playernum + 1, 0, sfx, 1, 1, 0); - } - - - /* - ================== - S_ClearBuffer - ================== - */ - static void ClearBuffer() - { - int clear; - - if (!sound_started) - return; - - s_rawend = 0; - - if (dma.samplebits == 8) - clear = 0x80; - else - clear = 0; - - SNDDMA_BeginPainting (); - if (dma.buffer != null) - //memset(dma.buffer, clear, dma.samples * dma.samplebits/8); - //Arrays.fill(dma.buffer, (byte)clear); - SNDDMA_Submit (); - } - - /* - ================== - S_StopAllSounds - ================== - */ - public static void StopAllSounds() - { - int i; - - if (!sound_started) - return; - - // clear all the playsounds - //memset(s_playsounds, 0, sizeof(s_playsounds)); - s_freeplays.next = s_freeplays.prev = s_freeplays; - s_pendingplays.next = s_pendingplays.prev = s_pendingplays; - - for (i=0 ; isound field will generated looped sounds - that are automatically started, stopped, and merged together - as the entities are sent to the client - ================== - */ - static void AddLoopSounds() - { - int i, j; - int[] sounds = new int[Defines.MAX_EDICTS]; - int left, right, left_total, right_total; - channel_t ch; - sfx_t sfx; - sfxcache_t sc; - int num; - entity_state_t ent; - - if (cl_paused.value != 0.0f) - return; - - if (cls.state != ca_active) - return; - - if (!cl.sound_prepped) - return; - - for (i=0 ; i 255) - left_total = 255; - if (right_total > 255) - right_total = 255; - ch.leftvol = left_total; - ch.rightvol = right_total; - ch.autosound = true; // remove next frame - ch.sfx = sfx; - ch.pos = paintedtime % sc.length; - ch.end = paintedtime + sc.length - ch.pos; - } - } - -// ============================================================================= - - /* - ============ - S_RawSamples - - Cinematic streaming and voice over network - ============ - */ - static void RawSamples(int samples, int rate, int width, int channels, byte[] data) - { - //TODO RawSamples - int i; - int src, dst; - float scale; - - if (!sound_started) - return; - - if (s_rawend < paintedtime) - s_rawend = paintedtime; - scale = (float)rate / dma.speed; - -// Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend); - if (channels == 2 && width == 2) - { - if (scale == 1.0) - { // optimized case -// for (i=0 ; i= samples) -// break; -// dst = s_rawend&(MAX_RAW_SAMPLES-1); -// s_rawend++; -// s_rawsamples[dst].left = -// LittleShort(((short *)data)[src*2]) << 8; -// s_rawsamples[dst].right = -// LittleShort(((short *)data)[src*2+1]) << 8; - } - } - } - else if (channels == 1 && width == 2) - { - for (i=0 ; ; i++) - { -// src = i*scale; -// if (src >= samples) -// break; -// dst = s_rawend&(MAX_RAW_SAMPLES-1); -// s_rawend++; -// s_rawsamples[dst].left = -// LittleShort(((short *)data)[src]) << 8; -// s_rawsamples[dst].right = -// LittleShort(((short *)data)[src]) << 8; - } - } - else if (channels == 2 && width == 1) - { - for (i=0 ; ; i++) - { -// src = i*scale; -// if (src >= samples) -// break; -// dst = s_rawend&(MAX_RAW_SAMPLES-1); -// s_rawend++; -// s_rawsamples[dst].left = -// ((char *)data)[src*2] << 16; -// s_rawsamples[dst].right = -// ((char *)data)[src*2+1] << 16; - } - } - else if (channels == 1 && width == 1) - { - for (i=0 ; ; i++) - { -// src = i*scale; -// if (src >= samples) -// break; -// dst = s_rawend&(MAX_RAW_SAMPLES-1); -// s_rawend++; -// s_rawsamples[dst].left = -// (((byte *)data)[src]-128) << 16; -// s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16; - } - } - } - -//// ============================================================================= - - /* - ============ - S_Update - - Called once each time through the main loop - ============ - */ - public static void Update(float[] origin, float[] forward, float[] right, float[] up) { - - if (!sound_started) - return; - - // if the laoding plaque is up, clear everything - // out to make sure we aren't looping a dirty - // dma buffer while loading - if (cls.disable_screen != 0.0f) { - ClearBuffer(); - return; - } - - // rebuild scale tables if volume is modified - if (s_volume.modified) - InitScaletable(); - - VectorCopy(origin, listener_origin); - VectorCopy(forward, listener_forward); - VectorCopy(right, listener_right); - VectorCopy(up, listener_up); - - channel_t combine = null; - - // update spatialization for dynamic sounds - channel_t ch; - for (int i = 0; i < MAX_CHANNELS; i++) { - ch = channels[i]; - if (ch.sfx == null) - continue; - if (ch.autosound) { // autosounds are regenerated fresh each frame - //memset (ch, 0, sizeof(*ch)); - ch.clear(); - continue; - } - Spatialize(ch); // respatialize channel - if (ch.leftvol == 0 && ch.rightvol == 0) { - //memset (ch, 0, sizeof(*ch)); - ch.clear(); - continue; - } - } - - // add loopsounds - AddLoopSounds(); - - // - // debugging output - // - if (s_show.value != 0.0f) { - int total = 0; - - for (int i = 0; i < MAX_CHANNELS; i++) { - ch = channels[i]; - if (ch.sfx != null && (ch.leftvol != 0 || ch.rightvol != 0)) { - Com.Printf(ch.leftvol + " " + ch.rightvol + " " + ch.sfx.name + "\n"); - total++; - } - } - - //Com.Printf("----(" + total + ")---- painted: " + paintedtime + "\n"); - } - - // mix some sound - Update_(); - } - - static int buffers = 0; - static int oldsamplepos = 0; - static void GetSoundtime() - { - int samplepos; - //static int buffers; - //static int oldsamplepos; - int fullsamples; - - fullsamples = dma.samples / dma.channels; - -// it is possible to miscount buffers if it has wrapped twice between -// calls to S_Update. Oh well. - samplepos = SNDDMA_GetDMAPos(); - - if (samplepos < oldsamplepos) - { - buffers++; // buffer wrapped - - if (paintedtime > 0x40000000) - { // time to chop things off to avoid 32 bit limits - buffers = 0; - paintedtime = fullsamples; - StopAllSounds(); - } - } - oldsamplepos = samplepos; - - soundtime = buffers*fullsamples + samplepos/dma.channels; - } - - static void Update_() - { - int endtime; - int samps; - - if (!sound_started) - return; - - SNDDMA_BeginPainting(); - - if (dma.buffer == null) - return; - - // Updates DMA time - GetSoundtime(); - - // check to make sure that we haven't overshot - if (paintedtime < soundtime) - { - Com.DPrintf("S_Update_ : overflow\n"); - paintedtime = soundtime; - } - - // mix ahead of current position - endtime = (int)(soundtime + s_mixahead.value * dma.speed); - // endtime = (soundtime + 4096) & ~4095; - - // mix to an even submission block size - endtime = (endtime + dma.submission_chunk-1) - & ~(dma.submission_chunk-1); - samps = dma.samples >> (dma.channels-1); - if (endtime - soundtime > samps) - endtime = soundtime + samps; - - PaintChannels(endtime); - - SNDDMA_Submit(); - } - - /* - =============================================================================== - - console functions - - =============================================================================== - */ - - static void Play() { - int i; - String name; - sfx_t sfx; - - i = 1; - while (i < Cmd.Argc()) { - name = new String(Cmd.Argv(i)); - if (name.indexOf('.') == -1) - name += ".wav"; - - sfx = RegisterSound(name); - StartSound(null, cl.playernum + 1, 0, sfx, 1.0f, 1.0f, 0.0f); - i++; - } - } - - static void SoundList() { - int i; - sfx_t sfx; - sfxcache_t sc; - int size, total; - - total = 0; - for (i = 0; i < num_sfx; i++) { - sfx = known_sfx[i]; - if (sfx.registration_sequence == 0) - continue; - sc = sfx.cache; - if (sc != null) { - size = sc.length * sc.width * (sc.stereo + 1); - total += size; - if (sc.loopstart >= 0) - Com.Printf("L"); - else - Com.Printf(" "); - Com.Printf("(%2db) %6i : %s\n", new Vargs(3).add(sc.width * 8).add(size).add(sfx.name)); - } else { - if (sfx.name.charAt(0) == '*') - Com.Printf(" placeholder : " + sfx.name + "\n"); - else - Com.Printf(" not loaded : " + sfx.name + "\n"); - } - } - Com.Printf("Total resident: " + total + "\n"); - } - -} + //// + // ======================================================================= + //// Internal sound data & structures + //// + // ======================================================================= + // + //// only begin attenuating sound volumes when outside the FULLVOLUME range + static final int SOUND_FULLVOLUME = 80; + + static final float SOUND_LOOPATTENUATE = 0.003f; + + static int s_registration_sequence; + + static boolean sound_started = false; + + static float[] listener_origin = { 0, 0, 0 }; + + static float[] listener_forward = { 0, 0, 0 }; + + static float[] listener_right = { 0, 0, 0 }; + + static float[] listener_up = { 0, 0, 0 }; + + static boolean s_registering; + + static int soundtime; // sample PAIRS + + // during registration it is possible to have more sounds + // than could actually be referenced during gameplay, + // because we don't want to free anything until we are + // sure we won't need it. + static final int MAX_SFX = (MAX_SOUNDS * 2); + + static sfx_t[] known_sfx = new sfx_t[MAX_SFX]; + static { + for (int i = 0; i < known_sfx.length; i++) + known_sfx[i] = new sfx_t(); + } + + static int num_sfx; + + static final int MAX_PLAYSOUNDS = 128; + + static playsound_t[] s_playsounds = new playsound_t[MAX_PLAYSOUNDS]; + static { + for (int i = 0; i < MAX_PLAYSOUNDS; i++) { + s_playsounds[i] = new playsound_t(); + } + } + + static playsound_t s_freeplays = new playsound_t(); + + static int s_beginofs; + + static cvar_t s_testsound; + + static cvar_t s_loadas8bit; + + static cvar_t s_khz; + + static cvar_t s_show; + + static cvar_t s_mixahead; + + static cvar_t s_primary; + + // + // + // int s_rawend; + // portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]; + // + // + // ==================================================================== + // User-setable variables + // ==================================================================== + + static void SoundInfo_f() { + if (!sound_started) { + Com.Printf("sound system not started\n"); + return; + } + + Com.Printf("%5d stereo\n", new Vargs(1).add(dma.channels - 1)); + Com.Printf("%5d samples\n", new Vargs(1).add(dma.samples)); + //Com.Printf("%5d samplepos\n", new Vargs(1).add(dma.samplepos)); + Com.Printf("%5d samplebits\n", new Vargs(1).add(dma.samplebits)); + Com.Printf("%5d submission_chunk\n", new Vargs(1) + .add(dma.submission_chunk)); + Com.Printf("%5d speed\n", new Vargs(1).add(dma.speed)); + } + + /* + * ================ S_Init ================ + */ + public static void Init() { + cvar_t cv; + + Com.Printf("\n------- sound initialization -------\n"); + + cv = Cvar.Get("s_initsound", "0", 0); + if (cv.value == 0.0f) + Com.Printf("not initializing.\n"); + else { + s_volume = Cvar.Get("s_volume", "0.7", CVAR_ARCHIVE); + s_khz = Cvar.Get("s_khz", "11", CVAR_ARCHIVE); + s_loadas8bit = Cvar.Get("s_loadas8bit", "1", CVAR_ARCHIVE); + s_mixahead = Cvar.Get("s_mixahead", "0.2", CVAR_ARCHIVE); + s_show = Cvar.Get("s_show", "0", 0); + s_testsound = Cvar.Get("s_testsound", "0", 0); + s_primary = Cvar.Get("s_primary", "0", CVAR_ARCHIVE); // win32 + // specific + + Cmd.AddCommand("play", new xcommand_t() { + public void execute() { + Play(); + } + }); + Cmd.AddCommand("stopsound", new xcommand_t() { + public void execute() { + StopAllSounds(); + } + }); + Cmd.AddCommand("soundlist", new xcommand_t() { + public void execute() { + SoundList(); + } + }); + Cmd.AddCommand("soundinfo", new xcommand_t() { + public void execute() { + SoundInfo_f(); + } + }); + + if (!SNDDMA_Init()) + return; + + InitScaletable(); + + sound_started = true; + num_sfx = 0; + + soundtime = 0; + paintedtime = 0; + + Com.Printf("sound sampling rate: " + dma.speed + "\n"); + + StopAllSounds(); + } + Com.Printf("------------------------------------\n"); + } + + // ======================================================================= + // Shutdown sound engine + // ======================================================================= + + public static void Shutdown() { + int i; + sfx_t[] sfx; + + if (!sound_started) + return; + + SNDDMA_Shutdown(); + + sound_started = false; + + Cmd.RemoveCommand("play"); + Cmd.RemoveCommand("stopsound"); + Cmd.RemoveCommand("soundlist"); + Cmd.RemoveCommand("soundinfo"); + + // free all sounds + for (i = 0, sfx = known_sfx; i < num_sfx; i++) { + if (sfx[i].name == null) + continue; + + //memset (sfx, 0, sizeof(*sfx)); + sfx[i].clear(); + } + + num_sfx = 0; + } + + // ======================================================================= + // Load a sound + // ======================================================================= + + /* + * ================== S_FindName + * + * ================== + */ + static sfx_t FindName(String name, boolean create) { + int i; + sfx_t sfx = null; + + if (name == null) + Com.Error(ERR_FATAL, "S_FindName: NULL\n"); + if (name.length() == 0) + Com.Error(ERR_FATAL, "S_FindName: empty name\n"); + + if (name.length() >= MAX_QPATH) + Com.Error(ERR_FATAL, "Sound name too long: " + name); + + // see if already loaded + for (i = 0; i < num_sfx; i++) + if (name.equals(known_sfx[i].name)) { + return known_sfx[i]; + } + + if (!create) + return null; + + // find a free sfx + for (i = 0; i < num_sfx; i++) + if (known_sfx[i].name == null) + // registration_sequence < s_registration_sequence) + break; + + if (i == num_sfx) { + if (num_sfx == MAX_SFX) + Com.Error(ERR_FATAL, "S_FindName: out of sfx_t"); + num_sfx++; + } + + sfx = known_sfx[i]; + //memset (sfx, 0, sizeof(*sfx)); + sfx.clear(); + sfx.name = name; + sfx.registration_sequence = s_registration_sequence; + + return sfx; + } + + /* + * ================== S_AliasName + * + * ================== + */ + static sfx_t AliasName(String aliasname, String truename) { + sfx_t sfx = null; + // char *s; + int i; + + // s = Z_Malloc (MAX_QPATH); + // strcpy (s, truename); + + // find a free sfx + for (i = 0; i < num_sfx; i++) + if (known_sfx[i].name == null) + break; + + if (i == num_sfx) { + if (num_sfx == MAX_SFX) + Com.Error(ERR_FATAL, "S_FindName: out of sfx_t"); + num_sfx++; + } + + sfx = known_sfx[i]; + //memset (sfx, 0, sizeof(*sfx)); + //strcpy (sfx->name, aliasname); + sfx.name = aliasname; + sfx.registration_sequence = s_registration_sequence; + sfx.truename = truename; + + return sfx; + } + + /* + * ===================== S_BeginRegistration + * + * ===================== + */ + public static void BeginRegistration() { + s_registration_sequence++; + s_registering = true; + } + + /* + * ================== S_RegisterSound + * + * ================== + */ + public static sfx_t RegisterSound(String name) { + sfx_t sfx = null; + + if (!sound_started) + return null; + + sfx = FindName(name, true); + sfx.registration_sequence = s_registration_sequence; + + if (!s_registering) + WaveLoader.LoadSound(sfx); + + return sfx; + } + + /* + * ===================== S_EndRegistration + * + * ===================== + */ + public static void EndRegistration() { + int i; + sfx_t sfx; + int size; + + // free any sounds not from this registration sequence + for (i = 0; i < num_sfx; i++) { + sfx = known_sfx[i]; + if (sfx.name == null) + continue; + if (sfx.registration_sequence != s_registration_sequence) { // don't + // need + // this + // sound + //memset (sfx, 0, sizeof(*sfx)); + sfx.clear(); + } else { + // make sure it is paged in + // if (sfx->cache) + // { + // size = sfx->cache->length*sfx->cache->width; + // Com_PageInMemory ((byte *)sfx->cache, size); + // } + } + + } + + // load everything in + for (i = 0; i < num_sfx; i++) { + sfx = known_sfx[i]; + if (sfx.name == null) + continue; + WaveLoader.LoadSound(sfx); + } + + s_registering = false; + } + + // ============================================================================= + + /* + * ================= S_PickChannel ================= + */ + static channel_t PickChannel(int entnum, int entchannel) { + int ch_idx; + int first_to_die; + int life_left; + channel_t ch; + + if (entchannel < 0) + Com.Error(ERR_DROP, "S_PickChannel: entchannel<0"); + + // Check for replacement sound, or find the best one to replace + first_to_die = -1; + life_left = 0x7fffffff; + for (ch_idx = 0; ch_idx < MAX_CHANNELS; ch_idx++) { + if (entchannel != 0 // channel 0 never overrides + && channels[ch_idx].entnum == entnum + && channels[ch_idx].entchannel == entchannel) { // always + // override + // sound + // from same + // entity + first_to_die = ch_idx; + break; + } + + // don't let monster sounds override player sounds + if ((channels[ch_idx].entnum == cl.playernum + 1) + && (entnum != cl.playernum + 1) + && channels[ch_idx].sfx != null) + continue; + + if (channels[ch_idx].end - paintedtime < life_left) { + life_left = channels[ch_idx].end - paintedtime; + first_to_die = ch_idx; + } + } + + if (first_to_die == -1) + return null; + + ch = channels[first_to_die]; + //memset (ch, 0, sizeof(*ch)); + ch.clear(); + + return ch; + } + + /* + * ================= S_SpatializeOrigin + * + * Used for spatializing channels and autosounds ================= + */ + static void SpatializeOrigin(float[] origin, float master_vol, + float dist_mult, channel_t ch) { + float dot; + float dist; + float lscale, rscale, scale; + float[] source_vec = { 0, 0, 0 }; + + if (cls.state != ca_active) { + ch.leftvol = ch.rightvol = 255; + return; + } + + // calculate stereo seperation and distance attenuation + Math3D.VectorSubtract(origin, listener_origin, source_vec); + + dist = Math3D.VectorNormalize(source_vec); + dist -= SOUND_FULLVOLUME; + if (dist < 0) + dist = 0; // close enough to be at full volume + dist *= dist_mult; // different attenuation levels + + dot = Math3D.DotProduct(listener_right, source_vec); + + if (dma.channels == 1 || dist_mult == 0.0f) { // no attenuation = no + // spatialization + rscale = 1.0f; + lscale = 1.0f; + } else { + rscale = 0.5f * (1.0f + dot); + lscale = 0.5f * (1.0f - dot); + } + + // add in distance effect + scale = (1.0f - dist) * rscale; + ch.rightvol = (int) (master_vol * scale); + if (ch.rightvol < 0) + ch.rightvol = 0; + + scale = (1.0f - dist) * lscale; + ch.leftvol = (int) (master_vol * scale); + if (ch.leftvol < 0) + ch.leftvol = 0; + } + + /* + * ================= S_Spatialize ================= + */ + static void Spatialize(channel_t ch) { + float[] origin = { 0, 0, 0 }; + + // anything coming from the view entity will always be full volume + if (ch.entnum == cl.playernum + 1) { + ch.leftvol = ch.master_vol; + ch.rightvol = ch.master_vol; + return; + } + + if (ch.fixed_origin) { + Math3D.VectorCopy(ch.origin, origin); + } else + CL_ents.GetEntitySoundOrigin(ch.entnum, origin); + + SpatializeOrigin(origin, (float) ch.master_vol, ch.dist_mult, ch); + } + + /* + * ================= S_AllocPlaysound ================= + */ + static playsound_t AllocPlaysound() { + playsound_t ps; + + ps = s_freeplays.next; + if (ps == s_freeplays) + return null; // no free playsounds + + // unlink from freelist + ps.prev.next = ps.next; + ps.next.prev = ps.prev; + + return ps; + } + + /* + * ================= S_FreePlaysound ================= + */ + static void FreePlaysound(playsound_t ps) { + // unlink from channel + ps.prev.next = ps.next; + ps.next.prev = ps.prev; + + // add to free list + ps.next = s_freeplays.next; + s_freeplays.next.prev = ps; + ps.prev = s_freeplays; + s_freeplays.next = ps; + } + + /* + * =============== S_IssuePlaysound + * + * Take the next playsound and begin it on the channel This is never called + * directly by S_Play*, but only by the update loop. =============== + */ + static void IssuePlaysound(playsound_t ps) { + channel_t ch; + sfxcache_t sc; + + if (s_show.value != 0.0f) + Com.Printf("Issue " + ps.begin + "\n"); + // pick a channel to play on + ch = PickChannel(ps.entnum, ps.entchannel); + if (ch == null) { + FreePlaysound(ps); + return; + } + + // spatialize + if (ps.attenuation == ATTN_STATIC) + ch.dist_mult = ps.attenuation * 0.001f; + else + ch.dist_mult = ps.attenuation * 0.0005f; + ch.master_vol = (int) ps.volume; + ch.entnum = ps.entnum; + ch.entchannel = ps.entchannel; + ch.sfx = ps.sfx; + Math3D.VectorCopy(ps.origin, ch.origin); + ch.fixed_origin = ps.fixed_origin; + + Spatialize(ch); + + ch.pos = 0; + sc = WaveLoader.LoadSound(ch.sfx); + ch.end = paintedtime + sc.length; + + // free the playsound + FreePlaysound(ps); + } + + static sfx_t RegisterSexedSound(entity_state_t ent, String base) { + sfx_t sfx = null; + + // determine what model the client is using + String model = "male"; + int n = CS_PLAYERSKINS + ent.number - 1; + if (cl.configstrings[n] != null) { + int p = cl.configstrings[n].indexOf('\\'); + if (p >= 0) { + p++; + model = cl.configstrings[n].substring(p); + //strcpy(model, p); + p = model.indexOf('/'); + if (p > 0) + model = model.substring(0, p - 1); + } + } + // if we can't figure it out, they're male + if (model == null || model.length() == 0) + model = "male"; + + // see if we already know of the model specific sound + String sexedFilename = "#players/" + model + "/" + base.substring(1); + //Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", + // model, base+1); + sfx = FindName(sexedFilename, false); + + if (sfx == null) { + // no, so see if it exists + RandomAccessFile f = null; + try { + f = FS.FOpenFile(sexedFilename.substring(1)); + } catch (IOException e) { + } + if (f != null) { + // yes, close the file and register it + try { + FS.FCloseFile(f); + } catch (IOException e1) { + } + sfx = RegisterSound(sexedFilename); + } else { + // no, revert to the male sound in the pak0.pak + //Com_sprintf (maleFilename, sizeof(maleFilename), + // "player/%s/%s", "male", base+1); + String maleFilename = "player/male/" + base.substring(1); + sfx = AliasName(sexedFilename, maleFilename); + } + } + + return sfx; + } + + // ======================================================================= + // Start a sound effect + // ======================================================================= + + /* + * ==================== S_StartSound + * + * Validates the parms and ques the sound up if pos is NULL, the sound will + * be dynamically sourced from the entity Entchannel 0 will never override a + * playing sound ==================== + */ + public static void StartSound(float[] origin, int entnum, int entchannel, + sfx_t sfx, float fvol, float attenuation, float timeofs) { + + if (!sound_started) + return; + + if (sfx == null) + return; + + if (sfx.name.charAt(0) == '*') + sfx = RegisterSexedSound(cl_entities[entnum].current, sfx.name); + + // make sure the sound is loaded + sfxcache_t sc = WaveLoader.LoadSound(sfx); + if (sc == null) + return; // couldn't load the sound's data + + int vol = (int) (fvol * 255); + + // make the playsound_t + playsound_t ps = AllocPlaysound(); + if (ps == null) + return; + + if (origin != null) { + Math3D.VectorCopy(origin, ps.origin); + ps.fixed_origin = true; + } else + ps.fixed_origin = false; + + ps.entnum = entnum; + ps.entchannel = entchannel; + ps.attenuation = attenuation; + ps.volume = vol; + ps.sfx = sfx; + + // drift s_beginofs + int start = (int) (cl.frame.servertime * 0.001f * dma.speed + s_beginofs); + if (start < paintedtime) { + start = paintedtime; + s_beginofs = (int) (start - (cl.frame.servertime * 0.001f * dma.speed)); + } else if (start > paintedtime + 0.3f * dma.speed) { + start = (int) (paintedtime + 0.1f * dma.speed); + s_beginofs = (int) (start - (cl.frame.servertime * 0.001f * dma.speed)); + } else { + s_beginofs -= 10; + } + + if (timeofs == 0.0f) + ps.begin = paintedtime; + else + ps.begin = (long) (start + timeofs * dma.speed); + + // sort into the pending sound list + playsound_t sort; + for (sort = s_pendingplays.next; sort != s_pendingplays + && sort.begin < ps.begin; sort = sort.next) + ; + + ps.next = sort; + ps.prev = sort.prev; + + ps.next.prev = ps; + ps.prev.next = ps; + } + + /* + * ================== S_StartLocalSound ================== + */ + public static void StartLocalSound(String sound) { + sfx_t sfx; + + if (!sound_started) + return; + + sfx = RegisterSound(sound); + if (sfx == null) { + Com.Printf("S_StartLocalSound: can't cache " + sound + "\n"); + return; + } + StartSound(null, cl.playernum + 1, 0, sfx, 1, 1, 0); + } + + /* + * ================== S_ClearBuffer ================== + */ + static void ClearBuffer() { + int clear; + + if (!sound_started) + return; + + s_rawend = 0; + + if (dma.samplebits == 8) + clear = 0x80; + else + clear = 0; + + SNDDMA_BeginPainting(); + if (dma.buffer != null) + //memset(dma.buffer, clear, dma.samples * dma.samplebits/8); + //Arrays.fill(dma.buffer, (byte)clear); + SNDDMA_Submit(); + } + + /* + * ================== S_StopAllSounds ================== + */ + public static void StopAllSounds() { + int i; + + if (!sound_started) + return; + + // clear all the playsounds + //memset(s_playsounds, 0, sizeof(s_playsounds)); + s_freeplays.next = s_freeplays.prev = s_freeplays; + s_pendingplays.next = s_pendingplays.prev = s_pendingplays; + + for (i = 0; i < MAX_PLAYSOUNDS; i++) { + s_playsounds[i].clear(); + s_playsounds[i].prev = s_freeplays; + s_playsounds[i].next = s_freeplays.next; + s_playsounds[i].prev.next = s_playsounds[i]; + s_playsounds[i].next.prev = s_playsounds[i]; + } + + // clear all the channels + //memset(channels, 0, sizeof(channels)); + for (i = 0; i < MAX_CHANNELS; i++) + channels[i].clear(); + + ClearBuffer(); + } + + /* + * ================== S_AddLoopSounds + * + * Entities with a ->sound field will generated looped sounds that are + * automatically started, stopped, and merged together as the entities are + * sent to the client ================== + */ + static void AddLoopSounds() { + int i, j; + int[] sounds = new int[Defines.MAX_EDICTS]; + int left, right, left_total, right_total; + channel_t ch; + sfx_t sfx; + sfxcache_t sc; + int num; + entity_state_t ent; + + if (cl_paused.value != 0.0f) + return; + + if (cls.state != ca_active) + return; + + if (!cl.sound_prepped) + return; + + for (i = 0; i < cl.frame.num_entities; i++) { + num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1); + ent = cl_parse_entities[num]; + sounds[i] = ent.sound; + } + + for (i = 0; i < cl.frame.num_entities; i++) { + if (sounds[i] == 0) + continue; + + sfx = cl.sound_precache[sounds[i]]; + if (sfx == null) + continue; // bad sound effect + sc = sfx.cache; + if (sc == null) + continue; + + num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1); + ent = cl_parse_entities[num]; + + channel_t tch = new channel_t(); + // find the total contribution of all sounds of this type + SpatializeOrigin(ent.origin, 255.0f, SOUND_LOOPATTENUATE, tch); + left_total = tch.leftvol; + right_total = tch.rightvol; + for (j = i + 1; j < cl.frame.num_entities; j++) { + if (sounds[j] != sounds[i]) + continue; + sounds[j] = 0; // don't check this again later + + num = (cl.frame.parse_entities + j) & (MAX_PARSE_ENTITIES - 1); + ent = cl_parse_entities[num]; + + SpatializeOrigin(ent.origin, 255.0f, SOUND_LOOPATTENUATE, tch); + left_total += tch.leftvol; + right_total += tch.rightvol; + } + + if (left_total == 0 && right_total == 0) + continue; // not audible + + // allocate a channel + ch = PickChannel(0, 0); + if (ch == null) + return; + + if (left_total > 255) + left_total = 255; + if (right_total > 255) + right_total = 255; + ch.leftvol = left_total; + ch.rightvol = right_total; + ch.autosound = true; // remove next frame + ch.sfx = sfx; + ch.pos = paintedtime % sc.length; + ch.end = paintedtime + sc.length - ch.pos; + } + } + + // ============================================================================= + + /* + * ============ S_RawSamples + * + * Cinematic streaming and voice over network ============ + */ + static void RawSamples(int samples, int rate, int width, int channels, + byte[] data) { + //TODO RawSamples + int i; + int src, dst; + float scale; + + if (!sound_started) + return; + + if (s_rawend < paintedtime) + s_rawend = paintedtime; + scale = (float) rate / dma.speed; + + // Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend); + if (channels == 2 && width == 2) { + if (scale == 1.0) { // optimized case + // for (i=0 ; i= samples) + // break; + // dst = s_rawend&(MAX_RAW_SAMPLES-1); + // s_rawend++; + // s_rawsamples[dst].left = + // LittleShort(((short *)data)[src*2]) << 8; + // s_rawsamples[dst].right = + // LittleShort(((short *)data)[src*2+1]) << 8; + } + } + } else if (channels == 1 && width == 2) { + for (i = 0;; i++) { + // src = i*scale; + // if (src >= samples) + // break; + // dst = s_rawend&(MAX_RAW_SAMPLES-1); + // s_rawend++; + // s_rawsamples[dst].left = + // LittleShort(((short *)data)[src]) << 8; + // s_rawsamples[dst].right = + // LittleShort(((short *)data)[src]) << 8; + } + } else if (channels == 2 && width == 1) { + for (i = 0;; i++) { + // src = i*scale; + // if (src >= samples) + // break; + // dst = s_rawend&(MAX_RAW_SAMPLES-1); + // s_rawend++; + // s_rawsamples[dst].left = + // ((char *)data)[src*2] << 16; + // s_rawsamples[dst].right = + // ((char *)data)[src*2+1] << 16; + } + } else if (channels == 1 && width == 1) { + for (i = 0;; i++) { + // src = i*scale; + // if (src >= samples) + // break; + // dst = s_rawend&(MAX_RAW_SAMPLES-1); + // s_rawend++; + // s_rawsamples[dst].left = + // (((byte *)data)[src]-128) << 16; + // s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16; + } + } + } + + //// + // ============================================================================= + + /* + * ============ S_Update + * + * Called once each time through the main loop ============ + */ + public static void Update(float[] origin, float[] forward, float[] right, + float[] up) { + + if (!sound_started) + return; + + // if the laoding plaque is up, clear everything + // out to make sure we aren't looping a dirty + // dma buffer while loading + if (cls.disable_screen != 0.0f) { + ClearBuffer(); + return; + } + + // rebuild scale tables if volume is modified + if (s_volume.modified) + InitScaletable(); + + Math3D.VectorCopy(origin, listener_origin); + Math3D.VectorCopy(forward, listener_forward); + Math3D.VectorCopy(right, listener_right); + Math3D.VectorCopy(up, listener_up); + + channel_t combine = null; + + // update spatialization for dynamic sounds + channel_t ch; + for (int i = 0; i < MAX_CHANNELS; i++) { + ch = channels[i]; + if (ch.sfx == null) + continue; + if (ch.autosound) { // autosounds are regenerated fresh each frame + //memset (ch, 0, sizeof(*ch)); + ch.clear(); + continue; + } + Spatialize(ch); // respatialize channel + if (ch.leftvol == 0 && ch.rightvol == 0) { + //memset (ch, 0, sizeof(*ch)); + ch.clear(); + continue; + } + } + + // add loopsounds + AddLoopSounds(); + + // + // debugging output + // + if (s_show.value != 0.0f) { + int total = 0; + + for (int i = 0; i < MAX_CHANNELS; i++) { + ch = channels[i]; + if (ch.sfx != null && (ch.leftvol != 0 || ch.rightvol != 0)) { + Com.Printf(ch.leftvol + " " + ch.rightvol + " " + + ch.sfx.name + "\n"); + total++; + } + } + + //Com.Printf("----(" + total + ")---- painted: " + paintedtime + + // "\n"); + } + + // mix some sound + Update_(); + } + + static int buffers = 0; + + static int oldsamplepos = 0; + + static void GetSoundtime() { + int samplepos; + //static int buffers; + //static int oldsamplepos; + int fullsamples; + + fullsamples = dma.samples / dma.channels; + + // it is possible to miscount buffers if it has wrapped twice between + // calls to S_Update. Oh well. + samplepos = SNDDMA_GetDMAPos(); + + if (samplepos < oldsamplepos) { + buffers++; // buffer wrapped + + if (paintedtime > 0x40000000) { // time to chop things off to avoid + // 32 bit limits + buffers = 0; + paintedtime = fullsamples; + StopAllSounds(); + } + } + oldsamplepos = samplepos; + + soundtime = buffers * fullsamples + samplepos / dma.channels; + } + + static void Update_() { + int endtime; + int samps; + + if (!sound_started) + return; + + SNDDMA_BeginPainting(); + + if (dma.buffer == null) + return; + + // Updates DMA time + GetSoundtime(); + + // check to make sure that we haven't overshot + if (paintedtime < soundtime) { + Com.DPrintf("S_Update_ : overflow\n"); + paintedtime = soundtime; + } + + // mix ahead of current position + endtime = (int) (soundtime + s_mixahead.value * dma.speed); + // endtime = (soundtime + 4096) & ~4095; + + // mix to an even submission block size + endtime = (endtime + dma.submission_chunk - 1) + & ~(dma.submission_chunk - 1); + samps = dma.samples >> (dma.channels - 1); + if (endtime - soundtime > samps) + endtime = soundtime + samps; + + PaintChannels(endtime); + + SNDDMA_Submit(); + } + + /* + * =============================================================================== + * + * console functions + * + * =============================================================================== + */ + + static void Play() { + int i; + String name; + sfx_t sfx; + + i = 1; + while (i < Cmd.Argc()) { + name = new String(Cmd.Argv(i)); + if (name.indexOf('.') == -1) + name += ".wav"; + + sfx = RegisterSound(name); + StartSound(null, cl.playernum + 1, 0, sfx, 1.0f, 1.0f, 0.0f); + i++; + } + } + + static void SoundList() { + int i; + sfx_t sfx; + sfxcache_t sc; + int size, total; + + total = 0; + for (i = 0; i < num_sfx; i++) { + sfx = known_sfx[i]; + if (sfx.registration_sequence == 0) + continue; + sc = sfx.cache; + if (sc != null) { + size = sc.length * sc.width * (sc.stereo + 1); + total += size; + if (sc.loopstart >= 0) + Com.Printf("L"); + else + Com.Printf(" "); + Com.Printf("(%2db) %6i : %s\n", new Vargs(3).add(sc.width * 8) + .add(size).add(sfx.name)); + } else { + if (sfx.name.charAt(0) == '*') + Com.Printf(" placeholder : " + sfx.name + "\n"); + else + Com.Printf(" not loaded : " + sfx.name + "\n"); + } + } + Com.Printf("Total resident: " + total + "\n"); + } + +} \ No newline at end of file diff --git a/src/jake2/sound/jsound/SND_MIX.java b/src/jake2/sound/jsound/SND_MIX.java index c3aae2c..c292d5d 100644 --- a/src/jake2/sound/jsound/SND_MIX.java +++ b/src/jake2/sound/jsound/SND_MIX.java @@ -2,490 +2,493 @@ * SND_MIX.java * Copyright (C) 2004 * - * $Id: SND_MIX.java,v 1.1 2004-07-09 06:50:48 hzi Exp $ + * $Id: SND_MIX.java,v 1.2 2004-09-22 19:22:09 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.sound.jsound; -import java.nio.*; -import java.nio.ByteBuffer; -import java.nio.ShortBuffer; - import jake2.game.cvar_t; -import jake2.sound.*; +import jake2.sound.WaveLoader; import jake2.sound.sfx_t; import jake2.sound.sfxcache_t; import jake2.util.Math3D; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; + /** * SND_MIX */ public class SND_MIX extends SND_JAVA { - static final int MAX_CHANNELS = 32; - static final int MAX_RAW_SAMPLES = 8192; - - static class playsound_t { - playsound_t prev, next; - sfx_t sfx; - float volume; - float attenuation; - int entnum; - int entchannel; - boolean fixed_origin; // use origin field instead of entnum's origin - float[] origin = { 0, 0, 0 }; - long begin; // begin on this sample - - public void clear() { - prev = next = null; - sfx = null; - volume = attenuation = begin = entnum = entchannel = 0; - fixed_origin = false; - Math3D.VectorClear(origin); - } - }; - - static class channel_t { - sfx_t sfx; // sfx number - int leftvol; // 0-255 volume - int rightvol; // 0-255 volume - int end; // end time in global paintsamples - int pos; // sample position in sfx - int looping; // where to loop, -1 = no looping OBSOLETE? - int entnum; // to allow overriding a specific sound - int entchannel; // - float[] origin = { 0, 0, 0 }; // only use if fixed_origin is set - float dist_mult; // distance multiplier (attenuation/clipK) - int master_vol; // 0-255 master volume - boolean fixed_origin; // use origin instead of fetching entnum's origin - boolean autosound; // from an entity->sound, cleared each frame - - void clear() { - sfx = null; - dist_mult = leftvol = rightvol = end = pos = looping = entnum = entchannel = master_vol = 0; - Math3D.VectorClear(origin); - fixed_origin = autosound = false; - } - }; - - static class portable_samplepair_t { - int left; - int right; - }; - - static cvar_t s_volume; - static int s_rawend; -//// snd_mix.c -- portable code to mix sounds for snd_dma.c -// -// #include "client.h" -// #include "snd_loc.h" -// - static final int PAINTBUFFER_SIZE = 2048; - //static portable_samplepair_t[] paintbuffer = new portable_samplepair_t[PAINTBUFFER_SIZE]; - static IntBuffer paintbuffer = IntBuffer.allocate(PAINTBUFFER_SIZE*2); - static int[][] snd_scaletable = new int[32][256]; -// int *snd_p, snd_linear_count, snd_vol; -// short *snd_out; - static IntBuffer snd_p; - static ShortBuffer snd_out; - static int snd_linear_count; - static int snd_vol; - - static int paintedtime; // sample PAIRS - static playsound_t s_pendingplays = new playsound_t(); - - //static portable_samplepair_t[] s_rawsamples = new portable_samplepair_t[MAX_RAW_SAMPLES]; - static IntBuffer s_rawsamples = IntBuffer.allocate(MAX_RAW_SAMPLES*2); - static channel_t[] channels = new channel_t[MAX_CHANNELS]; - static { - for(int i=0; i < MAX_CHANNELS; i++) - channels[i] = new channel_t(); - } - - static void WriteLinearBlastStereo16() - { - int i; - int val; - - for (i=0 ; i>8; - if (val > 0x7fff) - snd_out.put(i, (short)0x7fff); - else if (val < (short)0x8000) - snd_out.put(i,(short)0x8000); - else - snd_out.put(i, (short)val); - - val = snd_p.get(i+1)>>8; - if (val > 0x7fff) - snd_out.put(i+1, (short)0x7fff); - else if (val < (short)0x8000) - snd_out.put(i+1, (short)0x8000); - else - snd_out.put(i+1, (short)val); - } - } - - static void TransferStereo16(ByteBuffer pbuf, int endtime) - { - int lpos; - int lpaintedtime; - - snd_p = paintbuffer; - lpaintedtime = paintedtime; - - while (lpaintedtime < endtime) - { - // handle recirculating buffer issues - lpos = lpaintedtime & ((dma.samples>>1)-1); - -// snd_out = (short *) pbuf + (lpos<<1); - snd_out = pbuf.asShortBuffer(); - snd_out.position(lpos<<1); - snd_out = snd_out.slice(); - - snd_linear_count = (dma.samples>>1) - lpos; - if (lpaintedtime + snd_linear_count > endtime) - snd_linear_count = endtime - lpaintedtime; - - snd_linear_count <<= 1; - - // write a linear blast of samples - WriteLinearBlastStereo16(); - - //snd_p += snd_linear_count; - paintbuffer.position(snd_linear_count); - snd_p = paintbuffer.slice(); - - lpaintedtime += (snd_linear_count>>1); - } - } - - /* - =================== - S_TransferPaintBuffer - - =================== - */ - static void TransferPaintBuffer(int endtime) - { - int out_idx; - int count; - int out_mask; - int p; - int step; - int val; - //unsigned long *pbuf; - - ByteBuffer pbuf = ByteBuffer.wrap(dma.buffer); - pbuf.order(ByteOrder.LITTLE_ENDIAN); - - if (SND_DMA.s_testsound.value != 0.0f) - { - int i; - int count2; - - // write a fixed sine wave - count2 = (endtime - paintedtime)*2; - int v; - for (i=0 ; i 0) - { - val = paintbuffer.get(p) >> 8; - p+= step; - if (val > 0x7fff) - val = 0x7fff; - else if (val < (short)0x8000) - val = (short)0x8000; - out.put(out_idx, (short)val); -//System.out.println(out_idx + " " + val); - out_idx = (out_idx + 1) & out_mask; - } - } - else if (dma.samplebits == 8) - { -// unsigned char *out = (unsigned char *) pbuf; - ByteBuffer out = pbuf; - while (count-- > 0) - { - val = paintbuffer.get(p) >> 8; - p += step; - if (val > 0x7fff) - val = 0x7fff; - else if (val < (short)0x8000) - val = (short)0x8000; - out.put(out_idx,(byte)(val>>>8)); - out_idx = (out_idx + 1) & out_mask; - } - } - } - } - - - /* - =============================================================================== - - CHANNEL MIXING - - =============================================================================== - */ - static void PaintChannels(int endtime) - { - int i; - int end; - channel_t ch; - sfxcache_t sc; - int ltime, count; - playsound_t ps; - - snd_vol = (int)(s_volume.value*256); - -// Com_Printf ("%i to %i\n", paintedtime, endtime); - while (paintedtime < endtime) - { - // if paintbuffer is smaller than DMA buffer - end = endtime; - if (endtime - paintedtime > PAINTBUFFER_SIZE) - end = paintedtime + PAINTBUFFER_SIZE; - - // start any playsounds - while (true) - { - ps = s_pendingplays.next; - if (ps == s_pendingplays) - break; // no more pending sounds - if (ps.begin <= paintedtime) - { - SND_DMA.IssuePlaysound(ps); - continue; - } - - if (ps.begin < end) - end = (int)ps.begin; // stop here - break; - } - - // clear the paint buffer - if (s_rawend < paintedtime) - { -// Com_Printf ("clear\n"); - for (i = 0; i < (end-paintedtime)*2; i++) { - paintbuffer.put(i, 0); - } - //memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t)); - } - else - { // copy from the streaming sound source - int s; - int stop; - - stop = (end < s_rawend) ? end : s_rawend; - - for (i=paintedtime ; i 0 && ch.sfx != null) - { - if (sc.width == 1)// FIXME; 8 bit asm is wrong now - PaintChannelFrom8(ch, sc, count, ltime - paintedtime); - else - PaintChannelFrom16(ch, sc, count, ltime - paintedtime); - - ltime += count; - } - - // if at end of loop, restart - if (ltime >= ch.end) - { - if (ch.autosound) - { // autolooping sounds always go back to start - ch.pos = 0; - ch.end = ltime + sc.length; - } - else if (sc.loopstart >= 0) - { - ch.pos = sc.loopstart; - ch.end = ltime + sc.length - ch.pos; - } - else - { // channel just stopped - ch.sfx = null; - } - } - } - - } - - // transfer out according to DMA format - TransferPaintBuffer(end); - paintedtime = end; - } - } - - static void InitScaletable () - { - int i, j; - int scale; - - s_volume.modified = false; - for (i=0 ; i<32 ; i++) - { - scale = (int)(i * 8 * 256 * s_volume.value); - for (j=0 ; j<256 ; j++) - snd_scaletable[i][j] = ((byte)j) * scale; - } - } - - static void PaintChannelFrom8(channel_t ch, sfxcache_t sc, int count, int offset) - { - int data; - int[] lscale; - int[] rscale; - int sfx; - int i; - portable_samplepair_t samp; - - if (ch.leftvol > 255) - ch.leftvol = 255; - if (ch.rightvol > 255) - ch.rightvol = 255; - - //ZOID-- >>11 has been changed to >>3, >>11 didn't make much sense - //as it would always be zero. - lscale = snd_scaletable[ ch.leftvol >> 3]; - rscale = snd_scaletable[ ch.rightvol >> 3]; - sfx = ch.pos; - - //samp = paintbuffer[offset]; - - for (i=0 ; i>8; - right += (data * rightvol)>>8; - paintbuffer.put(offset*2, left); - paintbuffer.put(offset*2+1, right); - } - - ch.pos += count; - } + static final int MAX_CHANNELS = 32; + + static final int MAX_RAW_SAMPLES = 8192; + + static class playsound_t { + playsound_t prev, next; + + sfx_t sfx; + + float volume; + + float attenuation; + + int entnum; + + int entchannel; + + boolean fixed_origin; // use origin field instead of entnum's origin + + float[] origin = { 0, 0, 0 }; + + long begin; // begin on this sample + + public void clear() { + prev = next = null; + sfx = null; + volume = attenuation = begin = entnum = entchannel = 0; + fixed_origin = false; + Math3D.VectorClear(origin); + } + }; + + static class channel_t { + sfx_t sfx; // sfx number + + int leftvol; // 0-255 volume + + int rightvol; // 0-255 volume + + int end; // end time in global paintsamples + + int pos; // sample position in sfx + + int looping; // where to loop, -1 = no looping OBSOLETE? + + int entnum; // to allow overriding a specific sound + + int entchannel; // + + float[] origin = { 0, 0, 0 }; // only use if fixed_origin is set + + float dist_mult; // distance multiplier (attenuation/clipK) + + int master_vol; // 0-255 master volume + + boolean fixed_origin; // use origin instead of fetching entnum's origin + + boolean autosound; // from an entity->sound, cleared each frame + + void clear() { + sfx = null; + dist_mult = leftvol = rightvol = end = pos = looping = entnum = entchannel = master_vol = 0; + Math3D.VectorClear(origin); + fixed_origin = autosound = false; + } + }; + + static class portable_samplepair_t { + int left; + + int right; + }; + + static cvar_t s_volume; + + static int s_rawend; + + //// snd_mix.c -- portable code to mix sounds for snd_dma.c + // + // #include "client.h" + // #include "snd_loc.h" + // + static final int PAINTBUFFER_SIZE = 2048; + + //static portable_samplepair_t[] paintbuffer = new + // portable_samplepair_t[PAINTBUFFER_SIZE]; + static IntBuffer paintbuffer = IntBuffer.allocate(PAINTBUFFER_SIZE * 2); + + static int[][] snd_scaletable = new int[32][256]; + + // int *snd_p, snd_linear_count, snd_vol; + // short *snd_out; + static IntBuffer snd_p; + + static ShortBuffer snd_out; + + static int snd_linear_count; + + static int snd_vol; + + static int paintedtime; // sample PAIRS + + static playsound_t s_pendingplays = new playsound_t(); + + //static portable_samplepair_t[] s_rawsamples = new + // portable_samplepair_t[MAX_RAW_SAMPLES]; + static IntBuffer s_rawsamples = IntBuffer.allocate(MAX_RAW_SAMPLES * 2); + + static channel_t[] channels = new channel_t[MAX_CHANNELS]; + static { + for (int i = 0; i < MAX_CHANNELS; i++) + channels[i] = new channel_t(); + } + + static void WriteLinearBlastStereo16() { + int i; + int val; + + for (i = 0; i < snd_linear_count; i += 2) { + val = snd_p.get(i) >> 8; + if (val > 0x7fff) + snd_out.put(i, (short) 0x7fff); + else if (val < (short) 0x8000) + snd_out.put(i, (short) 0x8000); + else + snd_out.put(i, (short) val); + + val = snd_p.get(i + 1) >> 8; + if (val > 0x7fff) + snd_out.put(i + 1, (short) 0x7fff); + else if (val < (short) 0x8000) + snd_out.put(i + 1, (short) 0x8000); + else + snd_out.put(i + 1, (short) val); + } + } + + static void TransferStereo16(ByteBuffer pbuf, int endtime) { + int lpos; + int lpaintedtime; + + snd_p = paintbuffer; + lpaintedtime = paintedtime; + + while (lpaintedtime < endtime) { + // handle recirculating buffer issues + lpos = lpaintedtime & ((dma.samples >> 1) - 1); + + // snd_out = (short *) pbuf + (lpos<<1); + snd_out = pbuf.asShortBuffer(); + snd_out.position(lpos << 1); + snd_out = snd_out.slice(); + + snd_linear_count = (dma.samples >> 1) - lpos; + if (lpaintedtime + snd_linear_count > endtime) + snd_linear_count = endtime - lpaintedtime; + + snd_linear_count <<= 1; + + // write a linear blast of samples + WriteLinearBlastStereo16(); + + //snd_p += snd_linear_count; + paintbuffer.position(snd_linear_count); + snd_p = paintbuffer.slice(); + + lpaintedtime += (snd_linear_count >> 1); + } + } + + /* + * =================== S_TransferPaintBuffer + * + * =================== + */ + static void TransferPaintBuffer(int endtime) { + int out_idx; + int count; + int out_mask; + int p; + int step; + int val; + //unsigned long *pbuf; + + ByteBuffer pbuf = ByteBuffer.wrap(dma.buffer); + pbuf.order(ByteOrder.LITTLE_ENDIAN); + + if (SND_DMA.s_testsound.value != 0.0f) { + int i; + int count2; + + // write a fixed sine wave + count2 = (endtime - paintedtime) * 2; + int v; + for (i = 0; i < count2; i += 2) { + v = (int) (Math.sin((paintedtime + i) * 0.1) * 20000 * 256); + paintbuffer.put(i, v); + paintbuffer.put(i + 1, v); + } + } + + if (dma.samplebits == 16 && dma.channels == 2) { // optimized case + TransferStereo16(pbuf, endtime); + } else { // general case + p = 0; + count = (endtime - paintedtime) * dma.channels; + out_mask = dma.samples - 1; + out_idx = paintedtime * dma.channels & out_mask; + step = 3 - dma.channels; + + if (dma.samplebits == 16) { + // short *out = (short *) pbuf; + ShortBuffer out = pbuf.asShortBuffer(); + while (count-- > 0) { + val = paintbuffer.get(p) >> 8; + p += step; + if (val > 0x7fff) + val = 0x7fff; + else if (val < (short) 0x8000) + val = (short) 0x8000; + out.put(out_idx, (short) val); + //System.out.println(out_idx + " " + val); + out_idx = (out_idx + 1) & out_mask; + } + } else if (dma.samplebits == 8) { + // unsigned char *out = (unsigned char *) pbuf; + ByteBuffer out = pbuf; + while (count-- > 0) { + val = paintbuffer.get(p) >> 8; + p += step; + if (val > 0x7fff) + val = 0x7fff; + else if (val < (short) 0x8000) + val = (short) 0x8000; + out.put(out_idx, (byte) (val >>> 8)); + out_idx = (out_idx + 1) & out_mask; + } + } + } + } + + /* + * =============================================================================== + * + * CHANNEL MIXING + * + * =============================================================================== + */ + static void PaintChannels(int endtime) { + int i; + int end; + channel_t ch; + sfxcache_t sc; + int ltime, count; + playsound_t ps; + + snd_vol = (int) (s_volume.value * 256); + + // Com_Printf ("%i to %i\n", paintedtime, endtime); + while (paintedtime < endtime) { + // if paintbuffer is smaller than DMA buffer + end = endtime; + if (endtime - paintedtime > PAINTBUFFER_SIZE) + end = paintedtime + PAINTBUFFER_SIZE; + + // start any playsounds + while (true) { + ps = s_pendingplays.next; + if (ps == s_pendingplays) + break; // no more pending sounds + if (ps.begin <= paintedtime) { + SND_DMA.IssuePlaysound(ps); + continue; + } + + if (ps.begin < end) + end = (int) ps.begin; // stop here + break; + } + + // clear the paint buffer + if (s_rawend < paintedtime) { + // Com_Printf ("clear\n"); + for (i = 0; i < (end - paintedtime) * 2; i++) { + paintbuffer.put(i, 0); + } + //memset(paintbuffer, 0, (end - paintedtime) * + // sizeof(portable_samplepair_t)); + } else { // copy from the streaming sound source + int s; + int stop; + + stop = (end < s_rawend) ? end : s_rawend; + + for (i = paintedtime; i < stop; i++) { + s = i & (MAX_RAW_SAMPLES - 1); + //paintbuffer[i-paintedtime] = s_rawsamples[s]; + paintbuffer.put((i - paintedtime) * 2, s_rawsamples + .get(2 * s)); + paintbuffer.put((i - paintedtime) * 2 + 1, s_rawsamples + .get(2 * s) + 1); + } + // if (i != end) + // Com_Printf ("partial stream\n"); + // else + // Com_Printf ("full stream\n"); + for (; i < end; i++) { + //paintbuffer[i-paintedtime].left = + //paintbuffer[i-paintedtime].right = 0; + paintbuffer.put((i - paintedtime) * 2, 0); + paintbuffer.put((i - paintedtime) * 2 + 1, 0); + } + } + + // paint in the channels. + //ch = channels; + for (i = 0; i < MAX_CHANNELS; i++) { + ch = channels[i]; + ltime = paintedtime; + + while (ltime < end) { + if (ch.sfx == null || (ch.leftvol == 0 && ch.rightvol == 0)) + break; + + // max painting is to the end of the buffer + count = end - ltime; + + // might be stopped by running out of data + if (ch.end - ltime < count) + count = ch.end - ltime; + + sc = WaveLoader.LoadSound(ch.sfx); + if (sc == null) + break; + + if (count > 0 && ch.sfx != null) { + if (sc.width == 1)// FIXME; 8 bit asm is wrong now + PaintChannelFrom8(ch, sc, count, ltime + - paintedtime); + else + PaintChannelFrom16(ch, sc, count, ltime + - paintedtime); + + ltime += count; + } + + // if at end of loop, restart + if (ltime >= ch.end) { + if (ch.autosound) { // autolooping sounds always go back + // to start + ch.pos = 0; + ch.end = ltime + sc.length; + } else if (sc.loopstart >= 0) { + ch.pos = sc.loopstart; + ch.end = ltime + sc.length - ch.pos; + } else { // channel just stopped + ch.sfx = null; + } + } + } + + } + + // transfer out according to DMA format + TransferPaintBuffer(end); + paintedtime = end; + } + } + + static void InitScaletable() { + int i, j; + int scale; + + s_volume.modified = false; + for (i = 0; i < 32; i++) { + scale = (int) (i * 8 * 256 * s_volume.value); + for (j = 0; j < 256; j++) + snd_scaletable[i][j] = ((byte) j) * scale; + } + } + + static void PaintChannelFrom8(channel_t ch, sfxcache_t sc, int count, + int offset) { + int data; + int[] lscale; + int[] rscale; + int sfx; + int i; + portable_samplepair_t samp; + + if (ch.leftvol > 255) + ch.leftvol = 255; + if (ch.rightvol > 255) + ch.rightvol = 255; + + //ZOID-- >>11 has been changed to >>3, >>11 didn't make much sense + //as it would always be zero. + lscale = snd_scaletable[ch.leftvol >> 3]; + rscale = snd_scaletable[ch.rightvol >> 3]; + sfx = ch.pos; + + //samp = paintbuffer[offset]; + + for (i = 0; i < count; i++, offset++) { + int left = paintbuffer.get(offset * 2); + int right = paintbuffer.get(offset * 2 + 1); + data = sc.data[sfx + i]; + left += lscale[data]; + right += rscale[data]; + paintbuffer.put(offset * 2, left); + paintbuffer.put(offset * 2 + 1, right); + } + + ch.pos += count; + } + + private static ByteBuffer bb; + + private static ShortBuffer sb; + + static void PaintChannelFrom16(channel_t ch, sfxcache_t sc, int count, + int offset) { + int data; + int left, right; + int leftvol, rightvol; + int sfx; + int i; + portable_samplepair_t samp; + + leftvol = ch.leftvol * snd_vol; + rightvol = ch.rightvol * snd_vol; + ByteBuffer bb = ByteBuffer.wrap(sc.data); + bb.order(ByteOrder.LITTLE_ENDIAN); + sb = bb.asShortBuffer(); + sfx = ch.pos; + + //samp = paintbuffer[offset]; + for (i = 0; i < count; i++, offset++) { + left = paintbuffer.get(offset * 2); + right = paintbuffer.get(offset * 2 + 1); + data = sb.get(sfx + i); + left += (data * leftvol) >> 8; + right += (data * rightvol) >> 8; + paintbuffer.put(offset * 2, left); + paintbuffer.put(offset * 2 + 1, right); + } + + ch.pos += count; + } } \ No newline at end of file diff --git a/src/jake2/sys/IN.java b/src/jake2/sys/IN.java index 6f74ab4..2c70d53 100644 --- a/src/jake2/sys/IN.java +++ b/src/jake2/sys/IN.java @@ -2,27 +2,27 @@ * IN.java * Copyright (C) 2003 * - * $Id: IN.java,v 1.4 2004-09-08 09:37:39 hzi Exp $ + * $Id: IN.java,v 1.5 2004-09-22 19:22:14 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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.sys; import jake2.Globals; @@ -32,8 +32,11 @@ import jake2.game.Cmd; import jake2.game.usercmd_t; import jake2.qcommon.Cvar; import jake2.qcommon.xcommand_t; +import jake2.util.Math3D; -import java.awt.*; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Point; import javax.swing.ImageIcon; @@ -42,167 +45,192 @@ import javax.swing.ImageIcon; */ public final class IN extends Globals { - static Component c = null; - static Cursor emptyCursor = null; - - static boolean mouse_avail = true; - static boolean mouse_active = false; - static boolean ignorefirst = false; - - static int mouse_buttonstate; - static int mouse_oldbuttonstate; - - static int old_mouse_x; - static int old_mouse_y; - - static boolean mlooking; - - public static void ActivateMouse() { - if (!mouse_avail || c == null) return; - if (!mouse_active) { - KBD.mx = KBD.my = 0; // don't spazz - install_grabs(); - mouse_active = true; - } - } - - public static void DeactivateMouse() { - // if (!mouse_avail || c == null) return; - if (mouse_active) { - uninstall_grabs(); - mouse_active = false; - } - } - - private static void install_grabs() { - if (emptyCursor == null) { - ImageIcon emptyIcon = new ImageIcon(new byte[0]); - emptyCursor = c.getToolkit().createCustomCursor(emptyIcon.getImage(), new Point(0, 0), "emptyCursor"); - } - c.setCursor(emptyCursor); - KBD.centerMouse(); - - ignorefirst = true; - } - - private static void uninstall_grabs() { - c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - - public static void toggleMouse() { - if (mouse_avail) { - mouse_avail=false; - DeactivateMouse(); - } else { - mouse_avail=true; - ActivateMouse(); - } - } - - public static void Init() { - in_mouse = Cvar.Get("in_mouse", "1", CVAR_ARCHIVE); - in_joystick = Cvar.Get("in_joystick", "0", CVAR_ARCHIVE); - } - - public static void Shutdown() { - mouse_avail = false; - } - - public static void Real_IN_Init() { - // mouse variables - Globals.m_filter = Cvar.Get("m_filter", "0", 0); - Globals.in_mouse = Cvar.Get("in_mouse", "1", CVAR_ARCHIVE); - Globals.freelook = Cvar.Get("freelook", "1", 0 ); - Globals.lookstrafe = Cvar.Get("lookstrafe", "0", 0); - Globals.sensitivity = Cvar.Get("sensitivity", "3", 0); - Globals.m_pitch = Cvar.Get("m_pitch", "0.022", 0); - Globals.m_yaw = Cvar.Get("m_yaw", "0.022", 0); - Globals.m_forward = Cvar.Get("m_forward", "1", 0); - Globals.m_side = Cvar.Get("m_side", "0.8", 0); - - Cmd.AddCommand("+mlook", new xcommand_t() { - public void execute() {MLookDown();}}); - Cmd.AddCommand("-mlook", new xcommand_t() { - public void execute() {MLookUp();}}); - - Cmd.AddCommand ("force_centerview", new xcommand_t() { - public void execute() {Force_CenterView_f();}}); - - Cmd.AddCommand ("togglemouse", new xcommand_t() { - public void execute() {toggleMouse();}}); - - IN.mouse_avail = true; - } - - public static void Commands() { - int i; - - if (!IN.mouse_avail) - return; - - for (i=0 ; i<3 ; i++) { - if ( (IN.mouse_buttonstate & (1<= fdir.length) - return null; - - return fdir[fileindex++]; - } - - public static void FindClose() { - fdir= null; - } - - public static void SendKeyEvents() { - KBD.Update(); - - // grab frame time - Globals.sys_frame_time= Sys.Milliseconds(); - } - - public static String GetClipboardData() { - // TODO: implement GetClipboardData - return null; - } - - public static void ConsoleOutput(String msg) { - if (Globals.nostdout != null && Globals.nostdout.value != 0) - return; - - System.out.print(msg); - } + public static void Error(String error) { + + CL.Shutdown(); + //StackTrace(); + new Exception(error).printStackTrace(); + System.exit(1); + } + + public static void Quit() { + CL.Shutdown(); + + System.exit(0); + } + + //ok! + public static File[] FindAll(String path, int musthave, int canthave) { + + int index = path.lastIndexOf('/'); + + if (index != -1) { + findbase = path.substring(0, index); + findpattern = path.substring(index + 1, path.length()); + } else { + findbase = path; + findpattern = "*"; + } + + if (findpattern.equals("*.*")) { + findpattern = "*"; + } + + File fdir = new File(findbase); + + if (!fdir.exists()) + return null; + + FilenameFilter filter = new FileFilter(findpattern, musthave, canthave); + + return fdir.listFiles(filter); + } + + /** + * Match the pattern findpattern against the filename. + * + * In the pattern string, `*' matches any sequence of characters, `?' + * matches any character, [SET] matches any character in the specified set, + * [!SET] matches any character not in the specified set. A set is composed + * of characters or ranges; a range looks like character hyphen character + * (as in 0-9 or A-Z). [0-9a-zA-Z_] is the set of characters allowed in C + * identifiers. Any other character in the pattern must be matched exactly. + * To suppress the special syntactic significance of any of `[]*?!-\', and + * match the character exactly, precede it with a `\'. + */ + static class FileFilter implements FilenameFilter { + + String regexpr; + + int musthave, canthave; + + FileFilter(String findpattern, int musthave, int canthave) { + this.regexpr = convert2regexpr(findpattern); + this.musthave = musthave; + this.canthave = canthave; + + } + + /* + * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String) + */ + public boolean accept(File dir, String name) { + if (name.matches(regexpr)) { + return CompareAttributes(dir, musthave, canthave); + } + return false; + } + + String convert2regexpr(String pattern) { + + StringBuffer sb = new StringBuffer(); + + char c; + boolean escape = false; + + String subst; + + // convert pattern + for (int i = 0; i < pattern.length(); i++) { + c = pattern.charAt(i); + subst = null; + switch (c) { + case '*': + subst = (!escape) ? ".*" : "*"; + break; + case '.': + subst = (!escape) ? "\\." : "."; + break; + case '!': + subst = (!escape) ? "^" : "!"; + break; + case '?': + subst = (!escape) ? "." : "?"; + break; + case '\\': + escape = !escape; + break; + default: + escape = false; + } + if (subst != null) { + sb.append(subst); + escape = false; + } else + sb.append(c); + } + + // the converted pattern + String regexpr = sb.toString(); + + //Com.DPrintf("pattern: " + pattern + " regexpr: " + regexpr + + // '\n'); + try { + Pattern.compile(regexpr); + } catch (PatternSyntaxException e) { + Com.Printf("invalid file pattern ( *.* is used instead )\n"); + return ".*"; // the default + } + return regexpr; + } + + boolean CompareAttributes(File dir, int musthave, int canthave) { + // . and .. never match + String name = dir.getName(); + + if (name.equals(".") || name.equals("..")) + return false; + + return true; + } + + } + + private static long secbase = System.currentTimeMillis(); + + public static int Milliseconds() { + return Globals.curtime = (int) (System.currentTimeMillis() - secbase); + } + + //============================================ + + static File[] fdir; + + static int fileindex; + + static String findbase; + + static String findpattern; + + // ok. + public static File FindFirst(String path, int musthave, int canthave) { + + if (fdir != null) + Sys.Error("Sys_BeginFind without close"); + + // COM_FilePath (path, findbase); + + fdir = FindAll(path, canthave, musthave); + fileindex = 0; + + if (fdir == null) + return null; + + return FindNext(); + } + + public static File FindNext() { + + if (fileindex >= fdir.length) + return null; + + return fdir[fileindex++]; + } + + public static void FindClose() { + fdir = null; + } + + public static void SendKeyEvents() { + KBD.Update(); + + // grab frame time + Globals.sys_frame_time = Sys.Milliseconds(); + } + + public static String GetClipboardData() { + // TODO: implement GetClipboardData + return null; + } + + public static void ConsoleOutput(String msg) { + if (Globals.nostdout != null && Globals.nostdout.value != 0) + return; + + System.out.print(msg); + } -} +} \ No newline at end of file diff --git a/src/jake2/util/Lib.java b/src/jake2/util/Lib.java index e0d1791..ab3a40e 100644 --- a/src/jake2/util/Lib.java +++ b/src/jake2/util/Lib.java @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Created on 09.12.2003 by RST. -// $Id: Lib.java,v 1.5 2004-07-23 10:09:55 hzi Exp $ +// $Id: Lib.java,v 1.6 2004-09-22 19:22:13 salomo Exp $ package jake2.util; @@ -48,11 +48,9 @@ public class Lib { public static String vtos(float[] v) { return (int) v[0] + " " + (int) v[1] + " " + (int) v[2]; } - public static String vtofs(float[] v) { return v[0] + " " + v[1] + " " + v[2]; } - public static String vtofsbeaty(float[] v) { return Com.sprintf("%8.2f %8.2f %8.2f", new Vargs().add(v[0]).add(v[1]).add(v[2])); } @@ -70,33 +68,28 @@ public class Lib { public static float crand() { return (Globals.rnd.nextFloat() - 0.5f) * 2.0f; } - public static int strcmp(String in1, String in2) { return in1.compareTo(in2); } - public static boolean strstr(String i1, String i2) { return (i1.indexOf(i2) != -1); } - public static float atof(String in) { float res = 0; - + try { res = Float.parseFloat(in); } catch (Exception e) { } - + return res; } - public static int Q_stricmp(String in1, String in2) { return in1.compareToIgnoreCase(in2); } - // ================================================================================= - + public static int atoi(String in) { try { return Integer.parseInt(in); @@ -105,51 +98,45 @@ public class Lib { return 0; } } - public static float[] atov(String v) { float[] res = { 0, 0, 0 }; - + int i1 = v.indexOf(" "); int i2 = v.indexOf(" ", i1 + 1); - + res[0] = atof(v.substring(0, i1)); res[1] = atof(v.substring(i1 + 1, i2)); res[2] = atof(v.substring(i2 + 1, v.length())); - + return res; } - public static int strlen(char in[]) { for (int i = 0; i < in.length; i++) if (in[i] == 0) return i; return in.length; } - public static int strlen(byte in[]) { for (int i = 0; i < in.length; i++) if (in[i] == 0) return i; return in.length; } - static byte[] buffer = new byte[Defines.MAX_INFO_STRING]; public static String readString(ByteBuffer bb, int len) { bb.get(buffer, 0, len); return new String(buffer, 0, len); } - public static String hexdumpfile(ByteBuffer bb, int len) throws IOException { - + ByteBuffer bb1 = bb.slice(); - + byte buf[] = new byte[len]; - + bb1.get(buf); - + return hexDump(buf, len, false); } - // dump data as hexstring public static String hexDump(byte data1[], int len, boolean showAddress) { StringBuffer result = new StringBuffer(); @@ -164,13 +151,13 @@ public class Lib { } } int v = data1[i]; - + result.append(hex2(v)); result.append(" "); - + charfield.append(readableChar(v)); i++; - + // nach dem letzten, newline einfuegen if ((i & 0xf) == 0) { result.append(charfield); @@ -184,41 +171,35 @@ public class Lib { } return result.toString(); } - //formats an hex byte public static String hex2(int i) { String val = Integer.toHexString(i & 0xff); return ("00".substring(0, 2 - val.length()) + val).toUpperCase(); } - public static char readableChar(int i) { if ((i < 0x20) || (i > 0x7f)) return '.'; else return (char) i; } - public static void printv(String in, float arr[]) { for (int n = 0; n < arr.length; n++) { Com.Println(in + "[" + n + "]: " + arr[n]); } } - static final byte nullfiller[] = new byte[8192]; - public static void fwriteString(String s, int len, RandomAccessFile f) throws IOException { if (s == null) return; int diff = len - s.length(); if (diff > 0) { f.write(s.getBytes()); - + f.write(nullfiller, 0, diff); } else f.write(s.getBytes(), 0, len); } - public static RandomAccessFile fopen(String name, String mode) { try { return new RandomAccessFile(name, mode); @@ -228,7 +209,6 @@ public class Lib { return null; } } - public static void fclose(RandomAccessFile f) { try { f.close(); @@ -236,14 +216,12 @@ public class Lib { catch (Exception e) { } } - public static String freadString(RandomAccessFile f, int len) { byte buffer[] = new byte[len]; FS.Read(buffer, len, f); - + return new String(buffer).trim(); } - public static String rightFrom(String in, char c) { int pos = in.lastIndexOf(c); if (pos == -1) @@ -252,7 +230,6 @@ public class Lib { return in.substring(pos + 1, in.length()); return ""; } - public static String leftFrom(String in, char c) { int pos = in.lastIndexOf(c); if (pos == -1) @@ -261,25 +238,23 @@ public class Lib { return in.substring(0, pos); return ""; } - public static String[] linesplit(String in) { - + StringTokenizer tk = new StringTokenizer(in, "\r\n"); - + int count = tk.countTokens(); if (count == 0) return new String[] { }; - + String result[] = new String[count]; - + for (int i = 0; tk.hasMoreTokens(); i++) { result[i] = tk.nextToken(); } - + return result; } - public static int rename(String oldn, String newn) { try { File f1 = new File(oldn); @@ -291,7 +266,6 @@ public class Lib { return 1; } } - public static byte[] getIntBytes(int c) { byte b[] = new byte[4]; b[0] = (byte) ((c & 0xff)); @@ -300,57 +274,48 @@ public class Lib { b[3] = (byte) ((c >>> 24) & 0xff); return b; } - public static int getInt(byte b[]) { return (b[0] & 0xff) | ((b[1] & 0xff) << 8) | ((b[2] & 0xff) << 16) | ((b[3] & 0xff) << 24); } - public static float[] clone(float in[]) { float out[] = new float[in.length]; - + if (in.length != 0) System.arraycopy(in, 0, out, 0, in.length); - + return out; } - + /* * java.nio.* Buffer util functions */ public static final int SIZEOF_FLOAT = BufferUtils.SIZEOF_FLOAT; public static final int SIZEOF_INT = BufferUtils.SIZEOF_INT; - public static FloatBuffer newFloatBuffer(int numElements) { ByteBuffer bb = newByteBuffer(numElements * SIZEOF_FLOAT); return bb.asFloatBuffer(); } - public static FloatBuffer newFloatBuffer(int numElements, ByteOrder order) { ByteBuffer bb = newByteBuffer(numElements * SIZEOF_FLOAT, order); return bb.asFloatBuffer(); } - public static IntBuffer newIntBuffer(int numElements) { ByteBuffer bb = newByteBuffer(numElements * SIZEOF_INT); return bb.asIntBuffer(); } - public static IntBuffer newIntBuffer(int numElements, ByteOrder order) { ByteBuffer bb = newByteBuffer(numElements * SIZEOF_INT, order); return bb.asIntBuffer(); } - public static ByteBuffer newByteBuffer(int numElements) { ByteBuffer bb = ByteBuffer.allocateDirect(numElements); bb.order(ByteOrder.nativeOrder()); return bb; } - public static ByteBuffer newByteBuffer(int numElements, ByteOrder order) { ByteBuffer bb = ByteBuffer.allocateDirect(numElements); bb.order(order); return bb; } - } diff --git a/src/jake2/util/Math3D.java b/src/jake2/util/Math3D.java index 5c1f2eb..fc94614 100644 --- a/src/jake2/util/Math3D.java +++ b/src/jake2/util/Math3D.java @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Created on 09.12.2003 by RST. -// $Id: Math3D.java,v 1.6 2004-09-10 19:02:56 salomo Exp $ +// $Id: Math3D.java,v 1.7 2004-09-22 19:22:13 salomo Exp $ package jake2.util; @@ -27,60 +27,50 @@ import jake2.Defines; import jake2.game.cplane_t; import jake2.qcommon.Com; -public class Math3D extends Lib { - +public class Math3D { + static final float shortratio = 360.0f / 65536.0f; - static final float piratio = (float)(Math.PI / 360.0); - + static final float piratio = (float) (Math.PI / 360.0); public static void set(float v1[], float v2[]) { v1[0] = v2[0]; v1[1] = v2[1]; v1[2] = v2[2]; } - - public static void VectorSubtract(float[] a, float[] b, float[] c) { c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; } - public static void VectorSubtract(short[] a, short[] b, int[] c) { c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; } - public static void VectorAdd(float[] a, float[] b, float[] to) { to[0] = a[0] + b[0]; to[1] = a[1] + b[1]; to[2] = a[2] + b[2]; } - public static void VectorCopy(float[] from, float[] to) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; } - public static void VectorCopy(short[] from, short[] to) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; } - public static void VectorCopy(short[] from, float[] to) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; } - public static void VectorCopy(float[] from, short[] to) { to[0] = (short) from[0]; to[1] = (short) from[1]; to[2] = (short) from[2]; } - public static void VectorClear(float[] a) { a[0] = a[1] = a[2] = 0; } @@ -116,7 +106,6 @@ public class Math3D extends Lib { } return length; } - public static final float VectorLength(float v[]) { return (float) Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); } @@ -130,7 +119,6 @@ public class Math3D extends Lib { out[1] = in[1] * scale; out[2] = in[2] * scale; } - public static float vectoyaw(float[] vec) { float yaw; @@ -151,7 +139,6 @@ public class Math3D extends Lib { return yaw; } - public static void vectoangles(float[] value1, float[] angles) { float yaw, pitch; @@ -183,14 +170,12 @@ public class Math3D extends Lib { angles[Defines.YAW] = yaw; angles[Defines.ROLL] = 0; } - private static float m[][] = new float[3][3]; private static float im[][] = new float[3][3]; private static float tmpmat[][] = new float[3][3]; private static float zrot[][] = new float[3][3]; - public static void RotatePointAroundVector(float[] dst, float[] dir, float[] point, float degrees) { - + float[] vr = { 0.0f, 0.0f, 0.0f }; float[] vup = { 0.0f, 0.0f, 0.0f }; float[] vf = { 0.0f, 0.0f, 0.0f }; @@ -199,8 +184,8 @@ public class Math3D extends Lib { vf[1] = dir[1]; vf[2] = dir[2]; - Math3D.PerpendicularVector(vr, dir); - Math3D.CrossProduct(vr, vf, vup); + PerpendicularVector(vr, dir); + CrossProduct(vr, vf, vup); m[0][0] = vr[0]; m[1][0] = vr[1]; @@ -228,19 +213,17 @@ public class Math3D extends Lib { zrot[2][2] = 1.0F; - zrot[0][0] = zrot[1][1] = (float) Math.cos(Math3D.DEG2RAD(degrees)); - zrot[0][1] = (float) Math.sin(Math3D.DEG2RAD(degrees)); + zrot[0][0] = zrot[1][1] = (float) Math.cos(DEG2RAD(degrees)); + zrot[0][1] = (float) Math.sin(DEG2RAD(degrees)); zrot[1][0] = -zrot[0][1]; - Math3D.R_ConcatRotations(m, zrot, tmpmat); - Math3D.R_ConcatRotations(tmpmat, im, zrot); + R_ConcatRotations(m, zrot, tmpmat); + R_ConcatRotations(tmpmat, im, zrot); for (int i = 0; i < 3; i++) { dst[i] = zrot[i][0] * point[0] + zrot[i][1] * point[1] + zrot[i][2] * point[2]; } } - - public static void MakeNormalVectors(float[] forward, float[] right, float[] up) { // this rotate and negat guarantees a vector // not colinear with the original @@ -253,12 +236,9 @@ public class Math3D extends Lib { VectorNormalize(right); CrossProduct(right, forward, up); } - - public static float SHORT2ANGLE(int x) { return (x * shortratio); } - /* ================ R_ConcatTransforms @@ -278,7 +258,6 @@ public class Math3D extends Lib { out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3]; } - /** * concatenates 2 matrices each [3][3]. */ @@ -293,12 +272,11 @@ public class Math3D extends Lib { out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; } - public static void ProjectPointOnPlane(float[] dst, float[] p, float[] normal) { - float inv_denom = 1.0F / Math3D.DotProduct(normal, normal); + float inv_denom = 1.0F / DotProduct(normal, normal); - float d = Math3D.DotProduct(normal, p) * inv_denom; + float d = DotProduct(normal, p) * inv_denom; dst[0] = normal[0] * inv_denom; dst[1] = normal[1] * inv_denom; @@ -308,14 +286,12 @@ public class Math3D extends Lib { dst[1] = p[1] - d * dst[1]; dst[2] = p[2] - d * dst[2]; } - /** assumes "src" is normalized */ public static void PerpendicularVector(float[] dst, float[] src) { int pos; int i; float minelem = 1.0F; - // find the smallest magnitude axially aligned vector for (pos = 0, i = 0; i < 3; i++) { if (Math.abs(src[i]) < minelem) { @@ -330,18 +306,17 @@ public class Math3D extends Lib { ProjectPointOnPlane(dst, tempvec, src); //normalize the result - Math3D.VectorNormalize(dst); + VectorNormalize(dst); } - //===================================================================== /** stellt fest, auf welcher Seite sich die Kiste befindet, wenn die Ebene durch Entfernung und Senkrechten-Normale gegeben ist. erste Version mit vec3_t... */ public static final int BoxOnPlaneSide(float emins[], float emaxs[], cplane_t p) { - - assert (emins.length == 3 && emaxs.length == 3) : "vec3_t bug"; - + + assert(emins.length == 3 && emaxs.length == 3) : "vec3_t bug"; + float dist1, dist2; int sides; @@ -390,7 +365,7 @@ public class Math3D extends Lib { break; default : dist1 = dist2 = 0; - assert (false) : "BoxOnPlaneSide bug"; + assert(false) : "BoxOnPlaneSide bug"; break; } @@ -400,15 +375,13 @@ public class Math3D extends Lib { if (dist2 < p.dist) sides |= 2; - assert (sides != 0) : "BoxOnPlaneSide(): sides == 0 bug"; + assert(sides != 0) : "BoxOnPlaneSide(): sides == 0 bug"; return sides; - } - + } // this is the slow, general version private static float corners[][] = new float[2][3]; public static final int BoxOnPlaneSide2(float[] emins, float[] emaxs, cplane_t p) { - for (int i = 0; i < 3; i++) { if (p.normal[i] < 0) { @@ -420,8 +393,8 @@ public class Math3D extends Lib { corners[0][i] = emaxs[i]; } } - float dist1 = Math3D.DotProduct(p.normal, corners[0]) - p.dist; - float dist2 = Math3D.DotProduct(p.normal, corners[1]) - p.dist; + float dist1 = DotProduct(p.normal, corners[0]) - p.dist; + float dist2 = DotProduct(p.normal, corners[1]) - p.dist; int sides = 0; if (dist1 >= 0) sides = 1; @@ -430,7 +403,6 @@ public class Math3D extends Lib { return sides; } - public static void AngleVectors(float[] angles, float[] forward, float[] right, float[] up) { float cr = 2.0f * piratio; @@ -464,56 +436,39 @@ public class Math3D extends Lib { } } } - - public static void G_ProjectSource(float[] point, float[] distance, float[] forward, float[] right, float[] result) { + public static void G_ProjectSource( + float[] point, + float[] distance, + float[] forward, + float[] right, + float[] result) { result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1]; result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1]; result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2]; } - - - public static final float DotProduct(float[] x, float[] y) { return x[0] * y[0] + x[1] * y[1] + x[2] * y[2]; } - - - public static void CrossProduct(float[] v1, float[] v2, float[] cross) { cross[0] = v1[1] * v2[2] - v1[2] * v2[1]; cross[1] = v1[2] * v2[0] - v1[0] * v2[2]; cross[2] = v1[0] * v2[1] - v1[1] * v2[0]; } - - - public static int Q_log2(int val) { int answer = 0; while ((val >>= 1) > 0) answer++; return answer; } - - - public static float DEG2RAD(float in) { return (in * (float) Math.PI) / 180.0f; } - - - public static float anglemod(float a) { return (float) (shortratio) * ((int) (a / (shortratio)) & 65535); } - - - public static int ANGLE2SHORT(float x) { return ((int) ((x) / shortratio) & 65535); } - - - public static float LerpAngle(float a2, float a1, float frac) { if (a1 - a2 > 180) a1 -= 360; @@ -521,8 +476,6 @@ public class Math3D extends Lib { a1 += 360; return a2 + frac * (a1 - a2); } - - public static float CalcFov(float fov_x, float width, float height) { double a = 0.0f; double x; @@ -536,6 +489,6 @@ public class Math3D extends Lib { a = a / piratio; - return (float)a; + return (float) a; } } diff --git a/src/jake2/util/QuakeFile.java b/src/jake2/util/QuakeFile.java index 5b3c11b..3efcada 100644 --- a/src/jake2/util/QuakeFile.java +++ b/src/jake2/util/QuakeFile.java @@ -1,182 +1,166 @@ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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 24.07.2004 by RST. -// $Id: QuakeFile.java,v 1.3 2004-09-10 19:02:56 salomo Exp $ - +// $Id: QuakeFile.java,v 1.4 2004-09-22 19:22:13 salomo Exp $ package jake2.util; -import jake2.game.Game; +import jake2.game.GameAI; +import jake2.game.GameBase; import jake2.game.SuperAdapter; import jake2.game.edict_t; import jake2.game.gitem_t; import jake2.qcommon.Com; -import java.io.*; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; -/** - * RandomAccessFile, but handles readString/WriteString specially and - * offers other helper functions +/** + * RandomAccessFile, but handles readString/WriteString specially and offers + * other helper functions */ -public class QuakeFile extends RandomAccessFile -{ - - /** Standard Constructor.*/ - public QuakeFile(String filename, String mode) throws FileNotFoundException - { - super(filename, mode); - } - - /** Writes a Vector to a RandomAccessFile. */ - public void writeVector(float v[]) throws IOException - { - for (int n= 0; n < 3; n++) - writeFloat(v[n]); - } - - /** Writes a Vector to a RandomAccessFile. */ - public float[] readVector() throws IOException - { - float res[]= { 0, 0, 0 }; - for (int n= 0; n < 3; n++) - res[n]= readFloat(); - - return res; - } - - /** Reads a length specified string from a file. */ - public String readString() throws IOException - { - int len= readInt(); - - if (len == -1) - return null; - - if (len == 0) - return ""; - - byte bb[]= new byte[len]; - - super.read(bb, 0, len); - - return new String(bb, 0, len); - } - - /** Writes a length specified string to a file. */ - public void writeString(String s) throws IOException - { - if (s == null) - { - writeInt(-1); - return; - } - - writeInt(s.length()); - if (s.length() != 0) - writeBytes(s); - } - - /** Writes the edict reference. */ - public void writeEdictRef(edict_t ent) throws IOException - { - if (ent == null) - writeInt(-1); - else - { - writeInt(ent.s.number); - } - } - - /** - * Reads an edict index from a file and returns the edict. - */ - - public edict_t readEdictRef() throws IOException - { - int i= readInt(); - - // handle -1 - if (i < 0) - return null; - - if (i > Game.g_edicts.length) - { - Com.DPrintf("jake2: illegal edict num:" + i + "\n"); - return null; - } - - // valid edict. - return Game.g_edicts[i]; - } - - /** Writes the Adapter-ID to the file. */ - public void writeAdapter(SuperAdapter a) throws IOException - { - writeInt(3988); - if (a == null) - writeString(null); - else - { - String str= a.getID(); - if (a == null) - { - Com.DPrintf("writeAdapter: invalid Adapter id for " + a + "\n"); - } - writeString(str); - } - } - - /** Reads the adapter id and returns the adapter. */ - public SuperAdapter readAdapter() throws IOException - { - if (readInt() != 3988) - Com.DPrintf("wrong read position: readadapter 3988 \n"); - - String id= readString(); - - if (id == null) - { - // null adapter. :-) - return null; - } - - return SuperAdapter.getFromID(id); - } - - /** Writes an item reference. */ - public void writeItem(gitem_t item) throws IOException - { - if (item == null) - writeInt(-1); - else - writeInt(item.index); - } - - /** Reads the item index and returns the game item. */ - public gitem_t readItem() throws IOException - { - int ndx= readInt(); - if (ndx == -1) - return null; - else - return Game.itemlist[ndx]; - } - -} +public class QuakeFile extends RandomAccessFile { + + /** Standard Constructor. */ + public QuakeFile(String filename, String mode) throws FileNotFoundException { + super(filename, mode); + } + + /** Writes a Vector to a RandomAccessFile. */ + public void writeVector(float v[]) throws IOException { + for (int n = 0; n < 3; n++) + writeFloat(v[n]); + } + + /** Writes a Vector to a RandomAccessFile. */ + public float[] readVector() throws IOException { + float res[] = { 0, 0, 0 }; + for (int n = 0; n < 3; n++) + res[n] = readFloat(); + + return res; + } + + /** Reads a length specified string from a file. */ + public String readString() throws IOException { + int len = readInt(); + + if (len == -1) + return null; + + if (len == 0) + return ""; + + byte bb[] = new byte[len]; + + super.read(bb, 0, len); + + return new String(bb, 0, len); + } + + /** Writes a length specified string to a file. */ + public void writeString(String s) throws IOException { + if (s == null) { + writeInt(-1); + return; + } + + writeInt(s.length()); + if (s.length() != 0) + writeBytes(s); + } + + /** Writes the edict reference. */ + public void writeEdictRef(edict_t ent) throws IOException { + if (ent == null) + writeInt(-1); + else { + writeInt(ent.s.number); + } + } + + /** + * Reads an edict index from a file and returns the edict. + */ + + public edict_t readEdictRef() throws IOException { + int i = readInt(); + + // handle -1 + if (i < 0) + return null; + + if (i > GameBase.g_edicts.length) { + Com.DPrintf("jake2: illegal edict num:" + i + "\n"); + return null; + } + + // valid edict. + return GameBase.g_edicts[i]; + } + + /** Writes the Adapter-ID to the file. */ + public void writeAdapter(SuperAdapter a) throws IOException { + writeInt(3988); + if (a == null) + writeString(null); + else { + String str = a.getID(); + if (a == null) { + Com.DPrintf("writeAdapter: invalid Adapter id for " + a + "\n"); + } + writeString(str); + } + } + + /** Reads the adapter id and returns the adapter. */ + public SuperAdapter readAdapter() throws IOException { + if (readInt() != 3988) + Com.DPrintf("wrong read position: readadapter 3988 \n"); + + String id = readString(); + + if (id == null) { + // null adapter. :-) + return null; + } + + return SuperAdapter.getFromID(id); + } + + /** Writes an item reference. */ + public void writeItem(gitem_t item) throws IOException { + if (item == null) + writeInt(-1); + else + writeInt(item.index); + } + + /** Reads the item index and returns the game item. */ + public gitem_t readItem() throws IOException { + int ndx = readInt(); + if (ndx == -1) + return null; + else + return GameAI.itemlist[ndx]; + } + +} \ No newline at end of file -- cgit v1.2.3