about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game/server/entities/character.cpp (renamed from src/game/server/gs_ent_player.cpp)5
-rw-r--r--src/game/server/entities/character.hpp122
-rw-r--r--src/game/server/entities/laser.cpp112
-rw-r--r--src/game/server/entities/laser.hpp31
-rw-r--r--src/game/server/entities/pickup.cpp (renamed from src/game/server/gs_ent_pickup.cpp)6
-rw-r--r--src/game/server/entities/pickup.hpp24
-rw-r--r--src/game/server/entities/projectile.cpp108
-rw-r--r--src/game/server/entities/projectile.hpp38
-rw-r--r--src/game/server/entity.hpp83
-rw-r--r--src/game/server/eventhandler.hpp25
-rw-r--r--src/game/server/gamecontext.hpp38
-rw-r--r--src/game/server/gamecontroller.cpp (renamed from src/game/server/gs_game.cpp)2
-rw-r--r--src/game/server/gamecontroller.hpp97
-rw-r--r--src/game/server/gamemodes/ctf.cpp (renamed from src/game/server/gs_game_ctf.cpp)6
-rw-r--r--src/game/server/gamemodes/ctf.hpp (renamed from src/game/server/gs_game_ctf.hpp)4
-rw-r--r--src/game/server/gamemodes/dm.cpp (renamed from src/game/server/gs_game_dm.cpp)4
-rw-r--r--src/game/server/gamemodes/dm.hpp (renamed from src/game/server/gs_game_dm.hpp)4
-rw-r--r--src/game/server/gamemodes/tdm.cpp (renamed from src/game/server/gs_game_tdm.cpp)7
-rw-r--r--src/game/server/gamemodes/tdm.hpp (renamed from src/game/server/gs_game_tdm.hpp)4
-rw-r--r--src/game/server/gameworld.hpp126
-rw-r--r--src/game/server/gs_common.hpp587
-rw-r--r--src/game/server/gs_server.cpp226
-rw-r--r--src/game/server/player.hpp55
23 files changed, 901 insertions, 813 deletions
diff --git a/src/game/server/gs_ent_player.cpp b/src/game/server/entities/character.cpp
index b476a972..160e080a 100644
--- a/src/game/server/gs_ent_player.cpp
+++ b/src/game/server/entities/character.cpp
@@ -1,8 +1,11 @@
 #include <new>
 #include <engine/e_server_interface.h>
 #include <engine/e_config.h>
-#include "gs_common.hpp"
+#include <game/server/gs_common.hpp>
 
+#include "character.hpp"
+#include "laser.hpp"
+#include "projectile.hpp"
 
 struct INPUT_COUNT
 {
diff --git a/src/game/server/entities/character.hpp b/src/game/server/entities/character.hpp
new file mode 100644
index 00000000..6ceb987c
--- /dev/null
+++ b/src/game/server/entities/character.hpp
@@ -0,0 +1,122 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+
+#ifndef GAME_SERVER_ENTITY_CHARACTER_H
+#define GAME_SERVER_ENTITY_CHARACTER_H
+
+#include <game/server/entity.hpp>
+#include <game/generated/gs_data.hpp>
+#include <game/generated/g_protocol.hpp>
+
+#include <game/g_game.hpp>
+
+class CHARACTER : public ENTITY
+{
+public:
+	// player controlling this character
+	class PLAYER *player;
+	
+	bool alive;
+
+	// 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 queued_weapon;
+	
+	int reload_timer;
+	int attack_tick;
+	
+	int damage_taken;
+
+	int emote_type;
+	int emote_stop;
+
+	// TODO: clean this up
+	char skin_name[64];
+	int use_custom_color;
+	int color_body;
+	int color_feet;
+	
+	int last_action; // last tick that the player took any action ie some input
+
+	// these are non-heldback inputs
+	NETOBJ_PLAYER_INPUT latest_previnput;
+	NETOBJ_PLAYER_INPUT latest_input;
+
+	// input	
+	NETOBJ_PLAYER_INPUT previnput;
+	NETOBJ_PLAYER_INPUT input;
+	int num_inputs;
+	int jumped;
+	
+	int damage_taken_tick;
+
+	int health;
+	int armor;
+
+	// ninja
+	struct
+	{
+		vec2 activationdir;
+		int activationtick;
+		int currentcooldown;
+		int currentmovetime;
+	} ninja;
+
+	//
+	//int score;
+	int team;
+	int player_state; // if the client is chatting, accessing a menu or so
+
+	// the player core for the physics	
+	CHARACTER_CORE core;
+
+	//
+	CHARACTER();
+	
+	virtual void reset();
+	virtual void destroy();
+		
+	bool is_grounded();
+	
+	void set_weapon(int w);
+	
+	void handle_weaponswitch();
+	void do_weaponswitch();
+	
+	int handle_weapons();
+	int handle_ninja();
+
+	void on_predicted_input(NETOBJ_PLAYER_INPUT *new_input);
+	void on_direct_input(NETOBJ_PLAYER_INPUT *new_input);
+	void fire_weapon();
+
+	void die(int killer, int weapon);
+
+	bool take_damage(vec2 force, int dmg, int from, int weapon);	
+
+	
+	bool spawn(PLAYER *player, vec2 pos, int team);
+	//bool init_tryspawn(int team);
+	bool remove();
+
+	static const int phys_size = 28;
+
+	virtual void tick();
+	virtual void tick_defered();
+	virtual void snap(int snaping_client);
+	
+	bool increase_health(int amount);
+	bool increase_armor(int amount);
+};
+
+#endif
diff --git a/src/game/server/entities/laser.cpp b/src/game/server/entities/laser.cpp
new file mode 100644
index 00000000..cedf7850
--- /dev/null
+++ b/src/game/server/entities/laser.cpp
@@ -0,0 +1,112 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+#include <engine/e_server_interface.h>
+#include <game/generated/g_protocol.hpp>
+#include <game/server/gs_common.hpp>
+#include "laser.hpp"
+
+//////////////////////////////////////////////////
+// laser
+//////////////////////////////////////////////////
+LASER::LASER(vec2 pos, vec2 direction, float start_energy, CHARACTER *owner)
+: ENTITY(NETOBJTYPE_LASER)
+{
+	this->pos = pos;
+	this->owner = owner;
+	energy = start_energy;
+	dir = direction;
+	bounces = 0;
+	do_bounce();
+	
+	game.world.insert_entity(this);
+}
+
+
+bool LASER::hit_character(vec2 from, vec2 to)
+{
+	vec2 at;
+	CHARACTER *hit = game.world.intersect_character(pos, to, 0.0f, at, owner);
+	if(!hit)
+		return false;
+
+	this->from = from;
+	pos = at;
+	energy = -1;		
+	hit->take_damage(vec2(0,0), tuning.laser_damage, owner->player->client_id, WEAPON_RIFLE);
+	return true;
+}
+
+void LASER::do_bounce()
+{
+	eval_tick = server_tick();
+	
+	if(energy < 0)
+	{
+		//dbg_msg("laser", "%d removed", server_tick());
+		game.world.destroy_entity(this);
+		return;
+	}
+	
+	vec2 to = pos + dir*energy;
+	
+	if(col_intersect_line(pos, to, &to))
+	{
+		if(!hit_character(pos, to))
+		{
+			// intersected
+			from = pos;
+			pos = to - dir*2;
+			vec2 temp_pos = pos;
+			vec2 temp_dir = dir*4.0f;
+			
+			move_point(&temp_pos, &temp_dir, 1.0f, 0);
+			pos = temp_pos;
+			dir = normalize(temp_dir);
+			
+			energy -= distance(from, pos) + tuning.laser_bounce_cost;
+			bounces++;
+			
+			if(bounces > tuning.laser_bounce_num)
+				energy = -1;
+				
+			game.create_sound(pos, SOUND_RIFLE_BOUNCE);
+		}
+	}
+	else
+	{
+		if(!hit_character(pos, to))
+		{
+			from = pos;
+			pos = to;
+			energy = -1;
+		}
+	}
+		
+	//dbg_msg("laser", "%d done %f %f %f %f", server_tick(), from.x, from.y, pos.x, pos.y);
+}
+	
+void LASER::reset()
+{
+	game.world.destroy_entity(this);
+}
+
+void LASER::tick()
+{
+	if(server_tick() > eval_tick+(server_tickspeed()*tuning.laser_bounce_delay)/1000.0f)
+	{
+		do_bounce();
+	}
+
+}
+
+void LASER::snap(int snapping_client)
+{
+	if(distance(game.players[snapping_client].view_pos, pos) > 1000.0f)
+		return;
+
+	NETOBJ_LASER *obj = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id, sizeof(NETOBJ_LASER));
+	obj->x = (int)pos.x;
+	obj->y = (int)pos.y;
+	obj->from_x = (int)from.x;
+	obj->from_y = (int)from.y;
+	obj->start_tick = eval_tick;
+}
diff --git a/src/game/server/entities/laser.hpp b/src/game/server/entities/laser.hpp
new file mode 100644
index 00000000..4842b3f8
--- /dev/null
+++ b/src/game/server/entities/laser.hpp
@@ -0,0 +1,31 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+
+#ifndef GAME_SERVER_ENTITY_LASER_H
+#define GAME_SERVER_ENTITY_LASER_H
+
+#include <game/server/entity.hpp>
+
+class CHARACTER;
+
+class LASER : public ENTITY
+{
+	vec2 from;
+	vec2 dir;
+	float energy;
+	int bounces;
+	int eval_tick;
+	CHARACTER *owner;
+	
+	bool hit_character(vec2 from, vec2 to);
+	void do_bounce();
+	
+public:
+	
+	LASER(vec2 pos, vec2 direction, float start_energy, CHARACTER *owner);
+	
+	virtual void reset();
+	virtual void tick();
+	virtual void snap(int snapping_client);
+};
+
+#endif
diff --git a/src/game/server/gs_ent_pickup.cpp b/src/game/server/entities/pickup.cpp
index 304596d0..a4a3a2c9 100644
--- a/src/game/server/gs_ent_pickup.cpp
+++ b/src/game/server/entities/pickup.cpp
@@ -1,8 +1,10 @@
 #include <engine/e_server_interface.h>
-#include "gs_common.hpp"
+#include <game/generated/g_protocol.hpp>
+#include <game/server/gs_common.hpp>
+#include "pickup.hpp"
 
 //////////////////////////////////////////////////
-// powerup
+// pickup
 //////////////////////////////////////////////////
 PICKUP::PICKUP(int _type, int _subtype)
 : ENTITY(NETOBJTYPE_PICKUP)
diff --git a/src/game/server/entities/pickup.hpp b/src/game/server/entities/pickup.hpp
new file mode 100644
index 00000000..cd480d92
--- /dev/null
+++ b/src/game/server/entities/pickup.hpp
@@ -0,0 +1,24 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+
+#ifndef GAME_SERVER_ENTITY_PICKUP_H
+#define GAME_SERVER_ENTITY_PICKUP_H
+
+#include <game/server/entity.hpp>
+
+// TODO: move to seperate file
+class PICKUP : public ENTITY
+{
+public:
+	static const int phys_size = 14;
+	
+	int type;
+	int subtype; // weapon type for instance?
+	int spawntick;
+	PICKUP(int _type, int _subtype = 0);
+	
+	virtual void reset();
+	virtual void tick();
+	virtual void snap(int snapping_client);
+};
+
+#endif
diff --git a/src/game/server/entities/projectile.cpp b/src/game/server/entities/projectile.cpp
new file mode 100644
index 00000000..d258e69e
--- /dev/null
+++ b/src/game/server/entities/projectile.cpp
@@ -0,0 +1,108 @@
+#include <engine/e_server_interface.h>
+#include <game/generated/g_protocol.hpp>
+#include <game/server/gs_common.hpp>
+#include "projectile.hpp"
+
+
+//////////////////////////////////////////////////
+// projectile
+//////////////////////////////////////////////////
+PROJECTILE::PROJECTILE(int type, int owner, vec2 pos, vec2 dir, int span, ENTITY* powner,
+	int damage, int flags, float force, int sound_impact, int weapon)
+: ENTITY(NETOBJTYPE_PROJECTILE)
+{
+	this->type = type;
+	this->pos = pos;
+	this->direction = dir;
+	this->lifespan = span;
+	this->owner = owner;
+	this->powner = powner;
+	this->flags = flags;
+	this->force = force;
+	this->damage = damage;
+	this->sound_impact = sound_impact;
+	this->weapon = weapon;
+	this->bounce = 0;
+	this->start_tick = server_tick();
+	game.world.insert_entity(this);
+}
+
+void PROJECTILE::reset()
+{
+	game.world.destroy_entity(this);
+}
+
+vec2 PROJECTILE::get_pos(float time)
+{
+	float curvature = 0;
+	float speed = 0;
+	if(type == WEAPON_GRENADE)
+	{
+		curvature = tuning.grenade_curvature;
+		speed = tuning.grenade_speed;
+	}
+	else if(type == WEAPON_SHOTGUN)
+	{
+		curvature = tuning.shotgun_curvature;
+		speed = tuning.shotgun_speed;
+	}
+	else if(type == WEAPON_GUN)
+	{
+		curvature = tuning.gun_curvature;
+		speed = tuning.gun_speed;
+	}
+	
+	return calc_pos(pos, direction, curvature, speed, time);
+}
+
+
+void PROJECTILE::tick()
+{
+	
+	float pt = (server_tick()-start_tick-1)/(float)server_tickspeed();
+	float ct = (server_tick()-start_tick)/(float)server_tickspeed();
+	vec2 prevpos = get_pos(pt);
+	vec2 curpos = get_pos(ct);
+
+	lifespan--;
+	
+	int collide = col_intersect_line(prevpos, curpos, &curpos);
+	//int collide = col_check_point((int)curpos.x, (int)curpos.y);
+	
+	CHARACTER *targetchr = game.world.intersect_character(prevpos, curpos, 6.0f, curpos, powner);
+	if(targetchr || collide || lifespan < 0)
+	{
+		if(lifespan >= 0 || weapon == WEAPON_GRENADE)
+			game.create_sound(curpos, sound_impact);
+
+		if(flags & PROJECTILE_FLAGS_EXPLODE)
+			game.create_explosion(curpos, owner, weapon, false);
+		else if(targetchr)
+		{
+			targetchr->take_damage(direction * max(0.001f, force), damage, owner, weapon);
+		}
+
+		game.world.destroy_entity(this);
+	}
+}
+
+void PROJECTILE::fill_info(NETOBJ_PROJECTILE *proj)
+{
+	proj->x = (int)pos.x;
+	proj->y = (int)pos.y;
+	proj->vx = (int)(direction.x*100.0f);
+	proj->vy = (int)(direction.y*100.0f);
+	proj->start_tick = start_tick;
+	proj->type = type;
+}
+
+void PROJECTILE::snap(int snapping_client)
+{
+	float ct = (server_tick()-start_tick)/(float)server_tickspeed();
+	
+	if(distance(game.players[snapping_client].view_pos, get_pos(ct)) > 1000.0f)
+		return;
+
+	NETOBJ_PROJECTILE *proj = (NETOBJ_PROJECTILE *)snap_new_item(NETOBJTYPE_PROJECTILE, id, sizeof(NETOBJ_PROJECTILE));
+	fill_info(proj);
+}
diff --git a/src/game/server/entities/projectile.hpp b/src/game/server/entities/projectile.hpp
new file mode 100644
index 00000000..c1370af1
--- /dev/null
+++ b/src/game/server/entities/projectile.hpp
@@ -0,0 +1,38 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+
+#ifndef GAME_SERVER_ENTITY_PROJECTILE_H
+#define GAME_SERVER_ENTITY_PROJECTILE_H
+
+class PROJECTILE : public ENTITY
+{
+public:
+	enum
+	{
+		PROJECTILE_FLAGS_EXPLODE = 1 << 0,
+	};
+	
+	vec2 direction;
+	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;
+	int start_tick;
+	
+	PROJECTILE(int type, int owner, vec2 pos, vec2 vel, int span, ENTITY* powner,
+		int damage, int flags, float force, int sound_impact, int weapon);
+
+	vec2 get_pos(float time);
+	void fill_info(NETOBJ_PROJECTILE *proj);
+
+	virtual void reset();
+	virtual void tick();
+	virtual void snap(int snapping_client);
+};
+
+#endif
diff --git a/src/game/server/entity.hpp b/src/game/server/entity.hpp
new file mode 100644
index 00000000..d3ae3a1c
--- /dev/null
+++ b/src/game/server/entity.hpp
@@ -0,0 +1,83 @@
+#ifndef GAME_SERVER_ENTITY_H
+#define GAME_SERVER_ENTITY_H
+
+#include <base/vmath.hpp>
+
+/*
+	Class: Entity
+		Basic entity class.
+*/
+class ENTITY
+{
+private:
+	friend class GAMEWORLD; // thy these?
+	ENTITY *prev_entity;
+	ENTITY *next_entity;
+
+	ENTITY *prev_type_entity;
+	ENTITY *next_type_entity;
+protected:
+	bool marked_for_destroy;
+	int id;
+	int objtype;
+public:
+	
+	ENTITY(int objtype);
+	virtual ~ENTITY();
+	
+	ENTITY *typenext() { return next_type_entity; }
+	ENTITY *typeprev() { return prev_type_entity; }
+
+	/*
+		Function: destroy
+		Destorys the entity.
+	*/
+	virtual void destroy() { delete this; }
+		
+	/*
+		Function: reset
+		Called when the game resets the map. Puts the entity
+		back to it's starting state or perhaps destroys it.
+	*/
+	virtual void reset() {}
+	
+	/*
+		Function: tick
+		Called progress the entity to the next tick. Updates
+		and moves the entity to it's new state and position.
+	*/
+	virtual void tick() {}
+
+	/*
+		Function: tick_defered
+		Called after all entities tick() function has been called.
+	*/
+	virtual void tick_defered() {}
+	
+	/*
+		Function: snap
+		Called when a new snapshot is being generated for a specific
+		client.
+		
+		Arguments:
+			snapping_client - ID of the client which snapshot is
+				being generated. Could be -1 to create a complete
+				snapshot of everything in the game for demo
+				recording.
+	*/
+	virtual void snap(int snapping_client) {}
+
+	/*
+		Variable: proximity_radius
+		Contains the physical size of the entity.
+	*/
+	float proximity_radius;
+	
+	/*
+		Variable: pos
+		Contains the current posititon of the entity.
+	*/
+	vec2 pos;
+};
+
+#endif
diff --git a/src/game/server/eventhandler.hpp b/src/game/server/eventhandler.hpp
new file mode 100644
index 00000000..4d513154
--- /dev/null
+++ b/src/game/server/eventhandler.hpp
@@ -0,0 +1,25 @@
+#ifndef GAME_SERVER_EVENTHANDLER_H
+#define GAME_SERVER_EVENTHANDLER_H
+
+//
+class EVENTHANDLER
+{
+	static const int MAX_EVENTS = 128;
+	static const int MAX_DATASIZE = 128*64;
+
+	int types[MAX_EVENTS];  // TODO: remove some of these arrays
+	int offsets[MAX_EVENTS];
+	int sizes[MAX_EVENTS];
+	int client_masks[MAX_EVENTS];
+	char data[MAX_DATASIZE];
+	
+	int current_offset;
+	int num_events;
+public:
+	EVENTHANDLER();
+	void *create(int type, int size, int mask = -1);
+	void clear();
+	void snap(int snapping_client);
+};
+
+#endif
diff --git a/src/game/server/gamecontext.hpp b/src/game/server/gamecontext.hpp
new file mode 100644
index 00000000..c4035b3f
--- /dev/null
+++ b/src/game/server/gamecontext.hpp
@@ -0,0 +1,38 @@
+
+#include "eventhandler.hpp"
+#include "gamecontroller.hpp"
+#include "gameworld.hpp"
+
+class GAMECONTEXT
+{
+public:
+	GAMECONTEXT();
+	void clear();
+	
+	EVENTHANDLER events;
+	PLAYER players[MAX_CLIENTS];
+	
+	GAMECONTROLLER *controller;
+	GAMEWORLD world;
+
+	void tick();
+	void snap(int client_id);
+
+	// helper functions
+	void create_damageind(vec2 p, float angle_mod, int amount);
+	void create_explosion(vec2 p, int owner, int weapon, bool bnodamage);
+	void create_smoke(vec2 p);
+	void create_playerspawn(vec2 p);
+	void create_death(vec2 p, int who);
+	void create_sound(vec2 pos, int sound, int mask=-1);
+	void create_sound_global(int sound, int target=-1);	
+
+	// network
+	void send_chat(int cid, int team, const char *text);
+	void send_emoticon(int cid, int emoticon);
+	void send_weapon_pickup(int cid, int weapon);
+	void send_broadcast(const char *text, int cid);
+	void send_info(int who, int to_who);
+};
+
+extern GAMECONTEXT game;
diff --git a/src/game/server/gs_game.cpp b/src/game/server/gamecontroller.cpp
index 685d61ad..aeab559c 100644
--- a/src/game/server/gs_game.cpp
+++ b/src/game/server/gamecontroller.cpp
@@ -5,6 +5,8 @@
 #include <game/g_mapitems.hpp>
 #include "gs_common.hpp"
 
+#include "entities/pickup.hpp"
+
 GAMECONTROLLER::GAMECONTROLLER()
 {
 	// select gametype
diff --git a/src/game/server/gamecontroller.hpp b/src/game/server/gamecontroller.hpp
new file mode 100644
index 00000000..a3cfe9ba
--- /dev/null
+++ b/src/game/server/gamecontroller.hpp
@@ -0,0 +1,97 @@
+#ifndef GAME_SERVER_GAMECONTROLLER_H
+#define GAME_SERVER_GAMECONTROLLER_H
+
+#include <base/vmath.hpp>
+
+/*
+	Class: Game Controller
+		Controls the main game logic. Keeping track of team and player score,
+		winning conditions and specific game logic.
+*/
+class GAMECONTROLLER
+{
+protected:
+	void cyclemap();
+	void resetgame();
+	
+	int round_start_tick;
+	int game_over_tick;
+	int sudden_death;
+	
+	int teamscore[2];
+	
+	int warmup;
+	int round_count;
+	
+	bool is_teamplay;
+	
+public:
+	int gametype;
+	GAMECONTROLLER();
+
+	void do_team_score_wincheck();
+	void do_player_score_wincheck();
+	
+	void do_warmup(int seconds);
+	
+	void startround();
+	void endround();
+	
+	bool is_friendly_fire(int cid1, int cid2);
+
+	/*
+	
+	*/	
+	virtual void tick();
+	
+	virtual void snap(int snapping_client);
+	
+	/*
+		Function: on_entity
+			Called when the map is loaded to process an entity
+			in the map.
+			
+		Arguments:
+			index - Entity index.
+			pos - Where the entity is located in the world.
+			
+		Returns:
+			bool?
+	*/
+	virtual bool on_entity(int index, vec2 pos);
+	
+	/*
+		Function: on_character_spawn
+			Called when a character spawns into the game world.
+			
+		Arguments:
+			chr - The character that was spawned.
+	*/
+	virtual void on_character_spawn(class CHARACTER *chr) {}
+	
+	/*
+		Function: on_character_death
+			Called when a character in the world dies.
+			
+		Arguments:
+			victim - The character that died.
+			killer - The player that killed it.
+			weapon - What weapon that killed it. Can be -1 for undefined
+				weapon when switching team or player suicides.
+	*/
+	virtual int on_character_death(class CHARACTER *victim, class PLAYER *killer, int weapon);
+
+	virtual void on_player_info_change(class PLAYER *p);
+
+	/*
+	
+	*/	
+	virtual const char *get_team_name(int team);
+	virtual int get_auto_team(int notthisid);
+	virtual bool can_join_team(int team, int notthisid);
+	int clampteam(int team);
+
+	virtual void post_reset();
+};
+
+#endif
diff --git a/src/game/server/gs_game_ctf.cpp b/src/game/server/gamemodes/ctf.cpp
index 27da121a..4733ae82 100644
--- a/src/game/server/gs_game_ctf.cpp
+++ b/src/game/server/gamemodes/ctf.cpp
@@ -1,8 +1,10 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 #include <engine/e_server_interface.h>
 #include <game/g_mapitems.hpp>
-#include "gs_common.hpp"
-#include "gs_game_ctf.hpp"
+#include <game/server/entities/character.hpp>
+#include <game/server/player.hpp>
+#include <game/server/gamecontext.hpp>
+#include "ctf.hpp"
 
 GAMECONTROLLER_CTF::GAMECONTROLLER_CTF()
 {
diff --git a/src/game/server/gs_game_ctf.hpp b/src/game/server/gamemodes/ctf.hpp
index bf6282e7..636f9f38 100644
--- a/src/game/server/gs_game_ctf.hpp
+++ b/src/game/server/gamemodes/ctf.hpp
@@ -1,6 +1,8 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 
-// game object
+#include <game/server/gamecontroller.hpp>
+#include <game/server/entity.hpp>
+
 class GAMECONTROLLER_CTF : public GAMECONTROLLER
 {
 public:
diff --git a/src/game/server/gs_game_dm.cpp b/src/game/server/gamemodes/dm.cpp
index 264063bf..b38d18f6 100644
--- a/src/game/server/gs_game_dm.cpp
+++ b/src/game/server/gamemodes/dm.cpp
@@ -1,7 +1,5 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
-#include <engine/e_config.h>
-#include "gs_common.hpp"
-#include "gs_game_dm.hpp"
+#include "dm.hpp"
 
 void GAMECONTROLLER_DM::tick()
 {
diff --git a/src/game/server/gs_game_dm.hpp b/src/game/server/gamemodes/dm.hpp
index 99ceaec1..f57fe06d 100644
--- a/src/game/server/gs_game_dm.hpp
+++ b/src/game/server/gamemodes/dm.hpp
@@ -1,5 +1,7 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
-// game object
+
+#include <game/server/gamecontroller.hpp>
+
 class GAMECONTROLLER_DM : public GAMECONTROLLER
 {
 public:
diff --git a/src/game/server/gs_game_tdm.cpp b/src/game/server/gamemodes/tdm.cpp
index d865a65a..26441c9f 100644
--- a/src/game/server/gs_game_tdm.cpp
+++ b/src/game/server/gamemodes/tdm.cpp
@@ -1,7 +1,8 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
-#include <engine/e_config.h>
-#include "gs_common.hpp"
-#include "gs_game_tdm.hpp"
+#include <engine/e_server_interface.h>
+#include <game/server/entities/character.hpp>
+#include <game/server/player.hpp>
+#include "tdm.hpp"
 
 GAMECONTROLLER_TDM::GAMECONTROLLER_TDM()
 {
diff --git a/src/game/server/gs_game_tdm.hpp b/src/game/server/gamemodes/tdm.hpp
index bb35260c..51c47ca5 100644
--- a/src/game/server/gs_game_tdm.hpp
+++ b/src/game/server/gamemodes/tdm.hpp
@@ -1,5 +1,7 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
-// game object
+
+#include <game/server/gamecontroller.hpp>
+
 class GAMECONTROLLER_TDM : public GAMECONTROLLER
 {
 public:
diff --git a/src/game/server/gameworld.hpp b/src/game/server/gameworld.hpp
new file mode 100644
index 00000000..76b39d23
--- /dev/null
+++ b/src/game/server/gameworld.hpp
@@ -0,0 +1,126 @@
+
+class CHARACTER;
+
+/*
+	Class: Game World
+		Tracks all entities in the game. Propagates tick and
+		snap calls to all entities.
+*/
+class GAMEWORLD
+{
+	void reset();
+	void remove_entities();
+
+	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];
+
+public:
+	bool reset_requested;
+	bool paused;
+	WORLD_CORE core;
+	
+	GAMEWORLD();
+	~GAMEWORLD();
+	
+	ENTITY *find_first() { return first_entity; }
+	ENTITY *find_first(int type);
+	
+	/*
+		Function: find_entities
+			Finds entities close to a position and returns them in a list.
+			
+		Arguments:
+			pos - Position.
+			radius - How close the entities have to be.
+			ents - Pointer to a list that should be filled with the pointers
+				to the entities.
+			max - Number of entities that fits into the ents array.
+			type - Type of the entities to find. -1 for all types.
+			
+		Returns:
+			Number of entities found and added to the ents array.
+	*/
+	int find_entities(vec2 pos, float radius, ENTITY **ents, int max, int type = -1);
+	
+	/*
+		Function: interserct_character
+			Finds the closest character that intersects the line.
+			
+		Arguments:
+			pos0 - Start position
+			pos2 - End position
+			radius - How for from the line the character is allowed to be.
+			new_pos - Intersection position
+			notthis - Entity to ignore intersecting with
+			
+		Returns:
+			Returns a pointer to the closest hit or NULL of there is no intersection.
+	*/
+	class CHARACTER *intersect_character(vec2 pos0, vec2 pos1, float radius, vec2 &new_pos, class ENTITY *notthis = 0);
+	
+	/*
+		Function: closest_character
+			Finds the closest character to a specific point.
+			
+		Arguments:
+			pos - The center position.
+			radius - How far off the character is allowed to be
+			notthis - Entity to ignore
+			
+		Returns:
+			Returns a pointer to the closest character or NULL if no character is close enough.
+	*/
+	class CHARACTER *closest_character(vec2 pos, float radius, ENTITY *notthis);
+
+	/*
+		Function: insert_entity
+			Adds an entity to the world.
+			
+		Arguments:
+			entity - Entity to add
+	*/
+	void insert_entity(ENTITY *entity);
+
+	/*
+		Function: remove_entity
+			Removes an entity from the world.
+			
+		Arguments:
+			entity - Entity to remove
+	*/
+	void remove_entity(ENTITY *entity);
+
+	/*
+		Function: destroy_entity
+			Destroys an entity in the world.
+			
+		Arguments:
+			entity - Entity to destroy
+	*/
+	void destroy_entity(ENTITY *entity);
+	
+	/*
+		Function: snap
+			Calls snap on all the entities in the world to create
+			the snapshot.
+			
+		Arguments:
+			snapping_client - ID of the client which snapshot
+			is being created.
+	*/
+	void snap(int snapping_client);
+	
+	/*
+		Function: tick
+			Calls tick on all the entities in the world to progress
+			the world to the next tick.
+		
+	*/
+	void tick();
+};
diff --git a/src/game/server/gs_common.hpp b/src/game/server/gs_common.hpp
index ce03d728..37bb2638 100644
--- a/src/game/server/gs_common.hpp
+++ b/src/game/server/gs_common.hpp
@@ -32,590 +32,15 @@ inline bool cmask_is_set(int mask, int cid) { return (mask&cmask_one(cid)) != 0;
 */
 
 
+#include "eventhandler.hpp"
 
-//
-class EVENT_HANDLER
-{
-	static const int MAX_EVENTS = 128;
-	static const int MAX_DATASIZE = 128*64;
-
-	int types[MAX_EVENTS];  // TODO: remove some of these arrays
-	int offsets[MAX_EVENTS];
-	int sizes[MAX_EVENTS];
-	int client_masks[MAX_EVENTS];
-	char data[MAX_DATASIZE];
-	
-	int current_offset;
-	int num_events;
-public:
-	EVENT_HANDLER();
-	void *create(int type, int size, int mask = -1);
-	void clear();
-	void snap(int snapping_client);
-};
-
-/*
-	Class: Entity
-		Basic entity class.
-*/
-class ENTITY
-{
-private:
-	friend class GAMEWORLD; // thy these?
-	ENTITY *prev_entity;
-	ENTITY *next_entity;
-
-	ENTITY *prev_type_entity;
-	ENTITY *next_type_entity;
-protected:
-	bool marked_for_destroy;
-	int id;
-	int objtype;
-public:
-	
-	ENTITY(int objtype);
-	virtual ~ENTITY();
-	
-	ENTITY *typenext() { return next_type_entity; }
-	ENTITY *typeprev() { return prev_type_entity; }
-
-	/*
-		Function: destroy
-		Destorys the entity.
-	*/
-	virtual void destroy() { delete this; }
-		
-	/*
-		Function: reset
-		Called when the game resets the map. Puts the entity
-		back to it's starting state or perhaps destroys it.
-	*/
-	virtual void reset() {}
-	
-	/*
-		Function: tick
-		Called progress the entity to the next tick. Updates
-		and moves the entity to it's new state and position.
-	*/
-	virtual void tick() {}
-
-	/*
-		Function: tick_defered
-		Called after all entities tick() function has been called.
-	*/
-	virtual void tick_defered() {}
-	
-	/*
-		Function: snap
-		Called when a new snapshot is being generated for a specific
-		client.
-		
-		Arguments:
-			snapping_client - ID of the client which snapshot is
-				being generated. Could be -1 to create a complete
-				snapshot of everything in the game for demo
-				recording.
-	*/
-	virtual void snap(int snapping_client) {}
-
-	/*
-		Variable: proximity_radius
-		Contains the physical size of the entity.
-	*/
-	float proximity_radius;
-	
-	/*
-		Variable: pos
-		Contains the current posititon of the entity.
-	*/
-	vec2 pos;
-};
+#include "entity.hpp"
 
 
-/*
-	Class: Game World
-		Tracks all entities in the game. Propagates tick and
-		snap calls to all entities.
-*/
-class GAMEWORLD
-{
-	void reset();
-	void remove_entities();
-
-	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];
-
-public:
-	bool reset_requested;
-	bool paused;
-	WORLD_CORE core;
-	
-	GAMEWORLD();
-	~GAMEWORLD();
-	
-	ENTITY *find_first() { return first_entity; }
-	ENTITY *find_first(int type);
-	
-	/*
-		Function: find_entities
-			Finds entities close to a position and returns them in a list.
-			
-		Arguments:
-			pos - Position.
-			radius - How close the entities have to be.
-			ents - Pointer to a list that should be filled with the pointers
-				to the entities.
-			max - Number of entities that fits into the ents array.
-			type - Type of the entities to find. -1 for all types.
-			
-		Returns:
-			Number of entities found and added to the ents array.
-	*/
-	int find_entities(vec2 pos, float radius, ENTITY **ents, int max, int type = -1);
-	
-	/*
-		Function: interserct_character
-			Finds the closest character that intersects the line.
-			
-		Arguments:
-			pos0 - Start position
-			pos2 - End position
-			radius - How for from the line the character is allowed to be.
-			new_pos - Intersection position
-			notthis - Entity to ignore intersecting with
-			
-		Returns:
-			Returns a pointer to the closest hit or NULL of there is no intersection.
-	*/
-	class CHARACTER *intersect_character(vec2 pos0, vec2 pos1, float radius, vec2 &new_pos, class ENTITY *notthis = 0);
-	
-	/*
-		Function: closest_character
-			Finds the closest character to a specific point.
-			
-		Arguments:
-			pos - The center position.
-			radius - How far off the character is allowed to be
-			notthis - Entity to ignore
-			
-		Returns:
-			Returns a pointer to the closest character or NULL if no character is close enough.
-	*/
-	class CHARACTER *closest_character(vec2 pos, float radius, ENTITY *notthis);
-
-	/*
-		Function: insert_entity
-			Adds an entity to the world.
-			
-		Arguments:
-			entity - Entity to add
-	*/
-	void insert_entity(ENTITY *entity);
-
-	/*
-		Function: remove_entity
-			Removes an entity from the world.
-			
-		Arguments:
-			entity - Entity to remove
-	*/
-	void remove_entity(ENTITY *entity);
-
-	/*
-		Function: destroy_entity
-			Destroys an entity in the world.
-			
-		Arguments:
-			entity - Entity to destroy
-	*/
-	void destroy_entity(ENTITY *entity);
-	
-	/*
-		Function: snap
-			Calls snap on all the entities in the world to create
-			the snapshot.
-			
-		Arguments:
-			snapping_client - ID of the client which snapshot
-			is being created.
-	*/
-	void snap(int snapping_client);
-	
-	/*
-		Function: tick
-			Calls tick on all the entities in the world to progress
-			the world to the next tick.
-		
-	*/
-	void tick();
-};
-
-/*
-	Class: Game Controller
-		Controls the main game logic. Keeping track of team and player score,
-		winning conditions and specific game logic.
-*/
-class GAMECONTROLLER
-{
-protected:
-	void cyclemap();
-	void resetgame();
-	
-	int round_start_tick;
-	int game_over_tick;
-	int sudden_death;
-	
-	int teamscore[2];
-	
-	int warmup;
-	int round_count;
-	
-	bool is_teamplay;
-	
-public:
-	int gametype;
-	GAMECONTROLLER();
-
-	void do_team_score_wincheck();
-	void do_player_score_wincheck();
-	
-	void do_warmup(int seconds);
-	
-	void startround();
-	void endround();
-	
-	bool is_friendly_fire(int cid1, int cid2);
-
-	/*
-	
-	*/	
-	virtual void tick();
-	
-	virtual void snap(int snapping_client);
-	
-	/*
-		Function: on_entity
-			Called when the map is loaded to process an entity
-			in the map.
-			
-		Arguments:
-			index - Entity index.
-			pos - Where the entity is located in the world.
-			
-		Returns:
-			bool?
-	*/
-	virtual bool on_entity(int index, vec2 pos);
-	
-	/*
-		Function: on_character_spawn
-			Called when a character spawns into the game world.
-			
-		Arguments:
-			chr - The character that was spawned.
-	*/
-	virtual void on_character_spawn(class CHARACTER *chr) {}
-	
-	/*
-		Function: on_character_death
-			Called when a character in the world dies.
-			
-		Arguments:
-			victim - The character that died.
-			killer - The player that killed it.
-			weapon - What weapon that killed it. Can be -1 for undefined
-				weapon when switching team or player suicides.
-	*/
-	virtual int on_character_death(class CHARACTER *victim, class PLAYER *killer, int weapon);
-
-	virtual void on_player_info_change(class PLAYER *p);
-
-	/*
-	
-	*/	
-	virtual const char *get_team_name(int team);
-	virtual int get_auto_team(int notthisid);
-	virtual bool can_join_team(int team, int notthisid);
-	int clampteam(int team);
-
-	virtual void post_reset();
-};
-
-// TODO: move to seperate file
-class PICKUP : public ENTITY
-{
-public:
-	static const int phys_size = 14;
-	
-	int type;
-	int subtype; // weapon type for instance?
-	int spawntick;
-	PICKUP(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,
-	};
-	
-	vec2 direction;
-	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;
-	int start_tick;
-	
-	PROJECTILE(int type, int owner, vec2 pos, vec2 vel, int span, ENTITY* powner,
-		int damage, int flags, float force, int sound_impact, int weapon);
-
-	vec2 get_pos(float time);
-	void fill_info(NETOBJ_PROJECTILE *proj);
-
-	virtual void reset();
-	virtual void tick();
-	virtual void snap(int snapping_client);
-};
-
-class LASER : public ENTITY
-{
-	vec2 from;
-	vec2 dir;
-	float energy;
-	int bounces;
-	int eval_tick;
-	CHARACTER *owner;
-	
-	bool hit_character(vec2 from, vec2 to);
-	void do_bounce();
-	
-public:
-	
-	LASER(vec2 pos, vec2 direction, float start_energy, CHARACTER *owner);
-	
-	virtual void reset();
-	virtual void tick();
-	virtual void snap(int snapping_client);
-};
-
-
-class CHARACTER : public ENTITY
-{
-public:
-	// player controlling this character
-	class PLAYER *player;
-	
-	bool alive;
-
-	// 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 queued_weapon;
-	
-	int reload_timer;
-	int attack_tick;
-	
-	int damage_taken;
-
-	int emote_type;
-	int emote_stop;
-
-	// TODO: clean this up
-	char skin_name[64];
-	int use_custom_color;
-	int color_body;
-	int color_feet;
-	
-	int last_action; // last tick that the player took any action ie some input
-
-	// these are non-heldback inputs
-	NETOBJ_PLAYER_INPUT latest_previnput;
-	NETOBJ_PLAYER_INPUT latest_input;
-
-	// input	
-	NETOBJ_PLAYER_INPUT previnput;
-	NETOBJ_PLAYER_INPUT input;
-	int num_inputs;
-	int jumped;
-	
-	int damage_taken_tick;
-
-	int health;
-	int armor;
-
-	// ninja
-	struct
-	{
-		vec2 activationdir;
-		int activationtick;
-		int currentcooldown;
-		int currentmovetime;
-	} ninja;
-
-	//
-	//int score;
-	int team;
-	int player_state; // if the client is chatting, accessing a menu or so
-
-	// the player core for the physics	
-	CHARACTER_CORE core;
-
-	//
-	CHARACTER();
-	
-	virtual void reset();
-	virtual void destroy();
-		
-	bool is_grounded();
-	
-	void set_weapon(int w);
-	
-	void handle_weaponswitch();
-	void do_weaponswitch();
-	
-	int handle_weapons();
-	int handle_ninja();
-
-	void on_predicted_input(NETOBJ_PLAYER_INPUT *new_input);
-	void on_direct_input(NETOBJ_PLAYER_INPUT *new_input);
-	void fire_weapon();
-
-	void die(int killer, int weapon);
-
-	bool take_damage(vec2 force, int dmg, int from, int weapon);	
-
-	
-	bool spawn(PLAYER *player, vec2 pos, int team);
-	//bool init_tryspawn(int team);
-	bool remove();
-
-	static const int phys_size = 28;
-
-	virtual void tick();
-	virtual void tick_defered();
-	virtual void snap(int snaping_client);
-	
-	bool increase_health(int amount);
-	bool increase_armor(int amount);
-};
-
-// player object
-class PLAYER
-{
-public:
-	PLAYER();
-
-	// TODO: clean this up
-	char skin_name[64];
-	int use_custom_color;
-	int color_body;
-	int color_feet;
-	
-	//
-	bool spawning;
-	int client_id;
-	int team;
-	int score;
-
-	//
-	int64 last_chat;
-
-	// network latency calculations	
-	struct
-	{
-		int accum;
-		int accum_min;
-		int accum_max;
-		int avg;
-		int min;
-		int max;	
-	} latency;
-	
-	CHARACTER character;
-	
-	// this is used for snapping so we know how we can clip the view for the player
-	vec2 view_pos;
-
-	void init(int client_id);
-	
-	CHARACTER *get_character();
-	
-	void kill_character();
-
-	void try_respawn();
-	void respawn();
-	void set_team(int team);
-	
-	void tick();
-	void snap(int snaping_client);
-
-	void on_direct_input(NETOBJ_PLAYER_INPUT *new_input);
-	void on_predicted_input(NETOBJ_PLAYER_INPUT *new_input);
-	void on_disconnect();
-};
-
-class GAMECONTEXT
-{
-public:
-	GAMECONTEXT();
-	void clear();
-	
-	EVENT_HANDLER events;
-	PLAYER players[MAX_CLIENTS];
-	
-	GAMECONTROLLER *controller;
-	GAMEWORLD world;
-
-	void tick();
-	void snap(int client_id);
-
-	// helper functions
-	void create_damageind(vec2 p, float angle_mod, int amount);
-	void create_explosion(vec2 p, int owner, int weapon, bool bnodamage);
-	void create_smoke(vec2 p);
-	void create_playerspawn(vec2 p);
-	void create_death(vec2 p, int who);
-	void create_sound(vec2 pos, int sound, int mask=-1);
-	void create_sound_global(int sound, int target=-1);	
-
-	// network
-	void send_chat(int cid, int team, const char *text);
-	void send_emoticon(int cid, int emoticon);
-	void send_weapon_pickup(int cid, int weapon);
-	void send_broadcast(const char *text, int cid);
-	void send_info(int who, int to_who);
-};
-
-extern GAMECONTEXT game;
+#include "gamecontroller.hpp"
+#include "entities/character.hpp"
+#include "player.hpp"
+#include "gamecontext.hpp"
 
 enum
 {
diff --git a/src/game/server/gs_server.cpp b/src/game/server/gs_server.cpp
index 5af6758b..1d981ea5 100644
--- a/src/game/server/gs_server.cpp
+++ b/src/game/server/gs_server.cpp
@@ -11,9 +11,10 @@
 #include <game/g_collision.hpp>
 #include <game/g_layers.hpp>
 #include "gs_common.hpp"
-#include "gs_game_ctf.hpp"
-#include "gs_game_tdm.hpp"
-#include "gs_game_dm.hpp"
+
+#include "gamemodes/dm.hpp"
+#include "gamemodes/tdm.hpp"
+#include "gamemodes/ctf.hpp"
 
 TUNING_PARAMS tuning;
 GAMECONTEXT game;
@@ -106,12 +107,12 @@ void send_tuning_params(int cid)
 //////////////////////////////////////////////////
 // Event handler
 //////////////////////////////////////////////////
-EVENT_HANDLER::EVENT_HANDLER()
+EVENTHANDLER::EVENTHANDLER()
 {
 	clear();
 }
 
-void *EVENT_HANDLER::create(int type, int size, int mask)
+void *EVENTHANDLER::create(int type, int size, int mask)
 {
 	if(num_events == MAX_EVENTS)
 		return 0;
@@ -128,13 +129,13 @@ void *EVENT_HANDLER::create(int type, int size, int mask)
 	return p;
 }
 
-void EVENT_HANDLER::clear()
+void EVENTHANDLER::clear()
 {
 	num_events = 0;
 	current_offset = 0;
 }
 
-void EVENT_HANDLER::snap(int snapping_client)
+void EVENTHANDLER::snap(int snapping_client)
 {
 	for(int i = 0; i < num_events; i++)
 	{
@@ -327,217 +328,6 @@ void GAMEWORLD::tick()
 	remove_entities();
 }
 
-//////////////////////////////////////////////////
-// projectile
-//////////////////////////////////////////////////
-PROJECTILE::PROJECTILE(int type, int owner, vec2 pos, vec2 dir, int span, ENTITY* powner,
-	int damage, int flags, float force, int sound_impact, int weapon)
-: ENTITY(NETOBJTYPE_PROJECTILE)
-{
-	this->type = type;
-	this->pos = pos;
-	this->direction = dir;
-	this->lifespan = span;
-	this->owner = owner;
-	this->powner = powner;
-	this->flags = flags;
-	this->force = force;
-	this->damage = damage;
-	this->sound_impact = sound_impact;
-	this->weapon = weapon;
-	this->bounce = 0;
-	this->start_tick = server_tick();
-	game.world.insert_entity(this);
-}
-
-void PROJECTILE::reset()
-{
-	game.world.destroy_entity(this);
-}
-
-vec2 PROJECTILE::get_pos(float time)
-{
-	float curvature = 0;
-	float speed = 0;
-	if(type == WEAPON_GRENADE)
-	{
-		curvature = tuning.grenade_curvature;
-		speed = tuning.grenade_speed;
-	}
-	else if(type == WEAPON_SHOTGUN)
-	{
-		curvature = tuning.shotgun_curvature;
-		speed = tuning.shotgun_speed;
-	}
-	else if(type == WEAPON_GUN)
-	{
-		curvature = tuning.gun_curvature;
-		speed = tuning.gun_speed;
-	}
-	
-	return calc_pos(pos, direction, curvature, speed, time);
-}
-
-
-void PROJECTILE::tick()
-{
-	
-	float pt = (server_tick()-start_tick-1)/(float)server_tickspeed();
-	float ct = (server_tick()-start_tick)/(float)server_tickspeed();
-	vec2 prevpos = get_pos(pt);
-	vec2 curpos = get_pos(ct);
-
-	lifespan--;
-	
-	int collide = col_intersect_line(prevpos, curpos, &curpos);
-	//int collide = col_check_point((int)curpos.x, (int)curpos.y);
-	
-	CHARACTER *targetchr = game.world.intersect_character(prevpos, curpos, 6.0f, curpos, powner);
-	if(targetchr || collide || lifespan < 0)
-	{
-		if(lifespan >= 0 || weapon == WEAPON_GRENADE)
-			game.create_sound(curpos, sound_impact);
-
-		if(flags & PROJECTILE_FLAGS_EXPLODE)
-			game.create_explosion(curpos, owner, weapon, false);
-		else if(targetchr)
-		{
-			targetchr->take_damage(direction * max(0.001f, force), damage, owner, weapon);
-		}
-
-		game.world.destroy_entity(this);
-	}
-}
-
-void PROJECTILE::fill_info(NETOBJ_PROJECTILE *proj)
-{
-	proj->x = (int)pos.x;
-	proj->y = (int)pos.y;
-	proj->vx = (int)(direction.x*100.0f);
-	proj->vy = (int)(direction.y*100.0f);
-	proj->start_tick = start_tick;
-	proj->type = type;
-}
-
-void PROJECTILE::snap(int snapping_client)
-{
-	float ct = (server_tick()-start_tick)/(float)server_tickspeed();
-	
-	if(distance(game.players[snapping_client].view_pos, get_pos(ct)) > 1000.0f)
-		return;
-
-	NETOBJ_PROJECTILE *proj = (NETOBJ_PROJECTILE *)snap_new_item(NETOBJTYPE_PROJECTILE, id, sizeof(NETOBJ_PROJECTILE));
-	fill_info(proj);
-}
-
-
-//////////////////////////////////////////////////
-// laser
-//////////////////////////////////////////////////
-LASER::LASER(vec2 pos, vec2 direction, float start_energy, CHARACTER *owner)
-: ENTITY(NETOBJTYPE_LASER)
-{
-	this->pos = pos;
-	this->owner = owner;
-	energy = start_energy;
-	dir = direction;
-	bounces = 0;
-	do_bounce();
-	
-	game.world.insert_entity(this);
-}
-
-
-bool LASER::hit_character(vec2 from, vec2 to)
-{
-	vec2 at;
-	CHARACTER *hit = game.world.intersect_character(pos, to, 0.0f, at, owner);
-	if(!hit)
-		return false;
-
-	this->from = from;
-	pos = at;
-	energy = -1;		
-	hit->take_damage(vec2(0,0), tuning.laser_damage, owner->player->client_id, WEAPON_RIFLE);
-	return true;
-}
-
-void LASER::do_bounce()
-{
-	eval_tick = server_tick();
-	
-	if(energy < 0)
-	{
-		//dbg_msg("laser", "%d removed", server_tick());
-		game.world.destroy_entity(this);
-		return;
-	}
-	
-	vec2 to = pos + dir*energy;
-	
-	if(col_intersect_line(pos, to, &to))
-	{
-		if(!hit_character(pos, to))
-		{
-			// intersected
-			from = pos;
-			pos = to - dir*2;
-			vec2 temp_pos = pos;
-			vec2 temp_dir = dir*4.0f;
-			
-			move_point(&temp_pos, &temp_dir, 1.0f, 0);
-			pos = temp_pos;
-			dir = normalize(temp_dir);
-			
-			energy -= distance(from, pos) + tuning.laser_bounce_cost;
-			bounces++;
-			
-			if(bounces > tuning.laser_bounce_num)
-				energy = -1;
-				
-			game.create_sound(pos, SOUND_RIFLE_BOUNCE);
-		}
-	}
-	else
-	{
-		if(!hit_character(pos, to))
-		{
-			from = pos;
-			pos = to;
-			energy = -1;
-		}
-	}
-		
-	//dbg_msg("laser", "%d done %f %f %f %f", server_tick(), from.x, from.y, pos.x, pos.y);
-}
-	
-void LASER::reset()
-{
-	game.world.destroy_entity(this);
-}
-
-void LASER::tick()
-{
-	if(server_tick() > eval_tick+(server_tickspeed()*tuning.laser_bounce_delay)/1000.0f)
-	{
-		do_bounce();
-	}
-
-}
-
-void LASER::snap(int snapping_client)
-{
-	if(distance(game.players[snapping_client].view_pos, pos) > 1000.0f)
-		return;
-
-	NETOBJ_LASER *obj = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id, sizeof(NETOBJ_LASER));
-	obj->x = (int)pos.x;
-	obj->y = (int)pos.y;
-	obj->from_x = (int)from.x;
-	obj->from_y = (int)from.y;
-	obj->start_tick = eval_tick;
-}
-
 GAMECONTEXT::GAMECONTEXT()
 {
 	clear();
diff --git a/src/game/server/player.hpp b/src/game/server/player.hpp
new file mode 100644
index 00000000..c1866f85
--- /dev/null
+++ b/src/game/server/player.hpp
@@ -0,0 +1,55 @@
+
+// player object
+class PLAYER
+{
+public:
+	PLAYER();
+
+	// TODO: clean this up
+	char skin_name[64];
+	int use_custom_color;
+	int color_body;
+	int color_feet;
+	
+	//
+	bool spawning;
+	int client_id;
+	int team;
+	int score;
+
+	//
+	int64 last_chat;
+
+	// network latency calculations	
+	struct
+	{
+		int accum;
+		int accum_min;
+		int accum_max;
+		int avg;
+		int min;
+		int max;	
+	} latency;
+	
+	CHARACTER character;
+	
+	// this is used for snapping so we know how we can clip the view for the player
+	vec2 view_pos;
+
+	void init(int client_id);
+	
+	CHARACTER *get_character();
+	
+	void kill_character();
+
+	void try_respawn();
+	void respawn();
+	void set_team(int team);
+	
+	void tick();
+	void snap(int snaping_client);
+
+	void on_direct_input(NETOBJ_PLAYER_INPUT *new_input);
+	void on_predicted_input(NETOBJ_PLAYER_INPUT *new_input);
+	void on_disconnect();
+};