diff options
Diffstat (limited to 'src/jake2/game/GameMiscAdapters.java')
-rw-r--r-- | src/jake2/game/GameMiscAdapters.java | 1016 |
1 files changed, 1016 insertions, 0 deletions
diff --git a/src/jake2/game/GameMiscAdapters.java b/src/jake2/game/GameMiscAdapters.java new file mode 100644 index 0000000..c4322d3 --- /dev/null +++ b/src/jake2/game/GameMiscAdapters.java @@ -0,0 +1,1016 @@ +/* +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.1 2004-07-08 15:58:44 hzi 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.Date; + +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 + { + Date d = new Date(); + self.message = "" + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds(); + + /* + struct tm * ltime; + time_t gmtime; + + time(& gmtime); + ltime = localtime(& gmtime); + Com_sprintf(self.message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime.tm_hour, ltime.tm_min, ltime.tm_sec); + if (self.message[3] == ' ') + self.message[3] = '0'; + if (self.message[6] == ' ') + self.message[6] = '0'; + */ + } + + self.enemy.message = self.message; + self.enemy.use.use(self.enemy, self, self); + + if (((self.spawnflags & 1) != 0 && (self.health > self.wait)) + || ((self.spawnflags & 2) != 0 && (self.health < self.wait))) + { + if (self.pathtarget != null) + { + String savetarget; + String savemessage; + + savetarget = self.target; + savemessage = self.message; + self.target = self.pathtarget; + self.message = null; + 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; + } + }; +} |