r3857 - in trunk/data/qcsrc/server: . tturrets tturrets/include tturrets/system tturrets/units

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Mon Jul 21 05:55:08 EDT 2008


Author: tzork
Date: 2008-07-21 05:55:06 -0400 (Mon, 21 Jul 2008)
New Revision: 3857

Added:
   trunk/data/qcsrc/server/server.cbp
   trunk/data/qcsrc/server/tturrets/
   trunk/data/qcsrc/server/tturrets/include/
   trunk/data/qcsrc/server/tturrets/include/turret_tturrets.qh
   trunk/data/qcsrc/server/tturrets/include/turret_tturrets_early.qh
   trunk/data/qcsrc/server/tturrets/system/
   trunk/data/qcsrc/server/tturrets/system/turret_system_aimprocs.qc
   trunk/data/qcsrc/server/tturrets/system/turret_system_damage.qc
   trunk/data/qcsrc/server/tturrets/system/turret_system_main.qc
   trunk/data/qcsrc/server/tturrets/system/turret_system_misc.qc
   trunk/data/qcsrc/server/tturrets/system/turret_system_scoreprocs.qc
   trunk/data/qcsrc/server/tturrets/units/
   trunk/data/qcsrc/server/tturrets/units/turret_unit_common.qc
   trunk/data/qcsrc/server/tturrets/units/turret_unit_flac.qc
   trunk/data/qcsrc/server/tturrets/units/turret_unit_fusionreactor.qc
   trunk/data/qcsrc/server/tturrets/units/turret_unit_hellion.qc
   trunk/data/qcsrc/server/tturrets/units/turret_unit_hk.qc
   trunk/data/qcsrc/server/tturrets/units/turret_unit_machinegun.qc
   trunk/data/qcsrc/server/tturrets/units/turret_unit_mlrs.qc
   trunk/data/qcsrc/server/tturrets/units/turret_unit_phaser.qc
   trunk/data/qcsrc/server/tturrets/units/turret_unit_plasma.qc
   trunk/data/qcsrc/server/tturrets/units/turret_unit_targettrigger.qc
   trunk/data/qcsrc/server/tturrets/units/turret_unit_tessla.qc
Modified:
   trunk/data/qcsrc/server/assault.qc
   trunk/data/qcsrc/server/constants.qh
   trunk/data/qcsrc/server/g_damage.qc
   trunk/data/qcsrc/server/progs.src
Log:
tZork's turrets, code part (disabled by default, see includes for details). and a code::blocks project file.

Modified: trunk/data/qcsrc/server/assault.qc
===================================================================
--- trunk/data/qcsrc/server/assault.qc	2008-07-21 08:54:24 UTC (rev 3856)
+++ trunk/data/qcsrc/server/assault.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -44,7 +44,7 @@
 
 void assault_objective_use() {
 	// activate objective
-	self.health = 100; 
+	self.health = 100;
 	self.nextthink = time + 0.1;
 }
 
@@ -57,7 +57,7 @@
 		//self.effects = EF_STARDUST;
 		self.nextthink = time + 0.1;
 	}
-	
+
 }
 //=============================================================================
 
@@ -102,7 +102,7 @@
 		if(objective.classname == "target_objective") {
 			found = 1;
 			if(objective.health < ASSAULT_VALUE_INACTIVE) { // targeted objective is active
-				if(self.cnt == 1 && self.max_health >= ASSAULT_VALUE_INACTIVE) { 
+				if(self.cnt == 1 && self.max_health >= ASSAULT_VALUE_INACTIVE) {
 					// decrease was fired already, but objective did recover (round reset)
 					self.cnt = 0;
 				}
@@ -236,7 +236,7 @@
 		self.health = 100;
 
 	self.max_health = self.health;
-	
+
 	self.cnt = 0; // not yet activated
 
 	self.classname = "func_assault_destructible";
@@ -283,7 +283,7 @@
 
 void target_assault_roundend_reset() {
 	self.cnt = self.cnt + 1; // up round counter
-	self.winning = 0; // up round 
+	self.winning = 0; // up round
 }
 
 void target_assault_roundend_use() {
@@ -302,8 +302,33 @@
 }
 
 void assault_roundstart_use() {
+
 	activator = self;
 	SUB_UseTargets();
+
+#ifdef TTURRETS_ENABLED
+    entity ent,oldself;
+
+	//(Re)spawn all turrets
+	oldself = self;
+	ent = find(world, classname, "turret_main");
+	while(ent) {
+	    // Swap turret teams
+        if(ent.team == COLOR_TEAM1)
+            ent.team = COLOR_TEAM2;
+        else
+            ent.team = COLOR_TEAM1;
+
+        self = ent;
+
+        // Dubbles as teamchange
+        ent.turret_spawnfunc();
+
+		ent = find(ent, classname, "turret_main");
+	}
+	self = oldself;
+#endif
+
 }
 
 void spawnfunc_target_assault_roundstart() {
@@ -317,7 +342,7 @@
 // trigger new round
 // reset objectives, toggle spawnpoints, reset triggers, ...
 void assault_new_round() {
-	
+
 	// up round counter
 	self.winning = self.winning + 1;
 	// set end time for next round
@@ -356,7 +381,7 @@
 		self = oldself;
 
 		ent = find(ent, classname, "info_player_deathmatch");
-	} 
+	}
 
 	// reset all objectives
 	ent = find(world, classname, "target_objective");
@@ -368,7 +393,7 @@
 		self = oldself;
 
 		ent = find(ent, classname, "target_objective");
-	} 
+	}
 
 	// reset round end triggers
 	ent = find(world, classname, "target_assault_roundend");
@@ -388,7 +413,7 @@
 	{
 		ent.cnt = 0;
 		ent = find(ent, classname, "target_objective_decrease");
-	} 
+	}
 
 	// reset all spawnfunc_func_assault_destructible
 	ent = find(world, classname, "func_assault_destructible");
@@ -396,6 +421,12 @@
 	{
 		oldself = self;
 		self = ent;
+
+        if(ent.team == COLOR_TEAM1)
+            ent.team = COLOR_TEAM2;
+        else
+            ent.team = COLOR_TEAM1;
+
 		assault_destructible_reset();
 		self = oldself;
 		ent = find(ent, classname, "func_assault_destructible");
@@ -419,6 +450,7 @@
 		PutClientInServer();
 		self = oldself;
 		ent = find(ent, classname, "player");
+
 	}
 
 

Modified: trunk/data/qcsrc/server/constants.qh
===================================================================
--- trunk/data/qcsrc/server/constants.qh	2008-07-21 08:54:24 UTC (rev 3856)
+++ trunk/data/qcsrc/server/constants.qh	2008-07-21 09:55:06 UTC (rev 3857)
@@ -151,7 +151,11 @@
 float	DEATH_SHOOTING_STAR			= 10012;
 float	DEATH_ROT				= 10013;
 float	DEATH_MIRRORDAMAGE		= 10014;
+float   DEATH_TURRET            = 10100;
 
+
+
+
 float	IT_LASER				= 4096;
 float	IT_SHOTGUN				= 1;
 float	IT_UZI					= 2;

Modified: trunk/data/qcsrc/server/g_damage.qc
===================================================================
--- trunk/data/qcsrc/server/g_damage.qc	2008-07-21 08:54:24 UTC (rev 3856)
+++ trunk/data/qcsrc/server/g_damage.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -169,7 +169,7 @@
 				else
 					centerprint(targ, "^1You grew too old without taking your medicine\n\n\n");
 			} else if (deathtype == DEATH_MIRRORDAMAGE) {
-				if(sv_gentle)				
+				if(sv_gentle)
 					centerprint(targ, "^1Don't go against team mates!\n\n\n");
 				else
 					centerprint(targ, "^1Don't shoot your team mates!\n\n\n");
@@ -187,7 +187,7 @@
 					bprint ("^1",s, "^1 didn't become friends with the Lord of Teamplay\n");
 				else
 					bprint ("^1",s, "^1 will be reinserted into the game due to his own actions\n");
-	
+
 				if(deathtype != DEATH_TEAMCHANGE)
 				{
 					LogDeath("suicide", deathtype, targ, targ);
@@ -218,7 +218,7 @@
 					bprint ("^1",s, "^1 didn't become friends with the Lord of Teamplay\n");
 				else if (deathtype != DEATH_TEAMCHANGE)
 					bprint ("^1",s, "^1 couldn't resist the urge to self-destruct\n");
-	
+
 				if(deathtype != DEATH_TEAMCHANGE)
 				{
 					LogDeath("suicide", deathtype, targ, targ);
@@ -235,7 +235,7 @@
 				if(sv_gentle) {
 					centerprint(attacker, "^1Moron! You went against a teammate!\n\n\n");
 					bprint ("^1", a, "^1 took action against a teammate\n");
-				} else {				
+				} else {
 					centerprint(attacker, "^1Moron! You fragged a teammate!\n\n\n");
 					bprint ("^1", a, "^1 mows down a teammate\n");
 				}
@@ -315,6 +315,8 @@
 						bprint ("^1",s, "^1 was conserved by ", a, "\n");
 					else if (deathtype == DEATH_HURTTRIGGER)
 						bprint ("^1",s, "^1 was thrown into a world of hurt by ", a, "\n");
+                    else if(deathtype == DEATH_TURRET)
+                        bprint ("^1",s, "^1 was pushed into the line of fire by ^1", a, "\n");
 					else
 						bprint ("^1",s, "^1 was fragged by ", a, "\n");
 				}
@@ -432,6 +434,8 @@
 					bprint ("^1",s, "^1 discovered a swamp\n");
 				else
 					bprint ("^1",s, "^1 is now conserved for centuries to come\n");
+            else if(deathtype == DEATH_TURRET)
+                    bprint ("^1",s, "^1 was mowed down by a turret \n");
 			else
 				if(sv_gentle)
 					bprint ("^1",s, "^1 needs a restart\n");

Modified: trunk/data/qcsrc/server/progs.src
===================================================================
--- trunk/data/qcsrc/server/progs.src	2008-07-21 08:54:24 UTC (rev 3856)
+++ trunk/data/qcsrc/server/progs.src	2008-07-21 09:55:06 UTC (rev 3857)
@@ -8,6 +8,9 @@
 
 extensions.qh
 
+//// tZork Turrets ////
+tturrets/include/turret_tturrets_early.qh
+
 campaign.qh
 ../common/campaign_common.qh
 ../common/util.qh
@@ -114,3 +117,7 @@
 t_quake3.qc
 t_halflife.qc
 t_quake.qc
+
+
+//// tZork Turrets ////
+tturrets/include/turret_tturrets.qh
\ No newline at end of file

Added: trunk/data/qcsrc/server/server.cbp
===================================================================
--- trunk/data/qcsrc/server/server.cbp	                        (rev 0)
+++ trunk/data/qcsrc/server/server.cbp	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+	<FileVersion major="1" minor="6" />
+	<Project>
+		<Option title="server" />
+		<Option pch_mode="2" />
+		<Option compiler="quakec" />
+		<Build>
+			<Target title="Standard">
+				<Option output="bin\Debug\server" prefix_auto="1" extension_auto="1" />
+				<Option object_output="obj\Debug\" />
+				<Option type="1" />
+				<Option compiler="quakec" />
+				<Compiler>
+					<Add option="-g" />
+				</Compiler>
+			</Target>
+		</Build>
+		<Compiler>
+			<Add option="-Wall" />
+		</Compiler>
+		<Extensions>
+			<code_completion />
+			<envvars />
+			<debugger />
+			<lib_finder disable_auto="1" />
+		</Extensions>
+	</Project>
+</CodeBlocks_project_file>

Added: trunk/data/qcsrc/server/tturrets/include/turret_tturrets.qh
===================================================================
--- trunk/data/qcsrc/server/tturrets/include/turret_tturrets.qh	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/include/turret_tturrets.qh	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,31 @@
+#ifdef TTURRETS_ENABLED
+
+// Include section.
+#include "../system/turret_system_misc.qc"       /// Assorted junk & jewls
+#include "../system/turret_system_main.qc"       /// And routines
+#include "../system/turret_system_aimprocs.qc"   /// Aiming realted stuff
+#include "../system/turret_system_scoreprocs.qc" /// Target calssification
+#include "../system/turret_system_damage.qc"     /// Outch, they are hurting me! what should i do?
+
+#include "../units/turret_unit_common.qc"   /// Some "make life easyer" funcs.
+
+// Non combat units
+#include "../units/turret_unit_fusionreactor.qc"  /// Supply unites that need it with power
+// #include "../units/turret_unit_targetcomputer.qc" /// Optimized target selection for multiple units
+#include "../units/turret_unit_targettrigger.qc"  /// Hit me!
+
+// Combat units
+#include "../units/turret_unit_plasma.qc"  /// Basic energy cannon
+#include "../units/turret_unit_mlrs.qc"    /// Basic multibay RL
+#include "../units/turret_unit_hellion.qc" /// Seeking missiles MLRS
+#include "../units/turret_unit_flac.qc"    /// anti missile turret
+#include "../units/turret_unit_phaser.qc"   /// ZzzapT
+//#include "../units/turret_unit_gauss.qc"   /// Railgun
+#include "../units/turret_unit_hk.qc"      /// Hunter killers
+#include "../units/turret_unit_machinegun.qc" /// whacka
+//#include "../units/turret_unit_minigun.qc" /// whacka whacka
+#include "../units/turret_unit_tessla.qc"  /// Chain lightning capabale turret
+//#include "../units/turret_unit_walker.qc"
+//#include "../units/turret_unit_howitzer.qc"
+
+#endif // TTURRETS_ENABLED

Added: trunk/data/qcsrc/server/tturrets/include/turret_tturrets_early.qh
===================================================================
--- trunk/data/qcsrc/server/tturrets/include/turret_tturrets_early.qh	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/include/turret_tturrets_early.qh	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,459 @@
+// Comment out below to skip turrets
+//#define TTURRETS_ENABLED
+
+#ifdef TTURRETS_ENABLED
+
+#message "with tZork turrets rc1"
+
+vector real_origin(entity ent);
+
+/// target selection flags
+.float target_select_flags;
+.float target_validate_flags;
+/// Dont select a target on its own.
+#define TFL_TARGETSELECT_NO            1024
+/// Need line of sight
+#define TFL_TARGETSELECT_LOS           2
+/// Players are valid targets
+#define TFL_TARGETSELECT_PLAYERS       4
+/// Missiles are valid targets
+#define TFL_TARGETSELECT_MISSILES      8
+/// Responds to turret_trigger_target events
+#define TFL_TARGETSELECT_TRIGGERTARGET 16
+/// Angular limitations of turret head limits target selection
+#define TFL_TARGETSELECT_ANGLELIMITS   32
+/// Range limits apply in targetselection
+#define TFL_TARGETSELECT_RANGELIMTS    64
+/// DOnt select targets with a .team matching its own
+#define TFL_TARGETSELECT_TEAMCHECK     4096
+/// Cant select targets on its own. needs to be triggerd or slaved.
+#define TFL_TARGETSELECT_NOBUILTIN     256
+/// TFL_TARGETSELECT_TEAMCHECK is inverted (selects only mebers of own .team)
+#define TFL_TARGETSELECT_OWNTEAM       2048
+
+/// aim flags
+.float aim_flags;
+/// Dont aim.
+#define TFL_AIM_NO                  512
+/// Go for ground, not direct hit
+#define TFL_AIM_GROUND              2
+/// Use balistic aim (not implemented)
+#define TFL_AIM_BALISTIC            4
+/// Try to predict target movement
+#define TFL_AIM_LEAD                8
+/// Compensate for shot traveltime when lead
+#define TFL_AIM_SHOTTIMECOMPENSATE  16
+/// Aim slightly in front of target
+#define TFL_AIM_INFRONT             32
+/// Aim slightly behind target
+#define TFL_AIM_BEHIND              64
+/// blend real and predicted z positions. (fake bounce prediction)
+#define TFL_AIM_ZEASE               128
+/// Just poitn at target's current location
+#define TFL_AIM_SIMPLE              256
+
+/// track (turn and pitch head) flags
+.float track_flags;
+/// Dont move head
+#define TFL_TRACK_NO    2
+/// Pitch the head
+#define TFL_TRACK_PITCH 4
+/// Rotate the head
+#define TFL_TRACK_ROT   8
+
+/// How tracking is preformed
+.float track_type;
+/// Hard angle increments. Ugly for fast turning, best accuracy.
+#define TFL_TRACKTYPE_STEPMOTOR    1
+/// Smoth absolute movement. Looks ok, fair accuracy.
+#define TFL_TRACKTYPE_FLUIDPRECISE 2
+/// Simulated inertia. "Wobbly mode" Looks kool, can mean terrible accuracy depending on how the feilds below are set
+#define TFL_TRACKTYPE_FLUIDINERTIA 3
+/// TFL_TRACKTYPE_FLUIDINERTIA: pitch multiplier
+.float track_accel_pitch;
+/// TFL_TRACKTYPE_FLUIDINERTIA: rotation multiplier
+.float  track_accel_rot;
+/// TFL_TRACKTYPE_FLUIDINERTIA: Blendrate with old rotation (inertia simulation) 1  = only old, 0 = only new
+.float  track_blendrate;
+
+/// How prefire check is preformed
+.float firecheck_flags;
+/// Dont do any chekcs
+#define TFL_FIRECHECK_NO          8192
+/// Dont kill the world
+#define TFL_FIRECHECK_WORLD       2
+/// Dont kill the dead
+#define TFL_FIRECHECK_DEAD        4
+/// Range limits apply
+#define TFL_FIRECHECK_DISTANCES   8
+/// Line Of Sight needs to be clear
+#define TFL_FIRECHECK_LOS         16
+/// Consider distance inpactpoint<->aimspot
+#define TFL_FIRECHECK_AIMDIST     32
+/// Consider enemy origin<->impactpoint
+#define TFL_FIRECHECK_REALDIST    64
+/// Consider angular diff head<->aimspot
+#define TFL_FIRECHECK_ANGLEDIST  128
+/// (re)consider target.team<->self.team
+#define TFL_FIRECHECK_TEAMCECK   256
+/// Try to avoid friendly fire
+#define TFL_FIRECHECK_AFF        512
+/// Own .ammo needs to be >= then own .shot_dmg
+#define TFL_FIRECHECK_OWM_AMMO   1024
+/// Others ammo need to be < others .ammo_max
+#define TFL_FIRECHECK_OTHER_AMMO 2048
+/// Check own .attack_finished vs time
+#define TFL_FIRECHECK_REFIRE     4096
+
+/// How shooting is done
+.float shoot_flags;
+/// Dont shoot
+#define  TFL_SHOOT_NO          64
+/// Fire in vollys (partial implementation through .shot_volly)
+#define  TFL_SHOOT_VOLLY       2
+/// Always do a full volly, even if target is lost or dead. (not implemented)
+#define  TFL_SHOOT_VOLLYALWAYS 4
+/// Loop though all valid tarters, and hit them.
+#define  TFL_SHOOT_HITALLVALID 8
+/// Fiering makes unit loose target (after volly is done, if in volly mode)
+#define  TFL_SHOOT_CLEARTARGET 16
+///Custom shooting;
+#define  TFL_SHOOT_CUSTOM 32
+
+/// Information aboute the units capabilities
+.float turrcaps_flags;
+/// No kown capabilities
+#define  TFL_TURRCAPS_NONE        0
+/// Capable of sniping
+#define  TFL_TURRCAPS_SNIPER      2
+/// Capable of splasdamage
+#define  TFL_TURRCAPS_RADIUSDMG   4
+/// Has one or more cannons with zero shot traveltime
+#define  TFL_TURRCAPS_HITSCAN     8
+/// More then one (type of) gun
+#define  TFL_TURRCAPS_MULTIGUN    16
+/// Carries at least one guided weapon
+#define  TFL_TURRCAPS_GUIDED      32
+/// At least one gun fiers slow projectiles
+#define  TFL_TURRCAPS_SLOWPROJ    64
+/// At least one gun fiers medium speed projectiles
+#define  TFL_TURRCAPS_MEDPROJ     128
+/// At least one gun fiers fast projectiles
+#define  TFL_TURRCAPS_FASTPROJ    256
+/// At least one gun capable of damaging players
+#define  TFL_TURRCAPS_PLAYERKILL  512
+/// At least one gun that can shoot town missiles
+#define  TFL_TURRCAPS_MISSILEKILL 1024
+/// Has support capabilities. powerplants and sutch.
+#define  TFL_TURRCAPS_SUPPORT     2048
+/// Proveides at least one type of ammmo
+#define  TFL_TURRCAPS_AMMOSOURCE  4096
+/// Can recive targets from external sources
+#define TFL_TURRCAPS_RECIVETARGETS 8192
+/// Capable of self-transport
+#define TFL_TURRCAPS_MOVE 16384
+/// Will roam arround even if not chasing anyting
+#define TFL_TURRCAPS_ROAM 32768
+#define TFL_TURRCAPS_LINKED 65536
+
+/// Ammo types needed and/or provided
+.float ammo_flags;
+/// Has and needs no ammo
+#define  TFL_AMMO_NONE     64
+/// Uses power
+#define  TFL_AMMO_ENERGY   2
+/// Uses bullets
+#define  TFL_AMMO_BULLETS  4
+/// Uses explosives
+#define  TFL_AMMO_ROCKETS  8
+/// Regenerates ammo on its own
+#define  TFL_AMMO_RECHARGE 16
+ /// Can recive ammo from others
+#define  TFL_AMMO_RECIVE   32
+
+/// How incomming damage is handeld
+.float damage_flags;
+/// Cant be hurt
+#define  TFL_DMG_NO              256
+/// Can be damaged
+#define  TFL_DMG_YES             2
+/// Can be damaged  by teammates
+#define  TFL_DMG_TAKEFROMTEAM    4
+/// Traget attackers
+#define  TFL_DMG_RETALIATE       8
+/// Target attackers, even is on own team
+#define  TFL_DMG_RETALIATEONTEAM 16
+/// Loses target when damaged
+#define  TFL_DMG_TARGETLOSS      32
+/// Reciving damage trows off aim
+#define  TFL_DMG_AIMSHAKE        64
+/// Reciving damage slaps the head arround
+#define  TFL_DMG_HEADSHAKE       128
+
+// Spawnflags
+/// Spawn in teambased modes
+#define TFL_SPAWN_TEAM      2
+/// Spawn in FFA modes
+#define TFL_SPAWN_FFA       4
+/// Respawn after death
+#define TFL_SPAWN_RESPAWN   8
+
+/*
+* Fields commnly used by turrets
+*/
+/// Turrets internal ai speed
+.float      ticrate;
+/// Where to point the head when no target
+.vector     idle_aim;
+/// Top part of turret
+.entity     tur_head;
+/// Start/respawn health
+.float      tur_health;
+/// Defend this entity (or ratehr this entitys position)
+.entity     tur_defend;
+/// on/off toggle.
+.float      tur_active;
+/// Aim from this point,
+.vector     tur_aimorg;
+/// and shoot from here. (could be non constant, think MLRS)
+.vector     tur_shotorg;
+/// Aim at this spot
+.vector     tur_aimpos;
+/// Predicted time the round will impact
+.float      tur_impacttime;
+/// Predicted place the round will impact
+.vector     tur_impactpoint;
+/// What entity the aimtrace hit, if any.
+.entity     tur_impactent;
+/// Distance to enemy
+.float      tur_dist_enemy;
+/// Distance impact<->aim
+.float      tur_dist_toaimpos;
+/// Decresment counter form .shot_volly to 0.
+.float      volly_counter;
+/// Pointer to master when in slave mode
+.entity     emaster;            // A slave?
+
+/*
+* Projectile/missile. its up to the individual turret implementation to
+** deal the damage, blow upp the missile or whatever.
+*/
+/// Track then refireing is possible
+.float attack_finished;
+/// Shoot this often
+.float shot_refire;
+/// Shots travel this fast, when appliable
+.float shot_speed;
+/// Inaccuracy
+.float shot_spread;
+/// Estimated (core) damage of projectiles. also reduce on ammo with this amount when fiering
+.float shot_dmg;
+/// If radius dmg, this is how big that radius is.
+.float shot_radius;
+/// Max force exserted by round impact
+.float shot_force;
+/// < 1 = shoot # times at target (if possible)
+.float shot_volly;
+/// Refire after a compleated or borken volly.
+.float shot_volly_refire;
+
+/// Consider targets within this range
+.float target_range;
+/// Dont consider targets closer then
+.float target_range_min;
+/// Engage fire routine on targets within
+.float target_range_fire;
+/// Targets closer to this are prefered
+.float target_range_optimal;
+
+/*
+* The standard targetselection tries to select a target based on
+* range, angle offset, target type, "is old target"
+* Thise biases will allow score scaling to (dis)favor diffrent targets
+*/
+/// (dis)Favor best range this mutch
+.float target_select_rangebias;
+/// (dis)Favor targeting my old enemy this mutch
+.float target_select_samebias;
+/// (dis)Favor targeting the enemy closest to my guns current angle this mutch
+.float target_select_anglebias;
+/// (dis)Favor Missiles? (-1 to diable targeting compleatly)
+.float target_select_missilebias;
+/// (dis)Favot living players (-1 to diable targeting compleatly)
+.float target_select_playerbias;
+
+/*
+* Aim refers to real aiming, not gun pos (thats done by track)
+*/
+/// Maximum offset between impact and aim spot to fire
+.float aim_firetolerance_dist;
+/// Maximum angular offset between head and aimspot to fire
+.float aim_firetolerance_angle;
+/// How fast can i rotate/pitch (per second in stepmotor mode, base force in smooth modes)
+.float aim_speed;
+/// cant aim higher/lower then this
+.float aim_maxpitch;
+/// I cant rotate more then this
+.float aim_maxrot;
+
+// Ammo/power. keeping dmg and ammo on a one to one ratio is preferable (for rating)
+/// Staring & current ammo
+.float ammo;
+/// Regenerate this mutch ammo (per second)
+.float ammo_recharge;
+/// Max amount of ammo i can hold
+.float ammo_max;
+
+// Am i enslaved?
+// Slave turrets always target the same target as their master.
+// However; Depending on their individual capabiliteis, they may not fire at the same time
+// or at all. (slaves ranges, rotaion limits, ammo etc still apply)
+
+/// Set to another turrets .master_nameof to enslave me
+.string master_name;
+/// Set another turrets .master_name to this to enslave it
+.string master_nameof;
+
+// Uncomment below to enable various debug output.
+//#define TURRET_DEBUG
+//#define TURRET_DEBUG_TARGETVALIDATE
+//#define TURRET_DEBUG_TARGETSELECT
+
+#ifdef TURRET_DEBUG
+.float tur_dbg_dmg_t_h; // Total dmg that hit something (can be more then tur_dbg_dmg_t_f since it should count radius dmg.
+.float tur_dbg_dmg_t_f; // Total damage spent
+.float tur_dbg_start;   // When did i go online?
+.float tur_dbg_tmr1;    // timer for random use
+.float tur_dbg_tmr2;    // timer for random use
+.float tur_dbg_tmr3;    // timer for random use
+.vector tur_dbg_rvec;   // Random vector, mainly for coloruing stuff'
+#endif
+
+// System main's
+/// Main AI loop
+void turret_think();
+/// Prefire checks and sutch
+void turret_fire();
+
+// Callbacks
+/// implements the actual fiering
+.void()  turret_firefunc;
+/// prefire checks go here. return 1 to go bang, 0 not to.
+.float() turret_firecheckfunc;
+/// Execure BEFORE main ai loop. return 0 to cancel any following proccessing.
+.float() turret_prethink;
+/// Execure AFTER main AI loop UNLESS turret_prethink returnd 0
+.void()  turret_postthink;
+
+/// Add a target
+.float(entity e_target,entity e_sender) turret_addtarget;
+
+.float call_diehook;
+.float call_respwnhook;
+.void() turret_diehook;
+.void() turret_respawnhook;
+
+/*
+* Some turrets need other aimsystems then other.
+* This should return the place to aim at, not acctualy turn or
+* pitch anyting.
+*
+* use turret_stdproc_aim# or Make your own.
+* Make sure you update tur_enemy_dist and tur_enemy_adist
+* with the apropriate info, if you do.
+*/
+/// function used to aim, usualy turret_stdproc_aim_generic
+.vector() turret_aim;
+
+/*
+* This is where the acctual turret turning should take place
+* Use turret_stdproc_track or make your own.
+*/
+/// Function used to turn and pitch the .tur_head usualy turret_stdproc_track
+.void() turret_track;
+
+/*
+* Target selection, preferably but not nessesarely
+* return a normalized result.
+*/
+/// Function to use for target evaluation. usualy turret_stdproc_targetscore_generic
+.float(entity e_turret, entity e_target) turret_score_target;
+
+/*
+* Damage, death and respawn.
+*/
+void turret_gibs_precash();
+/// Function to handle incomming damage. usualy turret_stdproc_damage
+.void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce) turret_damagefunc;
+/// Function to handle the event of death. usualy turret_stdproc_die
+.void() turret_diefunc;
+ /// Function that handles rebirth. usualy turret_stdproc_respawn
+.void() turret_spawnfunc;
+
+/*
+* Stuff to plug into requierd but unused callbacks.
+*/
+/// Always return 1
+float turret_stdproc_true();
+/// Always return 0
+float turret_stdproc_false();
+/// Always return nothing at all
+void turret_stdproc_nothing();
+
+/*
+* Target selection
+*/
+/// "closeer is beter" selection
+float   turret_stdproc_targetscore_close(entity e_turret, entity e_target);
+/// "further is beter" selection
+float   turret_stdproc_targetscore_far(entity e_turret, entity e_target);
+/// only target_range_optimal
+float   turret_stdproc_targetscore_optimal(entity e_turret, entity e_target);
+/// defendpos
+float   turret_stdproc_targetscore_defend(entity e_turret, entity e_target);
+/// Generic fairly smart bias-aware target selection.
+float   turret_stdproc_targetscore_generic(entity e_turret, entity e_target);
+/// Experimental supportunits targetselector
+float turret_stdproc_targetscore_support(entity e_turret,entity e_target);
+
+/*
+* Aim functions
+*/
+/// Generic aimer guided by self.aim_flags
+vector turret_stdproc_aim_generic()
+/// Straight line, current location
+vector  turret_stdproc_aim_simple()
+
+/*
+* Turret turning & pitch
+*/
+/// Tries to line up the turret head with the aimpos
+void turret_stdproc_track();
+
+/// Generic damage handeling. blows up the turret when health <= 0
+void turret_stdproc_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce);
+/// Spawns a explotion, does some damage & trows bits arround.
+void turret_stdproc_die();
+/// reassembles the turret.
+void turret_stdproc_respawn();
+
+/// Evaluate target validity
+float turret_validate_target(entity e_turret,entity e_target,float validate_flags);
+/// Turret Head Angle Diff Vector. updated by a sucsessfull call to turret_validate_target
+vector tvt_thadv;
+/// Turret Angle Diff Vector. updated by a sucsessfull call to turret_validate_target
+vector tvt_tadv;
+/// Turret Head Angle Diff Float. updated by a sucsessfull call to turret_validate_target
+float  tvt_thadf;
+/// Turret Angle Diff Float. updated by a sucsessfull call to turret_validate_target
+float  tvt_tadf;
+/// Distance. updated by a sucsessfull call to turret_validate_target
+float  tvt_dist;
+
+/// updates aim org, shot org, shot dir and enemy org for selected turret
+void turret_do_updates(entity e_turret);
+.vector tur_aimorg_updated;
+.vector tur_shotorg_updated;
+.vector tur_shotdir_updated;
+
+#endif // TTURRETS_ENABLED

Added: trunk/data/qcsrc/server/tturrets/system/turret_system_aimprocs.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/system/turret_system_aimprocs.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/system/turret_system_aimprocs.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,119 @@
+/*
+* Straight line, Dead-on (no prediction)
+* Usefull for "stupid turrets" or ones
+* that launch guided weapons and just need to apeer to
+* somewhat face (and/or track) the target.
+
+supports:
+TFL_AIM_NO
+*/
+vector turret_stdproc_aim_simple()
+{
+    float s_bu;     // Solidity backup (for ground shooters)
+    vector aim_pos;
+
+    if (self.aim_flags & TFL_AIM_NO) return self.idle_aim;
+
+    aim_pos = self.enemy.origin;
+
+    // Target ground?
+    if (self.aim_flags & TFL_AIM_GROUND)
+    {
+        s_bu = self.enemy.solid;
+        self.enemy.solid = SOLID_NOT;
+        traceline(self.enemy.origin + '0 0 128',self.enemy.origin + '0 0 -99999',1,self.enemy);
+        self.enemy.solid = s_bu;
+        aim_pos = trace_endpos;
+    }
+
+    // This is where its at.
+    return aim_pos;
+}
+
+/*
+* Generic aim
+
+supports:
+TFL_AIM_NO
+TFL_AIM_GROUND
+TFL_AIM_LEAD
+TFL_AIM_SHOTTIMECOMPENSATE
+TFL_AIM_INFRONT
+TFL_AIM_BEHIND
+TFL_AIM_ZEASE
+
+not supported:
+TFL_AIM_BALISTIC
+*/
+vector turret_stdproc_aim_generic()
+{
+    vector pre_pos;
+
+    if (self.aim_flags == TFL_AIM_NO)
+        return self.idle_aim;
+
+    // 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
+            pre_pos += self.enemy.velocity * (self.tur_dist_enemy / self.shot_speed);
+        else if (self.turrcaps_flags & TFL_TURRCAPS_HITSCAN)   // Hitscan gun, conpensate for frametime and posibly refire offset.
+            pre_pos += self.enemy.velocity * (frametime + min(max(self.attack_finished - time,0),self.ticrate*2));
+        else                                                   // No lead
+            pre_pos += self.enemy.velocity;
+
+    // Smooth out predict-Z?
+    if (self.aim_flags & TFL_AIM_ZEASE)
+    {
+        vector v;
+        v = real_origin(self.enemy);
+        //pre_pos_z = (pre_pos_z * 0.5) + (v_z * 0.5);
+        pre_pos_z = (pre_pos_z  + v_z) * 0.5;
+    }
+
+    if (self.aim_flags & TFL_AIM_INFRONT)   // Aim a bit in front of the target
+        pre_pos -= normalize(self.tur_aimorg_updated - pre_pos) * 32;
+
+    if (self.aim_flags & TFL_AIM_BEHIND)    // Aim a bit behind the target
+        pre_pos += normalize(self.tur_aimorg_updated - pre_pos) * 32;
+
+
+    // This turret should hit the ground neer a target rather the do a direct hit
+    if (self.aim_flags & TFL_AIM_GROUND)
+    {
+        traceline(pre_pos + '0 0 512',pre_pos - '0 0 2048',1,self.enemy);
+        pre_pos = trace_endpos;
+    }
+
+    // self.tur_impacttime = vlen(pre_pos - self.origin) / self.shot_speed;
+
+    return pre_pos;
+}
+
+
+/*
+* Aim where it is
+supports:
+TFL_AIM_NO
+*/
+vector turret_stdproc_aim_rail()
+{
+    vector pre_pos;
+
+    if (self.aim_flags & TFL_AIM_NO)
+        return self.idle_aim;
+
+    pre_pos = real_origin(self.enemy);
+
+    self.tur_dist_toaimpos = vlen(self.enemy.origin - self.tur_aimorg_updated);
+
+    self.tur_impacttime = time;
+
+    return pre_pos;
+
+}
+
+
+

Added: trunk/data/qcsrc/server/tturrets/system/turret_system_damage.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/system/turret_system_damage.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/system/turret_system_damage.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,307 @@
+/*
+* Trow a turret gib
+*/
+void turret_gib_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
+{
+    self.velocity += vforce;
+}
+void turret_gibs_precash()
+{
+    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");
+}
+
+void turret_trowgib(
+    vector v_from, vector v_to, vector v_colormod,
+    string smodel,
+    float f_lifetime, float f_fadetime, float b_burn)
+{
+    local entity gib;
+    local entity burn;
+
+    gib = spawn();
+
+    gib.classname = "turret_gib";
+    setmodel(gib,smodel);
+    setorigin(gib,v_from);
+    SUB_SetFade(gib,time + f_lifetime,2);
+
+    gib.solid              = SOLID_BBOX;
+
+    gib.movetype           = MOVETYPE_BOUNCE;
+    gib.takedamage         = DAMAGE_YES;
+    gib.event_damage       = turret_gib_damage;
+    gib.health             = -1;
+    gib.effects            = EF_LOWPRECISION;
+    gib.flags              = FL_NOTARGET;
+    gib.colormod           = v_colormod;
+    gib.velocity           = v_to;
+
+    if (b_burn)
+    {
+        burn = spawn();
+        burn.effects        = EF_LOWPRECISION|EF_FLAME;
+        setattachment(burn,gib,"");
+        setorigin(burn,(gib.mins + gib.maxs) * 0.5);
+        SUB_SetFade(burn,time + (f_lifetime * 0.5) ,2);
+    }
+}
+
+void turret_gib_boom()
+{
+    entity gib;
+    float i;
+    string s;
+
+    for(i=1;i<5;i++)
+    {
+        gib = spawn();
+        gib.classname = "turret_gib";
+
+        s = strcat("models/turrets/head-gib",ftos(i));
+        s = strcat(s,".md3");
+        // bprint("s:",s,"\n");
+        setmodel(gib,s);
+
+        setorigin(gib,self.origin);
+
+        SUB_SetFade(gib,time + 5,2);
+
+        gib.solid              = SOLID_BBOX;
+
+        gib.movetype           = MOVETYPE_BOUNCE;
+        gib.gravity            = 0.5;
+        gib.damageforcescale   = 2;
+        gib.takedamage         = DAMAGE_YES;
+        gib.event_damage       = turret_gib_damage;
+        gib.health             = -1;
+        gib.effects            = EF_LOWPRECISION;
+        gib.flags              = FL_NOTARGET;
+        gib.velocity           = self.velocity + (randomvec() * 700);
+        gib.avelocity          = randomvec() * 64;
+    }
+
+    WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
+    WriteByte (MSG_BROADCAST, 78);
+    WriteCoord (MSG_BROADCAST, self.origin_x);
+    WriteCoord (MSG_BROADCAST, self.origin_y);
+    WriteCoord (MSG_BROADCAST, self.origin_z);
+
+    remove(self);
+}
+
+void turret_trowgib2(
+    vector v_from, vector v_to, vector v_colormod,
+    entity e_mimic, float boomtime)
+{
+    entity gib;
+
+    gib = spawn();
+
+    gib.classname = "turret_gib";
+    setmodel(gib,e_mimic.model);
+    setorigin(gib,v_from);
+
+    gib.solid              = SOLID_BBOX;
+
+    gib.movetype           = MOVETYPE_BOUNCE;
+    gib.gravity            = 0.75;
+    gib.damageforcescale   = 2;
+    gib.takedamage         = DAMAGE_YES;
+    gib.event_damage       = turret_gib_damage;
+    gib.health             = -1;
+    gib.effects            = EF_LOWPRECISION;
+    gib.flags              = FL_NOTARGET;
+    gib.colormod           = v_colormod;
+    gib.velocity           = v_to;
+    gib.avelocity          = randomvec() * 32;
+    gib.think              = turret_gib_boom;
+    gib.nextthink          = boomtime;
+    gib.effects            = EF_FLAME;
+
+
+}
+/*
+* Spawn a boom, trow fake bits arround
+* and hide the real ones.
+*/
+void turret_stdproc_die()
+{
+    vector org2;
+    vector t_dir;
+
+    // self.tur_active = 0;
+
+    self.deadflag = DEAD_DEAD;
+    self.tur_head.deadflag = self.deadflag;
+
+    sound (self, CHAN_BODY, "weapons/rocket_impact.wav", 1, ATTN_NORM);
+    org2 = self.origin + '0 0 40';
+
+// Explotion grafix
+    WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
+    WriteByte (MSG_BROADCAST, 78);
+    WriteCoord (MSG_BROADCAST, org2_x);
+    WriteCoord (MSG_BROADCAST, org2_y);
+    WriteCoord (MSG_BROADCAST, org2_z);
+
+// Unsolidify and hide real parts
+    self.solid = SOLID_NOT;
+    self.tur_head.solid   = self.solid;
+
+    self.alpha = -1;
+    self.tur_head.alpha = -1;
+
+    self.takedamage = DAMAGE_NO;
+    self.tur_head.takedamage    = self.takedamage;
+
+    self.effects = 0;
+    self.tur_head.effects   = self.effects;
+
+    self.health             = 0;
+
+
+// Trow fake parts arround
+
+    // base
+    makevectors(self.angles);
+    if(random() > 0.5)
+    {
+        turret_trowgib(self.origin, '0 0 0','1 1 1',"models/turrets/base-gib2.md3",min(self.respawntime,20),1,1);
+        t_dir = (v_up * 700) + (randomvec() * 300);
+        turret_trowgib(self.origin, t_dir,'1 1 1',"models/turrets/base-gib3.md3",min(self.respawntime,10),1,1);
+        t_dir = (v_up * 700) + (randomvec() * 300);
+        turret_trowgib(self.origin, t_dir,'1 1 1',"models/turrets/base-gib4.md3",min(self.respawntime,10),1,1);
+    } else {
+        turret_trowgib(self.origin, '0 0 0','1 1 1',"models/turrets/base-gib1.md3",min(self.respawntime,20),1,1);
+    }
+
+    // Blow the top part up into the air
+    turret_trowgib2( self.origin + (v_up * 50),
+                     v_up * 150 + randomvec() * 50,
+                     '0.2 0.2 0.2',
+                     self.tur_head,time + 0.5 + (random() * 0.5));
+
+
+// Go boom
+    RadiusDamage (self,self, min(self.ammo,50),min(self.ammo,50) * 0.25,250,world,min(self.ammo,50)*5,IT_ROCKET_LAUNCHER);
+
+// Setup respawn
+    self.nextthink      = time + self.respawntime;
+    self.think          = self.turret_spawnfunc;
+
+    if(self.call_diehook)
+        self.turret_diehook();
+
+}
+
+void turret_stdproc_respawn()
+{
+    // self.tur_active = 1;
+
+    // Make sure all parts belong to the same team since
+    // this function doubles as "teamchange" function.
+    self.tur_head.team = self.team;
+    if (self.team == COLOR_TEAM1) self.colormod = '1.4 0.8 0.8';
+    if (self.team == COLOR_TEAM2) self.colormod = '0.8 0.8 1.4';
+
+    self.deadflag = DEAD_NO;
+    self.tur_head.deadflag = self.deadflag;
+    self.effects = self.tur_head.effects = 0;
+
+    self.solid = SOLID_BBOX;
+    self.tur_head.solid   = self.solid;
+
+    self.alpha = 1;
+    self.tur_head.alpha     = self.alpha;
+
+    self.takedamage = DAMAGE_YES;
+    self.tur_head.takedamage    = self.takedamage;
+
+    self.avelocity = '0 0 0';
+    self.tur_head.avelocity    = self.avelocity;
+    self.tur_head.angles = self.idle_aim;
+
+    self.health             = self.tur_health;
+
+    self.enemy          = world;
+    self.volly_counter  = self.shot_volly;
+    self.ammo           = self.ammo_max;
+
+    self.nextthink  = time + self.ticrate;
+    self.think      = turret_think;
+
+    if(self.call_respwnhook)
+        self.turret_respawnhook();
+
+}
+
+/*
+* Standard damage proc.
+*/
+void turret_stdproc_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
+{
+    entity baseent;
+    // entity player;
+
+    if (self.health <= 0) return;
+
+    // Damage func is shared on all parts as standard, we need to know what the master entity of this turret is.
+    // if ((self.classname == "turret_head")||(self.classname == "turret_gun")||(self.classname == "turret_badge"))
+    if(self.owner)
+        baseent = self.owner;
+    else
+        baseent = self;
+
+    if (teamplay != 0)
+    {
+        if (self.team == attacker.team)
+        {
+            sprint(attacker,"Turret: Im on your team!\n");
+        } else {
+			/*
+            // This will get enoying fast...
+			FOR_EACH_PLAYER(player)
+				if(player.team == self.team)
+					sprint(player, "The enemy is attacking your base!");
+
+            */
+        }
+
+    }
+
+    baseent.health = baseent.health - damage;
+
+    // thorw head slightly off aim when hit?
+    if((self.classname == "turret_head") || (self.classname == "turret_gun"))
+    if(self.damage_flags & TFL_DMG_HEADSHAKE)
+    {
+        // makevectors(baseent.tur_head.v_angle);
+         baseent.tur_head.angles = baseent.tur_head.angles + randomvec() * damage;
+    }
+
+    if(self.turrcaps_flags & TFL_TURRCAPS_MOVE)
+    {
+        self.velocity = self.velocity + vforce;
+    }
+
+
+    // Start burning when we have 10% or less health left
+    if (self.health < (self.tur_health * 0.1))
+        self.effects = EF_FLAME;
+
+    if (self.health <= 0)
+    {
+        self = baseent;
+        baseent.turret_diefunc();
+    }
+}
+
+

Added: trunk/data/qcsrc/server/tturrets/system/turret_system_main.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/system/turret_system_main.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/system/turret_system_main.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,999 @@
+#define cvar_base "g_turrets_unit_"
+
+.float tur_lastscore;
+.string cvar_basename;
+
+string cvar_gets(string s_base,string s_add)
+{
+    return strcat(s_base,s_add);
+}
+
+.float turret_scale_damage;
+.float turret_scale_range;
+.float turret_scale_refire;
+.float turret_scale_ammo;
+.float turret_scale_aim;
+.float turret_scale_health;
+.float turret_scale_respawn;
+
+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 = ent.angles;
+    }
+    ent.health = cvar(cvar_gets(sbase,"_health")) * ent.turret_scale_health;
+    ent.respawntime = cvar(cvar_gets(sbase,"_respawntime")) * ent.turret_scale_respawn;
+
+    ent.shot_dmg = cvar(cvar_gets(sbase,"_shot_dmg")) * ent.turret_scale_damage;
+    ent.shot_refire = cvar(cvar_gets(sbase,"_shot_refire")) * ent.turret_scale_refire;
+    ent.shot_radius = cvar(cvar_gets(sbase,"_shot_radius")) * ent.turret_scale_damage;
+    ent.shot_speed = cvar(cvar_gets(sbase,"_shot_speed"));
+    ent.shot_spread = cvar(cvar_gets(sbase,"_shot_spread"));
+    ent.shot_force = cvar(cvar_gets(sbase,"_shot_force")) * ent.turret_scale_damage;
+    ent.shot_volly = cvar(cvar_gets(sbase,"_shot_volly"));
+    ent.shot_volly_refire = cvar(cvar_gets(sbase,"_shot_volly_refire")) * ent.turret_scale_refire;
+
+    ent.target_range = cvar(cvar_gets(sbase,"_target_range")) * ent.turret_scale_range;
+    ent.target_range_min = cvar(cvar_gets(sbase,"_target_range_min")) * ent.turret_scale_range;
+    ent.target_range_fire = cvar(cvar_gets(sbase,"_target_range_fire")) * ent.turret_scale_range;
+    ent.target_range_optimal = cvar(cvar_gets(sbase,"_target_range_optimal")) * ent.turret_scale_range;
+
+    ent.target_select_rangebias = cvar(cvar_gets(sbase,"_target_select_rangebias"));
+    ent.target_select_samebias = cvar(cvar_gets(sbase,"_target_select_samebias"));
+    ent.target_select_anglebias = cvar(cvar_gets(sbase,"_target_select_anglebias"));
+    ent.target_select_playerbias = cvar(cvar_gets(sbase,"_target_select_playerbias"));
+
+    ent.ammo_max = cvar(cvar_gets(sbase,"_ammo_max")) * ent.turret_scale_ammo;
+    //ent.ammo = cvar(cvar_gets(sbase,"_ammo"));
+    ent.ammo_recharge = cvar(cvar_gets(sbase,"_ammo_recharge")) * ent.turret_scale_ammo;
+
+    ent.aim_firetolerance_dist = cvar(cvar_gets(sbase,"_aim_firetolerance_dist"));
+    ent.aim_firetolerance_angle = cvar(cvar_gets(sbase,"_aim_firetolerance_angle"));
+    ent.aim_speed = cvar(cvar_gets(sbase,"_aim_speed")) * ent.turret_scale_aim;
+    ent.aim_maxrot = cvar(cvar_gets(sbase,"_aim_maxrot"));
+    ent.aim_maxpitch = cvar(cvar_gets(sbase,"_aim_maxpitch"));
+
+    ent.track_type = cvar(cvar_gets(sbase,"_track_type"));
+    ent.track_accel_pitch = cvar(cvar_gets(sbase,"_track_accel_pitch"));
+    ent.track_accel_rot = cvar(cvar_gets(sbase,"_track_accel_rot"));
+    ent.track_blendrate = cvar(cvar_gets(sbase,"_track_blendrate"));
+}
+
+float turret_stdproc_true()
+{
+    return 1;
+}
+
+float turret_stdproc_false()
+{
+    return 0;
+}
+
+void turret_stdproc_nothing()
+{
+    return;
+}
+
+/**
+** updates enemy distances, preicted impact point/time
+** & aim<->predict impact distance.
+** Also translates shoot & aimorgs by current rotation.
+**/
+void turret_do_updates(entity e_turret)
+{
+    //vector trueaimpoint;
+
+    if (self.turrcaps_flags & TFL_TURRCAPS_LINKED)
+    {
+        e_turret.tur_head.angles_x = e_turret.tur_head.angles_x * -1;
+        e_turret.angles_x = e_turret.angles_x * -1;
+        makevectors(e_turret.tur_head.angles + e_turret.angles);
+        e_turret.tur_head.angles_x = e_turret.tur_head.angles_x * -1;
+        e_turret.angles_x = e_turret.angles_x * -1;
+    }
+    else
+    {
+        e_turret.tur_head.angles_x = e_turret.tur_head.angles_x * -1;
+        makevectors(e_turret.tur_head.angles);
+        e_turret.tur_head.angles_x = e_turret.tur_head.angles_x * -1;
+    }
+
+    //traceline_hitcorpse(e_turret, e_turret.origin, e_turret.origin + v_forward * MAX_SHOT_DISTANCE, MOVE_NOMONSTERS, e_turret);
+    //trueaimpoint = trace_endpos;
+
+    e_turret.tur_shotorg_updated = e_turret.origin + v_forward * e_turret.tur_shotorg_x + v_right * e_turret.tur_shotorg_y + v_up * e_turret.tur_shotorg_z;
+    //e_turret.tur_shotdir_updated = normalize(trueaimpoint - e_turret.tur_shotorg_updated);
+    e_turret.tur_shotdir_updated = normalize((e_turret.tur_shotorg_updated + v_forward * 512) - e_turret.tur_shotorg_updated);
+    e_turret.tur_aimorg_updated = e_turret.origin + v_forward * e_turret.tur_aimorg_x + v_right * e_turret.tur_aimorg_y + v_up * e_turret.tur_aimorg_z;
+    //e_turret.tur_aimorg_updated = e_turret.tur_shotorg_updated;
+
+    e_turret.tur_dist_enemy = vlen(e_turret.tur_aimorg_updated - real_origin(e_turret.enemy));
+    //e_turret.tur_dist_enemy = vlen(e_turret.tur_aimpos - e_turret.tur_shotorg_updated);
+
+    traceline(e_turret.tur_aimorg_updated,e_turret.tur_aimorg_updated+(e_turret.tur_shotdir_updated * e_turret.tur_dist_enemy),TRUE,e_turret);
+
+    e_turret.tur_impactpoint = trace_endpos;
+    e_turret.tur_impactent = trace_ent;
+    e_turret.tur_impacttime = e_turret.tur_dist_enemy / e_turret.shot_speed;
+    e_turret.tur_dist_toaimpos = vlen(trace_endpos - e_turret.tur_aimpos);
+}
+
+/**
+** Handles head rotation according to
+** the units .track_type and .track_flags
+**/
+void turret_stdproc_track()
+{
+    vector wish_angle;  // This is where we'd need to be
+    vector real_angle;  // This is where we can go
+    float f_tmp;
+
+    if (self.track_flags == TFL_TRACK_NO)
+        return;
+
+    if (self.enemy == world)
+    {
+        if (self.turrcaps_flags & TFL_TURRCAPS_LINKED)
+            wish_angle = self.idle_aim + self.angles;
+        else
+            wish_angle = self.idle_aim;
+    }
+    else
+    {
+        if (self.turrcaps_flags & TFL_TURRCAPS_LINKED)
+            wish_angle = normalize(self.tur_aimpos - self.origin); // Find the direction
+        else
+            wish_angle = normalize(self.tur_aimpos - self.tur_head.origin); // Find the direction
+
+        wish_angle = vectoangles(wish_angle);                           // And make a angle
+    }
+
+    // Find the diffrence between where we currently aim and where we want to aim
+    if (self.turrcaps_flags & TFL_TURRCAPS_LINKED)
+        real_angle = wish_angle - (self.tur_head.angles + self.angles);
+    else
+        real_angle = wish_angle - self.tur_head.angles;
+
+    // Constrain it within +/- 360
+    if (real_angle_x < 0) real_angle_x += 360;
+    if (real_angle_x > 180) real_angle_x -= 360;
+
+    if (real_angle_y < 0) real_angle_y += 360;
+    if (real_angle_y > 180) real_angle_y -= 360;
+
+
+    if (self.track_type == TFL_TRACKTYPE_STEPMOTOR)
+    {
+        f_tmp = self.aim_speed * self.ticrate; // dgr/sec -> dgr/tic
+
+        // Limit turning speed
+        real_angle_x = bound((-1 * f_tmp),real_angle_x, f_tmp);
+        real_angle_y = bound((-1 * f_tmp),real_angle_y, f_tmp);
+
+        // Limit pich and rot.
+        if (self.track_flags & TFL_TRACK_PITCH)
+            self.tur_head.angles_x = bound((-1 * self.aim_maxpitch),self.tur_head.angles_x + real_angle_x,self.aim_maxpitch);
+
+        if (self.track_flags & TFL_TRACK_ROT)
+            self.tur_head.angles_y = bound((-1 * self.aim_maxrot),self.tur_head.angles_y  + real_angle_y,self.aim_maxrot);
+
+        return;
+    }
+
+    if (self.track_type == TFL_TRACKTYPE_FLUIDPRECISE)
+    {
+        if (self.track_flags & TFL_TRACK_PITCH)
+            self.tur_head.avelocity_x = real_angle_x;
+
+        if (self.track_flags & TFL_TRACK_ROT)
+            self.tur_head.avelocity_y = real_angle_y;
+    }
+    else if (self.track_type == TFL_TRACKTYPE_FLUIDINERTIA)
+    {
+        f_tmp = self.aim_speed * self.ticrate;
+
+        real_angle_y = bound(self.aim_speed * -1,real_angle_y * self.track_accel_rot * f_tmp,self.aim_speed);
+        real_angle_x = bound(self.aim_speed * -1,real_angle_x * self.track_accel_pitch * f_tmp,self.aim_speed);
+        real_angle = (self.tur_head.avelocity * self.track_blendrate) + (real_angle * (1 - self.track_blendrate));
+
+        if (self.track_flags & TFL_TRACK_PITCH) self.tur_head.avelocity_x = real_angle_x;
+        if (self.track_flags & TFL_TRACK_ROT)   self.tur_head.avelocity_y = real_angle_y;
+        self.tur_head.avelocity_z = real_angle_z;
+    }
+
+    // Limit pitch
+    if (self.track_flags & TFL_TRACK_PITCH)
+    {
+        if (self.tur_head.angles_x > self.aim_maxpitch)
+        {
+            self.tur_head.angles_x = self.aim_maxpitch;
+            self.tur_head.avelocity_x = 0;
+        }
+
+        if (self.tur_head.angles_x < (self.aim_maxpitch * -1))
+        {
+            self.tur_head.angles_x = (self.aim_maxpitch * -1);
+            self.tur_head.avelocity_x = 0;
+        }
+    }
+
+    // Limit rot
+    if (self.track_flags & TFL_TRACK_ROT)
+        if (self.tur_head.angles_y > self.aim_maxrot)
+        {
+            self.tur_head.angles_y = self.aim_maxrot;
+            self.tur_head.avelocity_y = 0;
+        }
+
+    if (self.track_flags & TFL_TRACK_ROT)
+        if (self.tur_head.angles_y < (self.aim_maxrot * -1))
+        {
+            self.tur_head.angles_y = (self.aim_maxrot * -1);
+            self.tur_head.avelocity_y = 0;
+        }
+
+
+}
+
+/*
+ + = 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_OWM_AMMO
+ + TFL_FIRECHECK_OTHER_AMMO
+ + TFL_FIRECHECK_REFIRE
+*/
+
+/**
+** Preforms pre-fire checks based on the uints firecheck_flags
+**/
+float turret_stdproc_firecheck()
+{
+    // This one just dont care =)
+    if (self.firecheck_flags & TFL_FIRECHECK_NO) return 1;
+
+    // Ready?
+    if (self.firecheck_flags & TFL_FIRECHECK_REFIRE)
+        if (self.attack_finished >= time) return 0;
+
+    //
+    if (self.firecheck_flags & TFL_FIRECHECK_DEAD)
+        if (self.enemy.deadflag != DEAD_NO) return 0;
+
+    // Plz stop killing the world!
+    if (self.firecheck_flags & TFL_FIRECHECK_WORLD)
+        if (self.enemy == world) return 0;
+
+    // Own ammo?
+    if (self.firecheck_flags & TFL_FIRECHECK_OWM_AMMO)
+        if (self.ammo < self.shot_dmg) return 0;
+
+    // Other's ammo? (carefull using this...)
+    if (self.firecheck_flags & TFL_FIRECHECK_OTHER_AMMO)
+        if (self.enemy.ammo >= self.enemy.ammo_max) return 0;
+
+    if (self.firecheck_flags & TFL_FIRECHECK_DISTANCES)
+    {
+        // Not close enougth?
+        if (self.tur_dist_enemy > self.target_range_fire) return 0;
+
+        // To close?
+        if (self.tur_dist_enemy < self.target_range_min) 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_toaimpos  > 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 +1))
+                return 0;
+    }
+
+    //if(self.tur_enemy_adist >= self.aim_firetolerance) return 0;
+
+
+    return 1;
+}
+
+/*
+ + TFL_TARGETSELECT_NO
+ + TFL_TARGETSELECT_LOS
+ + TFL_TARGETSELECT_PLAYERS
+ + TFL_TARGETSELECT_MISSILES
+ - TFL_TARGETSELECT_TRIGGERTARGET
+ + TFL_TARGETSELECT_ANGLELIMITS
+ + TFL_TARGETSELECT_RANGELIMTS
+ + TFL_TARGETSELECT_TEAMCHECK
+ - TFL_TARGETSELECT_NOBUILTIN
+ + TFL_TARGETSELECT_OWNTEAM
+*/
+
+/**
+** Evaluate a entity for target valitity based on validate_flags
+**/
+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)// == world)
+        return -1;
+
+    if (e_target.classname == "grapplinghook")
+        return - 1.5;
+
+    if (validate_flags & TFL_TARGETSELECT_NO)
+        return -2;
+
+    // If only this was used more..
+    if (e_target.flags & FL_NOTARGET)
+        return -3;
+
+    // Cant touch this
+    if ((e_target.takedamage == DAMAGE_NO) || (e_target.health < 0))
+        return -4;
+
+    // player
+    if (e_target.flags & FL_CLIENT)
+    {
+        if (!(validate_flags & TFL_TARGETSELECT_PLAYERS))
+            return -5;
+
+        if (e_target.deadflag != DEAD_NO)
+            return -6;
+    }
+
+    // Missile
+    if (e_target.flags & FL_PROJECTILE)
+    {
+        if (!(validate_flags & TFL_TARGETSELECT_MISSILES))
+            return -7;
+    }
+
+    // Team check
+    if (validate_flags & TFL_TARGETSELECT_TEAMCHECK)
+    {
+        if (validate_flags & TFL_TARGETSELECT_OWNTEAM)
+        {
+            if (e_target.team != e_turret.team)
+                return -8;
+
+            if (e_turret.team != e_target.owner.team)
+                return -8.5;
+
+        }
+        else
+        {
+            if (e_target.team == e_turret.team)
+                return -9;
+
+            if (e_turret.team == e_target.owner.team)
+                return -9.5;
+        }
+    }
+
+    // Line of sight?
+    if (validate_flags & TFL_TARGETSELECT_LOS)
+    {
+        v_tmp = real_origin(e_target) + ((e_target.mins + e_target.maxs) * 0.5);
+        //v_tmp = e_target.origin;
+        traceline(e_turret.origin,v_tmp,0,e_turret);
+
+        if (e_turret.aim_firetolerance_dist < vlen(v_tmp - trace_endpos))
+            return -10;
+    }
+
+    // Can we even aim this thing? (anglecheck)
+    tvt_thadv = angleofs(e_turret.tur_head,e_target);
+    tvt_tadv  = angleofs(e_turret,e_target);
+    tvt_thadf = vlen(tvt_thadv);
+    tvt_tadf  = vlen(tvt_tadv);
+
+    if (validate_flags & TFL_TARGETSELECT_ANGLELIMITS)
+    {
+        if (fabs(tvt_tadv_x) > e_turret.aim_maxpitch)
+            return -11;
+
+        if (fabs(tvt_tadv_y) > e_turret.aim_maxrot)
+            return -12;
+    }
+
+    // Range limits?
+    tvt_dist = vlen(e_turret.origin - real_origin(e_target));
+    if (validate_flags & TFL_TARGETSELECT_RANGELIMTS)
+    {
+        if (tvt_dist < e_turret.target_range_min)
+            return -13;
+
+        if (tvt_dist > e_turret.target_range)
+            return -14;
+    }
+
+#ifdef TURRET_DEBUG_TARGETSELECT
+    bprint("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
+    entity e_enemy;  // currently best scoreing enemy
+
+    float score;     // current target (e) score
+    float m_score;   // current best target (e_enemy) score
+    float f;
+    // string s;
+    e = findradius(self.origin,self.target_range);
+
+    // Nothing to aim at.
+    if (!e) return world;
+
+    m_score = 0;
+
+    while (e)
+    {
+        f = turret_validate_target(self,e,self.target_select_flags);
+        //s = ftos(f);
+        //bprint(e.netname, " = ",s,"\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;
+    }
+
+    self.tur_lastscore = m_score;
+
+    //if (self.enemy != e_enemy)
+    //self.volly_counter = 0;
+
+    return e_enemy;
+}
+
+void turret_think()
+{
+    entity e;
+
+    self.nextthink = (time + self.ticrate);
+
+    if (cvar("g_turrets_reloadcvars") == 1)
+    {
+        e = nextent(world);
+        while (e)
+        {
+            if (e.tur_head != world)
+            {
+                load_unit_settings(e,e.cvar_basename,1);
+                self.turret_postthink();
+            }
+
+            e = nextent(e);
+        }
+
+        cvar_set("g_turrets_reloadcvars","0");
+    }
+
+#ifdef TURRET_DEBUG
+    if (self.tur_dbg_tmr1 < time)
+    {
+        if (self.enemy) paint_target (self.enemy,128,self.tur_dbg_rvec,0.9);
+        paint_target(self,256,self.tur_dbg_rvec,0.9);
+        self.tur_dbg_tmr1 = time + 1;
+    }
+#endif
+
+    //Do custom prethink, and bail if it fails.
+    if (!self.turret_prethink()) return;
+
+    // Handle ammo
+    if (self.ammo < self.ammo_max)
+        self.ammo = min(self.ammo + self.ammo_recharge,self.ammo_max);
+
+
+    if ((!self.tur_active) || (self.deadflag != DEAD_NO))
+    {
+        dprint("Warning: Inactive or dead turret running the think function!\n");
+        self.enemy = world;
+        self.turret_track();
+        return;
+    }
+
+    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 (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
+    {
+        // Check if we have a vailid enemy, and get one if we dont.
+        if (self.emaster != world)
+        {
+            self.enemy = self.emaster.enemy;
+        }
+        else
+        {
+            // turret_do_updates(self);
+            if (turret_validate_target(self,self.enemy,self.target_validate_flags) <= 0)// || (self.cnt < time))
+            {
+                self.enemy = turret_select_target();
+                self.cnt = time + self.ticrate * 5;
+            }
+        }
+
+        // No target, just go to idle, do any custom stuff and bail.
+        if (self.enemy == world)
+        {
+            // Turn & pitch
+            self.turret_track();
+
+            // do any per-turret stuff
+            self.turret_postthink();
+
+            // And bail.
+            return;
+        }
+
+        // Update
+        turret_do_updates(self);
+
+        // Predict or whatnot
+        if (!self.aim_flags & TFL_AIM_NO)
+            self.tur_aimpos = self.turret_aim();
+
+        // Turn & pitch
+        if (!self.track_flags & TFL_TRACK_NO)
+            self.turret_track();
+
+        // Update
+        turret_do_updates(self);
+
+        // Fire?
+        if (self.turret_firecheckfunc() != 0)
+            turret_fire();
+    }
+
+    // do any per-turret stuff
+    self.turret_postthink();
+}
+
+void turret_fire()
+{
+    if (cvar("g_turrets_nofire") != 0)   return;
+    if ((!self.tur_active) || (self.deadflag != DEAD_NO)) return;
+
+    self.turret_firefunc();
+
+    self.attack_finished    = time + self.shot_refire;
+    self.ammo               = 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 = time + self.shot_volly_refire;
+    }
+
+
+#ifdef TURRET_DEBUG
+    if (self.enemy) paint_target3(self.tur_aimpos ,64,self.tur_dbg_rvec,self.tur_impacttime+0.25);
+#endif
+}
+
+void turret_stdproc_fire()
+{
+    dprint("^1Bang, ^3your dead^7 ",self.enemy.netname,"! ^1(turret with no real firefunc)\n");
+}
+
+void turret_stdproc_use()
+{
+    // bprint("Used:",self.netname,"\n");
+    if (self.tur_active)
+        self.tur_active = 0;
+    else
+        self.tur_active = 1;
+
+}
+
+/*
+* Standard turret initialization. use this!
+* (unless you have a very good reason not to.)
+* Any special stuff like multiple cannon models should be done
+* after this is proc called.
+* if the return value is 0, the turret should be removed.
+*/
+float turret_stdproc_init (string cvar_base_name)
+{
+    // Are turrets allowed atm?
+    if (cvar("g_turrets") == 0) return 0;
+
+    // Better more then once then never.
+    turret_gibs_precash();
+
+    if (self.spawnflags & 2)
+    {
+        entity tb;
+        precache_model("models/turrets/terrainbase.md3");
+        tb = spawn();
+        setmodel(tb,"models/turrets/terrainbase.md3");
+        setorigin(tb,self.origin);
+        tb.solid = SOLID_BBOX;
+        makestatic(tb);
+    }
+
+    self.cvar_basename = cvar_base_name;
+    load_unit_settings(self,self.cvar_basename,0);
+
+    // Group all turrets into the same team if in non teamplaymode, so they dont try to kill eachother.
+    if (cvar("g_assult") != 0)
+    {
+        if (!self.team)
+            self.team = 14; // Assume turrets are on the defending side if not explicitly set otehrwize
+    }
+    else
+        if ((!teamplay) || (!self.team))
+            self.team = MAX_SHOT_DISTANCE;
+
+
+    /*
+    * Try to guess some reasonaly defaults
+    * for missing params and do sanety checks
+    * thise checks could produce some "interesting" results
+    * if it hits a glitch in my logic :P so try to set as mutch
+    * as possible beforehand.
+    */
+    if (self.turrcaps_flags & TFL_TURRCAPS_SUPPORT)
+    {
+        // Support units generaly dont need to have a high speed ai-loop
+        if (!self.ticrate) self.ticrate = 0.25;     // Speed of this turrets AI loop
+    }
+    else
+    {
+        if (!self.ticrate) self.ticrate = 0.1;     // Speed of this turrets AI loop
+    }
+
+    self.ticrate = bound(0.01,self.ticrate,60);  // keep it sane plz
+
+// General stuff
+    if (self.netname == "")  self.netname        = "turret";
+
+    if (!self.respawntime) self.respawntime = 60;
+    self.respawntime = max(-1,self.respawntime);
+
+    if (!self.health)        self.health         = 1000;
+    self.tur_health = max(1,self.health);
+
+    if (!self.turrcaps_flags) self.turrcaps_flags = TFL_TURRCAPS_RADIUSDMG | TFL_TURRCAPS_MEDPROJ | TFL_TURRCAPS_PLAYERKILL;
+
+    if (!self.damage_flags) self.damage_flags = TFL_DMG_YES | TFL_DMG_RETALIATE | TFL_DMG_AIMSHAKE;
+
+// Shot stuff.
+    if (!self.shot_refire) self.shot_refire     = 1;
+    self.shot_refire = bound(0.01,self.shot_refire,9999);
+
+    if (!self.shot_dmg) self.shot_dmg        = self.shot_refire * 50;
+    self.shot_dmg = max(1,self.shot_dmg);
+
+    if (!self.shot_radius) self.shot_radius     = self.shot_dmg * 0.5;
+    self.shot_radius = max(1,self.shot_radius);
+
+    if (!self.shot_speed) self.shot_speed      = 2500;
+    self.shot_speed = max(1,self.shot_speed);
+
+    if (!self.shot_spread) self.shot_spread     = 0.0125;
+    self.shot_spread = bound(0.0001,self.shot_spread,500);
+
+    if (!self.shot_force) self.shot_force      = self.shot_dmg * 0.5 + self.shot_radius * 0.5;
+    self.shot_force = bound(0.001,self.shot_force,MAX_SHOT_DISTANCE * 0.5);
+
+    if (!self.shot_volly) self.shot_volly = 1;
+    self.shot_volly = bound(1,self.shot_volly,floor(self.ammo_max / self.shot_dmg));
+
+    if (!self.shot_volly_refire) self.shot_volly_refire = self.shot_refire * self.shot_volly;
+    self.shot_volly_refire = bound(self.shot_refire,self.shot_volly_refire,60);
+
+    if (!self.firecheck_flags)
+        self.firecheck_flags = TFL_FIRECHECK_WORLD | TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES |
+                               TFL_FIRECHECK_LOS | TFL_FIRECHECK_AIMDIST | TFL_FIRECHECK_TEAMCECK |
+                               TFL_FIRECHECK_OWM_AMMO | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_WORLD;
+
+// Range stuff.
+    if (!self.target_range) self.target_range               = self.shot_speed * 0.5;
+    self.target_range = bound(0,self.target_range,MAX_SHOT_DISTANCE);
+
+    if (!self.target_range_min)          self.target_range_min           = self.shot_radius * 2;
+    self.target_range_min = bound(0,self.target_range_min,MAX_SHOT_DISTANCE);
+
+    if (!self.target_range_fire)         self.target_range_fire          = self.target_range * 0.8;
+    self.target_range_fire = bound(0,self.target_range_fire,MAX_SHOT_DISTANCE);
+
+    if (!self.target_range_optimal)      self.target_range_optimal       = self.target_range_fire * 0.5;
+    self.target_range_optimal = bound(0,self.target_range_optimal,MAX_SHOT_DISTANCE);
+
+
+// Aim stuff.
+    if (!self.aim_maxrot)    self.aim_maxrot    = 45;
+    self.aim_maxrot = bound(0,self.aim_maxrot,361);
+
+    if (!self.aim_maxpitch)  self.aim_maxpitch  = 20;
+    self.aim_maxpitch = bound(0,self.aim_maxpitch,90);
+
+    if (!self.aim_speed)     self.aim_speed     = 36;
+    self.aim_speed  = bound(0.1,self.aim_speed, 1000);
+
+    if (!self.aim_firetolerance_dist)     self.aim_firetolerance_dist  = 5 + (self.shot_radius * 2);
+    self.aim_firetolerance_dist = bound(0.1,self.aim_firetolerance_dist,MAX_SHOT_DISTANCE);
+
+    if (!self.aim_firetolerance_angle)     self.aim_firetolerance_angle  = 10;
+    self.aim_firetolerance_angle = bound(0.1,self.aim_firetolerance_angle,360);
+
+    if (!self.aim_flags) self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_ZEASE;
+
+    // Sill the most tested (and aim-effective)
+    if (!self.track_type) self.track_type = TFL_TRACKTYPE_STEPMOTOR;
+
+    if (self.track_type != TFL_TRACKTYPE_STEPMOTOR)
+    {
+        // Fluid / ineria mode. Looks mutch nicer, bit experimental &
+        // Can inmapt aim preformance alot.
+        // needs a bit diffrent aimspeed
+        if (!self.aim_speed) self.aim_speed = 180;
+        self.aim_speed  = bound(0.1,self.aim_speed, 1000);
+
+        if (!self.track_accel_pitch) self.track_accel_pitch = 0.75;
+        if (!self.track_accel_rot)   self.track_accel_rot   = 0.75;
+        if (!self.track_blendrate)   self.track_blendrate   = 0.35;
+    }
+
+    if (!self.track_flags) self.track_flags = TFL_TRACK_PITCH | TFL_TRACK_ROT;
+
+
+// Target selection stuff.
+    if (!self.target_select_rangebias)   self.target_select_rangebias     = 1;
+    self.target_select_rangebias = bound(-10,self.target_select_rangebias,10);
+
+    if (!self.target_select_samebias)    self.target_select_samebias      = 1;
+    self.target_select_samebias = bound(-10,self.target_select_samebias,10);
+
+    if (!self.target_select_anglebias)   self.target_select_anglebias     = 1;
+    self.target_select_anglebias = bound(-10,self.target_select_anglebias,10);
+
+    if (!self.target_select_missilebias)   self.target_select_missilebias = -10;
+    self.target_select_missilebias = bound(-10,self.target_select_missilebias,10);
+    self.target_select_playerbias = bound(-10,self.target_select_playerbias,10);
+
+    if (!self.target_select_flags)
+        if (self.turrcaps_flags & TFL_TURRCAPS_MISSILEKILL)
+            self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_MISSILES |
+                                       TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_ANGLELIMITS;
+        else
+            self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS |
+                                       TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_ANGLELIMITS;
+
+    //if(!self.target_validate_flags)
+    self.target_validate_flags = self.target_select_flags;
+
+
+// Ammo stuff
+    if (!self.ammo_max)          self.ammo_max       = self.shot_dmg * 10;
+    self.ammo_max = max(self.shot_dmg,self.ammo_max);
+
+    if (!self.ammo)              self.ammo           = self.shot_dmg * 5;
+    self.ammo = bound(0,self.ammo,self.ammo_max);
+
+    if (!self.ammo_recharge)     self.ammo_recharge = self.shot_dmg / 2;
+    self.ammo_recharge = max(0,self.ammo_recharge);
+
+    // Convert the recharge from X per sec to X per ticrate
+    self.ammo_recharge = self.ammo_recharge * self.ticrate;
+
+    if (!self.ammo_flags) self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE;
+
+// Offsets & origins
+    if (!self.tur_aimorg)    self.tur_aimorg = '0 0 50';
+    if (!self.tur_shotorg)   self.tur_shotorg = '50 0 50';
+
+// End of default & sanety checks, start building the turret.
+
+// Spawn extra bits
+    self.tur_head   = spawn();
+
+    self.tur_head.netname = self.tur_head.classname     = "turret_head";
+    self.tur_head.team = self.team;
+
+    //Slave mode?
+    if (self.master_nameof != "")
+    {
+        self.emaster = find(world, master_name, self.master_name);
+        if (self.emaster == world)
+        {
+            self.master_nameof = "";
+            dprint("Turret has bad invalid!\n");
+        }
+    }
+
+    // Defend mode?
+    if (self.target != "")
+    {
+        self.tur_defend = find(world, targetname, self.target);
+        if (self.tur_defend == world)
+        {
+            self.target = "";
+            dprint("Turret has invalid defendpoint!\n");
+        }
+    }
+
+// Claim ownership
+    self.tur_head.owner   = self;
+
+// Put pices in place
+
+    if (!(self.turrcaps_flags & TFL_TURRCAPS_LINKED))
+        setorigin(self.tur_head,self.origin);
+
+    // In target defense mode, aim on the spot to defens when idle.
+    if (self.tur_defend)
+        self.idle_aim  = self.tur_head.angles + angleofs(self.tur_head,self.tur_defend);
+    else
+        self.idle_aim  = self.angles;
+
+    if (!(self.turrcaps_flags & TFL_TURRCAPS_LINKED))
+        self.tur_head.angles    = self.idle_aim;
+
+    if (!self.health) self.health  = 150;
+    self.tur_health = self.health;
+
+    //Solid bbox for preformance reasons
+    self.solid              = SOLID_BBOX;
+    self.tur_head.solid     = SOLID_BBOX;
+
+    self.takedamage             = DAMAGE_AIM;
+    self.tur_head.takedamage    = DAMAGE_AIM;
+
+    self.movetype            = MOVETYPE_NOCLIP;
+    self.tur_head.movetype   = MOVETYPE_NOCLIP;
+
+    // Team colouring?track
+    if (self.team == COLOR_TEAM1) self.colormod = '1.4 0.8 0.8';
+    if (self.team == COLOR_TEAM2) self.colormod = '0.8 0.8 1.4';
+
+    // Attach stdprocs. override when and what needed
+    if (self.turrcaps_flags & TFL_TURRCAPS_SUPPORT)
+    {
+        self.turret_prethink        = turret_stdproc_true;
+        self.turret_score_target    = turret_stdproc_targetscore_support;
+        self.turret_aim             = turret_stdproc_aim_generic;
+        self.turret_track           = turret_stdproc_track;
+        self.turret_firecheckfunc   = turret_stdproc_firecheck;
+        self.turret_firefunc        = turret_stdproc_fire;
+        self.turret_postthink       = turret_stdproc_nothing;
+
+        self.turret_damagefunc          = turret_stdproc_damage;
+        self.event_damage               = turret_stdproc_damage;
+        self.tur_head.event_damage      = turret_stdproc_damage;
+
+        self.turret_diefunc             = turret_stdproc_die;
+        self.turret_spawnfunc           = turret_stdproc_respawn;
+
+    }
+    else
+    {
+
+        self.turret_prethink        = turret_stdproc_true;
+        self.turret_score_target    = turret_stdproc_targetscore_generic;
+
+        if (self.aim_flags & TFL_AIM_SIMPLE)
+            self.turret_aim             = turret_stdproc_aim_simple;
+        else
+            self.turret_aim             = turret_stdproc_aim_generic;
+
+        self.turret_track           = turret_stdproc_track;
+        self.turret_firecheckfunc   = turret_stdproc_firecheck;
+        self.turret_firefunc        = turret_stdproc_fire;
+        self.turret_postthink       = turret_stdproc_nothing;
+
+        self.turret_damagefunc          = turret_stdproc_damage;
+        self.event_damage               = turret_stdproc_damage;
+        self.tur_head.event_damage      = turret_stdproc_damage;
+
+        self.turret_diefunc             = turret_stdproc_die;
+        self.turret_spawnfunc           = turret_stdproc_respawn;
+        self.turret_addtarget           = turret_stdproc_false;
+    }
+
+    self.use = turret_stdproc_use;
+
+    // Initiate the main AI loop
+    self.think     = turret_think;
+    self.nextthink = time + self.ticrate;
+
+    self.tur_head.team = self.team;
+    self.view_ofs = '0 0 0';
+
+#ifdef TURRET_DEBUG
+    self.tur_dbg_start = self.nextthink;
+    while (vlen(self.tur_dbg_rvec) < 2)
+        self.tur_dbg_rvec  = randomvec() * 4;
+
+    self.tur_dbg_rvec_x = fabs(self.tur_dbg_rvec_x);
+    self.tur_dbg_rvec_y = fabs(self.tur_dbg_rvec_y);
+    self.tur_dbg_rvec_z = fabs(self.tur_dbg_rvec_z);
+#endif
+
+    // Its all good.
+    self.classname = "turret_main";
+
+    self.tur_active = 1;
+
+    return 1;
+}
+
+

Added: trunk/data/qcsrc/server/tturrets/system/turret_system_misc.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/system/turret_system_misc.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/system/turret_system_misc.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,123 @@
+//--// Some support routines //--//
+
+// Get real origin
+vector real_origin(entity ent)
+{
+    entity e;
+    vector v;
+
+    e = ent.tag_entity;
+    while(e)
+    {
+        // v = v + e.origin;
+        v = v + ((e.absmin + e.absmax) * 0.5);
+        e = e.tag_entity;
+    }
+    //v = v + ent.origin;
+    v = v + ((ent.absmin + ent.absmax) * 0.5);
+    return v;
+
+}
+
+// Plug this into wherever precashing is done.
+void g_turrets_common_precash()
+{
+    precache_model ("models/turrets/c512.md3");
+}
+
+/*
+* Paint a v_color colord circle on target onwho
+* that fades away over f_time
+*/
+void paint_target(entity onwho, float f_size, vector v_color, float f_time)
+{
+    entity e;
+
+    e = spawn();
+    setmodel(e, "models/turrets/c512.md3"); // precision set above
+    e.scale = (f_size/512);
+    setsize(e, '0 0 0', '0 0 0');
+    ///setattachment(e,onwho,"");
+    setorigin(e,onwho.origin + '0 0 1');
+    e.alpha = 0.15;
+    e.movetype = MOVETYPE_FLY;
+
+    e.velocity = (v_color * 32); // + '0 0 1' * 64;
+
+    e.colormod = v_color;
+    SUB_SetFade(e,time,f_time);
+}
+
+void paint_target2(entity onwho, float f_size, vector v_color, float f_time)
+{
+    entity e;
+
+    e = spawn();
+    setmodel(e, "models/turrets/c512.md3"); // precision set above
+    e.scale = (f_size/512);
+    setsize(e, '0 0 0', '0 0 0');
+
+    setorigin(e,onwho.origin + '0 0 1');
+    e.alpha = 0.15;
+    e.movetype = MOVETYPE_FLY;
+
+    e.velocity = (v_color * 32); // + '0 0 1' * 64;
+    e.avelocity_x = -128;
+
+    e.colormod = v_color;
+    SUB_SetFade(e,time,f_time);
+}
+
+void paint_target3(vector where, float f_size, vector v_color, float f_time)
+{
+    entity e;
+    e = spawn();
+    setmodel(e, "models/turrets/c512.md3"); // precision set above
+    e.scale = (f_size/512);
+    setsize(e, '0 0 0', '0 0 0');
+    setorigin(e,where+ '0 0 1');
+    e.movetype = MOVETYPE_NONE;
+    e.velocity = '0 0 0';
+    e.colormod = v_color;
+    SUB_SetFade(e,time,f_time);
+}
+
+/*
+* Return the angle between two enteties
+*/
+vector angleofs(entity from, entity to)
+{
+    vector v_res;
+
+    // makevectors(from.angles);
+    v_res = normalize(to.origin - from.origin);
+    v_res = vectoangles(v_res);
+    v_res = v_res - from.angles;
+
+    if (v_res_x < 0) v_res_x += 360;
+    if (v_res_x > 180) v_res_x -= 360;
+
+    if (v_res_y < 0) v_res_y += 360;
+    if (v_res_y > 180) v_res_y -= 360;
+
+    return v_res;
+}
+
+vector angleofs2(entity from, vector to)
+{
+    vector v_res;
+
+    // makevectors(from.angles);
+    v_res = normalize(to - from.origin);
+    v_res = vectoangles(v_res);
+    v_res = v_res - from.angles;
+
+    if (v_res_x < 0) v_res_x += 360;
+    if (v_res_x > 180) v_res_x -= 360;
+
+    if (v_res_y < 0) v_res_y += 360;
+    if (v_res_y > 180) v_res_y -= 360;
+
+    return v_res;
+}
+

Added: trunk/data/qcsrc/server/tturrets/system/turret_system_scoreprocs.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/system/turret_system_scoreprocs.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/system/turret_system_scoreprocs.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,163 @@
+/*
+.float target_select_flags; /// target selection flags
+float TFL_TARGETSELECT_NO            = 1;   /// Dont select a target on its own.
+float TFL_TARGETSELECT_LOS           = 2;   /// Need line of sight
+float TFL_TARGETSELECT_PLAYERS       = 4;   /// Players are valid targets
+float TFL_TARGETSELECT_MISSILES      = 8;   /// Missiles are valid targets
+float TFL_TARGETSELECT_TRIGGERTARGET = 16;  /// Responds to turret_trigger_target events
+float TFL_TARGETSELECT_ANGLELIMITS   = 32;  /// Angular limitations of turret head limits target selection
+float TFL_TARGETSELECT_RANGELIMTS    = 64;  /// Range limits apply in targetselection
+float TFL_TARGETSELECT_TEAMCHECK     = 128; /// Consider team own <-> targets team
+float TFL_TARGETSELECT_NOBUILTIN     = 256; /// Cant select targets on its own. needs to be triggerd or slaved.
+float TFL_TARGETSELECT_OWNTEAM       = 512;
+*/
+
+float turret_stdproc_targetscore_support(entity e_turret,entity e_target)
+{
+    float score;        // Total score
+    float s_score,d_score;
+
+    if (e_turret.enemy == e_target) s_score = 1;
+
+    d_score = min(e_turret.target_range_optimal,tvt_dist) / max(e_turret.target_range_optimal,tvt_dist);
+
+    score = (d_score * e_turret.target_select_rangebias) +
+            (s_score * e_turret.target_select_samebias);
+
+    return score;
+}
+
+/*
+* Generic bias aware score system.
+*/
+float turret_stdproc_targetscore_generic(entity e_turret,entity e_target)
+{
+    //vector v_tmp;
+    float d_dist;       // Defendmode Distance
+
+    float score;        // Total score
+    float d_score;      // Distance score
+    //float da_score;     // Distance from aimpoint score
+    float a_score;      // Angular score
+    float s_score;      // samescore (same target as last time)
+    float m_score;      // missile score
+    float p_score;      // player score
+
+    float ikr;          // ideal kill range
+
+    if(!e_target) return 0;
+
+    if (e_target == e_turret.enemy) s_score = 1;
+
+    if (e_turret.tur_defend)
+    {
+        d_dist = vlen(real_origin(e_target) - e_turret.tur_defend.origin);
+        ikr = vlen(e_turret.origin - e_turret.tur_defend.origin);
+        d_score = 1 - d_dist / e_turret.target_range;
+    }
+    else
+    {
+        // Make a normlized value base on the targets distance from our optimal killzone
+        ikr = e_turret.target_range_optimal;
+        d_score = min(ikr,tvt_dist) / max(ikr,tvt_dist);
+    }
+
+    /*
+    // Determine the maximum time it could take this turrent to aim at someting.
+    max_aim_delay = (max(e_turret.aim_maxrot,e_turret.aim_maxpitch) / e_turret.aim_speed * 2);
+
+    // Find out how long it would take to aim at this taget.
+    aim_delay = (thadf+0.01) / e_turret.aim_speed;
+
+    // Turn this info into a normalized value.
+    aim_delay = (min(max_aim_delay,aim_delay) / max_aim_delay);
+    a_score = 1 - aim_delay;
+    */
+
+    a_score = 1 - (tvt_thadf / max(e_turret.aim_maxrot,e_turret.aim_maxpitch));
+
+    if ((e_turret.target_select_missilebias > 0) && (e_target.flags & FL_PROJECTILE))
+        m_score = 1;
+
+    if ((e_turret.target_select_playerbias > 0) && (e_target.flags & FL_CLIENT))
+        p_score = 1;
+
+    d_score = max(d_score,0);
+    s_score = max(s_score,0);
+    a_score = max(a_score,0);
+    m_score = max(m_score,0);
+    p_score = max(p_score,0);
+
+    score = (d_score * e_turret.target_select_rangebias) +
+            (s_score * e_turret.target_select_samebias) +
+            (a_score * e_turret.target_select_anglebias) +
+            (m_score * e_turret.target_select_missilebias) +
+            (p_score * e_turret.target_select_playerbias);
+
+    if(e_turret.target_range_fire < vlen(e_turret.tur_shotorg_updated - real_origin(e_target)))
+        score *= 0.1;
+
+#ifdef TURRET_DEBUG
+    string sd,sv,sa,sm,sp,ss;
+    string sdt,svt,sat,smt,spt;
+
+    sd = ftos(d_score);
+    d_score *= e_turret.target_select_rangebias;
+    sdt = ftos(d_score);
+
+    //sv = ftos(v_score);
+    //v_score *= e_turret.target_select_samebias;
+    //svt = ftos(v_score);
+
+    sa = ftos(a_score);
+    a_score *= e_turret.target_select_anglebias;
+    sat = ftos(a_score);
+
+    sm = ftos(m_score);
+    m_score *= e_turret.target_select_missilebias;
+    smt = ftos(m_score);
+
+    sp = ftos(p_score);
+    p_score *= e_turret.target_select_playerbias;
+    spt = ftos(p_score);
+
+
+    ss = ftos(score);
+    bprint("^3Target scores^7 \[  ",e_turret.netname, "  \] ^3for^7 \[  ", e_target.netname,"  \]\n");
+    bprint("^5Range:\[  ",sd,  "  \]^2+bias:\[  ",sdt,"  \]\n");
+    //bprint("^5Volly:\[  ",sv,  "  \]^2+bias:\[  ",svt,"  \]\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;
+}
+
+float turret_stdproc_targetscore_close(entity e_turret,entity e_target)
+{
+    return 1 - (tvt_dist / e_turret.target_range);
+}
+
+float turret_stdproc_targetscore_far (entity e_turret,entity e_target)
+{
+    return  tvt_dist / e_turret.target_range;
+}
+
+float turret_stdproc_targetscore_optimal(entity e_turret,entity e_target)
+{
+    return  min(e_turret.target_range_optimal,tvt_dist) / max(e_turret.target_range_optimal,tvt_dist);
+}
+
+float turret_stdproc_score_angular(entity e_turret,entity e_target)
+{
+    return 1 - (tvt_thadf / e_turret.aim_maxrot);
+}
+
+float turret_stdproc_targetscore_defend(entity e_turret,entity e_target)
+{
+    return 0;
+    //min(e_target.origin,e_turret.tur_defend.origin) / max(e_target.origin,e_turret.tur_defend.origin);
+}

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_common.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_common.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_common.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,116 @@
+float turret_tag_setup(float linked)
+{
+    vector v;
+    float f;
+
+    // Laters dooz
+    if(linked)
+        return 0;
+
+    f = gettagindex(self,"tag_head");
+    v = gettaginfo(self,f);
+    v = v + self.origin;
+    setorigin(self.tur_head,v);
+
+    f = gettagindex(self.tur_head,"tag_fire");
+    v = gettaginfo(self.tur_head,f) + (self.tur_head.origin - self.origin);
+    v_y *= -1;
+    self.tur_shotorg = v;
+
+    f = gettagindex(self.tur_head,"tag_aim");
+    v = gettaginfo(self.tur_head,f) + (self.tur_head.origin - self.origin);
+    self.tur_aimorg  = v;
+
+    return 1;
+}
+
+float turret_tag_fire_update()
+{
+    vector v;
+    float f;
+
+    f = gettagindex(self.tur_head,"tag_fire");
+    v = gettaginfo(self.tur_head,f) + (self.tur_head.origin - self.origin);
+    v_y *= -1;
+    self.tur_shotorg = v;
+
+    f = gettagindex(self.tur_head,"tag_aim");
+    v = gettaginfo(self.tur_head,f) + (self.tur_head.origin - self.origin);
+    self.tur_aimorg  = v;
+
+    return 1;
+}
+
+void FireImoBeam (vector start,vector end,vector smin,vector smax,
+                  float bforce,float f_dmg,float f_velfactor, float deathtype)
+
+{
+	local vector hitloc, force, endpoint, dir;
+	local entity ent;
+
+	dir = normalize(end - start);
+	force = dir * bforce;
+
+	// go a little bit into the wall because we need to hit this wall later
+	end = end + dir;
+
+	// trace multiple times until we hit a wall, each obstacle will be made unsolid.
+	// note down which entities were hit so we can damage them later
+	while (1)
+	{
+        tracebox(start, smin, smax, end, FALSE, self);
+
+		// if it is world we can't hurt it so stop now
+		if (trace_ent == world || trace_fraction == 1)
+			break;
+
+		if (trace_ent.solid == SOLID_BSP)
+            break;
+
+		// make the entity non-solid so we can hit the next one
+		trace_ent.railgunhit = TRUE;
+		trace_ent.railgunhitloc = end;
+		trace_ent.railgunhitsolidbackup = trace_ent.solid;
+
+		// stop if this is a wall
+
+
+		// make the entity non-solid
+		trace_ent.solid = SOLID_NOT;
+	}
+
+	endpoint = trace_endpos;
+
+	// find all the entities the railgun hit and restore their solid state
+	ent = findfloat(world, railgunhit, TRUE);
+	while (ent)
+	{
+		// restore their solid type
+		ent.solid = ent.railgunhitsolidbackup;
+		ent = findfloat(ent, railgunhit, TRUE);
+	}
+
+	// find all the entities the railgun hit and hurt them
+	ent = findfloat(world, railgunhit, TRUE);
+	while (ent)
+	{
+		// get the details we need to call the damage function
+		hitloc = ent.railgunhitloc;
+		ent.railgunhitloc = '0 0 0';
+		ent.railgunhitsolidbackup = SOLID_NOT;
+		ent.railgunhit = FALSE;
+
+		// apply the damage
+		if (ent.takedamage)
+		{
+			Damage (ent, self, self, f_dmg, deathtype, hitloc, force);
+            ent.velocity = ent.velocity * f_velfactor;
+            //ent.alpha = 0.25 + random() * 0.75;
+		}
+
+		// advance to the next entity
+		ent = findfloat(ent, railgunhit, TRUE);
+	}
+	trace_endpos = endpoint;
+}
+

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_flac.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_flac.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_flac.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,108 @@
+void spawnfunc_turret_flac();
+void turret_flac_dinit();
+void turret_flac_attack();
+void turret_flac_projectile_explode();
+
+void turret_flac_attack()
+{
+    local entity proj;
+
+    turret_tag_fire_update();
+
+    sound (self, CHAN_BODY, "weapons/hagar_fire.wav", 1, ATTN_NORM);
+    proj = spawn ();
+    setorigin(proj, self.tur_shotorg_updated);
+    setmodel(proj, "models/turrets/pd_proj.md3");
+    setsize(proj, '0 0 0', '0 0 0');
+    proj.classname          = "turret_fire";
+    proj.owner              = self;
+    proj.bot_dodge          = TRUE;
+    proj.bot_dodgerating    = self.shot_dmg;
+    proj.solid              = SOLID_NOT;
+    proj.movetype           = MOVETYPE_FLYMISSILE;
+    proj.flags              = FL_PROJECTILE;
+    proj.effects            = EF_LOWPRECISION;
+    proj.takedamage         = DAMAGE_YES;
+    proj.health             = 10;
+    proj.velocity           = (self.tur_shotdir_updated + randomvec() * self.shot_spread) * self.shot_speed;
+    proj.angles             = vectoangles(proj.velocity);
+    proj.touch              = turret_flac_projectile_explode;
+    proj.think              = turret_flac_projectile_explode;
+    proj.nextthink          = time + (vlen(self.tur_aimpos - self.tur_shotorg_updated) / self.shot_speed) + (random() * self.shot_spread);
+
+    self.tur_head.frame = self.tur_head.frame + 1;
+    if(self.tur_head.frame >= 4) self.tur_head.frame = 0;
+
+}
+
+void turret_flac_projectile_explode()
+{
+    //vector org2;
+    float d;
+
+    float b;
+    //org2 = findbetterlocation (self.origin, 12);
+    te_explosion (self.origin);
+
+    b = crandom();
+    if (b<-0.7)
+        sound (self, CHAN_BODY, "weapons/hagexp1.wav", 1, ATTN_NORM);
+    else if (b<0.4)
+        sound (self, CHAN_BODY, "weapons/hagexp2.wav", 1, ATTN_NORM);
+    else if (b<1)
+        sound (self, CHAN_BODY, "weapons/hagexp3.wav", 1, ATTN_NORM);
+
+
+    self.event_damage = SUB_Null;
+
+    d = RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, world, self.owner.shot_force, DEATH_TURRET);
+
+#ifdef TURRET_DEBUG
+    self.owner.tur_dbg_dmg_t_h = self.owner.tur_dbg_dmg_t_h + d; //self.owner.shot_dmg;
+    self.owner.tur_dbg_dmg_t_f = self.owner.tur_dbg_dmg_t_f + self.owner.shot_dmg;
+#endif
+
+    remove (self);
+}
+
+
+void turret_flac_dinit()
+{
+    if (self.netname == "")      self.netname  = "FLAC Cannon";
+
+
+    self.turrcaps_flags = TFL_TURRCAPS_RADIUSDMG | TFL_TURRCAPS_FASTPROJ | TFL_TURRCAPS_MISSILEKILL;
+    self.ammo_flags     = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE;
+    self.aim_flags      = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE;
+
+
+
+    precache_model ("models/turrets/base.md3");
+    precache_model ("models/turrets/flac.md3");
+    precache_model("models/turrets/pd_proj.md3");
+
+    if (turret_stdproc_init("flac_std") == 0)
+    {
+        remove(self);
+        return;
+    }
+
+    setmodel(self,"models/turrets/base.md3");
+    setmodel(self.tur_head,"models/turrets/flac.md3");
+
+    if(!turret_tag_setup(0))
+        dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
+
+    // Our fire routine
+    self.turret_firefunc  = turret_flac_attack;
+
+}
+/*QUAKED turret_flac (0 .5 .8) ?
+*/
+
+void spawnfunc_turret_flac()
+{
+    self.think = turret_flac_dinit;
+    self.nextthink = time + 0.5;
+}
+

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_fusionreactor.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_fusionreactor.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_fusionreactor.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,82 @@
+void spawnfunc_turret_fusionreactor();
+void turret_fusionreactor_dinit();
+void turret_fusionreactor_fire();
+
+float turret_fusionreactor_firecheck()
+{
+    if (self.enemy == world) return 0;
+
+    if (!self.enemy.ammo_flags & TFL_AMMO_RECIVE) return 0;
+    if (!self.enemy.ammo_flags & TFL_AMMO_ENERGY) return 0;
+
+    if (self.ammo < self.shot_dmg) return 0;
+    if (self.enemy.ammo >= self.enemy.ammo_max) return 0;
+    if (self.tur_dist_enemy > self.target_range_fire) return 0;
+    if (self.tur_dist_enemy < self.target_range_min) return 0;
+
+    return 1;
+}
+
+
+void turret_fusionreactor_fire()
+{
+    self.enemy.ammo = min(self.enemy.ammo + self.shot_dmg,self.enemy.ammo_max);
+    //te_lightning1(world,self.origin,self.enemy.origin);
+}
+
+void turret_fusionreactor_postthink()
+{
+}
+
+
+void turret_fusionreactor_dinit()
+{
+    if (self.netname == "")      self.netname     = "Fusionreactor";
+
+    self.turrcaps_flags =TFL_TURRCAPS_SUPPORT | TFL_TURRCAPS_AMMOSOURCE;
+
+    self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE;
+
+    self.target_select_flags = TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_OWNTEAM | TFL_TARGETSELECT_RANGELIMTS;
+
+    self.firecheck_flags = TFL_FIRECHECK_OWM_AMMO | TFL_FIRECHECK_OTHER_AMMO | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_DEAD | TFL_FIRECHECK_WORLD;
+
+    self.shoot_flags = TFL_SHOOT_HITALLVALID;
+
+    self.aim_flags = TFL_AIM_NO;
+
+    self.track_flags = TFL_TRACK_NO;
+
+    precache_model ("models/turrets/reactor.md3");
+    precache_model ("models/turrets/base.md3");
+    if (turret_stdproc_init("fusreac_std") == 0)
+    {
+        remove(self);
+        return;
+    }
+
+    setmodel(self,"models/turrets/base.md3");
+    setmodel(self.tur_head,"models/turrets/reactor.md3");
+
+    //if(!turret_tag_setup(0))
+    //    dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
+
+    self.tur_head.scale = 0.75;
+    setorigin(self.tur_head,self.origin + '0 0 25');
+    self.tur_head.avelocity = '0 50 0';
+
+    self.turret_firecheckfunc = turret_fusionreactor_firecheck;
+    self.turret_firefunc = turret_fusionreactor_fire;
+
+    // re-color badge & handle recoil effect
+    self.turret_postthink = turret_fusionreactor_postthink;
+}
+
+/*QUAKED turret_fusionreactor (0 .5 .8) ?
+*/
+void spawnfunc_turret_fusionreactor()
+{
+    // return;
+    self.think = turret_fusionreactor_dinit;
+    self.nextthink = time + 0.5;
+}

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_hellion.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_hellion.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_hellion.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,219 @@
+.float      shot_speed_max;
+.float      shot_speed_gain;
+
+void spawnfunc_turret_hellion();
+void turret_hellion_dinit();
+void turret_hellion_attack();
+void turret_hellion_missile_explode();
+void turret_hellion_missile_think();
+void turret_hellion_missile_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
+
+void turret_hellion_postthink()
+{
+    if(cvar("g_turrets_reloadcvars"))
+    {
+        if(!self.shot_speed_max)  self.shot_speed_max  = cvar("g_turrets_unit_hellion_std_shot_speed_max");
+        if(!self.shot_speed_gain) self.shot_speed_gain = cvar("g_turrets_unit_hellion_std_shot_speed_gain");
+    }
+
+    if(self.tur_head.frame != 0)
+        self.tur_head.frame = self.tur_head.frame + 1;
+
+    if(self.tur_head.frame > 7)
+        self.tur_head.frame = 0;
+}
+
+void turret_hellion_attack()
+{
+    local entity missile;
+
+    sound (self, CHAN_BODY, "weapons/hagar_fire.wav", 1, ATTN_NORM);
+
+    missile = spawn ();
+    setorigin(missile, self.tur_shotorg_updated);
+    sound (missile, CHAN_BODY, "weapons/rocket_fly.wav", 0.4, ATTN_NORM);
+    setmodel (missile, "models/turrets/mlrs_rocket.md3"); // precision set below
+    setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
+
+    missile.classname          = "hellion_missile";
+    missile.owner              = self;
+    missile.bot_dodge          = TRUE;
+    missile.bot_dodgerating    = self.shot_dmg;
+    missile.takedamage         = DAMAGE_YES;
+    missile.damageforcescale   = 2;
+    missile.health             = 50;
+    missile.enemy              = self.enemy;
+    missile.think              = turret_hellion_missile_think;
+    missile.nextthink          = time + 0.2;
+    missile.solid              = SOLID_BBOX;
+    missile.movetype           = MOVETYPE_FLYMISSILE;
+    missile.effects            = EF_LOWPRECISION;
+    missile.velocity           = (self.tur_shotdir_updated + randomvec() * self.shot_spread) * self.shot_speed; // + ('0 0 1' * self.shot_speed * 0.15);
+    missile.angles             = vectoangles(missile.velocity);
+    missile.touch              = turret_hellion_missile_explode;
+    missile.flags              = FL_PROJECTILE;
+    missile.solid              = SOLID_BBOX;
+    missile.tur_health         = time + 9;
+    missile.tur_aimpos         = randomvec() * 128;
+    te_explosion (missile.origin);
+
+    // switch tubes
+    self.tur_shotorg_y = self.tur_shotorg_y * -1;
+
+    if(self.tur_head.frame == 0)
+        self.tur_head.frame = self.tur_head.frame + 1;
+
+}
+
+void turret_hellion_missile_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) turret_hellion_missile_explode();
+}
+
+void turret_hellion_missile_think()
+{
+    vector olddir,newdir;
+    vector pre_pos;
+    float itime;
+
+    self.nextthink          = time + 0.1;
+
+    // Enemy in range?
+    if (vlen(self.origin - self.enemy.origin) < self.owner.shot_radius * 0.25)
+        turret_hellion_missile_explode();
+
+    olddir = normalize(self.velocity);
+
+    if (self.tur_health < time) turret_hellion_missile_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;
+
+        // Accelerate
+        self.velocity = olddir * min(vlen(self.velocity) * self.owner.shot_speed_gain,self.owner.shot_speed_max);
+
+        // Turn model
+        self.angles = vectoangles(self.velocity);
+
+        //if ( (vlen(self.origin - self.owner.origin)) > (self.owner.shot_radius * 10) )
+        //    turret_hellion_missile_explode();
+
+        // return;
+    }
+
+    olddir = normalize(self.velocity);
+
+    if(self.enemy)
+    {
+        // Predict enemy position
+        itime = vlen(self.enemy.origin - self.origin) / vlen(self.velocity);
+        pre_pos = self.enemy.origin + self.enemy.velocity * itime;
+    } else {
+        pre_pos = self.origin + olddir * 1024;
+    }
+
+    pre_pos = (pre_pos + self.enemy.origin) * 0.5;
+
+    //pre_pos += randomvec() * 128; //self.tur_aimpos * (sin(32) * time) ;
+
+
+    // Find out the direction to that place
+    newdir = normalize(pre_pos - self.origin);
+
+    // Turn
+    newdir = normalize(olddir + newdir * 0.5);
+
+    // Accelerate
+    self.velocity = newdir * min(vlen(self.velocity) * self.owner.shot_speed_gain,self.owner.shot_speed_max);
+
+    // Turn model
+    self.angles = vectoangles(self.velocity);
+
+    if (time+itime < time+0.1)
+    {
+        self.think = turret_hellion_missile_explode;
+        self.nextthink = time + itime;
+    }
+}
+
+void turret_hellion_missile_explode()
+{
+    vector org2;
+    float d;
+
+    sound (self, CHAN_BODY, "weapons/rocket_impact.wav", 1, ATTN_NORM);
+    org2 = findbetterlocation (self.origin, 16);
+
+    // LordHavoc: TE_TEI_BIGEXPLOSION
+    WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
+    WriteByte (MSG_BROADCAST, 78);
+    WriteCoord (MSG_BROADCAST, org2_x);
+    WriteCoord (MSG_BROADCAST, org2_y);
+    WriteCoord (MSG_BROADCAST, org2_z);
+
+    self.event_damage = SUB_Null;
+    d = RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, world, self.owner.shot_force, DEATH_TURRET);
+
+#ifdef TURRET_DEBUG
+    self.owner.tur_dbg_dmg_t_h = self.owner.tur_dbg_dmg_t_h + d; //self.owner.shot_dmg;
+    self.owner.tur_dbg_dmg_t_f = self.owner.tur_dbg_dmg_t_f + self.owner.shot_dmg;
+#endif
+
+    // Target dead, get another is still targeting the same.
+    if ((self.enemy.deadflag != DEAD_NO) && (self.enemy == self.owner.enemy))
+        self.owner.enemy = world;
+
+    remove (self);
+}
+
+void turret_hellion_dinit()
+{
+    if (self.netname == "")      self.netname  = "Hellion Missile Turret";
+
+    if(!self.shot_speed_max)  self.shot_speed_max  = cvar("g_turrets_unit_hellion_std_shot_speed_max");
+    if(!self.shot_speed_gain) self.shot_speed_gain = cvar("g_turrets_unit_hellion_std_shot_speed_gain");
+
+    self.turrcaps_flags = TFL_TURRCAPS_RADIUSDMG | TFL_TURRCAPS_FASTPROJ | TFL_TURRCAPS_PLAYERKILL | TFL_TURRCAPS_MISSILEKILL;
+    self.aim_flags = TFL_AIM_SIMPLE;
+    self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TRIGGERTARGET | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK ;
+    self.firecheck_flags = TFL_FIRECHECK_WORLD | TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_TEAMCECK | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF | TFL_FIRECHECK_OWM_AMMO;
+    self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE;
+
+    precache_model ( "models/turrets/mlrs_rocket.md3");
+    precache_model ("models/turrets/hellion.md3");
+    precache_model ("models/turrets/base.md3");
+
+    if (turret_stdproc_init("hellion_std") == 0)
+    {
+        remove(self);
+        return;
+    }
+
+    setmodel(self,"models/turrets/base.md3");
+    setmodel(self.tur_head,"models/turrets/hellion.md3");
+
+    if(!turret_tag_setup(0))
+        dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
+
+    // Our fire routine
+    self.turret_firefunc  = turret_hellion_attack;
+
+    // Custom animations and sutch
+    self.turret_postthink = turret_hellion_postthink;
+}
+
+/*QUAKED turret_hellion (0 .5 .8) ?
+*/
+void spawnfunc_turret_hellion()
+{
+    self.think = turret_hellion_dinit;
+    self.nextthink = time + 0.5;
+}
+
+

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_hk.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_hk.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_hk.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,469 @@
+//#define TURRET_DEBUG_HK
+
+#ifdef TURRET_DEBUG_HK
+.float atime;
+#endif
+
+void spawnfunc_turret_hk();
+void turret_hk_dinit();
+void turret_hk_attack();
+void turret_hk_missile_explode();
+void turret_hk_missile_think();
+void turret_hk_missile_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
+float turret_hk_addtarget(entity e_target,entity e_sender);
+//void turret_hk_missile_touch();
+
+float hk_maxspeed;
+float hk_minspeed;
+float hk_accel;
+float hk_accel2;
+float hk_decel;
+
+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;
+}
+
+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 ((e_target.flags & FL_CLIENT) && (self.owner.target_select_playerbias < 0))
+        return 0;
+
+    if ((e_target.flags & FL_CLIENT) && (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_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+    if (attacker.team == self.team)
+        damage *= 0.5;
+
+    self.velocity += force;
+
+    self.health -= damage;
+
+    if (self.health <= 0)
+        turret_hk_missile_explode();
+}
+
+void turret_hk_attack()
+{
+    local entity missile;
+    //local entity flash2;
+
+    sound (self, CHAN_BODY, "weapons/rocket_fire.wav", 1, ATTN_NORM);
+
+    missile                    = spawn ();
+    missile.solid            = SOLID_BBOX;
+    setmodel (missile, "models/turrets/hunter2.md3"); // precision set below
+    setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
+    sound    (missile, CHAN_BODY, "weapons/rocket_fly.wav", 0.4, ATTN_NORM);
+    setorigin(missile, self.tur_shotorg_updated);
+
+    missile.scale            = 1;
+    missile.classname        = "hk_missile";
+    missile.owner            = self;
+    missile.bot_dodge        = TRUE;
+    missile.bot_dodgerating  = self.shot_dmg;
+    missile.takedamage       = DAMAGE_YES;
+    missile.damageforcescale = 2;
+    missile.health           = 35;
+    missile.think            = turret_hk_missile_think;
+    missile.event_damage     = turret_hk_missile_damage;
+    missile.nextthink        = time + 0.25;
+    missile.movetype         = MOVETYPE_BOUNCEMISSILE;
+    missile.effects          = EF_LOWPRECISION;
+    missile.velocity         = self.tur_shotdir_updated * (self.shot_speed * 0.75);
+    missile.angles           = vectoangles(missile.velocity);
+    missile.touch            = turret_hk_missile_explode; //turret_hk_missile_touch;
+    missile.flags            = FL_PROJECTILE;
+    missile.enemy            = self.enemy;
+    missile.team             = self.team;
+    missile.cnt              = time + 30;
+
+    te_explosion (missile.origin);
+
+    if(self.tur_head.frame == 0)
+        self.tur_head.frame = self.tur_head.frame + 1;
+
+}
+
+/*
+void turret_hk_missile_touch()
+{
+    if(other == self.enemy)
+        turret_hk_missile_explode();
+    else
+    {
+        if(self.cnt < time)
+        {
+            self.cnt = time + 0.25;
+            self.health = self.health - 5;
+            if(self.health <= 0)
+                turret_hk_missile_explode();
+
+        }
+    }
+}
+*/
+
+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;
+
+    // 25fps
+    self.nextthink = time + 0.04;
+
+    //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)
+    {
+        // 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;
+
+        // Close enougth to do decent damage?
+        if ( vlen(self.origin - self.enemy.origin) <= (self.owner.shot_radius * 0.25) )
+        {
+            turret_hk_missile_explode();
+            return;
+        }
+    }
+    else
+    {
+        fe = 0;
+    }
+
+    if ((fe != 1) || (self.enemy == world))
+    {
+        myspeed = vlen(self.velocity);
+
+        lt_for  = myspeed * 2;
+        lt_seek = myspeed * 1.5;
+
+        // 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);
+
+        //Calculate new speed
+
+        // To close to something, Slow down!
+        if ( ((ff < 0.7) || (ad > 5)) && (myspeed > hk_minspeed) )
+            myspeed = max(myspeed * hk_decel,hk_minspeed);
+
+        // Failry clear, accelerate.
+        if ( (ff > 0.7) && (myspeed < hk_maxspeed) )
+            myspeed = min(myspeed * hk_accel,hk_maxspeed);
+
+        // Setup trace pitch
+        pt_seek = 1 - ff;
+        pt_seek = bound(0.125,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 < hk_maxspeed)
+            myspeed = min(myspeed * hk_accel2,hk_maxspeed);
+
+        wishdir = ve;
+        //wishdir = normalize(self.enemy.origin - (self.enemy.origin + self.enemy.velocity));
+    }
+
+    if((myspeed > hk_minspeed) && (self.cnt > time))
+        myspeed = min(myspeed * hk_accel2,hk_maxspeed);
+
+    // Ranoutagazfish?
+    if(self.cnt < time)
+    {
+        self.cnt = time + 0.25;
+        self.nextthink = 0;
+        self.movetype         = MOVETYPE_BOUNCE;
+        sound    (self, CHAN_BODY, "", 0.4, ATTN_NORM);
+        return;
+    }
+
+    // Calculate new heading
+    olddir = normalize(self.velocity);
+
+    newdir = normalize(olddir + wishdir * cvar("g_turrets_unit_hk_std_shot_speed_turnrate"));
+
+    //fu = (1 / hk_maxspeed) * myspeed;
+    //fd = fu - (0.75 - 0.25);
+    //newdir = normalize(olddir + wishdir * fd);
+
+    // 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)
+    {
+        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
+}
+
+void turret_hk_missile_explode()
+{
+    vector org2;
+    float d;
+
+    if ((other == self.owner)||(other == self.owner.tur_head))
+        return;
+
+    //vector	org2;
+    sound (self, CHAN_BODY, "weapons/rocket_impact.wav", 1, ATTN_NORM);
+    org2 = findbetterlocation (self.origin, 16);
+
+    // LordHavoc: TE_TEI_BIGEXPLOSION
+    WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
+    WriteByte (MSG_BROADCAST, 78);
+    WriteCoord (MSG_BROADCAST, org2_x);
+    WriteCoord (MSG_BROADCAST, org2_y);
+    WriteCoord (MSG_BROADCAST, org2_z);
+
+    self.event_damage = SUB_Null;
+    d = RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, world, self.owner.shot_force, DEATH_TURRET);
+
+#ifdef TURRET_DEBUG
+    self.owner.tur_dbg_dmg_t_h = self.owner.tur_dbg_dmg_t_h + d; //self.owner.shot_dmg;
+    self.owner.tur_dbg_dmg_t_f = self.owner.tur_dbg_dmg_t_f + self.owner.shot_dmg;
+#endif
+
+    // Target dead, get another is still targeting the same.
+    if ((self.enemy.deadflag != DEAD_NO) && (self.enemy == self.owner.enemy))
+        self.owner.enemy = world;
+
+    remove (self);
+}
+
+void turret_hk_postthink()
+{
+    if(cvar("g_turrets_reloadcvars"))
+    {
+        hk_maxspeed = cvar("g_turrets_unit_hk_std_shot_speed_max");
+        hk_minspeed = cvar("g_turrets_unit_hk_std_shot_speed");
+        hk_accel    = cvar("g_turrets_unit_hk_std_shot_speed_accel");
+        hk_accel2   = cvar("g_turrets_unit_hk_std_shot_speed_accel2");
+        hk_decel    = cvar("g_turrets_unit_hk_std_shot_speed_decel");
+    }
+
+    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;
+
+}
+
+void turret_hk_dinit()
+{
+    if (self.netname == "")      self.netname  = "Hunter-killer turret";
+
+    hk_maxspeed = cvar("g_turrets_unit_hk_std_shot_speed_max");
+    hk_minspeed = cvar("g_turrets_unit_hk_std_shot_speed");
+    hk_accel    = cvar("g_turrets_unit_hk_std_shot_speed_accel");
+    hk_accel2   = cvar("g_turrets_unit_hk_std_shot_speed_accel2");
+    hk_decel    = cvar("g_turrets_unit_hk_std_shot_speed_decel");
+
+    self.turrcaps_flags = TFL_TURRCAPS_RADIUSDMG | TFL_TURRCAPS_MEDPROJ | TFL_TURRCAPS_PLAYERKILL | TFL_TURRCAPS_RECIVETARGETS;
+
+    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_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK;
+
+    self.firecheck_flags = TFL_FIRECHECK_WORLD | TFL_FIRECHECK_DEAD | TFL_FIRECHECK_TEAMCECK  | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_AFF;
+
+    self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TRIGGERTARGET | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK;
+
+    self.shoot_flags = TFL_SHOOT_CLEARTARGET;
+
+
+    precache_model ( "models/turrets/hunter2.md3");
+
+    precache_model ("models/turrets/base.md3");
+    precache_model ("models/turrets/hk.md3");
+
+    if (turret_stdproc_init("hk_std") == 0)
+    {
+        remove(self);
+        return;
+    }
+
+    self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TEAMCHECK;
+
+    setmodel(self,"models/turrets/base.md3");
+    setmodel(self.tur_head,"models/turrets/hk.md3");
+
+    if(!turret_tag_setup(0))
+        dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
+
+    // Our fire routine
+    self.turret_firefunc  = turret_hk_attack;
+
+    // re-color badge & handle recoil effect
+    self.turret_postthink = turret_hk_postthink;
+
+    // What to do when reciveing foreign target data
+    self.turret_addtarget = turret_hk_addtarget;
+}
+
+/*
+* Turret that fires Hunter-killer missiles.
+* Missiles seek their target and try to avoid obstacles. If target dies early, they
+* pick a new one on their own.
+*/
+
+/*QUAKED turret_hk (0 .5 .8) ?
+hunter-killer missiles.
+*/
+
+void spawnfunc_turret_hk()
+{
+    self.think = turret_hk_dinit;
+    self.nextthink = time + 0.5;
+}
+
+

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_machinegun.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_machinegun.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_machinegun.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,71 @@
+void spawnfunc_turret_machinegun();
+void turret_machinegun_std_init();
+void turret_machinegun_attack();
+
+//.float bulletcounter;
+void turret_machinegun_attack()
+{
+
+    entity flash;
+    sound (self, CHAN_BODY, "weapons/uzi_fire.wav", 1, ATTN_NORM);
+    fireBullet (self.tur_shotorg_updated, self.tur_shotdir_updated,self.shot_spread, self.shot_dmg, self.shot_force, DEATH_TURRET, FALSE);
+
+    te_smallflash(self.tur_shotorg_updated);
+    trailparticles(self,particleeffectnum("EF_MINIGUNTRAIL"),self.tur_shotorg_updated,trace_endpos);
+
+    // muzzle flash for 3rd person view
+    flash = spawn();
+    //setorigin(flash, '43 1 8');
+    setmodel(flash, "models/uziflash.md3"); // precision set below
+    setattachment(flash, self.tur_head, "tag_fire");
+    flash.think = W_Uzi_Flash_Go;
+    flash.nextthink = time + 0.02;
+    flash.frame = 2;
+    flash.angles_z = flash.v_angle_z + random() * 180;
+    flash.alpha = 1;
+    flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+}
+
+
+void turret_machinegun_std_init()
+{
+    if (self.netname == "")      self.netname     = "Machinegun Turret";
+
+    precache_model ("models/turrets/machinegun.md3");
+    precache_model ("models/turrets/base.md3");
+
+    self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE;
+    self.turrcaps_flags = TFL_TURRCAPS_HITSCAN | TFL_TURRCAPS_PLAYERKILL;
+    self.aim_flags = TFL_AIM_LEAD | TFL_AIM_ZEASE;
+
+    if (turret_stdproc_init("machinegun_std") == 0)
+    {
+        remove(self);
+        return;
+    }
+
+    setmodel(self,"models/turrets/base.md3");
+    setmodel(self.tur_head,"models/turrets/machinegun.md3");
+
+    if(!turret_tag_setup(0))
+        dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
+
+    // Our fire routine
+    self.turret_firefunc  = turret_machinegun_attack;
+
+}
+
+
+
+/*
+* machinegun turret. does what you'd expect
+*/
+
+/*QUAKED turret_machinegun (0 .5 .8) ?
+*/
+void spawnfunc_turret_machinegun()
+{
+    self.think = turret_machinegun_std_init;
+    self.nextthink = time + 0.5;
+}
+

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_mlrs.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_mlrs.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_mlrs.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,115 @@
+void spawnfunc_turret_mlrs();
+void turret_mlrs_dinit();
+void turret_mlrs_attack();
+void turret_mlrs_projectile_explode();
+
+void turret_mlrs_postthink()
+{
+
+    if((self.tur_head.frame >= 6) && (self.attack_finished <= time))
+        self.tur_head.frame = 0;
+}
+
+void turret_mlrs_attack()
+{
+    entity missile;
+
+    turret_tag_fire_update();
+
+    sound (self, CHAN_BODY, "weapons/rocket_fire.wav", 1, ATTN_NORM);
+
+    missile                    = spawn ();
+    setmodel (missile, "models/turrets/rocket.md3"); // precision set below
+    setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
+    sound (missile, CHAN_BODY, "weapons/rocket_fly.wav", 0.4, ATTN_NORM);
+    setorigin(missile, self.tur_shotorg_updated);
+    missile.classname          = "mlrs_missile";
+    missile.owner              = self;
+    missile.bot_dodge          = TRUE;
+    missile.bot_dodgerating    = self.shot_dmg;
+    missile.takedamage         = DAMAGE_YES;
+    missile.damageforcescale   = 4;
+    missile.health             = 30;
+    missile.think              = turret_mlrs_projectile_explode;
+    missile.nextthink          = time + max(self.tur_impacttime,(self.shot_radius * 2) / self.shot_speed);
+    missile.solid              = SOLID_BBOX;
+    missile.movetype           = MOVETYPE_FLYMISSILE;
+    missile.effects            = EF_LOWPRECISION;
+    missile.velocity           = (self.tur_shotdir_updated + randomvec() * self.shot_spread) * self.shot_speed;
+    missile.angles             = vectoangles(missile.velocity);
+    missile.touch              = turret_mlrs_projectile_explode;
+    missile.flags              = FL_PROJECTILE;
+    missile.solid              = SOLID_BBOX;
+    missile.enemy              = self.enemy;
+
+    te_explosion (missile.origin);
+
+    self.tur_head.frame = 7 - self.volly_counter;
+}
+
+void turret_mlrs_projectile_explode()
+{
+    vector org2;
+
+    //vector	org2;
+    sound (self, CHAN_BODY, "weapons/rocket_impact.wav", 1, ATTN_NORM);
+    org2 = findbetterlocation (self.origin, 16);
+    pointparticles(particleeffectnum("rocket_explode"), org2, '0 0 0', 1);
+
+    self.event_damage = SUB_Null;
+    RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, world, self.owner.shot_force, DEATH_TURRET);
+
+#ifdef TURRET_DEBUG
+    float d;
+    d = RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, world, self.owner.shot_force, DEATH_TURRET);
+    self.owner.tur_dbg_dmg_t_h = self.owner.tur_dbg_dmg_t_h + d; //self.owner.shot_dmg;
+    self.owner.tur_dbg_dmg_t_f = self.owner.tur_dbg_dmg_t_f + self.owner.shot_dmg;
+#endif
+
+    // Target dead, get another is still targeting the same.
+    if ((self.enemy.deadflag != DEAD_NO) && (self.enemy == self.owner.enemy))
+        self.owner.enemy = world;
+
+    remove (self);
+}
+
+void turret_mlrs_dinit()
+{
+    if (self.netname == "")      self.netname  = "MLRS turret";
+
+    self.turrcaps_flags = TFL_TURRCAPS_RADIUSDMG | TFL_TURRCAPS_MEDPROJ | TFL_TURRCAPS_PLAYERKILL;
+    self.ammo_flags = TFL_AMMO_ROCKETS | TFL_AMMO_RECHARGE;
+    self.aim_flags = TFL_AIM_LEAD | TFL_AIM_ZEASE | TFL_AIM_SHOTTIMECOMPENSATE;
+
+    precache_model ( "models/turrets/rocket.md3");
+    precache_model ("models/turrets/mlrs.md3");
+    precache_model ("models/turrets/base.md3");
+
+    if (turret_stdproc_init("mlrs_std") == 0)
+    {
+        remove(self);
+        return;
+    }
+
+    setmodel(self,"models/turrets/base.md3");
+    setmodel(self.tur_head,"models/turrets/mlrs.md3");
+
+    if(!turret_tag_setup(0))
+        dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
+
+    // Our fire routine
+    self.turret_firefunc  = turret_mlrs_attack;
+    self.turret_postthink = turret_mlrs_postthink;
+
+}
+
+/*QUAKED turret_mlrs (0 .5 .8) ?
+*/
+
+void spawnfunc_turret_mlrs()
+{
+    self.think = turret_mlrs_dinit;
+    self.nextthink = time + 0.5;
+}
+
+

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_phaser.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_phaser.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_phaser.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,149 @@
+void spawnfunc_turret_phaser();
+void turret_phaser_dinit();
+void turret_phaser_attack();
+
+.float fireflag;
+
+float turret_phaser_firecheck()
+{
+    if(self.fireflag != 0) return 0;
+    return turret_stdproc_firecheck();
+}
+
+void turret_phaser_postthink()
+{
+    if(self.tur_head.frame == 0)
+        return;
+
+    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;
+        }
+    }
+}
+
+void beam_think()
+{
+    if((time > self.cnt)||(self.owner.deadflag != DEAD_NO))
+    {
+        self.owner.attack_finished = time + self.owner.shot_refire;
+        self.owner.fireflag = 2;
+        self.owner.tur_head.frame = 10;
+        sound (self, CHAN_BODY, "", 1, ATTN_NORM);
+        remove(self);
+        return;
+    }
+
+    turret_do_updates(self.owner);
+
+    if(time - self.shot_spread > 0)
+    {
+            self.shot_spread = time + 2;
+            sound (self, CHAN_BODY, "turrets/phaser.ogg", 1, ATTN_NORM);
+    }
+
+
+    self.nextthink = time + self.ticrate;
+
+    self.owner.attack_finished = time + frametime;
+    entity oldself;
+    oldself = self;
+    self = self.owner;
+    FireImoBeam (   self.tur_shotorg_updated,
+                    self.tur_shotorg_updated + self.tur_shotdir_updated * self.target_range_fire,
+                    '-1 -1 -1' * self.shot_radius,
+                    '1 1 1' * self.shot_radius,
+                    self.shot_force,
+                    oldself.shot_dmg,
+                    0.75,
+                    DEATH_TURRET);
+    self = oldself;
+    self.scale = vlen(self.owner.tur_shotorg_updated - trace_endpos) / 256;
+
+}
+
+void turret_phaser_attack()
+{
+    entity beam;
+
+    beam = spawn();
+    beam.ticrate = 0.1; //cvar("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_fire / 256;
+	beam.movetype = MOVETYPE_NONE;
+    beam.enemy = self.enemy;
+	beam.bot_dodge = TRUE;
+	beam.bot_dodgerating = beam.shot_dmg;
+	sound (beam, CHAN_BODY, "turrets/phaser.ogg", 1, ATTN_NORM);
+    self.fireflag = 1;
+
+    beam.attack_finished = self.attack_finished;
+    self.attack_finished = time; // + cvar("sys_ticrate");
+
+    setattachment(beam,self.tur_head,"tag_fire");
+
+    PointSound (trace_endpos, "weapons/neximpact.wav", 1, ATTN_NORM);
+
+    if(self.tur_head.frame == 0)
+        self.tur_head.frame = 1;
+}
+
+void turret_phaser_dinit()
+{
+    if (self.netname == "")      self.netname  = "Phaser Cannon";
+
+    self.turrcaps_flags = TFL_TURRCAPS_SNIPER|TFL_TURRCAPS_HITSCAN|TFL_TURRCAPS_PLAYERKILL;
+    self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE;
+    self.aim_flags = TFL_AIM_ZEASE | TFL_AIM_LEAD;
+
+
+    precache_sound ("turrets/phaser.ogg");
+    precache_model ("models/turrets/phaser.md3");
+    precache_model ("models/turrets/phaser_beam.md3");
+    precache_model ("models/turrets/base.md3");
+
+    if (turret_stdproc_init("phaser_std") == 0)
+    {
+        remove(self);
+        return;
+    }
+
+    setmodel(self,"models/turrets/base.md3");
+    setmodel(self.tur_head,"models/turrets/phaser.md3");
+
+    if(!turret_tag_setup(0))
+        dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
+
+    self.turret_firecheckfunc = turret_phaser_firecheck;
+    self.turret_firefunc  = turret_phaser_attack;
+    self.turret_postthink = turret_phaser_postthink;
+
+}
+
+/*QUAKED turret_phaser(0 .5 .8) ?
+*/
+void spawnfunc_turret_phaser()
+{
+    self.think = turret_phaser_dinit;
+    self.nextthink = time + 0.5;
+}
+

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_plasma.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_plasma.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_plasma.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,180 @@
+void spawnfunc_turret_plasma();
+void spawnfunc_turret_plasma_dual();
+
+void turret_plasma_std_init();
+void turret_plasma_dual_init();
+
+void turret_plasma_attack();
+void turret_plasma_projectile_explode();
+
+void turret_plasma_postthink()
+{
+    if(self.tur_head.frame != 0)
+        self.tur_head.frame = self.tur_head.frame + 1;
+
+    if(self.classname == "turret_plasma_dual")
+    {
+        if(self.tur_head.frame >= 6)
+            self.tur_head.frame = 0;
+    } else {
+        if(self.tur_head.frame >= 5)
+            self.tur_head.frame = 0;
+    }
+}
+
+void turret_plasma_attack()
+{
+    entity proj;
+
+    turret_tag_fire_update();
+
+    sound (self, CHAN_BODY, "weapons/hagar_fire.wav", 1, ATTN_NORM);
+    proj                    = spawn ();
+    setorigin(proj, self.tur_shotorg_updated);
+    setsize(proj, '0 0 0', '0 0 0');
+    setmodel(proj, "models/elaser.mdl"); // precision set above
+    proj.classname       = "plasmabomb";
+    proj.owner           = self;
+    proj.bot_dodge       = TRUE;
+    proj.bot_dodgerating = self.shot_dmg;
+    proj.think           = turret_plasma_projectile_explode;
+    proj.nextthink       = time + 9;
+    proj.solid           = SOLID_BBOX;
+    proj.movetype        = MOVETYPE_FLYMISSILE;
+    proj.velocity        = (self.tur_shotdir_updated + randomvec() * self.shot_spread) * self.shot_speed;
+    proj.angles          = vectoangles(proj.velocity);
+    proj.touch           = turret_plasma_projectile_explode;
+    proj.flags           = FL_PROJECTILE;
+    proj.effects         = EF_LOWPRECISION |  EF_BRIGHTFIELD;
+    proj.enemy           = self.enemy;
+    proj.flags           = FL_PROJECTILE | FL_NOTARGET;
+
+    if(self.tur_head.frame == 0)
+        self.tur_head.frame = 1;
+
+    // trailparticles(proj,particleeffectnum("TR_REDPLASMA"),proj.origin,proj.origin + proj.velocity);
+
+    // Snapback the head
+    // self.tur_head.angles_x = self.tur_head.angles_x + min((self.shot_dmg * 0.05),self.aim_maxpitch);
+
+    //if(self.classname == "turret_plasma_dual")
+    //    self.tur_shotorg_y = self.tur_shotorg_y * -1;
+
+}
+
+void turret_plasma_projectile_explode()
+{
+    vector org2;
+
+    org2 = findbetterlocation (self.origin, 8);
+    WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
+    WriteByte (MSG_BROADCAST, 79);
+    WriteCoord (MSG_BROADCAST, org2_x);
+    WriteCoord (MSG_BROADCAST, org2_y);
+    WriteCoord (MSG_BROADCAST, org2_z);
+    WriteCoord (MSG_BROADCAST, 0);		// SeienAbunae: groan... Useless clutter
+    WriteCoord (MSG_BROADCAST, 0);
+    WriteCoord (MSG_BROADCAST, 0);
+    WriteByte (MSG_BROADCAST, 155);
+
+    self.event_damage = SUB_Null;
+
+
+#ifdef TURRET_DEBUG
+    float d;
+
+    d = RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, world, self.owner.shot_force, DEATH_TURRET);
+    self.owner.tur_dbg_dmg_t_h = self.owner.tur_dbg_dmg_t_h + d; //self.owner.shot_dmg;
+    self.owner.tur_dbg_dmg_t_f = self.owner.tur_dbg_dmg_t_f + self.owner.shot_dmg;
+#else
+    RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, world, self.owner.shot_force, DEATH_TURRET);
+#endif
+    sound (self, CHAN_BODY, "weapons/electro_impact.wav", 1, ATTN_NORM);
+
+    remove (self);
+}
+
+void turret_plasma_std_init()
+{
+    if (self.netname == "")      self.netname     = "Plasma Cannon";
+
+    precache_model ("models/turrets/plasma.md3");
+    precache_model ("models/turrets/base.md3");
+
+    self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE;
+    self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_ZEASE;
+
+    if (turret_stdproc_init("plasma_std") == 0)
+    {
+        remove(self);
+        return;
+    }
+
+    setmodel(self,"models/turrets/base.md3");
+    setmodel(self.tur_head,"models/turrets/plasma.md3");
+
+    if(!turret_tag_setup(0))
+        dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
+
+    // Our fire routine
+    self.turret_firefunc  = turret_plasma_attack;
+
+    // re-color badge & handle recoil effect
+    self.turret_postthink = turret_plasma_postthink;
+}
+
+
+void turret_plasma_dual_init()
+{
+    if (self.netname == "")      self.netname     = "Dual Plasma Cannon";
+
+    precache_model ("models/turrets/plasmad.md3");
+    precache_model ("models/turrets/base.md3");
+
+    self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE;
+
+    if (turret_stdproc_init("plasma_dual") == 0)
+    {
+        remove(self);
+        return;
+    }
+
+    setmodel(self,"models/turrets/base.md3");
+    setmodel(self.tur_head,"models/turrets/plasmad.md3");
+
+    if(!turret_tag_setup(0))
+        dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
+
+    // select aim
+    self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_ZEASE;
+
+    // Our fire routine
+    self.turret_firefunc  = turret_plasma_attack;
+
+    // re-color badge & handle recoil effect
+    self.turret_postthink = turret_plasma_postthink;
+}
+
+
+/*
+* Basic moderate (std) or fast (dual) fireing, short-mid range energy cannon.
+* Not too mutch of a therat on its own, but can be rather dangerous in groups.
+* Regenerates ammo slowly, support with a fusionreactor(s) to do some real damage.
+*/
+
+/*QUAKED turret_plasma (0 .5 .8) ?
+*/
+void spawnfunc_turret_plasma()
+{
+    self.think = turret_plasma_std_init;
+    self.nextthink = time + 0.5;
+}
+
+/*QUAKED turret_plasma_dual (0 .5 .8) ?
+*/
+void spawnfunc_turret_plasma_dual()
+{
+    self.think = turret_plasma_dual_init;
+    self.nextthink = time + 0.5;
+}
+

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_targettrigger.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_targettrigger.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_targettrigger.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,41 @@
+void spawnfunc_turret_targettrigger();
+void turret_targettrigger_touch();
+
+void turret_targettrigger_touch()
+{
+    entity e;
+    if(self.cnt > time) return;
+    entity oldself;
+    oldself = self;
+
+    e = find(world, targetname, self.target);
+    while (e)
+    {
+        if(e.turrcaps_flags & TFL_TURRCAPS_RECIVETARGETS)
+        {
+            self = e;
+            e.turret_addtarget(other,oldself);
+        }
+
+        e = find(e, targetname, oldself.target);
+    }
+
+    oldself.cnt = time + 0.5;
+
+    self = oldself;
+}
+
+/*QUAKED turret_targettrigger (.5 .5 .5) ?
+*/
+void spawnfunc_turret_targettrigger()
+{
+    if(!cvar("g_turrets"))
+    {
+        remove(self);
+        return;
+    }
+
+    InitTrigger ();
+
+    self.touch = turret_targettrigger_touch;
+}

Added: trunk/data/qcsrc/server/tturrets/units/turret_unit_tessla.qc
===================================================================
--- trunk/data/qcsrc/server/tturrets/units/turret_unit_tessla.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/tturrets/units/turret_unit_tessla.qc	2008-07-21 09:55:06 UTC (rev 3857)
@@ -0,0 +1,147 @@
+void spawnfunc_turret_tesla();
+void turret_tesla_dinit();
+void turret_tesla_fire();
+
+.float toasted;
+entity toast(entity from, float range, float damage)
+{
+    entity e;
+    entity etarget;
+    float d,dd;
+
+    dd = range + 1;
+
+    e = findradius(from.origin,range);
+    while (e)
+    {
+        if((e.toasted != 1) && (e != from))
+        if (turret_validate_target(self,e,self.target_validate_flags) > 0)
+        {
+
+            traceline(from.origin,e.origin,0,from);
+            if(trace_fraction > 0.9)
+            {
+                d = vlen(e.origin - from.origin);
+                if(d < dd)
+                {
+                    dd = d;
+                    etarget = e;
+                }
+            }
+        }
+        e = e.chain;
+    }
+
+    if(etarget)
+    {
+        te_smallflash(etarget.origin);
+        te_lightning1(world,from.origin,etarget.origin);
+        Damage(etarget,self,self,damage,DEATH_TURRET,etarget.origin,'0 0 0');
+        etarget.toasted = 1;
+    }
+
+    return etarget;
+}
+
+void turret_tesla_fire()
+{
+    entity e,t;
+    float d,r,i;
+
+    if(cvar("g_turrets_nofire") != 0)
+        return;
+
+    if(self.attack_finished > time) return;
+
+    d = self.shot_dmg;
+    r = self.target_range;
+    e = spawn();
+    setorigin(e,self.origin + self.tur_shotorg);
+
+
+    self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES |
+                                 TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK;
+
+    t = toast(e,r,d);
+    remove(e);
+
+    if(t == world) return;
+
+    self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES |
+                                 TFL_TARGETSELECT_TEAMCHECK;
+
+    self.attack_finished = time + self.shot_refire;
+    self.ammo = self.ammo - self.shot_dmg;
+    for(i = 0;i < 10;i++)
+    {
+        d *= 0.5; r *= 0.75;
+        t = toast(t,r,d);
+        if(t == world) break;
+    }
+
+    e = findchainfloat(toasted, 1);
+    while(e)
+    {
+        e.toasted = 0;
+        e = e.chain;
+    }
+}
+
+void turret_tesla_postthink()
+{
+    turret_tesla_fire();
+
+    self.tur_head.frame = self.tur_head.frame + 1;
+
+    if(self.tur_head.frame >= 11)
+        self.tur_head.frame = 0;
+
+    if(self.tur_head.avelocity == '0 0 0')
+        self.tur_head.avelocity = '0 35 0';
+}
+
+
+void turret_tesla_dinit()
+{
+    if (self.netname == "")      self.netname     = "Tesla Coil";
+
+    self.turrcaps_flags = TFL_TURRCAPS_HITSCAN | TFL_TURRCAPS_PLAYERKILL | TFL_TURRCAPS_MISSILEKILL;
+    self.target_select_flags = TFL_TARGETSELECT_NO;
+    self.firecheck_flags = TFL_FIRECHECK_REFIRE;
+    self.shoot_flags = TFL_SHOOT_CUSTOM;
+    self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE;
+    self.aim_flags = TFL_AIM_NO;
+    self.track_flags = TFL_TRACK_NO;
+
+    precache_model ("models/turrets/tesla_head.md3");
+    precache_model ("models/turrets/tesla_base.md3");
+
+    if (turret_stdproc_init("tesla_std") == 0)
+    {
+        remove(self);
+        return;
+    }
+
+    self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES |
+                                 TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK;
+
+
+    setmodel(self,"models/turrets/tesla_base.md3");
+    setmodel(self.tur_head,"models/turrets/tesla_head.md3");
+
+    if(!turret_tag_setup(0))
+        dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
+
+    self.turret_firefunc = turret_stdproc_nothing;
+    self.turret_postthink = turret_tesla_postthink;
+}
+
+/*QUAKED turret_tesla (0 .5 .8) ?
+*/
+void spawnfunc_turret_tesla()
+{
+    // return;
+    self.think = turret_tesla_dinit;
+    self.nextthink = time + 0.5;
+}
+




More information about the nexuiz-commits mailing list