gt:             if ((self.move_angles[Defines.YAW] < self.pos1[Defines.YAW])
context: /*
   * Copyright (C) 1997-2001 Id Software, Inc.
   * 
   * This program is free software; you can redistribute it and/or modify it under
   * the terms of the GNU General Public License as published by the Free Software
   * Foundation; either version 2 of the License, or (at your option) any later
   * version.
   * 
   * This program is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   * FOR A PARTICULAR PURPOSE.
   * 
   * See the GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public License along with
   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
   * Place - Suite 330, Boston, MA 02111-1307, USA.
   *  
   */
  
  
  
  package jake2.game;
  
  import jake2.Defines;
  import jake2.Globals;
  import jake2.game.monsters.M_Infantry;
  import jake2.util.Lib;
  import jake2.util.Math3D;
  
  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);
          GameWeapon.fire_rocket(self.teammaster.owner, start, f, damage, speed, 150,
                  damage);
          game_import_t.positioned_sound(start, self, Defines.CHAN_WEAPON,
                  game_import_t.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;
          game_import_t.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 = turret_blocked;
  
          self.think = turret_breach_finish_init;
          self.nextthink = GameBase.level.time + Defines.FRAMETIME;
          game_import_t.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;
          game_import_t.setmodel(self, self.model);
          self.blocked = turret_blocked;
          game_import_t.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 = game_import_t
                  .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 = 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 = GameItems.FindItemByClassname(GameBase.st.item);
              if (self.item == null)
                  game_import_t.dprintf(self.classname + " at "
                          + Lib.vtos(self.s.origin) + " has bad item: "
                          + GameBase.st.item + '\n');
          }
  
          self.think = turret_driver_link;
          self.nextthink = GameBase.level.time + Defines.FRAMETIME;
  
          game_import_t.linkentity(self);
      }
  
      static final EntBlockedAdapter turret_blocked = new EntBlockedAdapter() {
      	@Override
          public String getID() { return "turret_blocked"; }
          @Override
          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;
                  GameCombat.T_Damage(other, self, attacker, Globals.vec3_origin,
                          other.s.origin, Globals.vec3_origin,
                          self.teammaster.dmg, 10, 0, Defines.MOD_CRUSH);
              }
          }
      };
  
      static final EntThinkAdapter turret_breach_think = new EntThinkAdapter() {
      	@Override
          public String getID() { return "turret_breach_think"; }
          @Override
          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);
              AnglesNormalize(current_angles);
  
              AnglesNormalize(self.move_angles);
              if (self.move_angles[Defines.PITCH] > 180)
                  self.move_angles[Defines.PITCH] -= 360;
  
              
              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];
  
  