Index: neither/darkwar/game/g_main.c
diff -u neither/darkwar/game/g_main.c:1.27 neither/darkwar/game/g_main.c:1.28
--- neither/darkwar/game/g_main.c:1.27	Mon Jan 17 01:15:38 2005
+++ neither/darkwar/game/g_main.c	Mon Jan 17 20:23:41 2005
@@ -399,7 +399,6 @@
 {
 	NUint32 i;
 	G_Entity *entity;
-	static Ndouble testtime = 0;
 	G.framecount++;
 	G.frametime = frametime;
 	G.oldtime = G.time;
@@ -410,12 +409,15 @@
 			entity->eclass->framecallback(entity);
 	// TODO: call physics
 #if 0
+{
+	static Ndouble testtime = 0;
 	if(testtime < G.time)
 	{
 		Ndouble origin[3] = { 200, 0, 0 };
 		testtime = G.time + 3;
 		ParticleEffect_Explosion (origin, 8);
 	}
+}
 #endif
 	ParticleEffect_Frame (&G.cameramatrix);
 }
@@ -584,13 +586,6 @@
 	G.allocentity = Min(G.allocentity, entitynum);
 }
 
-void G_RemoveEntities(void)
-{
-	NUint32 i;
-	for (i = 0;i < G_MAX_ENTITIES;i++)
-		G_Entity_Remove(G.entities + i);
-}
-
 void G_Entity_Relink(G_Entity *entity)
 {
 	Nvec3 cullorigin;
@@ -816,18 +811,20 @@
 	return;
 }
 
-Nbool G_Map_Load(const char *filename)
+void G_World_ClearEntities(void)
+{
+	NUint32 i;
+	for (i = 0;i < G_MAX_ENTITIES;i++)
+		G_Entity_Remove(G.entities + i);
+}
+
+void G_World_LoadEntityString(char *filedata, Nsize filesize)
 {
-	Nsize filesize;
-	char *filedata;
 	char *text, *textend;
 	NUint32 j;
 	Util_ParseC_TokenType tokentype;
 	char *token, *key[2];
 	G_Entity *entity;
-	filedata = File_LoadFile(filename, &filesize);
-	if (!filedata)
-		return false;
 	text = filedata;
 	textend = filedata + filesize;
 	token = NULL;
@@ -872,11 +869,9 @@
 	String_Free(&token);
 	String_Free(&key[0]);
 	String_Free(&key[1]);
-	Mem_Free(&filedata);
-	return true;
 }
 
-void G_Map_Save(const char *filename)
+void G_World_SaveEntities(const char *filename)
 {
 	NUint32 i, j;
 	Nsize filesize;
@@ -918,21 +913,33 @@
 	Mem_Free(filedata);
 }
 
-void G_Server_LoadLevel(const char *filename, Nbool editmode)
+void G_World_SpawnLevel(const char *filename, Nbool editmode)
 {
 	NUint32 i;
+	Nsize filesize;
+	char *filedata;
 	G_Entity *spot;
-	Ndouble rain[3] = { 0, 0, 0 };
-	if (!G_Map_Load(filename))
+
+	filedata = File_LoadFile(filename, &filesize);
+
+	if (!filedata)
 	{
-		Console_Printf("G_Server_LoadLevel: no such entity file \"%s\"\n", filename);
+		Console_Printf("G_World_SpawnLevel: no such entity file \"%s\"\n", filename);
 		return;
 	}
 
+	G_World_ClearEntities();
+
+	memset(&G, 0, sizeof(G));
+
 	G.framecount = 0;
 	G.time = G.oldtime = G.frametime = 0;
 	G.editing = editmode;
 
+	G_World_LoadEntityString(filedata, filesize);
+
+	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);
@@ -945,8 +952,11 @@
 		Matrix4x4_CreateIdentity(&G.cameramatrix);
 
 #if 0
+{
 	// testing
+	Ndouble rain[3] = { 0, 0, 0 };
 	ParticleEffect_Rain(rain, 256);
+}
 #endif
 
 	// run two 100ms frames to let the world stabilize before clients spawn
@@ -955,15 +965,18 @@
 	// TODO: spawn connected clients
 }
 
-void G_Server_Init(void)
+void G_World_Init(void)
 {
 	// TODO: networking?
 }
 
-void G_Server_Quit(void)
+void G_World_Quit(void)
 {
 	// TODO: networking
-	Console_Printf("Server shutting down\n");
+	if (GS.role & G_ROLE_SERVER)
+		Console_Printf("Server shutting down\n");
+	if (GS.role & G_ROLE_CLIENT)
+		Console_Printf("Client shutting down\n");
 }
 
 void G_UpdateFPS(void)
@@ -998,10 +1011,11 @@
 void G_Main(void)
 {
 	memset(&GS, 0, sizeof(GS));
-	memset(&G, 0, sizeof(G));
 
 	GS.memzone = Mem_AllocZone("Game", Global_Zone, 0);
 
+	GS.role = G_ROLE_CLIENT | G_ROLE_SERVER;
+
 	GS.quit = false;
 
 	GS.realtime = GS.oldrealtime = System_Time();
@@ -1010,14 +1024,6 @@
 	GS.fpsframecount = 0;
 	GS.fpsbasetime = 0;
 
-	// FIXME: rework this to happen in StartServer or something
-	ParticleEffect_Init(4);
-
-	Video_SetMode(800, 600, 32, false, true);
-	Audio_SetMode(44100);
-	G_Server_Init();
-	G_Server_LoadLevel("maps/test.ent", false);
-
 	// Commands
 	Command_Register(G_QuitEvent, "quit", "Quits DarkWar.");
 
@@ -1028,8 +1034,15 @@
 	Cvar_Register("g_showshadowvolumes", "0", "", CMD_ENGINE | CMD_DEFAULT);
 	Cvar_Register("g_showtris", "0", "", CMD_ENGINE | CMD_DEFAULT);
 
+	// FIXME: rework this to happen in StartServer or something
+	ParticleEffect_Init(4);
+
+	Video_SetMode(800, 600, 32, false, true);
+	Audio_SetMode(44100);
+	G_World_Init();
+	G_World_SpawnLevel("maps/test.ent", false);
 	G_MainLoop();
-	G_Server_Quit();
+	G_World_Quit();
 	ParticleEffect_Quit();
 
 	memset(&G, 0, sizeof(G));
Index: neither/darkwar/game/g_main.h
diff -u neither/darkwar/game/g_main.h:1.6 neither/darkwar/game/g_main.h:1.7
--- neither/darkwar/game/g_main.h:1.6	Sun Jan 16 22:47:31 2005
+++ neither/darkwar/game/g_main.h	Mon Jan 17 20:23:41 2005
@@ -43,12 +43,20 @@
 }
 G_Buttons;
 
+// bit flags
+#define G_ROLE_CLIENT 1<<0
+#define G_ROLE_SERVER 1<<1
+
 typedef struct G_Static
 {
 	// memory zone holding game structures
 	Mem_Zone *memzone;
 	// quit on next mainloop iteration
 	Nbool quit;
+	// role of this host
+	// (see G_ROLE_*)
+	NUint32 role;
+	// tells renderer to take a screenshot this frame
 	Nbool screenshot;
 	// input buttons
 	G_Buttons buttons;