about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2008-03-16 22:32:17 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2008-03-16 22:32:17 +0000
commit4a3c2e2c8c3a8dee5828258f920f1c175e952cb0 (patch)
treee0fda9dfad5e605c0810c8f27d719078cd48fd63
parent727c9a3a3249deec1c5a96025e99c0c654e7ff80 (diff)
downloadzcatch-4a3c2e2c8c3a8dee5828258f920f1c175e952cb0.tar.gz
zcatch-4a3c2e2c8c3a8dee5828258f920f1c175e952cb0.zip
loads of fixes, skidding, velocity ramping and other stuff
-rw-r--r--datasrc/teewars.ds7
-rw-r--r--src/game/client/gc_client.cpp28
-rw-r--r--src/game/client/gc_client.h1
-rw-r--r--src/game/client/gc_effects.cpp54
-rw-r--r--src/game/client/gc_particles.cpp1
-rw-r--r--src/game/client/gc_render_obj.cpp45
-rw-r--r--src/game/g_game.cpp19
-rw-r--r--src/game/g_game.h7
-rw-r--r--src/game/g_protocol.def4
-rw-r--r--src/game/g_tuning.h15
-rw-r--r--src/game/server/gs_common.h2
-rw-r--r--src/game/server/gs_server.cpp108
12 files changed, 220 insertions, 71 deletions
diff --git a/datasrc/teewars.ds b/datasrc/teewars.ds
index bcc21edf..c3fd9353 100644
--- a/datasrc/teewars.ds
+++ b/datasrc/teewars.ds
@@ -118,6 +118,13 @@ sounds {
 		"data/audio/vo_teefault_spawn-06.wv"
 		"data/audio/vo_teefault_spawn-07.wv"
 	}
+	
+	player_skid {
+		"data/audio/sfx_skid-01.wv"
+		"data/audio/sfx_skid-02.wv"
+		"data/audio/sfx_skid-03.wv"
+		"data/audio/sfx_skid-04.wv"
+	}
 
 	tee_cry {
 		"data/audio/vo_teefault_cry-01.wv"
diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp
index 7b191fbf..2526ab83 100644
--- a/src/game/client/gc_client.cpp
+++ b/src/game/client/gc_client.cpp
@@ -1373,11 +1373,15 @@ void render_game()
 	{
 		gfx_mapscreen(0, 0, 300*gfx_screenaspect(), 300);
 		
-		float speed = distance(vec2(netobjects.local_prev_character->x, netobjects.local_prev_character->y),
-			vec2(netobjects.local_character->x, netobjects.local_character->y));
+		/*float speed = distance(vec2(netobjects.local_prev_character->x, netobjects.local_prev_character->y),
+			vec2(netobjects.local_character->x, netobjects.local_character->y));*/
+
+		float velspeed = length(vec2(netobjects.local_character->vx/256.0f, netobjects.local_character->vy/256.0f))*50;
+		
+		float ramp = velocity_ramp(velspeed, tuning.velramp_start, tuning.velramp_range, tuning.velramp_curvature);
 		
 		char buf[512];
-		str_format(buf, sizeof(buf), "%.2f %d", speed/2, netobj_num_corrections());
+		str_format(buf, sizeof(buf), "%.0f\n%.0f\n%.2f\n%d", velspeed, velspeed*ramp, ramp, netobj_num_corrections());
 		gfx_text(0, 150, 50, 12, buf, -1);
 	}
 
@@ -1481,6 +1485,24 @@ void render_game()
 				
 				count++;
 			}
+			
+			y = y+count*6;
+			
+			gfx_texture_set(-1);
+			gfx_blend_normal();
+			gfx_lines_begin();
+			float height = 50.0f;
+			float pv = 1;
+			for(int i = 0; i < 100; i++)
+			{
+				float speed = i/100.0f * 3000;
+				float ramp = velocity_ramp(speed, tuning.velramp_start, tuning.velramp_range, tuning.velramp_curvature);
+				float rampedspeed = (speed * ramp)/1000.0f;
+				gfx_lines_draw((i-1)*2, y+height-pv*height, i*2, y+height-rampedspeed*height);
+				//gfx_lines_draw((i-1)*2, 200, i*2, 200);
+				pv = rampedspeed;
+			}
+			gfx_lines_end();
 		}
 		
 		gfx_text_color(1,1,1,1);
diff --git a/src/game/client/gc_client.h b/src/game/client/gc_client.h
index e6145954..55a880ed 100644
--- a/src/game/client/gc_client.h
+++ b/src/game/client/gc_client.h
@@ -142,6 +142,7 @@ void effects_update();
 
 void effect_bullettrail(vec2 pos);
 void effect_smoketrail(vec2 pos, vec2 vel);
+void effect_skidtrail(vec2 pos, vec2 vel);
 void effect_explosion(vec2 pos);
 void effect_air_jump(vec2 pos);
 void effect_damage_indicator(vec2 pos, vec2 dir);
diff --git a/src/game/client/gc_effects.cpp b/src/game/client/gc_effects.cpp
index fcf7ac93..094392e5 100644
--- a/src/game/client/gc_effects.cpp
+++ b/src/game/client/gc_effects.cpp
@@ -2,7 +2,8 @@
 #include "gc_client.h"
 #include "../generated/gc_data.h"
 
-static bool add_trail = false;
+static bool add_50hz = false;
+static bool add_100hz = false;
 
 void effect_air_jump(vec2 pos)
 {
@@ -27,7 +28,7 @@ void effect_air_jump(vec2 pos)
 
 void effect_powerupshine(vec2 pos, vec2 size)
 {
-	if(!add_trail)
+	if(!add_50hz)
 		return;
 		
 	particle p;
@@ -48,7 +49,7 @@ void effect_powerupshine(vec2 pos, vec2 size)
 
 void effect_smoketrail(vec2 pos, vec2 vel)
 {
-	if(!add_trail)
+	if(!add_50hz)
 		return;
 		
 	particle p;
@@ -65,9 +66,28 @@ void effect_smoketrail(vec2 pos, vec2 vel)
 }
 
 
+void effect_skidtrail(vec2 pos, vec2 vel)
+{
+	if(!add_100hz)
+		return;
+	
+	particle p;
+	p.set_default();
+	p.spr = SPRITE_PART_SMOKE;
+	p.pos = pos;
+	p.vel = vel + random_dir()*50.0f;
+	p.life_span = 0.5f + frandom()*0.5f;
+	p.start_size = 24.0f + frandom()*12;
+	p.end_size = 0;
+	p.friction = 0.7f;
+	p.gravity = frandom()*-500.0f;
+	p.color = vec4(0.75f,0.75f,0.75f,1.0f);
+	particle_add(PARTGROUP_GENERAL, &p);	
+}
+
 void effect_bullettrail(vec2 pos)
 {
-	if(!add_trail)
+	if(!add_100hz)
 		return;
 		
 	particle p;
@@ -77,7 +97,7 @@ void effect_bullettrail(vec2 pos)
 	p.life_span = 0.25f + frandom()*0.25f;
 	p.start_size = 8.0f;
 	p.end_size = 0;
-	p.friction = 0.7;
+	p.friction = 0.7f;
 	particle_add(PARTGROUP_PROJECTILE_TRAIL, &p);
 }
 
@@ -170,14 +190,26 @@ void effect_explosion(vec2 pos)
 
 void effects_update()
 {
-	static float last_update = 0;
-	if(client_localtime()-last_update > 0.02f)
+	static float last_update_100hz = 0;
+	static float last_update_50hz = 0;
+
+	if(client_localtime()-last_update_100hz > 0.01f)
 	{
-		add_trail = true;
-		last_update = client_localtime();
-		flow_update();
+		add_100hz = true;
+		last_update_100hz = client_localtime();
 	}
 	else
-		add_trail = false;
+		add_100hz = false;
+
+	if(client_localtime()-last_update_50hz > 0.02f)
+	{
+		add_50hz = true;
+		last_update_50hz = client_localtime();
+	}
+	else
+		add_50hz = false;
+		
+	if(add_50hz)
+		flow_update();
 		
 }
diff --git a/src/game/client/gc_particles.cpp b/src/game/client/gc_particles.cpp
index bdeb26fd..a0b1ff92 100644
--- a/src/game/client/gc_particles.cpp
+++ b/src/game/client/gc_particles.cpp
@@ -107,6 +107,7 @@ void particle_update(float time_passed)
 					particles[first_free].prev_part = i;
 				particles[i].prev_part = -1;
 				particles[i].next_part = first_free;
+				first_free = i;
 			}
 			
 			i = next;
diff --git a/src/game/client/gc_render_obj.cpp b/src/game/client/gc_render_obj.cpp
index 73f58a85..839a5261 100644
--- a/src/game/client/gc_render_obj.cpp
+++ b/src/game/client/gc_render_obj.cpp
@@ -25,15 +25,29 @@ void render_projectile(const NETOBJ_PROJECTILE *current, int itemid)
 	gfx_quads_begin();
 
 	// get positions
-	float gravity = -400;
-	if(current->type != WEAPON_GRENADE)
-		gravity = -100;
+	float curvature = 0;
+	float speed = 0;
+	if(current->type == WEAPON_GRENADE)
+	{
+		curvature = tuning.grenade_curvature;
+		speed = tuning.grenade_speed;
+	}
+	else if(current->type == WEAPON_SHOTGUN)
+	{
+		curvature = tuning.shotgun_curvature;
+		speed = tuning.shotgun_speed;
+	}
+	else if(current->type == WEAPON_GUN)
+	{
+		curvature = tuning.gun_curvature;
+		speed = tuning.gun_speed;
+	}
 
 	float ct = (client_tick()-current->start_tick)/(float)SERVER_TICK_SPEED + client_ticktime()*1/(float)SERVER_TICK_SPEED;
 	vec2 startpos(current->x, current->y);
-	vec2 startvel(current->vx, current->vy);
-	vec2 pos = calc_pos(startpos, startvel, gravity, ct);
-	vec2 prevpos = calc_pos(startpos, startvel, gravity, ct-0.001f);
+	vec2 startvel(current->vx/100.0f, current->vy/100.0f);
+	vec2 pos = calc_pos(startpos, startvel, curvature, speed, ct);
+	vec2 prevpos = calc_pos(startpos, startvel, curvature, speed, ct-0.001f);
 
 	select_sprite(data->weapons[clamp(current->type, 0, NUM_WEAPONS-1)].sprite_proj);
 	vec2 vel = pos-prevpos;
@@ -295,6 +309,7 @@ void render_player(
 
 	bool stationary = player.vx < 1 && player.vx > -1;
 	bool inair = col_check_point(player.x, player.y+16) == 0;
+	bool want_other_dir = (player.wanted_direction == -1 && vel.x > 0) || (player.wanted_direction == 1 && vel.x < 0);
 
 	// evaluate animation
 	float walk_time = fmod(position.x, 100.0f)/100.0f;
@@ -305,7 +320,7 @@ void render_player(
 		anim_eval_add(&state, &data->animations[ANIM_INAIR], 0, 1.0f); // TODO: some sort of time here
 	else if(stationary)
 		anim_eval_add(&state, &data->animations[ANIM_IDLE], 0, 1.0f); // TODO: some sort of time here
-	else
+	else if(!want_other_dir)
 		anim_eval_add(&state, &data->animations[ANIM_WALK], walk_time, 1.0f);
 
 	if (player.weapon == WEAPON_HAMMER)
@@ -318,6 +333,22 @@ void render_player(
 		float a = clamp((client_tick()-player.attacktick+ticktime)/40.0f, 0.0f, 1.0f);
 		anim_eval_add(&state, &data->animations[ANIM_NINJA_SWING], a, 1.0f);
 	}
+	
+	// do skidding
+	if(!inair && want_other_dir && length(vec2(prev.vx/256.0f, prev.vy/256.0f)*50) > 500.0f)
+	{
+		static int64 skid_sound_time = 0;
+		if(time_get()-skid_sound_time > time_freq()/10)
+		{
+			snd_play_random(CHN_WORLD, SOUND_PLAYER_SKID, 0.25f, position);
+			skid_sound_time = time_get();
+		}
+		
+		effect_skidtrail(
+			position+vec2(-player.wanted_direction*6,12),
+			vec2(-player.wanted_direction*100*length(vel),-50)
+		);
+	}
 
 	// draw hook
 	if (prev.hook_state>0 && player.hook_state>0)
diff --git a/src/game/g_game.cpp b/src/game/g_game.cpp
index c87da2d4..f2ebadee 100644
--- a/src/game/g_game.cpp
+++ b/src/game/g_game.cpp
@@ -154,6 +154,17 @@ void move_box(vec2 *inout_pos, vec2 *inout_vel, vec2 size, float elasticity)
 	*inout_vel = vel;
 }
 
+float hermite_basis1(float v)
+{
+	return 2*v*v*v - 3*v*v+1;
+}
+
+float velocity_ramp(float value, float start, float range, float curvature)
+{
+	if(value < start)
+		return 1.0f;
+	return 1.0f/pow(curvature, (value-start)/range);
+}
 
 void player_core::reset()
 {
@@ -405,13 +416,17 @@ void player_core::tick()
 	}	
 
 	// clamp the velocity to something sane
-	if(length(vel) > world->tuning.terminal_velocity)
-		vel = normalize(vel) * world->tuning.terminal_velocity;
+	if(length(vel) > 6000)
+		vel = normalize(vel) * 6000;
 }
 
 void player_core::move()
 {
+	float rampvalue = velocity_ramp(length(vel)*50, world->tuning.velramp_start, world->tuning.velramp_range, world->tuning.velramp_curvature);
+	
+	vel.x = vel.x*rampvalue;
 	move_box(&pos, &vel, vec2(28.0f, 28.0f), 0);
+	vel.x = vel.x*(1.0f/rampvalue);
 }
 
 void player_core::write(NETOBJ_PLAYER_CORE *obj_core)
diff --git a/src/game/g_game.h b/src/game/g_game.h
index 3cb6639b..6b13fb7b 100644
--- a/src/game/g_game.h
+++ b/src/game/g_game.h
@@ -53,11 +53,12 @@ inline float get_angle(vec2 dir)
 }
 
 
-inline vec2 calc_pos(vec2 p, vec2 v, float gravity, float t)
+inline vec2 calc_pos(vec2 p, vec2 v, float curvature, float speed, float t)
 {
 	vec2 n;
+	t *= speed;
 	n.x = p.x + v.x*t;
-	n.y = p.y + v.y*t - gravity*(t*t);
+	n.y = p.y + v.y*t + curvature/10000*(t*t);
 	return n;
 }
 
@@ -88,7 +89,7 @@ inline T saturated_add(T min, T max, T current, T modifier)
 void move_point(vec2 *inout_pos, vec2 *inout_vel, float elasticity, int *bounces);
 void move_box(vec2 *inout_pos, vec2 *inout_vel, vec2 size, float elasticity);
 bool test_box(vec2 pos, vec2 size);
-
+float velocity_ramp(float value, float start, float range, float curvature);
 
 // hooking stuff
 enum
diff --git a/src/game/g_protocol.def b/src/game/g_protocol.def
index 75ae4012..53753d65 100644
--- a/src/game/g_protocol.def
+++ b/src/game/g_protocol.def
@@ -151,14 +151,16 @@ end
 object player_character extends player_core
 	range(0, NUM_PLAYERSTATES-1) player_state
 	
+	range(-1, 1) wanted_direction
+	
 	range(0, 10) health
 	range(0, 10) armor
 	range(0, 10) ammocount
-	range(0, 10) weaponstage
 
 	range(0, NUM_WEAPONS-1) weapon
 	range(0, NUM_EMOTES-1) emote
 	
+	range(0, 10) weaponstage
 	range(0, max_int) attacktick
 end
 
diff --git a/src/game/g_tuning.h b/src/game/g_tuning.h
index c2201889..b80398d4 100644
--- a/src/game/g_tuning.h
+++ b/src/game/g_tuning.h
@@ -12,15 +12,20 @@ MACRO_TUNING_PARAM(hook_fire_speed, 45.0f)
 MACRO_TUNING_PARAM(hook_drag_accel, 3.0f)
 MACRO_TUNING_PARAM(hook_drag_speed, 15.0f)
 MACRO_TUNING_PARAM(gravity, 0.5f)
-MACRO_TUNING_PARAM(terminal_velocity, 1000.0f / ticks_per_second)
+
+MACRO_TUNING_PARAM(velramp_start, 500)
+MACRO_TUNING_PARAM(velramp_range, 2000)
+MACRO_TUNING_PARAM(velramp_curvature, 1.5f)
 
 /* weapon tuning */
-MACRO_TUNING_PARAM(gun_speed, 30.0f)
+MACRO_TUNING_PARAM(gun_curvature, 1.5f)
+MACRO_TUNING_PARAM(gun_speed, 2200.0f)
 
-MACRO_TUNING_PARAM(shotgun_speed_center, 40.0f)
-MACRO_TUNING_PARAM(shotgun_speed_wide, 30.0f)
+MACRO_TUNING_PARAM(shotgun_curvature, 1.5f)
+MACRO_TUNING_PARAM(shotgun_speed, 2200.0f)
 
-MACRO_TUNING_PARAM(grenade_speed, 15.0f)
+MACRO_TUNING_PARAM(grenade_curvature, 7.0f)
+MACRO_TUNING_PARAM(grenade_speed, 900.0f)
 
 MACRO_TUNING_PARAM(laser_reach, 800.0f)
 MACRO_TUNING_PARAM(laser_bounce_delay, 150)
diff --git a/src/game/server/gs_common.h b/src/game/server/gs_common.h
index ffeadecf..0de81318 100644
--- a/src/game/server/gs_common.h
+++ b/src/game/server/gs_common.h
@@ -188,7 +188,7 @@ public:
 		PROJECTILE_FLAGS_EXPLODE = 1 << 0,
 	};
 	
-	vec2 vel;
+	vec2 direction;
 	entity *powner; // this is nasty, could be removed when client quits
 	int lifespan;
 	int owner;
diff --git a/src/game/server/gs_server.cpp b/src/game/server/gs_server.cpp
index f674ecfd..fa3f9925 100644
--- a/src/game/server/gs_server.cpp
+++ b/src/game/server/gs_server.cpp
@@ -24,6 +24,7 @@ void create_playerspawn(vec2 p);
 void create_death(vec2 p);
 void create_sound(vec2 pos, int sound, int mask=-1);
 class player *intersect_player(vec2 pos0, vec2 pos1, vec2 &new_pos, class entity *notthis = 0);
+class player *closest_player(vec2 pos, float radius, entity *notthis);
 
 game_world *world;
 
@@ -380,13 +381,13 @@ static input_count count_input(int prev, int cur)
 //////////////////////////////////////////////////
 // projectile
 //////////////////////////////////////////////////
-projectile::projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner,
+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->vel = vel * server_tickspeed(); // TODO: remove this
+	this->direction = normalize(dir);
 	this->lifespan = span;
 	this->owner = owner;
 	this->powner = powner;
@@ -407,14 +408,28 @@ void projectile::reset()
 
 void projectile::tick()
 {
-	float gravity = -400;
-	if(type != WEAPON_GRENADE)
-		gravity = -100;
+	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;
+	}
 	
 	float pt = (server_tick()-start_tick-1)/(float)server_tickspeed();
 	float ct = (server_tick()-start_tick)/(float)server_tickspeed();
-	vec2 prevpos = calc_pos(pos, vel, gravity, pt);
-	vec2 curpos = calc_pos(pos, vel, gravity, ct);
+	vec2 prevpos = calc_pos(pos, direction, curvature, speed, pt);
+	vec2 curpos = calc_pos(pos, direction, curvature, speed, ct);
 
 	lifespan--;
 	
@@ -432,7 +447,7 @@ void projectile::tick()
 			create_explosion(prevpos, owner, weapon, false);
 		else if (targetplayer)
 		{
-			targetplayer->take_damage(normalize(vel) * max(0.001f, force), damage, owner, weapon);
+			targetplayer->take_damage(direction * max(0.001f, force), damage, owner, weapon);
 		}
 
 		world->destroy_entity(this);
@@ -443,19 +458,21 @@ void projectile::fill_info(NETOBJ_PROJECTILE *proj)
 {
 	proj->x = (int)pos.x;
 	proj->y = (int)pos.y;
-	proj->vx = (int)vel.x;
-	proj->vy = (int)vel.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();
-	vec2 curpos = calc_pos(pos, vel, -7.5f*server_tickspeed(), ct);
+	/*float ct = (server_tick()-start_tick)/(float)server_tickspeed();*/
+	/*vec2 curpos = calc_pos(pos, vel, -7.5f*server_tickspeed(), ct);*/
 
-	if(distance(players[snapping_client].pos, curpos) > 1000.0f)
-		return;
+	/*if(distance(players[snapping_client].pos, curpos) > 1000.0f)
+		return;*/
+		
+	/* TODO: FIX ME */
 
 	NETOBJ_PROJECTILE *proj = (NETOBJ_PROJECTILE *)snap_new_item(NETOBJTYPE_PROJECTILE, id, sizeof(NETOBJ_PROJECTILE));
 	fill_info(proj);
@@ -989,7 +1006,7 @@ void player::fire_weapon()
 			projectile *proj = new projectile(WEAPON_GUN,
 				client_id,
 				pos+vec2(0,0),
-				direction*tuning.gun_speed,
+				direction,
 				server_tickspeed(),
 				this,
 				1, 0, 0, -1, WEAPON_GUN);
@@ -1013,7 +1030,7 @@ void player::fire_weapon()
 			projectile *proj = new projectile(WEAPON_GRENADE,
 				client_id,
 				pos+vec2(0,0),
-				direction*tuning.grenade_speed,
+				direction,
 				100,
 				this,
 				1, projectile::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE);
@@ -1043,13 +1060,12 @@ void player::fire_weapon()
 			{
 				float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f};
 				float a = get_angle(direction);
-				float v = 1.0f-fabs(i/(float)shotspread);
 				a += spreading[i+2];
-				float speed = mix((float)tuning.shotgun_speed_wide, (float)tuning.shotgun_speed_center, v);
+				/*float speed = mix((float)tuning.shotgun_speed_wide, (float)tuning.shotgun_speed_center, v);*/
 				projectile *proj = new projectile(WEAPON_SHOTGUN,
 					client_id,
 					pos+vec2(0,0),
-					vec2(cosf(a), sinf(a))*speed,
+					vec2(cosf(a), sinf(a)),
 					(int)(server_tickspeed()*0.25f),
 					this,
 					1, 0, 0, -1, WEAPON_SHOTGUN);
@@ -1622,9 +1638,17 @@ void player::snap(int snaping_client)
 		character->ammocount = weapons[active_weapon].ammo;
 		character->health = 0;
 		character->armor = 0;
+		
 		character->weapon = active_weapon;
 		character->attacktick = attack_tick;
 
+		character->wanted_direction = 0;
+		if(input.left && !input.right)
+			character->wanted_direction = -1;
+		else if(!input.left && input.right)
+			character->wanted_direction = 1;
+
+
 		if(client_id == snaping_client)
 		{
 			character->health = health;
@@ -1696,8 +1720,7 @@ void powerup::tick()
 			return;
 	}
 	// Check if a player intersected us
-	vec2 meh;
-	player* pplayer = intersect_player(pos, pos + vec2(0,16), meh, 0);
+	player* pplayer = closest_player(pos, 20.0f, 0);
 	if (pplayer)
 	{
 		// player picked us up, is someone was hooking us, let them go
@@ -1957,29 +1980,38 @@ player *intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity *notthis)
 	}
 	
 	return closest;
-	
-	/*
-	entity *ents[64];
-	vec2 dir = pos1 - pos0;
-	float radius = length(dir * 0.5f);
-	vec2 center = pos0 + dir * 0.5f;
-	const int types[] = {OBJTYPE_PLAYER_CHARACTER};
-	int num = world->find_entities(center, radius, ents, 64, types, 1);
-	for (int i = 0; i < num; i++)
+}
+
+
+player *closest_player(vec2 pos, float radius, entity *notthis)
+{
+	// Find other players
+	float closest_range = radius*2;
+	player *closest = 0;
+		
+	for(int i = 0; i < MAX_CLIENTS; i++)
 	{
-		// Check if entity is a player
-		if (ents[i] != notthis)
+		if(players[i].client_id < 0 || (entity *)&players[i] == notthis)
+			continue;
+			
+		if(!(players[i].flags&entity::FLAG_PHYSICS))
+			continue;
+
+		float len = distance(pos, players[i].pos);
+		if(len < player::phys_size+radius)
 		{
-			new_pos = ents[i]->pos;
-			return (player*)ents[i];
+			if(len < closest_range)
+			{
+				closest_range = len;
+				closest = &players[i];
+			}
 		}
 	}
-
-	return 0;*/
+	
+	return closest;
 }
 
 
-
 // TODO: should be more general
 
 	/*
@@ -2281,7 +2313,7 @@ static void con_broadcast(void *result, void *user_data)
 
 void mods_console_init()
 {
-	MACRO_REGISTER_COMMAND("tune", "s?i", con_tune_param, 0);
+	MACRO_REGISTER_COMMAND("tune", "si", con_tune_param, 0);
 	MACRO_REGISTER_COMMAND("tune_reset", "", con_tune_reset, 0);
 	MACRO_REGISTER_COMMAND("tune_dump", "", con_tune_dump, 0);