Merge branch 'master' into Mario/turrets
authorMario <zacjardine@y7mail.com>
Tue, 20 Jan 2015 01:28:40 +0000 (12:28 +1100)
committerMario <zacjardine@y7mail.com>
Tue, 20 Jan 2015 01:28:40 +0000 (12:28 +1100)
Conflicts:
qcsrc/common/command/generic.qc
qcsrc/common/notifications.qh
qcsrc/server/g_damage.qc
qcsrc/server/progs.src
qcsrc/server/tturrets/system/system_main.qc
qcsrc/server/tturrets/units/unit_ewheel.qc
qcsrc/server/tturrets/units/unit_flac.qc
qcsrc/server/tturrets/units/unit_machinegun.qc
qcsrc/server/tturrets/units/unit_walker.qc

30 files changed:
1  2 
qcsrc/client/Main.qc
qcsrc/client/damage.qc
qcsrc/client/progs.src
qcsrc/common/command/generic.qc
qcsrc/common/notifications.qh
qcsrc/common/turrets/cl_turrets.qc
qcsrc/common/turrets/sv_turrets.qc
qcsrc/common/turrets/turrets.qc
qcsrc/common/turrets/unit/ewheel.qc
qcsrc/common/turrets/unit/flac.qc
qcsrc/common/turrets/unit/fusionreactor.qc
qcsrc/common/turrets/unit/hellion.qc
qcsrc/common/turrets/unit/hk.qc
qcsrc/common/turrets/unit/machinegun.qc
qcsrc/common/turrets/unit/mlrs.qc
qcsrc/common/turrets/unit/phaser.qc
qcsrc/common/turrets/unit/plasma.qc
qcsrc/common/turrets/unit/plasma_dual.qc
qcsrc/common/turrets/unit/tesla.qc
qcsrc/common/turrets/unit/walker.qc
qcsrc/server/autocvars.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/gamemode_assault.qc
qcsrc/server/mutators/gamemode_onslaught.qc
qcsrc/server/progs.src
qcsrc/server/t_teleporters.qc
qcsrc/server/vehicles/bumblebee.qc
qcsrc/server/vehicles/vehicles.qc

@@@ -126,8 -105,8 +106,7 @@@ void CSQC_Init(void
        Hook_Precache();
        GibSplash_Precache();
        Casings_Precache();
-       DamageInfo_Precache();
        Vehicles_Precache();
 -      turrets_precache();
        Tuba_Precache();
        CSQCPlayer_Precache();
  
Simple merge
Simple merge
@@@ -638,7 -638,7 +691,8 @@@ void GenericCommand_(float request
        GENERIC_COMMAND("addtolist", GenericCommand_addtolist(request, arguments), "Add a string to a cvar") \
        GENERIC_COMMAND("dumpcommands", GenericCommand_dumpcommands(request), "Dump all commands on the program to *_cmd_dump.txt") \
        GENERIC_COMMAND("dumpnotifs", GenericCommand_dumpnotifs(request), "Dump all notifications into notifications_dump.txt") \
 +      GENERIC_COMMAND("dumpturrets", GenericCommand_dumpturrets(request), "Dump all turrets into turrets_dump.txt") \
+       GENERIC_COMMAND("dumpweapons", GenericCommand_dumpweapons(request), "Dump all weapons into weapons_dump.txt") \
        GENERIC_COMMAND("maplist", GenericCommand_maplist(request, arguments), "Automatic control of maplist") \
        GENERIC_COMMAND("nextframe", GenericCommand_nextframe(request, arguments, command), "Execute the given command next frame of this VM") \
        GENERIC_COMMAND("qc_curl", GenericCommand_qc_curl(request, arguments), "Queries a URL") \
Simple merge
index 2b4b2c0,0000000..3365b92
mode 100644,000000..100644
--- /dev/null
@@@ -1,466 -1,0 +1,446 @@@
-       switch(self.team - 1)
-       {
-               case NUM_TEAM_1: // Red
-                       self.glowmod = '2 0 0';
-                       self.teamradar_color = '1 0 0';
-                       break;
-               case NUM_TEAM_2: // Blue
-                       self.glowmod = '0 0 2';
-                       self.teamradar_color = '0 0 1';
-                       break;
-               case NUM_TEAM_3: // Yellow
-                       self.glowmod = '1 1 0';
-                       self.teamradar_color = '1 1 0';
-                       break;
-               case NUM_TEAM_4: // Pink
-                       self.glowmod = '1 0 1';
-                       self.teamradar_color = '1 0 1';
-                       break;
-       }
 +void turret_remove()
 +{
 +      remove(self.tur_head);
 +      //remove(self.enemy);
 +      self.tur_head = world;
 +}
 +
 +.vector glowmod;
 +void turret_changeteam()
 +{
++      self.glowmod = Team_ColorRGB(self.team - 1) * 2;
++      self.teamradar_color = Team_ColorRGB(self.team - 1);
 +
 +      if(self.team)
 +              self.colormap = 1024 + (self.team - 1) * 17;
 +
 +      self.tur_head.colormap = self.colormap;
 +      self.tur_head.glowmod = self.glowmod;
 +
 +}
 +
 +void turret_head_draw()
 +{
 +      self.drawmask = MASK_NORMAL;
 +}
 +
 +void turret_draw()
 +{
 +      float dt;
 +
 +      dt = time - self.move_time;
 +      self.move_time = time;
 +      if(dt <= 0)
 +              return;
 +
 +      self.tur_head.angles += dt * self.tur_head.move_avelocity;
 +
 +      if (self.health < 127)
 +      {
 +              dt = random();
 +
 +              if(dt < 0.03)
 +                      te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
 +      }
 +
 +      if(self.health < 85)
 +      if(dt < 0.01)
 +              pointparticles(particleeffectnum("smoke_large"), (self.origin + (randomvec() * 80)), '0 0 0', 1);
 +
 +      if(self.health < 32)
 +      if(dt < 0.015)
 +              pointparticles(particleeffectnum("smoke_small"), (self.origin + (randomvec() * 80)), '0 0 0', 1);
 +
 +}
 +
 +void turret_draw2d()
 +{
 +      if(self.netname == "")
 +              return;
 +
 +      if(!autocvar_g_waypointsprite_turrets)
 +              return;
 +
 +      if(autocvar_cl_hidewaypoints)
 +              return;
 +
 +      float dist = vlen(self.origin - view_origin);
 +      float t = (GetPlayerColor(player_localnum) + 1);
 +
 +      vector o;
 +      string txt;
 +
 +      if(autocvar_cl_vehicles_hud_tactical)
 +      if(dist < 10240 && t != self.team)
 +      {
 +              // TODO: Vehicle tactical hud
 +              o = project_3d_to_2d(self.origin + '0 0 32');
 +              if(o_z < 0
 +              || o_x < (vid_conwidth * waypointsprite_edgeoffset_left)
 +              || o_y < (vid_conheight * waypointsprite_edgeoffset_top)
 +              || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))
 +              || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
 +                      return; // Dont draw wp's for turrets out of view
 +              o_z = 0;
 +              if(hud != HUD_NORMAL)
 +              {
 +                      if((get_turretinfo(self.turretid)).spawnflags & TUR_FLAG_MOVE)
 +                              txt = "gfx/vehicles/vth-mover.tga";
 +                      else
 +                              txt = "gfx/vehicles/vth-stationary.tga";
 +
 +                      vector pz = drawgetimagesize(txt) * 0.25;
 +                      drawpic(o - pz * 0.5, txt, pz , '1 1 1', 0.75, DRAWFLAG_NORMAL);
 +              }
 +      }
 +
 +      if(dist > self.maxdistance)
 +              return;
 +
 +      string spriteimage = self.netname;
 +      float a = self.alpha * autocvar_hud_panel_fg_alpha;
 +      vector rgb = spritelookupcolor(spriteimage, self.teamradar_color);
 +
 +
 +      if(self.maxdistance > waypointsprite_normdistance)
 +              a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
 +      else if(self.maxdistance > 0)
 +              a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
 +
 +      if(rgb == '0 0 0')
 +      {
 +              self.teamradar_color = '1 0 1';
 +              printf("WARNING: sprite of name %s has no color, using pink so you notice it\n", spriteimage);
 +      }
 +
 +      txt = self.netname;
 +      if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
 +              txt = _("Spam");
 +      else
 +              txt = spritelookuptext(spriteimage);
 +
 +      if(time - floor(time) > 0.5 && t == self.team)
 +      {
 +              if(self.helpme && time < self.helpme)
 +              {
 +                      a *= SPRITE_HELPME_BLINK;
 +                      txt = sprintf(_("%s under attack!"), txt);
 +              }
 +              else
 +                      a *= spritelookupblinkvalue(spriteimage);
 +      }
 +
 +      if(autocvar_g_waypointsprite_uppercase)
 +              txt = strtoupper(txt);
 +
 +      if(a > 1)
 +      {
 +              rgb *= a;
 +              a = 1;
 +      }
 +
 +      if(a <= 0)
 +              return;
 +
 +      rgb = fixrgbexcess(rgb);
 +
 +      o = project_3d_to_2d(self.origin + '0 0 64');
 +      if(o_z < 0
 +      || o_x < (vid_conwidth * waypointsprite_edgeoffset_left)
 +      || o_y < (vid_conheight * waypointsprite_edgeoffset_top)
 +      || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))
 +      || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
 +              return; // Dont draw wp's for turrets out of view
 +
 +      o_z = 0;
 +
 +      float edgedistance_min, crosshairdistance;
 +              edgedistance_min = min((o_y - (vid_conheight * waypointsprite_edgeoffset_top)),
 +      (o_x - (vid_conwidth * waypointsprite_edgeoffset_left)),
 +      (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) - o_x,
 +      (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)) - o_y);
 +
 +      float vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
 +
 +      crosshairdistance = sqrt( pow(o_x - vid_conwidth/2, 2) + pow(o_y - vid_conheight/2, 2) );
 +
 +      t = waypointsprite_scale * vidscale;
 +      a *= waypointsprite_alpha;
 +
 +      {
 +              a = a * (1 - (1 - waypointsprite_distancefadealpha) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
 +              t = t * (1 - (1 - waypointsprite_distancefadescale) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
 +      }
 +      if (edgedistance_min < waypointsprite_edgefadedistance) {
 +              a = a * (1 - (1 - waypointsprite_edgefadealpha) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
 +              t = t * (1 - (1 - waypointsprite_edgefadescale) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
 +      }
 +      if(crosshairdistance < waypointsprite_crosshairfadedistance) {
 +              a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
 +              t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
 +      }
 +
 +      o = drawspritearrow(o, M_PI, rgb, a, SPRITE_ARROW_SCALE * t);
 +      o = drawspritetext(o, M_PI, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
 +      drawhealthbar(
 +                      o,
 +                      0,
 +                      self.health / 255,
 +                      '0 0 0',
 +                      '0 0 0',
 +                      0.5 * SPRITE_HEALTHBAR_WIDTH * t,
 +                      0.5 * SPRITE_HEALTHBAR_HEIGHT * t,
 +                      SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize,
 +                      SPRITE_HEALTHBAR_BORDER * t,
 +                      0,
 +                      rgb,
 +                      a * SPRITE_HEALTHBAR_BORDERALPHA,
 +                      rgb,
 +                      a * SPRITE_HEALTHBAR_HEALTHALPHA,
 +                      DRAWFLAG_NORMAL
 +                      );
 +}
 +
 +void(entity e, entity tagentity, string tagname) setattachment = #443;
 +void turret_construct()
 +{
 +      entity tur = get_turretinfo(self.turretid);
 +
 +      if(self.tur_head == world)
 +              self.tur_head = spawn();
 +
 +      self.netname = TUR_NAME(self.turretid);
 +
 +      setorigin(self, self.origin);
 +      setmodel(self, tur.model);
 +      setmodel(self.tur_head, tur.head_model);
 +      setsize(self, tur.mins, tur.maxs);
 +      setsize(self.tur_head, '0 0 0', '0 0 0');
 +
 +      if(self.turretid == TUR_EWHEEL)
 +              setattachment(self.tur_head, self, "");
 +      else
 +              setattachment(self.tur_head, self, "tag_head");
 +
 +      self.tur_head.classname                 = "turret_head";
 +      self.tur_head.owner                             = self;
 +      self.tur_head.move_movetype             = MOVETYPE_NOCLIP;
 +      self.move_movetype                              = MOVETYPE_NOCLIP;
 +      self.tur_head.angles                    = self.angles;
 +      self.health                                             = 255;
 +      self.solid                                              = SOLID_BBOX;
 +      self.tur_head.solid                             = SOLID_NOT;
 +      self.movetype                                   = MOVETYPE_NOCLIP;
 +      self.tur_head.movetype                  = MOVETYPE_NOCLIP;
 +      self.draw                                               = turret_draw;
 +      self.entremove                                  = turret_remove;
 +      self.drawmask                                   = MASK_NORMAL;
 +      self.tur_head.drawmask                  = MASK_NORMAL;
 +      self.anim_start_time                    = 0;
 +      self.draw2d = turret_draw2d;
 +      self.maxdistance = autocvar_g_waypointsprite_turrets_maxdist;
 +      self.teamradar_color = '1 0 0';
 +      self.alpha = 1;
 +      
 +      TUR_ACTION(self.turretid, TR_SETUP);
 +}
 +
 +entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, float _explode);
 +void turret_gibboom();
 +void turret_gib_draw()
 +{
 +      Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
 +
 +      self.drawmask = MASK_NORMAL;
 +
 +      if(self.cnt)
 +      {
 +              if(time >= self.nextthink)
 +              {
 +                      turret_gibboom();
 +                      remove(self);
 +              }
 +      }
 +      else
 +      {
 +              self.alpha = bound(0, self.nextthink - time, 1);
 +              if(self.alpha < ALPHA_MIN_VISIBLE)
 +                      remove(self);
 +      }
 +}
 +
 +void turret_gibboom()
 +{
 +      float i;
 +
 +      sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
 +      pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
 +
 +      for (i = 1; i < 5; i = i + 1)
 +              turret_gibtoss(strcat("models/turrets/head-gib", ftos(i), ".md3"), self.origin + '0 0 2', self.velocity + randomvec() * 700, '0 0 0', FALSE);
 +}
 +
 +entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, float _explode)
 +{
 +      entity gib;
 +
 +      traceline(_from, _to, MOVE_NOMONSTERS, world);
 +      if(trace_startsolid)
 +              return world;
 +
 +      gib = spawn();
 +      setorigin(gib, _from);
 +      setmodel(gib, _model);
 +      gib.colormod    = _cmod;
 +      gib.solid          = SOLID_CORPSE;
 +      gib.draw                = turret_gib_draw;
 +      gib.cnt          = _explode;
 +      setsize(gib, '-1 -1 -1', '1 1 1');
 +      if(_explode)
 +      {
 +              gib.nextthink = time + 0.2 * (autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15));
 +              gib.effects = EF_FLAME;
 +      }
 +      else
 +              gib.nextthink = time + autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15);
 +
 +      gib.gravity              = 1;
 +      gib.move_movetype   = MOVETYPE_BOUNCE;
 +      gib.move_origin  = _from;
 +      setorigin(gib,          _from);
 +      gib.move_velocity   = _to;
 +      gib.move_avelocity  = prandomvec() * 32;
 +      gib.move_time      = time;
 +      gib.damageforcescale = 1;
 +      gib.classname = "turret_gib";
 +
 +      return gib;
 +}
 +
 +void turret_die()
 +{
 +      sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
 +      pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
 +      if (!autocvar_cl_nogibs)
 +      {
 +              // Base
 +              if(self.turretid == TUR_EWHEEL)
 +                      turret_gibtoss((get_turretinfo(self.turretid)).model, self.origin + '0 0 18', self.velocity + '0 0 400' + '0.1 0.1 1' * (random() * 400), '-1 -1 -1', TRUE);
 +              else if (self.turretid == TUR_WALKER)
 +                      turret_gibtoss((get_turretinfo(self.turretid)).model, self.origin + '0 0 18', self.velocity + '0 0 300' + '0.1 0.1 1' * (random() * 200), '-1 -1 -1', TRUE);
 +              else if (self.turretid == TUR_TESLA)
 +                      turret_gibtoss((get_turretinfo(self.turretid)).model, self.origin + '0 0 18', '0 0 200', '-1 -1 -1', FALSE);
 +              else
 +              {
 +                      if (random() > 0.5)
 +                      {
 +                              turret_gibtoss("models/turrets/base-gib2.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
 +                              turret_gibtoss("models/turrets/base-gib3.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
 +                              turret_gibtoss("models/turrets/base-gib4.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
 +                      }
 +                      else
 +                              turret_gibtoss("models/turrets/base-gib1.md3", self.origin + '0 0 8', '0 0 0', '0 0 0', TRUE);
 +
 +                      entity headgib = turret_gibtoss((get_turretinfo(self.turretid)).head_model, self.origin + '0 0 32', '0 0 200' + randomvec() * 200, '-1 -1 -1', TRUE);
 +                      if(headgib)
 +                      {
 +                              headgib.angles = headgib.move_angles = self.tur_head.angles;
 +                              headgib.avelocity = headgib.move_avelocity = self.tur_head.move_avelocity + randomvec() * 45;
 +                              headgib.avelocity_y = headgib.move_avelocity_y = headgib.move_avelocity_y * 5;
 +                              headgib.gravity = 0.5;
 +                      }
 +              }
 +      }
 +
 +      setmodel(self, "null");
 +      setmodel(self.tur_head, "null");
 +}
 +
 +void ent_turret()
 +{
 +      float sf;
 +      sf = ReadByte();
 +
 +      if(sf & TNSF_SETUP)
 +      {
 +              self.turretid = ReadByte();
 +
 +              self.origin_x = ReadCoord();
 +              self.origin_y = ReadCoord();
 +              self.origin_z = ReadCoord();
 +              setorigin(self, self.origin);
 +
 +              self.angles_x = ReadAngle();
 +              self.angles_y = ReadAngle();
 +              
 +              turret_construct();
 +              self.colormap = 1024;
 +              self.glowmod = '0 1 1';
 +              self.tur_head.colormap = self.colormap;
 +              self.tur_head.glowmod = self.glowmod;
 +      }
 +
 +      if(sf & TNSF_ANG)
 +      {
 +              if(self.tur_head == world) // aparenly this can happpen before TNSF_SETUP. great.
 +                      self.tur_head = spawn();
 +
 +              self.tur_head.move_angles_x = ReadShort();
 +              self.tur_head.move_angles_y = ReadShort();
 +              //self.tur_head.angles = self.angles + self.tur_head.move_angles;
 +              self.tur_head.angles = self.tur_head.move_angles;
 +      }
 +
 +      if(sf & TNSF_AVEL)
 +      {
 +              if(self.tur_head == world) // aparenly this can happpen before TNSF_SETUP. great.
 +                      self.tur_head = spawn();
 +
 +              self.tur_head.move_avelocity_x = ReadShort();
 +              self.tur_head.move_avelocity_y = ReadShort();
 +      }
 +
 +      if(sf & TNSF_MOVE)
 +      {
 +              self.origin_x = ReadShort();
 +              self.origin_y = ReadShort();
 +              self.origin_z = ReadShort();
 +              setorigin(self, self.origin);
 +
 +              self.velocity_x = ReadShort();
 +              self.velocity_y = ReadShort();
 +              self.velocity_z = ReadShort();
 +
 +              self.move_angles_y = ReadShort();
 +
 +              self.move_time   = time;
 +              self.move_velocity = self.velocity;
 +              self.move_origin   = self.origin;
 +      }
 +
 +      if(sf & TNSF_ANIM)
 +      {
 +              self.frame1time = ReadCoord();
 +              self.frame        = ReadByte();
 +      }
 +
 +      if(sf & TNSF_STATUS)
 +      {
 +              float _tmp;
 +              _tmp = ReadByte();
 +              if(_tmp != self.team)
 +              {
 +                      self.team = _tmp;
 +                      turret_changeteam();
 +              }
 +
 +              _tmp = ReadByte();
 +              if(_tmp == 0 && self.health != 0)
 +                      turret_die();
 +              else if(self.health && self.health != _tmp)
 +                      self.helpme = servertime + 10;
 +
 +              self.health = _tmp;
 +      }
 +      //self.enemy.health = self.health / 255;
 +}
index e979c48,0000000..aca2b8e
mode 100644,000000..100644
--- /dev/null
@@@ -1,1396 -1,0 +1,1396 @@@
-       if (teamplay)
-       if (self.team == attacker.team)
 +// =========================
 +//  SVQC Turret Properties
 +// =========================
 +
 +
 +// Generic aiming
 +vector turret_aim_generic()
 +{
 +
 +      vector pre_pos, prep;
 +      float distance, impact_time = 0, i, mintime;
 +
 +      turret_tag_fire_update();
 +
 +      if(self.aim_flags & TFL_AIM_SIMPLE)
 +              return real_origin(self.enemy);
 +
 +      mintime = max(self.attack_finished_single - time,0) + sys_frametime;
 +
 +      // Baseline
 +      pre_pos = real_origin(self.enemy);
 +
 +      // Lead?
 +      if (self.aim_flags & TFL_AIM_LEAD)
 +      {
 +              if (self.aim_flags & TFL_AIM_SHOTTIMECOMPENSATE)           // Need to conpensate for shot traveltime
 +              {
 +                      prep = pre_pos;
 +                      
 +                      distance = vlen(prep - self.tur_shotorg);
 +                      impact_time = distance / self.shot_speed;
 +
 +                      prep = pre_pos + (self.enemy.velocity * (impact_time + mintime));
 +
 +                      if(self.aim_flags & TFL_AIM_ZPREDICT)
 +                      if(!(self.enemy.flags & FL_ONGROUND))
 +                      if(self.enemy.movetype == MOVETYPE_WALK || self.enemy.movetype == MOVETYPE_TOSS || self.enemy.movetype == MOVETYPE_BOUNCE)
 +                      {
 +                              float vz;
 +                              prep_z = pre_pos_z;
 +                              vz = self.enemy.velocity_z;
 +                              for(i = 0; i < impact_time; i += sys_frametime)
 +                              {
 +                                      vz = vz - (autocvar_sv_gravity * sys_frametime);
 +                                      prep_z = prep_z + vz * sys_frametime;
 +                              }
 +                      }
 +                      pre_pos = prep;
 +              }
 +              else
 +                      pre_pos = pre_pos + self.enemy.velocity * mintime;
 +      }
 +
 +      if(self.aim_flags & TFL_AIM_SPLASH)
 +      {
 +              //tracebox(pre_pos + '0 0 32',self.enemy.mins,self.enemy.maxs,pre_pos -'0 0 64',MOVE_WORLDONLY,self.enemy);
 +              traceline(pre_pos + '0 0 32',pre_pos -'0 0 64',MOVE_WORLDONLY,self.enemy);
 +              if(trace_fraction != 1.0)
 +                      pre_pos = trace_endpos;
 +      }
 +
 +      return pre_pos;
 +}
 +
 +float turret_targetscore_support(entity _turret,entity _target)
 +{
 +      float score;            // Total score
 +      float s_score = 0, d_score;
 +
 +      if (_turret.enemy == _target) s_score = 1;
 +
 +      d_score = min(_turret.target_range_optimal,tvt_dist) / max(_turret.target_range_optimal,tvt_dist);
 +
 +      score = (d_score * _turret.target_select_rangebias) +
 +                      (s_score * _turret.target_select_samebias);
 +
 +      return score;
 +}
 +
 +/*
 +* Generic bias aware score system.
 +*/
 +float turret_targetscore_generic(entity _turret, entity _target)
 +{
 +      float d_dist;      // Defendmode Distance
 +      float score;            // Total score
 +      float d_score;    // Distance score
 +      float a_score;    // Angular score
 +      float m_score = 0;  // missile score
 +      float p_score = 0;  // player score
 +      float ikr;                // ideal kill range
 +
 +      if (_turret.tur_defend)
 +      {
 +              d_dist = vlen(real_origin(_target) - _turret.tur_defend.origin);
 +              ikr = vlen(_turret.origin - _turret.tur_defend.origin);
 +              d_score = 1 - d_dist / _turret.target_range;
 +      }
 +      else
 +      {
 +              // Make a normlized value base on the targets distance from our optimal killzone
 +              ikr = _turret.target_range_optimal;
 +              d_score = min(ikr, tvt_dist) / max(ikr, tvt_dist);
 +      }
 +
 +      a_score = 1 - tvt_thadf / _turret.aim_maxrotate;
 +
 +      if ((_turret.target_select_missilebias > 0) && (_target.flags & FL_PROJECTILE))
 +              m_score = 1;
 +
 +      if ((_turret.target_select_playerbias > 0) && IS_CLIENT(_target))
 +              p_score = 1;
 +
 +      d_score = max(d_score, 0);
 +      a_score = max(a_score, 0);
 +      m_score = max(m_score, 0);
 +      p_score = max(p_score, 0);
 +
 +      score = (d_score * _turret.target_select_rangebias) +
 +                      (a_score * _turret.target_select_anglebias) +
 +                      (m_score * _turret.target_select_missilebias) +
 +                      (p_score * _turret.target_select_playerbias);
 +
 +      if(_turret.target_range < vlen(_turret.tur_shotorg - real_origin(_target)))
 +      {
 +              //dprint("Wtf?\n");
 +              score *= 0.001;
 +      }
 +
 +#ifdef TURRET_DEBUG
 +      string sd,sa,sm,sp,ss;
 +      string sdt,sat,smt,spt;
 +
 +      sd = ftos(d_score);
 +      d_score *= _turret.target_select_rangebias;
 +      sdt = ftos(d_score);
 +
 +      //sv = ftos(v_score);
 +      //v_score *= _turret.target_select_samebias;
 +      //svt = ftos(v_score);
 +
 +      sa = ftos(a_score);
 +      a_score *= _turret.target_select_anglebias;
 +      sat = ftos(a_score);
 +
 +      sm = ftos(m_score);
 +      m_score *= _turret.target_select_missilebias;
 +      smt = ftos(m_score);
 +
 +      sp = ftos(p_score);
 +      p_score *= _turret.target_select_playerbias;
 +      spt = ftos(p_score);
 +
 +
 +      ss = ftos(score);
 +      bprint("^3Target scores^7 \[  ",_turret.netname, "  \] ^3for^7 \[  ", _target.netname,"  \]\n");
 +      bprint("^5Range:\[  ",sd,  "  \]^2+bias:\[  ",sdt,"  \]\n");
 +      bprint("^5Angle:\[  ",sa,  "  \]^2+bias:\[  ",sat,"  \]\n");
 +      bprint("^5Missile:\[  ",sm,"  \]^2+bias:\[  ",smt,"  \]\n");
 +      bprint("^5Player:\[  ",sp, "  \]^2+bias:\[  ",spt,"  \]\n");
 +      bprint("^3Total (w/bias):\[^1",ss,"\]\n");
 +
 +#endif
 +
 +      return score;
 +}
 +
 +// Generic damage handling
 +void() turret_respawn;
 +void turret_hide()
 +{
 +      self.effects   |= EF_NODRAW;
 +      self.nextthink = time + self.respawntime - 0.2;
 +      self.think       = turret_respawn;
 +}
 +
 +void turret_die()
 +{
 +      self.deadflag             = DEAD_DEAD;
 +      self.tur_head.deadflag = self.deadflag;
 +
 +// Unsolidify and hide real parts
 +      self.solid                       = SOLID_NOT;
 +      self.tur_head.solid      = self.solid;
 +
 +      self.event_damage                 = func_null;
 +      self.takedamage                  = DAMAGE_NO;
 +
 +      self.health                      = 0;
 +
 +// Go boom
 +      //RadiusDamage (self,self, min(self.ammo,50),min(self.ammo,50) * 0.25,250,world,min(self.ammo,50)*5,DEATH_TURRET,world);
 +
 +      if(self.damage_flags & TFL_DMG_DEATH_NORESPAWN)
 +      {
 +              TUR_ACTION(self.turretid, TR_DEATH);
 +
 +              remove(self.tur_head);
 +              remove(self);
 +      }
 +      else
 +      {
 +              // Setup respawn
 +              self.SendFlags    |= TNSF_STATUS;
 +              self.nextthink   = time + 0.2;
 +              self.think               = turret_hide;
 +
 +              TUR_ACTION(self.turretid, TR_DEATH);
 +      }
 +}
 +
 +void turret_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
 +{
 +      // Enougth allready!
 +      if(self.deadflag == DEAD_DEAD)
 +              return;
 +
 +      // Inactive turrets take no damage. (hm..)
 +      if(!self.active)
 +              return;
 +
-               // This does not happen anymore. Re-enable if you fix that.
-               if(IS_REAL_CLIENT(attacker))
-                       sprint(attacker, "\{1}Turret tells you: I'm on your team!\n");
++      if(SAME_TEAM(self, attacker))
 +      {
-       d = RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, self, self.owner.shot_force, self.totalfrags, world);
 +              if(autocvar_g_friendlyfire)
 +                      damage = damage * autocvar_g_friendlyfire;
 +              else
 +                      return;
 +      }
 +
 +      self.health -= damage;
 +
 +      // thorw head slightly off aim when hit?
 +      if (self.damage_flags & TFL_DMG_HEADSHAKE)
 +      {
 +              self.tur_head.angles_x = self.tur_head.angles_x + (-0.5 + random()) * damage;
 +              self.tur_head.angles_y = self.tur_head.angles_y + (-0.5 + random()) * damage;
 +
 +              self.SendFlags  |= TNSF_ANG;
 +      }
 +
 +      if (self.turret_flags & TUR_FLAG_MOVE)
 +              self.velocity = self.velocity + vforce;
 +
 +      if (self.health <= 0)
 +      {
 +              self.event_damage                 = func_null;
 +              self.tur_head.event_damage = func_null;
 +              self.takedamage                  = DAMAGE_NO;
 +              self.nextthink = time;
 +              self.think = turret_die;
 +      }
 +
 +      self.SendFlags  |= TNSF_STATUS;
 +}
 +
 +void() turret_think;
 +void turret_respawn()
 +{
 +      // Make sure all parts belong to the same team since
 +      // this function doubles as "teamchange" function.
 +      self.tur_head.team      = self.team;
 +      self.effects                       &= ~EF_NODRAW;
 +      self.deadflag                           = DEAD_NO;
 +      self.effects                            = EF_LOWPRECISION;
 +      self.solid                                      = SOLID_BBOX;
 +      self.takedamage                         = DAMAGE_AIM;
 +      self.event_damage                       = turret_damage;
 +      self.avelocity                          = '0 0 0';
 +      self.tur_head.avelocity         = self.avelocity;
 +      self.tur_head.angles            = self.idle_aim;
 +      self.health                                     = self.max_health;
 +      self.enemy                                      = world;
 +      self.volly_counter                      = self.shot_volly;
 +      self.ammo                                       = self.ammo_max;
 +
 +      self.nextthink = time + self.ticrate;
 +      self.think       = turret_think;
 +
 +      self.SendFlags = TNSF_FULL_UPDATE;
 +      
 +      TUR_ACTION(self.turretid, TR_SETUP);
 +}
 +
 +
 +// Main functions
 +#define cvar_base "g_turrets_unit_"
 +.float clientframe;
 +void turrets_setframe(float _frame, float client_only)
 +{
 +      if((client_only ? self.clientframe : self.frame ) != _frame)
 +      {
 +              self.SendFlags |= TNSF_ANIM;
 +              self.anim_start_time = time;
 +      }
 +
 +       if(client_only)
 +              self.clientframe = _frame;
 +      else
 +              self.frame = _frame;
 +
 +}
 +
 +float turret_send(entity to, float sf)
 +{
 +
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_TURRET);
 +      WriteByte(MSG_ENTITY, sf);
 +      if(sf & TNSF_SETUP)
 +      {
 +              WriteByte(MSG_ENTITY, self.turretid);
 +
 +              WriteCoord(MSG_ENTITY, self.origin_x);
 +              WriteCoord(MSG_ENTITY, self.origin_y);
 +              WriteCoord(MSG_ENTITY, self.origin_z);
 +
 +              WriteAngle(MSG_ENTITY, self.angles_x);
 +              WriteAngle(MSG_ENTITY, self.angles_y);
 +      }
 +
 +      if(sf & TNSF_ANG)
 +      {
 +              WriteShort(MSG_ENTITY, rint(self.tur_head.angles_x));
 +              WriteShort(MSG_ENTITY, rint(self.tur_head.angles_y));
 +      }
 +
 +      if(sf & TNSF_AVEL)
 +      {
 +              WriteShort(MSG_ENTITY, rint(self.tur_head.avelocity_x));
 +              WriteShort(MSG_ENTITY, rint(self.tur_head.avelocity_y));
 +      }
 +
 +      if(sf & TNSF_MOVE)
 +      {
 +              WriteShort(MSG_ENTITY, rint(self.origin_x));
 +              WriteShort(MSG_ENTITY, rint(self.origin_y));
 +              WriteShort(MSG_ENTITY, rint(self.origin_z));
 +
 +              WriteShort(MSG_ENTITY, rint(self.velocity_x));
 +              WriteShort(MSG_ENTITY, rint(self.velocity_y));
 +              WriteShort(MSG_ENTITY, rint(self.velocity_z));
 +
 +              WriteShort(MSG_ENTITY, rint(self.angles_y));
 +      }
 +
 +      if(sf & TNSF_ANIM)
 +      {
 +              WriteCoord(MSG_ENTITY, self.anim_start_time);
 +              WriteByte(MSG_ENTITY, self.frame);
 +      }
 +
 +      if(sf & TNSF_STATUS)
 +      {
 +              WriteByte(MSG_ENTITY, self.team);
 +
 +              if(self.health <= 0)
 +                      WriteByte(MSG_ENTITY, 0);
 +              else
 +                      WriteByte(MSG_ENTITY, ceil((self.health / self.max_health) * 255));
 +      }
 +
 +      return TRUE;
 +}
 +
 +void load_unit_settings(entity ent, string unitname, float is_reload)
 +{
 +      string sbase;
 +
 +      if (ent == world)
 +              return;
 +
 +      if(!ent.turret_scale_damage)    ent.turret_scale_damage = 1;
 +      if(!ent.turret_scale_range)             ent.turret_scale_range  = 1;
 +      if(!ent.turret_scale_refire)    ent.turret_scale_refire = 1;
 +      if(!ent.turret_scale_ammo)              ent.turret_scale_ammo   = 1;
 +      if(!ent.turret_scale_aim)               ent.turret_scale_aim     = 1;
 +      if(!ent.turret_scale_health)    ent.turret_scale_health = 1;
 +      if(!ent.turret_scale_respawn)   ent.turret_scale_respawn = 1;
 +
 +      sbase = strcat(cvar_base,unitname);
 +      if (is_reload)
 +      {
 +              ent.enemy = world;
 +              ent.tur_head.avelocity = '0 0 0';
 +
 +              ent.tur_head.angles = '0 0 0';
 +      }
 +
 +      ent.health       = cvar(strcat(sbase,"_health")) * ent.turret_scale_health;
 +      ent.respawntime = cvar(strcat(sbase,"_respawntime")) * ent.turret_scale_respawn;
 +
 +      ent.shot_dmg             = cvar(strcat(sbase,"_shot_dmg")) * ent.turret_scale_damage;
 +      ent.shot_refire   = cvar(strcat(sbase,"_shot_refire")) * ent.turret_scale_refire;
 +      ent.shot_radius   = cvar(strcat(sbase,"_shot_radius")) * ent.turret_scale_damage;
 +      ent.shot_speed          = cvar(strcat(sbase,"_shot_speed"));
 +      ent.shot_spread   = cvar(strcat(sbase,"_shot_spread"));
 +      ent.shot_force          = cvar(strcat(sbase,"_shot_force")) * ent.turret_scale_damage;
 +      ent.shot_volly          = cvar(strcat(sbase,"_shot_volly"));
 +      ent.shot_volly_refire = cvar(strcat(sbase,"_shot_volly_refire")) * ent.turret_scale_refire;
 +
 +      ent.target_range                 = cvar(strcat(sbase,"_target_range")) * ent.turret_scale_range;
 +      ent.target_range_min     = cvar(strcat(sbase,"_target_range_min")) * ent.turret_scale_range;
 +      ent.target_range_optimal = cvar(strcat(sbase,"_target_range_optimal")) * ent.turret_scale_range;
 +      //ent.target_range_fire = cvar(strcat(sbase,"_target_range_fire")) * ent.turret_scale_range;
 +
 +      ent.target_select_rangebias = cvar(strcat(sbase,"_target_select_rangebias"));
 +      ent.target_select_samebias  = cvar(strcat(sbase,"_target_select_samebias"));
 +      ent.target_select_anglebias = cvar(strcat(sbase,"_target_select_anglebias"));
 +      ent.target_select_playerbias = cvar(strcat(sbase,"_target_select_playerbias"));
 +      //ent.target_select_fov = cvar(cvar_gets(sbase,"_target_select_fov"));
 +
 +      ent.ammo_max     = cvar(strcat(sbase,"_ammo_max")) * ent.turret_scale_ammo;
 +      ent.ammo_recharge = cvar(strcat(sbase,"_ammo_recharge")) * ent.turret_scale_ammo;
 +
 +      ent.aim_firetolerance_dist = cvar(strcat(sbase,"_aim_firetolerance_dist"));
 +      ent.aim_speed   = cvar(strcat(sbase,"_aim_speed")) * ent.turret_scale_aim;
 +      ent.aim_maxrotate  = cvar(strcat(sbase,"_aim_maxrot"));
 +      ent.aim_maxpitch = cvar(strcat(sbase,"_aim_maxpitch"));
 +
 +      ent.track_type          = cvar(strcat(sbase,"_track_type"));
 +      ent.track_accel_pitch = cvar(strcat(sbase,"_track_accel_pitch"));
 +      ent.track_accel_rotate  = cvar(strcat(sbase,"_track_accel_rot"));
 +      ent.track_blendrate  = cvar(strcat(sbase,"_track_blendrate"));
 +
 +      if(is_reload)
 +              TUR_ACTION(self.turretid, TR_SETUP);
 +}
 +
 +void turret_projectile_explode()
 +{
 +
 +      self.takedamage = DAMAGE_NO;
 +      self.event_damage = func_null;
 +#ifdef TURRET_DEBUG
 +      float d;
-       RadiusDamage (self, self.realowner, self.owner.shot_dmg, 0, self.owner.shot_radius, self, self.owner.shot_force, self.totalfrags, world);
++      d = RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world);
 +      self.owner.tur_debug_dmg_t_h = self.owner.tur_debug_dmg_t_h + d;
 +      self.owner.tur_debug_dmg_t_f = self.owner.tur_debug_dmg_t_f + self.owner.shot_dmg;
 +#else
-       if(!e_target)
-               return -2;
++      RadiusDamage (self, self.realowner, self.owner.shot_dmg, 0, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world);
 +#endif
 +      remove(self);
 +}
 +
 +void turret_projectile_touch()
 +{
 +      PROJECTILE_TOUCH;
 +      turret_projectile_explode();
 +}
 +
 +void turret_projectile_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
 +{
 +      self.velocity  += vforce;
 +      self.health     -= damage;
 +      //self.realowner = attacker; // Dont change realowner, it does not make much sense for turrets
 +      if(self.health <= 0)
 +              W_PrepareExplosionByDamage(self.owner, turret_projectile_explode);
 +}
 +
 +entity turret_projectile(string _snd, float _size, float _health, float _death, float _proj_type, float _cull, float _cli_anim)
 +{
 +      entity proj;
 +
 +      sound (self, CH_WEAPON_A, _snd, VOL_BASE, ATTEN_NORM);
 +      proj                             = spawn ();
 +      setorigin(proj, self.tur_shotorg);
 +      setsize(proj, '-0.5 -0.5 -0.5' * _size, '0.5 0.5 0.5' * _size);
 +      proj.owner                = self;
 +      proj.realowner    = self;
 +      proj.bot_dodge    = TRUE;
 +      proj.bot_dodgerating = self.shot_dmg;
 +      proj.think                = turret_projectile_explode;
 +      proj.touch                = turret_projectile_touch;
 +      proj.nextthink    = time + 9;
 +      proj.movetype           = MOVETYPE_FLYMISSILE;
 +      proj.velocity           = normalize(self.tur_shotdir_updated + randomvec() * self.shot_spread) * self.shot_speed;
 +      proj.flags                = FL_PROJECTILE;
 +      proj.enemy                = self.enemy;
 +      proj.totalfrags  = _death;
 +      PROJECTILE_MAKETRIGGER(proj);
 +      if(_health)
 +      {
 +              proj.health              = _health;
 +              proj.takedamage  = DAMAGE_YES;
 +              proj.event_damage  = turret_projectile_damage;
 +      }
 +      else
 +              proj.flags |= FL_NOTARGET;
 +
 +      CSQCProjectile(proj, _cli_anim, _proj_type, _cull);
 +
 +      return proj;
 +}
 +
 +/**
 +** updates enemy distances, predicted impact point/time
 +** and updated aim<->predict impact distance.
 +**/
 +void turret_do_updates(entity t_turret)
 +{
 +      vector enemy_pos;
 +      entity oldself;
 +
 +      oldself = self;
 +      self = t_turret;
 +
 +      enemy_pos = real_origin(self.enemy);
 +
 +      turret_tag_fire_update();
 +
 +      self.tur_shotdir_updated = v_forward;
 +      self.tur_dist_enemy = vlen(self.tur_shotorg - enemy_pos);
 +      self.tur_dist_aimpos = vlen(self.tur_shotorg - self.tur_aimpos);
 +
 +      /*if((self.firecheck_flags & TFL_FIRECHECK_VERIFIED) && (self.enemy))
 +      {
 +              oldpos = self.enemy.origin;
 +              setorigin(self.enemy, self.tur_aimpos);
 +              tracebox(self.tur_shotorg, '-1 -1 -1', '1 1 1', self.tur_shotorg + (self.tur_shotdir_updated * self.tur_dist_aimpos), MOVE_NORMAL,self);
 +              setorigin(self.enemy, oldpos);
 +
 +              if(trace_ent == self.enemy)
 +                      self.tur_dist_impact_to_aimpos = 0;
 +              else
 +                      self.tur_dist_impact_to_aimpos = vlen(trace_endpos - self.tur_aimpos);
 +      }
 +      else*/
 +              tracebox(self.tur_shotorg, '-1 -1 -1','1 1 1', self.tur_shotorg + (self.tur_shotdir_updated * self.tur_dist_aimpos), MOVE_NORMAL,self);
 +
 +      self.tur_dist_impact_to_aimpos = vlen(trace_endpos - self.tur_aimpos) - (vlen(self.enemy.maxs - self.enemy.mins) * 0.5);
 +      self.tur_impactent                       = trace_ent;
 +      self.tur_impacttime                     = vlen(self.tur_shotorg - trace_endpos) / self.shot_speed;
 +
 +      self = oldself;
 +}
 +
 +/**
 +** Handles head rotation according to
 +** the units .track_type and .track_flags
 +**/
 +.float turret_framecounter;
 +void turret_track()
 +{
 +      vector target_angle; // This is where we want to aim
 +      vector move_angle;   // This is where we can aim
 +      float f_tmp;
 +      vector v1, v2;
 +      v1 = self.tur_head.angles;
 +      v2 = self.tur_head.avelocity;
 +
 +      if (self.track_flags == TFL_TRACK_NO)
 +              return;
 +
 +      if(!self.active)
 +              target_angle = self.idle_aim - ('1 0 0' * self.aim_maxpitch);
 +      else if (self.enemy == world)
 +      {
 +              if(time > self.lip)
 +                      target_angle = self.idle_aim + self.angles;
 +              else
 +                      target_angle = vectoangles(normalize(self.tur_aimpos - self.tur_shotorg));
 +      }
 +      else
 +      {
 +              target_angle = vectoangles(normalize(self.tur_aimpos - self.tur_shotorg));
 +      }
 +
 +      self.tur_head.angles_x = anglemods(self.tur_head.angles_x);
 +      self.tur_head.angles_y = anglemods(self.tur_head.angles_y);
 +
 +      // Find the diffrence between where we currently aim and where we want to aim
 +      //move_angle = target_angle - (self.angles + self.tur_head.angles);
 +      //move_angle = shortangle_vxy(move_angle,(self.angles + self.tur_head.angles));
 +
 +      move_angle = AnglesTransform_ToAngles(AnglesTransform_LeftDivide(AnglesTransform_FromAngles(self.angles), AnglesTransform_FromAngles(target_angle))) - self.tur_head.angles;
 +      move_angle = shortangle_vxy(move_angle, self.tur_head.angles);
 +
 +      switch(self.track_type)
 +      {
 +              case TFL_TRACKTYPE_STEPMOTOR:
 +                      f_tmp = self.aim_speed * self.ticrate; // dgr/sec -> dgr/tic
 +                      if (self.track_flags & TFL_TRACK_PITCH)
 +                      {
 +                              self.tur_head.angles_x += bound(-f_tmp,move_angle_x, f_tmp);
 +                              if(self.tur_head.angles_x > self.aim_maxpitch)
 +                                      self.tur_head.angles_x = self.aim_maxpitch;
 +
 +                              if(self.tur_head.angles_x  < -self.aim_maxpitch)
 +                                      self.tur_head.angles_x = self.aim_maxpitch;
 +                      }
 +
 +                      if (self.track_flags & TFL_TRACK_ROTATE)
 +                      {
 +                              self.tur_head.angles_y += bound(-f_tmp, move_angle_y, f_tmp);
 +                              if(self.tur_head.angles_y > self.aim_maxrotate)
 +                                      self.tur_head.angles_y = self.aim_maxrotate;
 +
 +                              if(self.tur_head.angles_y  < -self.aim_maxrotate)
 +                                      self.tur_head.angles_y = self.aim_maxrotate;
 +                      }
 +
 +                      // CSQC
 +                      self.SendFlags  |= TNSF_ANG;
 +
 +                      return;
 +
 +              case TFL_TRACKTYPE_FLUIDINERTIA:
 +                      f_tmp = self.aim_speed * self.ticrate; // dgr/sec -> dgr/tic
 +                      move_angle_x = bound(-self.aim_speed, move_angle_x * self.track_accel_pitch * f_tmp, self.aim_speed);
 +                      move_angle_y = bound(-self.aim_speed, move_angle_y * self.track_accel_rotate * f_tmp, self.aim_speed);
 +                      move_angle = (self.tur_head.avelocity * self.track_blendrate) + (move_angle * (1 - self.track_blendrate));
 +                      break;
 +
 +              case TFL_TRACKTYPE_FLUIDPRECISE:
 +
 +                      move_angle_y = bound(-self.aim_speed, move_angle_y, self.aim_speed);
 +                      move_angle_x = bound(-self.aim_speed, move_angle_x, self.aim_speed);
 +
 +                      break;
 +      }
 +
 +      //  pitch
 +      if (self.track_flags & TFL_TRACK_PITCH)
 +      {
 +              self.tur_head.avelocity_x = move_angle_x;
 +              if((self.tur_head.angles_x + self.tur_head.avelocity_x * self.ticrate) > self.aim_maxpitch)
 +              {
 +                      self.tur_head.avelocity_x = 0;
 +                      self.tur_head.angles_x = self.aim_maxpitch;
 +
 +                      self.SendFlags  |= TNSF_ANG;
 +              }
 +
 +              if((self.tur_head.angles_x + self.tur_head.avelocity_x * self.ticrate) < -self.aim_maxpitch)
 +              {
 +                      self.tur_head.avelocity_x = 0;
 +                      self.tur_head.angles_x = -self.aim_maxpitch;
 +
 +                      self.SendFlags  |= TNSF_ANG;
 +              }
 +      }
 +
 +      //  rot
 +      if (self.track_flags & TFL_TRACK_ROTATE)
 +      {
 +              self.tur_head.avelocity_y = move_angle_y;
 +
 +              if((self.tur_head.angles_y + self.tur_head.avelocity_y * self.ticrate) > self.aim_maxrotate)
 +              {
 +                      self.tur_head.avelocity_y = 0;
 +                      self.tur_head.angles_y = self.aim_maxrotate;
 +
 +                      self.SendFlags  |= TNSF_ANG;
 +              }
 +
 +              if((self.tur_head.angles_y + self.tur_head.avelocity_y * self.ticrate) < -self.aim_maxrotate)
 +              {
 +                      self.tur_head.avelocity_y = 0;
 +                      self.tur_head.angles_y = -self.aim_maxrotate;
 +
 +                      self.SendFlags  |= TNSF_ANG;
 +              }
 +      }
 +
 +      self.SendFlags  |= TNSF_AVEL;
 +
 +      // Force a angle update every 10'th frame
 +      self.turret_framecounter += 1;
 +      if(self.turret_framecounter >= 10)
 +      {
 +              self.SendFlags |= TNSF_ANG;
 +              self.turret_framecounter = 0;
 +      }
 +}
 +
 +/*
 + + TFL_TARGETSELECT_NO
 + + TFL_TARGETSELECT_LOS
 + + TFL_TARGETSELECT_PLAYERS
 + + TFL_TARGETSELECT_MISSILES
 + - TFL_TARGETSELECT_TRIGGERTARGET
 + + TFL_TARGETSELECT_ANGLELIMITS
 + + TFL_TARGETSELECT_RANGELIMITS
 + + TFL_TARGETSELECT_TEAMCHECK
 + - TFL_TARGETSELECT_NOBUILTIN
 + + TFL_TARGETSELECT_OWNTEAM
 +*/
 +
 +/**
 +** Evaluate a entity for target valitity based on validate_flags
 +** NOTE: the caller must check takedamage before calling this, to inline this check.
 +**/
 +float turret_validate_target(entity e_turret, entity e_target, float validate_flags)
 +{
 +      vector v_tmp;
 +
 +      //if(!validate_flags & TFL_TARGETSELECT_NOBUILTIN)
 +      //      return -0.5;
 +
++      if(!e_target)
++              return -2;
++
 +      if(e_target.owner == e_turret)
 +              return -0.5;
 +
 +      if(!checkpvs(e_target.origin, e_turret))
 +              return -1;
 +
++      if(e_target.alpha <= 0.3)
++              return -1;
 +
 +      if(g_onslaught)
 +              if (substring(e_target.classname, 0, 10) == "onslaught_") // don't attack onslaught targets, that's the player's job!
 +                      return - 3;
 +
 +      if (validate_flags & TFL_TARGETSELECT_NO)
 +              return -4;
 +
 +      // If only this was used more..
 +      if (e_target.flags & FL_NOTARGET)
 +              return -5;
 +
 +      // Cant touch this
 +      if(e_target.vehicle_flags & VHF_ISVEHICLE)
 +      {
 +              if (e_target.vehicle_health <= 0)
 +                      return -6;
 +      }
 +      else if (e_target.health <= 0)
 +              return -6;
 +      else if(e_target.frozen > 0)
 +              return -6;
 +
 +      // player
 +      if (IS_CLIENT(e_target))
 +      {
 +              if(!(validate_flags & TFL_TARGETSELECT_PLAYERS))
 +                      return -7;
 +
 +              if (e_target.deadflag != DEAD_NO)
 +                      return -8;
 +      }
 +
 +      // enemy turrets
 +      if(validate_flags & TFL_TARGETSELECT_NOTURRETS)
 +      if(e_target.owner.tur_head == e_target)
 +      if(e_target.team != e_turret.team) // Dont break support units.
 +              return -9;
 +
 +      // Missile
 +      if (e_target.flags & FL_PROJECTILE)
 +      if(!(validate_flags & TFL_TARGETSELECT_MISSILES))
 +              return -10;
 +
 +      if (validate_flags & TFL_TARGETSELECT_MISSILESONLY)
 +      if(!(e_target.flags & FL_PROJECTILE))
 +              return -10.5;
 +
 +      // Team check
 +      if (validate_flags & TFL_TARGETSELECT_TEAMCHECK)
 +      {
 +              if (validate_flags & TFL_TARGETSELECT_OWNTEAM)
 +              {
 +                      if (e_target.team != e_turret.team)
 +                              return -11;
 +
 +                      if (e_turret.team != e_target.owner.team)
 +                              return -12;
 +              }
 +              else
 +              {
 +                      if (e_target.team == e_turret.team)
 +                              return -13;
 +
 +                      if (e_turret.team == e_target.owner.team)
 +                              return -14;
 +              }
 +      }
 +
 +      // Range limits?
 +      tvt_dist = vlen(e_turret.origin - real_origin(e_target));
 +      if (validate_flags & TFL_TARGETSELECT_RANGELIMITS)
 +      {
 +              if (tvt_dist < e_turret.target_range_min)
 +                      return -15;
 +
 +              if (tvt_dist > e_turret.target_range)
 +                      return -16;
 +      }
 +
 +      // Can we even aim this thing?
 +      tvt_thadv = angleofs3(e_turret.tur_head.origin, e_turret.angles + e_turret.tur_head.angles, e_target);
 +      tvt_tadv = shortangle_vxy(angleofs(e_turret, e_target), e_turret.angles);
 +      tvt_thadf = vlen(tvt_thadv);
 +      tvt_tadf = vlen(tvt_tadv);
 +
 +      /*
 +      if(validate_flags & TFL_TARGETSELECT_FOV)
 +      {
 +              if(e_turret.target_select_fov < tvt_thadf)
 +                      return -21;
 +      }
 +      */
 +
 +      if (validate_flags & TFL_TARGETSELECT_ANGLELIMITS)
 +      {
 +              if (fabs(tvt_tadv_x) > e_turret.aim_maxpitch)
 +                      return -17;
 +
 +              if (fabs(tvt_tadv_y) > e_turret.aim_maxrotate)
 +                      return -18;
 +      }
 +
 +      // Line of sight?
 +      if (validate_flags & TFL_TARGETSELECT_LOS)
 +      {
 +              v_tmp = real_origin(e_target) + ((e_target.mins + e_target.maxs) * 0.5);
 +
 +              traceline(e_turret.origin + '0 0 16', v_tmp, 0, e_turret);
 +
 +              if (e_turret.aim_firetolerance_dist < vlen(v_tmp - trace_endpos))
 +                      return -19;
 +      }
 +
 +      if (e_target.classname == "grapplinghook")
 +              return -20;
 +
 +      /*
 +      if (e_target.classname == "func_button")
 +              return -21;
 +      */
 +
 +#ifdef TURRET_DEBUG_TARGETSELECT
 +      dprint("Target:",e_target.netname," is a valid target for ",e_turret.netname,"\n");
 +#endif
 +
 +      return 1;
 +}
 +
 +entity turret_select_target()
 +{
 +      entity e;               // target looper entity
 +      float  score;   // target looper entity score
 +      entity e_enemy;  // currently best scoreing target
 +      float  m_score;  // currently best scoreing target's score
 +
 +      m_score = 0;
 +      if(self.enemy && self.enemy.takedamage && turret_validate_target(self,self.enemy,self.target_validate_flags) > 0)
 +      {
 +              e_enemy = self.enemy;
 +              m_score = self.turret_score_target(self,e_enemy) * self.target_select_samebias;
 +      }
 +      else
 +              e_enemy = self.enemy = world;
 +
 +      e = findradius(self.origin, self.target_range);
 +
 +      // Nothing to aim at?
 +      if (!e)
 +              return world;
 +
 +      while (e)
 +      {
 +              if(e.takedamage)
 +              {
 +                      float f = turret_validate_target(self, e, self.target_select_flags);
 +                      //dprint("F is: ", ftos(f), "\n");
 +                      if ( f > 0)
 +                      {
 +                              score = self.turret_score_target(self,e);
 +                              if ((score > m_score) && (score > 0))
 +                              {
 +                                      e_enemy = e;
 +                                      m_score = score;
 +                              }
 +                      }
 +              }
 +              e = e.chain;
 +      }
 +
 +      return e_enemy;
 +}
 +
 +
 +/*
 + + = implemented
 + - = not implemented
 +
 + + TFL_FIRECHECK_NO
 + + TFL_FIRECHECK_WORLD
 + + TFL_FIRECHECK_DEAD
 + + TFL_FIRECHECK_DISTANCES
 + - TFL_FIRECHECK_LOS
 + + TFL_FIRECHECK_AIMDIST
 + + TFL_FIRECHECK_REALDIST
 + - TFL_FIRECHECK_ANGLEDIST
 + - TFL_FIRECHECK_TEAMCECK
 + + TFL_FIRECHECK_AFF
 + + TFL_FIRECHECK_AMMO_OWN
 + + TFL_FIRECHECK_AMMO_OTHER
 + + TFL_FIRECHECK_REFIRE
 +*/
 +
 +/**
 +** Preforms pre-fire checks based on the uints firecheck_flags
 +**/
 +float turret_firecheck()
 +{
 +      // This one just dont care =)
 +      if (self.firecheck_flags & TFL_FIRECHECK_NO)
 +              return 1;
 +
 +      if (self.enemy == world)
 +              return 0;
 +
 +      // Ready?
 +      if (self.firecheck_flags & TFL_FIRECHECK_REFIRE)
 +              if (self.attack_finished_single > time) return 0;
 +
 +      // Special case: volly fire turret that has to fire a full volly if a shot was fired.
 +      if (self.shoot_flags & TFL_SHOOT_VOLLYALWAYS)
 +              if (self.volly_counter != self.shot_volly)
 +                      if(self.ammo >= self.shot_dmg)
 +                              return 1;
 +
 +      // Lack of zombies makes shooting dead things unnecessary :P
 +      if (self.firecheck_flags & TFL_FIRECHECK_DEAD)
 +              if (self.enemy.deadflag != DEAD_NO)
 +                      return 0;
 +
 +      // Own ammo?
 +      if (self.firecheck_flags & TFL_FIRECHECK_AMMO_OWN)
 +              if (self.ammo < self.shot_dmg)
 +                      return 0;
 +
 +      // Other's ammo? (support-supply units)
 +      if (self.firecheck_flags & TFL_FIRECHECK_AMMO_OTHER)
 +              if (self.enemy.ammo >= self.enemy.ammo_max)
 +                      return 0;
 +
 +      // Target of opertunity?
 +      if(turret_validate_target(self, self.tur_impactent, self.target_validate_flags) > 0)
 +      {
 +              self.enemy = self.tur_impactent;
 +              return 1;
 +      }
 +
 +      if (self.firecheck_flags & TFL_FIRECHECK_DISTANCES)
 +      {
 +              // To close?
 +              if (self.tur_dist_aimpos < self.target_range_min)
 +                      if(turret_validate_target(self, self.tur_impactent, self.target_validate_flags) > 0)
 +                              return 1; // Target of opertunity?
 +                      else
 +                              return 0;
 +      }
 +
 +      // Try to avoid FF?
 +      if (self.firecheck_flags & TFL_FIRECHECK_AFF)
 +              if (self.tur_impactent.team == self.team)
 +                      return 0;
 +
 +      // aim<->predicted impact
 +      if (self.firecheck_flags & TFL_FIRECHECK_AIMDIST)
 +              if (self.tur_dist_impact_to_aimpos > self.aim_firetolerance_dist)
 +                      return 0;
 +
 +      // Volly status
 +      if (self.shot_volly > 1)
 +              if (self.volly_counter == self.shot_volly)
 +                      if (self.ammo < (self.shot_dmg * self.shot_volly))
 +                              return 0;
 +
 +      /*if(self.firecheck_flags & TFL_FIRECHECK_VERIFIED)
 +              if(self.tur_impactent != self.enemy)
 +                      return 0;*/
 +
 +      return 1;
 +}
 +
 +void turret_fire()
 +{
 +      if (autocvar_g_turrets_nofire != 0)
 +              return;
 +              
 +      TUR_ACTION(self.turretid, TR_ATTACK);
 +
 +      self.attack_finished_single = time + self.shot_refire;
 +      self.ammo -= self.shot_dmg;
 +      self.volly_counter = self.volly_counter - 1;
 +
 +      if (self.volly_counter <= 0)
 +      {
 +              self.volly_counter = self.shot_volly;
 +
 +              if (self.shoot_flags & TFL_SHOOT_CLEARTARGET)
 +                      self.enemy = world;
 +
 +              if (self.shot_volly > 1)
 +                      self.attack_finished_single = time + self.shot_volly_refire;
 +      }
 +
 +#ifdef TURRET_DEBUG
 +      if (self.enemy) paint_target3(self.tur_aimpos, 64, self.tur_debug_rvec, self.tur_impacttime + 0.25);
 +#endif
 +}
 +
 +void turret_think()
 +{
 +      entity e;
 +
 +      self.nextthink = time + self.ticrate;
 +
 +      // ONS uses somewhat backwards linking.
 +      if (teamplay)
 +      {
 +              if (g_onslaught)
 +                      if (self.target)
 +                      {
 +                              e = find(world, targetname,self.target);
 +                              if (e != world)
 +                                      self.team = e.team;
 +                      }
 +
 +              if (self.team != self.tur_head.team)
 +                      turret_respawn();
 +      }
 +
 +#ifdef TURRET_DEBUG
 +      if (self.tur_debug_tmr1 < time)
 +      {
 +              if (self.enemy) paint_target (self.enemy,128,self.tur_debug_rvec,0.9);
 +              paint_target(self,256,self.tur_debug_rvec,0.9);
 +              self.tur_debug_tmr1 = time + 1;
 +      }
 +#endif
 +
 +      // Handle ammo
 +      if (!(self.spawnflags & TSF_NO_AMMO_REGEN))
 +      if (self.ammo < self.ammo_max)
 +              self.ammo = min(self.ammo + self.ammo_recharge, self.ammo_max);
 +
 +      // Inactive turrets needs to run the think loop,
 +      // So they can handle animation and wake up if need be.
 +      if(!self.active)
 +      {
 +              turret_track();
 +              return;
 +      }
 +
 +      // This is typicaly used for zaping every target in range
 +      // turret_fusionreactor uses this to recharge friendlys.
 +      if (self.shoot_flags & TFL_SHOOT_HITALLVALID)
 +      {
 +              // Do a self.turret_fire for every valid target.
 +              e = findradius(self.origin,self.target_range);
 +              while (e)
 +              {
 +                      if(e.takedamage)
 +                      {
 +                              if (turret_validate_target(self,e,self.target_validate_flags))
 +                              {
 +                                      self.enemy = e;
 +
 +                                      turret_do_updates(self);
 +
 +                                      if (self.turret_firecheckfunc())
 +                                              turret_fire();
 +                              }
 +                      }
 +
 +                      e = e.chain;
 +              }
 +              self.enemy = world;
 +      }
 +      else if(self.shoot_flags & TFL_SHOOT_CUSTOM)
 +      {
 +              // This one is doing something.. oddball. assume its handles what needs to be handled.
 +
 +              // Predict?
 +              if(!(self.aim_flags & TFL_AIM_NO))
 +                      self.tur_aimpos = turret_aim_generic();
 +
 +              // Turn & pitch?
 +              if(!(self.track_flags & TFL_TRACK_NO))
 +                      turret_track();
 +
 +              turret_do_updates(self);
 +
 +              // Fire?
 +              if (self.turret_firecheckfunc())
 +                      turret_fire();
 +      }
 +      else
 +      {
 +              // Special case for volly always. if it fired once it must compleate the volly.
 +              if(self.shoot_flags & TFL_SHOOT_VOLLYALWAYS)
 +                      if(self.volly_counter != self.shot_volly)
 +                      {
 +                              // Predict or whatnot
 +                              if(!(self.aim_flags & TFL_AIM_NO))
 +                                      self.tur_aimpos = turret_aim_generic();
 +
 +                              // Turn & pitch
 +                              if(!(self.track_flags & TFL_TRACK_NO))
 +                                      turret_track();
 +
 +                              turret_do_updates(self);
 +
 +                              // Fire!
 +                              if (self.turret_firecheckfunc() != 0)
 +                                      turret_fire();
 +                                      
 +                              TUR_ACTION(self.turretid, TR_THINK);
 +
 +                              return;
 +                      }
 +
 +              // Check if we have a vailid enemy, and try to find one if we dont.
 +
 +              // g_turrets_targetscan_maxdelay forces a target re-scan at least this often
 +              float do_target_scan = 0;
 +              if((self.target_select_time + autocvar_g_turrets_targetscan_maxdelay) < time)
 +                      do_target_scan = 1;
 +
 +              // Old target (if any) invalid?
 +              if(self.target_validate_time < time)
 +              if (turret_validate_target(self, self.enemy, self.target_validate_flags) <= 0)
 +              {
 +                      self.enemy = world;
 +                      self.target_validate_time = time + 0.5;
 +                      do_target_scan = 1;
 +              }
 +
 +              // But never more often then g_turrets_targetscan_mindelay!
 +              if (self.target_select_time + autocvar_g_turrets_targetscan_mindelay > time)
 +                      do_target_scan = 0;
 +
 +              if(do_target_scan)
 +              {
 +                      self.enemy = turret_select_target();
 +                      self.target_select_time = time;
 +              }
 +
 +              // No target, just go to idle, do any custom stuff and bail.
 +              if (self.enemy == world)
 +              {
 +                      // Turn & pitch
 +                      if(!(self.track_flags & TFL_TRACK_NO))
 +                              turret_track();
 +                              
 +                      TUR_ACTION(self.turretid, TR_THINK);
 +
 +                      // And bail.
 +                      return;
 +              }
 +              else
 +                      self.lip = time + autocvar_g_turrets_aimidle_delay; // Keep track of the last time we had a target.
 +
 +              // Predict?
 +              if(!(self.aim_flags & TFL_AIM_NO))
 +                      self.tur_aimpos = turret_aim_generic();
 +
 +              // Turn & pitch?
 +              if(!(self.track_flags & TFL_TRACK_NO))
 +                      turret_track();
 +
 +              turret_do_updates(self);
 +
 +              // Fire?
 +              if (self.turret_firecheckfunc())
 +                      turret_fire();
 +      }
 +
 +      TUR_ACTION(self.turretid, TR_THINK);
 +}
 +
 +/*
 +      When .used a turret switch team to activator.team.
 +      If activator is world, the turret go inactive.
 +*/
 +void turret_use()
 +{
 +      dprint("Turret ",self.netname, " used by ", activator.classname, "\n");
 +
 +      self.team = activator.team;
 +
 +      if(self.team == 0)
 +              self.active = ACTIVE_NOT;
 +      else
 +              self.active = ACTIVE_ACTIVE;
 +
 +}
 +
 +void turret_link()
 +{
 +      Net_LinkEntity(self, TRUE, 0, turret_send);
 +      self.think       = turret_think;
 +      self.nextthink = time;
 +      self.tur_head.effects = EF_NODRAW;
 +}
 +
 +void turrets_manager_think()
 +{
 +      self.nextthink = time + 1;
 +
 +      entity e;
 +      if (autocvar_g_turrets_reloadcvars == 1)
 +      {
 +              e = nextent(world);
 +              while (e)
 +              {
 +                      if (e.turret_flags & TUR_FLAG_ISTURRET)
 +                      {
 +                              load_unit_settings(e,e.cvar_basename,1);
 +                              TUR_ACTION(self.turretid, TR_THINK);
 +                      }
 +
 +                      e = nextent(e);
 +              }
 +              cvar_set("g_turrets_reloadcvars","0");
 +      }
 +}
 +
 +float turret_initialize(float tur_id)
 +{
 +      if(!autocvar_g_turrets)
 +              return FALSE;
 +
 +      entity e;
 +      entity tur = get_turretinfo(tur_id);
 +      if(tur.turretid == 0)
 +              return FALSE; // invalid turret
 +
++      if(!self.tur_head) { TUR_ACTION(tur_id, TR_PRECACHE); } // if tur_head exists, we can assume this turret re-spawned
++
 +      e = find(world, classname, "turret_manager");
 +      if(!e)
 +      {
 +              e = spawn();
 +              e.classname = "turret_manager";
 +              e.think = turrets_manager_think;
 +              e.nextthink = time + 2;
 +      }
 +
 +      if(!(self.spawnflags & TSF_SUSPENDED))
 +              builtin_droptofloor();
 +
 +      self.cvar_basename = tur.cvar_basename;
 +      load_unit_settings(self, self.cvar_basename, 0);
 +      
 +      if(!self.team || !teamplay)             { self.team = MAX_SHOT_DISTANCE; }
 +      if(!self.ticrate)                               { self.ticrate = ((self.turret_flags & TUR_FLAG_SUPPORT) ? 0.2 : 0.1); }
 +      if(!self.health)                                { self.health = 1000; }
 +      if(!self.shot_refire)                   { self.shot_refire = 1; }
 +      if(!self.tur_shotorg)                   { self.tur_shotorg = '50 0 50'; }
 +      if(!self.turret_flags)                  { self.turret_flags = TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER; }
 +      if(!self.damage_flags)                  { self.damage_flags = TFL_DMG_YES | TFL_DMG_RETALIATE | TFL_DMG_AIMSHAKE; }
 +      if(!self.aim_flags)                             { self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; }
 +      if(!self.track_type)                    { self.track_type = TFL_TRACKTYPE_STEPMOTOR; }
 +      if(!self.track_flags)                   { self.track_flags = TFL_TRACK_PITCH | TFL_TRACK_ROTATE; }
 +      if(!self.ammo_flags)                    { self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE; }
 +      if(!self.target_select_flags)   { self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_ANGLELIMITS; }
 +      if(!self.firecheck_flags)               { self.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_LOS
 +                                                                                                                 | TFL_FIRECHECK_AIMDIST | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_AMMO_OWN | TFL_FIRECHECK_REFIRE; }
 +                                                                                                                 
 +      if(self.track_type != TFL_TRACKTYPE_STEPMOTOR)
 +      {
 +              // Fluid / Ineria mode. Looks mutch nicer.
 +              // Can reduce aim preformance alot, needs a bit diffrent aimspeed
 +              
 +              self.aim_speed = bound(0.1, ((!self.aim_speed) ? 180 : self.aim_speed), 1000);
 +              
 +              if(!self.track_accel_pitch)             { self.track_accel_pitch = 0.5; }
 +              if(!self.track_accel_rotate)    { self.track_accel_rotate = 0.5; }
 +              if(!self.track_blendrate)               { self.track_blendrate = 0.35; }
 +      }
 +      
 +      self.respawntime                                = max(-1, ((!self.respawntime) ? 60 : self.respawntime));
 +      self.shot_refire                                = bound(0.01, ((!self.shot_refire) ? 1 : self.shot_refire), 9999);
 +      self.shot_dmg                                   = max(1, ((!self.shot_dmg) ? self.shot_refire * 50 : self.shot_dmg));
 +      self.shot_radius                                = max(1, ((!self.shot_radius) ? self.shot_dmg * 0.5 : self.shot_radius));
 +      self.shot_speed                                 = max(1, ((!self.shot_speed) ? 2500 : self.shot_speed));
 +      self.shot_spread                                = bound(0.0001, ((!self.shot_spread) ? 0.0125 : self.shot_spread), 500);
 +      self.shot_force                                 = bound(0.001, ((!self.shot_force) ? self.shot_dmg * 0.5 + self.shot_radius * 0.5 : self.shot_force), 5000);
 +      self.shot_volly                                 = bound(1, ((!self.shot_volly) ? 1 : self.shot_volly), floor(self.ammo_max / self.shot_dmg));
 +      self.shot_volly_refire                  = bound(self.shot_refire, ((!self.shot_volly_refire) ? self.shot_refire * self.shot_volly : self.shot_volly_refire), 60);
 +      self.target_range                               = bound(0, ((!self.target_range) ? self.shot_speed * 0.5 : self.target_range), MAX_SHOT_DISTANCE);
 +      self.target_range_min                   = bound(0, ((!self.target_range_min) ? self.shot_radius * 2 : self.target_range_min), MAX_SHOT_DISTANCE);
 +      self.target_range_optimal               = bound(0, ((!self.target_range_optimal) ? self.target_range * 0.5 : self.target_range_optimal), MAX_SHOT_DISTANCE);
 +      self.aim_maxrotate                              = bound(0, ((!self.aim_maxrotate) ? 90 : self.aim_maxrotate), 360);
 +      self.aim_maxpitch                               = bound(0, ((!self.aim_maxpitch) ? 20 : self.aim_maxpitch), 90);
 +      self.aim_speed                                  = bound(0.1, ((!self.aim_speed) ? 36 : self.aim_speed), 1000);
 +      self.aim_firetolerance_dist     = bound(0.1, ((!self.aim_firetolerance_dist) ? 5 + (self.shot_radius * 2) : self.aim_firetolerance_dist), MAX_SHOT_DISTANCE);
 +      self.target_select_rangebias    = bound(-10, ((!self.target_select_rangebias) ? 1 : self.target_select_rangebias), 10);
 +      self.target_select_samebias     = bound(-10, ((!self.target_select_samebias) ? 1 : self.target_select_samebias), 10);
 +      self.target_select_anglebias    = bound(-10, ((!self.target_select_anglebias) ? 1 : self.target_select_anglebias), 10);
 +      self.target_select_missilebias  = bound(-10, ((!self.target_select_missilebias) ? 1 : self.target_select_missilebias), 10);
 +      self.target_select_playerbias   = bound(-10, ((!self.target_select_playerbias) ? 1 : self.target_select_playerbias), 10);
 +      self.ammo_max                                   = max(self.shot_dmg, ((!self.ammo_max) ? self.shot_dmg * 10 : self.ammo_max));
 +      self.ammo_recharge                              = max(0, ((!self.ammo_recharge) ? self.shot_dmg * 0.5 : self.ammo_recharge));
 +      
 +      self.turret_flags = TUR_FLAG_ISTURRET | (tur.spawnflags);
 +      
 +      if(self.turret_flags & TUR_FLAG_SPLASH)
 +              self.aim_flags |= TFL_AIM_SPLASH;
 +              
 +      if(self.turret_flags & TUR_FLAG_MISSILE)
 +              self.target_select_flags |= TFL_TARGETSELECT_MISSILES;
 +
 +      if(self.turret_flags & TUR_FLAG_PLAYER)
 +              self.target_select_flags |= TFL_TARGETSELECT_PLAYERS;
 +              
 +      if(self.spawnflags & TSL_NO_RESPAWN)
 +              self.damage_flags |= TFL_DMG_DEATH_NORESPAWN;
 +              
 +      if (self.turret_flags & TUR_FLAG_SUPPORT)
 +              self.turret_score_target = turret_targetscore_support;
 +      else
 +              self.turret_score_target = turret_targetscore_generic;
 +              
 +      ++turret_count;
 +              
 +      setmodel(self, tur.model);
 +      setsize(self, tur.mins, tur.maxs);
 +      
 +      self.turretid                           = tur_id;
 +      self.classname                          = "turret_main";
 +      self.active                                     = ACTIVE_ACTIVE;
 +      self.effects                            = EF_NODRAW;
 +      self.netname                            = TUR_NAME(tur_id);
 +      self.ticrate                            = bound(sys_frametime, self.ticrate, 60);
 +      self.max_health                         = self.health;
 +      self.target_validate_flags      = self.target_select_flags;
 +      self.ammo                                       = self.ammo_max;
 +      self.ammo_recharge                 *= self.ticrate;
 +      self.solid                                      = SOLID_BBOX;
 +      self.takedamage                         = DAMAGE_AIM;
 +      self.movetype                           = MOVETYPE_NOCLIP;
 +      self.view_ofs                           = '0 0 0';
 +      self.turret_firecheckfunc       = turret_firecheck;
 +      self.event_damage                       = turret_damage;
 +      self.use                                        = turret_use;
 +      self.bot_attack                         = TRUE;
 +      self.nextthink                          = time + 1;
 +      self.nextthink                     += turret_count * sys_frametime;
 +      
 +      self.tur_head = spawn();
 +      setmodel(self.tur_head, tur.head_model);
 +      setsize(self.tur_head, '0 0 0', '0 0 0');
 +      setorigin(self.tur_head, '0 0 0');
 +      setattachment(self.tur_head, self, "tag_head");
 +      
 +      self.tur_head.netname           = self.tur_head.classname = "turret_head";
 +      self.tur_head.team                      = self.team;
 +      self.tur_head.owner                     = self;
 +      self.tur_head.takedamage        = DAMAGE_NO;
 +      self.tur_head.solid                     = SOLID_NOT;
 +      self.tur_head.movetype          = self.movetype;
 +      
 +      if(!self.tur_defend)
 +      if(self.target != "")
 +      {
 +              self.tur_defend = find(world, targetname, self.target);
 +              if (self.tur_defend == world)
 +              {
 +                      self.target = "";
 +                      dprint("Turret has invalid defendpoint!\n");
 +              }
 +      }
 +      
 +      if (self.tur_defend)
 +              self.idle_aim = self.tur_head.angles + angleofs(self.tur_head, self.tur_defend);
 +      else
 +              self.idle_aim = '0 0 0';
 +              
 +#ifdef TURRET_DEBUG
 +      self.tur_debug_start = self.nextthink;
 +      while (vlen(self.tur_debug_rvec) < 2)
 +              self.tur_debug_rvec = randomvec() * 4;
 +
 +      self.tur_debug_rvec_x = fabs(self.tur_debug_rvec_x);
 +      self.tur_debug_rvec_y = fabs(self.tur_debug_rvec_y);
 +      self.tur_debug_rvec_z = fabs(self.tur_debug_rvec_z);
 +#endif
 +
 +      turret_link();
 +      turret_respawn();
 +      turret_tag_fire_update();
 +      
 +      TUR_ACTION(tur_id, TR_SETUP);
 +      
 +      if(MUTATOR_CALLHOOK(TurretSpawn))
 +              return FALSE;
 +
 +      return TRUE;
 +}
index 01fb660,0000000..4c588e9
mode 100644,000000..100644
--- /dev/null
@@@ -1,79 -1,0 +1,78 @@@
-       precache_model ("models/turrets/terrainbase.md3");
 +#include "all.qh"
 +
 +// TURRET PLUGIN SYSTEM
 +entity turret_info[TUR_MAXCOUNT];
 +entity dummy_turret_info;
 +
 +void turrets_common_precache()
 +{
 +      precache_sound ("weapons/rocket_impact.wav");
 +      precache_model ("models/turrets/base-gib1.md3");
 +      precache_model ("models/turrets/base-gib2.md3");
 +      precache_model ("models/turrets/base-gib3.md3");
 +      precache_model ("models/turrets/base-gib4.md3");
 +      precache_model ("models/turrets/head-gib1.md3");
 +      precache_model ("models/turrets/head-gib2.md3");
 +      precache_model ("models/turrets/head-gib3.md3");
 +      precache_model ("models/turrets/head-gib4.md3");
-       func(TR_PRECACHE);
 +      precache_model ("models/turrets/base.md3");
 +      precache_model ("models/turrets/rocket.md3");
 +      
 +      precache_model ("models/turrets/c512.md3");
 +      precache_model ("models/marker.md3");
 +      
 +#ifdef TURRET_DEBUG
++      precache_model ("models/turrets/terrainbase.md3");
 +      precache_model ("models/turrets/c512.md3");
 +      precache_model ("models/pathlib/goodsquare.md3");
 +      precache_model ("models/pathlib/badsquare.md3");
 +      precache_model ("models/pathlib/square.md3");
 +      precache_model ("models/pathlib/edge.md3");
 +#endif
 +}
 +
 +void register_turret(float id, float(float) func, float turretflags, vector min_s, vector max_s, string modelname, string headmodelname, string shortname, string mname)
 +{
 +      entity e;
 +      turret_info[id - 1] = e = spawn();
 +      e.classname = "turret_info";
 +      e.turretid = id;
 +      e.netname = shortname;
 +      e.turret_name = mname;
 +      e.turret_func = func;
 +      e.mdl = modelname;
 +      e.cvar_basename = shortname;
 +      e.spawnflags = turretflags;
 +      e.mins = min_s;
 +      e.maxs = max_s;
 +      e.model = strzone(strcat("models/turrets/", modelname));
 +      e.head_model = strzone(strcat("models/turrets/", headmodelname));
 +      
 +      #ifndef MENUQC
 +      turrets_common_precache();
 +      #endif
 +}
 +float t_null(float dummy) { return 0; }
 +void register_turrets_done()
 +{
 +      dummy_turret_info = spawn();
 +      dummy_turret_info.classname = "turret_info";
 +      dummy_turret_info.turretid = 0; // you can recognize dummies by this
 +      dummy_turret_info.netname = "";
 +      dummy_turret_info.turret_name = "Turret";
 +      dummy_turret_info.turret_func = t_null;
 +      dummy_turret_info.mdl = "";
 +      dummy_turret_info.mins = '-0 -0 -0';
 +      dummy_turret_info.maxs = '0 0 0';
 +      dummy_turret_info.model = "";
 +}
 +entity get_turretinfo(float id)
 +{
 +      entity m;
 +      if(id < TUR_FIRST || id > TUR_LAST)
 +              return dummy_turret_info;
 +      m = turret_info[id - 1];
 +      if(m)
 +              return m;
 +      return dummy_turret_info;
 +}
index 7787149,0000000..1c2dc55
mode 100644,000000..100644
--- /dev/null
@@@ -1,313 -1,0 +1,311 @@@
-                               _mis = turret_projectile("weapons/lasergun_fire.wav", 1, 0, DEATH_TURRET_EWHEEL, PROJECTILE_LASER, TRUE, TRUE);
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ EWHEEL,
 +/* function   */ t_ewheel,
 +/* spawnflags */ TUR_FLAG_PLAYER | TUR_FLAG_MOVE | TUR_FLAG_ROAM,
 +/* mins,maxs  */ '-32 -32 0', '32 32 48',
 +/* model      */ "ewheel-base2.md3",
 +/* head_model */ "ewheel-gun1.md3",
 +/* netname    */ "ewheel",
 +/* fullname   */ _("eWheel Turret")
 +);
 +#else
 +#ifdef SVQC
 +float autocvar_g_turrets_unit_ewheel_speed_fast;
 +float autocvar_g_turrets_unit_ewheel_speed_slow;
 +float autocvar_g_turrets_unit_ewheel_speed_slower;
 +float autocvar_g_turrets_unit_ewheel_speed_stop;
 +float autocvar_g_turrets_unit_ewheel_turnrate;
 +
 +const float ewheel_anim_stop = 0;
 +const float ewheel_anim_fwd_slow = 1;
 +const float ewheel_anim_fwd_fast = 2;
 +const float ewheel_anim_bck_slow = 3;
 +const float ewheel_anim_bck_fast = 4;
 +
 +//#define EWHEEL_FANCYPATH
 +void ewheel_move_path()
 +{
 +#ifdef EWHEEL_FANCYPATH
 +      // Are we close enougth to a path node to switch to the next?
 +      if (vlen(self.origin  - self.pathcurrent.origin) < 64)
 +              if (self.pathcurrent.path_next == world)
 +              {
 +                      // Path endpoint reached
 +                      pathlib_deletepath(self.pathcurrent.owner);
 +                      self.pathcurrent = world;
 +
 +                      if (self.pathgoal)
 +                      {
 +                              if (self.pathgoal.use)
 +                                      self.pathgoal.use();
 +
 +                              if (self.pathgoal.enemy)
 +                              {
 +                                      self.pathcurrent = pathlib_astar(self.pathgoal.origin,self.pathgoal.enemy.origin);
 +                                      self.pathgoal = self.pathgoal.enemy;
 +                              }
 +                      }
 +                      else
 +                              self.pathgoal = world;
 +              }
 +              else
 +                      self.pathcurrent = self.pathcurrent.path_next;
 +
 +#else
 +      if (vlen(self.origin - self.pathcurrent.origin) < 64)
 +              self.pathcurrent = self.pathcurrent.enemy;
 +#endif
 +
 +      if (self.pathcurrent)
 +      {
 +
 +              self.moveto = self.pathcurrent.origin;
 +              self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95);
 +
 +              movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_fast), 0.4);
 +      }
 +}
 +
 +void ewheel_move_enemy()
 +{
 +      float newframe;
 +
 +      self.steerto = steerlib_arrive(self.enemy.origin,self.target_range_optimal);
 +      
 +      self.moveto  = self.origin + self.steerto * 128;
 +
 +      if (self.tur_dist_enemy > self.target_range_optimal)
 +      {
 +              if ( self.tur_head.spawnshieldtime < 1 )
 +              {
 +                      newframe = ewheel_anim_fwd_fast;
 +                      movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_fast), 0.4);
 +              }
 +              else if (self.tur_head.spawnshieldtime < 2)
 +              {
 +
 +                      newframe = ewheel_anim_fwd_slow;
 +                      movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_slow), 0.4);
 +         }
 +              else
 +              {
 +                      newframe = ewheel_anim_fwd_slow;
 +                      movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_slower), 0.4);
 +              }
 +      }
 +      else if (self.tur_dist_enemy < self.target_range_optimal * 0.5)
 +      {
 +              newframe = ewheel_anim_bck_slow;
 +              movelib_move_simple(v_forward * -1, (autocvar_g_turrets_unit_ewheel_speed_slow), 0.4);
 +      }
 +      else
 +      {
 +              newframe = ewheel_anim_stop;
 +              movelib_beak_simple((autocvar_g_turrets_unit_ewheel_speed_stop));
 +      }
 +
 +      turrets_setframe(newframe, FALSE);
 +}
 +
 +void ewheel_move_idle()
 +{
 +      if(self.frame != 0)
 +      {
 +              self.SendFlags |= TNSF_ANIM;
 +              self.anim_start_time = time;
 +      }
 +
 +      self.frame = 0;
 +      if (vlen(self.velocity))
 +              movelib_beak_simple((autocvar_g_turrets_unit_ewheel_speed_stop));
 +}
 +
 +void spawnfunc_turret_ewheel() { if(!turret_initialize(TUR_EWHEEL)) remove(self); }
 +
 +float t_ewheel(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      float i;
 +                      entity _mis;
 +
 +                      for (i = 0; i < 1; ++i)
 +                      {
 +                              turret_do_updates(self);
 +
-                       precache_model ("models/turrets/ewheel-base2.md3");
-                       precache_model ("models/turrets/ewheel-gun1.md3");
++                              _mis = turret_projectile("weapons/lasergun_fire.wav", 1, 0, DEATH_TURRET_EWHEEL, PROJECTILE_BLASTER, TRUE, TRUE);
 +                              _mis.missile_flags = MIF_SPLASH;
 +
 +                              pointparticles(particleeffectnum("laser_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1);
 +
 +                              self.tur_head.frame += 2;
 +
 +                              if (self.tur_head.frame > 3)
 +                                      self.tur_head.frame = 0;
 +                      }
 +                      
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      float vz;
 +                      vector wish_angle, real_angle;
 +
 +                      vz = self.velocity_z;
 +
 +                      self.angles_x = anglemods(self.angles_x);
 +                      self.angles_y = anglemods(self.angles_y);
 +
 +                      fixedmakevectors(self.angles);
 +
 +                      wish_angle = normalize(self.steerto);
 +                      wish_angle = vectoangles(wish_angle);
 +                      real_angle = wish_angle - self.angles;
 +                      real_angle = shortangle_vxy(real_angle, self.tur_head.angles);
 +
 +                      self.tur_head.spawnshieldtime = fabs(real_angle_y);
 +                      real_angle_y  = bound(-self.tur_head.aim_speed, real_angle_y, self.tur_head.aim_speed);
 +                      self.angles_y = (self.angles_y + real_angle_y);
 +
 +                      if(self.enemy)
 +                              ewheel_move_enemy();
 +                      else if(self.pathcurrent)
 +                              ewheel_move_path();
 +                      else
 +                              ewheel_move_idle();
 +
 +                      self.velocity_z = vz;
 +
 +                      if(vlen(self.velocity))
 +                              self.SendFlags |= TNSF_MOVE;
 +              
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      self.velocity = '0 0 0';
 +
 +#ifdef EWHEEL_FANCYPATH
 +                      if (self.pathcurrent)
 +                              pathlib_deletepath(self.pathcurrent.owner);
 +#endif
 +                      self.pathcurrent = world;
 +      
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      entity e;
 +                      
 +                      if(self.movetype == MOVETYPE_WALK)
 +                      {
 +                              self.velocity = '0 0 0';
 +                              self.enemy = world;
 +
 +                              setorigin(self, self.pos1);
 +
 +                              if (self.target != "")
 +                              {
 +                                      e = find(world, targetname, self.target);
 +                                      if (!e)
 +                                      {
 +                                              dprint("Initital waypoint for ewheel does NOT exsist, fix your map!\n");
 +                                              self.target = "";
 +                                      }
 +
 +                                      if (e.classname != "turret_checkpoint")
 +                                              dprint("Warning: not a turrret path\n");
 +                                      else
 +                                      {
 +
 +#ifdef EWHEEL_FANCYPATH
 +                                              self.pathcurrent = WALKER_PATH(self.origin,e.origin);
 +                                              self.pathgoal = e;
 +#else
 +                                              self.pathcurrent  = e;
 +#endif
 +                                      }
 +                              }
 +                      }
 +                      
 +                      self.iscreature                         = TRUE;
 +                      self.teleportable                       = TELEPORT_NORMAL;
 +                      self.damagedbycontents          = TRUE;
 +                      self.movetype                           = MOVETYPE_WALK;
 +                      self.solid                                      = SOLID_SLIDEBOX;
 +                      self.takedamage                         = DAMAGE_AIM;
 +                      self.idle_aim                           = '0 0 0';
 +                      self.pos1                                       = self.origin;
 +                      self.target_select_flags        = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
 +                      self.target_validate_flags      = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
 +                      self.frame                                      = self.tur_head.frame = 1;
 +                      self.ammo_flags                         = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE;
 +                      
 +                      // Convert from dgr / sec to dgr / tic
 +                      self.tur_head.aim_speed = (autocvar_g_turrets_unit_ewheel_turnrate);
 +                      self.tur_head.aim_speed = self.tur_head.aim_speed / (1 / self.ticrate);
 +              
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/ewheel-base2.md3");
 +                      precache_model ("models/turrets/ewheel-gun1.md3");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +
 +void ewheel_draw()
 +{
 +      float dt;
 +
 +      dt = time - self.move_time;
 +      self.move_time = time;
 +      if(dt <= 0)
 +              return;
 +
 +      fixedmakevectors(self.angles);
 +      setorigin(self, self.origin + self.velocity * dt);
 +      self.tur_head.angles += dt * self.tur_head.move_avelocity;
 +      self.angles_y = self.move_angles_y;
 +
 +      if (self.health < 127)
 +      if(random() < 0.05)
 +              te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
 +}
 +
 +float t_ewheel(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      self.gravity            = 1;
 +                      self.movetype           = MOVETYPE_BOUNCE;
 +                      self.move_movetype      = MOVETYPE_BOUNCE;
 +                      self.move_origin        = self.origin;
 +                      self.move_time          = time;
 +                      self.draw                       = ewheel_draw;
 +                      
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index 436c86e,0000000..8c131e7
mode 100644,000000..100644
--- /dev/null
@@@ -1,105 -1,0 +1,103 @@@
-       d = RadiusDamage (self, self.owner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, self.owner.shot_force, self.totalfrags, world);
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ FLAC,
 +/* function   */ t_flac,
 +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_MISSILE,
 +/* mins,maxs  */ '-32 -32 0', '32 32 64',
 +/* model        */ "base.md3",
 +/* head_model */ "flac.md3",
 +/* netname      */ "flac",
 +/* fullname   */ _("FLAC Cannon")
 +);
 +#else
 +#ifdef SVQC
 +void turret_flac_projectile_think_explode()
 +{
 +      if(self.enemy != world)
 +      if(vlen(self.origin - self.enemy.origin) < self.owner.shot_radius * 3)
 +              setorigin(self,self.enemy.origin + randomvec() * self.owner.shot_radius);
 +
 +#ifdef TURRET_DEBUG
 +      float d;
-       RadiusDamage (self, self.realowner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, self.owner.shot_force, self.totalfrags, world);
++      d = RadiusDamage (self, self.owner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world);
 +      self.owner.tur_dbg_dmg_t_h = self.owner.tur_dbg_dmg_t_h + d;
 +      self.owner.tur_dbg_dmg_t_f = self.owner.tur_dbg_dmg_t_f + self.owner.shot_dmg;
 +#else
-                       precache_model ("models/turrets/base.md3");
-                       precache_model ("models/turrets/flac.md3");
++      RadiusDamage (self, self.realowner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world);
 +#endif
 +      remove(self);
 +}
 +
 +void spawnfunc_turret_flac() { if(!turret_initialize(TUR_FLAC)) remove(self); }
 +
 +float t_flac(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      entity proj;
 +
 +                      turret_tag_fire_update();
 +
 +                      proj = turret_projectile("weapons/hagar_fire.wav", 5, 0, DEATH_TURRET_FLAC, PROJECTILE_HAGAR, TRUE, TRUE);
 +                      pointparticles(particleeffectnum("laser_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1);
 +                      proj.think        = turret_flac_projectile_think_explode;
 +                      proj.nextthink  = time + self.tur_impacttime + (random() * 0.01 - random() * 0.01);
 +                      proj.missile_flags = MIF_SPLASH | MIF_PROXY;
 +
 +                      self.tur_head.frame = self.tur_head.frame + 1;
 +                      if (self.tur_head.frame >= 4)
 +                              self.tur_head.frame = 0;
 +                      
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE;
 +                      self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE;
 +                      self.damage_flags |= TFL_DMG_HEADSHAKE;
 +                      self.target_select_flags |= TFL_TARGETSELECT_NOTURRETS | TFL_TARGETSELECT_MISSILESONLY;
 +              
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/base.md3");
 +                      precache_model ("models/turrets/flac.md3");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +float t_flac(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index 9e7311a,0000000..d2a3c40
mode 100644,000000..100644
--- /dev/null
@@@ -1,118 -1,0 +1,116 @@@
-                       precache_model ("models/turrets/base.md3");
-                       precache_model ("models/turrets/reactor.md3");
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ FUSIONREACTOR,
 +/* function   */ t_fusionreactor,
 +/* spawnflags */ TUR_FLAG_SUPPORT | TUR_FLAG_AMMOSOURCE,
 +/* mins,maxs  */ '-34 -34 0', '34 34 90',
 +/* model        */ "base.md3",
 +/* head_model */ "reactor.md3",
 +/* netname      */ "fusionreactor",
 +/* fullname   */ _("Fusion Reactor")
 +);
 +#else
 +#ifdef SVQC
 +float turret_fusionreactor_firecheck()
 +{
 +      if (self.attack_finished_single > time)
 +              return 0;
 +
 +      if (self.enemy.deadflag != DEAD_NO)
 +              return 0;
 +
 +      if (self.enemy == world)
 +              return 0;
 +
 +      if (self.ammo < self.shot_dmg)
 +              return 0;
 +
 +      if (self.enemy.ammo >= self.enemy.ammo_max)
 +              return 0;
 +
 +      if (vlen(self.enemy.origin - self.origin) > self.target_range)
 +              return 0;
 +
 +      if(self.team != self.enemy.team)
 +              return 0;
 +
 +      if(!(self.enemy.ammo_flags & TFL_AMMO_ENERGY))
 +              return 0;
 +
 +      return 1;
 +}
 +
 +void spawnfunc_turret_fusionreactor() { if(!turret_initialize(TUR_FUSIONREACTOR)) remove(self); }
 +
 +float t_fusionreactor(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      vector fl_org;
 +
 +                      self.enemy.ammo = min(self.enemy.ammo + self.shot_dmg,self.enemy.ammo_max);
 +                      fl_org = 0.5 * (self.enemy.absmin + self.enemy.absmax);
 +                      te_smallflash(fl_org);
 +                      
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      self.tur_head.avelocity = '0 250 0' * (self.ammo / self.ammo_max);
 +              
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.ammo_flags                         = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE;
 +                      self.target_select_flags        = TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_OWNTEAM | TFL_TARGETSELECT_RANGELIMITS;
 +                      self.firecheck_flags            = TFL_FIRECHECK_AMMO_OWN | TFL_FIRECHECK_AMMO_OTHER | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_DEAD;
 +                      self.shoot_flags                        = TFL_SHOOT_HITALLVALID;
 +                      self.aim_flags                          = TFL_AIM_NO;
 +                      self.track_flags                        = TFL_TRACK_NO;
 +      
 +                      self.tur_head.scale = 0.75;
 +                      self.tur_head.avelocity = '0 50 0';
 +                      
 +                      self.turret_firecheckfunc = turret_fusionreactor_firecheck;
 +              
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/base.md3");
 +                      precache_model ("models/turrets/reactor.md3");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +float t_fusionreactor(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index c611e6d,0000000..57dca3b
mode 100644,000000..100644
--- /dev/null
@@@ -1,162 -1,0 +1,160 @@@
-                       precache_model ("models/turrets/base.md3");
-                       precache_model ("models/turrets/hellion.md3");
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ HELLION,
 +/* function   */ t_hellion,
 +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE,
 +/* mins,maxs  */ '-32 -32 0', '32 32 64',
 +/* model        */ "base.md3",
 +/* head_model */ "hellion.md3",
 +/* netname      */ "hellion",
 +/* fullname   */ _("Hellion Missile Turret")
 +);
 +#else
 +#ifdef SVQC
 +float autocvar_g_turrets_unit_hellion_shot_speed_gain;
 +float autocvar_g_turrets_unit_hellion_shot_speed_max;
 +
 +void turret_hellion_missile_think()
 +{
 +      vector olddir,newdir;
 +      vector pre_pos;
 +      float itime;
 +
 +      self.nextthink = time + 0.05;
 +
 +      olddir = normalize(self.velocity);
 +
 +      if(self.max_health < time)
 +              turret_projectile_explode();
 +
 +      // Enemy dead? just keep on the current heading then.
 +      if ((self.enemy == world) || (self.enemy.deadflag != DEAD_NO))
 +      {
 +
 +              // Make sure we dont return to tracking a respawned player
 +              self.enemy = world;
 +
 +              // Turn model
 +              self.angles = vectoangles(self.velocity);
 +
 +              if ( (vlen(self.origin - self.owner.origin)) > (self.owner.shot_radius * 5) )
 +                      turret_projectile_explode();
 +
 +              // Accelerate
 +              self.velocity = olddir * min(vlen(self.velocity) * (autocvar_g_turrets_unit_hellion_shot_speed_gain), (autocvar_g_turrets_unit_hellion_shot_speed_max));
 +
 +              UpdateCSQCProjectile(self);
 +
 +              return;
 +      }
 +
 +      // Enemy in range?
 +      if (vlen(self.origin - self.enemy.origin) < self.owner.shot_radius * 0.2)
 +              turret_projectile_explode();
 +
 +      // Predict enemy position
 +      itime = vlen(self.enemy.origin - self.origin) / vlen(self.velocity);
 +      pre_pos = self.enemy.origin + self.enemy.velocity * itime;
 +
 +      pre_pos = (pre_pos + self.enemy.origin) * 0.5;
 +
 +      // Find out the direction to that place
 +      newdir = normalize(pre_pos - self.origin);
 +
 +      // Turn
 +      newdir = normalize(olddir + newdir * 0.35);
 +
 +      // Turn model
 +      self.angles = vectoangles(self.velocity);
 +
 +      // Accelerate
 +      self.velocity = newdir * min(vlen(self.velocity) * (autocvar_g_turrets_unit_hellion_shot_speed_gain), (autocvar_g_turrets_unit_hellion_shot_speed_max));
 +
 +      if (itime < 0.05)
 +              self.think = turret_projectile_explode;
 +
 +      UpdateCSQCProjectile(self);
 +}
 +
 +void spawnfunc_turret_hellion() { if(!turret_initialize(TUR_HELLION)) remove(self); }
 +
 +float t_hellion(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      entity missile;
 +
 +                      if(self.tur_head.frame != 0)
 +                              self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire"));
 +                      else
 +                              self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire2"));
 +
 +                      missile = turret_projectile("weapons/rocket_fire.wav", 6, 10, DEATH_TURRET_HELLION, PROJECTILE_ROCKET, FALSE, FALSE);
 +                      te_explosion (missile.origin);
 +                      missile.think           = turret_hellion_missile_think;
 +                      missile.nextthink       = time;
 +                      missile.flags           = FL_PROJECTILE;
 +                      missile.max_health   = time + 9;
 +                      missile.tur_aimpos   = randomvec() * 128;
 +                      missile.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT;
 +                      self.tur_head.frame += 1;
 +                      
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      if (self.tur_head.frame != 0)
 +                              self.tur_head.frame += 1;
 +
 +                      if (self.tur_head.frame >= 7)
 +                              self.tur_head.frame = 0;
 +              
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.aim_flags = TFL_AIM_SIMPLE;
 +                      self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK ;
 +                      self.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF | TFL_FIRECHECK_AMMO_OWN;
 +                      self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE;
 +              
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/base.md3");
 +                      precache_model ("models/turrets/hellion.md3");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +float t_hellion(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index b34ebf5,0000000..c0f55fa
mode 100644,000000..100644
--- /dev/null
@@@ -1,363 -1,0 +1,361 @@@
-                       precache_model ("models/turrets/base.md3");
-                       precache_model ("models/turrets/hk.md3");
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ HK,
 +/* function   */ t_hk,
 +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER | TUR_FLAG_RECIEVETARGETS,
 +/* mins,maxs  */ '-32 -32 0', '32 32 64',
 +/* model        */ "base.md3",
 +/* head_model */ "hk.md3",
 +/* netname      */ "hk",
 +/* fullname   */ _("Hunter-Killer Turret")
 +);
 +#else
 +#ifdef SVQC
 +float autocvar_g_turrets_unit_hk_shot_speed;
 +float autocvar_g_turrets_unit_hk_shot_speed_accel;
 +float autocvar_g_turrets_unit_hk_shot_speed_accel2;
 +float autocvar_g_turrets_unit_hk_shot_speed_decel;
 +float autocvar_g_turrets_unit_hk_shot_speed_max;
 +float autocvar_g_turrets_unit_hk_shot_speed_turnrate;
 +
 +//#define TURRET_DEBUG_HK
 +
 +#ifdef TURRET_DEBUG_HK
 +.float atime;
 +#endif
 +
 +float hk_is_valid_target(entity e_target)
 +{
 +      if (e_target == world)
 +              return 0;
 +
 +      // If only this was used more..
 +      if (e_target.flags & FL_NOTARGET)
 +              return 0;
 +
 +      // Cant touch this
 +      if ((e_target.takedamage == DAMAGE_NO) || (e_target.health < 0))
 +              return 0;
 +
 +      // player
 +      if (IS_CLIENT(e_target))
 +      {
 +              if (self.owner.target_select_playerbias < 0)
 +                      return 0;
 +
 +              if (e_target.deadflag != DEAD_NO)
 +                      return 0;
 +      }
 +
 +      // Missile
 +      if ((e_target.flags & FL_PROJECTILE) && (self.owner.target_select_missilebias < 0))
 +              return 0;
 +
 +      // Team check
 +      if ((e_target.team == self.owner.team) || (self.owner.team == e_target.owner.team))
 +              return 0;
 +
 +      return 1;
 +}
 +
 +void turret_hk_missile_think()
 +{
 +      vector vu, vd, vf, vl, vr, ve;  // Vector (direction)
 +      float  fu, fd, ff, fl, fr, fe;  // Fraction to solid
 +      vector olddir,wishdir,newdir;   // Final direction
 +      float lt_for;   // Length of Trace FORwrad
 +      float lt_seek;  // Length of Trace SEEK (left, right, up down)
 +      float pt_seek;  // Pitch of Trace SEEK (How mutch to angele left, right up, down trace towards v_forward)
 +      vector pre_pos;
 +      float myspeed;
 +      entity e;
 +      float ad,edist;
 +
 +      self.nextthink = time + self.ticrate;
 +
 +      //if (self.cnt < time)
 +      //      turret_hk_missile_explode();
 +
 +      if (self.enemy.deadflag != DEAD_NO)
 +              self.enemy = world;
 +
 +      // Pick the closest valid target.
 +      if (!self.enemy)
 +      {
 +              e = findradius(self.origin, 5000);
 +              while (e)
 +              {
 +                      if (hk_is_valid_target(e))
 +                      {
 +                              if (!self.enemy)
 +                                      self.enemy = e;
 +                              else
 +                                      if (vlen(self.origin - e.origin) < vlen(self.origin - self.enemy.origin))
 +                                              self.enemy = e;
 +                      }
 +                      e = e.chain;
 +              }
 +      }
 +
 +      self.angles = vectoangles(self.velocity);
 +      self.angles_x = self.angles_x * -1;
 +      makevectors(self.angles);
 +      self.angles_x = self.angles_x * -1;
 +
 +      if (self.enemy)
 +      {
 +              edist = vlen(self.origin - self.enemy.origin);
 +              // Close enougth to do decent damage?
 +              if ( edist <= (self.owner.shot_radius * 0.25) )
 +              {
 +                      turret_projectile_explode();
 +                      return;
 +              }
 +
 +              // Get data on enemy position
 +              pre_pos = self.enemy.origin +
 +                                self.enemy.velocity *
 +                                min((vlen(self.enemy.origin - self.origin) / vlen(self.velocity)),0.5);
 +
 +              traceline(self.origin, pre_pos,TRUE,self.enemy);
 +              ve = normalize(pre_pos - self.origin);
 +              fe = trace_fraction;
 +
 +      }
 +      else
 +      {
 +      edist = 0;
 +      ve = '0 0 0';
 +              fe = 0;
 +      }
 +
 +      if ((fe != 1) || (self.enemy == world) || (edist > 1000))
 +      {
 +              myspeed = vlen(self.velocity);
 +
 +              lt_for  = myspeed * 3;
 +              lt_seek = myspeed * 2.95;
 +
 +              // Trace forward
 +              traceline(self.origin, self.origin + v_forward * lt_for,FALSE,self);
 +              vf = trace_endpos;
 +              ff = trace_fraction;
 +
 +              // Find angular offset
 +              ad = vlen(vectoangles(normalize(self.enemy.origin - self.origin)) - self.angles);
 +
 +              // To close to something, Slow down!
 +              if ( ((ff < 0.7) || (ad > 4)) && (myspeed > (autocvar_g_turrets_unit_hk_shot_speed)) )
 +                      myspeed = max(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_decel), (autocvar_g_turrets_unit_hk_shot_speed));
 +
 +              // Failry clear, accelerate.
 +              if ( (ff > 0.7) && (myspeed < (autocvar_g_turrets_unit_hk_shot_speed_max)) )
 +                      myspeed = min(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_accel), (autocvar_g_turrets_unit_hk_shot_speed_max));
 +
 +              // Setup trace pitch
 +              pt_seek = 1 - ff;
 +              pt_seek = bound(0.15,pt_seek,0.8);
 +              if (ff < 0.5) pt_seek = 1;
 +
 +              // Trace left
 +              traceline(self.origin, self.origin + (-1 * (v_right * pt_seek) + (v_forward * ff)) * lt_seek,FALSE,self);
 +              vl = trace_endpos;
 +              fl = trace_fraction;
 +
 +              // Trace right
 +              traceline(self.origin,  self.origin + ((v_right * pt_seek) + (v_forward * ff)) * lt_seek ,FALSE,self);
 +              vr = trace_endpos;
 +              fr = trace_fraction;
 +
 +              // Trace up
 +              traceline(self.origin,  self.origin + ((v_up * pt_seek) + (v_forward * ff)) * lt_seek ,FALSE,self);
 +              vu = trace_endpos;
 +              fu = trace_fraction;
 +
 +              // Trace down
 +              traceline(self.origin,  self.origin + (-1 * (v_up * pt_seek) + (v_forward * ff)) * lt_seek ,FALSE,self);
 +              vd = trace_endpos;
 +              fd = trace_fraction;
 +
 +              vl = normalize(vl - self.origin);
 +              vr = normalize(vr - self.origin);
 +              vu = normalize(vu - self.origin);
 +              vd = normalize(vd - self.origin);
 +
 +              // Panic tresh passed, find a single direction and turn as hard as we can
 +              if (pt_seek == 1)
 +              {
 +                      wishdir = v_right;
 +                      if (fl > fr) wishdir = -1 * v_right;
 +                      if (fu > fl) wishdir = v_up;
 +                      if (fd > fu) wishdir = -1 * v_up;
 +              }
 +              else
 +              {
 +                      // Normalize our trace vectors to make a smooth path
 +                      wishdir = normalize( (vl * fl) + (vr * fr) +  (vu * fu) +  (vd * fd) );
 +              }
 +
 +              if (self.enemy)
 +              {
 +                      if (fe < 0.1) fe = 0.1; // Make sure we always try to move sligtly towards our target
 +                      wishdir = (wishdir * (1 - fe)) + (ve * fe);
 +              }
 +      }
 +      else
 +      {
 +              // Got a clear path to target, speed up fast (if not at full speed) and go straight for it.
 +              myspeed = vlen(self.velocity);
 +              if (myspeed < (autocvar_g_turrets_unit_hk_shot_speed_max))
 +                      myspeed = min(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_accel2),(autocvar_g_turrets_unit_hk_shot_speed_max));
 +
 +              wishdir = ve;
 +      }
 +
 +      if ((myspeed > (autocvar_g_turrets_unit_hk_shot_speed)) && (self.cnt > time))
 +              myspeed = min(myspeed * (autocvar_g_turrets_unit_hk_shot_speed_accel2),(autocvar_g_turrets_unit_hk_shot_speed_max));
 +
 +      // Ranoutagazfish?
 +      if (self.cnt < time)
 +      {
 +              self.cnt = time + 0.25;
 +              self.nextthink = 0;
 +              self.movetype            = MOVETYPE_BOUNCE;
 +              return;
 +      }
 +
 +      // Calculate new heading
 +      olddir = normalize(self.velocity);
 +      newdir = normalize(olddir + wishdir * (autocvar_g_turrets_unit_hk_shot_speed_turnrate));
 +
 +      // Set heading & speed
 +      self.velocity = newdir * myspeed;
 +
 +      // Align model with new heading
 +      self.angles = vectoangles(self.velocity);
 +
 +
 +#ifdef TURRET_DEBUG_HK
 +      //if(self.atime < time) {
 +      if ((fe <= 0.99)||(edist > 1000))
 +      {
 +              te_lightning2(world,self.origin, self.origin + vr * lt_seek);
 +              te_lightning2(world,self.origin, self.origin + vl * lt_seek);
 +              te_lightning2(world,self.origin, self.origin + vu * lt_seek);
 +              te_lightning2(world,self.origin, self.origin + vd * lt_seek);
 +              te_lightning2(world,self.origin, vf);
 +      }
 +      else
 +      {
 +              te_lightning2(world,self.origin, self.enemy.origin);
 +      }
 +      bprint("Speed: ", ftos(rint(myspeed)), "\n");
 +      bprint("Trace to solid: ", ftos(rint(ff * 100)), "%\n");
 +      bprint("Trace to target:", ftos(rint(fe * 100)), "%\n");
 +      self.atime = time + 0.2;
 +      //}
 +#endif
 +
 +      UpdateCSQCProjectile(self);
 +}
 +
 +float turret_hk_addtarget(entity e_target,entity e_sender)
 +{
 +      if (e_target)
 +      {
 +              if (turret_validate_target(self,e_target,self.target_validate_flags) > 0)
 +              {
 +                      self.enemy = e_target;
 +                      return 1;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +void spawnfunc_turret_hk() { if(!turret_initialize(TUR_HK)) remove(self); }
 +
 +float t_hk(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      entity missile;
 +
 +                      missile = turret_projectile("weapons/rocket_fire.wav", 6, 10, DEATH_TURRET_HK, PROJECTILE_ROCKET, FALSE, FALSE);
 +                      te_explosion (missile.origin);
 +
 +                      missile.think                   = turret_hk_missile_think;
 +                      missile.nextthink               = time + 0.25;
 +                      missile.movetype                 = MOVETYPE_BOUNCEMISSILE;
 +                      missile.velocity                 = self.tur_shotdir_updated * (self.shot_speed * 0.75);
 +                      missile.angles             = vectoangles(missile.velocity);
 +                      missile.cnt                       = time + 30;
 +                      missile.ticrate           = max(autocvar_sys_ticrate, 0.05);
 +                      missile.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_AI;
 +
 +                      if (self.tur_head.frame == 0)
 +                              self.tur_head.frame = self.tur_head.frame + 1;
 +
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      if (self.tur_head.frame != 0)
 +                              self.tur_head.frame = self.tur_head.frame + 1;
 +
 +                      if (self.tur_head.frame > 5)
 +                              self.tur_head.frame = 0;
 +
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE;
 +                      self.aim_flags = TFL_AIM_SIMPLE;
 +                      self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TRIGGERTARGET | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK;
 +                      self.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_TEAMCHECK  | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF;
 +                      self.shoot_flags = TFL_SHOOT_CLEARTARGET;
 +                      self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TEAMCHECK;
 +
 +                      self.turret_addtarget = turret_hk_addtarget;
 +
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/base.md3");
 +                      precache_model ("models/turrets/hk.md3");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +float t_hk(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index 41ded85,0000000..26cbc48
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,79 @@@
-                       UziFlash();
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ MACHINEGUN,
 +/* function   */ t_machinegun,
 +/* spawnflags */ TUR_FLAG_PLAYER,
 +/* mins,maxs  */ '-32 -32 0', '32 32 64',
 +/* model        */ "base.md3",
 +/* head_model */ "machinegun.md3",
 +/* netname      */ "machinegun",
 +/* fullname   */ _("Machinegun Turret")
 +);
 +#else
 +#ifdef SVQC
 +void spawnfunc_turret_machinegun() { if(!turret_initialize(TUR_MACHINEGUN)) remove(self); }
 +
 +float t_machinegun(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      fireBullet (self.tur_shotorg, self.tur_shotdir_updated, self.shot_spread, 0, self.shot_dmg, self.shot_force, DEATH_TURRET_MACHINEGUN, 0);
 +
-                       precache_model ("models/turrets/base.md3");
-                       precache_model ("models/turrets/machinegun.md3");
++                      W_MachineGun_MuzzleFlash();
 +                      setattachment(self.muzzle_flash, self.tur_head, "tag_fire");
 +
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.damage_flags |= TFL_DMG_HEADSHAKE;
 +                      self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK;
 +                      self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE;
 +                      self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE;
 +                      self.turret_flags |= TUR_FLAG_HITSCAN;
 +
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/base.md3");
 +                      precache_model ("models/turrets/machinegun.md3");
 +                      precache_sound ("weapons/uzi_fire.wav");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +float t_machinegun(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index 8ed40fe,0000000..fa3c30e
mode 100644,000000..100644
--- /dev/null
@@@ -1,92 -1,0 +1,90 @@@
-                       precache_model ("models/turrets/base.md3");
-                       precache_model ("models/turrets/mlrs.md3");
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ MLRS,
 +/* function   */ t_mlrs,
 +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER,
 +/* mins,maxs  */ '-32 -32 0', '32 32 64',
 +/* model        */ "base.md3",
 +/* head_model */ "mlrs.md3",
 +/* netname      */ "mlrs",
 +/* fullname   */ _("MLRS Turret")
 +);
 +#else
 +#ifdef SVQC
 +void spawnfunc_turret_mlrs() { if(!turret_initialize(TUR_MLRS)) remove(self); }
 +
 +float t_mlrs(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      entity missile;
 +
 +                      turret_tag_fire_update();
 +                      missile = turret_projectile("weapons/rocket_fire.wav", 6, 10, DEATH_TURRET_MLRS, PROJECTILE_ROCKET, TRUE, TRUE);
 +                      missile.nextthink = time + max(self.tur_impacttime,(self.shot_radius * 2) / self.shot_speed);
 +                      missile.missile_flags = MIF_SPLASH;
 +                      te_explosion (missile.origin);
 +
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      // 0 = full, 6 = empty
 +                      self.tur_head.frame = bound(0, 6 - floor(0.1 + self.ammo / self.shot_dmg), 6);
 +                      if(self.tur_head.frame < 0)
 +                      {
 +                              dprint("ammo:",ftos(self.ammo),"\n");
 +                              dprint("shot_dmg:",ftos(self.shot_dmg),"\n");
 +                      }
 +              
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE;
 +                      self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE;
 +              
 +                      self.damage_flags |= TFL_DMG_HEADSHAKE;
 +                      self.shoot_flags  |= TFL_SHOOT_VOLLYALWAYS;
 +                      self.volly_counter = self.shot_volly;
 +
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/base.md3");
 +                      precache_model ("models/turrets/mlrs.md3");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +float t_mlrs(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index 60abd16,0000000..441e041
mode 100644,000000..100644
--- /dev/null
@@@ -1,175 -1,0 +1,173 @@@
-                       precache_model ("models/turrets/base.md3");
-                       precache_model ("models/turrets/phaser.md3");
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ PHASER,
 +/* function   */ t_phaser,
 +/* spawnflags */ TUR_FLAG_SNIPER | TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER,
 +/* mins,maxs  */ '-32 -32 0', '32 32 64',
 +/* model        */ "base.md3",
 +/* head_model */ "phaser.md3",
 +/* netname      */ "phaser",
 +/* fullname   */ _("Phaser Cannon")
 +);
 +#else
 +#ifdef SVQC
 +.float fireflag;
 +
 +float turret_phaser_firecheck()
 +{
 +      if (self.fireflag != 0) return 0;
 +      return turret_firecheck();
 +}
 +
 +void beam_think()
 +{
 +      if ((time > self.cnt) || (self.owner.deadflag != DEAD_NO))
 +      {
 +              self.owner.attack_finished_single = time + self.owner.shot_refire;
 +              self.owner.fireflag = 2;
 +              self.owner.tur_head.frame = 10;
 +              sound (self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, ATTEN_NORM);
 +              remove(self);
 +              return;
 +      }
 +
 +      turret_do_updates(self.owner);
 +
 +      if (time - self.shot_spread > 0)
 +      {
 +              self.shot_spread = time + 2;
 +              sound (self, CH_SHOTS_SINGLE, "turrets/phaser.wav", VOL_BASE, ATTEN_NORM);
 +      }
 +
 +
 +      self.nextthink = time + self.ticrate;
 +
 +      self.owner.attack_finished_single = time + frametime;
 +      entity oldself;
 +      oldself = self;
 +      self = self.owner;
 +      FireImoBeam (   self.tur_shotorg,
 +                                      self.tur_shotorg + self.tur_shotdir_updated * self.target_range,
 +                                      '-1 -1 -1' * self.shot_radius,
 +                                      '1 1 1' * self.shot_radius,
 +                                      self.shot_force,
 +                                      oldself.shot_dmg,
 +                                      0.75,
 +                                      DEATH_TURRET_PHASER);
 +      self = oldself;
 +      self.scale = vlen(self.owner.tur_shotorg - trace_endpos) / 256;
 +
 +}
 +
 +void spawnfunc_turret_phaser() { if(!turret_initialize(TUR_PHASER)) remove(self); }
 +
 +float t_phaser(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      entity beam;
 +
 +                      beam = spawn();
 +                      beam.ticrate = 0.1; //autocvar_sys_ticrate;
 +                      setmodel(beam,"models/turrets/phaser_beam.md3");
 +                      beam.effects = EF_LOWPRECISION;
 +                      beam.solid = SOLID_NOT;
 +                      beam.think = beam_think;
 +                      beam.cnt = time + self.shot_speed;
 +                      beam.shot_spread = time + 2;
 +                      beam.nextthink = time;
 +                      beam.owner = self;
 +                      beam.shot_dmg = self.shot_dmg / (self.shot_speed / beam.ticrate);
 +                      beam.scale = self.target_range / 256;
 +                      beam.movetype = MOVETYPE_NONE;
 +                      beam.enemy = self.enemy;
 +                      beam.bot_dodge = TRUE;
 +                      beam.bot_dodgerating = beam.shot_dmg;
 +                      sound (beam, CH_SHOTS_SINGLE, "turrets/phaser.wav", VOL_BASE, ATTEN_NORM);
 +                      self.fireflag = 1;
 +
 +                      beam.attack_finished_single = self.attack_finished_single;
 +                      self.attack_finished_single = time; // + autocvar_sys_ticrate;
 +
 +                      setattachment(beam,self.tur_head,"tag_fire");
 +
 +                      soundat (self, trace_endpos, CH_SHOTS, "weapons/neximpact.wav", VOL_BASE, ATTEN_NORM);
 +
 +                      if (self.tur_head.frame == 0)
 +                              self.tur_head.frame = 1;
 +
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      if (self.tur_head.frame != 0)
 +                      {
 +                              if (self.fireflag == 1)
 +                              {
 +                                      if (self.tur_head.frame == 10)
 +                                              self.tur_head.frame = 1;
 +                                      else
 +                                              self.tur_head.frame = self.tur_head.frame +1;
 +                              }
 +                              else if (self.fireflag == 2 )
 +                              {
 +                                      self.tur_head.frame = self.tur_head.frame +1;
 +                                      if (self.tur_head.frame == 15)
 +                                      {
 +                                              self.tur_head.frame = 0;
 +                                              self.fireflag = 0;
 +                                      }
 +                              }
 +                      }
 +
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE;
 +                      self.aim_flags = TFL_AIM_LEAD;
 +
 +                      self.turret_firecheckfunc = turret_phaser_firecheck;
 +
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/base.md3");
 +                      precache_model ("models/turrets/phaser.md3");
 +                      precache_model ("models/turrets/phaser_beam.md3");
 +                      precache_sound ("turrets/phaser.wav");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +float t_phaser(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index 6ffd635,0000000..ac62337
mode 100644,000000..100644
--- /dev/null
@@@ -1,113 -1,0 +1,111 @@@
-                       precache_model ("models/turrets/base.md3");
-                       precache_model ("models/turrets/plasma.md3");
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ PLASMA,
 +/* function   */ t_plasma,
 +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER,
 +/* mins,maxs  */ '-32 -32 0', '32 32 64',
 +/* model        */ "base.md3",
 +/* head_model */ "plasma.md3",
 +/* netname      */ "plasma",
 +/* fullname   */ _("Plasma Cannon")
 +);
 +#else
 +#ifdef SVQC
 +void spawnfunc_turret_plasma() { if(!turret_initialize(TUR_PLASMA)) remove(self); }
 +
 +float t_plasma(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      if(g_instagib)
 +                      {
 +                              float flying;
 +                              flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last
 +
 +                              FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000,
 +                                                                 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA);
 +
 +                              pointparticles(particleeffectnum("nex_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1);
 +
 +                              // teamcolor / hit beam effect
 +                              vector v;
 +                              string s;
 +                              v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
 +                              s = strcat("TE_TEI_G3", ((self.team) ? Static_Team_ColorName_Upper(self.team) : ""));
 +                              
 +                              WarpZone_TrailParticles(world, particleeffectnum(s), self.tur_shotorg, v);
 +                              
 +                              if (self.tur_head.frame == 0)
 +                                      self.tur_head.frame = 1;
 +                      }
 +                      else
 +                      {
 +                              entity missile = turret_projectile("weapons/hagar_fire.wav", 1, 0, DEATH_TURRET_PLASMA, PROJECTILE_ELECTRO_BEAM, TRUE, TRUE);
 +                              missile.missile_flags = MIF_SPLASH;
 +
 +                              pointparticles(particleeffectnum("laser_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1);
 +                              if (self.tur_head.frame == 0)
 +                                      self.tur_head.frame = 1;
 +                      }
 +
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      if (self.tur_head.frame != 0)
 +                              self.tur_head.frame = self.tur_head.frame + 1;
 +
 +                      if (self.tur_head.frame > 5)
 +                              self.tur_head.frame = 0;
 +
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE;
 +                      self.damage_flags |= TFL_DMG_HEADSHAKE;
 +                      self.firecheck_flags |= TFL_FIRECHECK_AFF;
 +                      self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_SPLASH;
 +                      
 +                      turret_do_updates(self);
 +
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/base.md3");
 +                      precache_model ("models/turrets/plasma.md3");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +float t_plasma(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index e2432dd,0000000..279b41e
mode 100644,000000..100644
--- /dev/null
@@@ -1,111 -1,0 +1,109 @@@
-                       precache_model ("models/turrets/base.md3");
-                       precache_model ("models/turrets/plasmad.md3");
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ PLASMA_DUAL,
 +/* function   */ t_plasma_dual,
 +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER,
 +/* mins,maxs  */ '-32 -32 0', '32 32 64',
 +/* model        */ "base.md3",
 +/* head_model */ "plasmad.md3",
 +/* netname      */ "plasma_dual",
 +/* fullname   */ _("Dual Plasma Cannon")
 +);
 +#else
 +#ifdef SVQC
 +void spawnfunc_turret_plasma_dual() { if(!turret_initialize(TUR_PLASMA_DUAL)) remove(self); }
 +
 +float t_plasma_dual(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      if(g_instagib)
 +                      {
 +                              float flying;
 +                              flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last
 +
 +                              FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000,
 +                                                                 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA);
 +
 +
 +                              pointparticles(particleeffectnum("nex_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1);
 +
 +                              // teamcolor / hit beam effect
 +                              vector v;
 +                              string s;
 +                              v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
 +                              s = strcat("TE_TEI_G3", ((self.team) ? Static_Team_ColorName_Upper(self.team) : ""));
 +                              
 +                              WarpZone_TrailParticles(world, particleeffectnum(s), self.tur_shotorg, v);
 +                                      
 +                              self.tur_head.frame += 1;
 +                      }
 +                      else
 +                      {
 +                              entity missile = turret_projectile("weapons/hagar_fire.wav", 1, 0, DEATH_TURRET_PLASMA, PROJECTILE_ELECTRO_BEAM, TRUE, TRUE);
 +                              missile.missile_flags = MIF_SPLASH;
 +                              pointparticles(particleeffectnum("laser_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1);
 +                              self.tur_head.frame += 1;
 +                      }
 +
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      if ((self.tur_head.frame != 0) && (self.tur_head.frame != 3))
 +                              self.tur_head.frame = self.tur_head.frame + 1;
 +
 +                      if (self.tur_head.frame > 6)
 +                              self.tur_head.frame = 0;
 +
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE;
 +                      self.damage_flags |= TFL_DMG_HEADSHAKE;
 +                      self.firecheck_flags |= TFL_FIRECHECK_AFF;
 +                      self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_SPLASH;
 +                      
 +                      turret_do_updates(self);
 +
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/base.md3");
 +                      precache_model ("models/turrets/plasmad.md3");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +float t_plasma_dual(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index 02f29d6,0000000..2878c31
mode 100644,000000..100644
--- /dev/null
@@@ -1,219 -1,0 +1,217 @@@
-                       precache_model ("models/turrets/tesla_base.md3");
-                       precache_model ("models/turrets/tesla_head.md3");
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ TESLA,
 +/* function   */ t_tesla,
 +/* spawnflags */ TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE,
 +/* mins,maxs  */ '-60 -60 0', '60 60 128',
 +/* model        */ "tesla_base.md3",
 +/* head_model */ "tesla_head.md3",
 +/* netname      */ "tesla",
 +/* fullname   */ _("Tesla Coil")
 +);
 +#else
 +#ifdef SVQC
 +entity toast(entity from, float range, float damage)
 +{
 +      entity e;
 +      entity etarget = world;
 +      float d,dd;
 +      float r;
 +
 +      dd = range + 1;
 +
 +      e = findradius(from.origin,range);
 +      while (e)
 +      {
 +              if ((e.railgunhit != 1) && (e != from))
 +              {
 +                      r = turret_validate_target(self,e,self.target_validate_flags);
 +                      if (r > 0)
 +                      {
 +                              traceline(from.origin,0.5 * (e.absmin + e.absmax),MOVE_WORLDONLY,from);
 +                              if (trace_fraction == 1.0)
 +                              {
 +                                      d = vlen(e.origin - from.origin);
 +                                      if (d < dd)
 +                                      {
 +                                              dd = d;
 +                                              etarget = e;
 +                                      }
 +                              }
 +                      }
 +              }
 +              e = e.chain;
 +      }
 +
 +      if (etarget)
 +      {
 +              te_csqc_lightningarc(from.origin,etarget.origin);
 +              Damage(etarget, self, self, damage, DEATH_TURRET_TESLA, etarget.origin, '0 0 0');
 +              etarget.railgunhit = 1;
 +      }
 +
 +      return etarget;
 +}
 +
 +float turret_tesla_firecheck()
 +{
 +      // g_turrets_targetscan_maxdelay forces a target re-scan at least this often
 +      float do_target_scan = 0;
 +
 +      if((self.target_select_time + autocvar_g_turrets_targetscan_maxdelay) < time)
 +              do_target_scan = 1;
 +
 +      // Old target (if any) invalid?
 +      if(self.target_validate_time < time)
 +      if (turret_validate_target(self, self.enemy, self.target_validate_flags) <= 0)
 +      {
 +              self.enemy = world;
 +              self.target_validate_time = time + 0.5;
 +              do_target_scan = 1;
 +      }
 +
 +      // But never more often then g_turrets_targetscan_mindelay!
 +      if (self.target_select_time + autocvar_g_turrets_targetscan_mindelay > time)
 +              do_target_scan = 0;
 +
 +      if(do_target_scan)
 +      {
 +              self.enemy = turret_select_target();
 +              self.target_select_time = time;
 +      }
 +
 +      if(!turret_firecheck())
 +              return 0;
 +
 +      if(self.enemy)
 +              return 1;
 +
 +      return 0;
 +}
 +
 +void spawnfunc_turret_tesla() { if(!turret_initialize(TUR_TESLA)) remove(self); }
 +
 +float t_tesla(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      entity e, t;
 +                      float d, r, i;
 +
 +                      d = self.shot_dmg;
 +                      r = self.target_range;
 +                      e = spawn();
 +                      setorigin(e,self.tur_shotorg);
 +
 +                      self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK;
 +
 +                      t = toast(e,r,d);
 +                      remove(e);
 +
 +                      if (t == world) return TRUE;
 +
 +                      self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_TEAMCHECK;
 +
 +                      self.attack_finished_single = time + self.shot_refire;
 +                      for (i = 0; i < 10; ++i)
 +                      {
 +                              d *= 0.75;
 +                              r *= 0.85;
 +                              t = toast(t, r, d);
 +                              if (t == world) break;
 +
 +                      }
 +
 +                      e = findchainfloat(railgunhit, 1);
 +                      while (e)
 +                      {
 +                              e.railgunhit = 0;
 +                              e = e.chain;
 +                      }
 +
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      if(!self.active)
 +                      {
 +                              self.tur_head.avelocity = '0 0 0';
 +                              return TRUE;
 +                      }
 +
 +                      if(self.ammo < self.shot_dmg)
 +                      {
 +                              self.tur_head.avelocity = '0 45 0' * (self.ammo / self.shot_dmg);
 +                      }
 +                      else
 +                      {
 +                              self.tur_head.avelocity = '0 180 0' * (self.ammo / self.shot_dmg);
 +
 +                              if(self.attack_finished_single > time)
 +                                      return TRUE;
 +
 +                              float f;
 +                              f = (self.ammo / self.ammo_max);
 +                              f = f * f;
 +                              if(f > random())
 +                                      if(random() < 0.1)
 +                                              te_csqc_lightningarc(self.tur_shotorg,self.tur_shotorg + (randomvec() * 350));
 +                      }
 +
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES |
 +                                                               TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK;
 +                                                               
 +                      self.turret_firecheckfunc = turret_tesla_firecheck;
 +                      self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES |
 +                                                         TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK;
 +
 +                      self.firecheck_flags    = TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AMMO_OWN;
 +                      self.shoot_flags                = TFL_SHOOT_CUSTOM;
 +                      self.ammo_flags                 = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE;
 +                      self.aim_flags                  = TFL_AIM_NO;
 +                      self.track_flags                = TFL_TRACK_NO;
 +
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/tesla_base.md3");
 +                      precache_model ("models/turrets/tesla_head.md3");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +float t_tesla(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
index 2c2bc90,0000000..fa89d5a
mode 100644,000000..100644
--- /dev/null
@@@ -1,698 -1,0 +1,696 @@@
-       RadiusDamage (self, self.owner, (autocvar_g_turrets_unit_walker_rocket_damage), 0, (autocvar_g_turrets_unit_walker_rocket_radius), self, (autocvar_g_turrets_unit_walker_rocket_force), DEATH_TURRET_WALK_ROCKET, world);
 +#ifdef REGISTER_TURRET
 +REGISTER_TURRET(
 +/* TUR_##id   */ WALKER,
 +/* function   */ t_walker,
 +/* spawnflags */ TUR_FLAG_PLAYER | TUR_FLAG_MOVE,
 +/* mins,maxs  */ '-70 -70 0', '70 70 95',
 +/* model        */ "walker_body.md3",
 +/* head_model */ "walker_head_minigun.md3",
 +/* netname      */ "walker",
 +/* fullname   */ _("Walker Turret")
 +);
 +#else
 +#ifdef SVQC
 +float autocvar_g_turrets_unit_walker_melee_damage;
 +float autocvar_g_turrets_unit_walker_melee_force;
 +float autocvar_g_turrets_unit_walker_melee_range;
 +float autocvar_g_turrets_unit_walker_rocket_damage;
 +float autocvar_g_turrets_unit_walker_rocket_radius;
 +float autocvar_g_turrets_unit_walker_rocket_force;
 +float autocvar_g_turrets_unit_walker_rocket_speed;
 +float autocvar_g_turrets_unit_walker_rocket_range;
 +float autocvar_g_turrets_unit_walker_rocket_range_min;
 +float autocvar_g_turrets_unit_walker_rocket_refire;
 +float autocvar_g_turrets_unit_walker_rocket_turnrate;
 +float autocvar_g_turrets_unit_walker_speed_stop;
 +float autocvar_g_turrets_unit_walker_speed_walk;
 +float autocvar_g_turrets_unit_walker_speed_run;
 +float autocvar_g_turrets_unit_walker_speed_jump;
 +float autocvar_g_turrets_unit_walker_speed_swim;
 +float autocvar_g_turrets_unit_walker_speed_roam;
 +float autocvar_g_turrets_unit_walker_turn;
 +float autocvar_g_turrets_unit_walker_turn_walk;
 +float autocvar_g_turrets_unit_walker_turn_strafe;
 +float autocvar_g_turrets_unit_walker_turn_swim;
 +float autocvar_g_turrets_unit_walker_turn_run;
 +
 +#define ANIM_NO         0
 +#define ANIM_TURN       1
 +#define ANIM_WALK       2
 +#define ANIM_RUN        3
 +#define ANIM_STRAFE_L   4
 +#define ANIM_STRAFE_R   5
 +#define ANIM_JUMP       6
 +#define ANIM_LAND       7
 +#define ANIM_PAIN       8
 +#define ANIM_MELEE      9
 +#define ANIM_SWIM       10
 +#define ANIM_ROAM       11
 +
 +.float animflag;
 +.float idletime;
 +
 +#define WALKER_PATH(s,e) pathlib_astar(s,e)
 +
 +float walker_firecheck()
 +{
 +      if (self.animflag == ANIM_MELEE)
 +              return 0;
 +
 +      return turret_firecheck();
 +}
 +
 +void walker_melee_do_dmg()
 +{
 +      vector where;
 +      entity e;
 +
 +      makevectors(self.angles);
 +      where = self.origin + v_forward * 128;
 +
 +      e = findradius(where,32);
 +      while (e)
 +      {
 +              if (turret_validate_target(self, e, self.target_validate_flags))
 +                      if (e != self && e.owner != self)
 +                              Damage(e, self, self, (autocvar_g_turrets_unit_walker_melee_damage), DEATH_TURRET_WALK_MELEE, '0 0 0', v_forward * (autocvar_g_turrets_unit_walker_melee_force));
 +
 +              e = e.chain;
 +      }
 +}
 +
 +void walker_setnoanim()
 +{
 +      turrets_setframe(ANIM_NO, FALSE);
 +      self.animflag = self.frame;
 +}
 +void walker_rocket_explode()
 +{
-                       precache_model ("models/turrets/walker_body.md3");
-                       precache_model ("models/turrets/walker_head_minigun.md3");
++      RadiusDamage (self, self.owner, (autocvar_g_turrets_unit_walker_rocket_damage), 0, (autocvar_g_turrets_unit_walker_rocket_radius), self, world, (autocvar_g_turrets_unit_walker_rocket_force), DEATH_TURRET_WALK_ROCKET, world);
 +      remove (self);
 +}
 +
 +void walker_rocket_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
 +{
 +      self.health = self.health - damage;
 +      self.velocity = self.velocity + vforce;
 +
 +      if (self.health <= 0)
 +              W_PrepareExplosionByDamage(self.owner, walker_rocket_explode);
 +}
 +
 +#define WALKER_ROCKET_MOVE movelib_move_simple(newdir, (autocvar_g_turrets_unit_walker_rocket_speed), (autocvar_g_turrets_unit_walker_rocket_turnrate)); UpdateCSQCProjectile(self)
 +void walker_rocket_loop();
 +void walker_rocket_think()
 +{
 +      vector newdir;
 +      float edist;
 +      float itime;
 +      float m_speed;
 +
 +      self.nextthink = time;
 +
 +      edist = vlen(self.enemy.origin - self.origin);
 +
 +      // Simulate crude guidance
 +      if (self.cnt < time)
 +      {
 +              if (edist < 1000)
 +                      self.tur_shotorg = randomvec() * min(edist, 64);
 +              else
 +                      self.tur_shotorg = randomvec() * min(edist, 256);
 +
 +              self.cnt = time + 0.5;
 +      }
 +
 +      if (edist < 128)
 +              self.tur_shotorg = '0 0 0';
 +
 +      if (self.max_health < time)
 +      {
 +              self.think        = walker_rocket_explode;
 +              self.nextthink  = time;
 +              return;
 +      }
 +
 +      if (self.shot_dmg != 1337 && random() < 0.01)
 +      {
 +              walker_rocket_loop();
 +              return;
 +      }
 +
 +      m_speed = vlen(self.velocity);
 +
 +      // Enemy dead? just keep on the current heading then.
 +      if (self.enemy == world || self.enemy.deadflag != DEAD_NO)
 +              self.enemy = world;
 +
 +      if (self.enemy)
 +      {
 +              itime = max(edist / m_speed, 1);
 +              newdir = steerlib_pull(self.enemy.origin + self.tur_shotorg);
 +      }
 +      else
 +              newdir  = normalize(self.velocity);
 +
 +      WALKER_ROCKET_MOVE;
 +}
 +
 +void walker_rocket_loop3()
 +{
 +      vector newdir;
 +      self.nextthink = time;
 +
 +      if (self.max_health < time)
 +      {
 +              self.think = walker_rocket_explode;
 +              return;
 +      }
 +
 +      if (vlen(self.origin - self.tur_shotorg) < 100 )
 +      {
 +              self.think = walker_rocket_think;
 +              return;
 +      }
 +
 +      newdir = steerlib_pull(self.tur_shotorg);
 +      WALKER_ROCKET_MOVE;
 +
 +      self.angles = vectoangles(self.velocity);
 +}
 +
 +void walker_rocket_loop2()
 +{
 +      vector newdir;
 +
 +      self.nextthink = time;
 +
 +      if (self.max_health < time)
 +      {
 +              self.think = walker_rocket_explode;
 +              return;
 +      }
 +
 +      if (vlen(self.origin - self.tur_shotorg) < 100 )
 +      {
 +              self.tur_shotorg = self.origin - '0 0 200';
 +              self.think = walker_rocket_loop3;
 +              return;
 +      }
 +
 +      newdir = steerlib_pull(self.tur_shotorg);
 +      WALKER_ROCKET_MOVE;
 +}
 +
 +void walker_rocket_loop()
 +{
 +      self.nextthink = time;
 +      self.tur_shotorg = self.origin + '0 0 300';
 +      self.think = walker_rocket_loop2;
 +      self.shot_dmg = 1337;
 +}
 +
 +void walker_fire_rocket(vector org)
 +{
 +      entity rocket;
 +
 +      fixedmakevectors(self.angles);
 +
 +      te_explosion (org);
 +
 +      rocket = spawn ();
 +      setorigin(rocket, org);
 +
 +      sound (self, CH_WEAPON_A, "weapons/hagar_fire.wav", VOL_BASE, ATTEN_NORM);
 +      setsize (rocket, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
 +
 +      rocket.classname                  = "walker_rocket";
 +      rocket.owner                      = self;
 +      rocket.bot_dodge                  = TRUE;
 +      rocket.bot_dodgerating  = 50;
 +      rocket.takedamage                = DAMAGE_YES;
 +      rocket.damageforcescale   = 2;
 +      rocket.health                    = 25;
 +      rocket.tur_shotorg              = randomvec() * 512;
 +      rocket.cnt                              = time + 1;
 +      rocket.enemy                      = self.enemy;
 +
 +      if (random() < 0.01)
 +              rocket.think              = walker_rocket_loop;
 +      else
 +              rocket.think              = walker_rocket_think;
 +
 +      rocket.event_damage        = walker_rocket_damage;
 +
 +      rocket.nextthink                  = time;
 +      rocket.movetype            = MOVETYPE_FLY;
 +      rocket.velocity            = normalize((v_forward + v_up * 0.5) + (randomvec() * 0.2)) * (autocvar_g_turrets_unit_walker_rocket_speed);
 +      rocket.angles                    = vectoangles(rocket.velocity);
 +      rocket.touch                      = walker_rocket_explode;
 +      rocket.flags                      = FL_PROJECTILE;
 +      rocket.solid                      = SOLID_BBOX;
 +      rocket.max_health                = time + 9;
 +      rocket.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT;
 +
 +      CSQCProjectile(rocket, FALSE, PROJECTILE_ROCKET, FALSE); // no culling, has fly sound
 +}
 +
 +.vector enemy_last_loc;
 +.float enemy_last_time;
 +void walker_move_to(vector _target, float _dist)
 +{
 +      switch (self.waterlevel)
 +      {
 +              case WATERLEVEL_NONE:
 +                      if (_dist > 500)
 +                              self.animflag = ANIM_RUN;
 +                      else
 +                              self.animflag = ANIM_WALK;
 +              case WATERLEVEL_WETFEET:
 +              case WATERLEVEL_SWIMMING:
 +                      if (self.animflag != ANIM_SWIM)
 +                              self.animflag = ANIM_WALK;
 +                      else
 +                              self.animflag = ANIM_SWIM;
 +                      break;
 +              case WATERLEVEL_SUBMERGED:
 +                      self.animflag = ANIM_SWIM;
 +      }
 +
 +      self.moveto = _target;
 +      self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95);
 +
 +      if(self.enemy)
 +      {
 +              self.enemy_last_loc = _target;
 +              self.enemy_last_time = time;
 +      }
 +}
 +
 +//#define WALKER_FANCYPATHING
 +
 +void walker_move_path()
 +{
 +#ifdef WALKER_FANCYPATHING
 +      // Are we close enougth to a path node to switch to the next?
 +      if (vlen(self.origin  - self.pathcurrent.origin) < 64)
 +              if (self.pathcurrent.path_next == world)
 +              {
 +                      // Path endpoint reached
 +                      pathlib_deletepath(self.pathcurrent.owner);
 +                      self.pathcurrent = world;
 +
 +                      if (self.pathgoal)
 +                      {
 +                              if (self.pathgoal.use)
 +                                      self.pathgoal.use();
 +
 +                              if (self.pathgoal.enemy)
 +                              {
 +                                      self.pathcurrent = WALKER_PATH(self.pathgoal.origin,self.pathgoal.enemy.origin);
 +                                      self.pathgoal = self.pathgoal.enemy;
 +                              }
 +                      }
 +                      else
 +                              self.pathgoal = world;
 +              }
 +              else
 +                      self.pathcurrent = self.pathcurrent.path_next;
 +
 +      self.moveto = self.pathcurrent.origin;
 +      self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
 +      walker_move_to(self.moveto, 0);
 +
 +#else
 +      if (vlen(self.origin - self.pathcurrent.origin) < 64)
 +              self.pathcurrent = self.pathcurrent.enemy;
 +
 +      if(!self.pathcurrent)
 +              return;
 +
 +      self.moveto = self.pathcurrent.origin;
 +      self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95);
 +      walker_move_to(self.moveto, 0);
 +#endif
 +}
 +
 +void spawnfunc_turret_walker() { if(!turret_initialize(TUR_WALKER)) remove(self); }
 +
 +float t_walker(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_ATTACK:
 +              {
 +                      sound (self, CH_WEAPON_A, "weapons/uzi_fire.wav", VOL_BASE, ATTEN_NORM);
 +                      fireBullet (self.tur_shotorg, self.tur_shotdir_updated, self.shot_spread, 0, self.shot_dmg, self.shot_force, DEATH_TURRET_WALK_GUN, 0);
 +                      pointparticles(particleeffectnum("laser_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1);
 +
 +                      return TRUE;
 +              }
 +              case TR_THINK:
 +              {
 +                      fixedmakevectors(self.angles);
 +
 +                      if (self.spawnflags & TSF_NO_PATHBREAK && self.pathcurrent)
 +                              walker_move_path();
 +                      else if (self.enemy == world)
 +                      {
 +                              if(self.pathcurrent)
 +                                      walker_move_path();
 +                              else
 +                              {
 +                                      if(self.enemy_last_time != 0)
 +                                      {
 +                                              if(vlen(self.origin - self.enemy_last_loc) < 128 || time - self.enemy_last_time > 10)
 +                                                      self.enemy_last_time = 0;
 +                                              else
 +                                                      walker_move_to(self.enemy_last_loc, 0);
 +                                      }
 +                                      else
 +                                      {
 +                                              if(self.animflag != ANIM_NO)
 +                                              {
 +                                                      traceline(self.origin + '0 0 64', self.origin + '0 0 64' + v_forward * 128, MOVE_NORMAL, self);
 +
 +                                                      if(trace_fraction != 1.0)
 +                                                              self.tur_head.idletime = -1337;
 +                                                      else
 +                                                      {
 +                                                              traceline(trace_endpos, trace_endpos - '0 0 256', MOVE_NORMAL, self);
 +                                                              if(trace_fraction == 1.0)
 +                                                                      self.tur_head.idletime = -1337;
 +                                                      }
 +
 +                                                      if(self.tur_head.idletime == -1337)
 +                                                      {
 +                                                              self.moveto = self.origin + randomvec() * 256;
 +                                                              self.tur_head.idletime = 0;
 +                                                      }
 +
 +                                                      self.moveto = self.moveto * 0.9 + ((self.origin + v_forward * 500) + randomvec() * 400) * 0.1;
 +                                                      self.moveto_z = self.origin_z + 64;
 +                                                      walker_move_to(self.moveto, 0);
 +                                              }
 +
 +                                              if(self.idletime < time)
 +                                              {
 +                                                      if(random() < 0.5 || !(self.spawnflags & TSL_ROAM))
 +                                                      {
 +                                                              self.idletime = time + 1 + random() * 5;
 +                                                              self.moveto = self.origin;
 +                                                              self.animflag = ANIM_NO;
 +                                                      }
 +                                                      else
 +                                                      {
 +                                                              self.animflag = ANIM_WALK;
 +                                                              self.idletime = time + 4 + random() * 2;
 +                                                              self.moveto = self.origin + randomvec() * 256;
 +                                                              self.tur_head.moveto = self.moveto;
 +                                                              self.tur_head.idletime = 0;
 +                                                      }
 +                                              }
 +                                      }
 +                              }
 +                      }
 +                      else
 +                      {
 +                              if (self.tur_dist_enemy < (autocvar_g_turrets_unit_walker_melee_range) && self.animflag != ANIM_MELEE)
 +                              {
 +                                      vector wish_angle;
 +
 +                                      wish_angle = angleofs(self, self.enemy);
 +                                      if (self.animflag != ANIM_SWIM)
 +                                      if (fabs(wish_angle_y) < 15)
 +                                      {
 +                                              self.moveto   = self.enemy.origin;
 +                                              self.steerto  = steerlib_attract2(self.moveto, 0.5, 500, 0.95);
 +                                              self.animflag = ANIM_MELEE;
 +                                      }
 +                              }
 +                              else if (self.tur_head.attack_finished_single < time)
 +                              {
 +                                      if(self.tur_head.shot_volly)
 +                                      {
 +                                              self.animflag = ANIM_NO;
 +
 +                                              self.tur_head.shot_volly = self.tur_head.shot_volly -1;
 +                                              if(self.tur_head.shot_volly == 0)
 +                                                      self.tur_head.attack_finished_single = time + (autocvar_g_turrets_unit_walker_rocket_refire);
 +                                              else
 +                                                      self.tur_head.attack_finished_single = time + 0.2;
 +
 +                                              if(self.tur_head.shot_volly > 1)
 +                                                      walker_fire_rocket(gettaginfo(self, gettagindex(self, "tag_rocket01")));
 +                                              else
 +                                                      walker_fire_rocket(gettaginfo(self, gettagindex(self, "tag_rocket02")));
 +                                      }
 +                                      else
 +                                      {
 +                                              if (self.tur_dist_enemy > (autocvar_g_turrets_unit_walker_rocket_range_min))
 +                                              if (self.tur_dist_enemy < (autocvar_g_turrets_unit_walker_rocket_range))
 +                                                      self.tur_head.shot_volly = 4;
 +                                      }
 +                              }
 +                              else
 +                              {
 +                                      if (self.animflag != ANIM_MELEE)
 +                                              walker_move_to(self.enemy.origin, self.tur_dist_enemy);
 +                              }
 +                      }
 +                      
 +                      {
 +                              vector real_angle;
 +                              float turny = 0, turnx = 0;
 +                              float vz;
 +
 +                              real_angle = vectoangles(self.steerto) - self.angles;
 +                              vz = self.velocity_z;
 +
 +                              switch (self.animflag)
 +                              {
 +                                      case ANIM_NO:
 +                                              movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop));
 +                                              break;
 +
 +                                      case ANIM_TURN:
 +                                              turny = (autocvar_g_turrets_unit_walker_turn);
 +                                              movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop));
 +                                              break;
 +
 +                                      case ANIM_WALK:
 +                                              turny = (autocvar_g_turrets_unit_walker_turn_walk);
 +                                              movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_walk), 0.6);
 +                                              break;
 +
 +                                      case ANIM_RUN:
 +                                              turny = (autocvar_g_turrets_unit_walker_turn_run);
 +                                              movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_run), 0.6);
 +                                              break;
 +
 +                                      case ANIM_STRAFE_L:
 +                                              turny = (autocvar_g_turrets_unit_walker_turn_strafe);
 +                                              movelib_move_simple(v_right * -1, (autocvar_g_turrets_unit_walker_speed_walk), 0.8);
 +                                              break;
 +
 +                                      case ANIM_STRAFE_R:
 +                                              turny = (autocvar_g_turrets_unit_walker_turn_strafe);
 +                                              movelib_move_simple(v_right, (autocvar_g_turrets_unit_walker_speed_walk), 0.8);
 +                                              break;
 +
 +                                      case ANIM_JUMP:
 +                                              self.velocity += '0 0 1' * (autocvar_g_turrets_unit_walker_speed_jump);
 +                                              break;
 +
 +                                      case ANIM_LAND:
 +                                              break;
 +
 +                                      case ANIM_PAIN:
 +                                              if(self.frame != ANIM_PAIN)
 +                                                      defer(0.25, walker_setnoanim);
 +
 +                                              break;
 +
 +                                      case ANIM_MELEE:
 +                                              if(self.frame != ANIM_MELEE)
 +                                              {
 +                                                      defer(0.41, walker_setnoanim);
 +                                                      defer(0.21, walker_melee_do_dmg);
 +                                              }
 +
 +                                              movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop));
 +                                              break;
 +
 +                                      case ANIM_SWIM:
 +                                              turny = (autocvar_g_turrets_unit_walker_turn_swim);
 +                                              turnx = (autocvar_g_turrets_unit_walker_turn_swim);
 +
 +                                              self.angles_x += bound(-10, shortangle_f(real_angle_x, self.angles_x), 10);
 +                                              movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_swim), 0.3);
 +                                              vz = self.velocity_z + sin(time * 4) * 8;
 +                                              break;
 +
 +                                      case ANIM_ROAM:
 +                                              turny = (autocvar_g_turrets_unit_walker_turn_walk);
 +                                              movelib_move_simple(v_forward ,(autocvar_g_turrets_unit_walker_speed_roam), 0.5);
 +                                              break;
 +                              }
 +
 +                              if(turny)
 +                              {
 +                                      turny = bound( turny * -1, shortangle_f(real_angle_y, self.angles_y), turny );
 +                                      self.angles_y += turny;
 +                              }
 +
 +                              if(turnx)
 +                              {
 +                                      turnx = bound( turnx * -1, shortangle_f(real_angle_x, self.angles_x), turnx );
 +                                      self.angles_x += turnx;
 +                              }
 +
 +                              self.velocity_z = vz;
 +                      }
 +
 +
 +                      if(self.origin != self.oldorigin)
 +                              self.SendFlags |= TNSF_MOVE;
 +
 +                      self.oldorigin = self.origin;
 +                      turrets_setframe(self.animflag, FALSE);
 +
 +                      return TRUE;
 +              }
 +              case TR_DEATH:
 +              {
 +#ifdef WALKER_FANCYPATHING
 +                      if (self.pathcurrent)
 +                              pathlib_deletepath(self.pathcurrent.owner);
 +#endif
 +                      self.pathcurrent = world;
 +              
 +                      return TRUE;
 +              }
 +              case TR_SETUP:
 +              {
 +                      self.ticrate = 0.05;
 +                      
 +                      entity e;
 +
 +                      // Respawn is called & first spawn to, to set team. need to make sure we do not move the initial spawn.
 +                      if(self.movetype == MOVETYPE_WALK)
 +                      {
 +                              if(self.pos1)
 +                                      setorigin(self, self.pos1);
 +                              if(self.pos2)
 +                                      self.angles = self.pos2;
 +                      }
 +                      
 +                      self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE;
 +                      self.aim_flags = TFL_AIM_LEAD;
 +                      self.turret_flags |= TUR_FLAG_HITSCAN;
 +                              
 +                      self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
 +                      self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
 +                      self.iscreature = TRUE;
 +                      self.teleportable = TELEPORT_NORMAL;
 +                      self.damagedbycontents = TRUE;
 +                      self.solid = SOLID_SLIDEBOX;
 +                      self.takedamage = DAMAGE_AIM;
 +                      if(self.movetype != MOVETYPE_WALK)
 +                      {
 +                              setorigin(self, self.origin);
 +                              tracebox(self.origin + '0 0 128', self.mins, self.maxs, self.origin - '0 0 10000', MOVE_NORMAL, self);
 +                              setorigin(self, trace_endpos + '0 0 4');
 +                              self.pos1 = self.origin;
 +                              self.pos2 = self.angles;
 +                      }
 +                      self.movetype = MOVETYPE_WALK;
 +                      self.idle_aim = '0 0 0';
 +                      self.turret_firecheckfunc = walker_firecheck;
 +                      
 +                      if (self.target != "")
 +                      {
 +                              e = find(world, targetname, self.target);
 +                              if (!e)
 +                              {
 +                                      dprint("Initital waypoint for walker does NOT exsist, fix your map!\n");
 +                                      self.target = "";
 +                              }
 +
 +                              if (e.classname != "turret_checkpoint")
 +                                      dprint("Warning: not a turrret path\n");
 +                              else
 +                              {
 +#ifdef WALKER_FANCYPATHING
 +                                      self.pathcurrent = WALKER_PATH(self.origin, e.origin);
 +                                      self.pathgoal = e;
 +#else
 +                                      self.pathcurrent = e;
 +#endif
 +                              }
 +                      }
 +
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      precache_model ("models/turrets/walker_body.md3");
 +                      precache_model ("models/turrets/walker_head_minigun.md3");
 +                      precache_model ("models/turrets/rocket.md3");
 +                      precache_sound ("weapons/rocket_impact.wav");
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // SVQC
 +#ifdef CSQC
 +
 +void walker_draw()
 +{
 +      float dt;
 +
 +      dt = time - self.move_time;
 +      self.move_time = time;
 +      if(dt <= 0)
 +              return;
 +
 +      fixedmakevectors(self.angles);
 +      movelib_groundalign4point(300, 100, 0.25, 45);
 +      setorigin(self, self.origin + self.velocity * dt);
 +      self.tur_head.angles += dt * self.tur_head.move_avelocity;
 +      self.angles_y = self.move_angles_y;
 +
 +      if (self.health < 127)
 +      if(random() < 0.15)
 +              te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
 +}
 +
 +float t_walker(float req)
 +{
 +      switch(req)
 +      {
 +              case TR_SETUP:
 +              {
 +                      self.gravity            = 1;
 +                      self.movetype           = MOVETYPE_BOUNCE;
 +                      self.move_movetype      = MOVETYPE_BOUNCE;
 +                      self.move_origin        = self.origin;
 +                      self.move_time          = time;
 +                      self.draw                       = walker_draw;
 +                      
 +                      return TRUE;
 +              }
 +              case TR_PRECACHE:
 +              {
 +                      return TRUE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
 +
 +#endif // CSQC
 +#endif // REGISTER_TURRET
Simple merge
@@@ -863,9 -864,9 +864,9 @@@ void Damage (entity targ, entity inflic
                        else
                                victim = targ;
  
 -                      if(IS_PLAYER(victim) || (victim.turrcaps_flags & TFL_TURRCAPS_ISTURRET) || (victim.flags & FL_MONSTER))
 +                      if(IS_PLAYER(victim) || ((victim.turret_flags & TUR_FLAG_ISTURRET) && victim.active == ACTIVE_ACTIVE) || (victim.flags & FL_MONSTER))
                        {
-                               if(DIFF_TEAM(victim, attacker))
+                               if(DIFF_TEAM(victim, attacker) && !victim.frozen)
                                {
                                        if(damage > 0)
                                        {
Simple merge
Simple merge
@@@ -230,14 -238,6 +241,12 @@@ cheats.q
  
  round_handler.qc
  
- ../common/explosion_equation.qc
 +../common/turrets/sv_turrets.qc
 +../common/turrets/config.qc
 +../common/turrets/turrets.qc
 +../common/turrets/checkpoint.qc
 +../common/turrets/targettrigger.qc
 +
  ../common/monsters/sv_monsters.qc
  ../common/monsters/monsters.qc
  
Simple merge
Simple merge
Simple merge