about summary refs log tree commit diff
path: root/src/game/server
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2007-09-25 23:03:15 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2007-09-25 23:03:15 +0000
commitfb87d00c8dfde266a46d5479838f06bce0b375fd (patch)
tree01fa66bbc4db4a54bc1c7dd55bc2f087dd0b5ed7 /src/game/server
parent31861cf222939ca26578010d5bbda61c8e2cd238 (diff)
downloadzcatch-fb87d00c8dfde266a46d5479838f06bce0b375fd.tar.gz
zcatch-fb87d00c8dfde266a46d5479838f06bce0b375fd.zip
moved out dm, tdm and ctf rules to separate files
Diffstat (limited to 'src/game/server')
-rw-r--r--src/game/server/game_server.cpp258
-rw-r--r--src/game/server/game_server.h310
-rw-r--r--src/game/server/srv_common.h286
-rw-r--r--src/game/server/srv_ctf.cpp148
-rw-r--r--src/game/server/srv_ctf.h35
-rw-r--r--src/game/server/srv_dm.cpp45
-rw-r--r--src/game/server/srv_dm.h6
-rw-r--r--src/game/server/srv_tdm.cpp40
-rw-r--r--src/game/server/srv_tdm.h6
9 files changed, 584 insertions, 550 deletions
diff --git a/src/game/server/game_server.cpp b/src/game/server/game_server.cpp
index 4647318a..0e42614e 100644
--- a/src/game/server/game_server.cpp
+++ b/src/game/server/game_server.cpp
@@ -2,10 +2,12 @@
 #include <stdio.h>
 #include <string.h>
 #include <engine/config.h>
-#include "../game.h"
 #include "../version.h"
-#include "data.h"
 #include "game_server.h"
+#include "srv_common.h"
+#include "srv_ctf.h"
+#include "srv_tdm.h"
+#include "srv_dm.h"
 
 data_container *data = 0x0;
 
@@ -279,8 +281,6 @@ gameobject::gameobject()
 	}
 		
 	//
-	
-	//
 	game_over_tick = -1;
 	sudden_death = 0;
 	round_start_tick = server_tick();
@@ -317,174 +317,20 @@ void gameobject::post_reset()
 	}
 }
 
-
-
-void gameobject::on_player_spawn(class player *p)
-{
-}
-
 void gameobject::on_player_death(class player *victim, class player *killer, int weapon)
 {
-	// drop flags
-	for(int fi = 0; fi < 2; fi++)
-	{
-		flag *f = flags[fi];
-		if(f && f->carrying_player == victim)
-			f->carrying_player = 0;
-	}
-}
-
-void gameobject::tick_ctf()
-{
-	// do flags
-	for(int fi = 0; fi < 2; fi++)
-	{
-		flag *f = flags[fi];
-		
-		//
-		if(f->carrying_player)
-		{
-			// update flag position
-			f->pos = f->carrying_player->pos;
-			
-			if(gameobj->flags[fi^1]->at_stand)
-			{
-				if(distance(f->pos, gameobj->flags[fi^1]->pos) < 24)
-				{
-					// CAPTURE! \o/
-					for(int i = 0; i < 2; i++)
-						gameobj->flags[i]->reset();
-				}
-			}			
-		}
-		else
-		{
-			player *players[MAX_CLIENTS];
-			int types[] = {OBJTYPE_PLAYER};
-			int num = world->find_entities(f->pos, 32.0f, (entity**)players, MAX_CLIENTS, types, 1);
-			for(int i = 0; i < num; i++)
-			{
-				if(players[i]->team == f->team)
-				{
-					// return the flag
-					f->reset();
-				}
-				else
-				{
-					// take the flag
-					f->at_stand = 0;
-					f->carrying_player = players[i];
-					break;
-				}
-			}
-			
-			if(!f->carrying_player)
-			{
-				f->vel.y += gravity;
-				move_box(&f->pos, &f->vel, vec2(f->phys_size, f->phys_size), 0.5f);
-			}
-		}
-	}
-}
-
-void gameobject::tick_dm()
-{
-	if(game_over_tick == -1)
-	{
-		// game is running
-		
-		// gather some stats
-		int topscore = 0;
-		int topscore_count = 0;
-		for(int i = 0; i < MAX_CLIENTS; i++)
-		{
-			if(players[i].client_id != -1)
-			{
-				if(players[i].score > topscore)
-				{
-					topscore = players[i].score;
-					topscore_count = 1;
-				}
-				else if(players[i].score == topscore)
-					topscore_count++;
-			}
-		}
-		
-		// check score win condition
-		if((config.scorelimit > 0 && topscore >= config.scorelimit) ||
-			(config.timelimit > 0 && (server_tick()-round_start_tick) >= config.timelimit*server_tickspeed()*60))
-		{
-			if(topscore_count == 1)
-				endround();
-			else
-				sudden_death = 1;
-		}
-	}
+	// do scoreing
+	if(!killer)
+		return;
+	if(killer == victim)
+		victim->score--; // klant arschel
 	else
-	{
-		// game over.. wait for restart
-		if(server_tick() > game_over_tick+server_tickspeed()*10)
-			startround();
-	}
+		killer->score++; // good shit
 }
 
-void gameobject::tick_tdm()
-{
-	if(game_over_tick == -1)
-	{
-		// game is running
-		
-		// gather some stats
-		int totalscore[2] = {0,0};
-		int topscore_count = 0;
-		for(int i = 0; i < MAX_CLIENTS; i++)
-		{
-			if(players[i].client_id != -1)
-				totalscore[players[i].team] += players[i].score;
-		}
-		if (totalscore[0] >= config.scorelimit)
-			topscore_count++;
-		if (totalscore[1] >= config.scorelimit)
-			topscore_count++;
-		
-		// check score win condition
-		if((config.scorelimit > 0 && (totalscore[0] >= config.scorelimit || totalscore[1] >= config.scorelimit)) ||
-			(config.timelimit > 0 && (server_tick()-round_start_tick) >= config.timelimit*server_tickspeed()*60))
-		{
-			if(topscore_count == 1)
-				endround();
-			else
-				sudden_death = 1;
-		}
-	}
-	else
-	{
-		// game over.. wait for restart
-		if(server_tick() > game_over_tick+server_tickspeed()*10)
-			startround();
-	}
-}
 
 void gameobject::tick()
 {
-	switch(gametype)
-	{
-	case GAMETYPE_CTF:
-		{
-			tick_ctf();
-			break;
-		}
-	case GAMETYPE_TDM:
-		{
-			tick_tdm();
-			break;
-		}
-	default:
-		{
-			tick_dm();
-			break;
-		}
-	}
 }
 
 void gameobject::snap(int snapping_client)
@@ -1179,18 +1025,6 @@ bool player::take_damage(vec2 force, int dmg, int from, int weapon)
 	// check for death
 	if(health <= 0)
 	{
-		// apply score
-		if(from != -1)
-		{
-			if(from == client_id)
-				score--;
-			else
-			{
-				player *p = get_player(from);
-				p->score++;
-			}
-		}
-		
 		die(from, weapon);
 
 		// set attacker's face to happy (taunt!)
@@ -1418,55 +1252,6 @@ void powerup::snap(int snapping_client)
 
 // POWERUP END ///////////////////////
 
-//////////////////////////////////////////////////
-// FLAG
-//////////////////////////////////////////////////
-flag::flag(int _team)
-: entity(OBJTYPE_FLAG)
-{
-	team = _team;
-	proximity_radius = phys_size;
-	carrying_player = 0x0;
-	
-	reset();
-	
-	// TODO: should this be done here?
-	world->insert_entity(this);
-}
-
-void flag::reset()
-{
-	carrying_player = 0;
-	at_stand = 1;
-	pos = stand_pos;
-	spawntick = -1;
-}
-
-void flag::tick()
-{
-}
-
-bool flag::is_grounded()
-{
-	if(col_check_point((int)(pos.x+phys_size/2), (int)(pos.y+phys_size/2+5)))
-		return true;
-	if(col_check_point((int)(pos.x-phys_size/2), (int)(pos.y+phys_size/2+5)))
-		return true;
-	return false;
-}
-
-void flag::snap(int snapping_client)
-{
-	if(spawntick != -1)
-		return;
-
-	obj_flag *flag = (obj_flag *)snap_new_item(OBJTYPE_FLAG, id, sizeof(obj_flag));
-	flag->x = (int)pos.x;
-	flag->y = (int)pos.y;
-	flag->team = team;
-}
-// FLAG END ///////////////////////
-
 player *get_player(int index)
 {
 	return &players[index];
@@ -1792,7 +1577,14 @@ void mods_init()
 
 	world = new game_world;
 	players = new player[MAX_CLIENTS];
-	gameobj = new gameobject;
+	
+	// select gametype
+	if(strcmp(config.gametype, "ctf") == 0)
+		gameobj = new gameobject_ctf;
+	else if(strcmp(config.gametype, "tdm") == 0)
+		gameobj = new gameobject_tdm;
+	else
+		gameobj = new gameobject_dm;
 	
 	// setup core world	
 	for(int i = 0; i < MAX_CLIENTS; i++)
@@ -1857,20 +1649,6 @@ void mods_init()
 	
 	if(gameobj->gametype == GAMETYPE_CTF)
 	{
-		// fetch flagstands
-		for(int i = 0; i < 2; i++)
-		{
-			mapres_flagstand *stand;
-			stand = (mapres_flagstand *)map_find_item(MAPRES_FLAGSTAND_RED+i, 0);
-			if(stand)
-			{
-				flag *f = new flag(i);
-				f->stand_pos = vec2(stand->x, stand->y);
-				f->pos = f->stand_pos;
-				gameobj->flags[i] = f;
-				dbg_msg("game", "flag at %f,%f", f->pos.x, f->pos.y);
-			}
-		}
 	}
 	
 	world->insert_entity(gameobj);
diff --git a/src/game/server/game_server.h b/src/game/server/game_server.h
index 22cc1f93..8b137891 100644
--- a/src/game/server/game_server.h
+++ b/src/game/server/game_server.h
@@ -1,311 +1 @@
 
-//
-class event_handler
-{
-	static const int MAX_EVENTS = 128;
-	static const int MAX_DATASIZE = 128*4;
-
-	int types[MAX_EVENTS];  // TODO: remove some of these arrays
-	int offsets[MAX_EVENTS];
-	int sizes[MAX_EVENTS];
-	int targets[MAX_EVENTS];
-	char data[MAX_DATASIZE];
-	
-	int current_offset;
-	int num_events;
-public:
-	event_handler();
-	void *create(int type, int size, int target = -1);
-	void clear();
-	void snap(int snapping_client);
-};
-
-extern event_handler events;
-
-// a basic entity
-class entity
-{
-private:
-	friend class game_world;
-	friend class player;
-	entity *prev_entity;
-	entity *next_entity;
-
-	entity *prev_type_entity;
-	entity *next_type_entity;
-
-	int index;
-protected:
-	int id;
-	
-public:
-	float proximity_radius;
-	unsigned flags;
-	int objtype;
-	vec2 pos;
-
-	enum
-	{
-		FLAG_DESTROY=0x00000001,
-		FLAG_ALIVE=0x00000002,
-	};
-	
-	entity(int objtype);
-	virtual ~entity();
-	
-	virtual void reset() {}
-	virtual void post_reset() {}
-	
-	void set_flag(unsigned flag) { flags |= flag; }
-	void clear_flag(unsigned flag) { flags &= ~flag; }
-
-	virtual void destroy() { delete this; }
-	virtual void tick() {}
-	virtual void tick_defered() {}
-		
-	virtual void snap(int snapping_client) {}
-		
-	virtual bool take_damage(vec2 force, int dmg, int from, int weapon) { return true; }
-};
-
-
-class game_world
-{
-	void reset();
-	void remove_entities();
-public:
-	enum
-	{
-		NUM_ENT_TYPES=10, // TODO: are more exact value perhaps? :)
-	};
-
-	// TODO: two lists seams kinda not good, shouldn't be needed
-	entity *first_entity;
-	entity *first_entity_types[NUM_ENT_TYPES];
-	bool paused;
-	bool reset_requested;
-	
-	world_core core;
-	
-	game_world();
-	int find_entities(vec2 pos, float radius, entity **ents, int max);
-	int find_entities(vec2 pos, float radius, entity **ents, int max, const int* types, int maxtypes);
-
-	void insert_entity(entity *ent);
-	void destroy_entity(entity *ent);
-	void remove_entity(entity *ent);
-	
-	//
-	void snap(int snapping_client);
-	void tick();
-};
-
-extern game_world *world;
-
-// game object
-class gameobject : public entity
-{
-	void resetgame();
-	void startround();
-	void endround();
-	
-	int round_start_tick;
-	int game_over_tick;
-	int sudden_death;
-	
-public:
-	class flag *flags[2];
-	
-	int gametype;
-	gameobject();
-	virtual void post_reset();
-	virtual void tick();
-	virtual void tick_dm();
-	virtual void tick_tdm();
-	virtual void tick_ctf();
-	
-	virtual void on_player_spawn(class player *p);
-	virtual void on_player_death(class player *victim, class player *killer, int weapon);
-	
-	virtual void snap(int snapping_client);
-	virtual int getteam(int notthisid);
-};
-
-extern gameobject *gameobj;
-
-
-// TODO: move to seperate file
-class powerup : public entity
-{
-public:
-	static const int phys_size = 14;
-	
-	int type;
-	int subtype; // weapon type for instance?
-	int spawntick;
-	powerup(int _type, int _subtype = 0);
-	
-	virtual void reset();
-	virtual void tick();
-	virtual void snap(int snapping_client);
-};
-
-
-
-// projectile entity
-class projectile : public entity
-{
-public:
-	enum
-	{
-		PROJECTILE_FLAGS_EXPLODE = 1 << 0,
-		
-		WEAPON_PROJECTILETYPE_GUN		= 0,
-		WEAPON_PROJECTILETYPE_ROCKET	= 1,
-		WEAPON_PROJECTILETYPE_SHOTGUN	= 2,
-	};
-	
-	vec2 vel;
-	entity *powner; // this is nasty, could be removed when client quits
-	int lifespan;
-	int owner;
-	int type;
-	int flags;
-	int damage;
-	int sound_impact;
-	int weapon;
-	int bounce;
-	float force;
-	
-	projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner,
-		int damage, int flags, float force, int sound_impact, int weapon);
-	virtual void reset();
-	virtual void tick();
-	virtual void snap(int snapping_client);
-};
-
-// player entity
-class player : public entity
-{
-public:
-	static const int phys_size = 28;
-	
-	enum // what are these?
-	{
-		MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY		= 1 << 0,
-		MODIFIER_RETURNFLAGS_OVERRIDEPOSITION		= 1 << 1,
-		MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY		= 1 << 2,
-	};
-
-	// weapon info
-	entity* hitobjects[10];
-	int numobjectshit;
-	struct weaponstat
-	{
-		int ammoregenstart;
-		int ammo;
-		int ammocost;
-		bool got;
-	} weapons[NUM_WEAPONS];
-	int active_weapon;
-	int last_weapon;
-	int reload_timer;
-	int attack_tick;
-	
-	int damage_taken;
-
-	int emote_type;
-	int emote_stop;
-
-	int last_action;
-	
-	//
-	int client_id;
-	char name[64];
-
-	// input	
-	player_input previnput;
-	player_input input;
-	int jumped;
-	
-	int damage_taken_tick;
-
-	int health;
-	int armor;
-
-	// ninja
-	vec2 activationdir;
-	int ninjaactivationtick;
-	int extrapowerflags;
-	int currentcooldown;
-	int currentactivation;
-	int currentmovetime;
-
-	//
-	int score;
-	int team;
-	int state;
-	
-	bool spawning;
-	bool dead;
-	int die_tick;
-	
-	// latency calculations
-	int latency_accum;
-	int latency_accum_min;
-	int latency_accum_max;
-	int latency_avg;
-	int latency_min;
-	int latency_max;
-
-	// the player core for the physics	
-	player_core core;
-
-	//
-	player();
-	void init();
-	virtual void reset();
-	virtual void destroy();
-		
-	void try_respawn();
-	void respawn();
-
-	bool is_grounded();
-	
-	void set_weapon(int w);
-	
-	int handle_weapons();
-	int handle_ninja();
-
-	virtual void tick();
-	virtual void tick_defered();
-	
-	void die(int killer, int weapon);
-	
-	virtual bool take_damage(vec2 force, int dmg, int from, int weapon);
-	virtual void snap(int snaping_client);
-};
-
-extern player *players;
-
-// TODO: move to seperate file
-class flag : public entity
-{
-public:
-	static const int phys_size = 14;
-	player *carrying_player;
-	vec2 vel;
-	vec2 stand_pos;
-	
-	int team;
-	int spawntick;
-	int at_stand;
-	
-	flag(int _team);
-
-	bool is_grounded();
-	
-	virtual void reset();
-	virtual void tick();
-	virtual void snap(int snapping_client);
-};
diff --git a/src/game/server/srv_common.h b/src/game/server/srv_common.h
new file mode 100644
index 00000000..7b6e7e1e
--- /dev/null
+++ b/src/game/server/srv_common.h
@@ -0,0 +1,286 @@
+#include "../game.h"
+#include "data.h"
+
+//
+class event_handler
+{
+	static const int MAX_EVENTS = 128;
+	static const int MAX_DATASIZE = 128*4;
+
+	int types[MAX_EVENTS];  // TODO: remove some of these arrays
+	int offsets[MAX_EVENTS];
+	int sizes[MAX_EVENTS];
+	int targets[MAX_EVENTS];
+	char data[MAX_DATASIZE];
+	
+	int current_offset;
+	int num_events;
+public:
+	event_handler();
+	void *create(int type, int size, int target = -1);
+	void clear();
+	void snap(int snapping_client);
+};
+
+extern event_handler events;
+
+// a basic entity
+class entity
+{
+private:
+	friend class game_world;
+	friend class player;
+	entity *prev_entity;
+	entity *next_entity;
+
+	entity *prev_type_entity;
+	entity *next_type_entity;
+
+	int index;
+protected:
+	int id;
+	
+public:
+	float proximity_radius;
+	unsigned flags;
+	int objtype;
+	vec2 pos;
+
+	enum
+	{
+		FLAG_DESTROY=0x00000001,
+		FLAG_ALIVE=0x00000002,
+	};
+	
+	entity(int objtype);
+	virtual ~entity();
+	
+	virtual void reset() {}
+	virtual void post_reset() {}
+	
+	void set_flag(unsigned flag) { flags |= flag; }
+	void clear_flag(unsigned flag) { flags &= ~flag; }
+
+	virtual void destroy() { delete this; }
+	virtual void tick() {}
+	virtual void tick_defered() {}
+		
+	virtual void snap(int snapping_client) {}
+		
+	virtual bool take_damage(vec2 force, int dmg, int from, int weapon) { return true; }
+};
+
+
+class game_world
+{
+	void reset();
+	void remove_entities();
+public:
+	enum
+	{
+		NUM_ENT_TYPES=10, // TODO: are more exact value perhaps? :)
+	};
+
+	// TODO: two lists seams kinda not good, shouldn't be needed
+	entity *first_entity;
+	entity *first_entity_types[NUM_ENT_TYPES];
+	bool paused;
+	bool reset_requested;
+	
+	world_core core;
+	
+	game_world();
+	int find_entities(vec2 pos, float radius, entity **ents, int max);
+	int find_entities(vec2 pos, float radius, entity **ents, int max, const int* types, int maxtypes);
+
+	void insert_entity(entity *ent);
+	void destroy_entity(entity *ent);
+	void remove_entity(entity *ent);
+	
+	//
+	void snap(int snapping_client);
+	void tick();
+};
+
+extern game_world *world;
+
+// game object
+// TODO: should change name of this one
+class gameobject : public entity
+{
+protected:
+	void resetgame();
+	void startround();
+	void endround();
+	
+	int round_start_tick;
+	int game_over_tick;
+	int sudden_death;
+	
+public:
+	int gametype;
+	gameobject();
+	virtual void post_reset();
+	virtual void tick();
+	
+	virtual void on_player_spawn(class player *p) {}
+	virtual void on_player_death(class player *victim, class player *killer, int weapon);
+	
+	virtual void snap(int snapping_client);
+	virtual int getteam(int notthisid);
+};
+
+extern gameobject *gameobj;
+
+
+// TODO: move to seperate file
+class powerup : public entity
+{
+public:
+	static const int phys_size = 14;
+	
+	int type;
+	int subtype; // weapon type for instance?
+	int spawntick;
+	powerup(int _type, int _subtype = 0);
+	
+	virtual void reset();
+	virtual void tick();
+	virtual void snap(int snapping_client);
+};
+
+// projectile entity
+class projectile : public entity
+{
+public:
+	enum
+	{
+		PROJECTILE_FLAGS_EXPLODE = 1 << 0,
+		
+		WEAPON_PROJECTILETYPE_GUN		= 0,
+		WEAPON_PROJECTILETYPE_ROCKET	= 1,
+		WEAPON_PROJECTILETYPE_SHOTGUN	= 2,
+	};
+	
+	vec2 vel;
+	entity *powner; // this is nasty, could be removed when client quits
+	int lifespan;
+	int owner;
+	int type;
+	int flags;
+	int damage;
+	int sound_impact;
+	int weapon;
+	int bounce;
+	float force;
+	
+	projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner,
+		int damage, int flags, float force, int sound_impact, int weapon);
+	virtual void reset();
+	virtual void tick();
+	virtual void snap(int snapping_client);
+};
+
+// player entity
+class player : public entity
+{
+public:
+	static const int phys_size = 28;
+	
+	enum // what are these?
+	{
+		MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY		= 1 << 0,
+		MODIFIER_RETURNFLAGS_OVERRIDEPOSITION		= 1 << 1,
+		MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY		= 1 << 2,
+	};
+
+	// weapon info
+	entity* hitobjects[10];
+	int numobjectshit;
+	struct weaponstat
+	{
+		int ammoregenstart;
+		int ammo;
+		int ammocost;
+		bool got;
+	} weapons[NUM_WEAPONS];
+	int active_weapon;
+	int last_weapon;
+	int reload_timer;
+	int attack_tick;
+	
+	int damage_taken;
+
+	int emote_type;
+	int emote_stop;
+
+	int last_action;
+	
+	//
+	int client_id;
+	char name[64];
+
+	// input	
+	player_input previnput;
+	player_input input;
+	int jumped;
+	
+	int damage_taken_tick;
+
+	int health;
+	int armor;
+
+	// ninja
+	vec2 activationdir;
+	int ninjaactivationtick;
+	int extrapowerflags;
+	int currentcooldown;
+	int currentactivation;
+	int currentmovetime;
+
+	//
+	int score;
+	int team;
+	int state;
+	
+	bool spawning;
+	bool dead;
+	int die_tick;
+	
+	// latency calculations
+	int latency_accum;
+	int latency_accum_min;
+	int latency_accum_max;
+	int latency_avg;
+	int latency_min;
+	int latency_max;
+
+	// the player core for the physics	
+	player_core core;
+
+	//
+	player();
+	void init();
+	virtual void reset();
+	virtual void destroy();
+		
+	void try_respawn();
+	void respawn();
+
+	bool is_grounded();
+	
+	void set_weapon(int w);
+	
+	int handle_weapons();
+	int handle_ninja();
+
+	virtual void tick();
+	virtual void tick_defered();
+	
+	void die(int killer, int weapon);
+	
+	virtual bool take_damage(vec2 force, int dmg, int from, int weapon);
+	virtual void snap(int snaping_client);
+};
+
+extern player *players;
diff --git a/src/game/server/srv_ctf.cpp b/src/game/server/srv_ctf.cpp
new file mode 100644
index 00000000..8f345436
--- /dev/null
+++ b/src/game/server/srv_ctf.cpp
@@ -0,0 +1,148 @@
+#include "srv_common.h"
+#include "srv_ctf.h"
+
+gameobject_ctf::gameobject_ctf()
+{
+	// fetch flagstands
+	for(int i = 0; i < 2; i++)
+	{
+		mapres_flagstand *stand;
+		stand = (mapres_flagstand *)map_find_item(MAPRES_FLAGSTAND_RED+i, 0);
+		if(stand)
+		{
+			flag *f = new flag(i);
+			f->stand_pos = vec2(stand->x, stand->y);
+			f->pos = f->stand_pos;
+			flags[i] = f;
+			//dbg_msg("game", "flag at %f,%f", f->pos.x, f->pos.y);
+		}
+		else
+		{
+			// report massive failure
+		}
+	}
+}
+
+void gameobject_ctf::on_player_spawn(class player *p)
+{
+}
+
+void gameobject_ctf::on_player_death(class player *victim, class player *killer, int weapon)
+{
+	// drop flags
+	for(int fi = 0; fi < 2; fi++)
+	{
+		flag *f = flags[fi];
+		if(f && f->carrying_player == victim)
+			f->carrying_player = 0;
+	}
+}
+
+void gameobject_ctf::tick()
+{
+	gameobject::tick();
+	
+	// do flags
+	for(int fi = 0; fi < 2; fi++)
+	{
+		flag *f = flags[fi];
+		
+		//
+		if(f->carrying_player)
+		{
+			// update flag position
+			f->pos = f->carrying_player->pos;
+			
+			if(flags[fi^1]->at_stand)
+			{
+				if(distance(f->pos, flags[fi^1]->pos) < 24)
+				{
+					// CAPTURE! \o/
+					for(int i = 0; i < 2; i++)
+						flags[i]->reset();
+				}
+			}			
+		}
+		else
+		{
+			player *players[MAX_CLIENTS];
+			int types[] = {OBJTYPE_PLAYER};
+			int num = world->find_entities(f->pos, 32.0f, (entity**)players, MAX_CLIENTS, types, 1);
+			for(int i = 0; i < num; i++)
+			{
+				if(players[i]->team == f->team)
+				{
+					// return the flag
+					f->reset();
+				}
+				else
+				{
+					// take the flag
+					f->at_stand = 0;
+					f->carrying_player = players[i];
+					break;
+				}
+			}
+			
+			if(!f->carrying_player)
+			{
+				f->vel.y += gravity;
+				move_box(&f->pos, &f->vel, vec2(f->phys_size, f->phys_size), 0.5f);
+			}
+		}
+	}
+}
+
+//////////////////////////////////////////////////
+// FLAG
+//////////////////////////////////////////////////
+flag::flag(int _team)
+: entity(OBJTYPE_FLAG)
+{
+	team = _team;
+	proximity_radius = phys_size;
+	carrying_player = 0x0;
+	
+	reset();
+	
+	// TODO: should this be done here?
+	world->insert_entity(this);
+}
+
+void flag::reset()
+{
+	carrying_player = 0;
+	at_stand = 1;
+	pos = stand_pos;
+	spawntick = -1;
+}
+
+void flag::tick()
+{
+}
+
+bool flag::is_grounded()
+{
+	if(col_check_point((int)(pos.x+phys_size/2), (int)(pos.y+phys_size/2+5)))
+		return true;
+	if(col_check_point((int)(pos.x-phys_size/2), (int)(pos.y+phys_size/2+5)))
+		return true;
+	return false;
+}
+
+void flag::snap(int snapping_client)
+{
+	if(spawntick != -1)
+		return;
+
+	obj_flag *flag = (obj_flag *)snap_new_item(OBJTYPE_FLAG, id, sizeof(obj_flag));
+	flag->x = (int)pos.x;
+	flag->y = (int)pos.y;
+	flag->team = team;
+	
+	if(carrying_player && carrying_player->client_id == snapping_client)
+		flag->local_carry = 1;
+	else
+		flag->local_carry = 0;
+}
+// FLAG END ///////////////////////
diff --git a/src/game/server/srv_ctf.h b/src/game/server/srv_ctf.h
new file mode 100644
index 00000000..70bb7777
--- /dev/null
+++ b/src/game/server/srv_ctf.h
@@ -0,0 +1,35 @@
+
+// game object
+class gameobject_ctf : public gameobject
+{
+public:
+	class flag *flags[2];
+	
+	gameobject_ctf();
+	virtual void tick();
+	
+	virtual void on_player_spawn(class player *p);
+	virtual void on_player_death(class player *victim, class player *killer, int weapon);
+};
+
+// TODO: move to seperate file
+class flag : public entity
+{
+public:
+	static const int phys_size = 14;
+	player *carrying_player;
+	vec2 vel;
+	vec2 stand_pos;
+	
+	int team;
+	int spawntick;
+	int at_stand;
+	
+	flag(int _team);
+
+	bool is_grounded();
+	
+	virtual void reset();
+	virtual void tick();
+	virtual void snap(int snapping_client);
+};
diff --git a/src/game/server/srv_dm.cpp b/src/game/server/srv_dm.cpp
new file mode 100644
index 00000000..01817262
--- /dev/null
+++ b/src/game/server/srv_dm.cpp
@@ -0,0 +1,45 @@
+#include <engine/config.h>
+#include "srv_common.h"
+#include "srv_dm.h"
+
+void gameobject_dm::tick()
+{
+	if(game_over_tick == -1)
+	{
+		// game is running
+		
+		// gather some stats
+		int topscore = 0;
+		int topscore_count = 0;
+		for(int i = 0; i < MAX_CLIENTS; i++)
+		{
+			if(players[i].client_id != -1)
+			{
+				if(players[i].score > topscore)
+				{
+					topscore = players[i].score;
+					topscore_count = 1;
+				}
+				else if(players[i].score == topscore)
+					topscore_count++;
+			}
+		}
+		
+		// check score win condition
+		if((config.scorelimit > 0 && topscore >= config.scorelimit) ||
+			(config.timelimit > 0 && (server_tick()-round_start_tick) >= config.timelimit*server_tickspeed()*60))
+		{
+			if(topscore_count == 1)
+				endround();
+			else
+				sudden_death = 1;
+		}
+	}
+	else
+	{
+		// game over.. wait for restart
+		if(server_tick() > game_over_tick+server_tickspeed()*10)
+			startround();
+	}
+}
+
diff --git a/src/game/server/srv_dm.h b/src/game/server/srv_dm.h
new file mode 100644
index 00000000..b6fc8b62
--- /dev/null
+++ b/src/game/server/srv_dm.h
@@ -0,0 +1,6 @@
+// game object
+class gameobject_dm : public gameobject
+{
+public:
+	virtual void tick();
+};
diff --git a/src/game/server/srv_tdm.cpp b/src/game/server/srv_tdm.cpp
new file mode 100644
index 00000000..ca1a5a67
--- /dev/null
+++ b/src/game/server/srv_tdm.cpp
@@ -0,0 +1,40 @@
+#include <engine/config.h>
+#include "srv_common.h"
+#include "srv_tdm.h"
+
+void gameobject_tdm::tick()
+{
+	if(game_over_tick == -1)
+	{
+		// game is running
+		
+		// gather some stats
+		int totalscore[2] = {0,0};
+		int topscore_count = 0;
+		for(int i = 0; i < MAX_CLIENTS; i++)
+		{
+			if(players[i].client_id != -1)
+				totalscore[players[i].team] += players[i].score;
+		}
+		if (totalscore[0] >= config.scorelimit)
+			topscore_count++;
+		if (totalscore[1] >= config.scorelimit)
+			topscore_count++;
+		
+		// check score win condition
+		if((config.scorelimit > 0 && (totalscore[0] >= config.scorelimit || totalscore[1] >= config.scorelimit)) ||
+			(config.timelimit > 0 && (server_tick()-round_start_tick) >= config.timelimit*server_tickspeed()*60))
+		{
+			if(topscore_count == 1)
+				endround();
+			else
+				sudden_death = 1;
+		}
+	}
+	else
+	{
+		// game over.. wait for restart
+		if(server_tick() > game_over_tick+server_tickspeed()*10)
+			startround();
+	}
+}
diff --git a/src/game/server/srv_tdm.h b/src/game/server/srv_tdm.h
new file mode 100644
index 00000000..748c2e9e
--- /dev/null
+++ b/src/game/server/srv_tdm.h
@@ -0,0 +1,6 @@
+// game object
+class gameobject_tdm : public gameobject
+{
+public:
+	virtual void tick();
+};