/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#include <game/server/gamecontext.hpp>
#include <engine/e_config.h>
#include <engine/e_server_interface.h>
#include <game/server/entities/character.hpp>
#include <game/server/player.hpp>
#include "freeze.hpp"
#include <string.h>
#include <game/mapitems.hpp>
#include "ctf.hpp"

GAMECONTROLLER_FREEZE::GAMECONTROLLER_FREEZE()
{
	gametype = "Freeze";

	teamscore[0] = 0;
	teamscore[1] = 0;

	flags[0] = 0;
	flags[1] = 0;
}

bool GAMECONTROLLER_FREEZE::on_entity(int index, vec2 pos)
{
	if(GAMECONTROLLER::on_entity(index, pos))
		return true;
	
	int team = -1;
	if(index == ENTITY_FLAGSTAND_RED) team = 0;
	if(index == ENTITY_FLAGSTAND_BLUE) team = 1;
	if(team == -1)
		return false;
		
	if(!is_ctf)
		return false;

	FLAG *f = new FLAG(team);
	f->stand_pos = pos;
	f->pos = pos;
	flags[team] = f;
	return true;
}

int GAMECONTROLLER_FREEZE::on_character_death(class PLAYER *victim, class PLAYER *killer, int weapon)
{
	GAMECONTROLLER::on_character_death(victim, killer, weapon);
	
	if(!victim)
		return 0;

	if(!victim->get_character())
		return 0;

	if(is_ctf)
	{
		FLAG *f1 = flags[0];
		FLAG *f2 = flags[1];

		if(victim->get_character() == f1->carrying_character || victim->get_character() == f2->carrying_character)
		{
			int had_flag = 0;
	
			// drop flags
			for(int fi = 0; fi < 2; fi++)
			{
				FLAG *f = flags[fi];
				if(f && killer && f->carrying_character == killer->get_character())
					had_flag |= 2;
				if(f && f->carrying_character == victim->get_character())
				{
					game.create_sound_global(SOUND_CTF_DROP);
					f->drop_tick = game_tick();
					f->carrying_character = 0;
					f->vel = vec2(0,0);
				
					if(killer && killer->team != victim->team)
						killer->score++;
				
					had_flag |= 1;
				}
			}
			victim->remove_chr(true);
			return had_flag;
		}
	}

	if(weapon != WEAPON_GAME && weapon != WEAPON_WORLD && (victim->spawn_tick == -1 || victim->join_frozen || weapon == WEAPON_SELF))
	{
		if(killer && killer != victim)
		{
			char buf[128];
			str_format(buf, sizeof(buf), "You froze %s.", server_clientname(victim->client_id));
			game.send_broadcast(buf, killer->client_id);
			str_format(buf, sizeof(buf), "%s froze you.", server_clientname(killer->client_id));
			game.send_broadcast(buf, victim->client_id);
		}

		game.create_sound_global(SOUND_CTF_RETURN, victim->client_id);

		victim->get_character()->emote_type = EMOTE_PAIN;
		victim->get_character()->emote_stop = game_tick() + 500 * server_tickspeed() / 1000;

		victim->frozen = true;
		victim->join_frozen = false;
		victim->automelt_tick = game_tick() + server_tickspeed() * config.sv_automelt_time;
		victim->get_character()->set_weapon(WEAPON_NINJA);

		if(config.sv_automelt_display)
			victim->get_character()->armor = 10;

		if(config.sv_frozen_tags)
		{
			str_format(tmp, sizeof(tmp),"[F] ");
			strncat(tmp, victim->start_name,MAX_NAME_LENGTH-5);
			tmp[MAX_NAME_LENGTH]=0;
			server_setclientname(victim->client_id, tmp);
		}

		if(!is_ctf)
			do_freeze_scoring();
	}

	return 0;
}

void GAMECONTROLLER_FREEZE::tick()
{
	do_team_score_wincheck();
	GAMECONTROLLER::tick();

	if(!is_ctf)
		return;

	for(int fi = 0; fi < 2; fi++)
	{
		FLAG *f = flags[fi];
		
		if(!f)
			continue;
		
		// flag hits death-tile, reset it
		if(col_get((int)f->pos.x, (int)f->pos.y)&COLFLAG_DEATH)
		{
			game.create_sound_global(SOUND_CTF_RETURN);
			f->reset();
			continue;
		}
		
		// Handle flag if carried
		if(f->carrying_character)
		{
			// update flag position
			f->pos = f->carrying_character->pos;
			
			if(flags[fi^1] && flags[fi^1]->at_stand)
			{
				if(distance(f->pos, flags[fi^1]->pos) < 32)
				{
					// CAPTURE! \o/
					teamscore[fi^1] += 100;
					f->carrying_character->player->score += 5;

					dbg_msg("game", "flag_capture player='%d:%s'",
						f->carrying_character->player->client_id,
						server_clientname(f->carrying_character->player->client_id));

					char buf[512];
					float capture_time = (game_tick() - f->grab_tick)/(float)server_tickspeed();
					if(capture_time <= 60)
					{
						str_format(buf, sizeof(buf), "the %s flag was captured by %s (%d.%s%d seconds)", fi ? "blue" : "red", server_clientname(f->carrying_character->player->client_id), (int)capture_time%60, ((int)(capture_time*100)%100)<10?"0":"", (int)(capture_time*100)%100);
					}
					else
					{
						str_format(buf, sizeof(buf), "the %s flag was captured by %s", fi ? "blue" : "red", server_clientname(f->carrying_character->player->client_id));
					}
					game.send_chat(-1, -2, buf);
					for(int i = 0; i < 2; i++)
						flags[i]->reset();
					
					game.create_sound_global(SOUND_CTF_CAPTURE);
				}
			}			
		}
		else
		{
			CHARACTER *close_characters[MAX_CLIENTS];
			int num = game.world.find_entities(f->pos, 32.0f, (ENTITY**)close_characters, MAX_CLIENTS, NETOBJTYPE_CHARACTER);
			for(int i = 0; i < num; i++)
			{
				if(!close_characters[i]->alive || close_characters[i]->player->team == -1 || col_intersect_line(f->pos, close_characters[i]->pos, NULL, NULL))
					continue;
				
				if(close_characters[i]->team == f->team)
				{
					// return the flag
					if(!f->at_stand)
					{
						CHARACTER *chr = close_characters[i];
						chr->player->score += 1;

						dbg_msg("game", "flag_return player='%d:%s'",
							chr->player->client_id,
							server_clientname(chr->player->client_id));

						game.create_sound_global(SOUND_CTF_RETURN);
						f->reset();
					}
				}
				else if(!close_characters[i]->player->frozen)
				{
					// take the flag
					if(f->at_stand)
					{
						teamscore[fi^1]++;
						f->grab_tick = game_tick();
					}
					f->at_stand = 0;
					f->carrying_character = close_characters[i];
					f->carrying_character->player->score += 1;

					dbg_msg("game", "flag_grab player='%d:%s'",
						f->carrying_character->player->client_id,
						server_clientname(f->carrying_character->player->client_id));
					
					for(int c = 0; c < MAX_CLIENTS; c++)
					{
						if(!game.players[c])
							continue;
							
						if(game.players[c]->team == fi)
							game.create_sound_global(SOUND_CTF_GRAB_EN, game.players[c]->client_id);
						else
							game.create_sound_global(SOUND_CTF_GRAB_PL, game.players[c]->client_id);
					}
					break;
				}
			}
			
			if(!f->carrying_character && !f->at_stand)
			{
				if(game_tick() > f->drop_tick + server_tickspeed()*30)
				{
					game.create_sound_global(SOUND_CTF_RETURN);
					f->reset();
				}
				else
				{
					f->vel.y += game.world.core.tuning.gravity;
					move_box(&f->pos, &f->vel, vec2(f->phys_size, f->phys_size), 0.5f);
				}
			}
		}
	}
}

void GAMECONTROLLER_FREEZE::do_freeze_scoring()
{
	int red = 0;
	int blue = 0;

	int red_f = 0;
	int blue_f = 0;

	for(int i = 0; i < MAX_CLIENTS; i++)
	{
		if(game.players[i])
		{
			if(game.players[i]->team == 1 && game.players[i]->get_character())
			{
				if(game.players[i]->get_character())
					blue++;
				if(game.players[i]->frozen)
					blue_f++;
			}
			else if(game.players[i]->team == 0 && game.players[i]->get_character())
			{
				if(game.players[i]->get_character())
					red++;
				if(game.players[i]->frozen)
					red_f++;
			}
		}
	}

	bool blue_score = red_f >= red && red && red_f;

	if(blue_score || (blue_f >= blue && blue && blue_f))
	{
		teamscore[blue_score]++;
		reset_frozens();
		game.send_broadcast(blue_score ? "Blue team scores!" : "Red team scores!", -1);
		game.create_sound_global(SOUND_CTF_CAPTURE);
	}
}

void GAMECONTROLLER_FREEZE::reset_frozens()
{
	for(int i = 0; i < MAX_CLIENTS; i++)
	{
		if(game.players[i])
		{
			if(game.players[i]->frozen)
			{
				game.players[i]->remove_chr(true);
			}
			else if(config.sv_all_respawn_after_score && game.players[i]->get_character())
			{
				game.players[i]->remove_chr(true);
			}
		}
	}
}
