📄 gameutil.java
字号:
/* * 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.15 2005/12/27 21:02:31 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 { public static void checkClassname(edict_t ent) { if (ent.classname == null) { Com.Printf("edict with classname = null: " + ent.index); } } /** * Use the targets. * * 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 = 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; } GameBase.g_edicts[ed.index] = new edict_t(ed.index); 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); } /** * 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 GameCombat.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 } /** * Returns true, if two edicts are on the same team. */ 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; } /** * Returns the team string of an entity * with respect to rteam_by_model and team_by_skin. */ 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 ValidateSelectedItem(edict_t ent) { gclient_t cl; cl = ent.client; if (cl.pers.inventory[cl.pers.selected_item] != 0) return; // valid GameItems.SelectNextItem(ent, -1); } /** * 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. */ public 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; } static void AttackFinished(edict_t self, float time) { self.monsterinfo.attack_finished = GameBase.level.time + time; } /** * Returns true if the entity is in front (in sight) of self */ public 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; } /** * 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; } /** * Finds a target. * * Self is currently not attacking anything, so try to find a target *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -