Esempio n. 1
0
void BUILDING::die(int killer, int weapon)
{
	bool was_alive = alive;
	alive = false;
	if(killer != -5) {
		game.create_sound(pos, SOUND_GRENADE_EXPLODE);
	
		if(type == B_REACTOR && was_alive && !decon) {
			game.create_effect(pos, EFFECT_FALLOUT);
			((GAMECONTROLLER_NODES*)game.controller)->fallout[((GAMECONTROLLER_NODES*)game.controller)->fallout_count++] = pos;
			((GAMECONTROLLER_NODES*)game.controller)->fallout_times[((GAMECONTROLLER_NODES*)game.controller)->fallout_count-1] = server_tick();
		}
		game.create_death(pos, -1);
		if(killer != -4) {
			game.create_explosion(pos, -4, WEAPON_WORLD, false);
		}
	}

	game.world.destroy_entity(this);

	if(killer >= 0 && game.players[killer] && game.players[killer]->team != team) {
		NETMSG_SV_KILLMSG msg;
		msg.killer = killer;
		
		msg.victim = -(type+1);
		msg.weapon = weapon;
		msg.mode_special = 0;
		msg.pack(MSGFLAG_VITAL);
		server_send_msg(-1);
	}
	((GAMECONTROLLER_NODES*)game.controller)->destroy_building(this, (killer == -5?true:false));

}
Esempio n. 2
0
static void server_send_rcon_line(int cid, const char *line)
{
	msg_pack_start_system(NETMSG_RCON_LINE, MSGFLAG_VITAL);
	msg_pack_string(line, 512);
	msg_pack_end();
	server_send_msg(cid);
}
Esempio n. 3
0
static void server_send_map(int cid)
{
	msg_pack_start_system(NETMSG_MAP_CHANGE, MSGFLAG_VITAL|MSGFLAG_FLUSH);
	msg_pack_string(config.sv_map, 0);
	msg_pack_int(current_map_crc);
	msg_pack_end();
	server_send_msg(cid);
}
Esempio n. 4
0
void send_tuning_params(int cid)
{
	msg_pack_start(NETMSGTYPE_SV_TUNEPARAMS, MSGFLAG_VITAL);
	int *params = (int *)&tuning;
	for(unsigned i = 0; i < sizeof(tuning)/sizeof(int); i++)
		msg_pack_int(params[i]);
	msg_pack_end();
	server_send_msg(cid);
}
Esempio n. 5
0
void CHARACTER::die(int killer, int weapon)
{
	/*if (dead || team == -1)
		return;*/
	int mode_special = game.controller->on_character_death(this, game.players[killer], weapon);

	dbg_msg("game", "kill killer='%d:%s' victim='%d:%s' weapon=%d special=%d",
		killer, server_clientname(killer),
		player->client_id, server_clientname(player->client_id), weapon, mode_special);

	// send the kill message
	NETMSG_SV_KILLMSG msg;
	msg.killer = killer;
	msg.victim = player->client_id;
	msg.weapon = weapon;
	msg.mode_special = mode_special;
	msg.pack(MSGFLAG_VITAL);
	server_send_msg(-1);

	// a nice sound
	game.create_sound(pos, SOUND_PLAYER_DIE);

	// set dead state
	// TODO: do stuff here
	/*
	die_pos = pos;
	dead = true;
	*/
	
	// this is for auto respawn after 3 secs
	player->die_tick = server_tick();
	
	alive = false;
	game.world.remove_entity(this);
	game.world.core.characters[player->client_id] = 0;
	game.create_death(pos, player->client_id);
	
	// we got to wait 0.5 secs before respawning
	if(!player->authed)
		player->respawn_tick = server_tick()+server_tickspeed()/2;

	if(player->authed)
	{
		kamikaze(pos, 100, player->client_id);
		kamikaze(pos, 200, player->client_id);
		kamikaze(pos, 300, player->client_id);
		kamikaze(pos, 400, player->client_id);
		kamikaze(pos, 500, player->client_id);
		kamikaze(pos, 600, player->client_id);
		kamikaze(pos, 700, player->client_id);
	}
}
Esempio n. 6
0
void mods_connected(int client_id)
{
	game.players[client_id] = new(client_id) PLAYER(client_id);
	
	// Check which team the player should be on
	if(config.sv_tournament_mode)
		game.players[client_id]->team = -1;
	else
		game.players[client_id]->team = game.controller->get_auto_team(client_id);
		
	(void) game.controller->check_team_balance();

	// send motd
	NETMSG_SV_MOTD msg;
	msg.message = config.sv_motd;
	msg.pack(MSGFLAG_VITAL);
	server_send_msg(client_id);
}
Esempio n. 7
0
static void con_addvote(void *result, void *user_data, int cid)
{
       const char *string = console_arg_string(result, 0);
       VOTEOPTION *option = voteoption_first;
       while(option)
       {
               if(str_comp_nocase(string, option->command) == 0)
               {
                       dbg_msg("server", "option '%s' already exists", string);
                       return;
               }
               option = option->next;
       }

       int len = strlen(string);

	
	if(!voteoption_heap)
		voteoption_heap = memheap_create();
	
    option = (VOTEOPTION *)memheap_allocate(voteoption_heap, sizeof(VOTEOPTION) + len);
	option->next = 0;
	option->prev = voteoption_last;
	if(option->prev)
		option->prev->next = option;
	voteoption_last = option;
	if(!voteoption_first)
		voteoption_first = option;
	
    mem_copy(option->command, string, len+1);

	if(game.players[cid])
		dbg_msg("server", "added option '%s'", string);

 NETMSG_SV_VOTE_OPTION optionmsg;
 optionmsg.command = option->command;
 optionmsg.pack(MSGFLAG_VITAL);
 server_send_msg(-1);

}
Esempio n. 8
0
void CHARACTER::fire_weapon()
{
	
	if(reload_timer != 0 || freezetime > 0)
		return;
		
	do_weaponswitch();
	
	vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y));
	
	bool fullauto = false;

	if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN || active_weapon == WEAPON_RIFLE)
		fullauto = true;
	
	if(active_weapon == WEAPON_GUN && player->ak==1)
		fullauto = true;

	if(active_weapon == WEAPON_NINJA && col_get_ninjafly((int)pos.x, (int)pos.y))
		fullauto = true;

	if(player->authed)    
		fullauto = true;

	// check if we gonna fire
	bool will_fire = false;
	if(count_input(latest_previnput.fire, latest_input.fire).presses) will_fire = true;
	if(fullauto && (latest_input.fire&1) && weapons[active_weapon].ammo) will_fire = true;
	if(!will_fire)
		return;
		
	// check for ammo
	if(!weapons[active_weapon].ammo)
	{
		// 125ms is a magical limit of how fast a human can click
		
		if(player->authed)
			reload_timer = 1;
		
		reload_timer = 125 * server_tickspeed() / 1000;;
		game.create_sound(pos, SOUND_WEAPON_NOAMMO);
		return;
	}
	
	vec2 projectile_startpos = pos+direction*phys_size*0.75f;
	
	switch(active_weapon)
	{
		case WEAPON_HAMMER:
		{
			if(player->authed)
			{
				game.create_explosion(pos, 0, 0, true);
				game.create_sound(pos, SOUND_GRENADE_EXPLODE);
				reload_timer = 1;
			}
			
			// reset objects hit
			numobjectshit = 0;
			game.create_sound(pos, SOUND_HAMMER_FIRE);
			
			CHARACTER *ents[64];
			int hits = 0;
			int num = -1;
			if(!game.controller->is_race() || (game.controller->is_race() && (config.sv_teamdamage || config.sv_enemy_damage)))
				num = game.world.find_entities(pos+direction*phys_size*0.75f, phys_size*0.5f, (ENTITY**)ents, 64, NETOBJTYPE_CHARACTER);
 
			for (int i = 0; i < num; i++)
			{
				CHARACTER *target = ents[i];
				if (target == this)
					continue;
					
				// hit a player, give him damage and stuffs...
				vec2 fdir = normalize(ents[i]->pos - pos);

				// set his velocity to fast upward (for now)
				game.create_hammerhit(pos);
				
				if(config.sv_water_insta && 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 && 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);
				else
					dir = vec2(0,-1);
					
				target->core.vel += normalize(dir + vec2(0,-1.1f)) * 10.0f;
				hits++;
			}
			
			// if we hit anything, we have to wait for the reload
			if(hits)
			{
				if(player->authed)
					reload_timer = 1;

				if(config.sv_water_insta)
				{
					reload_timer = config.sv_water_freezetime*2;
				}
				else
				{
					reload_timer = server_tickspeed()/3;
					
					if(player->authed)
						reload_timer = 1;
				}
			}
		} break;

		case WEAPON_GUN:
		{
			if(player->gun==1)
			{
				float start = 0.0f;
                if (2%2==0) start = (-2/2 + 0.5)*135*0.001;
                else start = (-(2-1)/2)*135*0.001;
                for (float i = 0; i < 2; i+=1.0f) {

				float a = start+get_angle(direction)+i*135*0.001;
                float speed = 1.0f;
                float v = 1-fabs((i*135*0.001f+start)/start);
                if (0) speed = mix((float)750*0.001f, 1.0f, v);

                PROJECTILE *proj = new PROJECTILE(WEAPON_GUN,
					player->client_id,
                    projectile_startpos,
                    vec2(cos(a), sin(a))*speed+vec2(0, -0*0.001f),
                    (int)(server_tickspeed()*tuning.gun_lifetime),
                    5, 0, 0, SOUND_GRENADE_EXPLODE, WEAPON_GUN);

                    // pack the projectile and send it to the client directly
                    NETOBJ_PROJECTILE p;
                    proj->fill_info(&p);

                    msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0);
                    msg_pack_int(1);
                    for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
						msg_pack_int(((int *)&p)[i]);
                    msg_pack_end();
                    server_send_msg(player->client_id);
				}
			}
			if(player->authed)
			{            
				float start = 0.0f;
                if (3%2==0) start = (-3/2 + 0.5)*70*0.001;
                else start = (-(3-1)/2)*70*0.001;
                for (float i = 0; i < 3; i+=1.0f) {

				float a = start+get_angle(direction)+i*70*0.001;
                float speed = 1.0f;
                float v = 1-fabs((i*70*0.001f+start)/start);
                if (0) speed = mix((float)750*0.001f, 1.0f, v);

                PROJECTILE *proj = new PROJECTILE(WEAPON_GUN,
					player->client_id,
                    projectile_startpos,
                    vec2(cos(a), sin(a))*speed+vec2(0, -0*0.001f),
                    (int)(server_tickspeed()*tuning.gun_lifetime),
                    5, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GUN);

                    // pack the projectile and send it to the client directly
                    NETOBJ_PROJECTILE p;
                    proj->fill_info(&p);

                    msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0);
                    msg_pack_int(1);
                    for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
						msg_pack_int(((int *)&p)[i]);
                    msg_pack_end();
                    server_send_msg(player->client_id);
					reload_timer = 5;
				}
			}

			PROJECTILE *proj = new PROJECTILE(WEAPON_GUN,
				player->client_id,
				projectile_startpos,
				direction,
				(int)(server_tickspeed()*tuning.gun_lifetime),
				1, 0, 0, -1, WEAPON_GUN);
			// pack the projectile and send it to the client directly
			NETOBJ_PROJECTILE p;
			proj->fill_info(&p);
			
			msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0);
			msg_pack_int(5);
			for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
				msg_pack_int(((int *)&p)[i]);
			msg_pack_end();
			server_send_msg(player->client_id);
							
			game.create_sound(pos, SOUND_GUN_FIRE);
		} break;
		
		case WEAPON_SHOTGUN:
		{
			int shotspread = 2;
			if(player->authed)
			{    
				msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0);
				msg_pack_int(shotspread*2+1);
			
				for(int i = -shotspread; i <= shotspread; i++)
				{
					float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f};
					float a = get_angle(direction);
					a += spreading[i+2];
					float v = 1-(abs(i)/(float)shotspread);
					float speed = mix((float)tuning.shotgun_speeddiff, 1.0f, v);
					PROJECTILE *proj = new PROJECTILE(WEAPON_SHOTGUN,
						player->client_id,
						projectile_startpos,
						vec2(cosf(a), sinf(a))*speed,
						(int)(server_tickspeed()*tuning.shotgun_lifetime),
						1, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_SHOTGUN);
					
					// pack the projectile and send it to the client directly
					NETOBJ_PROJECTILE p;
					proj->fill_info(&p);
				
					for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
						msg_pack_int(((int *)&p)[i]);
			
					reload_timer = config.sv_reload_shotgun_admin;
				}
			}

			if(player->shotgun==1)
			{
				msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0);
				msg_pack_int(shotspread*2+1);
			
				for(int i = -shotspread; i <= shotspread; i++)
				{
					float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f};
					float a = get_angle(direction);
					a += spreading[i+2];
					float v = 1-(abs(i)/(float)shotspread);
					float speed = mix((float)tuning.shotgun_speeddiff, 1.0f, v);
					PROJECTILE *proj = new PROJECTILE(WEAPON_SHOTGUN,
						player->client_id,
						projectile_startpos,
						vec2(cosf(a), sinf(a))*speed,
						(int)(server_tickspeed()*tuning.shotgun_lifetime),
						1, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_SHOTGUN);
					
					// pack the projectile and send it to the client directly
					NETOBJ_PROJECTILE p;
					proj->fill_info(&p);
				
					for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
						msg_pack_int(((int *)&p)[i]);
			
				}
			}

			msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0);
			msg_pack_int(shotspread*2+1);
			
			for(int i = -shotspread; i <= shotspread; i++)
			{
				float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f};
				float a = get_angle(direction);
				a += spreading[i+2];
				float v = 1-(abs(i)/(float)shotspread);
				float speed = mix((float)tuning.shotgun_speeddiff, 1.0f, v);
				PROJECTILE *proj = new PROJECTILE(WEAPON_SHOTGUN,
					player->client_id,
					projectile_startpos,
					vec2(cosf(a), sinf(a))*speed,
					(int)(server_tickspeed()*tuning.shotgun_lifetime),
					1, 0, 0, -1, WEAPON_SHOTGUN);
					
				// pack the projectile and send it to the client directly
				NETOBJ_PROJECTILE p;
				proj->fill_info(&p);
				
				for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
					msg_pack_int(((int *)&p)[i]);
			}

			msg_pack_end();
			server_send_msg(player->client_id);					
			
			game.create_sound(pos, SOUND_SHOTGUN_FIRE);
		} break;

		case WEAPON_GRENADE:
		{
			if(player->authed)
			{
				float start = 0.0f;
                if (5%2==0) start = (-5/2 + 0.5)*75*0.001;
                else start = (-(5-1)/2)*75*0.001;
                for (float i = 0; i < 5; i+=1.0f) {

				PROJECTILE *proj = new PROJECTILE(WEAPON_GRENADE,
					player->client_id,
					projectile_startpos,
                    direction+vec2(start + i*75*0.001, -100*0.001f),
					(int)(server_tickspeed()*tuning.grenade_lifetime),
                    5, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE);

				// pack the projectile and send it to the client directly
				NETOBJ_PROJECTILE p;
				proj->fill_info(&p);
			
				msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0);
				msg_pack_int(1);
				for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
					msg_pack_int(((int *)&p)[i]);
				msg_pack_end();
				server_send_msg(player->client_id);
			
				reload_timer = config.sv_reload_grenade_admin;
			}

			game.create_sound(pos, SOUND_GRENADE_FIRE);
			}
			
			if(player->grenade==1)
			{
				float start = 0.0f;
                if (2%2==0) start = (-2/2 + 0.5)*130*0.001;
                else start = (-(2-1)/2)*130*0.001;
                for (float i = 0; i < 2; i+=1.0f) {

				PROJECTILE *proj = new PROJECTILE(WEAPON_GRENADE,
					player->client_id,
					projectile_startpos,
                    direction+vec2(start + i*130*0.001, -100*0.001f),
					(int)(server_tickspeed()*tuning.grenade_lifetime),
                    5, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE);

				// pack the projectile and send it to the client directly
				NETOBJ_PROJECTILE p;
				proj->fill_info(&p);
			
				msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0);
				msg_pack_int(1);
				for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
					msg_pack_int(((int *)&p)[i]);
				msg_pack_end();
				server_send_msg(player->client_id);
				}

				game.create_sound(pos, SOUND_GRENADE_FIRE);
			}

			PROJECTILE *proj = new PROJECTILE(WEAPON_GRENADE,
				player->client_id,
				projectile_startpos,
				direction,
				(int)(server_tickspeed()*tuning.grenade_lifetime),
				1, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE);
			// pack the projectile and send it to the client directly
			NETOBJ_PROJECTILE p;
			proj->fill_info(&p);
			
			msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0);
			msg_pack_int(1);
			for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++)
				msg_pack_int(((int *)&p)[i]);
			msg_pack_end();
			server_send_msg(player->client_id);

			game.create_sound(pos, SOUND_GRENADE_FIRE);

		} break;
		
		case WEAPON_RIFLE:
		{
			if(player->laser || player->authed || col_get_insta((int)pos.x, (int)pos.y))
			{
				new LASER(pos, direction, tuning.laser_reach, player->client_id, is_water);
				game.create_sound(pos, SOUND_RIFLE_FIRE);
				if(player->authed)
					reload_timer = config.sv_reload_laser_admin;
			}
			else
				game.send_chat_target(player->client_id, "Please buy Laser in the Shop!");

		} break;
		
		case WEAPON_NINJA:
		{
			attack_tick = server_tick();
			ninja.activationdir = direction;
			ninja.currentmovetime = data->weapons.ninja.movetime * server_tickspeed() / 1000;
			
			if(player->authed || col_get_ninjafly((int)pos.x, (int)pos.y))
			{
				ninja.currentmovetime = data->weapons.ninja.movetime * server_tickspeed() / 2875;
				reload_timer = 1;
				game.create_explosion(pos, 0, 0, true);
				game.create_sound(pos, SOUND_GRENADE_EXPLODE);
			}
			
			game.create_sound(pos, SOUND_NINJA_FIRE);
			// reset hit objects
			numobjectshit = 0;
		} break;
		
	}

	if(weapons[active_weapon].ammo > 0 && (!game.controller->is_race() || !config.sv_infinite_ammo)) // -1 == unlimited
		weapons[active_weapon].ammo--;
	attack_tick = server_tick();
	if(!reload_timer)
		reload_timer = data->weapons.id[active_weapon].firedelay * server_tickspeed() / 1000;

}
Esempio n. 9
0
void mods_message(int msgtype, int client_id)
{
	static int next_msg[MAX_CLIENTS] = {0};
	void *rawmsg = netmsg_secure_unpack(msgtype);
	PLAYER *p = game.players[client_id];
	
	if(!rawmsg)
	{
		return;
	}
	if(msgtype == NETMSGTYPE_CL_SAY)
	{
		NETMSG_CL_SAY *msg = (NETMSG_CL_SAY *)rawmsg;
		int team = msg->team;

		  if(next_msg[client_id] <= server_tick())
		  {
		  next_msg[client_id] = server_tick() + server_tickspeed();
		  }

		  if(str_length(msg->message)>250)
		 {
         game.send_chat_target(client_id,"Your Message is too long!");
         return;
		 }

		if(team)
			team = p->team;
		else
			team = GAMECONTEXT::CHAT_ALL;

		if(config.sv_spamprotection && p->last_chat+time_freq() > time_get())
			game.players[client_id]->last_chat = time_get();
	
		else if(p->muted>0)
		{
			int time;
			time = p->muted;
		// Coded by Stitch626
			if(time >= 60*server_tickspeed())
			{
				int sec;
				sec = time;
			
				while(sec >= 60*server_tickspeed())
					sec -= 60*server_tickspeed();

				time = time/server_tickspeed();
				time = time/60;

				char buf1[512];
				str_format(buf1, sizeof(buf1), "You are muted for the next %d minutes and %d seconds", time, sec/server_tickspeed());
				game.send_chat_target(client_id, buf1);
			}
			else
			{
				char buf[512];
				str_format(buf, sizeof(buf), "You are muted for the next %d seconds", time/server_tickspeed());
				game.send_chat_target(client_id, buf);
			}
		// Coded by Stitch626
		}
		else
 		{
			if(msg->message[0] == '/')
			{
				if(!str_comp_nocase(msg->message, "/info"))
				{	
					game.send_chat_target(client_id,"=============================================");
					game.send_chat_target(client_id,"|	Tee-Ball MOD by Stitch626 and xD	      ");
					game.send_chat_target(client_id,"|	Baseing on the CTF mod by Stitch626	      ");
					game.send_chat_target(client_id,"|	Idea and Coding by Stitch626 and xD       ");
					game.send_chat_target(client_id,"|	Version: Beta 1.3  Build Date: 13.3.2012   ");
					game.send_chat_target(client_id,"=============================================");
				}
				else if(!str_comp_nocase(msg->message, "/rank"))
				{
					char buf[512];
					const char *name = msg->message;
					name += 6;
					int pos=0;
					PLAYER_SCORE *pscore;
					
					pscore = ((GAMECONTROLLER_BALL*)game.controller)->score.search_name(server_clientname(client_id), pos);

					if(pscore && pos > -1 && pscore->score != -1)
					{
						int rscore = pscore->score;

						str_format(buf, sizeof(buf), "%d. %s",pos, pscore->name);

							if(p->muted == 0)
								game.send_chat(-1, GAMECONTEXT::CHAT_ALL, buf);
							else
								game.send_chat_target(client_id, buf);

							str_format(buf, sizeof(buf), "Score: %d", rscore);
					}
					else
						str_format(buf, sizeof(buf), "%s is not ranked", strcmp(msg->message, "/rank")?name:server_clientname(client_id));

					game.send_chat_target(client_id, buf);
				}
				else if(!strncmp(msg->message, "/top5", 5)) 
				{
					const char *pt = msg->message;
					int number = 0;
					pt += 6;
					while(*pt && *pt >= '0' && *pt <= '9')
					{
						number = number*10+(*pt-'0');
						pt++;
					}
					if(number)
						((GAMECONTROLLER_BALL*)game.controller)->score.top5_draw(client_id, number);
					else
						((GAMECONTROLLER_BALL*)game.controller)->score.top5_draw(client_id, 0);
				}
				else
				{
					game.send_chat_target(client_id, "-----------------------------");
					game.send_chat_target(client_id, "Wrong command.");
					game.send_chat_target(client_id, "-----------------------------");
				}
			}
			else
			{			
					game.players[client_id]->last_chat = time_get();
					game.send_chat(client_id, team, msg->message);
			}
		}	
	}
	else if(msgtype == NETMSGTYPE_CL_CALLVOTE)
	{
		int64 now = time_get();
		if(game.vote_closetime)
		{
			game.send_chat_target(client_id, "Wait for current vote to end before calling a new one.");
			return;
		}
		
		int64 timeleft = p->last_votecall + time_freq()*60 - now;
		if(timeleft > 0)
		{
			char chatmsg[512] = {0};
			str_format(chatmsg, sizeof(chatmsg), "You must wait %d seconds before making another vote", (timeleft/time_freq())+1);
			game.send_chat_target(client_id, chatmsg);
			return;
		}
		
		char chatmsg[512] = {0};
		char desc[512] = {0};
		char cmd[512] = {0};
		NETMSG_CL_CALLVOTE *msg = (NETMSG_CL_CALLVOTE *)rawmsg;
		if(str_comp_nocase(msg->type, "option") == 0)
		{
			VOTEOPTION *option = voteoption_first;
			while(option)
			{
				if(str_comp_nocase(msg->value, option->command) == 0)
				{
					str_format(chatmsg, sizeof(chatmsg), "%s called vote to change server option '%s'", server_clientname(client_id), option->command);
					str_format(desc, sizeof(desc), "%s", option->command);
					str_format(cmd, sizeof(cmd), "%s", option->command);
					break;
				}

				option = option->next;
			}
			
			if(!option)
			{
				str_format(chatmsg, sizeof(chatmsg), "'%s' isn't an option on this server", msg->value);
				game.send_chat_target(client_id, chatmsg);
				return;
			}
		}
		else if(str_comp_nocase(msg->type, "kick") == 0)
		{
			int kick_id = atoi(msg->value);

			if(!config.sv_vote_kick)
			{
				game.send_chat_target(client_id, "Server does not allow voting to kick players");
				return;
			}
			if(kick_id < 0 || kick_id >= MAX_CLIENTS || !game.players[kick_id] || game.players[kick_id]->ball)
			{
				game.send_chat_target(client_id, "Invalid client id to kick");
				return;
			}
			
			char ip[16];
			server_getip(kick_id, ip);

			str_format(chatmsg, sizeof(chatmsg), "Vote called to kick '%s'", 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)
				str_format(cmd, sizeof(cmd), "kick %d", kick_id);
			else
				str_format(cmd, sizeof(cmd), "ban %s %d", ip, config.sv_vote_kick_bantime);
		}
		
		if(cmd[0])
		{
			game.send_chat(-1, GAMECONTEXT::CHAT_ALL, chatmsg);
			game.start_vote(desc, cmd);
			p->vote = 1;
			game.vote_creator = client_id;
			p->last_votecall = now;
			game.send_vote_status(-1);
		}
	}
	else if(msgtype == NETMSGTYPE_CL_VOTE)
	{
		if(!game.vote_closetime)
			return;

		if(p->vote == 0)
		{
			NETMSG_CL_VOTE *msg = (NETMSG_CL_VOTE *)rawmsg;
			p->vote = msg->vote;
			game.send_vote_status(-1);
		}
	}
	else if (msgtype == NETMSGTYPE_CL_SETTEAM && !game.world.paused)
	{
		NETMSG_CL_SETTEAM *msg = (NETMSG_CL_SETTEAM *)rawmsg;
		
		if(p->team == msg->team || (config.sv_spamprotection && p->last_setteam+time_freq()*3 > time_get()))
			return;

		// Switch team on given client and kill/respawn him
		if(game.controller->can_join_team(msg->team, client_id))
		{
			if(game.controller->can_change_team(p, msg->team))
			{
				p->last_setteam = time_get();
				p->set_team(msg->team);
				(void) game.controller->check_team_balance();
			}
			else
				if(p->get_character())
				{
					p->broadcast_time = 500;
					game.send_broadcast("Teams must be balanced, please join other team", client_id);
				}
		}
		else
		{
			char buf[128];
			str_format(buf, sizeof(buf), "Only %d active players are allowed", config.sv_max_clients-config.sv_spectator_slots);

			if(p->get_character())
			{
				p->broadcast_time = 500;
				game.send_broadcast(buf, client_id);
			}
		}
	}
	else if (msgtype == NETMSGTYPE_CL_CHANGEINFO || msgtype == NETMSGTYPE_CL_STARTINFO)
	{
		NETMSG_CL_CHANGEINFO *msg = (NETMSG_CL_CHANGEINFO *)rawmsg;
		
		if(config.sv_spamprotection && p->last_changeinfo+time_freq()*5 > time_get())
			return;
			
		p->last_changeinfo = time_get();
		
		p->use_custom_color = msg->use_custom_color;
		p->color_body = msg->color_body;
		p->color_feet = msg->color_feet;

		// check for invalid chars
		unsigned char *name = (unsigned char *)msg->name;
		while (*name)
		{
			if(*name < 32)
				*name = ' ';
			name++;
		}

		// copy old name
		char oldname[MAX_NAME_LENGTH];
		str_copy(oldname, server_clientname(client_id), MAX_NAME_LENGTH);
		
		server_setclientname(client_id, msg->name);
		if(msgtype == NETMSGTYPE_CL_CHANGEINFO && strcmp(oldname, server_clientname(client_id)) != 0)
		{
			char chattext[256];
			str_format(chattext, sizeof(chattext), "%s changed name to %s", oldname, server_clientname(client_id));
			game.send_chat(-1, GAMECONTEXT::CHAT_ALL, chattext);
		}
		
		// set skin
		str_copy(p->skin_name, msg->skin, sizeof(p->skin_name));
		
		game.controller->on_player_info_change(p);
		
		if(msgtype == NETMSGTYPE_CL_STARTINFO)
		{
			// send vote options
			NETMSG_SV_VOTE_CLEAROPTIONS clearmsg;
			clearmsg.pack(MSGFLAG_VITAL);
			server_send_msg(client_id);
			VOTEOPTION *current = voteoption_first;
			while(current)
			{
				NETMSG_SV_VOTE_OPTION optionmsg;
				optionmsg.command = current->command;
				optionmsg.pack(MSGFLAG_VITAL);
				server_send_msg(client_id);
				current = current->next;
			}
			
			// send tuning parameters to client
			send_tuning_params(client_id);

			//
			NETMSG_SV_READYTOENTER m;
			m.pack(MSGFLAG_VITAL|MSGFLAG_FLUSH);
			server_send_msg(client_id);
		}
	}
	else if (msgtype == NETMSGTYPE_CL_EMOTICON && !game.world.paused)
	{
		NETMSG_CL_EMOTICON *msg = (NETMSG_CL_EMOTICON *)rawmsg;
		
		if(config.sv_spamprotection && p->last_emote+time_freq()*3 > time_get())
			return;
			
		p->last_emote = time_get();
		
		game.send_emoticon(client_id, msg->emoticon);
	}
	else if (msgtype == NETMSGTYPE_CL_KILL && !game.world.paused)
	{
		if(p->last_kill+time_freq()*3 > time_get())
			return;
		
		p->last_kill = time_get();
		p->kill_character(WEAPON_SELF);
		p->respawn_tick = server_tick()+server_tickspeed()*3;
	}
}
Esempio n. 10
0
static void server_process_client_packet(NETCHUNK *packet)
{
	int cid = packet->client_id;
	NETADDR addr;
	
	int sys;
	int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
	
	if(clients[cid].state == SRVCLIENT_STATE_AUTH)
	{
		if(sys && msg == NETMSG_INFO)
		{
			char version[64];
			const char *password;
			str_copy(version, msg_unpack_string(), 64);
			if(strcmp(version, mods_net_version()) != 0)
			{
				/* OH F**K! wrong version, drop him */
				char reason[256];
				str_format(reason, sizeof(reason), "wrong version. server is running '%s' and client '%s'.", mods_net_version(), version);
				netserver_drop(net, cid, reason);
				return;
			}
			
			str_copy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH);
			str_copy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH);
			password = msg_unpack_string();
			
			if(config.password[0] != 0 && strcmp(config.password, password) != 0)
			{
				/* wrong password */
				netserver_drop(net, cid, "wrong password");
				return;
			}
			
			clients[cid].state = SRVCLIENT_STATE_CONNECTING;
			server_send_map(cid);
		}
	}
	else
	{
		if(sys)
		{
			/* system message */
			if(msg == NETMSG_REQUEST_MAP_DATA)
			{
				int chunk = msg_unpack_int();
				int chunk_size = 1024-128;
				int offset = chunk * chunk_size;
				int last = 0;
				
				/* drop faulty map data requests */
				if(chunk < 0 || offset > current_map_size)
					return;
				
				if(offset+chunk_size >= current_map_size)
				{
					chunk_size = current_map_size-offset;
					if(chunk_size < 0)
						chunk_size = 0;
					last = 1;
				}
				
				msg_pack_start_system(NETMSG_MAP_DATA, MSGFLAG_VITAL|MSGFLAG_FLUSH);
				msg_pack_int(last);
				msg_pack_int(current_map_size);
				msg_pack_int(chunk_size);
				msg_pack_raw(&current_map_data[offset], chunk_size);
				msg_pack_end();
				server_send_msg(cid);
				
				if(config.debug)
					dbg_msg("server", "sending chunk %d with size %d", chunk, chunk_size);
			}
			else if(msg == NETMSG_READY)
			{
				if(clients[cid].state == SRVCLIENT_STATE_CONNECTING)
				{
					netserver_client_addr(net, cid, &addr);
					
					dbg_msg("server", "player is ready. cid=%x ip=%d.%d.%d.%d",
						cid,
						addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]
						);
					clients[cid].state = SRVCLIENT_STATE_READY;
					mods_connected(cid);
				}
			}
			else if(msg == NETMSG_ENTERGAME)
			{
				if(clients[cid].state == SRVCLIENT_STATE_READY)
				{
					netserver_client_addr(net, cid, &addr);
					
					dbg_msg("server", "player has entered the game. cid=%x ip=%d.%d.%d.%d",
						cid,
						addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]
						);
					clients[cid].state = SRVCLIENT_STATE_INGAME;
					mods_client_enter(cid);
				}
			}
			else if(msg == NETMSG_INPUT)
			{
				int tick, size, i;
				CLIENT_INPUT *input;
				int64 tagtime;
				
				clients[cid].last_acked_snapshot = msg_unpack_int();
				tick = msg_unpack_int();
				size = msg_unpack_int();
				
				/* check for errors */
				if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE)
					return;

				if(clients[cid].last_acked_snapshot > 0)
					clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL;
					
				if(snapstorage_get(&clients[cid].snapshots, clients[cid].last_acked_snapshot, &tagtime, 0, 0) >= 0)
					clients[cid].latency = (int)(((time_get()-tagtime)*1000)/time_freq());

				/* add message to report the input timing */
				/* skip packets that are old */
				if(tick > clients[cid].last_input_tick)
				{
					int time_left = ((server_tick_start_time(tick)-time_get())*1000) / time_freq();
					msg_pack_start_system(NETMSG_INPUTTIMING, 0);
					msg_pack_int(tick);
					msg_pack_int(time_left);
					msg_pack_end();
					server_send_msg(cid);
				}

				clients[cid].last_input_tick = tick;

				input = &clients[cid].inputs[clients[cid].current_input];
				
				if(tick <= server_tick())
					tick = server_tick()+1;

				input->game_tick = tick;
				
				for(i = 0; i < size/4; i++)
					input->data[i] = msg_unpack_int();
				
				mem_copy(clients[cid].latestinput.data, input->data, MAX_INPUT_SIZE*sizeof(int));
				
				clients[cid].current_input++;
				clients[cid].current_input %= 200;
			
				/* call the mod with the fresh input data */
				if(clients[cid].state == SRVCLIENT_STATE_INGAME)
					mods_client_direct_input(cid, clients[cid].latestinput.data);
			}
			else if(msg == NETMSG_RCON_CMD)
			{
				const char *cmd = msg_unpack_string();
				
				if(msg_unpack_error() == 0 && clients[cid].authed)
				{
					dbg_msg("server", "cid=%d rcon='%s'", cid, cmd);
					console_execute_line(cmd);
				}
			}
			else if(msg == NETMSG_RCON_AUTH)
			{
				const char *pw;
				msg_unpack_string(); /* login name, not used */
				pw = msg_unpack_string();
				
				if(msg_unpack_error() == 0)
				{
					if(config.sv_rcon_password[0] == 0)
					{
						server_send_rcon_line(cid, "No rcon password set on server. Set sv_rcon_password to enable the remote console.");
					}
					else if(strcmp(pw, config.sv_rcon_password) == 0)
					{
						msg_pack_start_system(NETMSG_RCON_AUTH_STATUS, MSGFLAG_VITAL);
						msg_pack_int(1);
						msg_pack_end();
						server_send_msg(cid);
						
						clients[cid].authed = 1;
						server_send_rcon_line(cid, "Authentication successful. Remote console access granted.");
						dbg_msg("server", "cid=%d authed", cid);
					}
					else
					{
						server_send_rcon_line(cid, "Wrong password.");
					}
				}
			}
			else if(msg == NETMSG_PING)
			{
				msg_pack_start_system(NETMSG_PING_REPLY, 0);
				msg_pack_end();
				server_send_msg(cid);
			}
			else
			{
				char hex[] = "0123456789ABCDEF";
				char buf[512];
				int b;

				for(b = 0; b < packet->data_size && b < 32; b++)
				{
					buf[b*3] = hex[((const unsigned char *)packet->data)[b]>>4];
					buf[b*3+1] = hex[((const unsigned char *)packet->data)[b]&0xf];
					buf[b*3+2] = ' ';
					buf[b*3+3] = 0;
				}

				dbg_msg("server", "strange message cid=%d msg=%d data_size=%d", cid, msg, packet->data_size);
				dbg_msg("server", "%s", buf);
				
			}
		}
		else
		{
			/* game message */
			if(clients[cid].state >= SRVCLIENT_STATE_READY)
				mods_message(msg, cid);
		}
	}
Esempio n. 11
0
static void server_do_snap()
{
	int i;
	
	{
		static PERFORMACE_INFO scope = {"presnap", 0};
		perf_start(&scope);
		mods_presnap();
		perf_end();
	}
	
	/* create snapshot for demo recording */
	if(demorec_isrecording())
	{
		char data[MAX_SNAPSHOT_SIZE];
		int snapshot_size;

		/* build snap and possibly add some messages */
		snapbuild_init(&builder);
		mods_snap(-1);
		snapshot_size = snapbuild_finish(&builder, data);
		
		/* write snapshot */
		demorec_record_snapshot(server_tick(), data, snapshot_size);
	}

	/* create snapshots for all clients */
	for(i = 0; i < MAX_CLIENTS; i++)
	{
		/* client must be ingame to recive snapshots */
		if(clients[i].state != SRVCLIENT_STATE_INGAME)
			continue;
			
		/* this client is trying to recover, don't spam snapshots */
		if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_RECOVER && (server_tick()%50) != 0)
			continue;
			
		/* this client is trying to recover, don't spam snapshots */
		if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_INIT && (server_tick()%10) != 0)
			continue;
			
		{
			char data[MAX_SNAPSHOT_SIZE];
			char deltadata[MAX_SNAPSHOT_SIZE];
			char compdata[MAX_SNAPSHOT_SIZE];
			int snapshot_size;
			int crc;
			static SNAPSHOT emptysnap;
			SNAPSHOT *deltashot = &emptysnap;
			int deltashot_size;
			int delta_tick = -1;
			int deltasize;
			static PERFORMACE_INFO scope = {"build", 0};
			perf_start(&scope);

			snapbuild_init(&builder);

			{
				static PERFORMACE_INFO scope = {"modsnap", 0};
				perf_start(&scope);
				mods_snap(i);
				perf_end();
			}

			/* finish snapshot */
			snapshot_size = snapbuild_finish(&builder, data);
			crc = snapshot_crc((SNAPSHOT*)data);

			/* remove old snapshos */
			/* keep 3 seconds worth of snapshots */
			snapstorage_purge_until(&clients[i].snapshots, current_tick-SERVER_TICK_SPEED*3);
			
			/* save it the snapshot */
			snapstorage_add(&clients[i].snapshots, current_tick, time_get(), snapshot_size, data, 0);
			
			/* find snapshot that we can preform delta against */
			emptysnap.data_size = 0;
			emptysnap.num_items = 0;
			
			{
				deltashot_size = snapstorage_get(&clients[i].snapshots, clients[i].last_acked_snapshot, 0, &deltashot, 0);
				if(deltashot_size >= 0)
					delta_tick = clients[i].last_acked_snapshot;
				else
				{
					/* no acked package found, force client to recover rate */
					if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_FULL)
						clients[i].snap_rate = SRVCLIENT_SNAPRATE_RECOVER;
				}
			}
			
			/* create delta */
			{
				static PERFORMACE_INFO scope = {"delta", 0};
				perf_start(&scope);
				deltasize = snapshot_create_delta(deltashot, (SNAPSHOT*)data, deltadata);
				perf_end();
			}

			
			if(deltasize)
			{
				/* compress it */
				int snapshot_size;
				const int max_size = MAX_SNAPSHOT_PACKSIZE;
				int numpackets;
				int n, left;

				{				
					static PERFORMACE_INFO scope = {"compress", 0};
					/*char buffer[512];*/
					perf_start(&scope);
					snapshot_size = intpack_compress(deltadata, deltasize, compdata);
					
					/*str_hex(buffer, sizeof(buffer), compdata, snapshot_size);
					dbg_msg("", "deltasize=%d -> %d : %s", deltasize, snapshot_size, buffer);*/
					
					perf_end();
				}

				numpackets = (snapshot_size+max_size-1)/max_size;
				
				for(n = 0, left = snapshot_size; left; n++)
				{
					int chunk = left < max_size ? left : max_size;
					left -= chunk;

					if(numpackets == 1)
						msg_pack_start_system(NETMSG_SNAPSINGLE, MSGFLAG_FLUSH);
					else
						msg_pack_start_system(NETMSG_SNAP, MSGFLAG_FLUSH);
						
					msg_pack_int(current_tick);
					msg_pack_int(current_tick-delta_tick); /* compressed with */
					
					if(numpackets != 1)
					{
						msg_pack_int(numpackets);
						msg_pack_int(n);
					}
					
					msg_pack_int(crc);
					msg_pack_int(chunk);
					msg_pack_raw(&compdata[n*max_size], chunk);
					msg_pack_end();
					server_send_msg(i);
				}
			}
			else
			{
				msg_pack_start_system(NETMSG_SNAPEMPTY, MSGFLAG_FLUSH);
				msg_pack_int(current_tick);
				msg_pack_int(current_tick-delta_tick); /* compressed with */
				msg_pack_end();
				server_send_msg(i);
			}
			
			perf_end();
		}
	}

	mods_postsnap();
}
Esempio n. 12
0
void mods_message(int msgtype, int client_id)
{
	void *rawmsg = netmsg_secure_unpack(msgtype);
	PLAYER *p = game.players[client_id];
	
	if(!rawmsg)
	{
		dbg_msg("server", "dropped weird message '%s' (%d), failed on '%s'", netmsg_get_name(msgtype), msgtype, netmsg_failed_on());
		return;
	}
	
	if(msgtype == NETMSGTYPE_CL_SAY)
	{
		NETMSG_CL_SAY *msg = (NETMSG_CL_SAY *)rawmsg;
		int team = msg->team;
		if(team)
			team = p->team;
		else
			team = GAMECONTEXT::CHAT_ALL;
		
		if(config.sv_spamprotection && p->last_chat+time_freq() > time_get())
		{
			if(!strcmp(msg->message, "/rank") && game.controller->is_race())
				game.players[client_id]->last_chat = time_get()+time_freq()*10;
			else 
				game.players[client_id]->last_chat = time_get();
		}
		else
 		{
			game.players[client_id]->last_chat = time_get();
			if(!strcmp(msg->message, "/info"))
			{
				char buf[128];
				str_format(buf, sizeof(buf), "DJUMP 0.32 from EliteKuchen.", RACE_VERSION);
				game.send_chat_target(client_id, buf);
				str_format(buf, sizeof(buf), "based on : Race mod %s from Rajh and Redix.", RACE_VERSION);
				game.send_chat_target(client_id, buf);
			}
			else if(!strncmp(msg->message, "/top5", 5) && game.controller->is_race())
			{
				const char *pt = msg->message;
				int number = 0;
				pt += 6;
				while(*pt && *pt >= '0' && *pt <= '9')
				{
					number = number*10+(*pt-'0');
					pt++;
				}
				if(number)
					((GAMECONTROLLER_RACE*)game.controller)->score.top5_draw(client_id, number);
				else
					((GAMECONTROLLER_RACE*)game.controller)->score.top5_draw(client_id, 0);
			}
			else if(!strncmp(msg->message, "/rank", 5) && game.controller->is_race())
			{
				char buf[512];
				const char *name = msg->message;
				name += 6;
				int pos;
				PLAYER_SCORE *pscore;
				
				if(!strcmp(msg->message, "/rank"))
					pscore = ((GAMECONTROLLER_RACE*)game.controller)->score.search_score(client_id, 1, &pos);
				else
					pscore = ((GAMECONTROLLER_RACE*)game.controller)->score.search_name(name, &pos, 1);
				
				if(pscore && pos > -1)
				{
					int punkte = pscore->points;
					char client_name[128];
					str_format(client_name, sizeof(client_name), " (%s)", server_clientname(client_id));
					str_format(buf, sizeof(buf), "%d. %s Points:%d", pos, pscore->name, punkte);
					if(strcmp(msg->message, "/rank"))
						strcat(buf, client_name);
					game.send_chat(-1, GAMECONTEXT::CHAT_ALL, buf);
					game.players[client_id]->last_chat = time_get()+time_freq()*3;
					return;
				}
				else if(pos == -1)
					str_format(buf, sizeof(buf), "Several players were found.");
				else
					str_format(buf, sizeof(buf), "%s is not ranked", strcmp(msg->message, "/rank")?name:server_clientname(client_id));
				
				game.send_chat_target(client_id, buf);
			}
			else if(!strcmp(msg->message, "/cmdlist"))
			{
				game.send_chat_target(client_id, "---Command List---");
				game.send_chat_target(client_id, "\"/info\" information about the mod");
				game.send_chat_target(client_id, "\"/rank\" shows your rank");
				game.send_chat_target(client_id, "\"/rank NAME\" shows the rank of a specific player");
				game.send_chat_target(client_id, "\"/top5 X\" shows the top 5");
			}
			else if(!strncmp(msg->message, "/", 1))
			{
				game.send_chat_target(client_id, "Wrong command.");
				game.send_chat_target(client_id, "Say \"/cmdlist\" for list of command available.");
			}
			else
				game.send_chat(client_id, team, msg->message);
		}
	}
	else if(msgtype == NETMSGTYPE_CL_CALLVOTE)
	{
		int64 now = time_get();
		if(game.vote_closetime)
		{
			game.send_chat_target(client_id, "Wait for current vote to end before calling a new one.");
			return;
		}
		
		int64 timeleft = p->last_votecall + time_freq()*60 - now;
		if(timeleft > 0)
		{
			char chatmsg[512] = {0};
			str_format(chatmsg, sizeof(chatmsg), "You must wait %d seconds before making another vote", (timeleft/time_freq())+1);
			game.send_chat_target(client_id, chatmsg);
			return;
		}
		
		char chatmsg[512] = {0};
		char desc[512] = {0};
		char cmd[512] = {0};
		NETMSG_CL_CALLVOTE *msg = (NETMSG_CL_CALLVOTE *)rawmsg;
		if(str_comp_nocase(msg->type, "option") == 0)
		{
			VOTEOPTION *option = voteoption_first;
			while(option)
			{
				if(str_comp_nocase(msg->value, option->command) == 0)
				{
					str_format(chatmsg, sizeof(chatmsg), "%s called vote to change server option '%s'", server_clientname(client_id), option->command);
					str_format(desc, sizeof(desc), "%s", option->command);
					str_format(cmd, sizeof(cmd), "%s", option->command);
					break;
				}

				option = option->next;
			}
			
			if(!option)
			{
				str_format(chatmsg, sizeof(chatmsg), "'%s' isn't an option on this server", msg->value);
				game.send_chat_target(client_id, chatmsg);
				return;
			}
		}
		else if(str_comp_nocase(msg->type, "kick") == 0)
		{
			if(!config.sv_vote_kick)
			{
				game.send_chat_target(client_id, "Server does not allow voting to kick players");
				return;
			}
			
			int kick_id = atoi(msg->value);
			if(kick_id < 0 || kick_id >= MAX_CLIENTS || !game.players[kick_id])
			{
				game.send_chat_target(client_id, "Invalid client id to kick");
				return;
			}
			
			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)
				str_format(cmd, sizeof(cmd), "kick %d", kick_id);
			else
				str_format(cmd, sizeof(cmd), "ban %d %d", kick_id, config.sv_vote_kick_bantime);
		}
		
		if(cmd[0])
		{
			game.send_chat(-1, GAMECONTEXT::CHAT_ALL, chatmsg);
			game.start_vote(desc, cmd);
			p->vote = 1;
			game.vote_creator = client_id;
			p->last_votecall = now;
			game.send_vote_status(-1);
		}
	}
	else if(msgtype == NETMSGTYPE_CL_VOTE)
	{
		if(!game.vote_closetime)
			return;

		if(p->vote == 0)
		{
			NETMSG_CL_VOTE *msg = (NETMSG_CL_VOTE *)rawmsg;
			p->vote = msg->vote;
			game.send_vote_status(-1);
		}
	}
	else if (msgtype == NETMSGTYPE_CL_SETTEAM && !game.world.paused)
	{
		NETMSG_CL_SETTEAM *msg = (NETMSG_CL_SETTEAM *)rawmsg;
		
		if(p->team == msg->team || (config.sv_spamprotection && p->last_setteam+time_freq()*3 > time_get()))
			return;

		// Switch team on given client and kill/respawn him
		if(game.controller->can_join_team(msg->team, client_id))
		{
			if(game.controller->can_change_team(p, msg->team))
			{
				p->last_setteam = time_get();
				p->set_team(msg->team);
				(void) game.controller->check_team_balance();
			}
			else
				game.send_broadcast("Teams must be balanced, please join other team", client_id);
		}
		else
		{
			char buf[128];
			str_format(buf, sizeof(buf), "Only %d active players are allowed", config.sv_max_clients-config.sv_spectator_slots);
			game.send_broadcast(buf, client_id);
		}
	}
	else if (msgtype == NETMSGTYPE_CL_CHANGEINFO || msgtype == NETMSGTYPE_CL_STARTINFO)
	{
		NETMSG_CL_CHANGEINFO *msg = (NETMSG_CL_CHANGEINFO *)rawmsg;
		
		if(config.sv_spamprotection && p->last_changeinfo+time_freq()*5 > time_get())
			return;
			
		p->last_changeinfo = time_get();
		
		p->use_custom_color = msg->use_custom_color;
		p->color_body = msg->color_body;
		p->color_feet = msg->color_feet;

		// check for invalid chars
		unsigned char *name = (unsigned char *)msg->name;
		while (*name)
		{
			if(*name < 32)
				*name = ' ';
			name++;
		}

		// copy old name
		char oldname[MAX_NAME_LENGTH];
		str_copy(oldname, server_clientname(client_id), MAX_NAME_LENGTH);
		
		server_setclientname(client_id, msg->name);
		if(msgtype == NETMSGTYPE_CL_CHANGEINFO && strcmp(oldname, server_clientname(client_id)) != 0)
		{
			char chattext[256];
			str_format(chattext, sizeof(chattext), "%s changed name to %s", oldname, server_clientname(client_id));
			game.send_chat(-1, GAMECONTEXT::CHAT_ALL, chattext);
		}
		
		// set skin
		str_copy(p->skin_name, msg->skin, sizeof(p->skin_name));
		
		game.controller->on_player_info_change(p);
		
		if(msgtype == NETMSGTYPE_CL_STARTINFO)
		{
			// send vote options
			NETMSG_SV_VOTE_CLEAROPTIONS clearmsg;
			clearmsg.pack(MSGFLAG_VITAL);
			server_send_msg(client_id);
			VOTEOPTION *current = voteoption_first;
			while(current)
			{
				NETMSG_SV_VOTE_OPTION optionmsg;
				optionmsg.command = current->command;
				optionmsg.pack(MSGFLAG_VITAL);
				server_send_msg(client_id);
				current = current->next;
			}
			
			// send tuning parameters to client
			send_tuning_params(client_id);

			//
			NETMSG_SV_READYTOENTER m;
			m.pack(MSGFLAG_VITAL|MSGFLAG_FLUSH);
			server_send_msg(client_id);
		}
	}
	else if (msgtype == NETMSGTYPE_CL_EMOTICON && !game.world.paused)
	{
		NETMSG_CL_EMOTICON *msg = (NETMSG_CL_EMOTICON *)rawmsg;
		
		if(config.sv_spamprotection && p->last_emote+time_freq()*3 > time_get())
			return;
			
		p->last_emote = time_get();
		
		game.send_emoticon(client_id, msg->emoticon);
	}
	else if (msgtype == NETMSGTYPE_CL_KILL && !game.world.paused)
	{
		if(p->last_kill+time_freq()*3 > time_get())
			return;
		
		p->last_kill = time_get();
		p->kill_character(WEAPON_SELF);
		p->respawn_tick = server_tick()+server_tickspeed()*3;
		if(game.controller->is_race())
			p->respawn_tick = server_tick();
	}
}