r685 - in trunk: . base/gamedefs game

lordhavoc at icculus.org lordhavoc at icculus.org
Mon Mar 27 04:16:28 EST 2006


Author: lordhavoc
Date: 2006-03-27 04:16:27 -0500 (Mon, 27 Mar 2006)
New Revision: 685

Added:
   trunk/modelanim.c
   trunk/modelanim.h
Modified:
   trunk/Makefile
   trunk/base/gamedefs/entities.csv
   trunk/game/g_entity.c
   trunk/game/g_entity.h
   trunk/game/g_entityclass.c
   trunk/game/g_main.c
   trunk/game/g_main.h
   trunk/game/g_network.c
   trunk/game/g_packetbuffer.c
   trunk/game/g_packetbuffer.h
   trunk/game/g_render.c
   trunk/game/g_world.c
   trunk/mathlib.h
   trunk/model.c
   trunk/model.h
   trunk/resource.c
   trunk/resource.h
   trunk/system.c
   trunk/todo
Log:
some preparation work toward physics and animations


Modified: trunk/Makefile
===================================================================
--- trunk/Makefile	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/Makefile	2006-03-27 09:16:27 UTC (rev 685)
@@ -25,7 +25,7 @@
 ##### Common variables #####
 
 GAMEOBJECTS= game/g_main.o game/g_render.o game/g_audio.o game/g_network.o game/g_packetbuffer.o game/g_util.o game/particle.o game/g_rain.o game/g_explosion.o game/g_commands.o game/g_entity.o game/g_entityclass.o game/g_world.o game/m_menucore.o
-ENGINEOBJECTS= polygon.o crc.o hash.o system.o console.o collision.o util.o nmemory.o nstring.o nfile.o matrixlib.o resource.o material.o model.o sound.o texture.o video.o dwmesh.o r_dyngl.o r_dynglstubs.o r_main.o fs/dir.o fs/dir_posix.o fs/fs.o fs/pak.o fs/zip.o fs/rw_ops.o s_main.o lhnet.o shell.o shell_lang.o cvar.o lhsound.o systemfallbacks.o
+ENGINEOBJECTS= polygon.o crc.o hash.o system.o console.o collision.o util.o nmemory.o nstring.o nfile.o matrixlib.o resource.o material.o model.o modelanim.o sound.o texture.o video.o dwmesh.o r_dyngl.o r_dynglstubs.o r_main.o fs/dir.o fs/dir_posix.o fs/fs.o fs/pak.o fs/zip.o fs/rw_ops.o s_main.o lhnet.o shell.o shell_lang.o cvar.o lhsound.o systemfallbacks.o
 OBJECTS = $(GAMEOBJECTS) $(ENGINEOBJECTS)
 
 CC=gcc

Modified: trunk/base/gamedefs/entities.csv
===================================================================
--- trunk/base/gamedefs/entities.csv	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/base/gamedefs/entities.csv	2006-03-27 09:16:27 UTC (rev 685)
@@ -1,56 +1,66 @@
-CodeName	ParentCodeName	EnglishName	Class	Model	Mass	Health	Heal	NoRemove	I0Q	I0R	I0C	I0A	I0AR	I0B	I1Q	I1R	I1C	I1A	I1AR	I1B	I2Q	I2R	I2C	I2A	I2AR	I2B	I3Q	I3R	I3C	I3A	I3AR	I3B	I4Q	I4R	I4C	I4A	I4AR	I4B	I5Q	I5R	I5C	I5A	I5AR	I5B	I6Q	I6R	I6C	I6A	I6AR	I6B	I7Q	I7R	I7C	I7A	I7AR	I7B	I8Q	I8R	I8C	I8A	I8AR	I8B	I9Q	I9R	I9C	I9A	I9AR	I9B	AmmoMax	AmmoRegen	Projectile	SemiRefire	AutoRefire	Physics	StepHeight	JumpVelocity	Speed	TopSpeed	Acceleration	Friction	StopSpeed	AirSpeed	AirAcceleration	AirFriction	AirStopSpeed	HoverThrust	HoverAltitude	Cloaking	JumpFlight	CrouchShield	CrouchTurret	LifeTime	ImpactDelay	FleshDamage	ArmorDamage	Force	DamageRadius	Shake	ShakeRadius	IdleAnim	IdleFPS
-light		Light	light																																																																																																		
-model		Model	model	default																																																																																																	
-model_sky		Sky Model	model_sky	default																																																																																																	
-room		Room	room																																																																																																		
-infantry		Infantry	infantry	infantry/infantry	90	200	10		1		weaponmachinegun	400		weapon	1		weaponpistol	60		pistol	1		weaponhandgrenade			grenade1	1		weaponhandgrenade			grenade2	1		weaponhandgrenade			grenade3																																				infantry	0.3	4	5		10	2	10	20	0.02	0.1	0																
-infscout		Scout	infantry	infantry/scout	90	200	10		1		weaponplasmarifle	50		weapon	1		weaponpistol	60		pistol	1		weaponhandgrenade			grenade1	1		weaponhandgrenade			grenade2	1		weaponhandgrenade			grenade3																																				infantry	0.3	4	5		10	2	10	20	0.02	0.1	0			TRUE													
-infhellion		Hellion	infantry	infantry/hellion	90	200	10		1		weaponmachinegun	400		weapon	1		weaponpistol	60		pistol	1		weaponhandgrenade			grenade1	1		weaponhandgrenade			grenade2	1		weaponhandgrenade			grenade3																																				infantry	0.3	8	6		10	2	10	20	1	0.03	1				TRUE												
-infmarauder		Marauder	infantry	infantry/marauder	200	1000	40		1		weaponminigun	400		weapon	1		weaponpistol	60		pistol	1		weaponhandgrenade			grenade1	1		weaponhandgrenade			grenade2	1		weaponhandgrenade			grenade3	1		weaponhandgrenade			grenade4	1		weaponhandgrenade			grenade5																								infantry	0.3	6	5		10	2	10	20	0.2	0.03	0					TRUE											
-infgranite		Granite	infantry	infantry/granite	400	2000	80		1		weaponplasmacannon	30	10	weapon																																																												infantry	0.3	12	4		10	2	10	20	0.01	0.03	0						TRUE										
-vehapc		APC	vehicle_apc	vehicle/apc	3000	2000	50							weapon																																																												hover			0		0	0.2	1	20	0	0.01	5	20	0.5														
-vehtankrailgun		Railgun Hover Tank	vehicle_tank	vehicle/tankrailgun	3000	2000	50		1		weapontankrailgun	10	1	weapon																																																												hover			0		0	0.2	1	20	0	0.01	5	20	0.5														
-vehdropship		Drop Ship	vehicle_dropship	vehicle/dropship	2000	2000	50							weapon																																																												vtol			0		0	0.5	2	40	1	0.01	5																
-turretrailgun		Railgun Turret	turret	turret/turretrail	1000	3000	150		1		weaponturretrailgun	2	2	weapon																																																												default																											
-turretvulcan		Vulcan Turret	turret	turret/turretvulcan	1000	3000	150		1		weaponturretvulcan	20	20	weapon																																																												default																											
-turretartillery		Artillery Turret	turret	turret/turretartillery	1000	3000	150		1		weaponturretartillery	1	0.2	weapon																																																												default																											
-spawninfantry		Infantry Spawn Pad	spawnpad	spawn/infantry	500	500	25	TRUE	1	1	infantry																																																																																										
-spawninfscout		Scout Spawn Pad	spawnpad	spawn/infantry	2000	1000	50	TRUE	1	0.1	infscout																																																																																										
-spawninfhellion		Hellion Spawn Pad	spawnpad	spawn/infantry	2000	1000	50	TRUE	1	0.1	infhellion																																																																																										
-spawninfmarauder		Marauder Spawn Pad	spawnpad	spawn/infantry	2000	1000	50	TRUE	1	0.1	infmarauder																																																																																										
-spawninfgranite		Granite Spawn Pad	spawnpad	spawn/infantry	2000	1000	50	TRUE	1	0.1	infgranite																																																																																										
-spawnvehapc		APC Spawn Pad	vehiclepad	spawn/vehicle	10000	2000	100	TRUE	1	0.02	vehapc																																																																																										
-spawnvehtankrailgun		Railgun Hover Tank Spawn Pad	vehiclepad	spawn/vehicle	10000	2000	100	TRUE	1	0.04	vehtankrailgun																																																																																										
-spawnvehdropship		Drop Ship Spawn Pad	vehiclepad	spawn/vehicle	10000	2000	100	TRUE	1	0.02	vehdropship																																																																																										
-spawnturretrailgun		Railgun Turret Spawn Pad	vehiclepad	spawn/turret	10000	2000	100	TRUE	1	0.02	turretrailgun																																																																																										
-spawnturretvulcan		Vulcan Turret Spawn Pad	vehiclepad	spawn/turret	10000	2000	100	TRUE	1	0.02	turretvulcan																																																																																										
-spawnturretartillery		Artillery Turret Spawn Pad	vehiclepad	spawn/turret	10000	2000	100	TRUE	1	0.02	turretartillery																																																																																										
-weaponhandgrenade		Hand Grenade	weapon	weapon/handgrenade/body	0.2																																																																1		projhandgrenade	0.5	0.5																												
-weaponpistol		Pistol	weapon	weapon/pistol/body	1																																																																60		projpistol	0.2	0.5																												
-weaponmachinegun		Machinegun	weapon	weapon/machinegun/body	5																																																																400		projmachinegun	0.06	0.13																												
-weaponminigun		Minigun	weapon	weapon/minigun/body	20																																																																1200		projminigun	0.05	0.05																												
-weaponsniperrifle		Sniper Rifle	weapon	weapon/sniperrifle/body	4																																																																25		projsniperrifle	0.5	1																												
-weaponrocketlauncher		Rocket Launcher	weapon	weapon/rocketlauncher/body	10																																																																20		projrocketlauncher	0.3	0.3																												
-weaponplasmacannon		Plasma Cannon	weapon	weapon/plasmacannon/body	50																																																																30	10	projplasmacannon	1	1																												
-weapontankrailgun		Railgun	weapon	weapon/tankrailgun/body	50																																																																10	2	projtankrailgun	1	1																												
-weaponturretrailgun		Railgun	weapon	weapon/turretrailgun/body	50																																																																2	1	projturretrailgun	1	1																												
-weaponturretvulcan		Vulcan Cannon	weapon	weapon/turretvulcan/body	200																																																																20	20	projturretvulcan	0.06	0.06																												
-weaponturretartillery		Artillery Cannon	weapon	weapon/turretartillery/body	200																																																																1	0.2	projturretartillery	5	5																												
-projhandgrenade		Live Hand Grenade	projectile	weapon/handgrenade/projectile	0.2																																																																					default			10															3	4								
-projpistol		Pistol Bullet	projectile	weapon/pistol/projectile	0																																																																					default			1300															60	0								
-projmachinegun		Machinegun Bullet	projectile	weapon/machinegun/projectile	0																																																																					default			800															60	0								
-projminigun		Minigun Bullet	projectile	weapon/minigun/projectile	0																																																																					default			800															60	0								
-projplasmacannon		Plasma Cannon Ball	projectile	weapon/plasmacannon/projectile	0																																																																					default																		10	0								
-projtankrailgun		Railgun Bolt	projectile	weapon/tankrailgun/projectile	0.5																																																																					default																		60	0								
-projturretrailgun		Railgun Bolt	projectile	weapon/turretrailgun/projectile	0.1																																																																					default																		60	0								
-projturretvulcan		Vulcan Turret Bullet	projectile	weapon/turretvulcan/projectile	0.01																																																																					default																		60	0								
-projturretartillery		Artillery Cannon Shell	projectile	weapon/turretartillery/projectile	5																																																																					default																		60	2								
-expprojhandgrenade		Hand Grenade Explosion	explosion	weapon/handgrenade/projectileexplosion																																																																																										400	100	400	10	2	30		
-expprojpistol		Pistol Bullet Impact	explosion	weapon/pistol/projectileexplosion																																																																																										50	30	0.1	0.01	0	0		
-expprojmachinegun		Machinegun Bullet Impact	explosion	weapon/machinegun/projectileexplosion																																																																																										30	15	0.05	0.01	0	0		
-expprojminigun		Minigun Bullet Impact	explosion	weapon/minigun/projectileexplosion																																																																																										30	15	0.05	0.01	0	0		
-expprojplasmacannon		Plasma Cannon Shell Explosion	explosion	weapon/plasmacannon/projectileexplosion																																																																																										150	400	10	2	0	0		
-expprojtankrailgun		Railgun Bolt Impact	explosion	weapon/tankrailgun/projectileexplosion																																																																																										200	900	50	0.5	1	10		
-expprojturretrailgun		Railgun Bolt Impact	explosion	weapon/turretrailgun/projectileexplosion																																																																																										200	900	50	0.5	1	10		
-expprojturretvulcan		Vulcan Turret Bullet Impact	explosion	weapon/turretvulcan/projectileexplosion																																																																																										20	30	1	0.01	0	0		
-expprojturretartillery		Artillery Cannon Shell Explosion	explosion	weapon/turretartillery/projectileexplosion																																																																																										200	400	200	10	2	30		
+CodeName	ParentCodeName	EnglishName	Class	Model	Mass	Health	Heal	NoRemove	Respawn	I0C	I0B	I1C	I1B	I2C	I2B	I3C	I3B	I4C	I4B	I5C	I5B	I6C	I6B	I7C	I7B	I8C	I8B	I9C	I9B	AmmoMax	AmmoRegen	Projectile	Shots	Spread	SemiRefire	AutoRefire	Physics	StepHeight	JumpVelocity	Speed	TopSpeed	Acceleration	Friction	StopSpeed	AirSpeed	AirAcceleration	AirFriction	AirStopSpeed	HoverThrust	HoverAltitude	Cloaking	JumpFlight	CrouchShield	CrouchTurret	LifeTime	ImpactDelay	FleshDamage	ArmorDamage	Force	DamageRadius	Shake	ShakeRadius	IdleAnim	IdleFPS
+light		Light	light																																																													
+model		Model	model	default																																																												
+model_sky		Sky Model	model_sky	default																																																												
+room		Room	room																																																													
+infantry		Infantry	infantry	infantry/infantry	90	200	10			itemmachinegun	weapon	itempistol	pistol	itemhandgrenade	grenade1	itemhandgrenade	grenade2	itemhandgrenade	grenade3																		infantry	0.3	4	5		10	2	10	20	0.02	0.1	0																
+infscout		Scout	infantry	infantry/scout	90	200	10			itemsniperrifle	weapon	itempistol	pistol	itemhandgrenade	grenade1	itemhandgrenade	grenade2	itemhandgrenade	grenade3																		infantry	0.3	4	5		10	2	10	20	0.02	0.1	0			TRUE													
+infhellion		Hellion	infantry	infantry/hellion	90	200	10			itemmachinegun	weapon	itempistol	pistol	itemhandgrenade	grenade1	itemhandgrenade	grenade2	itemhandgrenade	grenade3																		infantry	0.3	8	6		10	2	10	20	1	0.03	1				TRUE												
+infmarauder		Marauder	infantry	infantry/marauder	200	1000	40			itemminigun	weapon	itempistol	pistol	itemhandgrenade	grenade1	itemhandgrenade	grenade2	itemhandgrenade	grenade3	itemhandgrenade	grenade4	itemhandgrenade	grenade5														infantry	0.3	6	5		10	2	10	20	0.2	0.03	0					TRUE											
+infgranite		Granite	infantry	infantry/granite	400	2000	80			itemplasmacannon	weapon																										infantry	0.3	12	4		10	2	10	20	0.01	0.03	0						TRUE										
+vehapc		APC	vehicle_apc	vehicle/apc	3000	2000	50				weapon																										hover			0		0	0.2	1	20	0	0.01	5	20	0.5														
+vehtankrailgun		Railgun Hover Tank	vehicle_tank	vehicle/tankrailgun	3000	2000	50			weapontankrailgun	weapon																										hover			0		0	0.2	1	20	0	0.01	5	20	0.5														
+vehdropship		Drop Ship	vehicle_dropship	vehicle/dropship	2000	2000	50				weapon																										vtol			0		0	0.5	2	40	1	0.01	5																
+turretrailgun		Railgun Turret	turret	turret/turretrail	1000	3000	150			weaponturretrailgun	weapon																										default																											
+turretvulcan		Vulcan Turret	turret	turret/turretvulcan	1000	3000	150			weaponturretvulcan	weapon																										default																											
+turretartillery		Artillery Turret	turret	turret/turretartillery	1000	3000	150			weaponturretartillery	weapon																										default																											
+spawninfantry		Infantry Spawn Pad	spawnpad	spawn/infantry	500	500	25	TRUE	1	infantry	spawn																																																					
+spawninfscout		Scout Spawn Pad	spawnpad	spawn/infantry	2000	1000	50	TRUE	10	infscout	spawn																																																					
+spawninfhellion		Hellion Spawn Pad	spawnpad	spawn/infantry	2000	1000	50	TRUE	10	infhellion	spawn																																																					
+spawninfmarauder		Marauder Spawn Pad	spawnpad	spawn/infantry	2000	1000	50	TRUE	10	infmarauder	spawn																																																					
+spawninfgranite		Granite Spawn Pad	spawnpad	spawn/infantry	2000	1000	50	TRUE	10	infgranite	spawn																																																					
+spawnvehapc		APC Spawn Pad	vehiclepad	spawn/vehicle	10000	2000	100	TRUE	50	vehapc	spawn																																																					
+spawnvehtankrailgun		Railgun Hover Tank Spawn Pad	vehiclepad	spawn/vehicle	10000	2000	100	TRUE	50	vehtankrailgun	spawn																																																					
+spawnvehdropship		Drop Ship Spawn Pad	vehiclepad	spawn/vehicle	10000	2000	100	TRUE	50	vehdropship	spawn																																																					
+spawnturretrailgun		Railgun Turret Spawn Pad	vehiclepad	spawn/turret	10000	2000	100	TRUE	50	turretrailgun	spawn																																																					
+spawnturretvulcan		Vulcan Turret Spawn Pad	vehiclepad	spawn/turret	10000	2000	100	TRUE	50	turretvulcan	spawn																																																					
+spawnturretartillery		Artillery Turret Spawn Pad	vehiclepad	spawn/turret	10000	2000	100	TRUE	50	turretartillery	spawn																																																					
+itemhandgrenade		Hand Grenade	item	weapon/handgrenade/body	0.2																											projhandgrenade	1	0.1	0.5	0.5																												
+itempistol		Pistol	item	weapon/pistol/body	1																									60		projpistol	1	0.01	0.2	0.5																												
+itemmachinegun		Machinegun	item	weapon/machinegun/body	5																									400		projmachinegun	1	0.01	0.06	0.13																												
+itemshotgun		Flechette Shotgun	item	weapon/shotgun/body	5																									50		projshotgun	8	0.03	0.2	0.5																												
+itemminigun		Minigun	item	weapon/minigun/body	20																									1200		projminigun	1	0.02	0.05	0.05																												
+itemsniperrifle		Sniper Rifle	item	weapon/sniperrifle/body	4																									25		projsniperrifle	1	0.0001	0.5	1																												
+itemgrenadelauncher		Grenade Launcher	item	weapon/grenadelauncher/body	3																									50		projgrenadelauncher	1	0.02	0.5	0.5																												
+itemrocketlauncher		Rocket Launcher	item	weapon/rocketlauncher/body	10																									20		projrocketlauncher	1	0.001	0.3	0.3																												
+itemplasmacannon		Plasma Cannon	item	weapon/plasmacannon/body	50																									30	10	projplasmacannon	1	0.01	1	1																												
+weapontankrailgun		Railgun	weapon	weapon/tankrailgun/body	50																									10	2	projtankrailgun	1	0.0001	1	1																												
+weaponturretrailgun		Railgun	weapon	weapon/turretrailgun/body	50																									2	1	projturretrailgun	1	0.01	1	1																												
+weaponturretvulcan		Vulcan Cannon	weapon	weapon/turretvulcan/body	200																									20	20	projturretvulcan	1	0.03	0.06	0.06																												
+weaponturretartillery		Artillery Cannon	weapon	weapon/turretartillery/body	200																									1	0.2	projturretartillery	1	0.01	5	5																												
+projhandgrenade		Live Hand Grenade	projectile	weapon/handgrenade/projectile	0.2																																default			10			1				0.1								3	4								
+projpistol		Pistol Bullet	projectile	weapon/pistol/projectile	0.01																																default			1300			1				0.1								60	0								
+projmachinegun		Machinegun Bullet	projectile	weapon/machinegun/projectile	0.005																																default			800			1				0.1								60	0								
+projshotgun		Shotgun Flechette	projectile	weapon/shotgun/projectile	0.02																																default			1100			1				0.1								60	0								
+projminigun		Minigun Bullet	projectile	weapon/minigun/projectile	0.01																																default			800			1				0.1								60	0								
+projsniperrifle		Sniper Rifle Flechette	projectile	weapon/sniperrifle/projectile	0.01																																default			4000			1				0.1								60	0								
+projgrenadelauncher		Grenade Launcher Grenade	projectile	weapon/grenadelauncher/projectile	0.5																																default			100			1				0.1								60	2								
+projrocketlauncher		Rocket Launcher Rocket	projectile	weapon/rocketlauncher/projectile	1																																default			100	5000	1000	1				0.1								60	0								
+projplasmacannon		Plasma Cannon Ball	projectile	weapon/plasmacannon/projectile	0.005																																default			400			1				0.1								10	0								
+projtankrailgun		Railgun Bolt	projectile	weapon/tankrailgun/projectile	0.5																																default			4000			1				0.1								60	0								
+projturretrailgun		Railgun Bolt	projectile	weapon/turretrailgun/projectile	0.1																																default			4000			1				0.1								60	0								
+projturretvulcan		Vulcan Turret Bullet	projectile	weapon/turretvulcan/projectile	0.01																																default			1000			1				0.1								60	0								
+projturretartillery		Artillery Cannon Shell	projectile	weapon/turretartillery/projectile	5																																default			300			1				0.01								60	2								
+expprojhandgrenade		Hand Grenade Explosion	explosion	weapon/handgrenade/projectileexplosion																																																					400	100	400	10	2	30		
+expprojpistol		Pistol Bullet Impact	explosion	weapon/pistol/projectileexplosion																																																					50	30	0.1	0.01	0	0		
+expprojmachinegun		Machinegun Bullet Impact	explosion	weapon/machinegun/projectileexplosion																																																					30	15	0.05	0.01	0	0		
+expprojshotgun		Shotgun Flechette Impact	explosion	weapon/shotgun/projectileexplosion																																																					20	20	0.05	0.01	0	0		
+expprojminigun		Minigun Bullet Impact	explosion	weapon/minigun/projectileexplosion																																																					30	15	0.05	0.01	0	0		
+expprojsniperrifle		Sniper Rifle Flechette Impact	explosion	weapon/sniperrifle/projectileexplosion																																																					150	150	0.05	0.01	0	0		
+expprojgrenadelauncher		Grenade Launcher Grenade Explosion	explosion	weapon/grenadelauncher/projectileexplosion																																																					300	100	300	10	2	30		
+expprojrocketlauncher		Rocket Launcher Rocket Explosion	explosion	weapon/rocketlauncher/projectileexplosion																																																					300	100	300	10	2	30		
+expprojplasmacannon		Plasma Cannon Shell Explosion	explosion	weapon/plasmacannon/projectileexplosion																																																					150	400	10	2	0	0		
+expprojtankrailgun		Railgun Bolt Impact	explosion	weapon/tankrailgun/projectileexplosion																																																					200	900	50	0.5	1	10		
+expprojturretrailgun		Railgun Bolt Impact	explosion	weapon/turretrailgun/projectileexplosion																																																					200	900	50	0.5	1	10		
+expprojturretvulcan		Vulcan Turret Bullet Impact	explosion	weapon/turretvulcan/projectileexplosion																																																					20	30	1	0.01	0	0		
+expprojturretartillery		Artillery Cannon Shell Explosion	explosion	weapon/turretartillery/projectileexplosion																																																					200	400	200	10	2	30		

Modified: trunk/game/g_entity.c
===================================================================
--- trunk/game/g_entity.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/game/g_entity.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -5,12 +5,20 @@
 #include "game/g_world.h"
 #include "model.h"
 
-G_Entity *G_Entity_New(G_Entity *parent, const G_Entity_Class *eclass)
+G_Entity *G_Entity_New(G_Entity *parent, const G_Entity_Class *eclass, const G_Entity_Position *position)
 {
 	G_Entity *entity;
 	NUint32 childindex = 0;
 	if (!eclass)
 		return NULL;
+	if (!eclass->codeclass->name)
+	{
+		Console_Printf("G_Entity_New: no code class found for classname \"%s\"\n", eclass->classname);
+		// if editing, we should keep the unrecognized entities so that the
+		// user can change them to something else
+		if (!G.editing)
+			return NULL;
+	}
 	if (parent)
 	{
 		for (childindex = 0;childindex < G_ENTITY_CHILDREN;childindex++)
@@ -23,6 +31,8 @@
 			return NULL;
 		}
 	}
+	if (!position)
+		position = &GS.identityposition;
 	// TODO: add a timeout after freeing an entity before it will be reused?  (if so this will need to scan twice if it can't find one with the timeout)
 	for (entity = G.entities + G.allocentity;G.allocentity < G_MAX_ENTITIES;G.allocentity++, entity++)
 	{
@@ -40,9 +50,10 @@
 				entity->owner = parent;
 				parent->children[childindex] = entity;
 			}
-			// now set up basic things that are generally wanted, to save code in the spawn functions
+			entity->position = *position;
 			if (entity->eclass->modelname && entity->eclass->modelname[0])
 				G_Entity_SetModel(entity, entity->eclass->modelname);
+			entity->lifetime = entity->eclass->lifetime;
 			return entity;
 		}
 	}
@@ -52,13 +63,6 @@
 
 void G_Entity_Spawn(G_Entity *entity)
 {
-	if (!entity->eclass)
-	{
-		Console_Printf("G_Entity_Spawn: NULL eclass\n");
-		entity->eclass = G_EntityClass_ByNumber(0);
-	}
-	if (!entity->modelindex && entity->eclass->modelname)
-		G_Entity_SetModel(entity, entity->eclass->modelname);
 	if (entity->eclass->codeclass->spawn)
 	{
 		entity->eclass->codeclass->spawn(entity);
@@ -69,38 +73,6 @@
 	G_Entity_Relink(entity);
 }
 
-void G_Entity_SpawnFromFields(G_Entity *entity)
-{
-	char *classname, *model, *cubemapname;
-	Nvec3 origin, angles;
-	Nvec scale;
-	classname = G_Entity_FieldValue_String(entity, "classname");
-	entity->eclass = G_EntityClass_ByName(classname);
-	// set up the most general fields to save code in spawn functions
-	G_Entity_FieldValue_Vector(entity, "origin", origin);
-	G_Entity_FieldValue_Vector(entity, "angles", angles);
-	scale = G_Entity_FieldValue_Double(entity, "scale");
-	if (!scale)
-		scale = 1;
-	Matrix4x4_CreateFromQuakeEntity(&entity->matrix, origin[0], origin[1], origin[2], angles[0], angles[1], angles[2], scale);
-	G_Entity_FieldValue_Vector(entity, "color", entity->lightcolor);
-	cubemapname = G_Entity_FieldValue_String(entity, "cubemap");
-	if (cubemapname)
-		entity->lightcubemap = Resource_IndexForName(cubemapname, RESOURCETYPE_TEXTURE, 0, 0);
-	model = G_Entity_FieldValue_String(entity, "model");
-	if (model)
-		G_Entity_SetModel(entity, model);
-	if (!G.editing)
-		G_Entity_RemoveFields(entity);
-	G_Entity_Spawn(entity);
-	if (!entity->eclass->codeclass->name)
-	{
-		Console_Printf("G_Entity_SpawnFromFields: no class found for classname \"%s\"\n", classname ? classname : "");
-		if (!G.editing)
-			G_Entity_Remove(entity);
-	}
-}
-
 static void G_Entity_Unlink(G_Entity *entity);
 void G_Entity_Remove(G_Entity *entity)
 {
@@ -138,7 +110,7 @@
 	if (entity->transforms)
 		Mem_Free(&entity->transforms);
 	// remove attached fields (which only exist in editing mode)
-	G_Entity_RemoveFields(entity);
+	StringKeys_FreeKeys(&entity->keys);
 	// clear the entity completely
 	memset(entity, 0, sizeof(*entity));
 	// reset allocentity to a level that will find this freshly freed entity
@@ -153,40 +125,46 @@
 			G_Entity_Remove(entity->children[childindex]);
 }
 
-void G_Entity_RemoveFields(G_Entity *entity)
-{
-	G_Entity_Field *field, *fieldnext;
-	for (field = entity->fields;field;field = fieldnext)
-	{
-		fieldnext = field->next;
-		String_Free(&field->key);
-		String_Free(&field->value);
-		Mem_Free(&field);
-	}
-	entity->fields = NULL;
-}
-
 void G_Entity_SpawnInventoryChildren(G_Entity *entity)
 {
 	NUint32 i;
 	for (i = 0;i < G_ENTITYCLASS_INVENTORY_MAX;i++)
 	{
-		if (entity->eclass->inventory[i].quantity > 0)
+		if (entity->eclass->inventory[i].codename)
 		{
 			const G_Entity_Class *itemeclass = G_EntityClass_ByName(entity->eclass->inventory[i].codename);
 			if (itemeclass)
 			{
-				G_Entity *item = G_Entity_New(entity, itemeclass);
-				item->quantity = entity->eclass->inventory[i].quantity;
+				G_Entity *item = G_Entity_New(entity, itemeclass, &entity->position);
+				item->attachment_entity = entity;
+				item->attachment_transformindex = Model_GetTransformNumberForName(entity->modelindex, entity->eclass->inventory[i].transformname) + 1;
+				item->attachment_matrix = GS.identityposition.m;
 				G_Entity_Spawn(item);
 			}
 			else
 				Console_Printf("G_Entity_SpawnInventoryChildren: Can't find entity class for %s.I%iC\n", entity->eclass->codename, i + 1);
 		}
 	}
-	// TODO; spawn inventory entities and attach to player model
 }
 
+void G_Entity_GetTransformMatrix(G_Entity *entity, NUint32 transformindex, matrix4x4_t *result)
+{
+	if (index >= 1 && index <= entity->numtransforms)
+		Matrix4x4_Concat(result, &entity->position.m, entity->transforms + (transformindex - 1));
+	else
+		*result = entity->position.m;
+}
+
+void G_Entity_UpdateAttachment(G_Entity *entity)
+{
+	matrix4x4_t parentmatrix;
+	if (!entity->attachment_entity)
+		return;
+	G_Entity_GetMatrix(entity->attachment_entity, entity->attachment_index, &parentmatrix);
+	Matrix4x4_Concat(&entity->position.m, &parentmatrix, &entity->attachment_matrix);
+	G_Entity_Relink(entity);
+}
+
 void G_World_UnlinkSurface(G_Entity_Surface *surface);
 void G_World_LinkSurface(G_Entity_Surface *surface);
 
@@ -236,6 +214,18 @@
 	G_Entity_SetModelIndex(entity, Resource_IndexForName(modelname, RESOURCETYPE_MODEL, 0, 0));
 }
 
+void G_Entity_SetAnimation(G_Entity *entity, G_Entity_AnimationState *state, G_Entity_AnimationType type, const char *modelanimname)
+{
+	state->type = type;
+	state->time = 0;
+	state->resourceindex = Resource_IndexForName(modelanimname, RESOURCETYPE_MODELANIM, 0, 0);
+}
+
+void G_Entity_Animation(G_Entity *entity, G_Entity_AnimationState *state)
+{
+	state->time += G.frametime;
+}
+
 // FIXME: move these to g_world.c
 void G_World_UnlinkSurface(G_Entity_Surface *surface)
 {
@@ -284,10 +274,13 @@
 
 	G_Entity_Unlink(entity);
 
+	// update the inverse matrix
+	Matrix4x4_Invert_Simple(&entity->position.inversem, &entity->position.m);
+
 	if (entity->eclass->codeclass->scopeflags & G_SCOPE_RENDER_LIGHTSOURCE)
 	{
-		Matrix4x4_OriginFromMatrix(&entity->matrix, entity->cullorigin);
-		entity->cullradius = Matrix4x4_ScaleFromMatrix(&entity->matrix);
+		Matrix4x4_OriginFromMatrix(&entity->position.m, entity->cullorigin);
+		entity->cullradius = Matrix4x4_ScaleFromMatrix(&entity->position.m);
 		entity->cullmins[0] = entity->cullorigin[0] - entity->cullradius;
 		entity->cullmins[1] = entity->cullorigin[1] - entity->cullradius;
 		entity->cullmins[2] = entity->cullorigin[2] - entity->cullradius;
@@ -310,9 +303,9 @@
 			meshlocalcullorigin[0] = (meshlocalmins[0] + meshlocalmaxs[0]) * 0.5;
 			meshlocalcullorigin[1] = (meshlocalmins[1] + meshlocalmaxs[1]) * 0.5;
 			meshlocalcullorigin[2] = (meshlocalmins[2] + meshlocalmaxs[2]) * 0.5;
-			Matrix4x4_Transform(&entity->matrix, meshlocalcullorigin, surface->cullorigin);
-			// TODO: scale radius based on longest vector in entity->matrix?
-			surface->cullradius = Matrix4x4_ScaleFromMatrix(&entity->matrix) * VectorDistance(meshlocalcullorigin, meshlocalmaxs);
+			Matrix4x4_Transform(&entity->position.m, meshlocalcullorigin, surface->cullorigin);
+			// TODO: scale radius based on longest vector in entity->position.m?
+			surface->cullradius = Matrix4x4_ScaleFromMatrix(&entity->position.m) * VectorDistance(meshlocalcullorigin, meshlocalmaxs);
 			VectorCopy(surface->cullorigin, surface->cullmins);
 			VectorCopy(surface->cullorigin, surface->cullmaxs);
 			// TODO: optimize unrotated case
@@ -322,7 +315,7 @@
 				localpoint[0] = i & 1 ? meshlocalmaxs[0] : meshlocalmins[0];
 				localpoint[1] = i & 2 ? meshlocalmaxs[1] : meshlocalmins[1];
 				localpoint[2] = i & 4 ? meshlocalmaxs[2] : meshlocalmins[2];
-				Matrix4x4_Transform(&entity->matrix, localpoint, point);
+				Matrix4x4_Transform(&entity->position.m, localpoint, point);
 				surface->cullmins[0] = Min(surface->cullmins[0], point[0]);
 				surface->cullmins[1] = Min(surface->cullmins[1], point[1]);
 				surface->cullmins[2] = Min(surface->cullmins[2], point[2]);
@@ -362,18 +355,18 @@
 		cullorigin[0] = (entitylocalmins[0] + entitylocalmaxs[0]) * 0.5;
 		cullorigin[1] = (entitylocalmins[1] + entitylocalmaxs[1]) * 0.5;
 		cullorigin[2] = (entitylocalmins[2] + entitylocalmaxs[2]) * 0.5;
-		Matrix4x4_Transform(&entity->matrix, cullorigin, entity->cullorigin);
-		// TODO: scale radius based on longest vector in entity->matrix?
-		entity->cullradius = Matrix4x4_ScaleFromMatrix(&entity->matrix) * VectorDistance(cullorigin, entitylocalmaxs);
+		Matrix4x4_Transform(&entity->position.m, cullorigin, entity->cullorigin);
+		// TODO: scale radius based on longest vector in entity->position.m?
+		entity->cullradius = Matrix4x4_ScaleFromMatrix(&entity->position.m) * VectorDistance(cullorigin, entitylocalmaxs);
 
 		// TODO: link into culling grid for collision detection
 	}
 	else
 	{
 		// no surfaces, so culling box is just a point
-		entity->cullorigin[0] = entity->matrix.m[0][3];
-		entity->cullorigin[1] = entity->matrix.m[1][3];
-		entity->cullorigin[2] = entity->matrix.m[2][3];
+		entity->cullorigin[0] = entity->position.m.m[0][3];
+		entity->cullorigin[1] = entity->position.m.m[1][3];
+		entity->cullorigin[2] = entity->position.m.m[2][3];
 		entity->cullradius = 0;
 		VectorCopy(entity->cullorigin, entity->cullmins);
 		VectorCopy(entity->cullorigin, entity->cullmaxs);
@@ -388,7 +381,7 @@
 	matrix4x4_t newmatrix;
 	G_Trace trace;
 
-	if (VectorLength2(self->velocity) < (1.0 / 1024.0))
+	if (VectorLength2(self->position.velocity) < (1.0 / 1024.0))
 	{
 		// no movement
 		return;
@@ -400,24 +393,24 @@
 	if (!scope)
 	{
 		// noclip
-		self->matrix.m[0][3] = self->matrix.m[0][3] + G.frametime * self->velocity[0];
-		self->matrix.m[1][3] = self->matrix.m[1][3] + G.frametime * self->velocity[1];
-		self->matrix.m[2][3] = self->matrix.m[2][3] + G.frametime * self->velocity[2];
+		self->position.m.m[0][3] = self->position.m.m[0][3] + G.frametime * self->position.velocity[0];
+		self->position.m.m[1][3] = self->position.m.m[1][3] + G.frametime * self->position.velocity[1];
+		self->position.m.m[2][3] = self->position.m.m[2][3] + G.frametime * self->position.velocity[2];
 		G_Entity_Relink(self);
 		return;
 	}
 
 	for (bump = 0, t = 1;bump < 16 && t >= (1.0 / 128.0);bump++)
 	{
-		newmatrix = self->matrix;
-		newmatrix.m[0][3] = self->matrix.m[0][3] + t * G.frametime * self->velocity[0];
-		newmatrix.m[1][3] = self->matrix.m[1][3] + t * G.frametime * self->velocity[1];
-		newmatrix.m[2][3] = self->matrix.m[2][3] + t * G.frametime * self->velocity[2];
+		newmatrix = self->position.m;
+		newmatrix.m[0][3] = self->position.m.m[0][3] + t * G.frametime * self->position.velocity[0];
+		newmatrix.m[1][3] = self->position.m.m[1][3] + t * G.frametime * self->position.velocity[1];
+		newmatrix.m[2][3] = self->position.m.m[2][3] + t * G.frametime * self->position.velocity[2];
 
-		G_World_Trace_Brush(&trace, &self->collisionbrush, &self->matrix, &newmatrix, self, scope);
+		G_World_Trace_Brush(&trace, &self->collisionbrush, &self->position.m, &newmatrix, self, scope);
 		if (trace.impact_fraction == 1)
 		{
-			self->matrix = trace.impact_matrix;
+			self->position.m = trace.impact_matrix;
 			break;
 		}
 
@@ -429,7 +422,7 @@
 			matrix4x4_t matrix2;
 			matrix4x4_t newmatrix2;
 			// trace again, but higher
-			matrix2 = self->matrix;
+			matrix2 = self->position.m;
 			matrix2.m[2][3] += stepheight;
 			newmatrix2 = newmatrix;
 			newmatrix2.m[2][3] += stepheight;
@@ -451,8 +444,8 @@
 			VectorCopy(trace.impact_normal, self->groundnormal);
 		}
 
-		self->matrix = trace.impact_matrix;
-		VectorReflect(self->velocity, bounce, trace.impact_normal, self->velocity);
+		self->position.m = trace.impact_matrix;
+		VectorReflect(self->position.velocity, bounce, trace.impact_normal, self->position.velocity);
 		t -= t * trace.impact_fraction;
 	}
 
@@ -463,12 +456,12 @@
 		G_Trace trace2;
 		matrix4x4_t matrix2;
 		matrix4x4_t newmatrix2;
-		matrix2 = self->matrix;
+		matrix2 = self->position.m;
 		newmatrix2 = matrix2;
 		newmatrix2.m[2][3] -= stepheight;
 		G_World_Trace_Brush(&trace2, &self->collisionbrush, &matrix2, &newmatrix2, self, scope);
 		if (trace2.impact_fraction < 1)
-			self->matrix = trace2.impact_matrix;
+			self->position.m = trace2.impact_matrix;
 	}
 	*/
 
@@ -486,15 +479,15 @@
 		if (!jumpspeed)
 		{
 			// apply stopspeed
-			VectorReflect(self->velocity, 0, self->groundnormal, groundwishdir);
+			VectorReflect(self->position.velocity, 0, self->groundnormal, groundwishdir);
 			VectorNormalize(groundwishdir);
-			f = DotProduct(self->velocity, groundwishdir);
+			f = DotProduct(self->position.velocity, groundwishdir);
 			f = Min(f, groundstopspeed * G.frametime);
 			if (f > 0)
-				VectorMA(self->velocity, -f, groundwishdir, self->velocity);
+				VectorMA(self->position.velocity, -f, groundwishdir, self->position.velocity);
 			// apply friction
 			f = Bound(0, G.frametime * groundfriction, 1);
-			VectorLerp(self->velocity, f, self->groundentity->velocity, self->velocity);
+			VectorLerp(self->position.velocity, f, self->groundentity->position.velocity, self->position.velocity);
 		}
 		if (wishvel)
 		{
@@ -505,47 +498,47 @@
 			// normalize the groundwishdir, we only wanted the direction
 			VectorNormalize(groundwishdir);
 			wishspeed = VectorLength(wishvel);
-			f = Min(wishspeed * groundaccel * G.frametime, wishspeed - DotProduct(self->velocity, groundwishdir));
+			f = Min(wishspeed * groundaccel * G.frametime, wishspeed - DotProduct(self->position.velocity, groundwishdir));
 			if (f > 0)
 			{
 				// apply acceleration
-				VectorMA(self->velocity, f, groundwishdir, self->velocity);
+				VectorMA(self->position.velocity, f, groundwishdir, self->position.velocity);
 			}
 		}
 		// add jump impulse along ground normal
 		if (jumpspeed)
-			VectorMA(self->velocity, jumpspeed, self->groundnormal, self->velocity);
+			VectorMA(self->position.velocity, jumpspeed, self->groundnormal, self->position.velocity);
 		// apply gravity acceleration
-		VectorAdd(self->velocity, gravityimpulse, self->velocity);
+		VectorAdd(self->position.velocity, gravityimpulse, self->position.velocity);
 		// add another impulse to counteract the sliding that results from gravity
 		VectorReflect(gravityimpulse, 0, self->groundnormal, countergravityimpulse);
-		VectorSubtract(self->velocity, countergravityimpulse, self->velocity);
+		VectorSubtract(self->position.velocity, countergravityimpulse, self->position.velocity);
 	}
 	else
 	{
 		// apply stopspeed
-		f = VectorLength(self->velocity);
+		f = VectorLength(self->position.velocity);
 		if (f > airstopspeed)
 		{
 			f = 1 - airstopspeed * G.frametime / f;
-			VectorScale(self->velocity, f, self->velocity);
+			VectorScale(self->position.velocity, f, self->position.velocity);
 		}
 		else
-			VectorClear(self->velocity);
+			VectorClear(self->position.velocity);
 		// apply friction
 		f = Bound(0, 1 - G.frametime * airfriction, 1);
-		VectorScale(self->velocity, f, self->velocity);
+		VectorScale(self->position.velocity, f, self->position.velocity);
 		if (wishvel)
 		{
 			// apply acceleration
 			f = Bound(-1, G.frametime * airaccel, 1);
-			VectorMA(self->velocity, f, wishvel, self->velocity);
+			VectorMA(self->position.velocity, f, wishvel, self->position.velocity);
 		}
 		// apply gravity acceleration
-		VectorAdd(self->velocity, gravityimpulse, self->velocity);
+		VectorAdd(self->position.velocity, gravityimpulse, self->position.velocity);
 	}
 	if (thrustvel)
-		VectorMA(self->velocity, G.frametime, thrustvel, self->velocity);
+		VectorMA(self->position.velocity, G.frametime, thrustvel, self->position.velocity);
 }
 
 static Collision_Brush boxbrush;
@@ -613,98 +606,6 @@
 	Collision_Brush_UpdateCullingData(&entity->collisionbrush);
 }
 
-void G_Entity_SetField(G_Entity *entity, const char *key, const char *value)
-{
-	G_Entity_Field *field, **nextpointer;
-	if (!String_ICompare(value, ""))
-	{
-		// remove a field
-		for (nextpointer = &entity->fields, field = *nextpointer;field;nextpointer = &field->next, field = *nextpointer)
-		{
-			if (!String_ICompare(field->key, key))
-			{
-				String_Free(&field->key);
-				String_Free(&field->value);
-				Mem_Free(&field);
-				// unlink the field by updating the previous field's next
-				// pointer to point to the next field after the removed field
-				*nextpointer = field->next;
-				return;
-			}
-		}
-		// no field found
-	}
-	else
-	{
-		// add or update a field
-		for (nextpointer = &entity->fields, field = *nextpointer;field;nextpointer = &field->next, field = *nextpointer)
-		{
-			if (!String_ICompare(field->key, key))
-			{
-				// update the existing field
-				String_Set(&field->key, GS.memzone, key);
-				String_Set(&field->value, GS.memzone, value);
-				return;
-			}
-		}
-		// add the field
-		*nextpointer = field = Mem_Alloc(GS.memzone, sizeof(G_Entity_Field));
-		String_Set(&field->key, GS.memzone, key);
-		String_Set(&field->value, GS.memzone, value);
-	}
-}
-
-char *G_Entity_FieldValue_String(G_Entity *entity, const char *key)
-{
-	G_Entity_Field *field;
-	for (field = entity->fields;field;field = field->next)
-		if (!String_ICompare(field->key, key))
-			return field->value;
-	return NULL;
-}
-
-NSint32 G_Entity_FieldValue_Integer(G_Entity *entity, const char *key)
-{
-	char *value = G_Entity_FieldValue_String(entity, key);
-	if (value)
-	{
-		while (*value && *value <= ' ')
-			value++;
-		return atoi(value);
-	}
-	return 0;
-}
-
-Ndouble G_Entity_FieldValue_Double(G_Entity *entity, const char *key)
-{
-	char *value = G_Entity_FieldValue_String(entity, key);
-	if (value)
-	{
-		while (*value && *value <= ' ')
-			value++;
-		return atof(value);
-	}
-	return 0;
-}
-
-void G_Entity_FieldValue_Vector(G_Entity *entity, const char *key, Nvec3 vector)
-{
-	NUint32 i;
-	char *value = G_Entity_FieldValue_String(entity, key);
-	VectorClear(vector);
-	if (value)
-	{
-		for (i = 0;i < 3;i++)
-		{
-			while (*value && *value <= ' ')
-				value++;
-			vector[i] = atof(value);
-			while (*value > ' ')
-				value++;
-		}
-	}
-}
-
 Nbool G_Entity_ReadPacket(G_PacketBuffer *buffer, NUint32 entityclassnumber)
 {
 	// read 16bit entitynum
@@ -749,7 +650,7 @@
 		if (G.client_networkentityindex[entitynum] < 0)
 		{
 			// create a new entity
-			entity = G_Entity_New(NULL, eclass);
+			entity = G_Entity_New(NULL, eclass, &GS.identityposition);
 			// network index this local entity represents
 			entity->networkindex = entitynum;
 			// backwards index from the network index to this local entity
@@ -781,8 +682,8 @@
 	NUint32 clientindex;
 	GS_Client *client;
 	for (clientindex = 0, client = GS.clients;clientindex < G_MAX_CLIENTS;clientindex++, client++)
-		if (client->netconnection)
-			client->netconnection->entitypriority[entitynumber] = Max(client->netconnection->entitypriority[entitynumber], 1);
+		if (client->netconnection && client->netconnection->entitypriority[entitynumber] < 1)
+			client->netconnection->entitypriority[entitynumber] = 1;
 }
 
 G_Entity *G_Entity_Find_CodeName(G_Entity *previous, const char *value)

Modified: trunk/game/g_entity.h
===================================================================
--- trunk/game/g_entity.h	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/game/g_entity.h	2006-03-27 09:16:27 UTC (rev 685)
@@ -6,30 +6,27 @@
 
 // G_Entity member functions:
 // creation/destruction of entities
-G_Entity *G_Entity_New(G_Entity *parent, const G_Entity_Class *eclass);
+G_Entity *G_Entity_New(G_Entity *parent, const G_Entity_Class *eclass, const G_Entity_Position *position);
 void G_Entity_Spawn(G_Entity *entity);
-void G_Entity_SpawnFromFields(G_Entity *entity);
 void G_Entity_Remove(G_Entity *entity);
 void G_Entity_RemoveChildren(G_Entity *entity);
-void G_Entity_RemoveFields(G_Entity *entity);
 void G_Entity_SpawnInventoryChildren(G_Entity *entity);
+// attaching entities to eachother
+void G_Entity_GetMatrix(G_Entity *entity, NUint32 index, matrix4x4_t *result);
+void G_Entity_UpdateAttachment(G_Entity *entity);
 // changing an entity's model
 G_Entity_Surface *G_Entity_AddSurface(G_Entity *entity, NUint32 meshindex);
 void G_Entity_RemoveSurface(G_Entity *entity, G_Entity_Surface *surface);
 void G_Entity_SetModelIndex(G_Entity *entity, NUint32 modelindex);
 void G_Entity_SetModel(G_Entity *entity, const char *modelname);
+// animation of an entity's model
+void G_Entity_Animation(G_Entity *entity, G_Entity_AnimationState *state);
 // entity physics
 void G_Entity_Relink(G_Entity *entity);
 void G_Entity_Move(G_Entity *self, NUint32 scope, Nvec stepheight, Nvec bounce);
 void G_Entity_PlayerPhysics(G_Entity *self, Nvec3 wishvel, Nvec groundfriction, Nvec groundaccel, Nvec stopspeed, Nvec airfriction, Nvec airaccel, Nvec airstopspeed, Nvec jumpspeed, Nvec gravityscale, Nvec3 thrustvel);
 void G_Entity_SetBrush_Box(G_Entity *entity, const Nvec3 boxmins, const Nvec3 boxmaxs);
 void G_Entity_SetBrush_Point(G_Entity *entity, const Nvec3 point);
-// editing
-void G_Entity_SetField(G_Entity *entity, const char *key, const char *value);
-Ndouble G_Entity_FieldValue_Double(G_Entity *entity, const char *key);
-NSint32 G_Entity_FieldValue_Integer(G_Entity *entity, const char *key);
-char *G_Entity_FieldValue_String(G_Entity *entity, const char *key);
-void G_Entity_FieldValue_Vector(G_Entity *entity, const char *key, Nvec3 vector);
 // networking
 Nbool G_Entity_ReadPacket(G_PacketBuffer *buffer, NUint32 entityclassnumber);
 void G_Entity_SendNetworkUpdate(G_Entity *entity);

Modified: trunk/game/g_entityclass.c
===================================================================
--- trunk/game/g_entityclass.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/game/g_entityclass.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -27,7 +27,7 @@
 
 static void G_Object_Light_WritePacket(G_Entity *self, G_PacketBuffer *buffer)
 {
-	G_PacketBuffer_WriteMatrix(buffer, &self->matrix, true, true, true);
+	G_PacketBuffer_WritePosition(buffer, &self->position, true, true, true, false, false);
 	G_PacketBuffer_WriteColorVector16(buffer, self->lightcolor);
 	G_PacketBuffer_WriteResourceIndex_NoCache(buffer, self->lightcubemap);
 	G_PacketBuffer_WriteBool(buffer, self->lightcastshadows);
@@ -38,7 +38,7 @@
 
 static void G_Object_Light_ReadPacket(G_Entity *self, G_PacketBuffer *buffer, Nbool reset)
 {
-	G_PacketBuffer_ReadMatrix(buffer, &self->matrix, true, true, true);
+	G_PacketBuffer_ReadPosition(buffer, &self->position, true, true, true, false, false);
 	G_PacketBuffer_ReadColorVector16(buffer, self->lightcolor);
 	self->lightcubemap = G_PacketBuffer_ReadResourceIndex_NoCache(buffer, RESOURCETYPE_TEXTURE);
 	self->lightcastshadows = G_PacketBuffer_ReadBool(buffer);
@@ -61,13 +61,13 @@
 
 static void G_Object_Model_WritePacket(G_Entity *self, G_PacketBuffer *buffer)
 {
-	G_PacketBuffer_WriteMatrix(buffer, &self->matrix, true, true, true);
+	G_PacketBuffer_WritePosition(buffer, &self->position, true, true, true, false, false);
 	G_PacketBuffer_WriteResourceIndex_NoCache(buffer, self->modelindex);
 }
 
 static void G_Object_Model_ReadPacket(G_Entity *self, G_PacketBuffer *buffer, Nbool reset)
 {
-	G_PacketBuffer_ReadMatrix(buffer, &self->matrix, true, true, true);
+	G_PacketBuffer_ReadPosition(buffer, &self->position, true, true, true, false, false);
 	G_Entity_SetModelIndex(self, G_PacketBuffer_ReadResourceIndex_NoCache(buffer, RESOURCETYPE_MODEL));
 }
 
@@ -125,6 +125,8 @@
 	user->localinput_pressedbuttonbits = 0;
 	VectorClear(user->localinput_relativeviewangles);
 
+	self->buttons = buttonbits;
+
 	speed = (user->flymode || user->noclipmode) ? 100 : self->eclass->speed;
 
 	VectorAdd(self->viewangles, relativeviewangles, self->viewangles);
@@ -132,17 +134,20 @@
 	self->viewangles[1] -= 360 * floor(self->viewangles[1] / 360);
 	self->viewangles[2] = 0;
 
+	G_Entity_Animation(self, &self->anim_head);
+	G_Entity_Animation(self, &self->anim_torso);
+	G_Entity_Animation(self, &self->anim_legs);
+
 	VectorClear(movement);
-	if (buttonbits & G_BUTTON_MOVEFORWARD)
-	{movement[0] += 1;}
-	if (buttonbits & G_BUTTON_MOVEBACKWARD) {movement[0] -= 1;}
-	if (buttonbits & G_BUTTON_MOVELEFT) {movement[1] += 1;}
-	if (buttonbits & G_BUTTON_MOVERIGHT) {movement[1] -= 1;}
+	if (buttonbits & G_BUTTON_MOVEFORWARD) movement[0] += 1;
+	if (buttonbits & G_BUTTON_MOVEBACKWARD) movement[0] -= 1;
+	if (buttonbits & G_BUTTON_MOVELEFT) movement[1] += 1;
+	if (buttonbits & G_BUTTON_MOVERIGHT) movement[1] -= 1;
 	if (user->flymode || user->noclipmode)
 	{
-		if (buttonbits & G_BUTTON_MOVEUP) {movement[2] += 1;}
-		if (buttonbits & G_BUTTON_MOVEDOWN) {movement[2] -= 1;}
-		Matrix4x4_CreateFromQuakeEntity(&newmatrix, self->matrix.m[0][3], self->matrix.m[1][3], self->matrix.m[2][3] + 0.7, self->viewangles[0], self->viewangles[1], self->viewangles[2], speed);
+		if (buttonbits & G_BUTTON_MOVEUP) movement[2] += 1;
+		if (buttonbits & G_BUTTON_MOVEDOWN) movement[2] -= 1;
+		Matrix4x4_CreateFromQuakeEntity(&newmatrix, self->position.m.m[0][3], self->position.m.m[1][3], self->position.m.m[2][3] + 0.7, self->viewangles[0], self->viewangles[1], self->viewangles[2], speed);
 	}
 	else
 		Matrix4x4_CreateFromQuakeEntity(&newmatrix, 0, 0, 0, 0, self->viewangles[1], 0, speed);
@@ -162,21 +167,21 @@
 		int j;
 		for (j = 0; j < 3; j++)
 		{
-			if (IsNAN(self->velocity[j]))
-				self->velocity[j] = 0;
+			if (IsNAN(self->position.velocity[j]))
+				self->position.velocity[j] = 0;
 		}
 	}
 
 	G_Entity_Move(self, user->noclipmode ? 0 : G_SCOPE_BLOCK_PLAYER, self->eclass->stepheight, 0);
 
-	//Matrix4x4_ConcatQuakeEntity(&self->matrix, movement[0], movement[1], movement[2], turn[0], turn[1], turn[2], 1);
-	//Matrix4x4_Normalize(&self->matrix, &self->matrix);
+	//Matrix4x4_ConcatQuakeEntity(&self->position.m, movement[0], movement[1], movement[2], turn[0], turn[1], turn[2], 1);
+	//Matrix4x4_Normalize(&self->position.m, &self->position.m);
 
 	if (user->client)
 	{
 		if (user->client->netconnection)
 		{
-			Matrix4x4_OriginFromMatrix(&self->matrix, user->client->netconnection->eyeorigin);
+			Matrix4x4_OriginFromMatrix(&self->position.m, user->client->netconnection->eyeorigin);
 			user->client->netconnection->eyeradius = 1000000; // 1000km
 		}
 		else
@@ -187,7 +192,7 @@
 			if (GS.localuserindex == self->localuserindex)
 			{
 				// set up the view matrix for the player
-				Matrix4x4_CreateFromQuakeEntity(&G.cameramatrix, self->matrix.m[0][3], self->matrix.m[1][3], self->matrix.m[2][3] + 0.7, self->viewangles[0], self->viewangles[1], self->viewangles[2], 1);
+				Matrix4x4_CreateFromQuakeEntity(&G.cameramatrix, self->position.m.m[0][3], self->position.m.m[1][3], self->position.m.m[2][3] + 0.7, self->viewangles[0], self->viewangles[1], self->viewangles[2], 1);
 			}
 		}
 	}
@@ -200,7 +205,7 @@
 static void G_Object_Infantry_WritePacket(G_Entity *self, G_PacketBuffer *buffer)
 {
 	G_PacketBuffer_Write16(buffer, GS.client_remotefromlocaluserindex[self->localuserindex]);
-	G_PacketBuffer_WriteMatrix(buffer, &self->matrix, true, false, false);
+	G_PacketBuffer_WritePosition(buffer, &self->position, true, false, false, false, false);
 	G_PacketBuffer_WriteAngles16(buffer, self->viewangles);
 }
 
@@ -208,7 +213,7 @@
 {
 	// TODO: bounds check userindex
 	self->localuserindex = GS.client_localfromremoteuserindex[G_PacketBuffer_Read16(buffer)];
-	G_PacketBuffer_ReadMatrix(buffer, &self->matrix, true, false, false);
+	G_PacketBuffer_ReadPosition(buffer, &self->position, true, false, false, false, false);
 	G_PacketBuffer_ReadAngles16(buffer, self->viewangles);
 	if (reset)
 		G_Entity_SetBrush_Box(self, playermins, playermaxs);
@@ -342,16 +347,63 @@
 {
 }
 
+static void G_Object_Weapon_LaunchProjectile(G_Entity *self)
+{
+	G_Entity_Position position;
+	G_Entity *projectile;
+	const G_Entity_Class *projectileclass;
+	Nvec3 speedvec;
+	position = self->position;
+	projectileclass = G_EntityClass_ByName(self->eclass->projectilecodename);
+	VectorSet(speedvec, projectileclass->speed, 0, 0);
+	Matrix4x4_Transform3x3(&position.m, speedvec, position.velocity);
+	// TODO: rifled bullet spin?
+	projectile = G_Entity_New(NULL, projectileclass, &position);
+	//if (!projectile)
+	//	return;
+}
+
 static void G_Object_Weapon_Frame(G_Entity *self)
 {
+	if (self->attachment_entity)
+		G_Entity_UpdateAttachment(self);
+	self->attackdelay -= G.frametime;
+	if (self->attackdelay <= 0)
+	{
+		if (self->owner->buttons & G_BUTTON_FIRE1)
+		{
+			G_Object_Weapon_LaunchProjectile(self);
+			self->attackdelay += self->eclass->autorefire;
+			G_Entity_SendNetworkUpdate(self);
+		}
+		else
+			self->attackdelay = 0;
+	}
 }
 
 static void G_Object_Weapon_WritePacket(G_Entity *self, G_PacketBuffer *buffer)
 {
+	if (self->owner)
+	{
+		G_PacketBuffer_WriteBool(buffer, true);
+		G_PacketBuffer_WriteEntityAsIndex(buffer, self->owner);
+		G_PacketBuffer_Write16(buffer, self->attachment_index);
+	}
+	else
+		G_PacketBuffer_WriteBool(buffer, false);
+	// we don't need much precision on how recently the gun was fired, so use
+	// an 8bit fraction-of-refire-time byte to save space
+	G_PacketBuffer_WriteClamped8(buffer, self->attackdelay, 255.0f / self->eclass->autorefire);
 }
 
 static void G_Object_Weapon_ReadPacket(G_Entity *self, G_PacketBuffer *buffer, Nbool reset)
 {
+	if (G_PacketBuffer_ReadBool(buffer))
+	{
+		self->owner = G_PacketBuffer_ReadEntityAsIndex(buffer);
+		self->attachment_index = G_PacketBuffer_Read16(buffer);
+	}
+	G_PacketBuffer_ReadClamped8(buffer, 255.0f / self->eclass->autorefire);
 }
 
 static void G_Object_Ammo_Spawn(G_Entity *self)
@@ -384,18 +436,33 @@
 
 static void G_Object_Projectile_Frame(G_Entity *self)
 {
+	// TODO: use a better physics function (one that handles spin)
+	G_Entity_PlayerPhysics(self, NULL, self->eclass->friction, self->eclass->acceleration, self->eclass->stopspeed, self->eclass->airfriction, self->eclass->airacceleration, self->eclass->airstopspeed, 0, 1, NULL);
+
+	G_Entity_Move(self, G_SCOPE_BLOCK_PROJECTILE, 0, 0);
+
+	self->lifetime -= G.frametime;
+	if (self->lifetime <= 0)
+		G_Entity_Remove(self);
 }
 
 static void G_Object_Projectile_WritePacket(G_Entity *self, G_PacketBuffer *buffer)
 {
+	// TODO: should we send only origin and velocity and try to guess the rest
+	// to save space, or be accurate and send origin rotation velocity spin?
+	G_PacketBuffer_WritePosition(buffer, &self->position, true, true, false, true, true);
+	G_PacketBuffer_WriteClamped8(buffer, self->lifetime, 255.0f / self->eclass->lifetime);
 }
 
 static void G_Object_Projectile_ReadPacket(G_Entity *self, G_PacketBuffer *buffer, Nbool reset)
 {
+	G_PacketBuffer_ReadPosition(buffer, &self->position, true, true, false, true, true);
+	self->lifetime = G_PacketBuffer_ReadClamped8(buffer, 255.0f / self->eclass->lifetime);
 }
 
 static void G_Object_Explosion_Spawn(G_Entity *self)
 {
+	// TODO: do damage
 }
 
 static void G_Object_Explosion_Remove(G_Entity *self)
@@ -404,14 +471,21 @@
 
 static void G_Object_Explosion_Frame(G_Entity *self)
 {
+	self->lifetime -= G.frametime;
+	if (self->lifetime <= 0)
+		G_Entity_Remove(self);
 }
 
 static void G_Object_Explosion_WritePacket(G_Entity *self, G_PacketBuffer *buffer)
 {
+	G_PacketBuffer_WritePosition(buffer, &self->position, true, false, false, false, false);
+	G_PacketBuffer_WriteClamped8(buffer, self->lifetime, 255.0f / self->eclass->lifetime);
 }
 
 static void G_Object_Explosion_ReadPacket(G_Entity *self, G_PacketBuffer *buffer, Nbool reset)
 {
+	G_PacketBuffer_ReadPosition(buffer, &self->position, true, false, false, false, false);
+	self->lifetime = G_PacketBuffer_ReadClamped8(buffer, 255.0f / self->eclass->lifetime);
 }
 
 static void G_Object_Light_Attached_Spawn(G_Entity *self)
@@ -429,7 +503,7 @@
 		G_Entity_Remove(self);
 		return;
 	}
-	Matrix4x4_Concat(&self->matrix, &self->owner->matrix, &self->lightmatrix);
+	Matrix4x4_Concat(&self->position.m, &self->owner->position.m, &self->lightmatrix);
 	G_Entity_Relink(self);
 }
 
@@ -451,7 +525,7 @@
 	model = Resource_GetData(self->modelindex);
 	if (model)
 		G_Entity_SetBrush_Box(self, model->basecullmins, model->basecullmaxs);
-	light = G_Entity_New(self, G_EntityClass_ByName("light_attached"));
+	light = G_Entity_New(self, G_EntityClass_ByName("light_attached"), &self->position);
 	Matrix4x4_CreateFromQuakeEntity(&light->lightmatrix, 0, 3.5, 4, 0, 0, 0, 30);
 	VectorSet(light->lightcolor, 1, 0.9, 0.2);
 	light->lightcastshadows = true;
@@ -474,21 +548,21 @@
 
 static void G_Object_Vehicle_RockBore_WritePacket(G_Entity *self, G_PacketBuffer *buffer)
 {
-	G_PacketBuffer_WriteMatrix(buffer, &self->matrix, true, true, true);
+	G_PacketBuffer_WritePosition(buffer, &self->position, true, true, true, true, true);
 }
 
 static void G_Object_Vehicle_RockBore_ReadPacket(G_Entity *self, G_PacketBuffer *buffer, Nbool reset)
 {
 	Model *model;
 	G_Entity *light;
-	G_PacketBuffer_ReadMatrix(buffer, &self->matrix, true, true, true);
+	G_PacketBuffer_ReadPosition(buffer, &self->position, true, true, true, true, true);
 	if (reset)
 	{
 		model = Resource_GetData(self->modelindex);
 		if (model)
 			G_Entity_SetBrush_Box(self, model->basecullmins, model->basecullmaxs);
 		G_Entity_RemoveChildren(self);
-		light = G_Entity_New(self, G_EntityClass_ByName("light_attached"));
+		light = G_Entity_New(self, G_EntityClass_ByName("light_attached"), &self->position);
 		Matrix4x4_CreateFromQuakeEntity(&light->lightmatrix, 0, 3.5, 4, 0, 0, 0, 30);
 		VectorSet(light->lightcolor, 1, 0.9, 0.2);
 		light->lightcastshadows = true;
@@ -510,7 +584,7 @@
 		G_Entity_Remove(self);
 		return;
 	}
-	Matrix4x4_Concat(&self->matrix, &self->owner->matrix, &self->lightmatrix);
+	Matrix4x4_Concat(&self->position.m, &self->owner->position.m, &self->lightmatrix);
 	G_Entity_Relink(self);
 }
 #endif
@@ -701,103 +775,6 @@
 
 G_Entity_Class G_EntityClasses[G_ENTITYCLASS_MAX];
 
-#if 0
-enum G_CSVColumn
-{
-	CSVCOLUMN_CodeName,
-	CSVCOLUMN_EnglishName,
-	CSVCOLUMN_Class,
-	CSVCOLUMN_Model,
-	CSVCOLUMN_Mass,
-	CSVCOLUMN_Health,
-	CSVCOLUMN_Heal,
-	CSVCOLUMN_NoRemove,
-	CSVCOLUMN_I1Q,
-	CSVCOLUMN_I1R,
-	CSVCOLUMN_I1C,
-	CSVCOLUMN_I2Q,
-	CSVCOLUMN_I2R,
-	CSVCOLUMN_I2C,
-	CSVCOLUMN_I3Q,
-	CSVCOLUMN_I3R,
-	CSVCOLUMN_I3C,
-	CSVCOLUMN_I4Q,
-	CSVCOLUMN_I4R,
-	CSVCOLUMN_I4C,
-	CSVCOLUMN_I5Q,
-	CSVCOLUMN_I5R,
-	CSVCOLUMN_I5C,
-	CSVCOLUMN_I6Q,
-	CSVCOLUMN_I6R,
-	CSVCOLUMN_I6C,
-	CSVCOLUMN_Projectile,
-	CSVCOLUMN_SemiRefire,
-	CSVCOLUMN_AutoRefire,
-	CSVCOLUMN_Speed,
-	CSVCOLUMN_Acceleration,
-	CSVCOLUMN_TopSpeed,
-	CSVCOLUMN_LifeTime,
-	CSVCOLUMN_ImpactDelay,
-	CSVCOLUMN_FleshDamage,
-	CSVCOLUMN_ArmorDamage,
-	CSVCOLUMN_Force,
-	CSVCOLUMN_DamageRadius,
-	CSVCOLUMN_Shake,
-	CSVCOLUMN_ShakeRadius,
-	CSVCOLUMN_IdleAnim,
-	CSVCOLUMN_IdleFPS,
-	CSVCOLUMN_END
-};
-
-static const char *csv_columnnames[CSVCOLUMN_END] =
-{
-	"CodeName",
-	"EnglishName",
-	"Class",
-	"Model",
-	"Mass",
-	"Health",
-	"Heal",
-	"NoRemove",
-	"I1Q",
-	"I1R",
-	"I1C",
-	"I2Q",
-	"I2R",
-	"I2C",
-	"I3Q",
-	"I3R",
-	"I3C",
-	"I4Q",
-	"I4R",
-	"I4C",
-	"I5Q",
-	"I5R",
-	"I5C",
-	"I6Q",
-	"I6R",
-	"I6C",
-	"Projectile",
-	"SemiRefire",
-	"AutoRefire",
-	"Speed",
-	"Acceleration",
-	"TopSpeed",
-	"LifeTime",
-	"ImpactDelay",
-	"FleshDamage",
-	"ArmorDamage",
-	"Force",
-	"DamageRadius",
-	"Shake",
-	"ShakeRadius",
-	"IdleAnim",
-	"IdleFPS",
-};
-
-static CSVColumn csv_columnremap[64];
-#endif
-
 typedef enum CSVColumnFieldType
 {
 	CSVCOLUMNFIELDTYPE_CHARPOINTER,
@@ -828,24 +805,29 @@
 	CSVCOLUMNINFO("Health", health, CSVCOLUMNFIELDTYPE_NVEC),
 	CSVCOLUMNINFO("Heal", heal, CSVCOLUMNFIELDTYPE_NVEC),
 	CSVCOLUMNINFO("NoRemove", noremove, CSVCOLUMNFIELDTYPE_BOOL),
-	CSVCOLUMNINFO("I1Q", inventory[0].quantity, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I1R", inventory[0].regen, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I1C", inventory[0].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
-	CSVCOLUMNINFO("I2Q", inventory[1].quantity, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I2R", inventory[1].regen, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I2C", inventory[1].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
-	CSVCOLUMNINFO("I3Q", inventory[2].quantity, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I3R", inventory[2].regen, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I3C", inventory[2].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
-	CSVCOLUMNINFO("I4Q", inventory[3].quantity, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I4R", inventory[3].regen, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I4C", inventory[3].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
-	CSVCOLUMNINFO("I5Q", inventory[4].quantity, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I5R", inventory[4].regen, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I5C", inventory[4].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
-	CSVCOLUMNINFO("I6Q", inventory[5].quantity, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I6R", inventory[5].regen, CSVCOLUMNFIELDTYPE_NVEC),
-	CSVCOLUMNINFO("I6C", inventory[5].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("Respawn", respawn, CSVCOLUMNFIELDTYPE_NVEC),
+	CSVCOLUMNINFO("I0C", inventory[0].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I0B", inventory[0].name, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I1C", inventory[1].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I1B", inventory[1].name, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I2C", inventory[2].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I2B", inventory[2].name, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I3C", inventory[3].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I3B", inventory[3].name, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I4C", inventory[4].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I4B", inventory[4].name, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I5C", inventory[5].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I5B", inventory[5].name, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I6C", inventory[6].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I6B", inventory[6].name, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I7C", inventory[7].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I7B", inventory[7].name, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I8C", inventory[8].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I8B", inventory[8].name, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I9C", inventory[9].codename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("I9B", inventory[9].name, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("AmmoMax", ammomax, CSVCOLUMNFIELDTYPE_NVEC),
+	CSVCOLUMNINFO("AmmoRegen", ammoregen, CSVCOLUMNFIELDTYPE_NVEC),
 	CSVCOLUMNINFO("Projectile", projectilecodename, CSVCOLUMNFIELDTYPE_CHARPOINTER),
 	CSVCOLUMNINFO("SemiRefire", semirefire, CSVCOLUMNFIELDTYPE_NVEC),
 	CSVCOLUMNINFO("AutoRefire", autorefire, CSVCOLUMNFIELDTYPE_NVEC),
@@ -863,6 +845,10 @@
 	CSVCOLUMNINFO("AirStopSpeed", airstopspeed, CSVCOLUMNFIELDTYPE_NVEC),
 	CSVCOLUMNINFO("HoverThrust", hoverthrust, CSVCOLUMNFIELDTYPE_NVEC),
 	CSVCOLUMNINFO("HoverAltitude", hoveraltitude, CSVCOLUMNFIELDTYPE_NVEC),
+	CSVCOLUMNINFO("Cloaking", cloaking, CSVCOLUMNFIELDTYPE_BOOL),
+	CSVCOLUMNINFO("JumpFlight", jumpflight, CSVCOLUMNFIELDTYPE_BOOL),
+	CSVCOLUMNINFO("CrouchShield", crouchshield, CSVCOLUMNFIELDTYPE_BOOL),
+	CSVCOLUMNINFO("CrouchTurret", crouchturret, CSVCOLUMNFIELDTYPE_BOOL),
 	CSVCOLUMNINFO("LifeTime", lifetime, CSVCOLUMNFIELDTYPE_NVEC),
 	CSVCOLUMNINFO("ImpactDelay", impactdelay, CSVCOLUMNFIELDTYPE_NVEC),
 	CSVCOLUMNINFO("FleshDamage", fleshdamage, CSVCOLUMNFIELDTYPE_NVEC),
@@ -871,8 +857,8 @@
 	CSVCOLUMNINFO("DamageRadius", damageradius, CSVCOLUMNFIELDTYPE_NVEC),
 	CSVCOLUMNINFO("Shake", shake, CSVCOLUMNFIELDTYPE_NVEC),
 	CSVCOLUMNINFO("ShakeRadius", shakeradius, CSVCOLUMNFIELDTYPE_NVEC),
-	//CSVCOLUMNINFO("IdleAnim", idleanim, CSVCOLUMNFIELDTYPE_CHARPOINTER),
-	//CSVCOLUMNINFO("IdleFPS", idlefps, CSVCOLUMNFIELDTYPE_NVEC),
+	CSVCOLUMNINFO("IdleAnim", idleanim, CSVCOLUMNFIELDTYPE_CHARPOINTER),
+	CSVCOLUMNINFO("IdleFPS", idlefps, CSVCOLUMNFIELDTYPE_NVEC),
 
 	{NULL, 0, CSVCOLUMNFIELDTYPE_END}
 };
@@ -952,10 +938,7 @@
 			switch(info->fieldtype)
 			{
 			case CSVCOLUMNFIELDTYPE_CHARPOINTER:
-				if (token[0])
-					String_Set(&fieldpointer->p, GS.memzone, token);
-				else
-					fieldpointer->p = NULL;
+				String_Set(&fieldpointer->p, GS.memzone, token);
 				break;
 			case CSVCOLUMNFIELDTYPE_NVEC:
 				fieldpointer->f = atof(token);
@@ -966,39 +949,6 @@
 			default:
 				break;
 			}
-#if 0
-			case CSVCOLUMN_CodeName: String_Set(&eclass->codename, token);break;
-			case CSVCOLUMN_EnglishName: String_Set(&eclass->codename, token);break;
-			case CSVCOLUMN_Class: String_Set(&eclass->codename, token);break;
-			case CSVCOLUMN_Model: String_Set(&eclass->codename, token);break;
-			case CSVCOLUMN_Mass: eclass->mass = atof(token);break;
-			case CSVCOLUMN_Health: eclass->health = atof(token);break;
-			case CSVCOLUMN_Heal: eclass->heal = atof(token);break;
-			case CSVCOLUMN_NoRemove: eclass->noremove = !String_ICompare(token, "TRUE");break;
-			case CSVCOLUMN_I1Q: String_Set(&eclass->codename, token);break;
-			case CSVCOLUMN_Projectile: String_Set(&eclass->projectilename, token);break;
-			case CSVCOLUMN_SemiRefire: eclass->semirefire = atof(token);break;
-			case CSVCOLUMN_AutoRefire: eclass->autorefire = atof(token);break;
-			case CSVCOLUMN_Speed: eclass-> = atof(token);break;
-			case CSVCOLUMN_Acceleration: eclass-> = atof(token);break;
-			case CSVCOLUMN_TopSpeed: eclass-> = atof(token);break;
-			case CSVCOLUMN_LifeTime: eclass-> = atof(token);break;
-			case CSVCOLUMN_ImpactDelay: eclass-> = atof(token);break;
-			case CSVCOLUMN_FleshDamage: eclass-> = atof(token);break;
-			case CSVCOLUMN_ArmorDAmage: eclass-> = atof(token);break;
-			case CSVCOLUMN_Force: eclass-> = atof(token);break;
-			case CSVCOLUMN_damageRadius: eclass-> = atof(token);break;
-			case CSVCOLUMN_Shake: eclass-> = atof(token);break;
-			case CSVCOLUMN_ShakeRadius: eclass-> = atof(token);break;
-			case CSVCOLUMN_: eclass-> = atof(token);break;
-			case CSVCOLUMN_: eclass-> = atof(token);break;
-			case CSVCOLUMN_: eclass-> = atof(token);break;
-			case CSVCOLUMN_: eclass-> = atof(token);break;
-			case CSVCOLUMN_: eclass-> = atof(token);break;
-			case CSVCOLUMN_: eclass-> = atof(token);break;
-			case CSVCOLUMN_: eclass-> = atof(token);break;
-			}
-#endif
 			column++;
 		}
 		if (tokentype == G_CSV_TOKENTYPE_EOF)

Modified: trunk/game/g_main.c
===================================================================
--- trunk/game/g_main.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/game/g_main.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -154,7 +154,7 @@
 	if (!Video_SetMode(Cvar_GetValue("vid_width")->ival, Cvar_GetValue("vid_height")->ival, 32, Cvar_GetValue("vid_fullscreen")->ival, true))
 	if (!Video.width || !Video_SetMode(Video.width, Video.height, Video.bpp, Video.fullscreen, Video.openglmode))
 	if (!Video_SetMode(640, 480, 32, false, true))
-	if (!Video_SetMode(640, 480, 32, false, false))
+	//if (!Video_SetMode(640, 480, 32, false, false))
 	{
 		Console_Printf("Unable to open video!\n");
 		GS.quit = true;
@@ -200,6 +200,11 @@
 	GS.realtime = GS.oldrealtime = System_Time();
 	GS.protocolname = "DarkWar1";
 
+	Matrix4x4_CreateIdentity(&GS.identityposition.m);
+	Matrix4x4_CreateIdentity(&GS.identityposition.inversem);
+	VectorClear(GS.identityposition.velocity);
+	Vector4Set(GS.identityposition.spin, 1, 0, 0, 0);
+
 	Menu_Init();
 	G_InitCommands();
 	G_World_Init();

Modified: trunk/game/g_main.h
===================================================================
--- trunk/game/g_main.h	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/game/g_main.h	2006-03-27 09:16:27 UTC (rev 685)
@@ -2,6 +2,15 @@
 #ifndef G_MAIN_H
 #define G_MAIN_H
 
+typedef struct G_Entity_Position
+{
+	matrix4x4_t m;
+	matrix4x4_t inversem;
+	Nvec3 velocity;
+	Nvec4 spin;
+}
+G_Entity_Position;
+
 #include "game/g_network.h"
 #include "collision.h"
 
@@ -205,6 +214,9 @@
 	NUint8 *server_networkresource_sent;
 	NUint32 client_networkresource_maxindices;
 	NUint32 *client_networkresource_remapindex;
+	// reference values for initializing structs
+	matrix4x4_t identitymatrix;
+	G_Entity_Position identityposition;
 }
 G_Static;
 
@@ -277,23 +289,14 @@
 #define G_SCOPE_NETWORK_HEARABLE (1<<24)
 #define G_SCOPE_AUDIO_SOUNDSOURCE (1<<25)
 
-typedef struct G_Entity_Field
-{
-	struct G_Entity_Field *next;
-	char *key;
-	char *value;
-}
-G_Entity_Field;
-
 // the protocol only supports up to 128
 #define G_ENTITYCLASS_MAX 128
 #define G_ENTITYCLASS_INVENTORY_MAX 6
 
 typedef struct G_Entity_Class_InventoryEntry
 {
-	Nvec quantity;
-	Nvec regen;
 	char *codename;
+	char *transformname;
 }
 G_Entity_Class_InventoryEntry;
 
@@ -331,7 +334,10 @@
 	Nvec health;
 	Nvec heal;
 	Nbool noremove;
+	Nvec respawn;
 	G_Entity_Class_InventoryEntry inventory[G_ENTITYCLASS_INVENTORY_MAX];
+	Nvec ammomax;
+	Nvec ammoregen;
 	char *projectilecodename;
 	Nvec semirefire;
 	Nvec autorefire;
@@ -349,6 +355,10 @@
 	Nvec airstopspeed;
 	Nvec hoverthrust;
 	Nvec hoveraltitude;
+	Nbool cloaking;
+	Nbool jumpflight;
+	Nbool crouchshield;
+	Nbool crouchturret;
 	Nvec lifetime;
 	Nvec impactdelay;
 	Nvec fleshdamage;
@@ -357,6 +367,8 @@
 	Nvec damageradius;
 	Nvec shake;
 	Nvec shakeradius;
+	char *idleanim;
+	Nvec idlefps;
 }
 G_Entity_Class;
 
@@ -414,6 +426,52 @@
 
 #define G_ENTITY_CHILDREN 16
 
+typedef enum G_Entity_AnimationType
+{
+	G_ANIM_IDLE,
+	G_ANIM_FIRE1,
+	G_ANIM_FIRE2,
+	G_ANIM_RELOAD,
+	G_ANIM_THROW,
+	G_ANIM_GET,
+	G_ANIM_PUT,
+	G_ANIM_RUNFORWARD,
+	G_ANIM_RUNBACKWARD,
+	G_ANIM_RUNLEFT,
+	G_ANIM_RUNRIGHT,
+	G_ANIM_WALKFORWARD,
+	G_ANIM_WALKBACKWARD,
+	G_ANIM_WALKLEFT,
+	G_ANIM_WALKRIGHT,
+	G_ANIM_ROLLFORWARD,
+	G_ANIM_ROLLBACKWARD,
+	G_ANIM_ROLLLEFT,
+	G_ANIM_ROLLRIGHT,
+	G_ANIM_JUMP,
+	G_ANIM_FALL,
+	G_ANIM_LAND,
+	G_ANIM_DYING,
+	G_ANIM_DEAD,
+	G_ANIM_SIGNAL_FORWARD,
+	G_ANIM_SIGNAL_STOP,
+	G_ANIM_SIGNAL_RETREAT,
+	G_ANIM_SIGNAL_ATTACK,
+	G_ANIM_SIGNAL_DEFEND,
+	G_ANIM_SIGNAL_HOLDPOSITION,
+}
+G_Entity_AnimationType;
+
+typedef struct G_Entity_AnimationState
+{
+	// type of animation (for comparison purposes)
+	G_Entity_AnimationType type;
+	// time since animation started
+	float time;
+	// the ModelAnim resource being shownf
+	NUint32 resourceindex;
+}
+G_Entity_AnimationState;
+
 typedef struct G_Entity
 {
 	// class this entity uses
@@ -422,24 +480,29 @@
 	// owner of this entity (used by projectiles mainly)
 	struct G_Entity *owner;
 	struct G_Entity *children[G_ENTITY_CHILDREN];
+	struct G_Entity *attachment_entity;
+	NUint32 attachment_transformindex;
+	matrix4x4_t attachment_matrix;
 	G_Entity_Surface *surfacelist;
 	G_Entity_Sound sound;
+	G_Entity_AnimationState anim_head;
+	G_Entity_AnimationState anim_torso;
+	G_Entity_AnimationState anim_legs;
 	// if >= 0 this is the index in the G.client_networkentityindex array that
 	// contains a pointer to this entity
 	NSint32 networkindex;
 	// index of associated user if this is a player entity
 	NUint32 localuserindex;
+	// pressed buttons as of last Infantry_Frame call, causes weapons to fire
+	NUint32 buttons;
 	// TODO: rendering
 	// index of model this entity is using
 	NUint32 modelindex;
 	// set of skeletal transforms for rendering the model, or NULL for static
+	NUint32 numtransforms;
 	matrix4x4_t *transforms;
-	// entity transform (skeletal is relative to this)
-	matrix4x4_t matrix;
-	// velocity (second order position)
-	Nvec3 velocity;
-	// axis and angle
-	Nvec4 spinvelocity;
+	// entity transform (skeletal is relative to this) and velocity
+	G_Entity_Position position;
 	// builtin collision brush buffers (to avoid alloc/free)
 	Collision_Brush collisionbrush;
 	Collision_Point collisionbrushpoints[16];
@@ -470,7 +533,14 @@
 	Nvec quantity;
 	// fields (classname and origin and so on), only present in editing mode
 	// and during loading
-	G_Entity_Field *fields;
+	NStringKeys keys;
+	// animation
+	G_Entity_AnimationState anim;
+	Nvec animframe;
+	// projectiles
+	Nvec lifetime;
+	// weapons
+	Nvec attackdelay;
 }
 G_Entity;
 

Modified: trunk/game/g_network.c
===================================================================
--- trunk/game/g_network.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/game/g_network.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -278,9 +278,9 @@
 			if (netconnection->entitypriority[i] < (G_NET_ENTITYPRIORITYLEVELS-1))
 			{
 				Nvec3 relativeorigin;
-				relativeorigin[0] = G.entities[i].matrix.m[0][3] - netconnection->eyeorigin[0];
-				relativeorigin[1] = G.entities[i].matrix.m[1][3] - netconnection->eyeorigin[1];
-				relativeorigin[2] = G.entities[i].matrix.m[2][3] - netconnection->eyeorigin[2];
+				relativeorigin[0] = G.entities[i].position.m.m[0][3] - netconnection->eyeorigin[0];
+				relativeorigin[1] = G.entities[i].position.m.m[1][3] - netconnection->eyeorigin[1];
+				relativeorigin[2] = G.entities[i].position.m.m[2][3] - netconnection->eyeorigin[2];
 				newpriority = (int)(G_NET_ENTITYPRIORITYMAX - VectorLength(relativeorigin) * G_NET_ENTITYPRIORITYDISTANCESCALE);
 				newpriority = netconnection->entitypriority[i] + Max(G_NET_ENTITYPRIORITYMIN, newpriority);
 				netconnection->entitypriority[i] = (NUint8)Min(newpriority, G_NET_ENTITYPRIORITYLEVELS-1);

Modified: trunk/game/g_packetbuffer.c
===================================================================
--- trunk/game/g_packetbuffer.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/game/g_packetbuffer.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -194,56 +194,81 @@
 
 // functions for more specialized data types
 
-void G_PacketBuffer_WriteMatrix(G_PacketBuffer *buf, matrix4x4_t *matrix, Nbool sendorigin, Nbool sendrotation, Nbool sendscale)
+void G_PacketBuffer_WritePosition(G_PacketBuffer *buf, G_Entity_Position *p, Nbool sendorigin, Nbool sendrotation, Nbool sendscale, Nbool sendvelocity, Nbool sendspin)
 {
+	// location
 	if (sendorigin)
 	{
-		G_PacketBuffer_WriteFloat(buf, matrix->m[0][3]);
-		G_PacketBuffer_WriteFloat(buf, matrix->m[1][3]);
-		G_PacketBuffer_WriteFloat(buf, matrix->m[2][3]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[0][3]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[1][3]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[2][3]);
 	}
 	// TODO: optimize rotation/scale sending, rotation can be sent as a 3
 	// component version of a normalized quat, scale can be sent as a float
 	if (sendrotation || sendscale)
 	{
-		G_PacketBuffer_WriteFloat(buf, matrix->m[0][0]);
-		G_PacketBuffer_WriteFloat(buf, matrix->m[0][1]);
-		G_PacketBuffer_WriteFloat(buf, matrix->m[0][2]);
-		G_PacketBuffer_WriteFloat(buf, matrix->m[1][0]);
-		G_PacketBuffer_WriteFloat(buf, matrix->m[1][1]);
-		G_PacketBuffer_WriteFloat(buf, matrix->m[1][2]);
-		G_PacketBuffer_WriteFloat(buf, matrix->m[2][0]);
-		G_PacketBuffer_WriteFloat(buf, matrix->m[2][1]);
-		G_PacketBuffer_WriteFloat(buf, matrix->m[2][2]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[0][0]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[1][0]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[2][0]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[0][1]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[1][1]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[2][1]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[0][2]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[1][2]);
+		G_PacketBuffer_WriteFloat(buf, p->m.m[2][2]);
 	}
+	// second order location (velocity)
+	if (sendvelocity)
+	{
+		G_PacketBuffer_WriteFloat(buf, p->velocity[0]);
+		G_PacketBuffer_WriteFloat(buf, p->velocity[1]);
+		G_PacketBuffer_WriteFloat(buf, p->velocity[2]);
+	}
+	// second order rotation (spin)
+	// this is a rodrigues vector (axis plus angle of rotation around it)
+	if (sendspin)
+	{
+		G_PacketBuffer_WriteFloat(buf, p->spin[0]);
+		G_PacketBuffer_WriteFloat(buf, p->spin[1]);
+		G_PacketBuffer_WriteFloat(buf, p->spin[2]);
+		G_PacketBuffer_WriteFloat(buf, p->spin[3]);
+	}
 }
 
-void G_PacketBuffer_ReadMatrix(G_PacketBuffer *buf, matrix4x4_t *matrix, Nbool sendorigin, Nbool sendrotation, Nbool sendscale)
+void G_PacketBuffer_ReadPosition(G_PacketBuffer *buf, G_Entity_Position *p, Nbool sendorigin, Nbool sendrotation, Nbool sendscale, Nbool sendvelocity, Nbool sendspin)
 {
+	*p = GS.identityposition;
 	if (sendorigin)
 	{
-		matrix->m[0][3] = G_PacketBuffer_ReadFloat(buf);
-		matrix->m[1][3] = G_PacketBuffer_ReadFloat(buf);
-		matrix->m[2][3] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[0][3] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[1][3] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[2][3] = G_PacketBuffer_ReadFloat(buf);
 	}
 	if (sendrotation || sendscale)
 	{
-		matrix->m[0][0] = G_PacketBuffer_ReadFloat(buf);
-		matrix->m[0][1] = G_PacketBuffer_ReadFloat(buf);
-		matrix->m[0][2] = G_PacketBuffer_ReadFloat(buf);
-		matrix->m[1][0] = G_PacketBuffer_ReadFloat(buf);
-		matrix->m[1][1] = G_PacketBuffer_ReadFloat(buf);
-		matrix->m[1][2] = G_PacketBuffer_ReadFloat(buf);
-		matrix->m[2][0] = G_PacketBuffer_ReadFloat(buf);
-		matrix->m[2][1] = G_PacketBuffer_ReadFloat(buf);
-		matrix->m[2][2] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[0][0] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[0][1] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[0][2] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[1][0] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[1][1] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[1][2] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[2][0] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[2][1] = G_PacketBuffer_ReadFloat(buf);
+		p->m.m[2][2] = G_PacketBuffer_ReadFloat(buf);
 	}
-	// LordHavoc: for a good time, comment out these lines; it took me a long
-	// time to figure out the resulting rendering bug.
-	matrix->m[3][0] = 0;
-	matrix->m[3][1] = 0;
-	matrix->m[3][2] = 0;
-	matrix->m[3][3] = 1;
+	if (sendvelocity)
+	{
+		p->velocity[0] = G_PacketBuffer_ReadFloat(buf);
+		p->velocity[1] = G_PacketBuffer_ReadFloat(buf);
+		p->velocity[2] = G_PacketBuffer_ReadFloat(buf);
+	}
+	if (sendspin)
+	{
+		p->spin[0] = G_PacketBuffer_ReadFloat(buf);
+		p->spin[1] = G_PacketBuffer_ReadFloat(buf);
+		p->spin[2] = G_PacketBuffer_ReadFloat(buf);
+		p->spin[3] = G_PacketBuffer_ReadFloat(buf);
+	}
 }
 
 void G_PacketBuffer_WriteColorVector16(G_PacketBuffer *buf, Nvec3 color)
@@ -322,3 +347,18 @@
 	return G_World_ResourceIndex_FromNetwork(G_PacketBuffer_Read32(buf));
 }
 
+void G_PacketBuffer_WriteEntityAsIndex(G_PacketBuffer *buf, G_Entity *entity)
+{
+	G_PacketBuffer_Write16(buf, entity - G.entities);
+}
+
+G_Entity *G_PacketBuffer_ReadEntityAsIndex(G_PacketBuffer *buf)
+{
+	NUint32 index;
+	index = G_PacketBuffer_Read16(buf);
+	if (index >= G_MAX_ENTITIES)
+		return NULL;
+	if (G.client_networkentityindex[index] < 0)
+		return NULL;
+	return G.entities + G.client_networkentityindex[index];
+}

Modified: trunk/game/g_packetbuffer.h
===================================================================
--- trunk/game/g_packetbuffer.h	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/game/g_packetbuffer.h	2006-03-27 09:16:27 UTC (rev 685)
@@ -51,8 +51,10 @@
 Nsize G_PacketBuffer_ReadBytes(G_PacketBuffer *buf, NUint8 *buffer, Nsize buffersize);
 
 // functions for more specialized data types:
-void G_PacketBuffer_WriteMatrix(G_PacketBuffer *buf, matrix4x4_t *matrix, Nbool sendorigin, Nbool sendrotation, Nbool sendscale);
-void G_PacketBuffer_ReadMatrix(G_PacketBuffer *buf, matrix4x4_t *matrix, Nbool sendorigin, Nbool sendrotation, Nbool sendscale);
+struct G_Entity_Position;
+struct G_Entity;
+void G_PacketBuffer_WritePosition(G_PacketBuffer *buf, struct G_Entity_Position *p, Nbool sendorigin, Nbool sendrotation, Nbool sendscale, Nbool sendvelocity, Nbool sendspin);
+void G_PacketBuffer_ReadPosition(G_PacketBuffer *buf, struct G_Entity_Position *p, Nbool sendorigin, Nbool sendrotation, Nbool sendscale, Nbool sendvelocity, Nbool sendspin);
 void G_PacketBuffer_WriteColorVector16(G_PacketBuffer *buf, Nvec3 color);
 void G_PacketBuffer_ReadColorVector16(G_PacketBuffer *buf, Nvec3 color);
 void G_PacketBuffer_WriteClamped8(G_PacketBuffer *buf, Nvec f, Nvec scale);
@@ -61,6 +63,8 @@
 void G_PacketBuffer_ReadAngles16(G_PacketBuffer *buf, Nvec3 angles);
 void G_PacketBuffer_WriteBool(G_PacketBuffer *buf, NUint32 i);
 Nbool G_PacketBuffer_ReadBool(G_PacketBuffer *buf);
+void G_PacketBuffer_WriteEntityAsIndex(G_PacketBuffer *buf, struct G_Entity *entity);
+struct G_Entity *G_PacketBuffer_ReadEntityAsIndex(G_PacketBuffer *buf);
 // nocache versions send the actual name string (type has to be known by the reader)
 void G_PacketBuffer_WriteResourceIndex_NoCache(G_PacketBuffer *buf, NUint32 i);
 NUint32 G_PacketBuffer_ReadResourceIndex_NoCache(G_PacketBuffer *buf, NUint32 type);

Modified: trunk/game/g_render.c
===================================================================
--- trunk/game/g_render.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/game/g_render.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -29,7 +29,7 @@
 			// TODO: verify the resource type is RESOURCETYPE_MODEL
 			model = Resource_GetData(entity->modelindex);
 			if (model)
-				R_SetEntity(&entity->matrix, entity->cullradius, entity->modelindex);
+				R_SetEntity(&entity->position.m, entity->cullradius, entity->modelindex);
 		}
 		if (!model)
 			continue;
@@ -64,7 +64,7 @@
 		if (currententity != entity)
 		{
 			currententity = entity;
-			R_SetEntity(&entity->matrix, entity->cullradius, entity->modelindex);
+			R_SetEntity(&entity->position.m, entity->cullradius, entity->modelindex);
 		}
 		mesh = model->meshes + surface->meshindex;
 		material = Resource_GetData(mesh->resource_material);
@@ -89,7 +89,7 @@
 						mode = R_DRAWMODE_LIT_LIGHTING;
 						R_SetDrawMode(R_DRAWMODE_LIT_LIGHTING);
 					}
-					R_SetLight(&light->matrix, light->lightcolor, light->lightcubemap, light->lightambientintensity, light->lightdiffuseintensity, light->lightspecularintensity);
+					R_SetLight(&light->position.m, light->lightcolor, light->lightcubemap, light->lightambientintensity, light->lightdiffuseintensity, light->lightspecularintensity);
 					R_DrawMesh(mesh->resource_material, surface->meshindex, entity->transforms);
 				}
 			}
@@ -389,11 +389,11 @@
 			light = G.drawview_lights[lnum];
 
 			// tell the renderer to prepare for light rendering
-			R_SetLight(&light->matrix, light->lightcolor, light->lightcubemap, light->lightambientintensity, light->lightdiffuseintensity, light->lightspecularintensity);
+			R_SetLight(&light->position.m, light->lightcolor, light->lightcubemap, light->lightambientintensity, light->lightdiffuseintensity, light->lightspecularintensity);
 
 			// find all surfaces visible to the light
-			Matrix4x4_OriginFromMatrix(&light->matrix, lightorigin);
-			lightradius = Matrix4x4_ScaleFromMatrix(&light->matrix);
+			Matrix4x4_OriginFromMatrix(&light->position.m, lightorigin);
+			lightradius = Matrix4x4_ScaleFromMatrix(&light->position.m);
 			G_Scope_VisibleSurfacesAndLights(G_SCOPE_RENDER_OPAQUE, lightorigin, lightradius, G_DRAWVIEW_SURFACES, G.drawview_light_surfaces, &G.drawview_light_numsurfaces, 0, NULL, NULL, false);
 
 			// make lists by type from the visible surfaces

Modified: trunk/game/g_world.c
===================================================================
--- trunk/game/g_world.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/game/g_world.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -225,13 +225,18 @@
 {
 	NUint32 j;
 	Util_ParseC_Thread thread;
+	NStringKeys keys;
+	G_Entity *entity;
+	const G_Entity_Class *eclass;
 	char *key[2];
-	G_Entity *entity;
+	Nvec3 origin, angles;
+	Nvec scale;
+	G_Entity_Position position;
 
+	Util_ParseC_SetUpThread(&thread, filedata, filesize);
+	StringKeys_Init(&keys, GS.memzone, 65536);
 	key[0] = NULL;
 	key[1] = NULL;
-
-	Util_ParseC_SetUpThread(&thread, filedata, filesize);
 	while (thread.type != UTIL_PARSEC_TOKENTYPE_EOF)
 	{
 		if (!Util_ParseC_MatchName(&thread, "{"))
@@ -239,7 +244,12 @@
 			Console_Printf("G_SpawnFromEntityFile: expected {\n");
 			break;
 		}
-		entity = G_Entity_New(NULL, G_EntityClass_ByNumber(0));
+		StringKeys_Empty(&keys);
+		position = GS.identityposition;
+		eclass = NULL;
+		VectorClear(origin);
+		VectorClear(angles);
+		scale = 1;
 		for (;;)
 		{
 			for (j = 0;j < 2;j++)
@@ -265,21 +275,56 @@
 			}
 			if (j < 2)
 				break;
-			G_Entity_SetField(entity, key[0], key[1]);
+			if (!String_Compare(key[0], "classname"))
+			{
+				if (eclass)
+					Console_Printf("G_SpawnFromEntityFile: entity with multiple classnames\n");
+				eclass = G_EntityClass_ByName(key[1]);
+			}
+			else if (!String_Compare(key[0], "origin"))
+				String_ToVector(key[1], origin, 3);
+			else if (!String_Compare(key[0], "angles"))
+				String_ToVector(key[1], angles, 3);
+			else if (!String_Compare(key[0], "scale"))
+				scale = String_ToDouble(key[1]);
+			else if (!String_Compare(key[0], "velocity"))
+				String_ToVector(key[1], position.velocity, 3);
+			else if (!String_Compare(key[0], "spin"))
+				String_ToVector(key[1], position.spin, 4);
+			StringKeys_SetKey(&keys, GS.memzone, key[0], key[1]);
 		}
+		if (eclass)
+		{
+			const char *s;
+			Matrix4x4_CreateFromQuakeEntity(&position.m, origin[0], origin[1], origin[2], angles[0], angles[1], angles[2], scale);
+			// TODO: parse keys here?
+			entity = G_Entity_New(NULL, eclass, &position);
+			// set up the most general fields to save code in spawn functions
+			String_ToVector(StringKeys_GetValue(&keys, "color"), entity->lightcolor, 3);
+			if ((s = StringKeys_GetValue(&keys, "cubemap")))
+				entity->lightcubemap = Resource_IndexForName(s, RESOURCETYPE_TEXTURE, 0, 0);
+			if ((s = StringKeys_GetValue(&keys, "model")))
+				G_Entity_SetModel(entity, s);
+			// only keep keys if in editing mode
+			if (G.editing)
+				StringKeys_Clone(&entity->keys, GS.memzone, &keys);
+		}
+		else
+			Console_Printf("G_SpawnFromEntityFile: entity with no classname\n");
 	}
-	Util_ParseC_CleanUpThread(&thread);
 	String_Free(&key[0]);
 	String_Free(&key[1]);
+	StringKeys_FreeKeys(&keys);
+	Util_ParseC_CleanUpThread(&thread);
 }
 
 void G_World_SaveEntities(const char *filename)
 {
-	NUint32 i, j;
+	NUint32 i, j, keyindex;
 	Nsize filesize;
 	G_Entity *entity;
-	G_Entity_Field *field;
 	char *filedata;
+	const char *key, *value;
 	if (!G.editing)
 	{
 		// we can't save because the entity fields were destroyed at load, and
@@ -294,15 +339,16 @@
 		{
 			// TODO: optimize this to buffer a bit rather than using String_Append?
 			String_Append(&filedata, GS.memzone, "{\n");
-			for (field = entity->fields;field;field = field->next)
+			keyindex = 0;
+			for (keyindex = 0;StringKeys_GetByNumber(&entity->keys, keyindex, &key, &value);keyindex++)
 			{
 				// FIXME: field->key is pretty safe but key->value may contain
 				// control characters like \n, these need to be converted to
 				// escape sequences.
 				String_Append(&filedata, GS.memzone, "\t\"");
-				String_Append(&filedata, GS.memzone, field->key);
+				String_Append(&filedata, GS.memzone, key);
 				String_Append(&filedata, GS.memzone, "\" \"");
-				String_Append(&filedata, GS.memzone, field->value);
+				String_Append(&filedata, GS.memzone, value);
 				String_Append(&filedata, GS.memzone, "\"\n");
 			}
 			String_Append(&filedata, GS.memzone, "}\n");
@@ -336,8 +382,8 @@
 	Mem_Free(&filedata);
 
 	for (i = 0;i < G_MAX_ENTITIES;i++)
-		if (G.entities[i].eclass && G.entities[i].fields)
-			G_Entity_SpawnFromFields(G.entities + i);
+		if (G.entities[i].eclass)
+			G_Entity_Spawn(G.entities + i);
 
 	// TODO: add team entities
 	// if no teams were defined by entities, set up default teams
@@ -438,7 +484,7 @@
 	G.time += G.frametime;
 	// execute entity think code
 	for (i = 0, entity = G.entities;i < G.numentities;i++, entity++)
-		if (entity->eclass && entity->eclass->codeclass && entity->eclass->codeclass->framecallback)
+		if (entity->eclass && entity->eclass->codeclass->framecallback)
 			entity->eclass->codeclass->framecallback(entity);
 	// TODO: call physics
 #if 0
@@ -459,18 +505,19 @@
 {
 	G_Entity *player;
 	G_Entity *spot;
+	G_Entity_Position position;
+	// TODO: better spawn point selection
+	spot = G_Entity_Find_CodeName(NULL, "spawninfantry");
+	if (spot)
+		position = spot->position;
+	else
+		position = GS.identityposition;
 	// set up player entity for this user
-	player = G_Entity_New(NULL, G_EntityClass_ByName("infantry"));
+	player = G_Entity_New(NULL, G_EntityClass_ByName("infantry"), &position);
 	player->localuserindex = user - GS.users;
 	G.users[player->localuserindex].teamindex = 1;
 	G.users[player->localuserindex].score = 0;
 	//G.users[player->localuserindex].entityindex = player - G.entities;
-	// TODO: better spawn point selection
-	spot = G_Entity_Find_CodeName(NULL, "spawninfantry");
-	if (spot)
-		player->matrix = spot->matrix;
-	else
-		Matrix4x4_CreateIdentity(&player->matrix);
 	G_Entity_Spawn(player);
 }
 
@@ -546,8 +593,8 @@
 			continue;
 		if (e == trace->moveentity)
 			continue;
-		Matrix4x4_Invert_Simple(&imatrix, &e->matrix);
-		Collision_Trace_Begin(&collisiontrace, &e->matrix, &imatrix, &startbrush, &endbrush, 1.0/32.0);
+		Matrix4x4_Invert_Simple(&imatrix, &e->position.m);
+		Collision_Trace_Begin(&collisiontrace, &e->position.m, &imatrix, &startbrush, &endbrush, 1.0/32.0);
 		if (e->collisionbrush.numpoints)
 			Collision_Trace_CheckBrushes(&collisiontrace, 1, &e->collisionbrush, &e->collisionbrush);
 		else if (e->surfacelist)

Modified: trunk/mathlib.h
===================================================================
--- trunk/mathlib.h	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/mathlib.h	2006-03-27 09:16:27 UTC (rev 685)
@@ -16,31 +16,69 @@
 #define RAD2DEG(a) ((a) * (180.0 / M_PI))
 
 #define VectorNegate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]),(b)[2]=-((a)[2]))
+#define Vector2Negate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]))
+#define Vector4Negate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]),(b)[2]=-((a)[2]),(b)[3]=-((a)[3]))
 #define VectorSet(a,b,c,d) ((a)[0]=(b),(a)[1]=(c),(a)[2]=(d))
+#define Vector2Set(a,b,c) ((a)[0]=(b),(a)[1]=(c))
+#define Vector4Set(a,b,c,d,e) ((a)[0]=(b),(a)[1]=(c),(a)[2]=(d),(a)[3]=(e))
 #define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0)
-#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2])
-#define DotProduct4(a,b) ((a)[0] * (b)[0] + (a)[1] * (b)[1] + (a)[2] * (b)[2] + (a)[3] * (b)[3])
+#define Vector2Clear(a) ((a)[0]=(a)[1]=0)
+#define Vector4Clear(a) ((a)[0]=(a)[1]=(a)[2]=(a)[3]=0)
 #define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2])
+#define Vector2Subtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1])
+#define Vector4Subtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3])
 #define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2])
+#define Vector2Add(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1])
+#define Vector4Add(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[2]=(a)[3]+(b)[3])
 #define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
+#define Vector2Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1])
+#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
 #define VectorMultiply(a,b,c) ((c)[0]=(a)[0]*(b)[0],(c)[1]=(a)[1]*(b)[1],(c)[2]=(a)[2]*(b)[2])
-#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0])
-#define VectorNormalize(v) do{float ilength = (float) sqrt(DotProduct(v,v));if (ilength) {ilength = 1.0f / ilength;VectorScale(v, ilength, v);}}while(0)
-#define VectorNormalizeDouble(v) do{double ilength = sqrt(DotProduct(v,v));if (ilength) {ilength = 1.0 / ilength;VectorScale(v, ilength, v);}}while(0)
+#define Vector2Multiply(a,b,c) ((c)[0]=(a)[0]*(b)[0],(c)[1]=(a)[1]*(b)[1])
+#define Vector4Multiply(a,b,c) ((c)[0]=(a)[0]*(b)[0],(c)[1]=(a)[1]*(b)[1],(c)[2]=(a)[2]*(b)[2],(c)[3]=(a)[3]*(b)[3])
+#define VectorNormalize(v) do{double ilength = sqrt(DotProduct(v,v));if (ilength) {ilength = 1.0 / ilength;VectorScale(v, ilength, v);}}while(0)
+#define Vector2Normalize(v) do{double ilength = sqrt(DotProduct2(v,v));if (ilength) {ilength = 1.0 / ilength;Vector2Scale(v, ilength, v);}}while(0)
+#define Vector4Normalize(v) do{double ilength = sqrt(DotProduct4(v,v));if (ilength) {ilength = 1.0 / ilength;Vector4Scale(v, ilength, v);}}while(0)
 #define VectorDistance2(a, b) (((a)[0] - (b)[0]) * ((a)[0] - (b)[0]) + ((a)[1] - (b)[1]) * ((a)[1] - (b)[1]) + ((a)[2] - (b)[2]) * ((a)[2] - (b)[2]))
+#define Vector2Distance2(a, b) (((a)[0] - (b)[0]) * ((a)[0] - (b)[0]) + ((a)[1] - (b)[1]) * ((a)[1] - (b)[1]))
+#define Vector4Distance2(a, b) (((a)[0] - (b)[0]) * ((a)[0] - (b)[0]) + ((a)[1] - (b)[1]) * ((a)[1] - (b)[1]) + ((a)[2] - (b)[2]) * ((a)[2] - (b)[2]) + ((a)[3] - (b)[3]) * ((a)[3] - (b)[3]))
 #define VectorDistance(a, b) (sqrt(VectorDistance2(a,b)))
-#define VectorLength(a) (sqrt(DotProduct(a, a)))
+#define Vector2Distance(a, b) (sqrt(Vector2Distance2(a,b)))
+#define Vector4Distance(a, b) (sqrt(Vector4Distance2(a,b)))
 #define VectorLength2(a) (DotProduct(a, a))
+#define Vector2Length2(a) (DotProduct2(a, a))
+#define Vector4Length2(a) (DotProduct4(a, a))
+#define VectorLength(a) (sqrt(VectorLength2(a)))
+#define Vector2Length(a) (sqrt(Vector2Length2(a)))
+#define Vector4Length(a) (sqrt(Vector4Length2(a)))
 #define VectorScale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale))
+#define Vector2Scale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale))
+#define Vector4Scale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale),(out)[3] = (in)[3] * (scale))
 #define VectorCompare(a,b) (((a)[0]==(b)[0])&&((a)[1]==(b)[1])&&((a)[2]==(b)[2]))
+#define Vector2Compare(a,b) (((a)[0]==(b)[0])&&((a)[1]==(b)[1]))
+#define Vector4Compare(a,b) (((a)[0]==(b)[0])&&((a)[1]==(b)[1])&&((a)[2]==(b)[2])&&((a)[3]==(b)[3]))
 #define VectorMA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1],(c)[2] = (a)[2] + (scale) * (b)[2])
+#define Vector2MA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1])
+#define Vector4MA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1],(c)[2] = (a)[2] + (scale) * (b)[2],(c)[3] = (a)[3] + (scale) * (b)[3])
 #define VectorRandom(v) do{(v)[0] = Random(-1, 1);(v)[1] = Random(-1, 1);(v)[2] = Random(-1, 1);}while(DotProduct(v, v) > 1)
+#define Vector2Random(v) do{(v)[0] = Random(-1, 1);(v)[1] = Random(-1, 1);}while(DotProduct2(v, v) > 1)
+#define Vector4Random(v) do{(v)[0] = Random(-1, 1);(v)[1] = Random(-1, 1);(v)[2] = Random(-1, 1);(v)[3] = Random(-1, 1);}while(DotProduct4(v, v) > 1)
 #define VectorLerp(v1,lerp,v2,c) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1]), (c)[2] = (v1)[2] + (lerp) * ((v2)[2] - (v1)[2]))
+#define Vector2Lerp(v1,lerp,v2,c) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1]))
+#define Vector4Lerp(v1,lerp,v2,c) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1]), (c)[2] = (v1)[2] + (lerp) * ((v2)[2] - (v1)[2]), (c)[3] = (v1)[3] + (lerp) * ((v2)[3] - (v1)[3]))
+#define VectorReflect(a,r,b,c) do{Nvec d;d = DotProduct((a), (b)) * -(1.0 + (r));VectorMA((a), (d), (b), (c));}while(0)
+#define Vector2Reflect(a,r,b,c) do{Nvec d;d = DotProduct2((a), (b)) * -(1.0 + (r));Vector2MA((a), (d), (b), (c));}while(0)
+
+#define DotProduct(a,b) ((a)[0] * (b)[0] + (a)[1] * (b)[1] + (a)[2] * (b)[2])
+#define DotProduct2(a,b) ((a)[0] * (b)[0] + (a)[1] * (b)[1])
+#define DotProduct4(a,b) ((a)[0] * (b)[0] + (a)[1] * (b)[1] + (a)[2] * (b)[2] + (a)[3] * (b)[3])
+#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0])
 #define BoxesOverlap(a,b,c,d) ((a)[0] <= (d)[0] && (b)[0] >= (c)[0] && (a)[1] <= (d)[1] && (b)[1] >= (c)[1] && (a)[2] <= (d)[2] && (b)[2] >= (c)[2])
+#define BoxesOverlap2(a,b,c,d) ((a)[0] <= (d)[0] && (b)[0] >= (c)[0] && (a)[1] <= (d)[1] && (b)[1] >= (c)[1])
 #define SpheresOverlap(a,b,c,d) (VectorDistance2(a,c) < (b*b+d*d))
+#define CirclesOverlap(a,b,c,d) (Vector2Distance2(a,c) < (b*b+d*d))
 #define TriangleNormal(a,b,c,n) ((n)[0] = ((a)[2] - (b)[2]) * ((c)[1] - (b)[1]) - ((a)[1] - (b)[1]) * ((c)[2] - (b)[2]), (n)[1] = ((a)[0] - (b)[0]) * ((c)[2] - (b)[2]) - ((a)[2] - (b)[2]) * ((c)[0] - (b)[0]), (n)[2] = ((a)[1] - (b)[1]) * ((c)[0] - (b)[0]) - ((a)[0] - (b)[0]) * ((c)[1] - (b)[1]))
 #define PointInfrontOfTriangle(p,a,b,c) (((p)[0] - (a)[0]) * (((a)[1] - (b)[1]) * ((c)[2] - (b)[2]) - ((a)[2] - (b)[2]) * ((c)[1] - (b)[1])) + ((p)[1] - (a)[1]) * (((a)[2] - (b)[2]) * ((c)[0] - (b)[0]) - ((a)[0] - (b)[0]) * ((c)[2] - (b)[2])) + ((p)[2] - (a)[2]) * (((a)[0] - (b)[0]) * ((c)[1] - (b)[1]) - ((a)[1] - (b)[1]) * ((c)[0] - (b)[0])) > 0)
-#define VectorReflect(a,r,b,c) do{Nvec d;d = DotProduct((a), (b)) * -(1.0 + (r));VectorMA((a), (d), (b), (c));}while(0)
 
 // conversion of a quaternion to 3 components by making it canonical (there are two equivilant representations of any quaternion depending on the sign of w, negative or positive w can be eliminated by negating xyz, thus reducing a normalized quaternion to xyz with an easily calculated w)
 #define Quat4ToQuat3(a,b) ((a)[3] > 0 ? VectorNegate((a),(b)) : VectorCopy((a),(b)))

Modified: trunk/model.c
===================================================================
--- trunk/model.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/model.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -212,18 +212,6 @@
 }
 Model_MD5_Weight;
 
-// LordHavoc: I got this code from:
-//http://www.doom3world.org/phpbb2/viewtopic.php?t=2884
-static void Model_Doom3Joint6ToMatrix(double *b, matrix4x4_t *m)
-{
-	double x = b[3], y = b[4], z = b[5], w = 1.0 - DotProduct(b + 3, b + 3);
-	w = w > 0.0 ? -sqrt(w) : 0.0;
-	m->m[0][0]= 1-2*((y*y)+(z*z)) ;m->m[0][1]=   2*((x*y)-(z*w)) ;m->m[0][2]=   2*((x*z)+(y*w)) ;m->m[0][3]=b[0];
-	m->m[1][0]=   2*((x*y)+(z*w)) ;m->m[1][1]= 1-2*((x*x)+(z*z)) ;m->m[1][2]=   2*((y*z)-(x*w)) ;m->m[1][3]=b[1];
-	m->m[2][0]=   2*((x*z)-(y*w)) ;m->m[2][1]=   2*((y*z)+(x*w)) ;m->m[2][2]= 1-2*((x*x)+(y*y)) ;m->m[2][3]=b[2];
-	m->m[3][0]=   0               ;m->m[3][1]=   0               ;m->m[3][2]=   0               ;m->m[3][3]=   1;
-}
-
 void Model_Load(ResourceEntry *r)
 {
 	Util_ParseC_Thread thread;
@@ -296,6 +284,7 @@
 			model->transformnames = Mem_Alloc(r->memzone, model->numtransforms * sizeof(*model->transformnames));
 			model->transformradius = Mem_Alloc(r->memzone, model->numtransforms * sizeof(*model->transformradius));
 			model->basetransforms = Mem_Alloc(r->memzone, model->numtransforms * sizeof(*model->basetransforms));
+			model->baseinversetransforms = Mem_Alloc(r->memzone, model->numtransforms * sizeof(*model->baseinversetransforms));
 		}
 		//numMeshes 1
 		else if (Util_ParseC_MatchKeyword(&thread, "numMeshes"))
@@ -334,7 +323,8 @@
 				LoadValue(joint6[4], "(joint 4)");
 				LoadValue(joint6[5], "(joint 5)");
 				ExpectKeyword(")", "after second joint data list");
-				Model_Doom3Joint6ToMatrix(joint6, &model->basetransforms[jointnum]);
+				Matrix4x4_CreateFromDoom3Joint(&model->basetransforms[jointnum], joint6[0], joint6[1], joint6[2], joint6[3], joint6[4], joint6[5]);
+				Matrix4x4_Invert_Simple(&model->baseinversetransforms[jointnum], &model->basetransforms[jointnum]);
 				if (parent >= (NSint32)jointnum)
 				{
 					Console_Printf("Model_Load: joint.parent (%i) >= joint (%i)\n", parent, jointnum);
@@ -343,7 +333,7 @@
 			}
 			if (jointnum != model->numtransforms)
 			{
-				Console_Printf("Model_Load: final jointnum (%i) != numjuoints (%i)\n", jointnum, model->numtransforms);
+				Console_Printf("Model_Load: final jointnum (%i) != numJoints (%i)\n", jointnum, model->numtransforms);
 				Abort();
 			}
 		}
@@ -814,6 +804,19 @@
 	}
 }
 
+NSint32 Model_GetTransformNumberForName(NUint32 modelresource, const char *name)
+{
+	NUint32 i;
+	Model *model;
+	model = Resource_GetData(modelresource);
+	if (!model)
+		return -1; // no model
+	for (i = 0;i < model->numtransforms;i++)
+		if (!String_Compare(model->transformnames[i], name))
+			return i;
+	return -1;
+}
+
 /*
 // TODO: data hiding or not?
 

Modified: trunk/model.h
===================================================================
--- trunk/model.h	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/model.h	2006-03-27 09:16:27 UTC (rev 685)
@@ -84,6 +84,7 @@
 	char **transformnames;
 	float *transformradius;
 	matrix4x4_t *basetransforms;
+	matrix4x4_t *baseinversetransforms;
 
 	Nvec3 basecullmins;
 	Nvec3 basecullmaxs;
@@ -98,6 +99,7 @@
 void Model_GetVertices(Model_Mesh *mesh, const matrix4x4_t *transforms, float *outvertex3f, float *outsvector3f, float *outtvector3f, float *outnormal3f, float *outplane4f);
 void Model_GetCullBox(NUint32 modelresource, const matrix4x4_t *transforms, Nvec3 cullmins, Nvec3 cullmaxs);
 void Model_GetMeshCullBox(NUint32 modelresource, NUint32 meshindex, const matrix4x4_t *transforms, Nvec3 cullmins, Nvec3 cullmaxs);
+NSint32 Model_GetTransformNumberForName(NUint32 modelresource, const char *name);
 
 #endif
 

Added: trunk/modelanim.c
===================================================================
--- trunk/modelanim.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/modelanim.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -0,0 +1,352 @@
+
+#include "ncommon.h"
+#include "model.h"
+#include "modelanim.h"
+#include "util.h"
+
+/* example clips of an MD5 anim
+MD5Version 10
+commandline ""
+numFrames 21
+numJoints 3
+frameRate 30
+numAnimatedComponents 18
+hierarchy {
+	"root"  -1 63 0 //
+	"weapon_link"   0 63 6  // root ( Tx Ty Tz Qx Qy Qz )
+	"weapon_main"   1 63 12 // weapon_link ( Tx Ty Tz Qx Qy Qz )
+}
+bounds {
+	( -1.145777 -2.429096 -13.948964 ) ( 19.801897 4.962530 -5.251172 )
+	( -0.687599 -2.425639 -13.722960 ) ( 20.277922 5.083089 -4.994154 )
+...
+}
+baseframe {
+	( 0.000000 0.000000 0.000000 ) ( -0.707107 0.000000 -0.000000 )
+	( 0.000000 0.000000 -1.200000 ) ( 0.375011 0.599472 0.375011 )
+	( -0.000000 0.000000 -12.343824 ) ( -0.681099 -0.000000 -0.000000 )
+}
+frame 0 {
+	0.000000 0.000000 0.000000 -0.707107 0.000000 -0.000000
+	0.000000 0.000000 -1.200000 0.375011 0.599472 0.375011
+	-0.000000 0.000000 -12.343824 -0.681099 -0.000000 -0.000000
+}
+...
+*/
+
+void ModelAnim_Load(ResourceEntry *r)
+{
+	Util_ParseC_Thread thread;
+	NUint32 meshnum, version;
+	Nbool error;
+	Nsize filesize;
+	ModelAnim *modelanim;
+	char *filedata;
+
+	modelanim = Mem_Alloc(r->memzone, sizeof(ModelAnim));
+
+	filedata = File_LoadFile(r->name, &filesize);
+	if (!filedata)
+		return;
+
+	Util_ParseC_SetUpThread(&thread, filedata, filesize);
+
+#define Abort()		{ error = true; break; }
+#define LoadValue(var, errstr)		if (thread.type != UTIL_PARSEC_TOKENTYPE_VALUE) { \
+				Console_Printf("ModelAnim_Load: Expected value " errstr "\n"); Abort(); \
+			} else \
+				(var) = thread.value, Util_ParseC_Lex(&thread)
+
+#define LoadInt(var, errstr)		if (thread.type != UTIL_PARSEC_TOKENTYPE_VALUE) { \
+				Console_Printf("ModelAnim_Load: Expected integer " errstr "\n"); Abort(); \
+			} else \
+				(var) = thread.value, Util_ParseC_Lex(&thread)
+
+#define LoadString(var, errstr)		if (thread.type != UTIL_PARSEC_TOKENTYPE_STRING) { \
+				Console_Printf("ModelAnim_Load: Expected string " errstr "\n"); Abort(); \
+			} else \
+				String_Set( &(var), r->memzone, thread.token), Util_ParseC_Lex(&thread)
+
+#define ExpectKeyword(str, errstr)		if (!Util_ParseC_MatchName(&thread, (str))) { \
+				Console_Printf("ModelAnim_Load: Expected '" str "' " errstr "\n"); Abort(); }
+
+	version = 0;
+	meshnum = 0;
+	error = false;
+
+	while (!error && thread.type != UTIL_PARSEC_TOKENTYPE_EOF)
+	{
+		//MD5Version 10
+		if (Util_ParseC_MatchKeyword(&thread, "MD5Version"))
+		{
+			LoadInt(version, "after 'MD5Version'");
+			if (version != 10)
+			{
+				Console_Printf("ModelAnim_Load: MD5Version %i not supported\n", version);
+				Abort();
+			}
+		}
+		//commandline ""
+		else if (Util_ParseC_MatchKeyword(&thread, "commandline"))
+		{
+			Util_ParseC_Lex(&thread);
+		}
+		//numFrames 21
+		else if (Util_ParseC_MatchKeyword(&thread, "numFrames"))
+		{
+			LoadInt(modelanim->numframes, "after 'numFrames'");
+			if (modelanim->numframes < 1)
+			{
+				Console_Printf("ModelAnim_Load: numFrames %i < 1\n", modelanim->numframes);
+				Abort();
+			}
+		}
+		//numJoints 3
+		else if (Util_ParseC_MatchKeyword(&thread, "numJoints"))
+		{
+			LoadInt(modelanim->numtransforms, "after 'numJoints'");
+			if (modelanim->numtransforms < 1)
+			{
+				Console_Printf("ModelAnim_Load: numJoints %i < 1\n", modelanim->numtransforms);
+				Abort();
+			}
+		}
+		//frameRate 30
+		else if (Util_ParseC_MatchKeyword(&thread, "frameRate"))
+		{
+			LoadValue(modelanim->framerate, "after 'frameRate'");
+			if (modelanim->framerate <= 0)
+			{
+				Console_Printf("ModelAnim_Load: frameRate %f <= 0\n", modelanim->framerate);
+				Abort();
+			}
+		}
+		//numAnimatedComponents 18
+		else if (Util_ParseC_MatchKeyword(&thread, "numAnimatedComponents"))
+		{
+			LoadInt(modelanim->numvaluesperframe, "after 'numAnimatedComponents'");
+			if (modelanim->numvaluesperframe < 0)
+			{
+				Console_Printf("ModelAnim_Load: numAnimatedComponents %i < 0\n", modelanim->numvaluesperframe);
+				Abort();
+			}
+			if (modelanim->numvaluesperframe > modelanim->numtransforms * 6)
+			{
+				Console_Printf("ModelAnim_Load: numAnimatedComponents %i > numJoints * 6\n", modelanim->numvaluesperframe);
+				Abort();
+			}
+		}
+		//hierarchy {
+		else if (Util_ParseC_MatchKeyword(&thread, "hierarchy"))
+		{
+			NUint32 jointnum;
+			ExpectKeyword("{", "after 'hierarchy'");
+			modelanim->transforminfo = Mem_Alloc(r->memzone, modelanim->numtransforms * sizeof(*modelanim->transforminfo));
+			for (jointnum = 0; !Util_ParseC_MatchKeyword(&thread, "}");jointnum++)
+			{
+				NSint32 parent;
+				NUint32 componentflags;
+				NUint32 numcomponents;
+				NUint32 firstcomponent;
+				NUint32 componentindex;
+				//	"weapon_link"	0 63 6	// root ( Tx Ty Tz Qx Qy Qz )
+				LoadString(modelanim->transforminfo[jointnum].name, "for joint name");
+				LoadInt(parent, "as parent");
+				LoadInt(componentflags, "component flags");
+				LoadInt(firstcomponent, "first component index");
+				if (parent >= (NSint32)jointnum)
+				{
+					Console_Printf("ModelAnim_Load: joint.parent (%i) >= joint (%i)\n", parent, jointnum);
+					Abort();
+				}
+				if (componentflags & ~63)
+				{
+					Console_Printf("ModelAnim_Load: joint[%i].componentflags < 0 || componentflags > 63\n", jointnum);
+					Abort();
+				}
+				numcomponents = 0;
+				for (componentindex = 0;componentindex < 6;componentindex++)
+					if (componentflags & (1<<componentindex))
+						numcomponents++;
+				if (firstcomponent + numcomponents > modelanim->numvaluesperframe)
+				{
+					Console_Printf("ModelAnim_Load: joint[%i].firstcomponent < 0 || firstcomponent + numcomponents > numAnimatedComponents\n", jointnum);
+					Abort();
+				}
+				modelanim->transforminfo[jointnum].parentindex = parent;
+				modelanim->transforminfo[jointnum].valueflags = componentflags;
+				modelanim->transforminfo[jointnum].firstvalue = firstcomponent;
+				modelanim->transforminfo[jointnum].numvalues = numcomponents;
+			}
+			if (jointnum != modelanim->numtransforms)
+			{
+				Console_Printf("ModelAnim_Load: final jointnum (%i) != numJoints (%i)\n", jointnum, modelanim->numtransforms);
+				Abort();
+			}
+		}
+		//bounds {
+		else if (Util_ParseC_MatchKeyword(&thread, "bounds"))
+		{
+			NUint32 framenum;
+			ExpectKeyword("{", "after 'bounds'");
+			for (framenum = 0; !Util_ParseC_MatchKeyword(&thread, "}");framenum++)
+			{
+				Nvec3 mins, maxs;
+				//	( -1.145777 -2.429096 -13.948964 ) ( 19.801897 4.962530 -5.251172 )
+				ExpectKeyword("(", "before minimum corner of frame box");
+				LoadValue(mins[0], "(mins[0])");
+				LoadValue(mins[1], "(mins[1])");
+				LoadValue(mins[2], "(mins[2])");
+				ExpectKeyword(")", "after minimum corner of frame box");
+				ExpectKeyword("(", "before maximum corner of frame box");
+				LoadValue(maxs[0], "(maxs[0])");
+				LoadValue(maxs[1], "(maxs[1])");
+				LoadValue(maxs[2], "(maxs[2])");
+				ExpectKeyword(")", "after maximum corner of frame box");
+			}
+			if (framenum != modelanim->numframes)
+			{
+				Console_Printf("ModelAnim_Load: final framenum (%i) != numFrames (%i)\n", framenum, modelanim->numframes);
+				Abort();
+			}
+		}
+		//baseframe {
+		else if (Util_ParseC_MatchKeyword(&thread, "baseframe"))
+		{
+			NUint32 jointnum;
+			ExpectKeyword("{", "after 'baseframe'");
+			modelanim->basevalues = Mem_Alloc(r->memzone, modelanim->numtransforms * 6 * sizeof(*modelanim->basevalues));
+			modelanim->values = Mem_Alloc(r->memzone, modelanim->numframes * modelanim->numvaluesperframe * sizeof(*modelanim->values));
+			for (jointnum = 0; !Util_ParseC_MatchKeyword(&thread, "}");jointnum++)
+			{
+				//	( 0.000000 0.000000 0.000000 ) ( -0.707107 0.000000 -0.000000 )
+				ExpectKeyword("(", "before first joint data list");
+				LoadValue(modelanim->basevalues[jointnum*6+0], "(joint 0)");
+				LoadValue(modelanim->basevalues[jointnum*6+1], "(joint 1)");
+				LoadValue(modelanim->basevalues[jointnum*6+2], "(joint 2)");
+				ExpectKeyword(")", "after first joint data list");
+				ExpectKeyword("(", "before second joint data list");
+				LoadValue(modelanim->basevalues[jointnum*6+3], "(joint 3)");
+				LoadValue(modelanim->basevalues[jointnum*6+4], "(joint 4)");
+				LoadValue(modelanim->basevalues[jointnum*6+5], "(joint 5)");
+				ExpectKeyword(")", "after second joint data list");
+			}
+			if (jointnum != modelanim->numtransforms)
+			{
+				Console_Printf("ModelAnim_Load: final jointnum (%i) != numJoints (%i)\n", jointnum, modelanim->numtransforms);
+				Abort();
+			}
+		}
+		//frame 0 {
+		else if (Util_ParseC_MatchKeyword(&thread, "frame"))
+		{
+			NUint32 framenum;
+			NUint32 valuenum;
+			float *values;
+			LoadInt(framenum, "number of frames");
+			if (framenum < 0 || framenum >= modelanim->numframes)
+			{
+				Console_Printf("ModelAnim_Load: frame number %i < 0 || frame number %i >= numFrames (%i)\n", framenum, framenum, modelanim->numframes);
+				Abort();
+			}
+			ExpectKeyword("{", "after 'frame'");
+			values = modelanim->values + framenum * modelanim->numvaluesperframe;
+			for (valuenum = 0; !Util_ParseC_MatchKeyword(&thread, "}");valuenum++)
+			{
+				if (valuenum >= modelanim->numvaluesperframe)
+				{
+					Console_Printf("ModelAnim_Load: too many components in frame %i\n", framenum);
+					Abort();
+				}
+				LoadValue(values[valuenum], "component value");
+			}
+			if (valuenum != modelanim->numvaluesperframe)
+			{
+				Console_Printf("ModelAnim_Load: final component (%i) != numAnimatedComponents (%i)\n", valuenum, modelanim->numvaluesperframe);
+				Abort();
+			}
+		}
+	}
+	Util_ParseC_CleanUpThread(&thread);
+	Mem_Free(&filedata);
+	// if there was a load error, don't point to the Model so nothing will try
+	// to use the incomplete data
+	if (!error)
+		r->data = modelanim;
+#undef Abort
+#undef LoadInt
+#undef LoadValue
+#undef LoadString
+#undef ExpectKeyword
+}
+
+void ModelAnim_Unload(ResourceEntry *r)
+{
+	// freeing of the memzone will get rid of the modelanim
+}
+
+NUint32 ModelAnim_GetNumTransforms(NUint32 resourceindex)
+{
+	ModelAnim *modelanim;
+	modelanim = Resource_GetData(resourceindex);
+	if (!modelanim)
+		return 0; // no modelanim
+	return modelanim->numtransforms;
+}
+
+NUint32 ModelAnim_GetNumFrames(NUint32 resourceindex)
+{
+	ModelAnim *modelanim;
+	modelanim = Resource_GetData(resourceindex);
+	if (!modelanim)
+		return 0; // no modelanim
+	return modelanim->numframes;
+}
+
+double ModelAnim_GetFrameRate(NUint32 resourceindex)
+{
+	ModelAnim *modelanim;
+	modelanim = Resource_GetData(resourceindex);
+	if (!modelanim)
+		return 0; // no modelanim
+	return modelanim->framerate;
+}
+
+void ModelAnim_BlendPoses(NUint32 modelanimresource, NUint32 modelresource, NUint32 frame1, NUint32 frame2, float framelerp, matrix4x4_t *transforms, Nbool clearfirst)
+{
+	NUint32 transformnum;
+	float iframelerp = 1 - framelerp;
+	const float *v1, *v2, *b;
+	Model *model;
+	ModelAnim *modelanim;
+	ModelAnim_TransformInfo *info;
+	modelanim = Resource_GetData(modelanimresource);
+	if (!modelanim)
+		return; // no modelanim
+	model = Resource_GetData(modelresource);
+	if (!model)
+		return; // no model
+	if (model->numtransforms != modelanim->numtransforms)
+		return; // error
+	v1 = modelanim->values + frame1 * modelanim->numvaluesperframe;
+	v2 = modelanim->values + frame2 * modelanim->numvaluesperframe;
+	b = modelanim->basevalues;
+	for (transformnum = 0, info = modelanim->transforminfo;transformnum < modelanim->numtransforms;transformnum++, info++, b += 6)
+	{
+		NUint32 component;
+		NUint32 valueflags = info->valueflags;
+		const float *f1 = v1 + info->firstvalue;
+		const float *f2 = v2 + info->firstvalue;
+		float pose[6];
+		matrix4x4_t posematrix, relativematrix;
+		for (component = 0;component < 6;component++)
+		{
+			if (valueflags & (1<<component))
+				pose[component] = *f1++ * iframelerp + *f2++ * framelerp;
+			else
+				pose[component] = b[component];
+		}
+		Matrix4x4_CreateFromDoom3Joint(&posematrix, pose[0], pose[1], pose[2], pose[3], pose[4], pose[5]);
+		Matrix4x4_Concat(&relativematrix, &posematrix, &model->baseinversetransforms[transformnum]);
+	}
+}

Added: trunk/modelanim.h
===================================================================
--- trunk/modelanim.h	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/modelanim.h	2006-03-27 09:16:27 UTC (rev 685)
@@ -0,0 +1,35 @@
+
+typedef struct ModelAnim_TransformInfo
+{
+	char *name;
+	NUint32 parentindex;
+	NUint32 valueflags;
+	NUint32 firstvalue;
+	NUint32 numvalues;
+}
+ModelAnim_TransformInfo;
+
+typedef struct ModelAnim
+{
+	// md5anim files store a baseline (default values) of the entire joint set,
+	// and then flags for which values are animated, since most of the joint
+	// set is unchanging in most animations
+	// each joint is 6 values (3 location, 3 quaternion)
+	// the quaternions are stored as canonical unit vectors in which w is
+	// assumed to be negative (it is easy to regenerate any one component of a
+	// unit vector if you know its sign)
+	NUint32 numtransforms;
+	NUint32 numvaluesperframe;
+	NUint32 numframes;
+	float framerate;
+	ModelAnim_TransformInfo *transforminfo; // [numtransforms]
+	float *values; // [numframes*numvaluesperframe]
+	float *basevalues; // [numtransforms*6]
+}
+ModelAnim;
+
+void ModelAnim_Load(ResourceEntry *r);
+void ModelAnim_Unload(ResourceEntry *r);
+
+NUint32 ModelAnim_GetNumTransforms(NUint32 resourceindex);
+void ModelAnim_GetTransforms(NUint32 resourceindex, NUint32 frame1, NUint32 frame2, float framelerp, matrix4x4_t *transforms);

Modified: trunk/resource.c
===================================================================
--- trunk/resource.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/resource.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -2,6 +2,7 @@
 #include "ncommon.h"
 #include "material.h"
 #include "model.h"
+#include "modelanim.h"
 #include "sound.h"
 #include "texture.h"
 #include "video.h"
@@ -182,6 +183,9 @@
 	case RESOURCETYPE_MODEL:
 		Model_Load(r);
 		break;
+	case RESOURCETYPE_MODELANIM:
+		ModelAnim_Load(r);
+		break;
 	case RESOURCETYPE_SOUND:
 		Sound_Load(r);
 		break;
@@ -221,6 +225,9 @@
 		case RESOURCETYPE_MODEL:
 			Model_Unload(r);
 			break;
+		case RESOURCETYPE_MODELANIM:
+			ModelAnim_Unload(r);
+			break;
 		case RESOURCETYPE_SOUND:
 			Sound_Unload(r);
 			break;

Modified: trunk/resource.h
===================================================================
--- trunk/resource.h	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/resource.h	2006-03-27 09:16:27 UTC (rev 685)
@@ -28,6 +28,7 @@
 {
 	RESOURCETYPE_INVALID = 0,
 	RESOURCETYPE_MODEL,
+	RESOURCETYPE_MODELANIM,
 	RESOURCETYPE_SOUND,
 	RESOURCETYPE_MATERIAL,
 	RESOURCETYPE_TEXTURE,

Modified: trunk/system.c
===================================================================
--- trunk/system.c	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/system.c	2006-03-27 09:16:27 UTC (rev 685)
@@ -30,6 +30,20 @@
 	R_Quit();
 	if (openglmode)
 	{
+		// hack to work around SDL not resetting the SDL_GL_SetAttribute stuff
+		// until we open a non-GL window
+		if (Video.running)
+		{
+			if (Video.openglmode)
+				DynGL_CloseLibrary();
+			SDL_WM_SetCaption ("DarkWar", "DarkWar");
+			Video_Surface = SDL_SetVideoMode(width, height, bpp, SDL_HWSURFACE | (fullscreen ? SDL_FULLSCREEN : 0));
+			if (!Video_Surface)
+			{
+				Console_Printf("Could not open video: %s.\n", SDL_GetError());
+				return false;
+			}
+		}
 		if (!DynGL_LoadLibrary(NULL))
 		{
 			char *error = SDL_GetError();
@@ -71,7 +85,8 @@
 	Video.fullscreen = fullscreen;
 	Video.openglmode = openglmode;
 	Video.framecount = 0;
-	DynGL_GetFunctions(NULL);
+	if (openglmode)
+		DynGL_GetFunctions(NULL);
 	R_Init();
 
 	Input.hasfocus = true;	//this ought to be true just after initialization (SDL doesn't seem to tell us either way).

Modified: trunk/todo
===================================================================
--- trunk/todo	2006-03-27 09:14:49 UTC (rev 684)
+++ trunk/todo	2006-03-27 09:16:27 UTC (rev 685)
@@ -15,3 +15,4 @@
 d bug darkwar console: cursoring left on the commandline and editing the text discards the rest of the line
 d change darkwar drawview: redesign G_DrawView to cull surfaces of entities
 d change darkwar util: util_maketerrain should emit only one md5mesh file with all the surfaces in it
+0 bug darkwar networking: attached entities should add dependencies to their owner so that if the owner update is lost and no more recent update of the child exists it forces an update of the child so that the child can attach properly
\ No newline at end of file




More information about the neither-commits mailing list