/* * 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.4 2004-09-22 19:22:03 salomo Exp $ package jake2.game; import java.util.Calendar; 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; } }; }