From: TimePath <andrew.hardaker1995@gmail.com>
Date: Tue, 22 Sep 2015 11:36:18 +0000 (+1000)
Subject: Create a model list
X-Git-Tag: xonotic-v0.8.2~1922^2
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=a95e5467c6e1e20a886b19bd6464ec2b005ff53f;p=xonotic%2Fxonotic-data.pk3dir.git

Create a model list
---

diff --git a/qcsrc/client/_all.qh b/qcsrc/client/_all.qh
index e758fdb7a7..66fd813143 100644
--- a/qcsrc/client/_all.qh
+++ b/qcsrc/client/_all.qh
@@ -8,4 +8,6 @@
 
 #include "../dpdefs/csprogsdefs.qh"
 
+#include "../common/models/models.qh"
+
 #endif
diff --git a/qcsrc/client/command/cl_cmd.qc b/qcsrc/client/command/cl_cmd.qc
index 8b0a33e6c2..72fa244835 100644
--- a/qcsrc/client/command/cl_cmd.qc
+++ b/qcsrc/client/command/cl_cmd.qc
@@ -174,7 +174,7 @@ void LocalCommand_debugmodel(int request, int argc)
 
 			debugmodel_entity = spawn();
 			precache_model(modelname);
-			setmodel(debugmodel_entity, modelname);
+			_setmodel(debugmodel_entity, modelname);
 			setorigin(debugmodel_entity, view_origin);
 			debugmodel_entity.angles = view_angles;
 			debugmodel_entity.draw = DrawDebugModel;
diff --git a/qcsrc/client/controlpoint.qc b/qcsrc/client/controlpoint.qc
index 83ee0316bd..aec000d64c 100644
--- a/qcsrc/client/controlpoint.qc
+++ b/qcsrc/client/controlpoint.qc
@@ -26,11 +26,6 @@ void cpicon_precache()
 	if(cpicon_precached)
 		return; // already precached
 
-	precache_model("models/onslaught/controlpoint_icon_dmg3.md3");
-	precache_model("models/onslaught/controlpoint_icon_dmg2.md3");
-	precache_model("models/onslaught/controlpoint_icon_dmg1.md3");
-	precache_model("models/onslaught/controlpoint_icon.md3");
-
 	cpicon_precached = true;
 }
 
@@ -103,13 +98,13 @@ void cpicon_damage(float hp)
 	if(!self.iscaptured) { return; }
 
 	if(hp < self.max_health * 0.25)
-		setmodel(self, "models/onslaught/controlpoint_icon_dmg3.md3");
+		setmodel(self, MDL_ONS_CP3);
 	else if(hp < self.max_health * 0.50)
-		setmodel(self, "models/onslaught/controlpoint_icon_dmg2.md3");
+		setmodel(self, MDL_ONS_CP2);
 	else if(hp < self.max_health * 0.75)
-		setmodel(self, "models/onslaught/controlpoint_icon_dmg1.md3");
+		setmodel(self, MDL_ONS_CP1);
 	else if(hp <= self.max_health || hp >= self.max_health)
-		setmodel(self, "models/onslaught/controlpoint_icon.md3");
+		setmodel(self, MDL_ONS_CP);
 
 	self.punchangle = (2 * randomvec() - '1 1 1') * 45;
 
@@ -124,13 +119,13 @@ void cpicon_construct()
 {SELFPARAM();
 	self.netname = "Control Point Icon";
 
-	setmodel(self, "models/onslaught/controlpoint_icon.md3");
+	setmodel(self, MDL_ONS_CP);
 	setsize(self, CPICON_MIN, CPICON_MAX);
 
 	if(self.icon_realmodel == world)
 	{
 		self.icon_realmodel = spawn();
-		setmodel(self.icon_realmodel, "null");
+		setmodel(self.icon_realmodel, MDL_Null);
 		setorigin(self.icon_realmodel, self.origin);
 		setsize(self.icon_realmodel, CPICON_MIN, CPICON_MAX);
 		self.icon_realmodel.movetype = MOVETYPE_NOCLIP;
diff --git a/qcsrc/client/csqcmodel_hooks.qc b/qcsrc/client/csqcmodel_hooks.qc
index 70e2c99fea..022afd9d11 100644
--- a/qcsrc/client/csqcmodel_hooks.qc
+++ b/qcsrc/client/csqcmodel_hooks.qc
@@ -51,7 +51,7 @@ void CSQCPlayer_LOD_Apply(void)
 		if(fexists(s))
 		{
 			precache_model(s);
-			setmodel(self, s);
+			_setmodel(self, s);
 			if(self.modelindex)
 				self.lodmodelindex1 = self.modelindex;
 		}
@@ -60,12 +60,12 @@ void CSQCPlayer_LOD_Apply(void)
 		if(fexists(s))
 		{
 			precache_model(s);
-			setmodel(self, s);
+			_setmodel(self, s);
 			if(self.modelindex)
 				self.lodmodelindex2 = self.modelindex;
 		}
 
-		setmodel(self, modelname); // make everything normal again
+		_setmodel(self, modelname); // make everything normal again
 		setsize(self, mi, ma);
 	}
 
@@ -150,7 +150,7 @@ void CSQCPlayer_ModelAppearance_Apply(bool islocalplayer)
 		entity e;
 		e = spawn();
 		precache_model(cvar_defstring("_cl_playermodel"));
-		setmodel(e, cvar_defstring("_cl_playermodel"));
+		_setmodel(e, cvar_defstring("_cl_playermodel"));
 		forceplayermodels_goodmodel = e.model;
 		forceplayermodels_goodmodelindex = e.modelindex;
 		remove(e);
@@ -181,7 +181,7 @@ void CSQCPlayer_ModelAppearance_Apply(bool islocalplayer)
 		// only if this failed, find it out on our own
 		entity e;
 		e = spawn();
-		setmodel(e, autocvar__cl_playermodel); // this is harmless, see below
+		_setmodel(e, autocvar__cl_playermodel); // this is harmless, see below
 		forceplayermodels_modelisgoodmodel = fexists(e.model);
 		forceplayermodels_model = e.model;
 		forceplayermodels_modelindex = e.modelindex;
@@ -193,7 +193,7 @@ void CSQCPlayer_ModelAppearance_Apply(bool islocalplayer)
 	{
 		entity e;
 		e = spawn();
-		setmodel(e, autocvar_cl_forcemyplayermodel); // this is harmless, see below
+		_setmodel(e, autocvar_cl_forcemyplayermodel); // this is harmless, see below
 		forceplayermodels_myisgoodmodel = fexists(e.model);
 		forceplayermodels_mymodel = e.model;
 		forceplayermodels_mymodelindex = e.modelindex;
diff --git a/qcsrc/client/damage.qc b/qcsrc/client/damage.qc
index 21c1a79b6f..ec6da98428 100644
--- a/qcsrc/client/damage.qc
+++ b/qcsrc/client/damage.qc
@@ -113,7 +113,7 @@ void DamageEffect(vector hitorg, float thedamage, int type, int specnum)
 	}
 
 	e = spawn();
-	setmodel(e, "null"); // necessary to attach and read origin
+	setmodel(e, MDL_Null); // necessary to attach and read origin
 	setattachment(e, self, gettaginfo_name); // attach to the given bone
 	e.classname = "damage";
 	e.owner = self;
diff --git a/qcsrc/client/generator.qc b/qcsrc/client/generator.qc
index 710ed01f5b..c9358b6795 100644
--- a/qcsrc/client/generator.qc
+++ b/qcsrc/client/generator.qc
@@ -9,20 +9,6 @@ void generator_precache()
 	if(generator_precached)
 		return; // already precached
 
-	precache_model("models/onslaught/generator.md3");
-	precache_model("models/onslaught/generator_dead.md3");
-	precache_model("models/onslaught/generator_dmg1.md3");
-	precache_model("models/onslaught/generator_dmg2.md3");
-	precache_model("models/onslaught/generator_dmg3.md3");
-	precache_model("models/onslaught/generator_dmg4.md3");
-	precache_model("models/onslaught/generator_dmg5.md3");
-	precache_model("models/onslaught/generator_dmg6.md3");
-	precache_model("models/onslaught/generator_dmg7.md3");
-	precache_model("models/onslaught/generator_dmg8.md3");
-	precache_model("models/onslaught/generator_dmg9.md3");
-	precache_model("models/onslaught/generator_dead.md3");
-
-	precache_model("models/onslaught/ons_ray.md3");
 	precache_sound("onslaught/shockwave.wav");
 	precache_sound(W_Sound("grenade_impact"));
 	precache_sound(W_Sound("rocket_impact"));
@@ -58,7 +44,7 @@ void ons_generator_ray_spawn(vector org)
 	entity e;
 	e = spawn();
 	e.classname = "ons_ray";
-	setmodel(e, "models/onslaught/ons_ray.md3");
+	setmodel(e, MDL_ONS_RAY);
 	setorigin(e, org);
 	e.angles = randomvec() * 360;
 	e.move_origin = org;
@@ -146,27 +132,27 @@ void generator_draw()
 void generator_damage(float hp)
 {SELFPARAM();
 	if(hp <= 0)
-		setmodel(self, "models/onslaught/generator_dead.md3");
+		setmodel(self, MDL_ONS_GEN_DEAD);
 	else if(hp < self.max_health * 0.10)
-		setmodel(self, "models/onslaught/generator_dmg9.md3");
+		setmodel(self, MDL_ONS_GEN9);
 	else if(hp < self.max_health * 0.20)
-		setmodel(self, "models/onslaught/generator_dmg8.md3");
+		setmodel(self, MDL_ONS_GEN8);
 	else if(hp < self.max_health * 0.30)
-		setmodel(self, "models/onslaught/generator_dmg7.md3");
+		setmodel(self, MDL_ONS_GEN7);
 	else if(hp < self.max_health * 0.40)
-		setmodel(self, "models/onslaught/generator_dmg6.md3");
+		setmodel(self, MDL_ONS_GEN6);
 	else if(hp < self.max_health * 0.50)
-		setmodel(self, "models/onslaught/generator_dmg5.md3");
+		setmodel(self, MDL_ONS_GEN5);
 	else if(hp < self.max_health * 0.60)
-		setmodel(self, "models/onslaught/generator_dmg4.md3");
+		setmodel(self, MDL_ONS_GEN4);
 	else if(hp < self.max_health * 0.70)
-		setmodel(self, "models/onslaught/generator_dmg3.md3");
+		setmodel(self, MDL_ONS_GEN3);
 	else if(hp < self.max_health * 0.80)
-		setmodel(self, "models/onslaught/generator_dmg2.md3");
+		setmodel(self, MDL_ONS_GEN2);
 	else if(hp < self.max_health * 0.90)
-		setmodel(self, "models/onslaught/generator_dmg1.md3");
+		setmodel(self, MDL_ONS_GEN1);
 	else if(hp <= self.max_health || hp >= self.max_health)
-		setmodel(self, "models/onslaught/generator.md3");
+		setmodel(self, MDL_ONS_GEN);
 
 	setsize(self, GENERATOR_MIN, GENERATOR_MAX);
 }
@@ -177,7 +163,7 @@ void generator_construct()
 	self.classname = "onslaught_generator";
 
 	setorigin(self, self.origin);
-	setmodel(self, "models/onslaught/generator.md3");
+	setmodel(self, MDL_ONS_GEN);
 	setsize(self, GENERATOR_MIN, GENERATOR_MAX);
 
 	self.move_movetype	= MOVETYPE_NOCLIP;
diff --git a/qcsrc/client/gibs.qc b/qcsrc/client/gibs.qc
index 3c46ea9288..0302f18415 100644
--- a/qcsrc/client/gibs.qc
+++ b/qcsrc/client/gibs.qc
@@ -42,9 +42,9 @@ void Gib_setmodel(entity gib, string mdlname, int specnum)
 			if(specnum != SPECIES_ROBOT_SOLID || mdlname == "models/gibs/chunk.mdl")
 			{
 				if(mdlname == "models/gibs/bloodyskull.md3")
-					setmodel(gib, "models/gibs/robo.md3");
+					setmodel(gib, MDL_GIB_ROBO);
 				else
-					setmodel(gib, strcat("models/gibs/robo", ftos(floor(random() * 8) + 1), ".md3"));
+					setmodel(gib, MDL_GIB_ROBO_RANDOM());
 				if(specnum == SPECIES_ROBOT_SHINY)
 				{
 					gib.skin = 1;
@@ -54,7 +54,7 @@ void Gib_setmodel(entity gib, string mdlname, int specnum)
 				break;
 			}
 		default:
-			setmodel(gib, mdlname);
+			_setmodel(gib, mdlname);
 			gib.skin = specnum;
 			break;
 	}
@@ -275,25 +275,6 @@ void Ent_GibSplash(bool isNew)
 
 void GibSplash_Precache()
 {
-	precache_model("models/gibs/chunk.mdl");
-	precache_model("models/gibs/leg1.md3");
-	precache_model("models/gibs/leg2.md3");
-	precache_model("models/gibs/chest.md3");
-	precache_model("models/gibs/smallchest.md3");
-	precache_model("models/gibs/arm.md3");
-	precache_model("models/gibs/bloodyskull.md3");
-	precache_model("models/gibs/eye.md3");
-
-	precache_model("models/gibs/robo.md3");
-	precache_model("models/gibs/robo1.md3");
-	precache_model("models/gibs/robo2.md3");
-	precache_model("models/gibs/robo3.md3");
-	precache_model("models/gibs/robo4.md3");
-	precache_model("models/gibs/robo5.md3");
-	precache_model("models/gibs/robo6.md3");
-	precache_model("models/gibs/robo7.md3");
-	precache_model("models/gibs/robo8.md3");
-
 	precache_sound ("misc/gib.wav");
     precache_sound ("misc/gib_splat01.wav");
     precache_sound ("misc/gib_splat02.wav");
diff --git a/qcsrc/client/hook.qc b/qcsrc/client/hook.qc
index 781681cf73..528646979e 100644
--- a/qcsrc/client/hook.qc
+++ b/qcsrc/client/hook.qc
@@ -224,7 +224,7 @@ void Ent_ReadHook(float bIsNew, float type)
 			default:
 			case ENT_CLIENT_HOOK:
 				// for the model
-				setmodel(self, "models/hook.md3");
+				setmodel(self, MDL_HOOK);
 				self.drawmask = MASK_NORMAL;
 				break;
 			case ENT_CLIENT_ARC_BEAM:
@@ -239,7 +239,6 @@ void Ent_ReadHook(float bIsNew, float type)
 void Hook_Precache()
 {
 	precache_sound(W_Sound("lgbeam_fly"));
-	precache_model("models/hook.md3");
 }
 
 // TODO: hook: temporarily transform self.origin for drawing the model along warpzones!
diff --git a/qcsrc/client/main.qc b/qcsrc/client/main.qc
index 798b7c7dd9..c534cc7a5d 100644
--- a/qcsrc/client/main.qc
+++ b/qcsrc/client/main.qc
@@ -156,7 +156,6 @@ void CSQC_Init(void)
 	initialize_minigames();
 
 	// precaches
-	precache_model("null");
 	precache_sound("misc/hit.wav");
 	precache_sound("misc/typehit.wav");
 
diff --git a/qcsrc/client/weapons/projectile.qc b/qcsrc/client/weapons/projectile.qc
index 0d143cb1e3..1be6f8974b 100644
--- a/qcsrc/client/weapons/projectile.qc
+++ b/qcsrc/client/weapons/projectile.qc
@@ -280,55 +280,55 @@ void Ent_Projectile()
 
 		self.scale = 1;
 		self.traileffect = 0;
-		switch(self.cnt)
-		{
-			case PROJECTILE_ELECTRO: setmodel(self, "models/ebomb.mdl");self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
-			case PROJECTILE_ROCKET: setmodel(self, "models/rocket.md3");self.traileffect = particleeffectnum(EFFECT_TR_ROCKET); self.scale = 2; break;
-			case PROJECTILE_CRYLINK: setmodel(self, "models/plasmatrail.mdl");self.traileffect = particleeffectnum(EFFECT_TR_CRYLINKPLASMA); break;
-			case PROJECTILE_CRYLINK_BOUNCING: setmodel(self, "models/plasmatrail.mdl");self.traileffect = particleeffectnum(EFFECT_TR_CRYLINKPLASMA); break;
-			case PROJECTILE_ELECTRO_BEAM: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
-			case PROJECTILE_GRENADE: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum(EFFECT_TR_GRENADE); break;
-			case PROJECTILE_GRENADE_BOUNCING: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum(EFFECT_TR_GRENADE); break;
-			case PROJECTILE_MINE: setmodel(self, "models/mine.md3");self.traileffect = particleeffectnum(EFFECT_TR_GRENADE); break;
-			case PROJECTILE_BLASTER: setmodel(self, "models/laser.mdl");self.traileffect = particleeffectnum(EFFECT_Null); break;
-			case PROJECTILE_HLAC: setmodel(self, "models/hlac_bullet.md3");self.traileffect = particleeffectnum(EFFECT_Null); break;
-			case PROJECTILE_PORTO_RED: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum(EFFECT_TR_WIZSPIKE); self.scale = 4; break;
-			case PROJECTILE_PORTO_BLUE: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum(EFFECT_TR_WIZSPIKE); self.scale = 4; break;
-			case PROJECTILE_HOOKBOMB: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum(EFFECT_TR_KNIGHTSPIKE); break;
-			case PROJECTILE_HAGAR: setmodel(self, "models/hagarmissile.mdl");self.traileffect = particleeffectnum(EFFECT_HAGAR_ROCKET); self.scale = 0.75; break;
-			case PROJECTILE_HAGAR_BOUNCING: setmodel(self, "models/hagarmissile.mdl");self.traileffect = particleeffectnum(EFFECT_HAGAR_ROCKET); self.scale = 0.75; break;
-			case PROJECTILE_NAPALM_FOUNTAIN: //self.model = ""; self.modelindex = 0; self.traileffect = _particleeffectnum("torch_small"); break;
-			case PROJECTILE_FIREBALL: self.model = ""; self.modelindex = 0; self.traileffect = particleeffectnum(EFFECT_FIREBALL); break; // particle effect is good enough
-			case PROJECTILE_FIREMINE: self.model = ""; self.modelindex = 0; self.traileffect = particleeffectnum(EFFECT_FIREMINE); break; // particle effect is good enough
-			case PROJECTILE_TAG: setmodel(self, "models/laser.mdl"); self.traileffect = particleeffectnum(EFFECT_TR_ROCKET); break;
-			case PROJECTILE_FLAC: setmodel(self, "models/hagarmissile.mdl"); self.scale = 0.4; self.traileffect = particleeffectnum(EFFECT_FLAC_TRAIL); break;
-			case PROJECTILE_SEEKER: setmodel(self, "models/tagrocket.md3"); self.traileffect = particleeffectnum(EFFECT_SEEKER_TRAIL); break;
-
-			case PROJECTILE_MAGE_SPIKE: setmodel(self, "models/ebomb.mdl"); self.traileffect = particleeffectnum(EFFECT_TR_VORESPIKE); break;
-			case PROJECTILE_SHAMBLER_LIGHTNING: setmodel(self, "models/ebomb.mdl"); self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
-
-			case PROJECTILE_RAPTORBOMB:    setmodel(self, "models/vehicles/clusterbomb.md3"); self.gravity = 1; self.avelocity = '0 0 180'; self.traileffect = particleeffectnum(EFFECT_Null); break;
-			case PROJECTILE_RAPTORBOMBLET: setmodel(self, "models/vehicles/bomblet.md3");     self.gravity = 1; self.avelocity = '0 0 180'; self.traileffect = particleeffectnum(EFFECT_Null); break;
-			case PROJECTILE_RAPTORCANNON:  setmodel(self, "models/plasmatrail.mdl"); self.traileffect = particleeffectnum(EFFECT_TR_CRYLINKPLASMA); break;
-
-			case PROJECTILE_SPIDERROCKET: setmodel(self, "models/vehicles/rocket02.md3"); self.traileffect = particleeffectnum(EFFECT_SPIDERBOT_ROCKET_TRAIL); break;
-			case PROJECTILE_WAKIROCKET:   setmodel(self, "models/vehicles/rocket01.md3");  self.traileffect = particleeffectnum(EFFECT_RACER_ROCKET_TRAIL); break;
-			case PROJECTILE_WAKICANNON:   setmodel(self, "models/laser.mdl");  self.traileffect = particleeffectnum(EFFECT_Null); break;
-
-			case PROJECTILE_BUMBLE_GUN: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
-			case PROJECTILE_BUMBLE_BEAM: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
-
-			case PROJECTILE_RPC: setmodel(self, W_Model("ok_rocket"));self.traileffect = particleeffectnum(EFFECT_TR_ROCKET); break;
-
-			case PROJECTILE_ROCKETMINSTA_LASER: setmodel(self, "models/elaser.mdl");self.traileffect = _particleeffectnum(rm_suffix); break;
-
+		switch (self.cnt) {
+#define CASE(id) case PROJECTILE_##id: setmodel(self, MDL_PROJECTILE_##id);
+			CASE(ELECTRO)            self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
+			CASE(ROCKET)             self.traileffect = particleeffectnum(EFFECT_TR_ROCKET); self.scale = 2; break;
+			CASE(CRYLINK)            self.traileffect = particleeffectnum(EFFECT_TR_CRYLINKPLASMA); break;
+			CASE(CRYLINK_BOUNCING)   self.traileffect = particleeffectnum(EFFECT_TR_CRYLINKPLASMA); break;
+			CASE(ELECTRO_BEAM)       self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
+			CASE(GRENADE)            self.traileffect = particleeffectnum(EFFECT_TR_GRENADE); break;
+			CASE(GRENADE_BOUNCING)   self.traileffect = particleeffectnum(EFFECT_TR_GRENADE); break;
+			CASE(MINE)               self.traileffect = particleeffectnum(EFFECT_TR_GRENADE); break;
+			CASE(BLASTER)            self.traileffect = particleeffectnum(EFFECT_Null); break;
+			CASE(HLAC)               self.traileffect = particleeffectnum(EFFECT_Null); break;
+			CASE(PORTO_RED)          self.traileffect = particleeffectnum(EFFECT_TR_WIZSPIKE); self.scale = 4; break;
+			CASE(PORTO_BLUE)         self.traileffect = particleeffectnum(EFFECT_TR_WIZSPIKE); self.scale = 4; break;
+			CASE(HOOKBOMB)           self.traileffect = particleeffectnum(EFFECT_TR_KNIGHTSPIKE); break;
+			CASE(HAGAR)              self.traileffect = particleeffectnum(EFFECT_HAGAR_ROCKET); self.scale = 0.75; break;
+			CASE(HAGAR_BOUNCING)     self.traileffect = particleeffectnum(EFFECT_HAGAR_ROCKET); self.scale = 0.75; break;
+			CASE(NAPALM_FOUNTAIN)    // fallthrough // sself.modelindex = 0; self.traileffect = _particleeffectnum("torch_small"); break;
+			CASE(FIREBALL)           self.modelindex = 0; self.traileffect = particleeffectnum(EFFECT_FIREBALL); break; // particle effect is good enough
+			CASE(FIREMINE)           self.modelindex = 0; self.traileffect = particleeffectnum(EFFECT_FIREMINE); break; // particle effect is good enough
+			CASE(TAG)                self.traileffect = particleeffectnum(EFFECT_TR_ROCKET); break;
+			CASE(FLAC)               self.scale = 0.4; self.traileffect = particleeffectnum(EFFECT_FLAC_TRAIL); break;
+			CASE(SEEKER)             self.traileffect = particleeffectnum(EFFECT_SEEKER_TRAIL); break;
+
+			CASE(MAGE_SPIKE)         self.traileffect = particleeffectnum(EFFECT_TR_VORESPIKE); break;
+			CASE(SHAMBLER_LIGHTNING) self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
+
+			CASE(RAPTORBOMB)         self.gravity = 1; self.avelocity = '0 0 180'; self.traileffect = particleeffectnum(EFFECT_Null); break;
+			CASE(RAPTORBOMBLET)      self.gravity = 1; self.avelocity = '0 0 180'; self.traileffect = particleeffectnum(EFFECT_Null); break;
+			CASE(RAPTORCANNON)       self.traileffect = particleeffectnum(EFFECT_TR_CRYLINKPLASMA); break;
+
+			CASE(SPIDERROCKET)       self.traileffect = particleeffectnum(EFFECT_SPIDERBOT_ROCKET_TRAIL); break;
+			CASE(WAKIROCKET)         self.traileffect = particleeffectnum(EFFECT_RACER_ROCKET_TRAIL); break;
+			CASE(WAKICANNON)         self.traileffect = particleeffectnum(EFFECT_Null); break;
+
+			CASE(BUMBLE_GUN)         self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
+			CASE(BUMBLE_BEAM)        self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
+
+			CASE(RPC)                self.traileffect = particleeffectnum(EFFECT_TR_ROCKET); break;
+
+			CASE(ROCKETMINSTA_LASER) self.traileffect = _particleeffectnum(rm_suffix); break;
+#undef CASE
 			default:
 				if(MUTATOR_CALLHOOK(Ent_Projectile, self))
 					break;
 
 				if (Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
 				{
-					setmodel(self, W_Model("v_ok_grenade.md3"));
+					setmodel(self, MDL_PROJECTILE_NADE);
 					self.traileffect = _particleeffectnum(Nade_TrailEffect(self.cnt, self.team));
 					break;
 				}
@@ -508,22 +508,6 @@ void Ent_Projectile()
 
 void Projectile_Precache()
 {
-	precache_model("models/ebomb.mdl");
-	precache_model("models/elaser.mdl");
-	precache_model("models/grenademodel.md3");
-	precache_model("models/mine.md3");
-	precache_model("models/hagarmissile.mdl");
-	precache_model("models/hlac_bullet.md3");
-	precache_model("models/laser.mdl");
-	precache_model("models/plasmatrail.mdl");
-	precache_model("models/rocket.md3");
-	precache_model("models/tagrocket.md3");
-	precache_model("models/tracer.mdl");
-	precache_model("models/sphere/sphere.md3");
-
-	precache_model(W_Model("v_ok_grenade.md3"));
-	precache_model(W_Model("ok_rocket.md3"));
-
 	precache_sound(W_Sound("electro_fly"));
 	precache_sound(W_Sound("rocket_fly"));
 	precache_sound(W_Sound("fireball_fly"));
diff --git a/qcsrc/common/models/models.inc b/qcsrc/common/models/models.inc
new file mode 100644
index 0000000000..467352ee21
--- /dev/null
+++ b/qcsrc/common/models/models.inc
@@ -0,0 +1,360 @@
+// Global list of models
+// TODO: remove uses of _setmodel
+
+string W_Model(string w_mdl);
+
+MODEL(CTF_SHIELD,                       "models/ctf/shield.md3");
+MODEL(CTF_CAPTURE,                      "models/ctf/shockwavetransring.md3");
+
+MODEL(DOM_NEUTRAL,                      "models/domination/dom_unclaimed.md3");
+MODEL(DOM_RED,                          "models/domination/dom_red.md3");
+MODEL(DOM_BLUE,                         "models/domination/dom_blue.md3");
+MODEL(DOM_YELLOW,                       "models/domination/dom_yellow.md3");
+MODEL(DOM_PINK,                         "models/domination/dom_pink.md3");
+
+MODEL(ICE,                              "models/ice/ice.md3");
+
+MODEL(KH_KEY,                           "models/keyhunt/key.md3");
+#ifdef KH_PLAYER_USE_CARRIEDMODEL
+MODEL(KH_KEY_CARRIED,                   "models/keyhunt/key-carried.md3");
+#endif
+
+MODEL(OK_HMG,                           W_Model("g_ok_hmg.md3"));
+
+MODEL(OK_RPC,                           W_Model("g_ok_rl.md3"));
+
+MODEL(OK_MG_VIEW,                       W_Model("h_ok_mg.iqm"));
+MODEL(OK_MG_WORLD,                      W_Model("v_ok_mg.md3"));
+MODEL(OK_MG_ITEM,                       W_Model("g_ok_mg.md3"));
+
+MODEL(OK_SHOTGUN_VIEW,                  W_Model("h_ok_shotgun.iqm"));
+MODEL(OK_SHOTGUN_WORLD,                 W_Model("v_ok_shotgun.md3"));
+MODEL(OK_SHOTGUN_ITEM,                  W_Model("g_ok_shotgun.md3"));
+
+MODEL(OK_SNIPER_VIEW,                   W_Model("h_ok_sniper.iqm"));
+MODEL(OK_SNIPER_WORLD,                  W_Model("v_ok_sniper.md3"));
+MODEL(OK_SNIPER_ITEM,                   W_Model("g_ok_sniper.md3"));
+
+MODEL(ONS_CP,                           "models/onslaught/controlpoint_icon.md3");
+MODEL(ONS_CP_SHIELD,                    "models/onslaught/controlpoint_shield.md3");
+MODEL(ONS_CP_PAD1,                      "models/onslaught/controlpoint_pad.md3");
+MODEL(ONS_CP_PAD2,                      "models/onslaught/controlpoint_pad2.md3");
+MODEL(ONS_CP1,                          "models/onslaught/controlpoint_icon_dmg1.md3");
+MODEL(ONS_CP1_GIB,                      "models/onslaught/controlpoint_icon_gib1.md3");
+MODEL(ONS_CP2,                          "models/onslaught/controlpoint_icon_dmg2.md3");
+MODEL(ONS_CP2_GIB,                      "models/onslaught/controlpoint_icon_gib2.md3");
+MODEL(ONS_CP3,                          "models/onslaught/controlpoint_icon_dmg3.md3");
+MODEL(ONS_CP3_GIB,                      "models/onslaught/controlpoint_icon_gib4.md3");
+MODEL(ONS_RAY,                          "models/onslaught/ons_ray.md3");
+MODEL(ONS_GEN,                          "models/onslaught/generator.md3");
+MODEL(ONS_GEN_SHIELD,                   "models/onslaught/generator_shield.md3");
+MODEL(ONS_GEN_GIB1,                     "models/onslaught/gen_gib1.md3");
+MODEL(ONS_GEN_GIB2,                     "models/onslaught/gen_gib2.md3");
+MODEL(ONS_GEN_GIB3,                     "models/onslaught/gen_gib3.md3");
+MODEL(ONS_GEN1,                         "models/onslaught/generator_dmg1.md3");
+MODEL(ONS_GEN2,                         "models/onslaught/generator_dmg2.md3");
+MODEL(ONS_GEN3,                         "models/onslaught/generator_dmg3.md3");
+MODEL(ONS_GEN4,                         "models/onslaught/generator_dmg4.md3");
+MODEL(ONS_GEN5,                         "models/onslaught/generator_dmg5.md3");
+MODEL(ONS_GEN6,                         "models/onslaught/generator_dmg6.md3");
+MODEL(ONS_GEN7,                         "models/onslaught/generator_dmg7.md3");
+MODEL(ONS_GEN8,                         "models/onslaught/generator_dmg8.md3");
+MODEL(ONS_GEN9,                         "models/onslaught/generator_dmg9.md3");
+MODEL(ONS_GEN_DEAD,                     "models/onslaught/generator_dead.md3");
+
+MODEL(PROJECTILE_ELECTRO,               "models/ebomb.mdl");
+MODEL(PROJECTILE_ELECTRO_BEAM,          "models/elaser.mdl");
+
+MODEL(PROJECTILE_ROCKET,                "models/rocket.md3");
+
+MODEL(PROJECTILE_CRYLINK,               "models/plasmatrail.mdl");
+MODEL(PROJECTILE_CRYLINK_BOUNCING,      "models/plasmatrail.mdl");
+
+MODEL(PROJECTILE_GRENADE,               "models/grenademodel.md3");
+MODEL(PROJECTILE_GRENADE_BOUNCING,      "models/grenademodel.md3");
+
+MODEL(PROJECTILE_MINE,                  "models/mine.md3");
+
+MODEL(PROJECTILE_BLASTER,               "models/laser.mdl");
+
+MODEL(PROJECTILE_HLAC,                  "models/hlac_bullet.md3");
+
+MODEL(PROJECTILE_PORTO_RED,             "models/grenademodel.md3");
+MODEL(PROJECTILE_PORTO_BLUE,            "models/grenademodel.md3");
+
+MODEL(PROJECTILE_HOOKBOMB,              "models/grenademodel.md3");
+
+MODEL(PROJECTILE_HAGAR,                 "models/hagarmissile.mdl");
+MODEL(PROJECTILE_HAGAR_BOUNCING,        "models/hagarmissile.mdl");
+
+// napalm grenade
+MODEL(PROJECTILE_NAPALM_FOUNTAIN,       "null");
+// fireball primary
+MODEL(PROJECTILE_FIREBALL,              "null");
+// fireball secondary
+MODEL(PROJECTILE_FIREMINE,              "null");
+
+MODEL(PROJECTILE_TAG,                   "models/laser.mdl");
+
+MODEL(PROJECTILE_FLAC,                  "models/hagarmissile.mdl");
+
+MODEL(PROJECTILE_SEEKER,                "models/tagrocket.md3");
+
+MODEL(PROJECTILE_MAGE_SPIKE,            "models/ebomb.mdl");
+MODEL(PROJECTILE_SHAMBLER_LIGHTNING,    "models/ebomb.mdl");
+
+MODEL(PROJECTILE_RAPTORBOMB,            "models/vehicles/clusterbomb.md3");
+MODEL(PROJECTILE_RAPTORBOMBLET,         "models/vehicles/bomblet.md3");
+MODEL(PROJECTILE_RAPTORCANNON,          "models/plasmatrail.mdl");
+
+MODEL(PROJECTILE_SPIDERROCKET,          "models/vehicles/rocket02.md3");
+
+MODEL(PROJECTILE_WAKIROCKET,            "models/vehicles/rocket01.md3");
+MODEL(PROJECTILE_WAKICANNON,            "models/laser.mdl");
+
+MODEL(PROJECTILE_BUMBLE_GUN,            "models/elaser.mdl");
+MODEL(PROJECTILE_BUMBLE_BEAM,           "models/elaser.mdl");
+
+MODEL(PROJECTILE_RPC,                   W_Model("ok_rocket.md3"));
+
+MODEL(PROJECTILE_ROCKETMINSTA_LASER,    "models/elaser.mdl");
+
+MODEL(PROJECTILE_NADE,                  W_Model("v_ok_grenade.md3"));
+MODEL(NADE_VIEW,                        W_Model("h_ok_grenade.iqm"));
+MODEL(NADE_TIMER,                       "models/ok_nade_counter/ok_nade_counter.md3");
+MODEL(NADE_HEAL,                        "models/ctf/shield.md3");
+
+MODEL(GIB_CHUNK,                        "models/gibs/chunk.mdl");
+MODEL(GIB_LEG1,                         "models/gibs/leg1.md3");
+MODEL(GIB_LEG2,                         "models/gibs/leg2.md3");
+MODEL(GIB_CHEST,                        "models/gibs/chest.md3");
+MODEL(GIB_SMALLCHEST,                   "models/gibs/smallchest.md3");
+MODEL(GIB_ARM,                          "models/gibs/arm.md3");
+MODEL(GIB_BLOODYSKULL,                  "models/gibs/bloodyskull.md3");
+MODEL(GIB_EYE,                          "models/gibs/eye.md3");
+
+MODEL(GIB_ROBO,                         "models/gibs/robo.md3");
+MODEL(GIB_ROBO_1,                       "models/gibs/robo1.md3");
+MODEL(GIB_ROBO_2,                       "models/gibs/robo2.md3");
+MODEL(GIB_ROBO_3,                       "models/gibs/robo3.md3");
+MODEL(GIB_ROBO_4,                       "models/gibs/robo4.md3");
+MODEL(GIB_ROBO_5,                       "models/gibs/robo5.md3");
+MODEL(GIB_ROBO_6,                       "models/gibs/robo6.md3");
+MODEL(GIB_ROBO_7,                       "models/gibs/robo7.md3");
+MODEL(GIB_ROBO_8,                       "models/gibs/robo8.md3");
+Model MDL_GIB_ROBO_RANDOM() {
+    int i = floor(random() * 8);
+    return MODELS[MDL_GIB_ROBO_1.m_id + i];
+}
+
+MODEL(CASING_SHELL,                     "models/casing_shell.mdl");
+MODEL(CASING_BULLET,                    "models/casing_bronze.iqm");
+
+MODEL(BUFF,                             "models/relics/relic.md3");
+
+MODEL(BLASTER_VIEW,                     W_Model("h_laser.iqm"));
+MODEL(BLASTER_WORLD,                    W_Model("v_laser.md3"));
+MODEL(BLASTER_ITEM,                     W_Model("g_laser.md3"));
+
+MODEL(SHOTGUN_MUZZLEFLASH,              "models/uziflash.md3");
+MODEL(SHOTGUN_VIEW,                     W_Model("h_shotgun.iqm"));
+MODEL(SHOTGUN_WORLD,                    W_Model("v_shotgun.md3"));
+MODEL(SHOTGUN_ITEM,                     W_Model("g_shotgun.md3"));
+
+MODEL(MACHINEGUN_MUZZLEFLASH,           "models/uziflash.md3");
+MODEL(MACHINEGUN_VIEW,                  W_Model("h_uzi.iqm"));
+MODEL(MACHINEGUN_WORLD,                 W_Model("v_uzi.md3"));
+MODEL(MACHINEGUN_ITEM,                  W_Model("g_uzi.md3"));
+
+MODEL(MORTAR_VIEW,                      W_Model("h_gl.iqm"));
+MODEL(MORTAR_WORLD,                     W_Model("v_gl.md3"));
+MODEL(MORTAR_ITEM,                      W_Model("g_gl.md3"));
+
+MODEL(MINELAYER_MUZZLEFLASH,            "models/flash.md3");
+MODEL(MINELAYER_MINE,                   "models/mine.md3");
+MODEL(MINELAYER_VIEW,                   W_Model("h_minelayer.iqm"));
+MODEL(MINELAYER_WORLD,                  W_Model("v_minelayer.md3"));
+MODEL(MINELAYER_ITEM,                   W_Model("g_minelayer.md3"));
+
+MODEL(ELECTRO_VIEW,                     W_Model("h_electro.iqm"));
+MODEL(ELECTRO_WORLD,                    W_Model("v_electro.md3"));
+MODEL(ELECTRO_ITEM,                     W_Model("g_electro.md3"));
+
+MODEL(CRYLINK_VIEW,                     W_Model("h_crylink.iqm"));
+MODEL(CRYLINK_WORLD,                    W_Model("v_crylink.md3"));
+MODEL(CRYLINK_ITEM,                     W_Model("g_crylink.md3"));
+
+MODEL(VORTEX_MUZZLEFLASH,               "models/nexflash.md3");
+MODEL(VORTEX_VIEW,                      W_Model("h_nex.iqm"));
+MODEL(VORTEX_WORLD,                     W_Model("v_nex.md3"));
+MODEL(VORTEX_ITEM,                      W_Model("g_nex.md3"));
+
+MODEL(HAGAR_VIEW,                       W_Model("h_hagar.iqm"));
+MODEL(HAGAR_WORLD,                      W_Model("v_hagar.md3"));
+MODEL(HAGAR_ITEM,                       W_Model("g_hagar.md3"));
+
+MODEL(DEVASTATOR_MUZZLEFLASH,           "models/flash.md3");
+MODEL(DEVASTATOR_VIEW,                  W_Model("h_rl.iqm"));
+MODEL(DEVASTATOR_WORLD,                 W_Model("v_rl.md3"));
+MODEL(DEVASTATOR_ITEM,                  W_Model("g_rl.md3"));
+
+MODEL(PORTAL,                           "models/portal.md3");
+MODEL(PORTO_VIEW,                       W_Model("h_porto.iqm"));
+MODEL(PORTO_WORLD,                      W_Model("v_porto.md3"));
+MODEL(PORTO_ITEM,                       W_Model("g_porto.md3"));
+
+MODEL(VAPORIZER_MUZZLEFLASH,            "models/nexflash.md3");
+MODEL(VAPORIZER_VIEW,                   W_Model("h_minstanex.iqm"));
+MODEL(VAPORIZER_WORLD,                  W_Model("v_minstanex.md3"));
+MODEL(VAPORIZER_ITEM,                   W_Model("g_minstanex.md3"));
+
+MODEL(HOOK,                             "models/hook.md3");
+MODEL(HOOK_VIEW,                        W_Model("h_hookgun.iqm"));
+MODEL(HOOK_WORLD,                       W_Model("v_hookgun.md3"));
+MODEL(HOOK_ITEM,                        W_Model("g_hookgun.md3"));
+
+MODEL(HLAC_VIEW,                        W_Model("h_hlac.iqm"));
+MODEL(HLAC_WORLD,                       W_Model("v_hlac.md3"));
+MODEL(HLAC_ITEM,                        W_Model("g_hlac.md3"));
+
+MODEL(TUBA_VIEW,                        W_Model("h_tuba.iqm"));
+MODEL(TUBA_WORLD,                       W_Model("v_tuba.md3"));
+MODEL(TUBA_ITEM,                        W_Model("g_tuba.md3"));
+MODEL(ACCORDION_VIEW,                   W_Model("h_akordeon.iqm"));
+MODEL(ACCORDION_WORLD,                  W_Model("v_akordeon.md3"));
+MODEL(KLEINBOTTLE_VIEW,                 W_Model("h_kleinbottle.iqm"));
+MODEL(KLEINBOTTLE_WORLD,                W_Model("v_kleinbottle.md3"));
+
+MODEL(RIFLE_VIEW,                       W_Model("h_campingrifle.iqm"));
+MODEL(RIFLE_WORLD,                      W_Model("v_campingrifle.md3"));
+MODEL(RIFLE_ITEM,                       W_Model("g_campingrifle.md3"));
+
+MODEL(FIREBALL_SPHERE,                  "models/sphere/sphere.md3");
+MODEL(FIREBALL_VIEW,                    W_Model("h_fireball.iqm"));
+MODEL(FIREBALL_WORLD,                   W_Model("v_fireball.md3"));
+MODEL(FIREBALL_ITEM,                    W_Model("g_fireball.md3"));
+
+MODEL(SEEKER_VIEW,                      W_Model("h_seeker.iqm"));
+MODEL(SEEKER_WORLD,                     W_Model("v_seeker.md3"));
+MODEL(SEEKER_ITEM,                      W_Model("g_seeker.md3"));
+
+MODEL(SHOCKWAVE_MUZZLEFLASH,            "models/uziflash.md3");
+MODEL(SHOCKWAVE_VIEW,                   W_Model("h_shotgun.iqm"));
+MODEL(SHOCKWAVE_WORLD,                  W_Model("v_shotgun.md3"));
+MODEL(SHOCKWAVE_ITEM,                   W_Model("g_shotgun.md3"));
+
+MODEL(ARC_MUZZLEFLASH,                  "models/flash.md3");
+MODEL(ARC_VIEW,                         W_Model("h_arc.iqm"));
+MODEL(ARC_WORLD,                        W_Model("v_arc.md3"));
+MODEL(ARC_ITEM,                         W_Model("g_arc.md3"));
+
+MODEL(HMG_MUZZLEFLASH,                  "models/uziflash.md3");
+MODEL(HMG_VIEW,                         W_Model("h_ok_hmg.iqm"));
+MODEL(HMG_WORLD,                        W_Model("v_ok_hmg.md3"));
+MODEL(HMG_ITEM,                         W_Model("g_ok_hmg.md3"));
+
+MODEL(RPC_MUZZLEFLASH,                  "models/flash.md3");
+MODEL(RPC_VIEW,                         W_Model("h_ok_rl.iqm"));
+MODEL(RPC_WORLD,                        W_Model("v_ok_rl.md3"));
+MODEL(RPC_ITEM,                         W_Model("g_ok_rl.md3"));
+
+MODEL(TUR_GIB_BASE1,                    "models/turrets/base-gib1.md3");
+MODEL(TUR_GIB_BASE2,                    "models/turrets/base-gib2.md3");
+MODEL(TUR_GIB_BASE3,                    "models/turrets/base-gib3.md3");
+MODEL(TUR_GIB_BASE4,                    "models/turrets/base-gib4.md3");
+MODEL(TUR_GIB_HEAD1,                    "models/turrets/head-gib1.md3");
+MODEL(TUR_GIB_HEAD2,                    "models/turrets/head-gib2.md3");
+MODEL(TUR_GIB_HEAD3,                    "models/turrets/head-gib3.md3");
+MODEL(TUR_GIB_HEAD4,                    "models/turrets/head-gib4.md3");
+MODEL(TUR_BASE,                         "models/turrets/base.md3");
+
+MODEL(TUR_EWHEEL_BASE,                  "models/turrets/ewheel-base2.md3");
+MODEL(TUR_EWHEEL_HEAD,                  "models/turrets/ewheel-gun1.md3");
+
+MODEL(TUR_FLAC_BASE,                    "models/turrets/base.md3");
+MODEL(TUR_FLAC_HEAD,                    "models/turrets/flac.md3");
+
+MODEL(TUR_FUSIONREACTOR_BASE,           "models/turrets/base.md3");
+MODEL(TUR_FUSIONREACTOR_HEAD,           "models/turrets/reactor.md3");
+
+MODEL(TUR_HELLION_BASE,                 "models/turrets/base.md3");
+MODEL(TUR_HELLION_HEAD,                 "models/turrets/hellion.md3");
+
+MODEL(TUR_HK_BASE,                      "models/turrets/base.md3");
+MODEL(TUR_HK_HEAD,                      "models/turrets/hk.md3");
+
+MODEL(TUR_MACHINEGUN_BASE,              "models/turrets/base.md3");
+MODEL(TUR_MACHINEGUN_HEAD,              "models/turrets/machinegun.md3");
+
+MODEL(TUR_MIRS_BASE,                    "models/turrets/base.md3");
+MODEL(TUR_MIRS_HEAD,                    "models/turrets/mlrs.md3");
+
+MODEL(TUR_PHASER_BASE,                  "models/turrets/base.md3");
+MODEL(TUR_PHASER_BEAM,                  "models/turrets/phaser_beam.md3");
+MODEL(TUR_PHASER_HEAD,                  "models/turrets/phaser.md3");
+
+MODEL(TUR_PLASMA_BASE,                  "models/turrets/base.md3");
+MODEL(TUR_PLASMA_HEAD,                  "models/turrets/plasma.md3");
+
+MODEL(TUR_PLASMA_DUAL_BASE,             "models/turrets/base.md3");
+MODEL(TUR_PLASMA_DUAL_HEAD,             "models/turrets/plasmad.md3");
+
+MODEL(TUR_TESLA_BASE,                   "models/turrets/tesla_base.md3");
+MODEL(TUR_TESLA_HEAD,                   "models/turrets/tesla_head.md3");
+
+MODEL(TUR_WALKER_BASE,                  "models/turrets/walker_body.md3");
+MODEL(TUR_WALKER_HEAD,                  "models/turrets/walker_head_minigun.md3");
+
+MODEL(VEH_SHIELD,                       "models/vhshield.md3");
+
+MODEL(VEH_BUMBLEBEE_BODY,               "models/vehicles/bumblebee_body.dpm");
+MODEL(VEH_BUMBLEBEE_CANNON_CENTER,      "models/vehicles/bumblebee_ray.dpm");
+MODEL(VEH_BUMBLEBEE_CANNON_LEFT,        "models/vehicles/bumblebee_plasma_left.dpm");
+MODEL(VEH_BUMBLEBEE_CANNON_RIGHT,       "models/vehicles/bumblebee_plasma_right.dpm");
+MODEL(VEH_BUMBLEBEE_SHIELD,             "models/vhshield.md3");
+
+MODEL(VEH_RACER_BODY,                   "models/vehicles/wakizashi.dpm");
+MODEL(VEH_RACER_VIEW,                   "models/vehicles/wakizashi_cockpit.dpm");
+
+MODEL(VEH_RAPTOR_BODY,                  "models/vehicles/raptor.dpm");
+MODEL(VEH_RAPTOR_CB_FOLDED,             "models/vehicles/clusterbomb_folded.md3");
+MODEL(VEH_RAPTOR_CB_FRAGMENT,           "models/vehicles/clusterbomb_fragment.md3");
+MODEL(VEH_RAPTOR_FLARE,                 "models/runematch/rune.mdl");
+MODEL(VEH_RAPTOR_GUN,                   "models/vehicles/raptor_gun.dpm");
+MODEL(VEH_RAPTOR_PROP,                  "models/vehicles/spinner.dpm");
+MODEL(VEH_RAPTOR_TAIL,                  "models/vehicles/raptor_body.dpm");
+MODEL(VEH_RAPTOR_VIEW,                  "models/vehicles/raptor_cockpit.dpm");
+
+MODEL(VEH_SPIDERBOT_BODY,               "models/vehicles/spiderbot.dpm");
+MODEL(VEH_SPIDERBOT_GUN,                "models/vehicles/spiderbot_barrels.dpm");
+MODEL(VEH_SPIDERBOT_MUZZLEFLASH,        "models/uziflash.md3");
+MODEL(VEH_SPIDERBOT_TOP,                "models/vehicles/spiderbot_top.dpm");
+MODEL(VEH_SPIDERBOT_VIEW,               "models/vehicles/spiderbot_cockpit.dpm");
+
+MODEL(MON_MAGE,                         "models/monsters/mage.dpm");
+MODEL(MON_SHAMBLER,                     "models/monsters/shambler.mdl");
+MODEL(MON_SPIDER,                       "models/monsters/spider.dpm");
+MODEL(MON_WYVERN,                       "models/monsters/wizard.mdl");
+MODEL(MON_ZOMBIE,                       "models/monsters/zombie.dpm");
+
+MODEL(CHAT,                             "models/misc/chatbubble.spr");
+
+MODEL(0,                                "models/sprites/0.spr32");
+MODEL(1,                                "models/sprites/1.spr32");
+MODEL(2,                                "models/sprites/2.spr32");
+MODEL(3,                                "models/sprites/3.spr32");
+MODEL(4,                                "models/sprites/4.spr32");
+MODEL(5,                                "models/sprites/5.spr32");
+MODEL(6,                                "models/sprites/6.spr32");
+MODEL(7,                                "models/sprites/7.spr32");
+MODEL(8,                                "models/sprites/8.spr32");
+MODEL(9,                                "models/sprites/9.spr32");
+MODEL(10,                               "models/sprites/10.spr32");
+Model MDL_NUM(int i) {
+    if (!(i >= 0 && i <= 10))
+    return MDL_Null;
+    return MODELS[MDL_0.m_id + i];
+}
+
+MODEL(WAYPOINT,                         "models/runematch/rune.mdl");
+MODEL(MARKER,                           "models/marker.md3");
diff --git a/qcsrc/common/models/models.qh b/qcsrc/common/models/models.qh
new file mode 100644
index 0000000000..c668959655
--- /dev/null
+++ b/qcsrc/common/models/models.qh
@@ -0,0 +1,47 @@
+#ifndef MODELS_H
+#define MODELS_H
+
+#define setmodel(e, m) _setmodel((e), (m).model_str())
+
+void RegisterModels();
+const int MAX_MODELS = 128;
+entity MODELS[MAX_MODELS], MODELS_first, MODELS_last;
+int MODELS_COUNT;
+
+CLASS(Model, Object)
+    ATTRIB(Model, m_id, int, 0)
+    ATTRIB(Model, model_str, string(), func_null)
+    CONSTRUCTOR(Model, string() path)
+    {
+        CONSTRUCT(Model);
+        this.model_str = path;
+    }
+    METHOD(Model, model_precache, void(entity this)) {
+        string s = this.model_str();
+        int fh = fopen(s, FILE_READ);
+        if (fh >= 0) {
+            fclose(fh);
+        } else if (s && s != "" && s != "null") {
+            LOG_WARNINGF("Missing model: \"%s\"\n", s);
+            return;
+        }
+        LOG_TRACEF("precache_model(\"%s\")\n", s);
+        precache_model(s);
+    }
+ENDCLASS(Model)
+
+#define MODEL(name, path) \
+    string MDL_##name##_get() { return path; } \
+    REGISTER(RegisterModels, MDL, MODELS, MODELS_COUNT, name, m_id, NEW(Model, MDL_##name##_get))
+REGISTER_REGISTRY(RegisterModels)
+
+STATIC_INIT(RegisterModels_precache) {
+    FOREACH(MODELS, true, LAMBDA({
+        it.model_precache(it);
+    }));
+}
+
+MODEL(Null, "null");
+#include "models.inc"
+
+#endif
diff --git a/qcsrc/common/monsters/monster/mage.qc b/qcsrc/common/monsters/monster/mage.qc
index 8e26b9c1f3..d2881e9ba9 100644
--- a/qcsrc/common/monsters/monster/mage.qc
+++ b/qcsrc/common/monsters/monster/mage.qc
@@ -422,7 +422,6 @@ bool M_Mage(int req)
 		}
 		case MR_PRECACHE:
 		{
-			precache_model("models/monsters/mage.dpm");
 			precache_sound (W_Sound("grenade_impact"));
 			precache_sound (W_Sound("tagexp1"));
 			return true;
diff --git a/qcsrc/common/monsters/monster/shambler.qc b/qcsrc/common/monsters/monster/shambler.qc
index 0a77342f62..ea7fbbf7cc 100644
--- a/qcsrc/common/monsters/monster/shambler.qc
+++ b/qcsrc/common/monsters/monster/shambler.qc
@@ -274,7 +274,6 @@ bool M_Shambler(int req)
 		}
 		case MR_PRECACHE:
 		{
-			precache_model("models/monsters/shambler.mdl");
 			return true;
 		}
 		#endif
diff --git a/qcsrc/common/monsters/monster/spider.qc b/qcsrc/common/monsters/monster/spider.qc
index 7c9d31b2f7..fb71c2f222 100644
--- a/qcsrc/common/monsters/monster/spider.qc
+++ b/qcsrc/common/monsters/monster/spider.qc
@@ -176,7 +176,6 @@ bool M_Spider(int req)
 		}
 		case MR_PRECACHE:
 		{
-			precache_model("models/monsters/spider.dpm");
 			precache_sound (W_Sound("electro_fire2"));
 			return true;
 		}
diff --git a/qcsrc/common/monsters/monster/wyvern.qc b/qcsrc/common/monsters/monster/wyvern.qc
index f1160fb52e..af174603d2 100644
--- a/qcsrc/common/monsters/monster/wyvern.qc
+++ b/qcsrc/common/monsters/monster/wyvern.qc
@@ -158,7 +158,6 @@ bool M_Wyvern(int req)
 		}
 		case MR_PRECACHE:
 		{
-			precache_model("models/monsters/wizard.mdl");
 			return true;
 		}
 		#endif
diff --git a/qcsrc/common/monsters/monster/zombie.qc b/qcsrc/common/monsters/monster/zombie.qc
index fe7c384ca9..ed169c99d7 100644
--- a/qcsrc/common/monsters/monster/zombie.qc
+++ b/qcsrc/common/monsters/monster/zombie.qc
@@ -214,7 +214,6 @@ bool M_Zombie(int req)
 		}
 		case MR_PRECACHE:
 		{
-			precache_model("models/monsters/zombie.dpm");
 			return true;
 		}
 		#endif
diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc
index fb7ab2fca4..8eab200a6d 100644
--- a/qcsrc/common/monsters/sv_monsters.qc
+++ b/qcsrc/common/monsters/sv_monsters.qc
@@ -538,7 +538,7 @@ void Monster_Dead_Fade()
 		setorigin(self, self.pos1);
 		self.angles = self.pos2;
 		self.health = self.max_health;
-		setmodel(self, "null");
+		setmodel(self, MDL_Null);
 	}
 	else
 	{
@@ -1325,7 +1325,7 @@ bool Monster_Spawn(int mon_id)
 	if(!(self.spawnflags & MONSTERFLAG_RESPAWNED)) // don't count re-spawning monsters either
 		monsters_total += 1;
 
-	setmodel(self, self.mdl);
+	_setmodel(self, self.mdl);
 	self.flags				= FL_MONSTER;
 	self.classname			= "monster";
 	self.takedamage			= DAMAGE_AIM;
diff --git a/qcsrc/common/mutators/mutator/casings.qc b/qcsrc/common/mutators/mutator/casings.qc
index e93ed49a4b..fedcf9fe57 100644
--- a/qcsrc/common/mutators/mutator/casings.qc
+++ b/qcsrc/common/mutators/mutator/casings.qc
@@ -149,11 +149,11 @@ MUTATOR_HOOKFUNCTION(casings, CSQC_Parse_TempEntity)
     switch (casing.state)
     {
         case 1:
-            setmodel(casing, "models/casing_shell.mdl");
+            setmodel(casing, MDL_CASING_SHELL);
             casing.cnt = time + autocvar_cl_casings_shell_time;
             break;
         default:
-            setmodel(casing, "models/casing_bronze.iqm");
+            setmodel(casing, MDL_CASING_BULLET);
             casing.cnt = time + autocvar_cl_casings_bronze_time;
             break;
     }
@@ -165,8 +165,6 @@ MUTATOR_HOOKFUNCTION(casings, CSQC_Parse_TempEntity)
 
 STATIC_INIT(Casings)
 {
-    precache_model("models/casing_shell.mdl");
-    precache_model("models/casing_bronze.iqm");
     precache_sound(W_Sound("brass1"));
     precache_sound(W_Sound("brass2"));
     precache_sound(W_Sound("brass3"));
diff --git a/qcsrc/common/nades.qc b/qcsrc/common/nades.qc
index 08f579b275..f361730ba1 100644
--- a/qcsrc/common/nades.qc
+++ b/qcsrc/common/nades.qc
@@ -54,7 +54,7 @@ void healer_draw()
 
 void healer_setup()
 {SELFPARAM();
-	setmodel(self, "models/ctf/shield.md3");
+	setmodel(self, MDL_NADE_HEAL);
 
 	setorigin(self, self.origin);
 
diff --git a/qcsrc/common/triggers/func/breakable.qc b/qcsrc/common/triggers/func/breakable.qc
index 160399d0d2..0430db2d41 100644
--- a/qcsrc/common/triggers/func/breakable.qc
+++ b/qcsrc/common/triggers/func/breakable.qc
@@ -56,7 +56,7 @@ void LaunchDebris (string debrisname, vector force)
 	           + '1 0 0' * random() * (self.absmax.x - self.absmin.x)
 	           + '0 1 0' * random() * (self.absmax.y - self.absmin.y)
 	           + '0 0 1' * random() * (self.absmax.z - self.absmin.z));
-	setmodel (dbr, debrisname );
+	_setmodel (dbr, debrisname );
 	dbr.skin = self.debrisskin;
 	dbr.colormap = self.colormap; // inherit team colors
 	dbr.owner = self; // do not be affected by our own explosion
@@ -108,7 +108,7 @@ void func_breakable_look_destroyed()
 			setorigin(self,((self.absmax+self.absmin)*.5));
 			self.origin_z = floorZ;
 		}
-		setmodel(self, self.mdl_dead);
+		_setmodel(self, self.mdl_dead);
 		self.effects &= ~EF_NODRAW;
 	}
 
@@ -119,7 +119,7 @@ void func_breakable_look_destroyed()
 
 void func_breakable_look_restore()
 {SELFPARAM();
-	setmodel(self, self.mdl);
+	_setmodel(self, self.mdl);
 	self.effects &= ~EF_NODRAW;
 
 	if(self.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
diff --git a/qcsrc/common/triggers/func/door.qc b/qcsrc/common/triggers/func/door.qc
index 053f0f5f66..8d19a740c2 100644
--- a/qcsrc/common/triggers/func/door.qc
+++ b/qcsrc/common/triggers/func/door.qc
@@ -812,7 +812,7 @@ void ent_door()
 		self.spawnflags = ReadByte();
 
 		self.mdl = strzone(ReadString());
-		setmodel(self, self.mdl);
+		_setmodel(self, self.mdl);
 
 		trigger_common_read(true);
 
diff --git a/qcsrc/common/triggers/func/plat.qc b/qcsrc/common/triggers/func/plat.qc
index 8fc95bf48b..f2c57be21e 100644
--- a/qcsrc/common/triggers/func/plat.qc
+++ b/qcsrc/common/triggers/func/plat.qc
@@ -145,7 +145,7 @@ void ent_plat()
 		self.spawnflags = ReadByte();
 
 		self.model = strzone(ReadString());
-		setmodel(self, self.model);
+		_setmodel(self, self.model);
 
 		trigger_common_read(true);
 
diff --git a/qcsrc/common/triggers/func/pointparticles.qc b/qcsrc/common/triggers/func/pointparticles.qc
index f303ca9f2b..3c11b2a5b6 100644
--- a/qcsrc/common/triggers/func/pointparticles.qc
+++ b/qcsrc/common/triggers/func/pointparticles.qc
@@ -115,7 +115,7 @@ void pointparticles_reset()
 void spawnfunc_func_pointparticles()
 {SELFPARAM();
 	if(self.model != "")
-		setmodel(self, self.model);
+		_setmodel(self, self.model);
 	if(self.noise != "")
 		precache_sound (self.noise);
 
diff --git a/qcsrc/common/triggers/func/train.qc b/qcsrc/common/triggers/func/train.qc
index 6469d17e60..4149b538dc 100644
--- a/qcsrc/common/triggers/func/train.qc
+++ b/qcsrc/common/triggers/func/train.qc
@@ -242,7 +242,7 @@ void ent_train()
 		self.spawnflags = ReadByte();
 
 		self.model = strzone(ReadString());
-		setmodel(self, self.model);
+		_setmodel(self, self.model);
 
 		trigger_common_read(true);
 
diff --git a/qcsrc/common/triggers/target/music.qc b/qcsrc/common/triggers/target/music.qc
index 488ed0999b..33261eabdb 100644
--- a/qcsrc/common/triggers/target/music.qc
+++ b/qcsrc/common/triggers/target/music.qc
@@ -128,7 +128,7 @@ void trigger_music_use()
 void spawnfunc_trigger_music()
 {SELFPARAM();
 	if(self.model != "")
-		setmodel(self, self.model);
+		_setmodel(self, self.model);
 	if(!self.volume)
 		self.volume = 1;
 	if(!self.modelindex)
diff --git a/qcsrc/common/triggers/target/spawn.qc b/qcsrc/common/triggers/target/spawn.qc
index 6572221f75..591b971d50 100644
--- a/qcsrc/common/triggers/target/spawn.qc
+++ b/qcsrc/common/triggers/target/spawn.qc
@@ -24,7 +24,7 @@ float target_spawn_count;
 
 void target_spawn_helper_setmodel()
 {SELFPARAM();
-	setmodel(self, self.model);
+	_setmodel(self, self.model);
 }
 
 void target_spawn_helper_setsize()
diff --git a/qcsrc/common/turrets/cl_turrets.qc b/qcsrc/common/turrets/cl_turrets.qc
index 174e0ea7d4..232f546c12 100644
--- a/qcsrc/common/turrets/cl_turrets.qc
+++ b/qcsrc/common/turrets/cl_turrets.qc
@@ -211,8 +211,8 @@ void turret_construct()
 	self.netname = TUR_NAME(self.turretid);
 
 	setorigin(self, self.origin);
-	setmodel(self, tur.model);
-	setmodel(self.tur_head, tur.head_model);
+	_setmodel(self, tur.model);
+	_setmodel(self.tur_head, tur.head_model);
 	setsize(self, tur.mins, tur.maxs);
 	setsize(self.tur_head, '0 0 0', '0 0 0');
 
@@ -289,7 +289,7 @@ entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, flo
 
 	gib = spawn();
 	setorigin(gib, _from);
-	setmodel(gib, _model);
+	_setmodel(gib, _model);
 	gib.colormod	= _cmod;
 	gib.solid	   = SOLID_CORPSE;
 	gib.draw		= turret_gib_draw;
@@ -351,8 +351,8 @@ void turret_die()
 		}
 	}
 
-	setmodel(self, "null");
-	setmodel(self.tur_head, "null");
+	setmodel(self, MDL_Null);
+	setmodel(self.tur_head, MDL_Null);
 }
 
 void ent_turret()
diff --git a/qcsrc/common/turrets/sv_turrets.qc b/qcsrc/common/turrets/sv_turrets.qc
index 9297187837..9c02d7ad91 100644
--- a/qcsrc/common/turrets/sv_turrets.qc
+++ b/qcsrc/common/turrets/sv_turrets.qc
@@ -1327,7 +1327,7 @@ float turret_initialize(float tur_id)
 
 	++turret_count;
 
-	setmodel(self, tur.model);
+	_setmodel(self, tur.model);
 	setsize(self, tur.mins, tur.maxs);
 
 	self.turretid				= tur_id;
@@ -1352,7 +1352,7 @@ float turret_initialize(float tur_id)
 	self.nextthink			   += turret_count * sys_frametime;
 
 	self.tur_head = spawn();
-	setmodel(self.tur_head, tur.head_model);
+	_setmodel(self.tur_head, tur.head_model);
 	setsize(self.tur_head, '0 0 0', '0 0 0');
 	setorigin(self.tur_head, '0 0 0');
 	setattachment(self.tur_head, self, "tag_head");
diff --git a/qcsrc/common/turrets/turrets.qc b/qcsrc/common/turrets/turrets.qc
index 46ecf5bf1d..37c85ca65a 100644
--- a/qcsrc/common/turrets/turrets.qc
+++ b/qcsrc/common/turrets/turrets.qc
@@ -7,26 +7,12 @@ entity dummy_turret_info;
 void turrets_common_precache()
 {
 	precache_sound (W_Sound("rocket_impact"));
-	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");
-	precache_model ("models/turrets/base.md3");
-	precache_model ("models/turrets/rocket.md3");
-
-	precache_model ("models/turrets/c512.md3");
-	precache_model ("models/marker.md3");
 
 #ifdef SVQC
 	precache_sound(W_Sound("rocket_impact"));
 #endif
 
 #ifdef TURRET_DEBUG
-	precache_model ("models/turrets/c512.md3");
 	precache_model ("models/pathlib/goodsquare.md3");
 	precache_model ("models/pathlib/badsquare.md3");
 	precache_model ("models/pathlib/square.md3");
diff --git a/qcsrc/common/turrets/unit/ewheel.qc b/qcsrc/common/turrets/unit/ewheel.qc
index 716a70ceff..e61897cdd8 100644
--- a/qcsrc/common/turrets/unit/ewheel.qc
+++ b/qcsrc/common/turrets/unit/ewheel.qc
@@ -252,8 +252,6 @@ float t_ewheel(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/ewheel-base2.md3");
-            precache_model ("models/turrets/ewheel-gun1.md3");
             return true;
         }
     }
diff --git a/qcsrc/common/turrets/unit/flac.qc b/qcsrc/common/turrets/unit/flac.qc
index eff6a5801e..228049f411 100644
--- a/qcsrc/common/turrets/unit/flac.qc
+++ b/qcsrc/common/turrets/unit/flac.qc
@@ -71,8 +71,6 @@ float t_flac(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/base.md3");
-            precache_model ("models/turrets/flac.md3");
             return true;
         }
     }
diff --git a/qcsrc/common/turrets/unit/fusionreactor.qc b/qcsrc/common/turrets/unit/fusionreactor.qc
index 25cddf006e..3ba1ff0747 100644
--- a/qcsrc/common/turrets/unit/fusionreactor.qc
+++ b/qcsrc/common/turrets/unit/fusionreactor.qc
@@ -84,8 +84,6 @@ float t_fusionreactor(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/base.md3");
-            precache_model ("models/turrets/reactor.md3");
             return true;
         }
     }
diff --git a/qcsrc/common/turrets/unit/hellion.qc b/qcsrc/common/turrets/unit/hellion.qc
index 66b9907998..f785f4e953 100644
--- a/qcsrc/common/turrets/unit/hellion.qc
+++ b/qcsrc/common/turrets/unit/hellion.qc
@@ -128,8 +128,6 @@ float t_hellion(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/base.md3");
-            precache_model ("models/turrets/hellion.md3");
             return true;
         }
     }
diff --git a/qcsrc/common/turrets/unit/hk.qc b/qcsrc/common/turrets/unit/hk.qc
index 8a78e976ad..f01275187d 100644
--- a/qcsrc/common/turrets/unit/hk.qc
+++ b/qcsrc/common/turrets/unit/hk.qc
@@ -329,8 +329,6 @@ float t_hk(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/base.md3");
-            precache_model ("models/turrets/hk.md3");
             return true;
         }
     }
diff --git a/qcsrc/common/turrets/unit/machinegun.qc b/qcsrc/common/turrets/unit/machinegun.qc
index 8b580af0a9..afecb7fa56 100644
--- a/qcsrc/common/turrets/unit/machinegun.qc
+++ b/qcsrc/common/turrets/unit/machinegun.qc
@@ -48,8 +48,6 @@ float t_machinegun(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/base.md3");
-            precache_model ("models/turrets/machinegun.md3");
             precache_sound (W_Sound("uzi_fire"));
             return true;
         }
diff --git a/qcsrc/common/turrets/unit/mlrs.qc b/qcsrc/common/turrets/unit/mlrs.qc
index 548ca8fc80..1a3c9220b8 100644
--- a/qcsrc/common/turrets/unit/mlrs.qc
+++ b/qcsrc/common/turrets/unit/mlrs.qc
@@ -58,8 +58,6 @@ float t_mlrs(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/base.md3");
-            precache_model ("models/turrets/mlrs.md3");
             return true;
         }
     }
diff --git a/qcsrc/common/turrets/unit/phaser.qc b/qcsrc/common/turrets/unit/phaser.qc
index c83b34056d..e1ddef3a9d 100644
--- a/qcsrc/common/turrets/unit/phaser.qc
+++ b/qcsrc/common/turrets/unit/phaser.qc
@@ -69,7 +69,7 @@ float t_phaser(float req)
 
             beam = spawn();
             beam.ticrate = 0.1; //autocvar_sys_ticrate;
-            setmodel(beam,"models/turrets/phaser_beam.md3");
+            setmodel(beam, MDL_TUR_PHASER_BEAM);
             beam.effects = EF_LOWPRECISION;
             beam.solid = SOLID_NOT;
             beam.think = beam_think;
@@ -137,9 +137,6 @@ float t_phaser(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/base.md3");
-            precache_model ("models/turrets/phaser.md3");
-            precache_model ("models/turrets/phaser_beam.md3");
             precache_sound ("turrets/phaser.wav");
             return true;
         }
diff --git a/qcsrc/common/turrets/unit/plasma.qc b/qcsrc/common/turrets/unit/plasma.qc
index ff882d18c9..df986d79e0 100644
--- a/qcsrc/common/turrets/unit/plasma.qc
+++ b/qcsrc/common/turrets/unit/plasma.qc
@@ -79,8 +79,6 @@ float t_plasma(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/base.md3");
-            precache_model ("models/turrets/plasma.md3");
             return true;
         }
     }
diff --git a/qcsrc/common/turrets/unit/plasma_dual.qc b/qcsrc/common/turrets/unit/plasma_dual.qc
index 47dd34ae89..f3bd32448f 100644
--- a/qcsrc/common/turrets/unit/plasma_dual.qc
+++ b/qcsrc/common/turrets/unit/plasma_dual.qc
@@ -77,8 +77,6 @@ float t_plasma_dual(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/base.md3");
-            precache_model ("models/turrets/plasmad.md3");
             return true;
         }
     }
diff --git a/qcsrc/common/turrets/unit/tesla.qc b/qcsrc/common/turrets/unit/tesla.qc
index 8f80abea75..50e37182c3 100644
--- a/qcsrc/common/turrets/unit/tesla.qc
+++ b/qcsrc/common/turrets/unit/tesla.qc
@@ -185,8 +185,6 @@ float t_tesla(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/tesla_base.md3");
-            precache_model ("models/turrets/tesla_head.md3");
             return true;
         }
     }
diff --git a/qcsrc/common/turrets/unit/walker.qc b/qcsrc/common/turrets/unit/walker.qc
index 58c1be198d..9e7b0cbe13 100644
--- a/qcsrc/common/turrets/unit/walker.qc
+++ b/qcsrc/common/turrets/unit/walker.qc
@@ -634,9 +634,6 @@ float t_walker(float req)
         }
         case TR_PRECACHE:
         {
-            precache_model ("models/turrets/walker_body.md3");
-            precache_model ("models/turrets/walker_head_minigun.md3");
-            precache_model ("models/turrets/rocket.md3");
             precache_sound (W_Sound("rocket_impact"));
             return true;
         }
diff --git a/qcsrc/common/turrets/util.qc b/qcsrc/common/turrets/util.qc
index 8fa223aef1..53c5fb74df 100644
--- a/qcsrc/common/turrets/util.qc
+++ b/qcsrc/common/turrets/util.qc
@@ -228,7 +228,7 @@ void mark_error(vector where,float lifetime)
 
 	err = spawn();
 	err.classname = "error_marker";
-	setmodel(err,"models/marker.md3");
+	setmodel(err, MDL_MARKER);
 	setorigin(err,where);
 	err.movetype = MOVETYPE_NONE;
 	err.think = marker_think;
@@ -244,7 +244,7 @@ void mark_info(vector where,float lifetime)
 
 	err = spawn();
 	err.classname = "info_marker";
-	setmodel(err,"models/marker.md3");
+	setmodel(err, MDL_MARKER);
 	setorigin(err,where);
 	err.movetype = MOVETYPE_NONE;
 	err.think = marker_think;
@@ -260,7 +260,7 @@ entity mark_misc(vector where,float lifetime)
 
 	err = spawn();
 	err.classname = "mark_misc";
-	setmodel(err,"models/marker.md3");
+	setmodel(err, MDL_MARKER);
 	setorigin(err,where);
 	err.movetype = MOVETYPE_NONE;
 	err.think = marker_think;
@@ -271,6 +271,8 @@ entity mark_misc(vector where,float lifetime)
 	return err;
 }
 
+MODEL(TUR_C512, "models/turrets/c512.md3");
+
 /*
 * Paint a v_color colord circle on target onwho
 * that fades away over f_time
@@ -280,7 +282,7 @@ 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
+	setmodel(e, MDL_TUR_C512); // precision set above
 	e.scale = (f_size/512);
 	//setsize(e, '0 0 0', '0 0 0');
 	//setattachment(e,onwho,"");
@@ -299,7 +301,7 @@ 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
+	setmodel(e, MDL_TUR_C512); // precision set above
 	e.scale = (f_size/512);
 	setsize(e, '0 0 0', '0 0 0');
 
@@ -318,7 +320,7 @@ 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
+	setmodel(e, MDL_TUR_C512); // precision set above
 	e.scale = (f_size/512);
 	setsize(e, '0 0 0', '0 0 0');
 	setorigin(e,where+ '0 0 1');
diff --git a/qcsrc/common/vehicles/all.qc b/qcsrc/common/vehicles/all.qc
index 923ed4e5bd..3f3b77ea33 100644
--- a/qcsrc/common/vehicles/all.qc
+++ b/qcsrc/common/vehicles/all.qc
@@ -17,12 +17,6 @@
 STATIC_INIT(vehicles_common_initialize)
 {
 #ifdef CSQC
-	precache_model("models/vehicles/bomblet.md3");
-	precache_model("models/vehicles/clusterbomb.md3");
-	precache_model("models/vehicles/clusterbomb_fragment.md3");
-	precache_model("models/vehicles/rocket01.md3");
-	precache_model("models/vehicles/rocket02.md3");
-
 	precache_sound ("vehicles/alarm.wav");
 	precache_sound ("vehicles/alarm_shield.wav");
 #endif // CSQC
diff --git a/qcsrc/common/vehicles/sv_vehicles.qc b/qcsrc/common/vehicles/sv_vehicles.qc
index 33e0bab15b..73ff86b4be 100644
--- a/qcsrc/common/vehicles/sv_vehicles.qc
+++ b/qcsrc/common/vehicles/sv_vehicles.qc
@@ -321,7 +321,7 @@ void vehicles_gib_think()
 entity vehicle_tossgib(entity _template, vector _vel, string _tag, bool _burn, bool _explode, float _maxtime, vector _rot)
 {SELFPARAM();
 	entity _gib = spawn();
-	setmodel(_gib, _template.model);
+	_setmodel(_gib, _template.model);
 	setorigin(_gib, gettaginfo(self, gettagindex(self, _tag)));
 	_gib.velocity = _vel;
 	_gib.movetype = MOVETYPE_TOSS;
@@ -369,8 +369,8 @@ bool vehicle_addplayerslot(	entity _owner,
 	_slot.vehicle_hudmodel.viewmodelforclient = _slot;
 	_slot.vehicle_viewport.effects = (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT);
 
-	setmodel(_slot.vehicle_hudmodel, _hud_model);
-	setmodel(_slot.vehicle_viewport, "null");
+	_setmodel(_slot.vehicle_hudmodel, _hud_model);
+	setmodel(_slot.vehicle_viewport, MDL_Null);
 
 	setattachment(_slot.vehicle_hudmodel, _slot, "");
 	setattachment(_slot.vehicle_viewport, _slot.vehicle_hudmodel, "");
@@ -516,7 +516,7 @@ void vehicles_showwp()
 
 		oldself = self;
 		setself(spawn());
-		setmodel(self, "null");
+		setmodel(self, MDL_Null);
 		self.team = oldself.wp00.team;
 		self.wp00 = oldself.wp00;
 		setorigin(self, oldself.wp00.pos1);
@@ -565,7 +565,7 @@ void vehicles_setreturn(entity veh)
 		ret.nextthink   = min(time + veh.respawntime, time + veh.respawntime - 1);
 	}
 
-	setmodel(ret, "null");
+	setmodel(ret, MDL_Null);
 	setorigin(ret, veh.pos1 + '0 0 96');
 
 }
@@ -617,7 +617,7 @@ void shieldhit_think()
 	self.alpha -= 0.1;
 	if (self.alpha <= 0)
 	{
-		//setmodel(self, "");
+		// setmodel(self, MDL_Null);
 		self.alpha = -1;
 		self.effects |= EF_NODRAW;
 	}
@@ -683,7 +683,7 @@ void vehicles_damage(entity inflictor, entity attacker, float damage, int deatht
 			self.vehicle_shieldent = spawn();
 			self.vehicle_shieldent.effects = EF_LOWPRECISION;
 
-			setmodel(self.vehicle_shieldent, "models/vhshield.md3");
+			setmodel(self.vehicle_shieldent, MDL_VEH_SHIELD);
 			setattachment(self.vehicle_shieldent, self, "");
 			setorigin(self.vehicle_shieldent, real_origin(self) - self.origin);
 			self.vehicle_shieldent.scale	   = 256 / vlen(self.maxs - self.mins);
@@ -1220,9 +1220,9 @@ bool vehicle_initialize(entity veh, bool nodrop)
 		self.team = 0;
 
 	if(self.mdl == "" || !self.mdl)
-		setmodel(self, veh.model);
+		_setmodel(self, veh.model);
 	else
-		setmodel(self, self.mdl);
+		_setmodel(self, self.mdl);
 
 	self.vehicle_flags |= VHF_ISVEHICLE;
 
@@ -1253,12 +1253,12 @@ bool vehicle_initialize(entity veh, bool nodrop)
 	if(autocvar_g_fullbrightplayers)
 		self.effects |= EF_FULLBRIGHT;
 
-	setmodel(self.vehicle_hudmodel, veh.hud_model);
-	setmodel(self.vehicle_viewport, "null");
+	_setmodel(self.vehicle_hudmodel, veh.hud_model);
+	setmodel(self.vehicle_viewport, MDL_Null);
 
 	if(veh.head_model != "")
 	{
-		setmodel(self.tur_head, veh.head_model);
+		_setmodel(self.tur_head, veh.head_model);
 		setattachment(self.tur_head, self, veh.tag_head);
 		setattachment(self.vehicle_hudmodel, self.tur_head, veh.tag_hud);
 		setattachment(self.vehicle_viewport, self.vehicle_hudmodel, veh.tag_view);
diff --git a/qcsrc/common/vehicles/unit/bumblebee.qc b/qcsrc/common/vehicles/unit/bumblebee.qc
index d88e3dfc06..96fef6c05c 100644
--- a/qcsrc/common/vehicles/unit/bumblebee.qc
+++ b/qcsrc/common/vehicles/unit/bumblebee.qc
@@ -902,7 +902,7 @@ float v_bumblebee(float req)
 				// for some reason, autosizing of the shield entity refuses to work for this one so set it up in advance.
 				self.vehicle_shieldent = spawn();
 				self.vehicle_shieldent.effects = EF_LOWPRECISION;
-				setmodel(self.vehicle_shieldent, "models/vhshield.md3");
+				setmodel(self.vehicle_shieldent, MDL_VEH_BUMBLEBEE_SHIELD);
 				setattachment(self.vehicle_shieldent, self, "");
 				setorigin(self.vehicle_shieldent, real_origin(self) - self.origin);
 				self.vehicle_shieldent.scale       = 512 / vlen(self.maxs - self.mins);
@@ -922,9 +922,9 @@ float v_bumblebee(float req)
 
 				self.gun1.classname = self.gun2.classname = "vehicle_playerslot";
 
-				setmodel(self.gun1, "models/vehicles/bumblebee_plasma_right.dpm");
-				setmodel(self.gun2, "models/vehicles/bumblebee_plasma_left.dpm");
-				setmodel(self.gun3, "models/vehicles/bumblebee_ray.dpm");
+				setmodel(self.gun1, MDL_VEH_BUMBLEBEE_CANNON_RIGHT);
+				setmodel(self.gun2, MDL_VEH_BUMBLEBEE_CANNON_LEFT);
+				setmodel(self.gun3, MDL_VEH_BUMBLEBEE_CANNON_CENTER);
 
 				setattachment(self.gun1, self, "cannon_right");
 				setattachment(self.gun2, self, "cannon_left");
@@ -1000,13 +1000,6 @@ float v_bumblebee(float req)
 		}
 		case VR_PRECACHE:
 		{
-			precache_model("models/vehicles/bumblebee_body.dpm");
-			precache_model("models/vehicles/bumblebee_plasma_left.dpm");
-			precache_model("models/vehicles/bumblebee_plasma_right.dpm");
-			precache_model("models/vehicles/bumblebee_ray.dpm");
-			precache_model("models/vehicles/wakizashi_cockpit.dpm");
-			precache_model("models/vehicles/spiderbot_cockpit.dpm");
-			precache_model("models/vehicles/raptor_cockpit.dpm");
 			return true;
 		}
 	}
diff --git a/qcsrc/common/vehicles/unit/racer.qc b/qcsrc/common/vehicles/unit/racer.qc
index 846c647a03..62a6e850fd 100644
--- a/qcsrc/common/vehicles/unit/racer.qc
+++ b/qcsrc/common/vehicles/unit/racer.qc
@@ -863,12 +863,6 @@ bool v_racer(int req)
 			precache_sound ("vehicles/racer_idle.wav");
 			precache_sound ("vehicles/racer_move.wav");
 			precache_sound ("vehicles/racer_boost.wav");
-
-			precache_model ("models/vhshield.md3");
-		#endif
-		#ifndef MENUQC
-			precache_model ("models/vehicles/wakizashi.dpm");
-			precache_model ("models/vehicles/wakizashi_cockpit.dpm");
 		#endif
 			return true;
 		}
diff --git a/qcsrc/common/vehicles/unit/raptor.qc b/qcsrc/common/vehicles/unit/raptor.qc
index 263da161f0..96a84892cf 100644
--- a/qcsrc/common/vehicles/unit/raptor.qc
+++ b/qcsrc/common/vehicles/unit/raptor.qc
@@ -588,7 +588,7 @@ float raptor_frame()
 			for(i = 0; i < 3; ++i)
 			{
 			_flare = spawn();
-			setmodel(_flare, "models/runematch/rune.mdl");
+			setmodel(_flare, MDL_VEH_RAPTOR_FLARE);
 			_flare.effects = EF_LOWPRECISION | EF_FLAME;
 			_flare.scale = 0.5;
 			setorigin(_flare, self.origin - '0 0 16');
@@ -872,11 +872,11 @@ float v_raptor(float req)
 				self.gun1  = spawn();
 				self.gun2  = spawn();
 
-				setmodel(self.bomb1,"models/vehicles/clusterbomb_folded.md3");
-				setmodel(self.bomb2,"models/vehicles/clusterbomb_folded.md3");
-				setmodel(self.gun1, "models/vehicles/raptor_gun.dpm");
-				setmodel(self.gun2, "models/vehicles/raptor_gun.dpm");
-				setmodel(self.tur_head, "models/vehicles/raptor_body.dpm");
+				setmodel(self.bomb1, MDL_VEH_RAPTOR_CB_FOLDED);
+				setmodel(self.bomb2, MDL_VEH_RAPTOR_CB_FOLDED);
+				setmodel(self.gun1, MDL_VEH_RAPTOR_GUN);
+				setmodel(self.gun2, MDL_VEH_RAPTOR_GUN);
+				setmodel(self.tur_head, MDL_VEH_RAPTOR_TAIL);
 
 				setattachment(self.bomb1, self, "bombmount_left");
 				setattachment(self.bomb2, self, "bombmount_right");
@@ -903,7 +903,7 @@ float v_raptor(float req)
 
 				spinner = spawn();
 				spinner.owner = self;
-				setmodel(spinner,"models/vehicles/spinner.dpm");
+				setmodel(spinner, MDL_VEH_RAPTOR_PROP);
 				setattachment(spinner, self, "engine_left");
 				spinner.movetype = MOVETYPE_NOCLIP;
 				spinner.avelocity = '0 90 0';
@@ -911,7 +911,7 @@ float v_raptor(float req)
 
 				spinner = spawn();
 				spinner.owner = self;
-				setmodel(spinner,"models/vehicles/spinner.dpm");
+				setmodel(spinner, MDL_VEH_RAPTOR_PROP);
 				setattachment(spinner, self, "engine_right");
 				spinner.movetype = MOVETYPE_NOCLIP;
 				spinner.avelocity = '0 -90 0';
@@ -969,13 +969,6 @@ float v_raptor(float req)
 		}
 		case VR_PRECACHE:
 		{
-			precache_model ("models/vehicles/raptor.dpm");
-			precache_model ("models/vehicles/raptor_gun.dpm");
-			precache_model ("models/vehicles/spinner.dpm");
-			precache_model ("models/vehicles/raptor_cockpit.dpm");
-			precache_model ("models/vehicles/clusterbomb_folded.md3");
-			precache_model ("models/vehicles/raptor_body.dpm");
-
 			precache_sound ("vehicles/raptor_fly.wav");
 			precache_sound ("vehicles/raptor_speed.wav");
 			precache_sound ("vehicles/missile_alarm.wav");
@@ -1011,7 +1004,7 @@ void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang)
 	entity sfrag;
 
 	sfrag = spawn();
-	setmodel(sfrag, "models/vehicles/clusterbomb_fragment.md3");
+	setmodel(sfrag, MDL_VEH_RAPTOR_CB_FRAGMENT);
 	setorigin(sfrag, _org);
 
 	sfrag.move_movetype = MOVETYPE_BOUNCE;
diff --git a/qcsrc/common/vehicles/unit/spiderbot.qc b/qcsrc/common/vehicles/unit/spiderbot.qc
index 7060b78153..7d03c7736f 100644
--- a/qcsrc/common/vehicles/unit/spiderbot.qc
+++ b/qcsrc/common/vehicles/unit/spiderbot.qc
@@ -704,10 +704,10 @@ void spiderbot_blowup()
 	g1 = spawn();
 	g2 = spawn();
 
-	setmodel(b, "models/vehicles/spiderbot.dpm");
-	setmodel(h, "models/vehicles/spiderbot_top.dpm");
-	setmodel(g1, "models/vehicles/spiderbot_barrels.dpm");
-	setmodel(g2, "models/vehicles/spiderbot_barrels.dpm");
+	setmodel(b, MDL_VEH_SPIDERBOT_BODY);
+	setmodel(h, MDL_VEH_SPIDERBOT_TOP);
+	setmodel(g1, MDL_VEH_SPIDERBOT_GUN);
+	setmodel(g2, MDL_VEH_SPIDERBOT_GUN);
 
 	setorigin(b, self.origin);
 	b.frame = 11;
@@ -878,8 +878,8 @@ float v_spiderbot(float req)
 				self.vehicles_impulse = spiderbot_impulse;
 				self.gun1 = spawn();
 				self.gun2 = spawn();
-				setmodel(self.gun1, "models/vehicles/spiderbot_barrels.dpm");
-				setmodel(self.gun2, "models/vehicles/spiderbot_barrels.dpm");
+				setmodel(self.gun1, MDL_VEH_SPIDERBOT_GUN);
+				setmodel(self.gun2, MDL_VEH_SPIDERBOT_GUN);
 				setattachment(self.gun1, self.tur_head, "tag_hardpoint01");
 				setattachment(self.gun2, self.tur_head, "tag_hardpoint02");
 				self.gravity = 2;
@@ -925,13 +925,6 @@ float v_spiderbot(float req)
 		}
 		case VR_PRECACHE:
 		{
-			precache_model ("models/vhshield.md3");
-			precache_model ("models/vehicles/spiderbot.dpm");
-			precache_model ("models/vehicles/spiderbot_top.dpm");
-			precache_model ("models/vehicles/spiderbot_barrels.dpm");
-			precache_model ("models/vehicles/spiderbot_cockpit.dpm");
-			precache_model ( "models/uziflash.md3");
-
 			precache_sound (W_Sound("uzi_fire") );
 			precache_sound (W_Sound("rocket_impact"));
 
diff --git a/qcsrc/common/weapons/weapon/arc.qc b/qcsrc/common/weapons/weapon/arc.qc
index fe8c20c7a2..a6a0730996 100644
--- a/qcsrc/common/weapons/weapon/arc.qc
+++ b/qcsrc/common/weapons/weapon/arc.qc
@@ -716,9 +716,6 @@ bool W_Arc(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_arc.md3"));
-			precache_model(W_Model("v_arc.md3"));
-			precache_model(W_Model("h_arc.iqm"));
 			precache_sound(W_Sound("arc_fire"));
 			precache_sound(W_Sound("arc_loop"));
 			precache_sound(W_Sound("arc_stop"));
@@ -1290,7 +1287,7 @@ void Ent_ReadArcBeam(float isnew)
 				self.beam_muzzlelight[3] = 1;
 				if(self.beam_muzzleeffect >= 0)
 				{
-					setmodel(flash, "models/flash.md3");
+					setmodel(flash, MDL_ARC_MUZZLEFLASH);
 					flash.alpha = self.beam_alpha;
 					flash.colormod = self.beam_color;
 					flash.scale = 0.5;
@@ -1316,7 +1313,7 @@ void Ent_ReadArcBeam(float isnew)
 				self.beam_image = "particles/lgbeam";
 				if(self.beam_muzzleeffect >= 0)
 				{
-					setmodel(flash, "models/flash.md3");
+					setmodel(flash, MDL_ARC_MUZZLEFLASH);
 					flash.alpha = self.beam_alpha;
 					flash.colormod = self.beam_color;
 					flash.scale = 0.5;
@@ -1342,7 +1339,7 @@ void Ent_ReadArcBeam(float isnew)
 				self.beam_image = "particles/lgbeam";
 				if(self.beam_muzzleeffect >= 0)
 				{
-					setmodel(flash, "models/flash.md3");
+					setmodel(flash, MDL_ARC_MUZZLEFLASH);
 					flash.alpha = self.beam_alpha;
 					flash.colormod = self.beam_color;
 					flash.scale = 0.5;
@@ -1368,7 +1365,7 @@ void Ent_ReadArcBeam(float isnew)
 				self.beam_image = "particles/lgbeam";
 				if(self.beam_muzzleeffect >= 0)
 				{
-					setmodel(flash, "models/flash.md3");
+					setmodel(flash, MDL_ARC_MUZZLEFLASH);
 					flash.alpha = self.beam_alpha;
 					flash.colormod = self.beam_color;
 					flash.scale = 0.5;
@@ -1394,7 +1391,7 @@ void Ent_ReadArcBeam(float isnew)
 				self.beam_image = "particles/lgbeam";
 				if(self.beam_muzzleeffect >= 0)
 				{
-					setmodel(flash, "models/flash.md3");
+					setmodel(flash, MDL_ARC_MUZZLEFLASH);
 					flash.alpha = self.beam_alpha;
 					flash.colormod = self.beam_color;
 					flash.scale = 0.5;
@@ -1420,7 +1417,7 @@ void Ent_ReadArcBeam(float isnew)
 				self.beam_image = "particles/lgbeam";
 				if(self.beam_muzzleeffect >= 0)
 				{
-					setmodel(flash, "models/flash.md3");
+					setmodel(flash, MDL_ARC_MUZZLEFLASH);
 					flash.alpha = self.beam_alpha;
 					flash.colormod = self.beam_color;
 					flash.scale = 0.5;
@@ -1446,7 +1443,7 @@ void Ent_ReadArcBeam(float isnew)
 				self.beam_image = "particles/lgbeam";
 				if(self.beam_muzzleeffect >= 0)
 				{
-					setmodel(flash, "models/flash.md3");
+					setmodel(flash, MDL_ARC_MUZZLEFLASH);
 					flash.alpha = self.beam_alpha;
 					flash.colormod = self.beam_color;
 					flash.scale = 0.5;
@@ -1472,7 +1469,7 @@ void Ent_ReadArcBeam(float isnew)
 				self.beam_image = "particles/lgbeam";
 				if(self.beam_muzzleeffect >= 0)
 				{
-					setmodel(flash, "models/flash.md3");
+					setmodel(flash, MDL_ARC_MUZZLEFLASH);
 					flash.alpha = self.beam_alpha;
 					flash.colormod = self.beam_color;
 					flash.scale = 0.5;
@@ -1500,7 +1497,7 @@ void Ent_ReadArcBeam(float isnew)
 				self.beam_image = "particles/lgbeam";
 				if(self.beam_muzzleeffect >= 0)
 				{
-					setmodel(flash, "models/flash.md3");
+					setmodel(flash, MDL_ARC_MUZZLEFLASH);
 					flash.alpha = self.beam_alpha;
 					flash.colormod = self.beam_color;
 					flash.scale = 0.5;
diff --git a/qcsrc/common/weapons/weapon/blaster.qc b/qcsrc/common/weapons/weapon/blaster.qc
index e3edb492eb..b20713c029 100644
--- a/qcsrc/common/weapons/weapon/blaster.qc
+++ b/qcsrc/common/weapons/weapon/blaster.qc
@@ -223,9 +223,6 @@ bool W_Blaster(int request)
 
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_laser.md3"));
-			precache_model(W_Model("v_laser.md3"));
-			precache_model(W_Model("h_laser.iqm"));
 			precache_sound(W_Sound("lasergun_fire"));
 			BLASTER_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
 			return true;
diff --git a/qcsrc/common/weapons/weapon/crylink.qc b/qcsrc/common/weapons/weapon/crylink.qc
index ba63afbcea..6821d5a0e1 100644
--- a/qcsrc/common/weapons/weapon/crylink.qc
+++ b/qcsrc/common/weapons/weapon/crylink.qc
@@ -638,9 +638,6 @@ bool W_Crylink(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_crylink.md3"));
-			precache_model(W_Model("v_crylink.md3"));
-			precache_model(W_Model("h_crylink.iqm"));
 			precache_sound(W_Sound("crylink_fire"));
 			precache_sound(W_Sound("crylink_fire2"));
 			precache_sound(W_Sound("crylink_linkjoin"));
diff --git a/qcsrc/common/weapons/weapon/devastator.qc b/qcsrc/common/weapons/weapon/devastator.qc
index bbce1a8ca4..cb2d16659c 100644
--- a/qcsrc/common/weapons/weapon/devastator.qc
+++ b/qcsrc/common/weapons/weapon/devastator.qc
@@ -383,7 +383,7 @@ void W_Devastator_Attack(void)
 
 	// muzzle flash for 1st person view
 	flash = spawn();
-	setmodel(flash, "models/flash.md3"); // precision set below
+	setmodel(flash, MDL_DEVASTATOR_MUZZLEFLASH); // precision set below
 	SUB_SetFade(flash, time, 0.1);
 	flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
 	W_AttachToShotorg(flash, '5 0 0');
@@ -569,10 +569,6 @@ bool W_Devastator(int req)
 		{
 			//if(autocvar_sv_precacheweapons)
 			//{
-				precache_model("models/flash.md3");
-				precache_model(W_Model("g_rl.md3"));
-				precache_model(W_Model("v_rl.md3"));
-				precache_model(W_Model("h_rl.iqm"));
 				precache_sound(W_Sound("rocket_det"));
 				precache_sound(W_Sound("rocket_fire"));
 				precache_sound(W_Sound("rocket_mode"));
diff --git a/qcsrc/common/weapons/weapon/electro.qc b/qcsrc/common/weapons/weapon/electro.qc
index b308d2e0fc..7f02a00ce2 100644
--- a/qcsrc/common/weapons/weapon/electro.qc
+++ b/qcsrc/common/weapons/weapon/electro.qc
@@ -395,7 +395,7 @@ void W_Electro_Attack_Orb(void)
 	entity p2;
 	p2 = spawn();
 	copyentity(proj, p2);
-	setmodel(p2, "models/ebomb.mdl");
+	setmodel(p2, MDL_PROJECTILE_ELECTRO);
 	setsize(p2, proj.mins, proj.maxs);
 #endif
 
@@ -498,9 +498,6 @@ bool W_Electro(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_electro.md3"));
-			precache_model(W_Model("v_electro.md3"));
-			precache_model(W_Model("h_electro.iqm"));
 			precache_sound(W_Sound("electro_bounce"));
 			precache_sound(W_Sound("electro_fire"));
 			precache_sound(W_Sound("electro_fire2"));
diff --git a/qcsrc/common/weapons/weapon/fireball.qc b/qcsrc/common/weapons/weapon/fireball.qc
index cb33a244c4..a37ae8f099 100644
--- a/qcsrc/common/weapons/weapon/fireball.qc
+++ b/qcsrc/common/weapons/weapon/fireball.qc
@@ -399,10 +399,6 @@ bool W_Fireball(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_fireball.md3"));
-			precache_model(W_Model("v_fireball.md3"));
-			precache_model(W_Model("h_fireball.iqm"));
-			precache_model("models/sphere/sphere.md3");
 			precache_sound(W_Sound("fireball_fire"));
 			precache_sound(W_Sound("fireball_fire2"));
 			precache_sound(W_Sound("fireball_prefire2"));
diff --git a/qcsrc/common/weapons/weapon/hagar.qc b/qcsrc/common/weapons/weapon/hagar.qc
index cc01af7db1..d55a1b6072 100644
--- a/qcsrc/common/weapons/weapon/hagar.qc
+++ b/qcsrc/common/weapons/weapon/hagar.qc
@@ -451,9 +451,6 @@ bool W_Hagar(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_hagar.md3"));
-			precache_model(W_Model("v_hagar.md3"));
-			precache_model(W_Model("h_hagar.iqm"));
 			precache_sound(W_Sound("hagar_fire"));
 			precache_sound(W_Sound("hagar_load"));
 			precache_sound(W_Sound("hagar_beep"));
diff --git a/qcsrc/common/weapons/weapon/hlac.qc b/qcsrc/common/weapons/weapon/hlac.qc
index 8e0ce6f118..074b760538 100644
--- a/qcsrc/common/weapons/weapon/hlac.qc
+++ b/qcsrc/common/weapons/weapon/hlac.qc
@@ -241,9 +241,6 @@ bool W_HLAC(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_hlac.md3"));
-			precache_model(W_Model("v_hlac.md3"));
-			precache_model(W_Model("h_hlac.iqm"));
 			precache_sound(W_Sound("lasergun_fire"));
 			HLAC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
 			return true;
diff --git a/qcsrc/common/weapons/weapon/hmg.qc b/qcsrc/common/weapons/weapon/hmg.qc
index c9afd42ecd..c55304118b 100644
--- a/qcsrc/common/weapons/weapon/hmg.qc
+++ b/qcsrc/common/weapons/weapon/hmg.qc
@@ -118,10 +118,6 @@ bool W_HeavyMachineGun(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model ("models/uziflash.md3");
-			precache_model(W_Model("g_ok_hmg.md3"));
-			precache_model(W_Model("v_ok_hmg.md3"));
-			precache_model(W_Model("h_ok_hmg.iqm"));
 			precache_sound (W_Sound("uzi_fire"));
 			HMG_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
 			return true;
diff --git a/qcsrc/common/weapons/weapon/hook.qc b/qcsrc/common/weapons/weapon/hook.qc
index c6b352212e..b7f51b54c4 100644
--- a/qcsrc/common/weapons/weapon/hook.qc
+++ b/qcsrc/common/weapons/weapon/hook.qc
@@ -288,9 +288,6 @@ bool W_Hook(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_hookgun.md3"));
-			precache_model(W_Model("v_hookgun.md3"));
-			precache_model(W_Model("h_hookgun.iqm"));
 			precache_sound(W_Sound("hook_impact")); // done by g_hook.qc
 			precache_sound(W_Sound("hook_fire"));
 			precache_sound(W_Sound("hookbomb_fire"));
diff --git a/qcsrc/common/weapons/weapon/machinegun.qc b/qcsrc/common/weapons/weapon/machinegun.qc
index a0bad57faa..01efced0f5 100644
--- a/qcsrc/common/weapons/weapon/machinegun.qc
+++ b/qcsrc/common/weapons/weapon/machinegun.qc
@@ -90,7 +90,7 @@ void W_MachineGun_MuzzleFlash(void)
 		self.muzzle_flash = spawn();
 
 	// muzzle flash for 1st person view
-	setmodel(self.muzzle_flash, "models/uziflash.md3"); // precision set below
+	setmodel(self.muzzle_flash, MDL_MACHINEGUN_MUZZLEFLASH); // precision set below
 
 	self.muzzle_flash.scale = 0.75;
 	self.muzzle_flash.think = W_MachineGun_MuzzleFlash_Think;
@@ -304,10 +304,6 @@ bool W_MachineGun(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model("models/uziflash.md3");
-			precache_model(W_Model("g_uzi.md3"));
-			precache_model(W_Model("v_uzi.md3"));
-			precache_model(W_Model("h_uzi.iqm"));
 			precache_sound(W_Sound("uzi_fire"));
 			MACHINEGUN_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
 			return true;
diff --git a/qcsrc/common/weapons/weapon/minelayer.qc b/qcsrc/common/weapons/weapon/minelayer.qc
index 7d655615c6..1c7e89fde2 100644
--- a/qcsrc/common/weapons/weapon/minelayer.qc
+++ b/qcsrc/common/weapons/weapon/minelayer.qc
@@ -76,7 +76,7 @@ void W_MineLayer_Stick(entity to)
 	newmine.realowner = self.realowner;
 	setsize(newmine, '-4 -4 -4', '4 4 4');
 	setorigin(newmine, self.origin);
-	setmodel(newmine, "models/mine.md3");
+	setmodel(newmine, MDL_MINELAYER_MINE);
 	newmine.angles = vectoangles(-trace_plane_normal); // face against the surface
 
 	newmine.mine_orientation = -trace_plane_normal;
@@ -364,7 +364,7 @@ void W_MineLayer_Attack(void)
 
 	// muzzle flash for 1st person view
 	flash = spawn();
-	setmodel(flash, "models/flash.md3"); // precision set below
+	setmodel(flash, MDL_MINELAYER_MUZZLEFLASH); // precision set below
 	SUB_SetFade(flash, time, 0.1);
 	flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
 	W_AttachToShotorg(flash, '5 0 0');
@@ -530,11 +530,6 @@ bool W_MineLayer(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model("models/flash.md3");
-			precache_model("models/mine.md3");
-			precache_model(W_Model("g_minelayer.md3"));
-			precache_model(W_Model("v_minelayer.md3"));
-			precache_model(W_Model("h_minelayer.iqm"));
 			precache_sound(W_Sound("mine_det"));
 			precache_sound(W_Sound("mine_fire"));
 			precache_sound(W_Sound("mine_stick"));
diff --git a/qcsrc/common/weapons/weapon/mortar.qc b/qcsrc/common/weapons/weapon/mortar.qc
index 1e8f4f91a1..d03eb8e565 100644
--- a/qcsrc/common/weapons/weapon/mortar.qc
+++ b/qcsrc/common/weapons/weapon/mortar.qc
@@ -405,9 +405,6 @@ bool W_Mortar(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_gl.md3"));
-			precache_model(W_Model("v_gl.md3"));
-			precache_model(W_Model("h_gl.iqm"));
 			precache_sound(W_Sound("grenade_bounce1"));
 			precache_sound(W_Sound("grenade_bounce2"));
 			precache_sound(W_Sound("grenade_bounce3"));
diff --git a/qcsrc/common/weapons/weapon/porto.qc b/qcsrc/common/weapons/weapon/porto.qc
index 9bc8f3b1c7..58c28716ae 100644
--- a/qcsrc/common/weapons/weapon/porto.qc
+++ b/qcsrc/common/weapons/weapon/porto.qc
@@ -373,10 +373,6 @@ bool W_Porto(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_porto.md3"));
-			precache_model(W_Model("v_porto.md3"));
-			precache_model(W_Model("h_porto.iqm"));
-			precache_model("models/portal.md3");
 			precache_sound("porto/bounce.wav");
 			precache_sound("porto/create.wav");
 			precache_sound("porto/expire.wav");
diff --git a/qcsrc/common/weapons/weapon/rifle.qc b/qcsrc/common/weapons/weapon/rifle.qc
index 37923e16c8..66be38175f 100644
--- a/qcsrc/common/weapons/weapon/rifle.qc
+++ b/qcsrc/common/weapons/weapon/rifle.qc
@@ -204,9 +204,6 @@ bool W_Rifle(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_sniperrifle.md3"));
-			precache_model(W_Model("v_sniperrifle.md3"));
-			precache_model(W_Model("h_sniperrifle.iqm"));
 			precache_sound(W_Sound("campingrifle_fire"));
 			precache_sound(W_Sound("campingrifle_fire2"));
 			RIFLE_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
diff --git a/qcsrc/common/weapons/weapon/rpc.qc b/qcsrc/common/weapons/weapon/rpc.qc
index 1b336f4edf..51c0404405 100644
--- a/qcsrc/common/weapons/weapon/rpc.qc
+++ b/qcsrc/common/weapons/weapon/rpc.qc
@@ -138,7 +138,7 @@ void W_RocketPropelledChainsaw_Attack (void)
 
 	CSQCProjectile(missile, true, PROJECTILE_RPC, false);
 
-	setmodel(flash, "models/flash.md3"); // precision set below
+	setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
 	SUB_SetFade (flash, time, 0.1);
 	flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
 	W_AttachToShotorg(flash, '5 0 0');
@@ -182,10 +182,6 @@ bool W_RocketPropelledChainsaw(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model ("models/flash.md3");
-			precache_model(W_Model("g_ok_rl.md3"));
-			precache_model(W_Model("v_ok_rl.md3"));
-			precache_model(W_Model("h_ok_rl.iqm"));
 			precache_sound (W_Sound("rocket_fire"));
 			RPC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
 			return true;
diff --git a/qcsrc/common/weapons/weapon/seeker.qc b/qcsrc/common/weapons/weapon/seeker.qc
index 7350cb1bc0..0687437afb 100644
--- a/qcsrc/common/weapons/weapon/seeker.qc
+++ b/qcsrc/common/weapons/weapon/seeker.qc
@@ -662,9 +662,6 @@ bool W_Seeker(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_seeker.md3"));
-			precache_model(W_Model("v_seeker.md3"));
-			precache_model(W_Model("h_seeker.iqm"));
 			precache_sound(W_Sound("tag_fire"));
 			precache_sound(W_Sound("flac_fire"));
 			precache_sound(W_Sound("seeker_fire"));
diff --git a/qcsrc/common/weapons/weapon/shockwave.qc b/qcsrc/common/weapons/weapon/shockwave.qc
index 4103370801..b56a41fbbf 100644
--- a/qcsrc/common/weapons/weapon/shockwave.qc
+++ b/qcsrc/common/weapons/weapon/shockwave.qc
@@ -708,10 +708,6 @@ bool W_Shockwave(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model("models/uziflash.md3");
-			precache_model(W_Model("g_shotgun.md3"));
-			precache_model(W_Model("v_shotgun.md3"));
-			precache_model(W_Model("h_shotgun.iqm"));
 			precache_sound("misc/itempickup.wav");
 			precache_sound(W_Sound("lasergun_fire"));
 			precache_sound(W_Sound("shotgun_melee"));
diff --git a/qcsrc/common/weapons/weapon/shotgun.qc b/qcsrc/common/weapons/weapon/shotgun.qc
index d61a2521dd..814d573036 100644
--- a/qcsrc/common/weapons/weapon/shotgun.qc
+++ b/qcsrc/common/weapons/weapon/shotgun.qc
@@ -74,7 +74,7 @@ void W_Shotgun_Attack(float isprimary)
 
 	// muzzle flash for 1st person view
 	flash = spawn();
-	setmodel(flash, "models/uziflash.md3"); // precision set below
+	setmodel(flash, MDL_SHOTGUN_MUZZLEFLASH); // precision set below
 	flash.think = SUB_Remove;
 	flash.nextthink = time + 0.06;
 	flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
@@ -286,10 +286,6 @@ float W_Shotgun(float req)
 		}
 		case WR_INIT:
 		{
-			precache_model("models/uziflash.md3");
-			precache_model(W_Model("g_shotgun.md3"));
-			precache_model(W_Model("v_shotgun.md3"));
-			precache_model(W_Model("h_shotgun.iqm"));
 			precache_sound("misc/itempickup.wav");
 			precache_sound(W_Sound("shotgun_fire"));
 			precache_sound(W_Sound("shotgun_melee"));
diff --git a/qcsrc/common/weapons/weapon/tuba.qc b/qcsrc/common/weapons/weapon/tuba.qc
index 2987d0b816..20100bf39f 100644
--- a/qcsrc/common/weapons/weapon/tuba.qc
+++ b/qcsrc/common/weapons/weapon/tuba.qc
@@ -411,13 +411,6 @@ bool W_Tuba(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model(W_Model("g_tuba.md3"));
-			precache_model(W_Model("v_tuba.md3"));
-			precache_model(W_Model("h_tuba.iqm"));
-			precache_model(W_Model("v_akordeon.md3"));
-			precache_model(W_Model("h_akordeon.iqm"));
-			precache_model(W_Model("v_kleinbottle.md3"));
-			precache_model(W_Model("h_kleinbottle.iqm"));
 			TUBA_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
 			return true;
 		}
diff --git a/qcsrc/common/weapons/weapon/vaporizer.qc b/qcsrc/common/weapons/weapon/vaporizer.qc
index b057f2edb5..13c3fef8c6 100644
--- a/qcsrc/common/weapons/weapon/vaporizer.qc
+++ b/qcsrc/common/weapons/weapon/vaporizer.qc
@@ -362,10 +362,6 @@ float W_Vaporizer(float req)
 		}
 		case WR_INIT:
 		{
-			precache_model("models/nexflash.md3");
-			precache_model(W_Model("g_minstanex.md3"));
-			precache_model(W_Model("v_minstanex.md3"));
-			precache_model(W_Model("h_minstanex.iqm"));
 			precache_sound(W_Sound("minstanexfire"));
 			precache_sound(W_Sound("nexwhoosh1"));
 			precache_sound(W_Sound("nexwhoosh2"));
diff --git a/qcsrc/common/weapons/weapon/vortex.qc b/qcsrc/common/weapons/weapon/vortex.qc
index 03cd25066b..2e515137c5 100644
--- a/qcsrc/common/weapons/weapon/vortex.qc
+++ b/qcsrc/common/weapons/weapon/vortex.qc
@@ -253,10 +253,6 @@ bool W_Vortex(int req)
 		}
 		case WR_INIT:
 		{
-			precache_model("models/nexflash.md3");
-			precache_model(W_Model("g_nex.md3"));
-			precache_model(W_Model("v_nex.md3"));
-			precache_model(W_Model("h_nex.iqm"));
 			precache_sound(W_Sound("nexfire"));
 			precache_sound(W_Sound("nexcharge"));
 			precache_sound(W_Sound("nexwhoosh1"));
diff --git a/qcsrc/dpdefs/csprogsdefs.qh b/qcsrc/dpdefs/csprogsdefs.qh
index f48df8e5cc..6ad27242aa 100644
--- a/qcsrc/dpdefs/csprogsdefs.qh
+++ b/qcsrc/dpdefs/csprogsdefs.qh
@@ -9,8 +9,8 @@
 #define FALSE _FALSE
 
 #define spawn _spawn
-
 #define particleeffectnum _particleeffectnum
+#define setmodel _setmodel
 
 #include "upstream/csprogsdefs.qc"
 
@@ -20,8 +20,8 @@
 #undef FALSE
 
 #undef spawn
-
 #undef particleeffectnum
+#undef setmodel
 
 #pragma noref 0
 
diff --git a/qcsrc/dpdefs/progsdefs.qh b/qcsrc/dpdefs/progsdefs.qh
index 3592c7015b..5a93a2444c 100644
--- a/qcsrc/dpdefs/progsdefs.qh
+++ b/qcsrc/dpdefs/progsdefs.qh
@@ -9,6 +9,7 @@
 #define FALSE _FALSE
 
 #define spawn _spawn
+#define setmodel _setmodel
 
 #include "upstream/progsdefs.qc"
 
@@ -18,6 +19,7 @@
 #undef FALSE
 
 #undef spawn
+#undef setmodel
 
 #pragma noref 0
 
diff --git a/qcsrc/server/_all.qh b/qcsrc/server/_all.qh
index a331362151..9d7617e006 100644
--- a/qcsrc/server/_all.qh
+++ b/qcsrc/server/_all.qh
@@ -9,4 +9,6 @@
 #include "../dpdefs/progsdefs.qh"
 #include "../dpdefs/dpextensions.qh"
 
+#include "../common/models/models.qh"
+
 #endif
diff --git a/qcsrc/server/bot/aim.qc b/qcsrc/server/bot/aim.qc
index a30f399383..4f750cdb4d 100644
--- a/qcsrc/server/bot/aim.qc
+++ b/qcsrc/server/bot/aim.qc
@@ -40,7 +40,7 @@ float findtrajectorywithleading(vector org, vector m1, vector m2, entity targ, f
 		tracetossfaketarget = spawn();
 	tracetossfaketarget.solid = savesolid;
 	tracetossfaketarget.movetype = targ.movetype;
-	setmodel(tracetossfaketarget, targ.model); // no low precision
+	_setmodel(tracetossfaketarget, targ.model); // no low precision
 	tracetossfaketarget.model = targ.model;
 	tracetossfaketarget.modelindex = targ.modelindex;
 	setsize(tracetossfaketarget, targ.mins, targ.maxs);
diff --git a/qcsrc/server/bot/waypoints.qc b/qcsrc/server/bot/waypoints.qc
index 957f2478d2..b34af78bbc 100644
--- a/qcsrc/server/bot/waypoints.qc
+++ b/qcsrc/server/bot/waypoints.qc
@@ -66,7 +66,7 @@ entity waypoint_spawn(vector m1, vector m2, float f)
 	{
 		m1 = w.mins;
 		m2 = w.maxs;
-		setmodel(w, "models/runematch/rune.mdl"); w.effects = EF_LOWPRECISION;
+		setmodel(w, MDL_WAYPOINT); w.effects = EF_LOWPRECISION;
 		setsize(w, m1, m2);
 		if (w.wpflags & WAYPOINTFLAG_ITEM)
 			w.colormod = '1 0 0';
@@ -269,7 +269,7 @@ void waypoint_schedulerelink(entity wp)
 		vector m1, m2;
 		m1 = wp.mins;
 		m2 = wp.maxs;
-		setmodel(wp, "models/runematch/rune.mdl"); wp.effects = EF_LOWPRECISION;
+		setmodel(wp, MDL_WAYPOINT); wp.effects = EF_LOWPRECISION;
 		setsize(wp, m1, m2);
 		if (wp.wpflags & WAYPOINTFLAG_ITEM)
 			wp.colormod = '1 0 0';
diff --git a/qcsrc/server/cheats.qc b/qcsrc/server/cheats.qc
index a87b304bcb..26af000d2d 100644
--- a/qcsrc/server/cheats.qc
+++ b/qcsrc/server/cheats.qc
@@ -409,7 +409,7 @@ float CheatCommand(float argc)
 			e.think = DragBox_Think;
 			e.nextthink = time;
 			e.solid = -1; // black
-			setmodel(e, "null"); // network it
+			setmodel(e, MDL_Null); // network it
 			if(argc == 4)
 				e.cnt = stof(argv(1));
 			else
@@ -418,7 +418,7 @@ float CheatCommand(float argc)
 			e.aiment = spawn();
 			e.aiment.classname = "dragbox_corner_1";
 			e.aiment.owner = e;
-			setmodel(e.aiment, "models/marker.md3");
+			setmodel(e.aiment, MDL_MARKER);
 			e.aiment.skin = 0;
 			setsize(e.aiment, '0 0 0', '0 0 0');
 			if(argc == 4)
@@ -432,7 +432,7 @@ float CheatCommand(float argc)
 			e.enemy = spawn();
 			e.enemy.classname = "dragbox_corner_2";
 			e.enemy.owner = e;
-			setmodel(e.enemy, "models/marker.md3");
+			setmodel(e.enemy, MDL_MARKER);
 			e.enemy.skin = 1;
 			setsize(e.enemy, '0 0 0', '0 0 0');
 			end = normalize(self.origin + self.view_ofs - e.aiment.origin);
@@ -464,7 +464,7 @@ float CheatCommand(float argc)
 			e.think = DragBox_Think;
 			e.nextthink = time;
 			e.solid = 0; // nothing special
-			setmodel(e, "models/marker.md3");
+			setmodel(e, MDL_MARKER);
 			setsize(e, PL_MIN, PL_MAX);
 			e.skin = 2;
 			if(argc == 3)
@@ -1084,19 +1084,19 @@ void DragBox_Think()
 	if(self.cnt == -1) // actually race_place -1
 	{
 		// show "10 10" for qualifying spawns
-		setmodel(self.killindicator, "models/sprites/10.spr32");
-		setmodel(self.killindicator.killindicator, "models/sprites/10.spr32");
+		setmodel(self.killindicator, MDL_NUM(10));
+		setmodel(self.killindicator.killindicator, MDL_NUM(10));
 	}
 	else if(self.cnt == -2) // actually race_place 0
 	{
 		// show "10 0" for loser spawns
-		setmodel(self.killindicator, "models/sprites/10.spr32");
-		setmodel(self.killindicator.killindicator, "models/sprites/0.spr32");
+		setmodel(self.killindicator, MDL_NUM(10));
+		setmodel(self.killindicator.killindicator, MDL_NUM(0));
 	}
 	else
 	{
-		setmodel(self.killindicator, strcat("models/sprites/", ftos(self.cnt % 10), ".spr32"));
-		setmodel(self.killindicator.killindicator, strcat("models/sprites/", ftos(floor(self.cnt / 10)), ".spr32"));
+		setmodel(self.killindicator, MDL_NUM(self.cnt % 10));
+		setmodel(self.killindicator.killindicator, MDL_NUM(floor(self.cnt / 10)));
 	}
 
 	self.nextthink = time;
diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc
index 7aefe7bd30..bd9c46a9b0 100644
--- a/qcsrc/server/cl_client.qc
+++ b/qcsrc/server/cl_client.qc
@@ -172,7 +172,7 @@ string CheckPlayerModel(string plyermodel) {
 void setplayermodel(entity e, string modelname)
 {
 	precache_model(modelname);
-	setmodel(e, modelname);
+	_setmodel(e, modelname);
 	player_setupanimsformodel();
 	UpdatePlayerSounds();
 }
@@ -292,7 +292,7 @@ void PutObserverInServer (void)
 	self.weapons = '0 0 0';
 	self.model = "";
 	FixPlayermodel();
-	setmodel(self, "null");
+	setmodel(self, MDL_Null);
 	self.drawonlytoclient = self;
 
 	setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX); // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY
@@ -856,7 +856,7 @@ void KillIndicator_Think()
 	else
 	{
 		if(self.cnt <= 10)
-			setmodel(self, strcat("models/sprites/", ftos(self.cnt), ".spr32"));
+			setmodel(self, MDL_NUM(self.cnt));
 		if(IS_REAL_CLIENT(self.owner))
 		{
 			if(self.cnt <= 10)
@@ -1378,7 +1378,7 @@ void ChatBubbleThink()
 	}
 
 	if ( self.model != self.mdl )
-		setmodel(self, self.mdl);
+		_setmodel(self, self.mdl);
 
 }
 
@@ -1394,7 +1394,7 @@ void UpdateChatBubble()
 		self.chatbubbleentity.exteriormodeltoclient = self;
 		self.chatbubbleentity.think = ChatBubbleThink;
 		self.chatbubbleentity.nextthink = time;
-		setmodel(self.chatbubbleentity, "models/misc/chatbubble.spr"); // precision set below
+		setmodel(self.chatbubbleentity, MDL_CHAT); // precision set below
 		//setorigin(self.chatbubbleentity, self.origin + '0 0 15' + self.maxs_z * '0 0 1');
 		setorigin(self.chatbubbleentity, '0 0 15' + self.maxs_z * '0 0 1');
 		setattachment(self.chatbubbleentity, self, "");  // sticks to moving player better, also conserves bandwidth
diff --git a/qcsrc/server/cl_impulse.qc b/qcsrc/server/cl_impulse.qc
index 0271f085bd..bc71664b72 100644
--- a/qcsrc/server/cl_impulse.qc
+++ b/qcsrc/server/cl_impulse.qc
@@ -355,7 +355,7 @@ void ImpulseCommands (void)
 							setorigin(e, org);
 							LOG_INFO("spawn without waypoint: ", etos(e), " ", vtos(e.origin), "\n");
 							e.effects |= EF_NODEPTHTEST;
-							setmodel(e, self.model);
+							_setmodel(e, self.model);
 							e.frame = self.frame;
 							e.skin = self.skin;
 							e.colormod = '8 0.5 8';
diff --git a/qcsrc/server/command/sv_cmd.qc b/qcsrc/server/command/sv_cmd.qc
index 8287643b99..d08588ff99 100644
--- a/qcsrc/server/command/sv_cmd.qc
+++ b/qcsrc/server/command/sv_cmd.qc
@@ -816,11 +816,11 @@ void GameCommand_gettaginfo(float request, float argc)
 			{
 				tmp_entity = spawn();
 				if(argv(1) == "w")
-					setmodel(tmp_entity, (nextent(world)).weaponentity.model);
+					_setmodel(tmp_entity, (nextent(world)).weaponentity.model);
 				else
 				{
 					precache_model(argv(1));
-					setmodel(tmp_entity, argv(1));
+					_setmodel(tmp_entity, argv(1));
 				}
 				tmp_entity.frame = stof(argv(2));
 				if(substring(argv(3), 0, 1) == "#")
@@ -874,11 +874,11 @@ void GameCommand_animbench(float request, float argc)
 			{
 				tmp_entity = spawn();
 				if(argv(1) == "w")
-					setmodel(tmp_entity, (nextent(world)).weaponentity.model);
+					_setmodel(tmp_entity, (nextent(world)).weaponentity.model);
 				else
 				{
 					precache_model(argv(1));
-					setmodel(tmp_entity, argv(1));
+					_setmodel(tmp_entity, argv(1));
 				}
 				float f1 = stof(argv(2));
 				float f2 = stof(argv(3));
diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc
index 5e10f41a04..b5d87eed17 100644
--- a/qcsrc/server/g_damage.qc
+++ b/qcsrc/server/g_damage.qc
@@ -569,7 +569,7 @@ void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypo
 	ice.think = Ice_Think;
 	ice.nextthink = time;
 	ice.frame = floor(random() * 21); // ice model has 20 different looking frames
-	setmodel(ice, "models/ice/ice.md3");
+	setmodel(ice, MDL_ICE);
 	ice.alpha = 1;
 	ice.colormod = Team_ColorRGB(targ.team);
 	ice.glowmod = ice.colormod;
diff --git a/qcsrc/server/g_hook.qc b/qcsrc/server/g_hook.qc
index 543432e405..6a95a61fe0 100644
--- a/qcsrc/server/g_hook.qc
+++ b/qcsrc/server/g_hook.qc
@@ -375,7 +375,7 @@ void FireGrapplingHook (void)
 	missile.movetype = ((autocvar_g_balance_grapplehook_gravity) ? MOVETYPE_TOSS : MOVETYPE_FLY);
 	PROJECTILE_MAKETRIGGER(missile);
 
-	//setmodel (missile, "models/hook.md3"); // precision set below
+	//setmodel (missile, MDL_HOOK); // precision set below
 	setsize (missile, '-3 -3 -3', '3 3 3');
 	setorigin (missile, org);
 
diff --git a/qcsrc/server/g_subs.qc b/qcsrc/server/g_subs.qc
index fc70c758a4..723087a963 100644
--- a/qcsrc/server/g_subs.qc
+++ b/qcsrc/server/g_subs.qc
@@ -354,13 +354,13 @@ void LODmodel_attach()
 		ma = self.maxs;
 
 		precache_model(self.lodmodel1);
-		setmodel(self, self.lodmodel1);
+		_setmodel(self, self.lodmodel1);
 		self.lodmodelindex1 = self.modelindex;
 
 		if(self.lodmodel2 != "")
 		{
 			precache_model(self.lodmodel2);
-			setmodel(self, self.lodmodel2);
+			_setmodel(self, self.lodmodel2);
 			self.lodmodelindex2 = self.modelindex;
 		}
 
@@ -409,11 +409,11 @@ void SetBrushEntityModel()
 		{
 			vector mi = self.mins;
 			vector ma = self.maxs;
-			setmodel(self, self.model); // no precision needed
+			_setmodel(self, self.model); // no precision needed
 			setsize(self, mi, ma);
 		}
 		else
-			setmodel(self, self.model); // no precision needed
+			_setmodel(self, self.model); // no precision needed
 		InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
  	}
 	setorigin(self, self.origin);
@@ -429,11 +429,11 @@ void SetBrushEntityModelNoLOD()
 		{
 			vector mi = self.mins;
 			vector ma = self.maxs;
-			setmodel(self, self.model); // no precision needed
+			_setmodel(self, self.model); // no precision needed
 			setsize(self, mi, ma);
 		}
 		else
-			setmodel(self, self.model); // no precision needed
+			_setmodel(self, self.model); // no precision needed
  	}
 	setorigin(self, self.origin);
 	ApplyMinMaxScaleAngles(self);
diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc
index 81f5c71f40..b5a2806d76 100644
--- a/qcsrc/server/g_world.qc
+++ b/qcsrc/server/g_world.qc
@@ -662,7 +662,6 @@ void spawnfunc_worldspawn (void)
 
 	PlayerStats_GameReport_Init(); // we need this to be initiated before InitGameplayMode
 
-	precache_model ("null"); // we need this one before InitGameplayMode
 	InitGameplayMode();
 	readlevelcvars();
 	GrappleHookInit();
diff --git a/qcsrc/server/item_key.qc b/qcsrc/server/item_key.qc
index eccfbd91c7..6a1527745e 100644
--- a/qcsrc/server/item_key.qc
+++ b/qcsrc/server/item_key.qc
@@ -103,7 +103,7 @@ void spawn_item_key()
 
 	self.mdl = self.model;
 	self.effects = EF_LOWPRECISION;
-	setmodel(self, self.model);
+	_setmodel(self, self.model);
 	//setsize(self, '-16 -16 -24', '16 16 32');
 	setorigin(self, self.origin + '0 0 32');
 	setsize(self, '-16 -16 -56', '16 16 0');
diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc
index e76545c73e..356a2b74af 100644
--- a/qcsrc/server/miscfunctions.qc
+++ b/qcsrc/server/miscfunctions.qc
@@ -972,8 +972,6 @@ void precache_all_playermodels(string pattern)
 void precache()
 {SELFPARAM();
     // gamemode related things
-    precache_model ("models/misc/chatbubble.spr");
-	precache_model("models/ice/ice.md3");
 
     // Precache all player models if desired
     if (autocvar_sv_precacheplayermodels)
@@ -1014,7 +1012,6 @@ void precache()
 
     // gore and miscellaneous sounds
     //precache_sound ("misc/h2ohit.wav");
-    precache_model ("models/hook.md3");
     precache_sound ("misc/armorimpact.wav");
     precache_sound ("misc/bodyimpact1.wav");
     precache_sound ("misc/bodyimpact2.wav");
@@ -1033,18 +1030,6 @@ void precache()
     precache_sound ("player/lava.wav");
     precache_sound ("player/slime.wav");
 
-    precache_model ("models/sprites/0.spr32");
-    precache_model ("models/sprites/1.spr32");
-    precache_model ("models/sprites/2.spr32");
-    precache_model ("models/sprites/3.spr32");
-    precache_model ("models/sprites/4.spr32");
-    precache_model ("models/sprites/5.spr32");
-    precache_model ("models/sprites/6.spr32");
-    precache_model ("models/sprites/7.spr32");
-    precache_model ("models/sprites/8.spr32");
-    precache_model ("models/sprites/9.spr32");
-    precache_model ("models/sprites/10.spr32");
-
     // common weapon precaches
 	precache_sound (W_Sound("reload")); // until weapons have individual reload sounds, precache the reload sound here
     precache_sound (W_Sound("weapon_switch"));
@@ -1057,10 +1042,6 @@ void precache()
         precache_sound (W_Sound("hook_impact")); // hook
     }
 
-    precache_model("models/elaser.mdl");
-    precache_model("models/laser.mdl");
-    precache_model("models/ebomb.mdl");
-
 #if 0
     // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
 
@@ -1233,7 +1214,7 @@ void Net_LinkEntity(entity e, bool docull, float dt, bool(entity, int) sendfunc)
     {
         mi = e.mins;
         ma = e.maxs;
-        setmodel(e, "null");
+        setmodel(e, MDL_Null);
         setsize(e, mi, ma);
     }
 
@@ -1834,7 +1815,7 @@ void modeleffect_spawn(string m, float s, float f, vector o, vector v, vector an
 	float sz;
 	e = spawn();
 	e.classname = "modeleffect";
-	setmodel(e, m);
+	_setmodel(e, m);
 	e.frame = f;
 	setorigin(e, o);
 	e.velocity = v;
diff --git a/qcsrc/server/mutators/gamemode_assault.qc b/qcsrc/server/mutators/gamemode_assault.qc
index 239c3d3b4b..844043222a 100644
--- a/qcsrc/server/mutators/gamemode_assault.qc
+++ b/qcsrc/server/mutators/gamemode_assault.qc
@@ -317,7 +317,7 @@ void spawnfunc_func_assault_wall()
 
 	self.classname = "func_assault_wall";
 	self.mdl = self.model;
-	setmodel(self, self.mdl);
+	_setmodel(self, self.mdl);
 	self.solid = SOLID_BSP;
 	self.think = assault_wall_think;
 	self.nextthink = time;
diff --git a/qcsrc/server/mutators/gamemode_ctf.qc b/qcsrc/server/mutators/gamemode_ctf.qc
index 4f4eab3561..060752c111 100644
--- a/qcsrc/server/mutators/gamemode_ctf.qc
+++ b/qcsrc/server/mutators/gamemode_ctf.qc
@@ -214,7 +214,7 @@ void ctf_CaptureShield_Spawn(entity flag)
 	shield.scale = 0.5;
 
 	setorigin(shield, self.origin);
-	setmodel(shield, "models/ctf/shield.md3");
+	setmodel(shield, MDL_CTF_SHIELD);
 	setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
 }
 
@@ -1150,11 +1150,9 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e
 	precache_sound(flag.snd_flag_touch);
 	precache_sound(flag.snd_flag_pass);
 	precache_model(flag.model);
-	precache_model("models/ctf/shield.md3");
-	precache_model("models/ctf/shockwavetransring.md3");
 
 	// appearence
-	setmodel(flag, flag.model); // precision set below
+	_setmodel(flag, flag.model); // precision set below
 	setsize(flag, FLAG_MIN, FLAG_MAX);
 	setorigin(flag, (flag.origin + FLAG_SPAWN_OFFSET));
 
diff --git a/qcsrc/server/mutators/gamemode_domination.qc b/qcsrc/server/mutators/gamemode_domination.qc
index 322c7e0dd6..6fa778309f 100644
--- a/qcsrc/server/mutators/gamemode_domination.qc
+++ b/qcsrc/server/mutators/gamemode_domination.qc
@@ -252,7 +252,7 @@ void dom_controlpoint_setup()
 
 	// copy important properties from spawnfunc_dom_team entity
 	self.goalentity = head;
-	setmodel(self, head.mdl); // precision already set
+	_setmodel(self, head.mdl); // precision already set
 	self.skin = head.skin;
 
 	self.cnt = -1;
@@ -505,7 +505,7 @@ void spawnfunc_dom_team()
 	if (self.noise1 != "")
 		precache_sound(self.noise1);
 	self.classname = "dom_team";
-	setmodel(self, self.model); // precision not needed
+	_setmodel(self, self.model); // precision not needed
 	self.mdl = self.model;
 	self.dmg = self.modelindex;
 	self.model = "";
@@ -555,7 +555,7 @@ void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float p
 	self.message = capmessage;
 
 	// this code is identical to spawnfunc_dom_team
-	setmodel(self, self.model); // precision not needed
+	_setmodel(self, self.model); // precision not needed
 	self.mdl = self.model;
 	self.dmg = self.modelindex;
 	self.model = "";
@@ -622,11 +622,6 @@ void dom_DelayedInit() // Do this check with a delay so we can wait for teams to
 
 void dom_Initialize()
 {
-	precache_model("models/domination/dom_red.md3");
-	precache_model("models/domination/dom_blue.md3");
-	precache_model("models/domination/dom_yellow.md3");
-	precache_model("models/domination/dom_pink.md3");
-	precache_model("models/domination/dom_unclaimed.md3");
 	precache_sound("domination/claim.wav");
 
 	InitializeEntity(world, dom_DelayedInit, INITPRIO_GAMETYPE);
diff --git a/qcsrc/server/mutators/gamemode_keepaway.qc b/qcsrc/server/mutators/gamemode_keepaway.qc
index 3ab6342b3b..6d7c8c9901 100644
--- a/qcsrc/server/mutators/gamemode_keepaway.qc
+++ b/qcsrc/server/mutators/gamemode_keepaway.qc
@@ -396,7 +396,7 @@ void ka_SpawnBall() // loads various values for the ball, runs only once at star
 	e = spawn();
 	e.model = "models/orbs/orbblue.md3";
 	precache_model(e.model);
-	setmodel(e, e.model);
+	_setmodel(e, e.model);
 	setsize(e, '-16 -16 -20', '16 16 20'); // 20 20 20 was too big, player is only 16 16 24... gotta cheat with the Z (20) axis so that the particle isn't cut off
 	e.classname = "keepawayball";
 	e.damageforcescale = autocvar_g_keepawayball_damageforcescale;
diff --git a/qcsrc/server/mutators/gamemode_keyhunt.qc b/qcsrc/server/mutators/gamemode_keyhunt.qc
index 92125926f7..56e55d86d9 100644
--- a/qcsrc/server/mutators/gamemode_keyhunt.qc
+++ b/qcsrc/server/mutators/gamemode_keyhunt.qc
@@ -1009,11 +1009,6 @@ void kh_Initialize()  // sets up th KH environment
 	precache_sound(kh_sound_collect);
 	precache_sound(kh_sound_alarm);  // the new siren
 
-#ifdef KH_PLAYER_USE_CARRIEDMODEL
-	precache_model("models/keyhunt/key-carried.md3");
-#endif
-	precache_model("models/keyhunt/key.md3");
-
 	// setup variables
 	kh_teams = autocvar_g_keyhunt_teams_override;
 	if(kh_teams < 2)
@@ -1025,7 +1020,7 @@ void kh_Initialize()  // sets up th KH environment
 	kh_controller.think = kh_Controller_Think;
 	kh_Controller_SetThink(0, kh_WaitForPlayers);
 
-	setmodel(kh_controller, "models/keyhunt/key.md3");
+	setmodel(kh_controller, MDL_KH_KEY);
 	kh_key_dropped = kh_controller.modelindex;
 	/*
 	dprint(vtos(kh_controller.mins));
@@ -1033,7 +1028,7 @@ void kh_Initialize()  // sets up th KH environment
 	dprint("\n");
 	*/
 #ifdef KH_PLAYER_USE_CARRIEDMODEL
-	setmodel(kh_controller, "models/keyhunt/key-carried.md3");
+	setmodel(kh_controller, MDL_KH_KEY_CARRIED);
 	kh_key_carried = kh_controller.modelindex;
 #else
 	kh_key_carried = kh_key_dropped;
diff --git a/qcsrc/server/mutators/gamemode_nexball.qc b/qcsrc/server/mutators/gamemode_nexball.qc
index fad911386c..e3480a42e0 100644
--- a/qcsrc/server/mutators/gamemode_nexball.qc
+++ b/qcsrc/server/mutators/gamemode_nexball.qc
@@ -495,7 +495,7 @@ void SpawnBall(void)
 	}
 
 	precache_model(self.model);
-	setmodel(self, self.model);
+	_setmodel(self, self.model);
 	setsize(self, BALL_MINS, BALL_MAXS);
 	ball_scale = self.scale;
 
@@ -860,10 +860,6 @@ float w_nexball_weapon(float req)
 	}
 	else if(req == WR_INIT)
 	{
-		precache_model(W_Model("g_porto.md3"));
-		precache_model(W_Model("v_porto.md3"));
-		precache_model(W_Model("h_porto.iqm"));
-		precache_model("models/elaser.mdl");
 		precache_sound("nexball/shoot1.wav");
 		precache_sound("nexball/shoot2.wav");
 		precache_sound("misc/typehit.wav");
diff --git a/qcsrc/server/mutators/gamemode_onslaught.qc b/qcsrc/server/mutators/gamemode_onslaught.qc
index 76a7a65d57..e5d127748b 100644
--- a/qcsrc/server/mutators/gamemode_onslaught.qc
+++ b/qcsrc/server/mutators/gamemode_onslaught.qc
@@ -66,7 +66,7 @@ void ons_CaptureShield_Spawn(entity generator, bool is_generator)
 
 	precache_model(shield.model);
 	setorigin(shield, generator.origin);
-	setmodel(shield, shield.model);
+	_setmodel(shield, shield.model);
 	setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
 }
 
@@ -84,7 +84,7 @@ void ons_debug(string input)
 	}
 }
 
-void setmodel_fixsize(entity e, string m)
+void setmodel_fixsize(entity e, Model m)
 {
 	setmodel(e, m);
 	FixSize(e);
@@ -409,7 +409,7 @@ void ons_ControlPoint_Icon_Damage(entity inflictor, entity attacker, float damag
 
 		self.owner.waslinked = self.owner.islinked;
 		if(self.owner.model != "models/onslaught/controlpoint_pad.md3")
-			setmodel_fixsize(self.owner, "models/onslaught/controlpoint_pad.md3");
+			setmodel_fixsize(self.owner, MDL_ONS_CP_PAD1);
 		//setsize(self, '-32 -32 0', '32 32 8');
 
 		remove(self);
@@ -546,8 +546,8 @@ void ons_ControlPoint_Icon_BuildThink()
 
 		self.SendFlags |= CPSF_SETUP;
 	}
-	if(self.owner.model != "models/onslaught/controlpoint_pad2.md3")
-		setmodel_fixsize(self.owner, "models/onslaught/controlpoint_pad2.md3");
+	if(self.owner.model != MDL_ONS_CP_PAD2.model_str())
+		setmodel_fixsize(self.owner, MDL_ONS_CP_PAD2);
 
 	if(random() < 0.9 - self.health / self.max_health)
 		Send_Effect(EFFECT_RAGE, self.origin + 10 * randomvec(), '0 0 -1', 1);
@@ -704,7 +704,7 @@ void ons_ControlPoint_Reset()
 	self.think = ons_ControlPoint_Think;
 	self.ons_toucher = world;
 	self.nextthink = time + ONS_CP_THINKRATE;
-	setmodel_fixsize(self, "models/onslaught/controlpoint_pad.md3");
+	setmodel_fixsize(self, MDL_ONS_CP_PAD1);
 
 	WaypointSprite_UpdateMaxHealth(self.sprite, 0);
 	WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
@@ -752,16 +752,6 @@ void ons_ControlPoint_Setup(entity cp)
 	if(cp.message == "") { cp.message = "a"; }
 
 	// precache - TODO: clean up!
-	precache_model("models/onslaught/controlpoint_pad.md3");
-	precache_model("models/onslaught/controlpoint_pad2.md3");
-	precache_model("models/onslaught/controlpoint_shield.md3");
-	precache_model("models/onslaught/controlpoint_icon.md3");
-	precache_model("models/onslaught/controlpoint_icon_dmg1.md3");
-	precache_model("models/onslaught/controlpoint_icon_dmg2.md3");
-	precache_model("models/onslaught/controlpoint_icon_dmg3.md3");
-	precache_model("models/onslaught/controlpoint_icon_gib1.md3");
-	precache_model("models/onslaught/controlpoint_icon_gib2.md3");
-	precache_model("models/onslaught/controlpoint_icon_gib4.md3");
 	precache_sound("onslaught/controlpoint_build.wav");
 	precache_sound("onslaught/controlpoint_built.wav");
 	precache_sound(W_Sound("grenade_impact"));
@@ -771,7 +761,7 @@ void ons_ControlPoint_Setup(entity cp)
 	precache_sound("onslaught/ons_spark2.wav");
 
 	// appearence
-	setmodel_fixsize(cp, "models/onslaught/controlpoint_pad.md3");
+	setmodel_fixsize(cp, MDL_ONS_CP_PAD1);
 
 	// control point placement
 	if((cp.spawnflags & 1) || cp.noalign) // don't drop to floor, just stay at fixed location
@@ -1019,10 +1009,6 @@ void ons_GeneratorSetup(entity gen) // called when spawning a generator entity o
 	gen.touch = onslaught_generator_touch;
 
 	// precache - TODO: clean up!
-	precache_model("models/onslaught/generator_shield.md3");
-	precache_model("models/onslaught/gen_gib1.md3");
-	precache_model("models/onslaught/gen_gib2.md3");
-	precache_model("models/onslaught/gen_gib3.md3");
 	precache_sound("onslaught/generator_decay.wav");
 	precache_sound(W_Sound("grenade_impact"));
 	precache_sound(W_Sound("rocket_impact"));
diff --git a/qcsrc/server/mutators/mutator_buffs.qc b/qcsrc/server/mutators/mutator_buffs.qc
index 3464a6478e..79004e1c41 100644
--- a/qcsrc/server/mutators/mutator_buffs.qc
+++ b/qcsrc/server/mutators/mutator_buffs.qc
@@ -47,7 +47,7 @@ bool buffs_BuffModel_Customize()
 void buffs_BuffModel_Spawn(entity player)
 {
 	player.buff_model = spawn();
-	setmodel(player.buff_model, BUFF_MODEL);
+	setmodel(player.buff_model, MDL_BUFF);
 	setsize(player.buff_model, '0 0 -40', '0 0 40');
 	setattachment(player.buff_model, player, "");
 	setorigin(player.buff_model, '0 0 1' * (player.buff_model.maxs.z * 1));
@@ -228,7 +228,7 @@ void buff_Think()
 		self.glowmod = buff_GlowColor(buff);
 		self.skin = buff.m_skin;
 
-		setmodel(self, BUFF_MODEL);
+		setmodel(self, MDL_BUFF);
 
 		if(self.buff_waypoint)
 		{
@@ -368,7 +368,7 @@ void buff_Init(entity ent)
 	if(self.noalign)
 		self.movetype = MOVETYPE_NONE; // reset by random location
 
-	setmodel(self, BUFF_MODEL);
+	setmodel(self, MDL_BUFF);
 	setsize(self, BUFF_MIN, BUFF_MAX);
 
 	if(cvar("g_buffs_random_location") || (self.spawnflags & 64))
@@ -957,7 +957,6 @@ void buffs_DelayedInit()
 
 void buffs_Initialize()
 {
-	precache_model(BUFF_MODEL);
 	precache_sound("misc/strength_respawn.wav");
 	precache_sound("misc/shield_respawn.wav");
 	precache_sound("relics/relic_effect.wav");
diff --git a/qcsrc/server/mutators/mutator_buffs.qh b/qcsrc/server/mutators/mutator_buffs.qh
index 29e59316f2..10d84ef4e5 100644
--- a/qcsrc/server/mutators/mutator_buffs.qh
+++ b/qcsrc/server/mutators/mutator_buffs.qh
@@ -24,8 +24,6 @@
 .int oldbuffs; // for updating effects
 .entity buff_model; // controls effects (TODO: make csqc)
 
-const string BUFF_MODEL = "models/relics/relic.md3";
-
 const vector BUFF_MIN = ('-16 -16 -20');
 const vector BUFF_MAX = ('16 16 20');
 
diff --git a/qcsrc/server/mutators/mutator_nades.qc b/qcsrc/server/mutators/mutator_nades.qc
index 8e49e2aa63..99c7854825 100644
--- a/qcsrc/server/mutators/mutator_nades.qc
+++ b/qcsrc/server/mutators/mutator_nades.qc
@@ -29,7 +29,7 @@ void nade_burn_spawn(entity _nade)
 void nade_spawn(entity _nade)
 {
 	entity timer = spawn();
-	setmodel(timer, "models/ok_nade_counter/ok_nade_counter.md3");
+	setmodel(timer, MDL_NADE_TIMER);
 	setattachment(timer, _nade, "");
 	timer.classname = "nade_timer";
 	timer.colormap = _nade.colormap;
@@ -133,7 +133,7 @@ void nade_napalm_ball()
 	proj.movetype = MOVETYPE_BOUNCE;
 	proj.projectiledeathtype = DEATH_NADE_NAPALM;
 	PROJECTILE_MAKETRIGGER(proj);
-	setmodel(proj, "null");
+	setmodel(proj, MDL_Null);
 	proj.scale = 1;//0.5;
 	setsize(proj, '-4 -4 -4', '4 4 4');
 	setorigin(proj, self.origin);
@@ -331,9 +331,9 @@ void nade_ice_boom()
 
 	if ( autocvar_g_nades_ice_explode )
 	{
-		setmodel(fountain, "models/grenademodel.md3");
+		setmodel(fountain, MDL_PROJECTILE_GRENADE);
 		entity timer = spawn();
-		setmodel(timer, "models/ok_nade_counter/ok_nade_counter.md3");
+		setmodel(timer, MDL_NADE_TIMER);
 		setattachment(timer, fountain, "");
 		timer.classname = "nade_timer";
 		timer.colormap = self.colormap;
@@ -345,7 +345,7 @@ void nade_ice_boom()
 		timer.skin = 10;
 	}
 	else
-		setmodel(fountain, "null");
+		setmodel(fountain, MDL_Null);
 }
 
 void nade_translocate_boom()
@@ -459,7 +459,7 @@ void nade_heal_boom()
 	healer.solid = SOLID_TRIGGER;
 	healer.touch = nade_heal_touch;
 
-	setmodel(healer, "models/ctf/shield.md3");
+	setmodel(healer, MDL_NADE_HEAL);
 	healer.healer_radius = autocvar_g_nades_nade_radius;
 	vector size = '1 1 1' * healer.healer_radius / 2;
 	setsize(healer,-size,size);
@@ -689,7 +689,7 @@ void toss_nade(entity e, vector _velocity, float _time)
 		offset = '0 0 0';
 
 	setorigin(_nade, w_shotorg + offset + (v_right * 25) * -1);
-	//setmodel(_nade, W_Model("v_ok_grenade.md3"));
+	//setmodel(_nade, MDL_PROJECTILE_NADE);
 	//setattachment(_nade, world, "");
 	PROJECTILE_MAKETRIGGER(_nade);
 	setsize(_nade, '-16 -16 -16', '16 16 16');
@@ -826,7 +826,7 @@ void nade_prime()
 
 	n.nade_type = bound(1, n.nade_type, NADES_COUNT);
 
-	setmodel(n, W_Model("v_ok_grenade.md3"));
+	setmodel(n, MDL_PROJECTILE_NADE);
 	//setattachment(n, self, "bip01 l hand");
 	n.exteriormodeltoclient = self;
 	n.customizeentityforclient = nade_customize;
@@ -841,7 +841,7 @@ void nade_prime()
 	n.nextthink = max(n.wait - 3, time);
 	n.projectiledeathtype = DEATH_NADE;
 
-	setmodel(fn, W_Model("h_ok_grenade.iqm"));
+	setmodel(fn, MDL_NADE_VIEW);
 	setattachment(fn, self.weaponentity, "");
 	fn.realowner = fn.owner = self;
 	fn.colormod = NADES[n.nade_type].m_color;
@@ -1199,11 +1199,6 @@ void nades_Initialize()
 	addstat(STAT_HEALING_ORB, AS_FLOAT, stat_healing_orb);
 	addstat(STAT_HEALING_ORB_ALPHA, AS_FLOAT, stat_healing_orb_alpha);
 
-	precache_model("models/ok_nade_counter/ok_nade_counter.md3");
-	precache_model(W_Model("h_ok_grenade.iqm"));
-	precache_model(W_Model("v_ok_grenade.md3"));
-	precache_model("models/ctf/shield.md3");
-
 	precache_sound(W_Sound("rocket_impact"));
 	precache_sound(W_Sound("grenade_bounce1"));
 	precache_sound(W_Sound("grenade_bounce2"));
diff --git a/qcsrc/server/mutators/mutator_overkill.qc b/qcsrc/server/mutators/mutator_overkill.qc
index d7739d8eec..5b7018b303 100644
--- a/qcsrc/server/mutators/mutator_overkill.qc
+++ b/qcsrc/server/mutators/mutator_overkill.qc
@@ -214,7 +214,7 @@ MUTATOR_HOOKFUNCTION(ok_OnEntityPreSpawn)
 		{
 			entity wep = spawn();
 			setorigin(wep, self.origin);
-			setmodel(wep, W_Model("g_ok_hmg.md3"));
+			setmodel(wep, MDL_OK_HMG);
 			wep.classname = "weapon_hmg";
 			wep.ok_item = true;
 			wep.noalign = self.noalign;
@@ -231,7 +231,7 @@ MUTATOR_HOOKFUNCTION(ok_OnEntityPreSpawn)
 		{
 			entity wep = spawn();
 			setorigin(wep, self.origin);
-			setmodel(wep, W_Model("g_ok_rl.md3"));
+			setmodel(wep, MDL_OK_RPC);
 			wep.classname = "weapon_rpc";
 			wep.ok_item = true;
 			wep.noalign = self.noalign;
@@ -316,18 +316,6 @@ void ok_Initialize()
 
 	precache_all_playermodels("models/ok_player/*.dpm");
 
-	precache_model(W_Model("h_ok_mg.iqm"));
-	precache_model(W_Model("v_ok_mg.md3"));
-	precache_model(W_Model("g_ok_mg.md3"));
-
-	precache_model(W_Model("h_ok_shotgun.iqm"));
-	precache_model(W_Model("v_ok_shotgun.md3"));
-	precache_model(W_Model("g_ok_shotgun.md3"));
-
-	precache_model(W_Model("h_ok_sniper.iqm"));
-	precache_model(W_Model("v_ok_sniper.md3"));
-	precache_model(W_Model("g_ok_sniper.md3"));
-
 	precache_sound(W_Sound("dryfire"));
 
 	addstat(STAT_OK_AMMO_CHARGE, AS_FLOAT, ok_use_ammocharge);
diff --git a/qcsrc/server/mutators/mutator_physical_items.qc b/qcsrc/server/mutators/mutator_physical_items.qc
index 0fc96a1347..144a8d2eaa 100644
--- a/qcsrc/server/mutators/mutator_physical_items.qc
+++ b/qcsrc/server/mutators/mutator_physical_items.qc
@@ -72,7 +72,7 @@ MUTATOR_HOOKFUNCTION(item_spawning)
 	// Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
 	entity wep;
 	wep = spawn();
-	setmodel(wep, self.model);
+	_setmodel(wep, self.model);
 	setsize(wep, self.mins, self.maxs);
 	setorigin(wep, self.origin);
 	wep.angles = self.angles;
diff --git a/qcsrc/server/mutators/sandbox.qc b/qcsrc/server/mutators/sandbox.qc
index da4f68d58e..509e920511 100644
--- a/qcsrc/server/mutators/sandbox.qc
+++ b/qcsrc/server/mutators/sandbox.qc
@@ -91,7 +91,7 @@ void sandbox_ObjectEdit_Scale(entity e, float f)
 	if(e.scale)
 	{
 		e.scale = bound(autocvar_g_sandbox_object_scale_min, e.scale, autocvar_g_sandbox_object_scale_max);
-		setmodel(e, e.model); // reset mins and maxs based on mesh
+		_setmodel(e, e.model); // reset mins and maxs based on mesh
 		setsize(e, e.mins * e.scale, e.maxs * e.scale); // adapt bounding box size to model size
 	}
 }
@@ -323,7 +323,7 @@ entity sandbox_ObjectPort_Load(string s, float database)
 			parent = e; // mark parent objects as such
 		}
 		// properties stored for all objects
-		setmodel(e, argv(argv_num));	++argv_num;
+		_setmodel(e, argv(argv_num));	++argv_num;
 		e.skin = stof(argv(argv_num));	++argv_num;
 		e.alpha = stof(argv(argv_num));	++argv_num;
 		e.colormod = stov(argv(argv_num));	++argv_num;
@@ -498,7 +498,7 @@ MUTATOR_HOOKFUNCTION(sandbox_PlayerCommand)
 				}
 
 				e = sandbox_ObjectSpawn(false);
-				setmodel(e, argv(2));
+				_setmodel(e, argv(2));
 
 				if(autocvar_g_sandbox_info > 0)
 					LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " spawned an object at origin ^3", vtos(e.origin), "\n"));
diff --git a/qcsrc/server/pathlib/debug.qc b/qcsrc/server/pathlib/debug.qc
index 1da4fc0493..09dae70edc 100644
--- a/qcsrc/server/pathlib/debug.qc
+++ b/qcsrc/server/pathlib/debug.qc
@@ -1,5 +1,10 @@
 #include "../pathlib.qh"
 
+MODEL(SQUARE,       "models/pathlib/square.md3");
+MODEL(SQUARE_GOOD,  "models/pathlib/goodsquare.md3");
+MODEL(SQUARE_BAD,   "models/pathlib/badsquare.md3");
+MODEL(EDGE,         "models/pathlib/edge.md3");
+
 #ifdef TURRET_DEBUG
 void mark_error(vector where,float lifetime);
 void mark_info(vector where,float lifetime);
@@ -54,7 +59,7 @@ void pathlib_showsquare2(entity node ,vector ncolor,float align)
     node.scale     = pathlib_gridsize / 512.001;
     node.solid     = SOLID_NOT;
 
-    setmodel(node,"models/pathlib/square.md3");
+    setmodel(node, MDL_SQUARE);
     setorigin(node,node.origin);
     node.colormod = ncolor;
 
@@ -84,12 +89,7 @@ void pathlib_showsquare(vector where,float goodsquare,float _lifetime)
     s.scale     = pathlib_gridsize / 512.001;
     s.solid     = SOLID_NOT;
 
-    if(goodsquare)
-        setmodel(s,"models/pathlib/goodsquare.md3");
-    else
-        setmodel(s,"models/pathlib/badsquare.md3");
-
-
+    setmodel(s, goodsquare ? MDL_SQUARE_GOOD : MDL_SQUARE_BAD);
 
     traceline(where + '0 0 32',where - '0 0 128',MOVE_WORLDONLY,s);
 
@@ -114,7 +114,7 @@ void pathlib_showedge(vector where,float _lifetime,float rot)
     e.scale     = pathlib_gridsize / 512;
     e.solid     = SOLID_NOT;
     setorigin(e,where);
-    setmodel(e,"models/pathlib/edge.md3");
+    setmodel(e, MDL_EDGE);
     //traceline(where + '0 0 32',where - '0 0 128',MOVE_WORLDONLY,e);
     //e.angles = vectoangles(trace_plane_normal);
     e.angles_y = rot;
diff --git a/qcsrc/server/playerdemo.qc b/qcsrc/server/playerdemo.qc
index 4a750be3e6..b21ed2ea37 100644
--- a/qcsrc/server/playerdemo.qc
+++ b/qcsrc/server/playerdemo.qc
@@ -129,7 +129,7 @@ void playerdemo_read_modelstring(.string f, string name)
 {SELFPARAM();
 	string s = fgets(self.playerdemo_fh);
 	if (s != self.(f))
-		setmodel(self, s);
+		_setmodel(self, s);
 }
 void playerdemo_read_float(.float f, string name)
 {SELFPARAM();
diff --git a/qcsrc/server/portals.qc b/qcsrc/server/portals.qc
index e02c04d6b2..7501b63607 100644
--- a/qcsrc/server/portals.qc
+++ b/qcsrc/server/portals.qc
@@ -636,7 +636,7 @@ entity Portal_Spawn(entity own, vector org, vector ang)
 	portal.event_damage = Portal_Damage;
 	portal.fade_time = time + autocvar_g_balance_portal_lifetime;
 	portal.health = autocvar_g_balance_portal_health;
-	setmodel(portal, "models/portal.md3");
+	setmodel(portal, MDL_PORTAL);
 	portal.savemodelindex = portal.modelindex;
 	portal.customizeentityforclient = Portal_Customize;
 
diff --git a/qcsrc/server/steerlib.qc b/qcsrc/server/steerlib.qc
index fcdbda9776..6ebfc8ad31 100644
--- a/qcsrc/server/steerlib.qc
+++ b/qcsrc/server/steerlib.qc
@@ -545,6 +545,7 @@ void flocker_think()
         self.nextthink = time + 0.1;
 }
 
+MODEL(FLOCKER, "models/turrets/rocket.md3");
 
 void spawn_flocker()
 {SELFPARAM();
@@ -553,7 +554,7 @@ void spawn_flocker()
     flocker = spawn ();
 
     setorigin(flocker, self.origin + '0 0 32');
-    setmodel (flocker, "models/turrets/rocket.md3");
+    setmodel (flocker, MDL_FLOCKER);
     setsize (flocker, '-3 -3 -3', '3 3 3');
 
     flocker.flock_id   = self.flock_id;
@@ -641,8 +642,6 @@ void flocker_hunter_think()
 float globflockcnt;
 void spawnfunc_flockerspawn()
 {SELFPARAM();
-    precache_model ( "models/turrets/rocket.md3");
-    precache_model("models/turrets/c512.md3");
     ++globflockcnt;
 
     if(!self.cnt)      self.cnt = 20;
@@ -654,7 +653,7 @@ void spawnfunc_flockerspawn()
 
     self.enemy = spawn();
 
-    setmodel(self.enemy, "models/turrets/rocket.md3");
+    setmodel(self.enemy, MDL_FLOCKER);
     setorigin(self.enemy,self.origin + '0 0 768' + (randomvec() * 128));
 
     self.enemy.classname = "FLock Hunter";
diff --git a/qcsrc/server/t_items.qc b/qcsrc/server/t_items.qc
index df03b45380..0fbbf2732e 100644
--- a/qcsrc/server/t_items.qc
+++ b/qcsrc/server/t_items.qc
@@ -207,7 +207,7 @@ void ItemRead(float _IsNew)
             LOG_TRACE("^1WARNING!^7 self.mdl is unset for item ", self.classname, " tell tZork aboute this!\n");
 
         precache_model(self.mdl);
-        setmodel(self, self.mdl);
+        _setmodel(self, self.mdl);
     }
 
     if(sf & ISF_COLORMAP)
@@ -1139,7 +1139,7 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
 	self.mdl = self.model;
 	self.netname = itemname;
 	self.touch = Item_Touch;
-	setmodel(self, "null"); // precision set below
+	setmodel(self, MDL_Null); // precision set below
 	//self.effects |= EF_LOWPRECISION;
 
 	if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
diff --git a/qcsrc/server/weapons/weaponsystem.qc b/qcsrc/server/weapons/weaponsystem.qc
index b725cbd195..076a172c8d 100644
--- a/qcsrc/server/weapons/weaponsystem.qc
+++ b/qcsrc/server/weapons/weaponsystem.qc
@@ -117,12 +117,12 @@ void CL_WeaponEntity_SetModel(string name)
 		// if there is a child entity, hide it until we're sure we use it
 		if (self.weaponentity)
 			self.weaponentity.model = "";
-		setmodel(self, W_Model(strcat("v_", name, ".md3")));
+		_setmodel(self, W_Model(strcat("v_", name, ".md3")));
 		v_shot_idx = gettagindex(self, "shot"); // used later
 		if(!v_shot_idx)
 			v_shot_idx = gettagindex(self, "tag_shot");
 
-		setmodel(self, W_Model(strcat("h_", name, ".iqm")));
+		_setmodel(self, W_Model(strcat("h_", name, ".iqm")));
 		// preset some defaults that work great for renamed zym files (which don't need an animinfo)
 		self.anim_fire1  = animfixfps(self, '0 1 0.01', '0 0 0');
 		self.anim_fire2  = animfixfps(self, '1 1 0.01', '0 0 0');
@@ -135,14 +135,14 @@ void CL_WeaponEntity_SetModel(string name)
 		{
 			if (!self.weaponentity)
 				self.weaponentity = spawn();
-			setmodel(self.weaponentity, W_Model(strcat("v_", name, ".md3")));
+			_setmodel(self.weaponentity, W_Model(strcat("v_", name, ".md3")));
 			setattachment(self.weaponentity, self, "weapon");
 		}
 		else if(gettagindex(self, "tag_weapon"))
 		{
 			if (!self.weaponentity)
 				self.weaponentity = spawn();
-			setmodel(self.weaponentity, W_Model(strcat("v_", name, ".md3")));
+			_setmodel(self.weaponentity, W_Model(strcat("v_", name, ".md3")));
 			setattachment(self.weaponentity, self, "tag_weapon");
 		}
 		else
@@ -376,7 +376,7 @@ void CL_ExteriorWeaponentity_Think()
 		self.dmg = self.owner.modelindex;
 		self.deadflag = self.owner.deadflag;
 		if (self.owner.weaponname != "")
-			setmodel(self, W_Model(strcat("v_", self.owner.weaponname, ".md3")));
+			_setmodel(self, W_Model(strcat("v_", self.owner.weaponname, ".md3")));
 		else
 			self.model = "";
 
@@ -411,7 +411,7 @@ void CL_SpawnWeaponentity(entity e)
 	view.classname = "weaponentity";
 	view.solid = SOLID_NOT;
 	view.owner = e;
-	setmodel(view, ""); // precision set when changed
+	setmodel(view, MDL_Null); // precision set when changed
 	setorigin(view, '0 0 0');
 	view.angles = '0 0 0';
 	view.viewmodelforclient = e;
diff --git a/qcsrc/warpzonelib/server.qc b/qcsrc/warpzonelib/server.qc
index bda756bba4..5d0afc819e 100644
--- a/qcsrc/warpzonelib/server.qc
+++ b/qcsrc/warpzonelib/server.qc
@@ -140,7 +140,7 @@ float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
 		player.fixangle = false;
 
 		entity ts = spawn();
-		setmodel(ts, "null");
+		setmodel(ts, MDL_Null);
 		ts.SendEntity = WarpZone_Teleported_Send;
 		ts.SendFlags = 0xFFFFFF;
 		ts.drawonlytoclient = player;
@@ -700,11 +700,6 @@ void spawnfunc_trigger_warpzone(void)
 	//              the map, with another killtarget to designate its
 	//              orientation
 
-#ifndef WARPZONE_USE_FIXANGLE
-	// used when teleporting
-	precache_model("null");
-#endif
-
 	if(!self.scale)
 		self.scale = self.modelscale;
 	if(!self.scale)
@@ -715,7 +710,7 @@ void spawnfunc_trigger_warpzone(void)
  	if(m != "")
  	{
  		precache_model(m);
- 		setmodel(self, m); // no precision needed
+ 		_setmodel(self, m); // no precision needed
 	}
 	setorigin(self, self.origin);
 	if(self.scale)
@@ -737,7 +732,7 @@ void spawnfunc_func_camera(void)
  	if(self.model != "")
  	{
  		precache_model(self.model);
- 		setmodel(self, self.model); // no precision needed
+ 		_setmodel(self, self.model); // no precision needed
 	}
 	setorigin(self, self.origin);
 	if(self.scale)
diff --git a/qcsrc/warpzonelib/util_server.qc b/qcsrc/warpzonelib/util_server.qc
index 29bbecce4e..0b983c299c 100644
--- a/qcsrc/warpzonelib/util_server.qc
+++ b/qcsrc/warpzonelib/util_server.qc
@@ -30,7 +30,7 @@ void WarpZoneLib_ExactTrigger_Init()
 		mi = self.mins;
 		ma = self.maxs;
  		precache_model(self.model);
- 		setmodel(self, self.model);
+ 		_setmodel(self, self.model);
 		// let mapper-set mins/maxs override the model's bounds if set
 		if(mi != '0 0 0' || ma != '0 0 0')
 		{