Index: src/game/collision.cpp
===================================================================
--- src/game/collision.cpp	(Revision 1952)
+++ src/game/collision.cpp	(Arbeitskopie)
@@ -24,17 +24,33 @@
 	
 	for(int i = 0; i < width*height; i++)
 	{
+		//int DOOR_BASE=ENTITY_OFFSET+17;
 		int index = tiles[i].index;
 		
+		//if(index >=DOOR_BASE && index < DOOR_BASE+16)
+		//	tiles[i].index |= COLFLAG_SOLID;
+		
 		if(index > 128)
 			continue;
 		
 		if(index == TILE_DEATH)
 			tiles[i].index = COLFLAG_DEATH;
-		else if(index == TILE_SOLID)
+		else if(index == TILE_SOLID/* || (index >=DOOR_BASE && index < DOOR_BASE+16)*/)
 			tiles[i].index = COLFLAG_SOLID;
 		else if(index == TILE_NOHOOK)
 			tiles[i].index = COLFLAG_SOLID|COLFLAG_NOHOOK;
+			
+		else if(index == TILE_WATER)
+			tiles[i].index = COLFLAG_WATER;
+		else if(index == TILE_WATER_UP)
+			tiles[i].index = COLFLAG_WATER_UP;
+		else if(index == TILE_WATER_DOWN)
+			tiles[i].index = COLFLAG_WATER_DOWN;
+		else if(index == TILE_WATER_LEFT)
+			tiles[i].index = COLFLAG_WATER_LEFT;
+		else if(index == TILE_WATER_RIGHT)
+			tiles[i].index = COLFLAG_WATER_RIGHT;
+			
 		else
 			tiles[i].index = 0;
 	}
@@ -55,10 +71,23 @@
 
 int col_is_solid(int x, int y)
 {
-	return col_get(x,y)&COLFLAG_SOLID;
+	return (col_get(x, y)&COLFLAG_SOLID);
 }
 
+int col_is_water(int x, int y)
+{
+	return (col_get(x,y)&COLFLAG_WATER) || (col_get(x,y)&COLFLAG_WATER_UP) || (col_get(x,y)&COLFLAG_WATER_DOWN) || (col_get(x,y)&COLFLAG_WATER_LEFT) || (col_get(x,y)&COLFLAG_WATER_RIGHT);
+}
 
+void col_set(int x, int y, int flag)
+{
+	int nx = clamp(x/32, 0, width-1);
+	int ny = clamp(y/32, 0, height-1);
+	
+	tiles[ny*width+nx].index = flag;
+}
+
+
 // TODO: rewrite this smarter!
 int col_intersect_line(vec2 pos0, vec2 pos1, vec2 *out_collision, vec2 *out_before_collision)
 {
@@ -85,3 +114,61 @@
 		*out_before_collision = pos1;
 	return 0;
 }
+
+int col_intersect_water(vec2 pos0, vec2 pos1, vec2 *out_collision, vec2 *out_before_collision)
+{
+	float d = distance(pos0, pos1);
+	vec2 last = pos0;
+	
+	for(float f = 0; f < d; f++)
+	{
+		float a = f/d;
+		vec2 pos = mix(pos0, pos1, a);
+		if(col_is_solid(round(pos.x), round(pos.y)) || col_is_water(round(pos.x), round(pos.y)))
+		{
+			if(out_collision)
+				*out_collision = pos;
+			if(out_before_collision)
+				*out_before_collision = last;
+			if(col_is_water(round(pos.x), round(pos.y)))
+				return -1;
+			else
+				return col_get(round(pos.x), round(pos.y));
+		}
+		last = pos;
+	}
+	if(out_collision)
+		*out_collision = pos1;
+	if(out_before_collision)
+		*out_before_collision = pos1;
+	return 0;
+}
+
+int col_intersect_air(vec2 pos0, vec2 pos1, vec2 *out_collision, vec2 *out_before_collision)
+{
+	float d = distance(pos0, pos1);
+	vec2 last = pos0;
+	
+	for(float f = 0; f < d; f++)
+	{
+		float a = f/d;
+		vec2 pos = mix(pos0, pos1, a);
+		if(col_is_solid(round(pos.x), round(pos.y)) || !col_get(round(pos.x), round(pos.y)))
+		{
+			if(out_collision)
+				*out_collision = pos;
+			if(out_before_collision)
+				*out_before_collision = last;
+			if(!col_get(round(pos.x), round(pos.y)))
+				return -1;
+			else
+				return col_get(round(pos.x), round(pos.y));
+		}
+		last = pos;
+	}
+	if(out_collision)
+		*out_collision = pos1;
+	if(out_before_collision)
+		*out_before_collision = pos1;
+	return 0;
+}
Index: src/game/collision.hpp
===================================================================
--- src/game/collision.hpp	(Revision 1952)
+++ src/game/collision.hpp	(Arbeitskopie)
@@ -9,13 +9,24 @@
 	COLFLAG_SOLID=1,
 	COLFLAG_DEATH=2,
 	COLFLAG_NOHOOK=4,
+	COLFLAG_WATER=8,
+	COLFLAG_WATER_UP=16,
+	COLFLAG_WATER_DOWN=32,
+	COLFLAG_WATER_LEFT=64,
+	COLFLAG_WATER_RIGHT=128,
 };
 
+
 int col_init();
 int col_is_solid(int x, int y);
+int col_is_water(int x, int y);
+void col_set(int x, int y, int flag);
 int col_get(int x, int y);
 int col_width();
 int col_height();
 int col_intersect_line(vec2 pos0, vec2 pos1, vec2 *out_collision, vec2 *out_before_collision);
+int col_intersect_water(vec2 pos0, vec2 pos1, vec2 *out_collision, vec2 *out_before_collision);
+int col_intersect_air(vec2 pos0, vec2 pos1, vec2 *out_collision, vec2 *out_before_collision);
 
+
 #endif
Index: src/game/mapitems.hpp
===================================================================
--- src/game/mapitems.hpp	(Revision 1952)
+++ src/game/mapitems.hpp	(Arbeitskopie)
@@ -45,6 +45,11 @@
 	TILE_SOLID,
 	TILE_DEATH,
 	TILE_NOHOOK,
+	TILE_WATER,
+	TILE_WATER_UP,
+	TILE_WATER_DOWN,
+	TILE_WATER_LEFT,
+	TILE_WATER_RIGHT,
 	
 	TILEFLAG_VFLIP=1,
 	TILEFLAG_HFLIP=2,
Index: src/game/server/entities/character.cpp
===================================================================
--- src/game/server/entities/character.cpp	(Revision 1952)
+++ src/game/server/entities/character.cpp	(Arbeitskopie)
@@ -255,6 +255,8 @@
 {
 	if(reload_timer != 0)
 		return;
+	if(freezetime>0)
+		return;
 		
 	do_weaponswitch();
 	
@@ -306,7 +308,23 @@
 
 				// set his velocity to fast upward (for now)
 				game.create_hammerhit(pos);
-				ents[i]->take_damage(vec2(0,-1.0f), data->weapons.hammer.base->damage, player->client_id, active_weapon);
+				if(config.sv_water_insta) {
+					if(ents[i]->team != team) {
+						ents[i]->take_damage(vec2(0,-1.0f), 0, player->client_id, active_weapon);
+						if(config.sv_water_strip && ents[i]->team != team) {
+							if(ents[i]->weapons[WEAPON_RIFLE].got) {
+								ents[i]->weapons[WEAPON_RIFLE].got = false;
+								//ents[i]->freezetime = config.sv_water_freezetime*2;
+								if(ents[i]->active_weapon==WEAPON_RIFLE)
+									ents[i]->active_weapon=WEAPON_HAMMER;
+							}
+						}
+						ents[i]->freezetime = config.sv_water_freezetime;
+						game.send_emoticon( ents[i]->player->client_id,  12);
+					}
+					
+				} else
+					ents[i]->take_damage(vec2(0,-1.0f), data->weapons.hammer.base->damage, player->client_id, active_weapon);
 				vec2 dir;
 				if (length(target->pos - pos) > 0.0f)
 					dir = normalize(target->pos - pos);
@@ -318,8 +336,13 @@
 			}
 			
 			// if we hit anything, we have to wait for the reload
-			if(hits)
-				reload_timer = server_tickspeed()/3;
+			if(config.sv_water_insta) {
+				if(hits)
+					reload_timer = config.sv_water_freezetime*2;
+			} else {
+				if(hits)
+					reload_timer = server_tickspeed()/3;
+			}
 			
 		} break;
 
@@ -406,7 +429,7 @@
 		
 		case WEAPON_RIFLE:
 		{
-			new LASER(pos, direction, tuning.laser_reach, player->client_id);
+			new LASER(pos, direction, tuning.laser_reach, player->client_id, is_water);
 			game.create_sound(pos, SOUND_RIFLE_FIRE);
 		} break;
 		
@@ -427,6 +450,7 @@
 		
 	}
 
+	
 	if(weapons[active_weapon].ammo > 0) // -1 == unlimited
 		weapons[active_weapon].ammo--;
 	attack_tick = server_tick();
@@ -527,6 +551,131 @@
 	mem_copy(&latest_previnput, &latest_input, sizeof(latest_input));
 }
 
+/*void CHARACTER::myowntick(int jumped, int direction)
+{
+	float phys_size = 28.0f;
+	
+	// get ground state
+	bool grounded = false;
+	if(col_check_point(pos.x+phys_size/2, pos.y+phys_size/2+5))
+		grounded = true;
+	if(col_check_point(pos.x-phys_size/2, pos.y+phys_size/2+5))
+		grounded = true;
+	
+	vec2 target_direction = normalize(vec2(input.target_x, input.target_y));
+
+	//core.vel.y += tuning.gravity;
+	
+	float max_speed = grounded ? tuning.ground_control_speed : tuning.air_control_speed;
+	float accel = grounded ? tuning.ground_control_accel : tuning.air_control_accel;
+	float friction = grounded ? tuning.ground_friction : tuning.air_friction;
+	
+	if(col_is_water((int)(pos.x), (int)(pos.y))) {
+		dbg_msg("watermod", "in water =D");
+		//core.vel.y += tuning.water_gravity;
+		//max_speed = tuning.water_control_speed;
+		//accel = tuning.water_control_accel;
+		//friction = tuning.water_friction;
+		core.vel.y += 0.25f;
+		max_speed = 5.0f;
+		accel = 1.0f;
+		friction = 0.7f;
+	} else {
+		core.vel.y += tuning.gravity;
+		max_speed = grounded ? tuning.ground_control_speed : tuning.air_control_speed;
+		accel = grounded ? tuning.ground_control_accel : tuning.air_control_accel;
+		friction = grounded ? tuning.ground_friction : tuning.air_friction;
+	}
+	
+	
+	// handle input
+	if(true)
+	{
+		direction = input.direction;
+
+		// setup angle
+		float a = 0;
+		if(input.target_x == 0)
+			a = atan((float)input.target_y);
+		else
+			a = atan((float)input.target_y/(float)input.target_x);
+			
+		if(input.target_x < 0)
+			a = a+pi;
+			
+		core.angle = (int)(a*256.0f);
+
+		// handle jump
+		if(input.jump)
+		{
+			if(!(jumped&1))
+			{
+				if(grounded)
+				{
+					core.vel.y = -tuning.ground_jump_impulse;
+					jumped |= 1;
+				}
+				else if(!(jumped&2))
+				{
+					core.vel.y = -tuning.air_jump_impulse;
+					jumped |= 3;
+				}
+			}
+		}
+		else
+			jumped &= ~1;
+
+		// handle hook	
+	}
+	
+	// add the speed modification according to players wanted direction
+	if(direction < 0)
+		core.vel.x = saturated_add(-max_speed, max_speed, core.vel.x, -accel);
+	if(direction > 0)
+		core.vel.x = saturated_add(-max_speed, max_speed, core.vel.x, accel);
+	if(direction == 0)
+		core.vel.x *= friction;
+	
+	// handle jumping
+	// 1 bit = to keep track if a jump has been made on this input
+	// 2 bit = to keep track if a air-jump has been made
+	if(grounded)
+		jumped &= ~2;
+	
+	// do hook
+	
+	if(core.hook_state == HOOK_GRABBED)
+	{
+		// don't do this hook rutine when we are hook to a player
+		if(core.hooked_player == -1 && distance(core.hook_pos, pos) > 46.0f)
+		{
+			vec2 hookvel = normalize(core.hook_pos-pos)*tuning.hook_drag_accel;
+			// the hook as more power to drag you up then down.
+			// this makes it easier to get on top of an platform
+			if(hookvel.y > 0)
+				hookvel.y *= 0.3f;
+			
+			// the hook will boost it's power if the player wants to move
+			// in that direction. otherwise it will dampen everything abit
+			if((hookvel.x < 0 && direction < 0) || (hookvel.x > 0 && direction > 0)) 
+				hookvel.x *= 0.95f;
+			else
+				hookvel.x *= 0.75f;
+			
+			vec2 new_vel = core.vel+hookvel;
+
+			// check if we are under the legal limit for the hook
+			if(length(new_vel) < tuning.hook_drag_speed || length(new_vel) < length(core.vel))
+				core.vel = new_vel; // no problem. apply
+				
+		}
+	}
+
+	// clamp the velocity to something sane
+	if(length(core.vel) > 6000)
+		core.vel = normalize(core.vel) * 6000;
+}*/
+
 void CHARACTER::tick()
 {
 	if(player->force_balanced)
@@ -537,13 +686,129 @@
 		
 		player->force_balanced = false;
 	}
+	
 
+
 	//player_core core;
 	//core.pos = pos;
 	//core.jumped = jumped;
+	//int direction = input.direction;
+	//int oldx = core.vel.x;
+	//int oldy = core.vel.y;
+	//int jumped = core.jumped;
+	
+	if(input.direction != 0 || input.jump != 0) {
+		lastmove = server_tick();
+	}
+	
+	if(server_tick()-lastmove > config.sv_water_kicktime) {
+		
+	}
+	
+	if(freezetime > 0) {
+		freezetime--;
+		if(freezetime > 0) {
+			input.direction = 0;
+			input.jump = 0;
+			core.hook_state = HOOK_RETRACT_START;
+			game.send_emoticon( player->client_id,  11);
+		}
+	}
+	
+	
 	core.input = input;
 	core.tick(true);
+	//core.vel.x = oldx;
+	//core.vel.y = oldy;
+	//myowntick(jumped, direction);
 	
+	do_splash = false;
+	
+	core.vel.y -= tuning.gravity;
+
+
+	if(col_is_water((int)(pos.x), (int)(pos.y))) {
+		if(!is_water) {
+			//play a cool sound
+			game.create_sound(pos, SOUND_PLAYER_SPAWN);
+			do_splash = true;
+			//game.create_explosion(pos, -1, -1, true);
+		}
+		core.vel.y += config.sv_water_gravity/100.0f;
+		if(core.vel.x>config.sv_water_maxx/100.0f || core.vel.x<-config.sv_water_maxx/100.0f) {
+			core.vel.x *= config.sv_water_friction/100.0f;
+		}
+		if(core.vel.y>config.sv_water_maxy/100.0f || core.vel.y<-config.sv_water_maxy/100.0f) {
+			core.vel.y *= config.sv_water_friction/100.0f;
+		}
+		if(core.jumped>=2) {
+			core.jumped=1;
+		}
+		
+		if(col_get((int)(pos.x), (int)(pos.y))&COLFLAG_WATER_UP)
+			core.vel.y -= config.sv_water_gain/100.0f;
+		else if(col_get((int)(pos.x), (int)(pos.y))&COLFLAG_WATER_DOWN)
+			core.vel.y += config.sv_water_gain/100.0f;
+		else if(col_get((int)(pos.x), (int)(pos.y))&COLFLAG_WATER_LEFT)
+			core.vel.x -= config.sv_water_gain/100.0f;
+		else if(col_get((int)(pos.x), (int)(pos.y))&COLFLAG_WATER_RIGHT)
+			core.vel.x += config.sv_water_gain/100.0f;
+		
+		is_water = true;
+		
+	} else {
+		if(is_water) {
+			//play another cool sound
+			game.create_sound(pos, SOUND_PLAYER_SPAWN);
+			do_splash = true;
+			//game.create_explosion(pos, -1, -1, true);
+		}
+		core.vel.y += tuning.gravity;
+		
+		is_water = false;
+	}
+	
+	
+	if(config.sv_water_oxygen) {
+		if(is_water) {
+			if ( ( server_tick( ) % (int)(config.sv_water_oxy_drain / 1000.0f * 50) ) == 0 ) {
+				if(armor) {
+					armor--;
+				} else {
+					take_damage(vec2(0,0), 1, player->client_id, WEAPON_WORLD);
+					game.send_emoticon( player->client_id,  config.sv_water_oxy_emoteid);
+				}
+			}
+		} else {
+			if ( ( server_tick( ) % (int)(config.sv_water_oxy_regen / 1000.0f * 50) ) == 0 ) {
+				if(armor < 10) {
+					armor++;
+				}
+			}
+		}
+	}
+
+	for(int i=0; i < 16; i++) {
+		for(int j=0; j < game.controller->doors[i].apos_count; j++) {
+			if(distance(pos, game.controller->doors[i].apos[j]) < 30.0f) {
+				if(server_tick()-game.controller->doors[i].change_tick > 50) {
+					if(game.controller->doors[i].team==-1 || game.controller->doors[i].team == team) {
+						game.controller->doors[i].change_tick = server_tick();
+						game.controller->set_door(i, !game.controller->get_door(i));
+						game.create_sound(pos, SOUND_WEAPON_NOAMMO);
+					} else {
+						game.controller->doors[i].change_tick = server_tick();
+						game.send_chat_target(player->client_id, "This is your enemies' door, you can not operate it!");
+
+						game.create_sound(pos, SOUND_HOOK_NOATTACH);
+					}
+				}
+			}
+		}
+	}
+	
+	//undo stupid stuff from gamecore
+	
 	float phys_size = 28.0f;
 	// handle death-tiles
 	if(col_get((int)(pos.x+phys_size/2), (int)(pos.y-phys_size/2))&COLFLAG_DEATH ||
@@ -553,6 +818,8 @@
 	{
 		die(player->client_id, WEAPON_WORLD);
 	}
+	
+	
 
 	// handle weapons
 	handle_weapons();
@@ -561,9 +828,57 @@
 
 	// Previnput
 	previnput = input;
+	oldpos = core.pos;
 	return;
+	
 }
 
+float point_distance(vec2 point, vec2 line_start, vec2 line_end)
+{
+	float res = -1.0f;
+	vec2 dir = normalize(line_end-line_start);
+	for(int i = 0; i < length(line_end-line_start); i++) {
+		vec2 step = dir;
+		step.x *=i;
+		step.y *=i;
+		float dist = distance(step+line_start, point);
+		if(res < 0 || dist < res)
+			res = dist;
+	}
+	return res;
+}
+
+void CHARACTER::reset_pos() {
+	core.pos = oldpos;
+	core.vel = vec2(0,0);//normalize(-core.vel);
+	
+	if(core.jumped>=2) {
+		core.jumped=1;
+	}
+}
+
+bool CHARACTER::is_hitting_door()
+{
+	bool done = false;
+	for(int i=0; i < 16 && !done; i++) {
+		if(!game.controller->doors[i].valid)
+			continue;
+		//if(distance(core.pos, game.controller->doors[i].pos[0]) < 33.0f || distance(core.pos, game.controller->doors[i].pos[game.controller->doors[i].pos_count-1]) < 33.0f) {
+		//	done = true;
+		//	break;
+		//}
+		if(!game.controller->get_door(i))
+			continue;
+		for(int j = 0; j < game.controller->doors[i].pos_count-1; j++) {
+			if(point_distance(core.pos, game.controller->doors[i].pos[j], game.controller->doors[i].pos[j+1]) < 30.0f) {
+				done = true;
+				break;
+			}
+		}
+	}
+	return done;
+}
+
 void CHARACTER::tick_defered()
 {
 	// advance the dummy
@@ -583,6 +898,28 @@
 		bool stuck_before = test_box(core.pos, vec2(28.0f, 28.0f));
 		
 		core.move();
+		
+		
+		if(is_hitting_door()) {
+			reset_pos();
+			if(is_hitting_door()) {
+			//	die(player->client_id, WEAPON_WORLD);
+				if(!doorstuck) {
+					game.send_emoticon( player->client_id,  11);
+					doorstuck = true;
+				}
+				
+			}
+		} else {
+			doorstuck = false;
+		}
+		
+		/*core.vel.x = core.vel.x*rampvalue;
+		move_box(&core.pos, &core.vel, vec2(0.0f, 28.0f), 0);
+		core.vel.x = core.vel.x*(1.0f/rampvalue);*/
+		
+		
+		
 		bool stuck_after_move = test_box(core.pos, vec2(28.0f, 28.0f));
 		core.quantize();
 		bool stuck_after_quant = test_box(core.pos, vec2(28.0f, 28.0f));
@@ -599,6 +936,8 @@
 				*((unsigned *)&start_pos.x), *((unsigned *)&start_pos.y),
 				*((unsigned *)&start_vel.x), *((unsigned *)&start_vel.y));
 		}
+		
+		
 
 		int events = core.triggered_events;
 		int mask = cmask_all_except_one(player->client_id);
@@ -721,24 +1060,26 @@
 
 	if(dmg)
 	{
-		if(armor)
-		{
-			if(dmg > 1)
+		if(!config.sv_water_oxygen) {
+			if(armor)
 			{
-				health--;
-				dmg--;
+				if(dmg > 1)
+				{
+					health--;
+					dmg--;
+				}
+				
+				if(dmg > armor)
+				{
+					dmg -= armor;
+					armor = 0;
+				}
+				else
+				{
+					armor -= dmg;
+					dmg = 0;
+				}
 			}
-			
-			if(dmg > armor)
-			{
-				dmg -= armor;
-				armor = 0;
-			}
-			else
-			{
-				armor -= dmg;
-				dmg = 0;
-			}
 		}
 		
 		health -= dmg;
@@ -802,6 +1143,10 @@
 		sendcore.write(character);
 	}
 	
+	if (do_splash) {
+		character->jumped = 3;
+	}
+	
 	// set emote
 	if (emote_stop < server_tick())
 	{
Index: src/game/server/entities/character.hpp
===================================================================
--- src/game/server/entities/character.hpp	(Revision 1952)
+++ src/game/server/entities/character.hpp	(Arbeitskopie)
@@ -71,6 +71,8 @@
 	int health;
 	int armor;
 
+	vec2 oldpos;
+	bool ignore_me;
 	// ninja
 	struct
 	{
@@ -83,6 +85,11 @@
 	//int score;
 	int team;
 	int player_state; // if the client is chatting, accessing a menu or so
+	bool is_water;
+	bool do_splash;
+	int freezetime;
+	bool doorstuck;
+	int lastmove;
 
 	// the player core for the physics	
 	CHARACTER_CORE core;
@@ -112,6 +119,7 @@
 	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);	
@@ -120,11 +128,15 @@
 	bool spawn(PLAYER *player, vec2 pos, int team);
 	//bool init_tryspawn(int team);
 	bool remove();
+	
 
 	static const int phys_size = 28;
 
+	//void myowntick(int jumped, int direction);
 	virtual void tick();
 	virtual void tick_defered();
+	virtual void reset_pos();
+	virtual bool is_hitting_door();
 	virtual void snap(int snapping_client);
 	
 	bool increase_health(int amount);
Index: src/game/server/entities/laser.cpp
===================================================================
--- src/game/server/entities/laser.cpp	(Revision 1952)
+++ src/game/server/entities/laser.cpp	(Arbeitskopie)
@@ -1,4 +1,5 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+#include <engine/e_config.h>
 #include <engine/e_server_interface.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/server/gamecontext.hpp>
@@ -7,16 +8,18 @@
 //////////////////////////////////////////////////
 // laser
 //////////////////////////////////////////////////
-LASER::LASER(vec2 pos, vec2 direction, float start_energy, int owner)
+LASER::LASER(vec2 pos, vec2 direction, float start_energy, int owner, bool in_water)
 : ENTITY(NETOBJTYPE_LASER)
 {
 	this->pos = pos;
 	this->owner = owner;
+	this->in_water = in_water;
 	energy = start_energy;
 	dir = direction;
 	bounces = 0;
 	do_bounce();
 	
+	
 	game.world.insert_entity(this);
 }
 
@@ -31,15 +34,19 @@
 
 	this->from = from;
 	pos = at;
-	energy = -1;		
-	hit->take_damage(vec2(0,0), tuning.laser_damage, owner, WEAPON_RIFLE);
+	energy = -1;
+	if (config.sv_water_insta) {
+		hit->take_damage(vec2(0,0), 100, owner, WEAPON_RIFLE);
+	} else {
+		hit->take_damage(vec2(0,0), tuning.laser_damage, owner, WEAPON_RIFLE);
+	}
 	return true;
 }
 
 void LASER::do_bounce()
 {
 	eval_tick = server_tick();
-	
+
 	if(energy < 0)
 	{
 		//dbg_msg("laser", "%d removed", server_tick());
@@ -49,8 +56,21 @@
 	
 	vec2 to = pos + dir*energy;
 	vec2 org_to = to;
+	vec2 coltile;
 	
-	if(col_intersect_line(pos, to, 0x0, &to))
+	int res;
+	//(col_intersect_line(pos, to, 0x0, &to))
+	if(config.sv_water_reflect) {
+		if(in_water)
+			res = col_intersect_air(pos, to, &coltile, &to);
+		else
+			res = col_intersect_water(pos, to, &coltile, &to);
+	} else {
+			res = col_intersect_line(pos, to, &coltile, &to);
+	}
+	
+	
+	if(res)
 	{
 		if(!hit_character(pos, to))
 		{
@@ -60,8 +80,18 @@
 
 			vec2 temp_pos = pos;
 			vec2 temp_dir = dir*4.0f;
-			
+			int f;
+			if(res == -1) {
+				f = col_get(round(coltile.x), round(coltile.y));
+				col_set(round(coltile.x), round(coltile.y), COLFLAG_SOLID);
+			}
 			move_point(&temp_pos, &temp_dir, 1.0f, 0);
+			if(res == -1) {
+				col_set(round(coltile.x), round(coltile.y), f);
+			}
+			if(config.sv_water_rambo)
+				col_set(round(coltile.x), round(coltile.y), 0);
+
 			pos = temp_pos;
 			dir = normalize(temp_dir);
 			
@@ -71,6 +101,9 @@
 			if(bounces > tuning.laser_bounce_num)
 				energy = -1;
 				
+			if(config.sv_water_laserjump)
+				game.create_explosion(to, owner, -1, true);
+
 			game.create_sound(pos, SOUND_RIFLE_BOUNCE);
 		}
 	}
@@ -94,6 +127,7 @@
 
 void LASER::tick()
 {
+	
 	if(server_tick() > eval_tick+(server_tickspeed()*tuning.laser_bounce_delay)/1000.0f)
 	{
 		do_bounce();
@@ -112,4 +146,5 @@
 	obj->from_x = (int)from.x;
 	obj->from_y = (int)from.y;
 	obj->start_tick = eval_tick;
+
 }
Index: src/game/server/entities/laser.hpp
===================================================================
--- src/game/server/entities/laser.hpp	(Revision 1952)
+++ src/game/server/entities/laser.hpp	(Arbeitskopie)
@@ -15,14 +15,14 @@
 	int bounces;
 	int eval_tick;
 	int owner;
+	bool in_water;
 	
 	bool hit_character(vec2 from, vec2 to);
 	void do_bounce();
 	
 public:
+	LASER(vec2 pos, vec2 direction, float start_energy, int owner, bool in_water);
 	
-	LASER(vec2 pos, vec2 direction, float start_energy, int owner);
-	
 	virtual void reset();
 	virtual void tick();
 	virtual void snap(int snapping_client);
Index: src/game/server/entities/light.cpp
===================================================================
--- src/game/server/entities/light.cpp	(Revision 0)
+++ src/game/server/entities/light.cpp	(Revision 0)
@@ -0,0 +1,170 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+#include <engine/e_config.h>
+#include <engine/e_server_interface.h>
+#include <game/generated/g_protocol.hpp>
+#include <game/server/gamecontext.hpp>
+#include "light.hpp"
+
+//////////////////////////////////////////////////
+// LIGHT
+//////////////////////////////////////////////////
+LIGHT::LIGHT(vec2 from, vec2 to, int team, int width)
+: ENTITY(NETOBJ_INVALID)
+{
+	this->from = from;
+	this->to = to;
+	this->visible = true;
+	this->width = width;
+	this->team = team;
+	keep_points = false;
+	this->id2 = snap_new_id();
+	//do_bounce();
+	
+	game.world.insert_entity(this);
+}
+
+
+bool LIGHT::hit_character(vec2 from, vec2 to)
+{
+	return false;
+	/*if(this->visual)
+		return false;
+	vec2 at;
+	CHARACTER *owner_char = game.get_player_char(owner);
+	CHARACTER *hit = game.world.intersect_character(pos, to, 0.0f, at, owner_char);
+	if(!hit)
+		return false;
+
+	this->from = from;
+	pos = at;
+	energy = -1;
+	if (config.sv_water_insta) {
+		hit->take_damage(vec2(0,0), 100, owner, WEAPON_RIFLE);
+	} else {
+		hit->take_damage(vec2(0,0), tuning.LIGHT_damage, owner, WEAPON_RIFLE);
+	}
+	return true;*/
+}
+
+void LIGHT::do_bounce()
+{
+	/*
+	eval_tick = server_tick();
+	
+	
+	if(energy < 0)
+	{
+		//dbg_msg("LIGHT", "%d removed", server_tick());
+		game.world.destroy_entity(this);
+		return;
+	}
+	if(visual) {
+		from = pos;
+		energy = -1;
+		return;
+	}
+	
+	vec2 to = pos + dir*energy;
+	vec2 org_to = to;
+	
+	
+	if(col_intersect_line(pos, to, 0x0, &to))
+	{
+		if(!hit_character(pos, to))
+		{
+			// intersected
+			from = pos;
+			pos = to;
+
+			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.LIGHT_bounce_cost;
+			bounces++;
+			
+			if(bounces > tuning.LIGHT_bounce_num)
+				energy = -1;
+				
+			game.create_sound(pos, SOUND_RIFLE_BOUNCE);
+		}
+	}
+	else
+	{
+		if(!hit_character(pos, to))
+		{
+			if(!visual) {
+				from = pos;
+				pos = to;
+				energy = -1;
+			}
+		}
+	}
+		
+	//dbg_msg("LIGHT", "%d done %f %f %f %f", server_tick(), from.x, from.y, pos.x, pos.y);*/
+}
+	
+void LIGHT::reset()
+{
+	//dbg_msg("light", "i died, oh my!");
+	game.world.destroy_entity(this);
+}
+
+void LIGHT::tick()
+{
+	return;
+	/*if(server_tick() > eval_tick+(server_tickspeed()*tuning.LIGHT_bounce_delay)/1000.0f)
+	{
+		do_bounce();
+	}*/
+
+}
+
+void LIGHT::snap(int snapping_client)
+{
+	//if((networkclipped(snapping_client)))
+	//	return;
+		
+	if(!this->visible && !keep_points)
+		return;
+
+	NETOBJ_LASER *obj;
+	if(this->team == -1) {
+		obj = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id, sizeof(NETOBJ_LASER));
+		obj->x = (int)from.x;
+		obj->y = (int)from.y;
+		obj->from_x = (int)to.x;
+		obj->from_y = (int)to.y;
+		obj->start_tick = server_tick()-2;
+	} else if (game.players[snapping_client]->team == this->team) {
+		obj = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id, sizeof(NETOBJ_LASER));
+		obj->x = (int)from.x;
+		obj->y = (int)from.y;
+		obj->from_x = (int)to.x;
+		obj->from_y = (int)to.y;
+		obj->start_tick = server_tick()-4;
+	} else {
+		obj = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id, sizeof(NETOBJ_LASER));
+		obj->x = (int)from.x-5;
+		obj->y = (int)from.y-5;
+		obj->from_x = (int)to.x-5;
+		obj->from_y = (int)to.y-5;
+		obj->start_tick = server_tick();
+	}
+	NETOBJ_LASER *obj2 = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id2, sizeof(NETOBJ_LASER));
+	obj2->x = obj->from_x;
+	obj2->y = obj->from_y;
+	obj2->from_x = obj->x;
+	obj2->from_y = obj->y;
+	obj2->start_tick = obj->start_tick;
+	
+	if(!visible) {
+		obj->x = obj->from_x;
+		obj->y = obj->from_y;
+		obj2->x = obj2->from_x;
+		obj2->y = obj2->from_y;
+	}
+}
Index: src/game/server/entities/light.hpp
===================================================================
--- src/game/server/entities/light.hpp	(Revision 0)
+++ src/game/server/entities/light.hpp	(Revision 0)
@@ -0,0 +1,33 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+
+#ifndef GAME_SERVER_ENTITY_LIGHT_H
+#define GAME_SERVER_ENTITY_LIGHT_H
+
+#include <game/server/entity.hpp>
+
+class CHARACTER;
+
+class LIGHT : public ENTITY
+{
+	vec2 from;
+	vec2 to;
+	int bounces;
+	int eval_tick;
+	int id2;
+	
+	bool hit_character(vec2 from, vec2 to);
+	void do_bounce();
+	
+public:
+	bool visible;
+	bool keep_points;
+	int width;
+	int team;
+	LIGHT(vec2 from, vec2 to, int team, int width = 0);
+	
+	virtual void reset();
+	virtual void tick();
+	virtual void snap(int snapping_client);
+};
+
+#endif
Index: src/game/server/entities/pickup.cpp
===================================================================
--- src/game/server/entities/pickup.cpp	(Revision 1952)
+++ src/game/server/entities/pickup.cpp	(Arbeitskopie)
@@ -1,4 +1,5 @@
 #include <engine/e_server_interface.h>
+#include <engine/e_config.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/server/gamecontext.hpp>
 #include "pickup.hpp"
@@ -67,7 +68,16 @@
 			break;
 
 		case POWERUP_WEAPON:
-			if(subtype >= 0 && subtype < NUM_WEAPONS)
+			if(config.sv_water_insta && config.sv_water_strip && subtype == WEAPON_RIFLE) {
+				 if(!chr->weapons[WEAPON_RIFLE].got) {
+					chr->weapons[WEAPON_RIFLE].got=true;
+					chr->weapons[WEAPON_RIFLE].ammo=-1;
+					chr->active_weapon=WEAPON_RIFLE;
+					respawntime = data->pickups[type].respawntime;
+					game.create_sound(pos, SOUND_PICKUP_SHOTGUN);
+				}
+				break;	
+			} else if(subtype >= 0 && subtype < NUM_WEAPONS)
 			{
 				if(chr->weapons[subtype].ammo < data->weapons.id[subtype].maxammo || !chr->weapons[subtype].got)
 				{
Index: src/game/server/gamecontroller.cpp
===================================================================
--- src/game/server/gamecontroller.cpp	(Revision 1952)
+++ src/game/server/gamecontroller.cpp	(Arbeitskopie)
@@ -7,6 +7,8 @@
 #include <game/generated/g_protocol.hpp>
 
 #include "entities/pickup.hpp"
+#include "entities/laser.hpp"
+#include "entities/light.hpp"
 #include "gamecontroller.hpp"
 #include "gamecontext.hpp"
 
@@ -114,36 +116,82 @@
 	int type = -1;
 	int subtype = 0;
 	
+	int DOOR_BASE = 17;
+	
 	if(index == ENTITY_SPAWN)
 		spawn_points[0][num_spawn_points[0]++] = pos;
 	else if(index == ENTITY_SPAWN_RED)
 		spawn_points[1][num_spawn_points[1]++] = pos;
 	else if(index == ENTITY_SPAWN_BLUE)
 		spawn_points[2][num_spawn_points[2]++] = pos;
-	else if(index == ENTITY_ARMOR_1)
-		type = POWERUP_ARMOR;
-	else if(index == ENTITY_HEALTH_1)
-		type = POWERUP_HEALTH;
-	else if(index == ENTITY_WEAPON_SHOTGUN)
-	{
-		type = POWERUP_WEAPON;
-		subtype = WEAPON_SHOTGUN;
+		
+	else if(index >= DOOR_BASE && index < DOOR_BASE+16) {
+		if(doors[index-DOOR_BASE].tmpstart == vec2(-42,-42)) {
+			doors[index-DOOR_BASE].tmpstart = pos;
+			doors[index-DOOR_BASE].tmpend = pos;
+			doors[index-DOOR_BASE].valid = true;
+			dbg_msg("door", "doorstart-> %f:%f in %d", pos.x, pos.y, index-DOOR_BASE);
+		} else {
+			doors[index-DOOR_BASE].tmpend = pos;
+			doors[index-DOOR_BASE].circle = false;
+			dbg_msg("door", "doorend-> %f:%f in %d,%d(%d)", pos.x, pos.y, index, DOOR_BASE, index-DOOR_BASE);
+		}
 	}
-	else if(index == ENTITY_WEAPON_GRENADE)
-	{
-		type = POWERUP_WEAPON;
-		subtype = WEAPON_GRENADE;
+	
+	else if(index >= DOOR_BASE+16 && index < DOOR_BASE+32) {
+		int doorno = index-DOOR_BASE-16;
+		if(doors[doorno].pos_count < 126) {
+			doors[doorno].tmppos[doors[doorno].pos_count++] = pos;
+			dbg_msg("door", "doortile-> %f:%f in %d", pos.x, pos.y, doorno);
+			//Door completed =D
+		}
 	}
-	else if(index == ENTITY_WEAPON_RIFLE)
-	{
-		type = POWERUP_WEAPON;
-		subtype = WEAPON_RIFLE;
+	
+	else if(index >= DOOR_BASE+32 && index < DOOR_BASE+48) {
+		int doorno = index-DOOR_BASE-32;
+		int idx = doors[doorno].apos_count++;
+		
+		int team;
+		if(doorno <10) {
+			team = -1;
+		} else if(doorno >=10 && doorno < 13) {
+			team = 0; //red door
+		} else {
+			team = 1; //blue door
+		}
+		doors[doorno].apos[idx] = pos;
 	}
-	else if(index == ENTITY_POWERUP_NINJA && config.sv_powerups)
-	{
-		type = POWERUP_NINJA;
-		subtype = WEAPON_NINJA;
+		
+
+	if((config.sv_water_insta && config.sv_water_strip) || (!config.sv_water_insta)) {
+		if(index == ENTITY_WEAPON_RIFLE)
+		{
+			type = POWERUP_WEAPON;
+			subtype = WEAPON_RIFLE;
+		}
 	}
+
+	if(!config.sv_water_insta) {
+		if(index == ENTITY_ARMOR_1)
+			type = POWERUP_ARMOR;
+		else if(index == ENTITY_HEALTH_1)
+			type = POWERUP_HEALTH;
+		else if(index == ENTITY_WEAPON_SHOTGUN)
+		{
+			type = POWERUP_WEAPON;
+			subtype = WEAPON_SHOTGUN;
+		}
+		else if(index == ENTITY_WEAPON_GRENADE)
+		{
+			type = POWERUP_WEAPON;
+			subtype = WEAPON_GRENADE;
+		}
+		else if(index == ENTITY_POWERUP_NINJA && config.sv_powerups)
+		{
+			type = POWERUP_NINJA;
+			subtype = WEAPON_NINJA;
+		}
+	}
 	
 	if(type != -1)
 	{
@@ -155,6 +203,100 @@
 	return false;
 }
 
+void GAMECONTROLLER::deinit_lights()
+{
+	dbg_msg("door", "unlights =D");
+	for(int doorno = 0; doorno < 16; doorno++) {
+		for(int j = 0; j < doors[doorno].pos_count-1; j++) {
+			delete doors[doorno].light[j];
+		}
+		for(int idx = 0; idx < doors[doorno].apos_count; idx++) {
+			delete doors[doorno].alight[idx][0];
+			delete doors[doorno].alight[idx][1];
+			delete doors[doorno].alight[idx][2];
+			delete doors[doorno].alight[idx][3];
+			delete doors[doorno].alight[idx][4];
+		}
+	}
+}
+
+void GAMECONTROLLER::init_lights()
+{
+	dbg_msg("door", "lights =D");
+	for(int doorno = 0; doorno < 16; doorno++) {
+		for(int j = 0; j < doors[doorno].pos_count-1; j++) {
+			vec2 from=doors[doorno].pos[j];
+			vec2 to  =doors[doorno].pos[j+1];
+			if(j==0 && !doors[doorno].circle)
+				from = from - normalize(to-from)*17;
+				
+			if(j==doors[doorno].pos_count-2 && !doors[doorno].circle)
+				to = to + normalize(to-from)*17;
+			doors[doorno].light[j] = new LIGHT(from, to, doors[doorno].team);
+			//if(j==0 || j == doors[doorno].pos_count-2)
+			doors[doorno].light[j]->keep_points = true;
+		}
+		int team = doors[doorno].team;
+		for(int idx = 0; idx < doors[doorno].apos_count; idx++) {
+			doors[doorno].alight[idx][0] = new LIGHT(doors[doorno].apos[idx], doors[doorno].apos[idx], team);
+			doors[doorno].alight[idx][1] = new LIGHT( vec2(doors[doorno].apos[idx].x-15,doors[doorno].apos[idx].y),  vec2(doors[doorno].apos[idx].x,doors[doorno].apos[idx].y-15), team, 4) ;
+			doors[doorno].alight[idx][2] = new LIGHT( vec2(doors[doorno].apos[idx].x,doors[doorno].apos[idx].y-15),  vec2(doors[doorno].apos[idx].x+15,doors[doorno].apos[idx].y), team, 4) ;
+			doors[doorno].alight[idx][3] = new LIGHT( vec2(doors[doorno].apos[idx].x+15,doors[doorno].apos[idx].y),  vec2(doors[doorno].apos[idx].x,doors[doorno].apos[idx].y+15), team, 4) ;
+			doors[doorno].alight[idx][4] = new LIGHT( vec2(doors[doorno].apos[idx].x,doors[doorno].apos[idx].y+15),  vec2(doors[doorno].apos[idx].x-15,doors[doorno].apos[idx].y), team, 4) ;
+		}
+	}
+}
+
+void GAMECONTROLLER::init_doors()
+{
+	dbg_msg("door", "i inits nao!");
+
+	for(int doorno = 0; doorno < 16; doorno++) {
+		if(doorno <10) {
+			doors[doorno].team = -1;
+		} else if(doorno >=10 && doorno < 13) {
+			doors[doorno].team = 0; //red door
+		} else {
+			doors[doorno].team = 1; //blue door
+		}
+		if(!doors[doorno].valid) 
+			continue;
+		doors[doorno].pos[0] = doors[doorno].tmpstart;
+		for(int i = 0; i < doors[doorno].pos_count; i++) {
+			//dbg_msg("door", "i has a door %f:%f", doors[doorno].pos[i].x, doors[doorno].pos[i].y);
+			int dist = -1;
+			for(int j = 0; j < doors[doorno].pos_count; j++) {
+				if(doors[doorno].mark[j])
+					continue;
+				if(dist < 0)
+					dist = j;
+				else {
+					float olddist = distance(doors[doorno].tmppos[dist], doors[doorno].pos[i]);
+					float newdist = distance(doors[doorno].tmppos[j], doors[doorno].pos[i]);
+					if(newdist < olddist) dist = j;
+				}
+			}
+			doors[doorno].pos[i+1] = doors[doorno].tmppos[dist];
+			doors[doorno].mark[dist] = true;
+		}
+			
+		doors[doorno].pos_count += 2;
+		doors[doorno].pos[doors[doorno].pos_count-1] = doors[doorno].tmpend;
+		//dbg_msg("door", "i sorted doors and i has %d pos in door %d=D", doors[doorno].pos_count, doorno);
+		//for(int i = 0; i < doors[doorno].pos_count; i++) {
+			//dbg_msg("door", "%f:%f", doors[doorno].pos[i].x,doors[doorno].pos[i].y);
+		//}
+
+		
+		//dbg_msg("door","i inits lights!");
+		//
+	}
+	dbg_msg("door","i s dun!");
+	init_lights();
+	for(int i = 0; i < 16; i++)
+		set_door(i, true);
+}
+
 void GAMECONTROLLER::endround()
 {
 	if(warmup) // game can't end when we are running warmup
@@ -202,7 +344,13 @@
 	teamscore[1] = 0;
 	unbalanced_tick = -1;
 	force_balanced = false;
+	//init_lights();
+	for(int i = 0; i < 16; i++) {
+		set_door(i, true);
+	}
 	dbg_msg("game","start round type='%s' teamplay='%d'", gametype, game_flags&GAMEFLAG_TEAMS);
+	//init_lights(); //is done in this stupid gameworld shit -.-
+	
 }
 
 void GAMECONTROLLER::change_map(const char *to_map)
@@ -329,10 +477,20 @@
 	chr->health = 10;
 	
 	// give default weapons
-	chr->weapons[WEAPON_HAMMER].got = 1;
-	chr->weapons[WEAPON_HAMMER].ammo = -1;
-	chr->weapons[WEAPON_GUN].got = 1;
-	chr->weapons[WEAPON_GUN].ammo = 10;
+	if(config.sv_water_insta) {
+		chr->weapons[WEAPON_HAMMER].got = 1;
+		chr->weapons[WEAPON_HAMMER].ammo = -1;
+		chr->weapons[WEAPON_GUN].got = 0;
+		//chr->weapons[WEAPON_GUN].ammo = 10;
+		chr->weapons[WEAPON_RIFLE].got = 1;
+		chr->weapons[WEAPON_RIFLE].ammo = -1;
+		chr->active_weapon=WEAPON_RIFLE;
+	} else {
+		chr->weapons[WEAPON_HAMMER].got = 1;
+		chr->weapons[WEAPON_HAMMER].ammo = -1;
+		chr->weapons[WEAPON_GUN].got = 1;
+		chr->weapons[WEAPON_GUN].ammo = 10;
+	}
 }
 
 void GAMECONTROLLER::do_warmup(int seconds)
@@ -370,6 +528,8 @@
 
 void GAMECONTROLLER::tick()
 {
+	
+	
 	// do warmup
 	if(warmup)
 	{
@@ -383,8 +543,11 @@
 		// game over.. wait for restart
 		if(server_tick() > game_over_tick+server_tickspeed()*10)
 		{
+			//deinit_lights();
 			cyclemap();
+			//init_lights();
 			startround();
+	
 			round_count++;
 		}
 	}
@@ -468,6 +631,57 @@
 	if(warmup)
 		prog = -1;
 		
+	/*if(game_over_tick == -1) {
+		for(int i = 0; i < 16; i++) {
+			if(doors[i].valid) {
+				if(!doors[i].light[0])
+					init_lights();
+					break;
+			}
+		}
+	}*/
+	
+	/**if(game_over_tick == -1 && !(server_tick()%5)) {
+		for(int i = 0; i < 16; i++) {
+			for(int j = 0; j < doors[i].pos_count; j++) {
+				if(!get_door(i))
+					continue;
+				LASER *blar;
+				if(doors[i].team != 0) {
+					blar = new LASER(doors[i].pos[j], vec2(-1, -1), 1, 0, true);
+					blar->cross = 1;
+				}
+				
+				if(doors[i].team != 1) {
+					blar = new LASER(doors[i].pos[j], vec2(-1, -1), 1, 0, true);
+					blar->cross = 2;
+				}
+				//blar->visual = true;
+			}
+			if(get_door(i))
+				LASER *blar = new LASER(doors[i].pos[0], doors[i].pos[1], 1, 0, true);
+			
+			
+			for(int j = 0; j < doors[i].apos_count; j++) {
+				// this is ugly, but the whole code is ugly, I'm just continuing someone elses' shit
+				new LASER(vec2(doors[i].apos[j].x, doors[i].apos[j].y ), vec2(-1, -1), 1, 0, true);
+				if(get_door(i)) {
+					if(doors[i].team != 0)
+						new LASER(vec2(doors[i].apos[j].x, doors[i].apos[j].y-15 ), vec2(-1, -1), 1, 0, true);
+					if(doors[i].team != 1)
+						new LASER(vec2(doors[i].apos[j].x, doors[i].apos[j].y+15 ), vec2(-1, -1), 1, 0, true);
+					new LASER(vec2(doors[i].apos[j].x-15, doors[i].apos[j].y ), vec2(-1, -1), 1, 0, true);
+					new LASER(vec2(doors[i].apos[j].x+15, doors[i].apos[j].y ), vec2(-1, -1), 1, 0, true);
+				}
+			}
+		}
+	}*/
+	
+	if(!(server_tick() % (50*60*5))) {
+		game.send_chat(-1, GAMECONTEXT::CHAT_ALL, "Welcome to WaterMOD");
+		game.send_chat(-1, GAMECONTEXT::CHAT_ALL, "by .0xdeadbeef//inherited");
+		game.send_chat(-1, GAMECONTEXT::CHAT_ALL, "for help, say '$help'");
+	}
 	server_setbrowseinfo(gametype, prog);
 }
 
@@ -507,6 +721,10 @@
 		gameobj->teamscore_red = is_teamplay() ? teamscore[0] : game.players[snapping_client]->score;
 		gameobj->teamscore_blue = teamscore[1];
 	}
+	
+	
+ 
+	
 }
 
 int GAMECONTROLLER::get_auto_team(int notthisid)
@@ -534,6 +752,34 @@
 	return -1;
 }
 
+bool GAMECONTROLLER::get_door(int idx)
+{
+	return doors[idx].act;
+}
+
+void GAMECONTROLLER::set_door(int idx, bool active)
+{
+	if(!doors[idx].valid)
+		return;
+	doors[idx].act = active;
+
+	//if(active) {
+	for(int i = 0; i < doors[idx].apos_count; i++) {
+		for(int j = 1; j < 5; j++) {
+			doors[idx].alight[i][j]->visible = active;
+		}
+			//(j<3&&doors[idx].team==0)||(j>=3&&doors[idx].team)||(doors[idx].team==-1) ? active : false;
+	}
+	for(int i = 0; i < doors[idx].pos_count-1; i++) {
+		doors[idx].light[i]->visible = active;
+			//(j<3&&doors[idx].team==0)||(j>=3&&doors[idx].team)||(doors[idx].team==-1) ? active : false;
+	}
+		
+	//for(int i = 0; i < doors[idx].pos_count; i++)
+	//	col_set_solid(doors[idx].pos[i].x, doors[idx].pos[i].y, active);
+	//}
+}
+
 bool GAMECONTROLLER::can_join_team(int team, int notthisid)
 {
 	(void)team;
Index: src/game/server/gamecontroller.hpp
===================================================================
--- src/game/server/gamecontroller.hpp	(Revision 1952)
+++ src/game/server/gamecontroller.hpp	(Arbeitskopie)
@@ -2,12 +2,87 @@
 #define GAME_SERVER_GAMECONTROLLER_H
 
 #include <base/vmath.hpp>
+//#include <game/server/entity.hpp>
+//#include <game/generated/gs_data.hpp>
+//#include <game/generated/g_protocol.hpp>
 
+//#include <game/server/entities/laser.hpp>
+//#include "entities/laser.hpp"
+
 /*
 	Class: Game Controller
 		Controls the main game logic. Keeping track of team and player score,
 		winning conditions and specific game logic.
 */
+class LIGHT;
+struct DOOR
+{
+	DOOR()
+	{
+		act = true;
+		change_tick = 0;
+		for(int i = 0; i < 128; i++) {
+			pos[i] = vec2(-42, -42);
+			apos[i] = vec2(-42, -42);
+		}
+		pos_count = 0;
+		apos_count = 0;
+		team=-1;
+	}
+	
+	int team;
+	bool act;
+	int pos_count;
+	int apos_count;
+	//int activators;
+	int change_tick;
+	vec2 pos[2];
+	vec2 apos[128];
+};
+
+struct DOOR2
+{
+	DOOR2()
+	{
+		act = false;
+		valid = false;
+		change_tick = 0;
+		for(int i = 0; i < 128; i++) {
+			pos[i] = vec2(-42, -42);
+			apos[i] = vec2(-42, -42);
+			mark[i] = false;
+		}
+		tmpstart = vec2(-42,-42);
+		tmpend = vec2(-42,-42);
+		pos_count = 0;
+		apos_count = 0;
+		team=-1;
+		circle = true;
+		//activator = -1;
+	}
+	
+
+	//int activator;
+	int team;
+	bool act;
+	bool valid;
+	bool circle;
+	int pos_count;
+	int apos_count;
+	//int activators;
+	int change_tick;
+	
+	vec2 tmppos[126];
+	bool mark[128];
+	vec2 tmpstart;
+	vec2 tmpend;
+	
+	vec2 pos[128];
+	vec2 apos[128];
+	LIGHT *light[127];
+	LIGHT *alight[128][5];
+};
+
 class GAMECONTROLLER
 {
 	vec2 spawn_points[3][64];
@@ -27,7 +102,9 @@
 		int friendly_team;
 		float score;
 	};
-
+	
+	
+	
 	float evaluate_spawn_pos(SPAWNEVAL *eval, vec2 pos);
 	void evaluate_spawn_type(SPAWNEVAL *eval, int type);
 	bool evaluate_spawn(class PLAYER *p, vec2 *pos);
@@ -55,6 +132,8 @@
 	const char *gametype;
 
 	bool is_teamplay() const;
+	//DOOR doors[16];
+	DOOR2 doors[16];
 	
 	GAMECONTROLLER();
 	virtual ~GAMECONTROLLER();
@@ -92,6 +171,9 @@
 			bool?
 	*/
 	virtual bool on_entity(int index, vec2 pos);
+	virtual void init_doors();
+	virtual void deinit_lights();
+	virtual void init_lights();
 	
 	/*
 		Function: on_character_spawn
@@ -131,6 +213,9 @@
 	int clampteam(int team);
 
 	virtual void post_reset();
+	
+	virtual bool get_door(int idx);
+	virtual void set_door(int idx, bool active);
 };
 
 #endif
Index: src/game/server/gamemodes/ctf.cpp
===================================================================
--- src/game/server/gamemodes/ctf.cpp	(Revision 1952)
+++ src/game/server/gamemodes/ctf.cpp	(Arbeitskopie)
@@ -10,7 +10,7 @@
 {
 	flags[0] = 0;
 	flags[1] = 0;
-	gametype = "CTF";
+	gametype = "water-CTF";
 	game_flags = GAMEFLAG_TEAMS|GAMEFLAG_FLAGS;
 }
 
Index: src/game/server/gamemodes/dm.cpp
===================================================================
--- src/game/server/gamemodes/dm.cpp	(Revision 1952)
+++ src/game/server/gamemodes/dm.cpp	(Arbeitskopie)
@@ -4,7 +4,7 @@
 
 GAMECONTROLLER_DM::GAMECONTROLLER_DM()
 {
-	gametype = "DM";
+	gametype = "water-DM";
 }
 
 void GAMECONTROLLER_DM::tick()
Index: src/game/server/gamemodes/tdm.cpp
===================================================================
--- src/game/server/gamemodes/tdm.cpp	(Revision 1952)
+++ src/game/server/gamemodes/tdm.cpp	(Arbeitskopie)
@@ -6,7 +6,7 @@
 
 GAMECONTROLLER_TDM::GAMECONTROLLER_TDM()
 {
-	gametype = "TDM";
+	gametype = "water-TDM";
 	game_flags = GAMEFLAG_TEAMS;
 }
 
Index: src/game/server/gameworld.cpp
===================================================================
--- src/game/server/gameworld.cpp	(Revision 1952)
+++ src/game/server/gameworld.cpp	(Arbeitskopie)
@@ -118,6 +118,7 @@
 
 	game.controller->post_reset();
 	remove_entities();
+	game.controller->init_lights();
 
 	reset_requested = false;
 }
Index: src/game/server/hooks.cpp
===================================================================
--- src/game/server/hooks.cpp	(Revision 1952)
+++ src/game/server/hooks.cpp	(Arbeitskopie)
@@ -115,7 +115,12 @@
 	char buf[512];
 	str_format(buf, sizeof(buf), "%s entered and joined the %s", server_clientname(client_id), game.controller->get_team_name(game.players[client_id]->team));
 	game.send_chat(-1, GAMECONTEXT::CHAT_ALL, buf); 
+	
+	game.send_chat_target(client_id, "Welcome to WaterMOD");
+	game.send_chat_target(client_id, "by .0xdeadbeef//inherited");
+	game.send_chat_target(client_id, "for help, say '$help'");
 
+
 	dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), game.players[client_id]->team);
 }
 
@@ -195,7 +200,27 @@
 		
 		p->last_chat = time_get();
 		
-		game.send_chat(client_id, team, msg->message);
+		if(msg->message[0] == '$') {
+			if(!strcmp(msg->message, "$help")) {
+				game.send_chat_target(client_id, "WaterMOD v. 0.60 by .0xdeadbeef//inherited, special thanks to Apprentice Sheng.");
+				game.send_chat_target(client_id, "Use double jump in water to swim upwards.");
+				game.send_chat_target(client_id, "Blue lasers are doors, if you can see them, the door is closed, you can't go through it.");
+				game.send_chat_target(client_id, "Use the switches to open/close doors.");
+				game.send_chat_target(client_id, "Bigger lasers are from hostile, smaller lasers are your teams' door, only team members can open them.");
+				game.send_chat_target(client_id, "Use the hammer to strip your enemies' weapon and/or freeze him! (if enabled)");
+				
+			//} else if(!strcmp(msg->message, "$l")) {
+			//	game.controller->init_lights();
+					
+			//} else if(!strcmp(msg->message, "$d")) {
+			//	game.controller->deinit_lights();
+					
+			} else {
+				game.send_chat_target(client_id, "Command not found.");
+			}
+		} else {
+			game.send_chat(client_id, team, msg->message);
+		}
 	}
 	else if(msgtype == NETMSGTYPE_CL_CALLVOTE)
 	{
@@ -257,7 +282,7 @@
 				return;
 			}
 			
-			str_format(chatmsg, sizeof(chatmsg), "Vote called to kick '%s'", server_clientname(kick_id));
+			str_format(chatmsg, sizeof(chatmsg), "%s called for vote to kick '%s'", server_clientname(client_id), server_clientname(kick_id));
 			str_format(desc, sizeof(desc), "Kick '%s'", server_clientname(kick_id));
 			str_format(cmd, sizeof(cmd), "kick %d", kick_id);
 			if (!config.sv_vote_kick_bantime)
@@ -554,20 +579,25 @@
 	num_spawn_points[2] = 0;
 	*/
 	
+//	int DOOR_BASE=17+ENTITY_OFFSET;
+	
 	for(int y = 0; y < tmap->height; y++)
 	{
 		for(int x = 0; x < tmap->width; x++)
 		{
 			int index = tiles[y*tmap->width+x].index;
+
 			
 			if(index >= ENTITY_OFFSET)
 			{
 				vec2 pos(x*32.0f+16.0f, y*32.0f+16.0f);
 				game.controller->on_entity(index-ENTITY_OFFSET, pos);
+				//if(index >= DOOR_BASE && index < DOOR_BASE+16) 
+				//	tiles[y*tmap->width+x].index = COLFLAG_SOLID;
 			}
 		}
 	}
-
+	game.controller->init_doors();
 	//game.world.insert_entity(game.controller);
 
 #ifdef CONF_DEBUG
Index: src/game/tuning.hpp
===================================================================
--- src/game/tuning.hpp	(Revision 1952)
+++ src/game/tuning.hpp	(Arbeitskopie)
@@ -13,6 +13,11 @@
 MACRO_TUNING_PARAM(hook_drag_speed, 15.0f)
 MACRO_TUNING_PARAM(gravity, 0.5f)
 
+//MACRO_TUNING_PARAM(water_control_speed, 5.0f / ticks_per_second)
+//MACRO_TUNING_PARAM(water_control_accel, 1.0f)
+//MACRO_TUNING_PARAM(water_friction, 0.7f)
+//MACRO_TUNING_PARAM(water_gravity, 0.25f)
+
 MACRO_TUNING_PARAM(velramp_start, 550)
 MACRO_TUNING_PARAM(velramp_range, 2000)
 MACRO_TUNING_PARAM(velramp_curvature, 1.4f)
Index: src/game/variables.hpp
===================================================================
--- src/game/variables.hpp	(Revision 1952)
+++ src/game/variables.hpp	(Arbeitskopie)
@@ -71,3 +71,21 @@
 
 MACRO_CONFIG_INT(dbg_focus, 0, 0, 1, CFGFLAG_CLIENT, "")
 MACRO_CONFIG_INT(dbg_tuning, 0, 0, 1, CFGFLAG_CLIENT, "")
+
+/* watermod */
+MACRO_CONFIG_INT(sv_water_gravity, 30, -10000, 10000, CFGFLAG_SERVER, "gravty")
+MACRO_CONFIG_INT(sv_water_maxx, 600, -10000, 10000, CFGFLAG_SERVER, "maxx")
+MACRO_CONFIG_INT(sv_water_maxy, 450, -10000, 10000, CFGFLAG_SERVER, "maxy")
+MACRO_CONFIG_INT(sv_water_friction, 90, -10000, 10000, CFGFLAG_SERVER, "friction")
+MACRO_CONFIG_INT(sv_water_insta, 1, 0, 1, CFGFLAG_SERVER, "insta gib")
+MACRO_CONFIG_INT(sv_water_strip, 1, 0, 1, CFGFLAG_SERVER, "if using insta gib, strip weapon first")
+MACRO_CONFIG_INT(sv_water_freezetime, 60, 0, 100000, CFGFLAG_SERVER, "if using insta gib, freeze time the hammer freezes you (50=1 sec, 100 = 2 sec, ...)")
+MACRO_CONFIG_INT(sv_water_oxygen, 1, 0, 1, CFGFLAG_SERVER, "use oxygen")
+MACRO_CONFIG_INT(sv_water_oxy_drain, 1300, -100000, 100000, CFGFLAG_SERVER, "oxygen drainage")
+MACRO_CONFIG_INT(sv_water_oxy_regen, 250, -100000, 100000, CFGFLAG_SERVER, "oxygen regeneration")
+MACRO_CONFIG_INT(sv_water_oxy_emoteid, 3, 0, 100000, CFGFLAG_SERVER, "emote id")
+MACRO_CONFIG_INT(sv_water_laserjump, 0, 0, 1, CFGFLAG_SERVER, "laser jumps =D")
+MACRO_CONFIG_INT(sv_water_kicktime, 10000, 0, 10000, CFGFLAG_SERVER, "auto kick time")
+MACRO_CONFIG_INT(sv_water_rambo, 0, 0, 1, CFGFLAG_SERVER, "easter egg")
+MACRO_CONFIG_INT(sv_water_gain, 100, 0, 100000, CFGFLAG_SERVER, "speed change when accelerated by water")
+MACRO_CONFIG_INT(sv_water_reflect, 1, 0, 1, CFGFLAG_SERVER, "reflect lasers by water")

