Jump to content
  • 0
Sign in to follow this  
MikZ

HERCULES BATTLEGROUND

Question

Good day!

Help me how to correct these warnings please.

Spoiler

/*
* This file is part of a Hercules Plugin library.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*  __                 _
* / _\_ __ ___   ___ | | _______  ___   _ ____
* \ \| '_ ` _ \ / _ \| |/ / _ \ \/ / | | |_  /
* _\ \ | | | | | (_) |   <  __/>  <| |_| |/ /
* \__/_| |_| |_|\___/|_|\_\___/_/\_\\__, /___|
*                                   |___/
*
* Copyright (c) 2017 Smokexyz ([email protected])
* 
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License <http://www.gnu.org/licenses/> for
* more details.
* * * * * * * * * * * * * * * * * * * * * * * * *
* Hercules Battlegrounds Plugin by [Smokexyz]
* * * * * * * * * * * * * * * * * * * * * * * * */

#include "common/hercules.h" /* Should always be the first Hercules file included! */

#include "common/memmgr.h"
#include "common/mmo.h"
#include "common/socket.h"
#include "common/strlib.h"
#include "common/nullpo.h"
#include "common/timer.h"
#include "common/utils.h"
#include "common/sql.h"

#include "map/chrif.h"
#include "map/atcommand.h"
#include "map/clif.h"
#include "map/pc.h"
#include "map/script.h"
#include "map/npc.h"
#include "map/party.h"
#include "map/mapreg.h"
#include "map/guild.h"
#include "map/chat.h"
#include "map/quest.h"
#include "map/mob.h"
#include "map/map.h"
#include "map/pet.h"
#include "map/homunculus.h"
#include "map/mercenary.h"
#include "map/elemental.h"
#include "map/skill.h"
#include "map/battleground.h"

#include "char/mapif.h"
#include "char/inter.h"

#include "plugins/HPMHooking.h" /* Hooking Macros */
#include "common/HPMDataCheck.h" /* should always be the last Hercules file included! */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Utility Functions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define add2limit(a, b, max) \
	do { \
		if ((max - a) < b) { \
			a = max; \
		} else { \
			a += b; \
		} \
	} while(0)

#define sub2limit(a, b, min) \
	do { \
		if ((b + min) > a) { \
			a = min; \
		} else { \
			a -= b; \
		} \
	} while(0)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    HPM Structure Definition
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
HPExport struct hplugin_info pinfo = {
	"Hercules Battlegrounds",    // Plugin name
	SERVER_TYPE_MAP | SERVER_TYPE_CHAR, // Server Type
	"1.0a",       // Plugin version
	HPM_VERSION, // HPM Version (automatically updated)
};

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Global Variables
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define MAX_BATTLEGROUND_TEAMS 13
#define BLUE_SKULL 8965
#define RED_SKULL 8966
#define GREEN_SKULL 8967

/* Queue Database */
static struct DBMap* hBG_queue_db;
/* Battleground Guild Storage */
struct guild bg_guild[MAX_BATTLEGROUND_TEAMS];
/* Battleground Guild Colors */
const unsigned int bg_colors[MAX_BATTLEGROUND_TEAMS] = {
	0x0000FF, // Blue
	0xFF0000, // Red
	0x00FF00, // Green
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF
};

/* Counter to check the next battleground ID */
static unsigned int bg_team_counter = 0;
/* hBG Queue Counter */
static unsigned int hBG_queue_counter = 0;

/**
 * Battle Configuration Variables
 */
int hBG_idle_announce,
	hBG_idle_autokick,
	hBG_reward_rates,
	hBG_ranked_mode,
	hBG_reportafk_leaderonly,
	hBG_balanced_queue,
	hBG_ip_check,
	hBG_from_town_only,
	hBG_enabled,
	hBG_xy_interval,
	hBG_leader_change;

/**
 * BG Fame list types
 */
enum bg_fame_list_types
{
	BG_NORMAL,
	BG_RANKED
};

/**
 * Inter-server communication packet IDs.
 */
enum inter_packet_types {
	PACKET_INTER_BG_STATS_SAVE =  0x9000,
	PACKET_INTER_BG_STATS_REQ,
	PACKET_MAP_BG_STATS_GET,
};

enum bg_mob_types {
	BARRICADE_        = 1906,
	OBJ_NEUTRAL       = 1911,
	E_BAPHOMET2       = 2100,
	E_LORD_OF_DEATH2,
	E_DARK_LORD,
	E_KTULLANUX,
	E_DARK_SNAKE_LORD,
	E_TURTLE_GENERAL,
	E_APOCALIPS_H,
	E_FALLINGBISHOP,
};

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Structure Definitions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * BGD Structure Appendant
 */
struct hBG_data
{
	time_t created_at; // Creation of this Team
	int leader_char_id;
	unsigned int color;
	// BG Guild Link
	struct guild *g;
	bool reveal_pos, reveal_pos2, reveal_flag;
	// Score Board
	int team_score;
};

/**
 * hBG Queue Member Linked List
 */
struct hBG_queue_member
{
	int position;
	struct map_session_data *sd;
	struct hBG_queue_member *next;
};

struct hBG_stats
{
	unsigned int
	best_damage,
	boss_damage,
	total_damage_done,
	total_damage_received;
	
	unsigned short
	// Triple Inferno
	ti_wins,
	ti_lost,
	ti_tie,
	// Tierra EoS
	eos_flags,
	eos_bases,
	eos_wins,
	eos_lost,
	eos_tie,
	// Tierra Bossnia
	boss_killed,
	boss_flags,
	boss_wins,
	boss_lost,
	boss_tie,
	// Tierra Domination
	dom_bases,
	dom_off_kills,
	dom_def_kills,
	dom_wins,
	dom_lost,
	dom_tie,
	// Flavius TD
	td_kills,
	td_deaths,
	td_wins,
	td_lost,
	td_tie,
	// Flavius SC
	sc_stolen,
	sc_captured,
	sc_dropped,
	sc_wins,
	sc_lost,
	sc_tie,
	// Flavius CTF
	ctf_taken,
	ctf_captured,
	ctf_dropped,
	ctf_wins,
	ctf_lost,
	ctf_tie,
	// Conquest
	emperium_kills,
	barricade_kills,
	guardian_stone_kills,
	conquest_wins,
	conquest_losses,
	// Rush
	ru_captures,
	ru_wins,
	ru_lost,
	ru_skulls;
	
	unsigned int // Ammo
	sp_heal_potions,
	hp_heal_potions,
	yellow_gemstones,
	red_gemstones,
	blue_gemstones,
	poison_bottles,
	acid_demostration,
	acid_demostration_fail,
	support_skills_used,
	healing_done,
	wrong_support_skills_used,
	wrong_healing_done,
	sp_used,
	zeny_used,
	spiritb_used,
	ammo_used;
	
	unsigned short
	kill_count,
	death_count,
	wins, losses, ties,
	wins_as_leader,
	losses_as_leader,
	ties_as_leader,
	total_deserted,
	ranked_games;
	
	int score,
	points,
	ranked_points;
};

/**
 * MSD Structure Appendant (class 0)
 */
struct hBG_queue_data
{
	unsigned int q_id, users, min_level;
	struct hBG_queue_member *first, *last;
	char queue_name[50], join_event[EVENT_NAME_LENGTH];
};

/**
 * MSD Structure Appendant (class 1)
 */
struct hBG_map_session_data
{
	unsigned int bg_kills;
	struct {
		unsigned afk : 1;
	} state;
	
	struct hBG_stats stats;
};

/**
 * MOBD Structure Appendant
 */
struct hBG_mob_data
{
	struct {
		unsigned immunity: 1;
	} state;
};

/**
 * MAPD Structure Appendant
 */
struct hBG_mapflag
{
	unsigned hBG_topscore : 1; // No Detect NoMapFlag
};

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Function Forward Declarations
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int hBG_countlogin(struct map_session_data *sd, bool check_bat_room);
int hBG_config_get(const char *key);
struct guild* hBG_get_guild(int bg_id);
struct map_session_data* hBG_getavailablesd(struct battleground_data *bgd);

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Packet Sending Functions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
 * Updates HP bar of a camp member.
 * Packet Ver < 20140613: 02e0 <account id>.L <name>.24B <hp>.W <max hp>.W (ZC_BATTLEFIELD_NOTIFY_HP).
 * Packet Ver >= 20140613: 0a0e <account id>.L <hp>.L <max hp>.L (ZC_BATTLEFIELD_NOTIFY_HP2)
 *
 * @param sd map_session_data to send the packet to.
 * @return void.
 */
void hBG_send_hp_area(struct map_session_data *sd)
{
	unsigned char buf[34];
	
	// packet version can be wrong,
	// due to inconsistend data on other servers.
#if PACKETVER < 20140613
	const int cmd = 0x2e0;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;

	WBUFW(buf, 0) = cmd;
	WBUFL(buf, 2) = sd->status.account_id;
	memcpy(WBUFP(buf, 6), sd->status.name, NAME_LENGTH);

	if (sd->battle_status.max_hp > INT16_MAX) { // To correctly display the %hp bar. [Skotlex]
		WBUFW(buf, 30) = sd->battle_status.hp / (sd->battle_status.max_hp / 100);
		WBUFW(buf, 32) = 100;
	}
	else {
		WBUFW(buf, 30) = sd->battle_status.hp;
		WBUFW(buf, 32) = sd->battle_status.max_hp;
	}
	
	clif->send(buf, packet->len, &sd->bl, BG_AREA_WOS);
#else
	const int cmd = 0xa0e;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;

	WBUFW(buf, 0) = cmd;
	WBUFL(buf, 2) = sd->status.account_id;
	if (sd->battle_status.max_hp > INT32_MAX) {
		WBUFL(buf, 6) = sd->battle_status.hp / (sd->battle_status.max_hp / 100);
		WBUFL(buf, 10) = 100;
	} else {
		WBUFL(buf, 6) = sd->battle_status.hp;
		WBUFL(buf, 10) = sd->battle_status.max_hp;
	}
	
	clif->send(buf, packet->len, &sd->bl, BG_AREA_WOS);
#endif
}

/**
 * Notify a singly client of HP change.
 *
 * @param fd  socket fd to write
 * @param sd  map_session_data containing information to be sent.
 */
void hBG_send_hp_single(int fd, struct map_session_data* sd)
{
	const int cmd = 0x2e0;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;

	WFIFOHEAD(fd, packet->len);
	WFIFOW(fd, 0) = cmd;
	WFIFOL(fd, 2) = sd->bl.id;
	memcpy(WFIFOP(fd,6),sd->status.name, NAME_LENGTH);
	if (sd->battle_status.max_hp > INT16_MAX) {
		WFIFOW(fd, 30) = sd->battle_status.hp/(sd->battle_status.max_hp/100);
		WFIFOW(fd, 32) = 100;
	} else {
		WFIFOW(fd, 30) = sd->battle_status.hp;
		WFIFOW(fd, 32) = sd->battle_status.max_hp;
	}

	WFIFOSET(fd, packet->len);
}

/**
 * Character Guild Name Information Packet
 *
 * @param sd map_session_data to send the packet to.
 * @return void
 */
void hBG_send_guild_info(struct map_session_data *sd)
{
	int fd;
	int cmd = 0x16c;
	struct guild *g;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);

	if (!sd->bg_id || (g = hBG_get_guild(sd->bg_id)) == NULL || packet == NULL)
		return;

	fd = sd->fd;
	WFIFOHEAD(fd, packet->len);
	WFIFOW(fd,0) = 0x16c;
	WFIFOL(fd,2) = g->guild_id;
	WFIFOL(fd,6) = g->emblem_id;
	WFIFOL(fd,10) = 0;
	WFIFOB(fd,14) = 0;
	WFIFOL(fd,15) = 0;
	memcpy(WFIFOP(fd,19), g->name, NAME_LENGTH);

	WFIFOSET(fd,  packet->len);
}

/** 
 * Sends guild skills (ZC_GUILD_SKILLINFO).
 * 0162 <packet len>.W <skill points>.W { <skill id>.W <type>.L <level>.W <sp cost>.W <atk range>.W <skill name>.24B <upgradeable>.B }*
 */
void hBG_send_guild_skillinfo(struct map_session_data* sd)
{
	int fd;
	struct guild* g;
	int i,c;
	
	nullpo_retv(sd);
	
	if (!sd->bg_id || (g = hBG_get_guild(sd->bg_id)) == NULL)
		return;
	
	fd = sd->fd;
	WFIFOHEAD(fd, 6 + MAX_GUILDSKILL*37);
	WFIFOW(fd,0) = 0x0162;
	WFIFOW(fd,4) = g->skill_point;
	for (i = 0, c = 0; i < MAX_GUILDSKILL; i++) {
		if(g->skill[i].id > 0 && guild->check_skill_require(g, g->skill[i].id)) {
			int id = g->skill[i].id;
			int p = 6 + c*37;
			WFIFOW(fd,p+0) = id;
			WFIFOL(fd,p+2) = skill->get_inf(id);
			WFIFOW(fd,p+6) = g->skill[i].lv;
			if ( g->skill[i].lv) {
				WFIFOW(fd, p + 8) = skill->get_sp(id, g->skill[i].lv);
				WFIFOW(fd, p + 10) = skill->get_range(id, g->skill[i].lv);
			} else {
				WFIFOW(fd, p + 8) = 0;
				WFIFOW(fd, p + 10) = 0;
			}
			safestrncpy(WFIFOP(fd,p+12), skill->get_name(id), NAME_LENGTH);
			WFIFOB(fd,p+36)= (g->skill[i].lv < guild->skill_get_max(id) && sd == g->member[0].sd) ? 1 : 0;
			c++;
		}
	}
	WFIFOW(fd,2) = 6 + c*37;
	WFIFOSET(fd,WFIFOW(fd,2));
}

/**
 * Sends Guild Window Information
 * 01b6 <guild id>.L <level>.L <member num>.L <member max>.L <exp>.L <max exp>.L <points>.L <honor>.L <virtue>.L <emblem id>.L <name>.24B <master name>.24B <manage land>.16B <zeny>.L (ZC_GUILD_INFO2)
 * @param sd map_session_data to send the packet to.
 * @return void
 */
void hBG_guild_window_info(struct map_session_data *sd)
{
	int fd;
	int cmd = 0x1b6;
	struct guild *g;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	fd = sd->fd;
	
	if ((g = hBG_get_guild(sd->bg_id)) == NULL || packet == NULL)
		return;
	
	WFIFOHEAD(fd, packet->len); // Hardcoded Length
	WFIFOW(fd, 0)= cmd;
	WFIFOL(fd, 2)= g->guild_id;
	WFIFOL(fd, 6)= g->guild_lv;
	WFIFOL(fd,10)= g->connect_member;
	WFIFOL(fd,14)= g->max_member;
	WFIFOL(fd,18)= g->average_lv;
	WFIFOL(fd,22)= (uint32)cap_value(g->exp,0,INT32_MAX);
	WFIFOL(fd,26)= g->next_exp;
	WFIFOL(fd,30)= 0; // Tax Points
	WFIFOL(fd,34)= 0; // Honor: (left) Vulgar [-100,100] Famed (right)
	WFIFOL(fd,38)= 0; // Virtue: (down) Wicked [-100,100] Righteous (up)
	WFIFOL(fd,42)= g->emblem_id;
	memcpy(WFIFOP(fd,46), g->name, NAME_LENGTH);
	memcpy(WFIFOP(fd,70), g->master, NAME_LENGTH);
	
	//safestrncpy(WFIFOP(fd,94), 0, 0); // "'N' castles"
	WFIFOL(fd, 110) = 0;  // zeny
	
	WFIFOSET(fd, packet->len);
}

/**
 * Sends Guild Emblem to a player
 * @param sd   map_session_data to send the packet to
 * @param g    guild data
 * @return void
 */
void hBG_send_emblem(struct map_session_data *sd, struct guild *g)
{
	int fd;

	nullpo_retv(sd);
	nullpo_retv(g);

	if (g->emblem_len <= 0)
		return;

	fd = sd->fd;
	WFIFOHEAD(fd, g->emblem_len+12);
	WFIFOW(fd,0) = 0x152;
	WFIFOW(fd,2) = g->emblem_len+12;
	WFIFOL(fd,4) = g->guild_id;
	WFIFOL(fd,8) = g->emblem_id;
	memcpy(WFIFOP(fd,12),g->emblem_data,g->emblem_len);

	WFIFOSET(fd, WFIFOW(fd,2));
}

/**
 * Sends guild member list 
 * @param sd  map_session_data to send the packet to
 * @return void
 */
void hBG_send_guild_member_list(struct map_session_data *sd)
{
	int fd, i, c;
	struct battleground_data *bgd;
	struct map_session_data *psd;
	struct hBG_data *hBGd;
	
	nullpo_retv(sd);

	if ((fd = sd->fd) == 0)
		return;
	if (!sd->bg_id || (bgd = bg->team_search(sd->bg_id)) == NULL)
		return;
	else if ((hBGd = getFromBGDATA(bgd, 0)) == NULL)
		return;

	WFIFOHEAD(fd, bgd->count * 104 + 4);
	WFIFOW(fd, 0) = 0x154;

	for (i = 0, c = 0; i < bgd->count; i++) {
		struct hBG_map_session_data *hBGsd;

		if ((psd = bgd->members[i].sd) == NULL)
			continue;

		if ((hBGsd = getFromMSD(psd, 1)) == NULL)
			continue;

		WFIFOL(fd,c*104+ 4) = psd->status.account_id;
		WFIFOL(fd,c*104+ 8) = psd->status.char_id;
		WFIFOW(fd,c*104+12) = psd->status.hair;
		WFIFOW(fd,c*104+14) = psd->status.hair_color;
		WFIFOW(fd,c*104+16) = psd->status.sex;
		WFIFOW(fd,c*104+18) = psd->status.class;
		WFIFOW(fd,c*104+20) = psd->status.base_level;
		WFIFOL(fd,c*104+22) = hBGsd->bg_kills; // Exp slot used to show kills
		WFIFOL(fd,c*104+26) = 1; // Online
		WFIFOL(fd,c*104+30) = hBGd->leader_char_id == psd->status.char_id ? 0 : 1; // Position
		memset(WFIFOP(fd,c*104+34),0,50); // Position Name
		memcpy(WFIFOP(fd,c*104+84),psd->status.name,NAME_LENGTH); // Player Name
		c++;
	}

	WFIFOW(fd, 2)=c*104+4;

	WFIFOSET(fd,WFIFOW(fd,2));
}

/**
 * Send guild leave packet
 * @param sd map_session_data to send the packet to
 * @param *name contains name of the character.
 * @param *mes  contains leave message from player.
 * @return void
 */
void hBG_send_leave_single(struct map_session_data *sd, const char *name, const char *mes)
{
	unsigned char buf[128];
	int cmd = 0x15a;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;
	
	WBUFW(buf, 0) = cmd;
	memcpy(WBUFP(buf, 2), name, NAME_LENGTH);
	memcpy(WBUFP(buf,26), mes, 40);
	
	clif->send(buf, packet->len, &sd->bl, SELF);
}

/**
 * Notifies clients of a battleground message ZC_BATTLEFIELD_CHAT
 * 02dc <packet len>.W <account id>.L <name>.24B <message>.?B
 *
 * @param bgd battleground_data to send the message to
 * @param src_id id of the source of the message.
 * @param name contains the name of the character.
 * @param mes contains the message to be sent.
 * @param len contains the length of the message.
 * @return void.
 */
void hBG_send_chat_message(struct battleground_data *bgd, int src_id, const char *name, const char *mes, int len)
{
	struct map_session_data *sd;
	unsigned char *buf;

	nullpo_retv(bgd);
	nullpo_retv(name);
	nullpo_retv(mes);

	if ((sd = hBG_getavailablesd(bgd)) == NULL)
		return;

	len = (int)strlen(mes);
	Assert_retv(len <= INT16_MAX - NAME_LENGTH - 8);
	buf = (unsigned char*)aMalloc((len + NAME_LENGTH + 8)*sizeof(unsigned char));

	WBUFW(buf, 0) = 0x2dc;

	WBUFW(buf, 2) = len + NAME_LENGTH + 8;
	WBUFL(buf, 4) = src_id;
	memcpy(WBUFP(buf, 8), name, NAME_LENGTH);
	memcpy(WBUFP(buf, 32), mes, len); // [!] no NULL terminator

	clif->send(buf, WBUFW(buf, 2), &sd->bl, BG);

	if (buf)
		aFree(buf);
}

/**
 * Notifies the client of a guild expulsion.
 *
 * @param sd   map_session_data to send the packet to
 * @param *name  contains the name of the character.
 * @param *mes   contains the expulsion message.
 */
void hBG_send_expulsion(struct map_session_data *sd, const char *name, const char *mes)
{
	int fd;
	int cmd = 0x15c;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;

	fd = sd->fd;
	WFIFOHEAD(fd, packet->len);
	WFIFOW(fd,0) = cmd;
	safestrncpy((char*)WFIFOP(fd,2), name, NAME_LENGTH);
	safestrncpy((char*)WFIFOP(fd,26), mes, 40);
	safestrncpy((char*)WFIFOP(fd,66), "", NAME_LENGTH);
	WFIFOSET(fd, packet->len);
}

/**
 * Notifies a single client of BG score updates
 * 
 * @param sd map_session_data to send the packet to
 * @return void
 */
void hBG_update_score_single(struct map_session_data *sd)
{
	int fd;
	int cmd = 0x2de;
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	struct hBG_mapflag *hBG_mf = getFromMAPD(&map->list[sd->bl.m], 0);
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;
	
	fd = sd->fd;

	WFIFOHEAD(fd, packet->len);
	WFIFOW(fd,0) = cmd;

	if (map->list[sd->bl.m].flag.battleground == 2) { // Score Board on Map. Team vs Team
		WFIFOW(fd,2) = map->list[sd->bl.m].bgscore_lion;
		WFIFOW(fd,4) = map->list[sd->bl.m].bgscore_eagle;
	} else if (map->list[sd->bl.m].flag.battleground == 3
			&& (bgd = bg->team_search(sd->bg_id)) != NULL
			&& (hBGd = getFromBGDATA(bgd, 0)) != NULL) { // Score Board Multiple. Team vs Best Score
		WFIFOW(fd,2) = hBGd->team_score;
		WFIFOL(fd,4) = hBG_mf->hBG_topscore;
	}
	WFIFOSET(fd, packet->len);
}

/**
 * Notifies all clients in a Battleground Team
 *
 * @param bgd battleground_data containing the map_session_datas to send the packet to
 * @return void
 */
void hBG_update_score_team(struct battleground_data *bgd)
{
	unsigned char buf[6];
	struct map_session_data *sd;
	int i, m, cmd = 0x2de;
	struct hBG_data *hBGd = getFromBGDATA(bgd, 0);
	struct hBG_mapflag *hBG_mf;
	const struct s_packet_db *packet = clif->packet(cmd);

	nullpo_retv(bg);

	if ((m = map->mapindex2mapid(bgd->mapindex)) < 0
		|| hBGd == NULL
		|| (hBG_mf = getFromMAPD(&map->list[m], 0)) == NULL
		|| packet == NULL)
		return;

	WBUFW(buf,0) = cmd;
	WBUFW(buf,2) = hBGd->team_score;
	WBUFW(buf,4) = hBG_mf->hBG_topscore;

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL || sd->bl.m != m)
			continue;

		clif->send(buf, packet->len, &sd->bl, SELF);
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Queue System Functions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Searches hBG_queue_db by q_id
 * @param q_id contains the id of the queue to be searched.
 * @return hBG_queue_data * pointer to the memory location or null if not found.
 */
struct hBG_queue_data* hBG_queue_search(int q_id)
{ // Search a Queue using q_id
	if (!q_id)
		return NULL;
	
	return (struct hBG_queue_data *) idb_get(hBG_queue_db, q_id);
}

/**
 * Creates a Queue
 * @param queue_name contains the name of the queue.
 * @param join_event contains the event run on joining the queue.
 * @param min_level contains the minimum level to be able to join.
 * @return queue_id id of the queue created.
 */
int hBG_queue_create(const char* queue_name, const char* join_event, int min_level)
{
	struct hBG_queue_data *hBGqd;
	
	if (++hBG_queue_counter <= 0)
		hBG_queue_counter = 1;

	CREATE(hBGqd, struct hBG_queue_data, 1);
	hBGqd->q_id = hBG_queue_counter;
	
	safestrncpy(hBGqd->queue_name, queue_name, sizeof(hBGqd->queue_name));
	safestrncpy(hBGqd->join_event, join_event, sizeof(hBGqd->join_event));
	
	hBGqd->first = hBGqd->last = NULL; // First and Last Queue Members
	hBGqd->users = 0;
	hBGqd->min_level = min_level;
	
	idb_put(hBG_queue_db, hBG_queue_counter, hBGqd);

	return hBGqd->q_id;
}

/**
 * Remove all queue members from the queue and free the links.
 * @param hBGqd pointer to the queue data.
 * @return void.
 */
void hBG_queue_members_finalize(struct hBG_queue_data *hBGqd)
{
	struct hBG_queue_member *head, *next;
	
	nullpo_retv(hBGqd);

	head = hBGqd->first;
	while (head) {
		next = head->next;
		
		aFree(head);
		
		head = next;
	}

	hBGqd->first = hBGqd->last = NULL;
	hBGqd->users = 0;
}

/**
 * Add a player to the queue.
 * @param hBGqd pointer to the queue data.
 * @param sd    player to be added to the queue.
 * @return postition of the player in queue.
 */
int hBG_queue_member_add(struct hBG_queue_data *hBGqd, struct map_session_data *sd)
{
	struct hBG_queue_member *hBGqm;

	nullpo_retr(0, hBGqd);
	nullpo_retr(0, sd);

	hBGqd->users++;
	
	CREATE(hBGqm, struct hBG_queue_member, 1);
	
	hBGqm->sd = sd;
	hBGqm->position = hBGqd->users;
	hBGqm->next = NULL;
	
	if (getFromMSD (sd, 0) == NULL)
		addToMSD(sd, hBGqd, 0, false);
	
	if (hBGqd->last == NULL) {
		hBGqd->first = hBGqd->last = hBGqm; // Attach to first position
	} else { // Attach at the end of the queue
		hBGqd->last->next = hBGqm;
		hBGqd->last = hBGqm;
	}
	
	return hBGqm->position;
}

/**
 * Get a member of the queue from position n.
 * @param hBGqd    pointer to the queue data
 * @param position position of the player in queue
 * @return queue_member data or NULL if not found.
 */
struct hBG_queue_member* hBG_queue_member_get(struct hBG_queue_data *hBGqd, int position)
{
	struct hBG_queue_member *head;
	if (!hBGqd) return NULL;

	head = hBGqd->first;
	while (head != NULL) {
		if (head->sd && head->position == position)
			return head;

		head = head->next;
	}

	return NULL;
}

/**
 * Clear a queue and remove from memory.
 * @param hBGqd pointer to queue_data
 * return 1 on success, 0 on failure.
 */
int hBG_queue_destroy(struct hBG_queue_data *hBGqd)
{
	nullpo_ret(hBGqd);
	
	hBG_queue_members_finalize(hBGqd);
	
	idb_remove(hBG_queue_db, hBGqd->q_id);
	
	return 1;
}

/**
 * Remove a member from a queue
 * @param hBGqd pointer to queue data.
 * @param id    block list ID of player in queue.
 * @return position of a player in the queue or 0 if not found.
 */
int hBG_queue_member_remove(struct hBG_queue_data *hBGqd, int id)
{
	struct hBG_queue_member *head, *previous;
	int i;
	
	nullpo_retr(0, hBGqd);

	head = hBGqd->first;
	previous = NULL;

	while (head != NULL) {
		if (head->sd && head->sd->bl.id == id) {
			struct hBG_queue_member *next;
			
			next = head->next;
			i = head->position;
			
			hBGqd->users--;
			
			// De-attach target from the main queue
			if (previous) {
				previous->next = head->next;
			} else {
				hBGqd->first = head->next; // Deleted is on first position
			}
			
			if (head->next == NULL)
				hBGqd->last = previous; // Deleted is on last position
			
			while (next != NULL) {
				next->position--; // Decrement positions of the next in queue.
				next = next->next;
			}
			
			aFree(head);
			
			return i;
		}

		previous = head;
		head = head->next;
	}

	return 0;
}

/**
 * Search a member in the queue by Block List ID.
 * @param hBGqd pointer to queue data.
 * @param id    block list ID of a player in queue.
 * @return position of a player in the queue or 0 if not found.
 */
int hBG_queue_member_search(struct hBG_queue_data *hBGqd, int id)
{
	struct hBG_queue_member *head;
	
	nullpo_retr(0,hBGqd);

	head = hBGqd->first;

	while (head != NULL) {
		if (head->sd && head->sd->bl.id == id)
			return head->position;

		head = head->next;
	}

	return 0; // Not Found
}

/**
 * Add a player to the queue.
 * @param sd pointer to player to be added in queue.
 * @param q_id ID of the queue to be appended.
 * @return 0 on failure, 1 on success.
 */
int hBG_queue_join(struct map_session_data *sd, int q_id)
{
	char output[128];
	struct hBG_queue_data *hBGqd;
	int i = 0;
	int login_ip_count = hBG_config_get("battle_configuration/hBG_ip_check");
	
	nullpo_ret(sd);
	
	if (hBG_config_get("battle_configuration/hBG_from_town_only") && map->list[sd->bl.m].flag.town == 0) {
		clif->message(sd->fd,"You only can join BG queues from Towns or BG Waiting Room.");
		return 0;
	} else if (sd->bg_id) {
		clif->message(sd->fd,"You cannot join queues when already playing Battlegrounds.");
		return 0;
	} else if (sd->sc.data[SC_JAILED]) {
		clif->message(sd->fd,"You cannot join queues when jailed.");
		return 0;
	}
	// Get Queue by ID
	if ((hBGqd = hBG_queue_search(q_id)) == NULL) {
		return 0; // Current Queue don't exists
	} else if ((i = hBG_queue_member_search(hBGqd, sd->bl.id))) { // You cannot join a Queue if you are already in one.
		sprintf(output, "You are already in %s queue at position %d.", hBGqd->queue_name, i);
		clif->message(sd->fd, output);
		return 0;
	} else if (hBGqd && hBGqd->min_level && sd->status.base_level < hBGqd->min_level) {
		sprintf(output,"You cannot join %s queue. Required min level is %ud.", hBGqd->queue_name, hBGqd->min_level);
		clif->message(sd->fd,output);
		return 0;
	} else if (login_ip_count && hBG_countlogin(sd,false) > login_ip_count) {
		sprintf(output,"You cannot join %s queue. A max of %d characters are using your IP address.", hBGqd->queue_name, login_ip_count);
		clif->message(sd->fd,output);
		return 0;
	}

	i = hBG_queue_member_add(hBGqd, sd);
	
	sprintf(output,"You have joined %s queue at position %d.", hBGqd->queue_name, i);
	
	clif->message(sd->fd,output);

	if (hBGqd->join_event[0])
		npc->event_do(hBGqd->join_event);

	return i;
}

/**
 * Process player leaving a queue.
 * @param sd pointer to player leaving the queue.
 * @param q_id ID of the queue to be left.
 * @return 0 on failure, 1 on success.
 */
int hBG_queue_leave(struct map_session_data *sd, int q_id)
{
	char output[128];
	struct hBG_queue_data *qd;

	if ((qd = hBG_queue_search(q_id)) == NULL)
		return 0;

	if (!hBG_queue_member_remove(qd,sd->bl.id)) {
		sprintf(output,"You are not in the %s queue.", qd->queue_name);
		clif->message(sd->fd,output);
		return 0;
	}
	
	sprintf(output, "You have been removed from the %s queue.", qd->queue_name);
	clif->message(sd->fd, output);

	return 1;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Battleground Functions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
 * Return any available player in a Battleground
 * @param bgd pointer to battleground queue.
 * @return map_session_data *sd pointer to player data or NULL if not found.
 */
struct map_session_data* hBG_getavailablesd(struct battleground_data *bgd)
{
	int i;
	nullpo_retr(NULL, bgd);
	ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd != NULL);
	return(i < MAX_BG_MEMBERS) ? bgd->members[i].sd : NULL;
}

/**
 * Count the number of players with the same IP in battlegrounds.
 * @param sd pointer to map session data.
 * @param check_bat_room boolean to include checks in bat_room.
 * @return amount of accounts online.
 */
int hBG_countlogin(struct map_session_data *sd, bool check_bat_room)
{
	int c = 0, m = map->mapname2mapid("bat_room");
	struct map_session_data* pl_sd;
	struct s_mapiterator* iter;
	nullpo_ret(sd);

	iter = mapit_getallusers();
	for (pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter)) {
		if (!(getFromMSD(sd, 0) || map->list[pl_sd->bl.m].flag.battleground || (check_bat_room && pl_sd->bl.m == m)))
			continue;
		if (sockt->session[sd->fd]->client_addr == sockt->session[pl_sd->fd]->client_addr)
			c++;
	}
	mapit->free(iter);
	return c;
}

/**
 * Performs initialization tasks on new battlegrounds.
 * @param m map Index
 * @param rx respawn X co-ordinate
 * @param ry respawn Y co-ordinate
 * @param guild_index Index of the BG guild to be used
 * @param *ev NPC Script event to be called when player logs out.
 * @param *dev NPC Script event to be called when player dies.
 * @return ID of the battleground.
 */
int hBG_create(unsigned short m, short rx, short ry, int guild_index, const char *ev, const char *dev)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;

	CREATE(bgd, struct battleground_data, 1);
	CREATE(hBGd, struct hBG_data, 1);

	if (++bg_team_counter <= 0)
		bg_team_counter = 1;

	bgd->bg_id = bg_team_counter;
	bgd->count = 0;
	bgd->mapindex = m;
	bgd->x = rx;
	bgd->y = ry;

	safestrncpy(bgd->logout_event, ev, sizeof(bgd->logout_event));
	safestrncpy(bgd->die_event, dev, sizeof(bgd->die_event));

	memset(&bgd->members, 0, sizeof(bgd->members));

	hBGd->color = bg_colors[guild_index];
	hBGd->created_at = 0;
	hBGd->g = &bg_guild[guild_index];

	addToBGDATA(bgd, hBGd, 0, true);

	idb_put(bg->team_db, bg_team_counter, bgd);

	return bgd->bg_id;
}

/**
 * Add a player to the Battleground Team
 * @param bg_id Id of the battleground
 * @param sd pointer to the player's session data.
 * @return 0 on failure, 1 on success.
 */
int hBG_team_join(int bg_id, struct map_session_data *sd)
{ // Player joins team
	int i;
	struct battleground_data *bgd = bg->team_search(bg_id);
	struct map_session_data *pl_sd;
	struct hBG_map_session_data *hBGsd;
	struct hBG_data *hBGd;

	if (bgd == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL || sd == NULL || sd->bg_id)
		return 0;

	ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd == NULL);
	
	if (i == MAX_BG_MEMBERS)
		return 0; // No free slots

	// Handle Additional Map Session BG data
	if ((hBGsd = getFromMSD(sd, 1)) == NULL) {
		CREATE(hBGsd, struct hBG_map_session_data, 1);
		addToMSD(sd, hBGsd, 1, false);
	}
	
	hBGsd->bg_kills = 0;
	hBGsd->state.afk = 0;

	// Update player's idle item.
	pc->update_idle_time(sd, BCIDLE_WALK);

	sd->bg_id = bg_id;

	// Battleground Member data
	bgd->members[i].sd = sd;
	bgd->members[i].x = sd->bl.x;
	bgd->members[i].y = sd->bl.y;
	bgd->count++;
	
	// Guild Member Data simulation
	hBGd->g->member[i].sd = sd;

	// Creation Tick = First member joined.
	if (hBGd->created_at == 0)
		hBGd->created_at = sockt->last_tick;

	// First Join = Team Leader
	if (hBGd->leader_char_id == 0)
		hBGd->leader_char_id = sd->status.char_id;

	guild->send_dot_remove(sd);

	hBG_send_guild_info(sd); // Send Guild Name/Emblem under character
	
	clif->charnameupdate(sd); // Update character's nameplate
	
	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((pl_sd = bgd->members[i].sd) == NULL)
			continue;

		// Simulate Guild Information
		hBG_guild_window_info(pl_sd); // Main Guild window information.
		hBG_send_emblem(pl_sd, hBGd->g); // Emblems
		hBG_send_guild_member_list(pl_sd); // Member list
		hBG_send_guild_skillinfo(sd); // Send Guild skill information.

		if (pl_sd != sd)
			hBG_send_hp_single(sd->fd,pl_sd);
	}

	clif->guild_emblem_area(&sd->bl);

	clif->bg_hp(sd);
	clif->bg_xy(sd);

	return 1;
}

/**
 * Reveal a player's position to another player.
 * @param bl pointer to block list.
 * @param ap list of arguments
 * @return 0.
 */
int hBG_reveal_pos(struct block_list *bl, va_list ap)
{
	struct map_session_data *pl_sd, *sd = NULL;
	int flag, color;

	pl_sd = (struct map_session_data *)bl;
	sd = va_arg(ap,struct map_session_data *); // Source
	flag = va_arg(ap,int);
	color = va_arg(ap,int);

	if (pl_sd->bg_id == sd->bg_id)
		return 0; // Same Team

	clif->viewpoint(pl_sd,sd->bl.id,flag,sd->bl.x,sd->bl.y,sd->bl.id,color);
	return 0;
}

/**
 * Remove minimap indicator for player.
 * @param sd pointer to session data.
 * @return 0
 */
int hBG_send_dot_remove(struct map_session_data *sd)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int m;

	if (sd && sd->bg_id && (bgd = bg->team_search(sd->bg_id)) != NULL
	   && (hBGd = getFromBGDATA(bgd, 0)) != NULL) {
		clif->bg_xy_remove(sd);
		if (hBGd->reveal_pos && (m = map->mapindex2mapid(bgd->mapindex)) == sd->bl.m)
			map->foreachinmap(hBG_reveal_pos, m,BL_PC,sd,2,0xFFFFFF);
	}
	return 0;
}

/**
 * Searches and removes battleground game specific 
 * items from the player's inventory.
 * @param sd as struct map_session_data
 */
void hBG_member_remove_bg_items(struct map_session_data *sd)
{
	int n;
	
	nullpo_retv(sd);
	
	if ((n = pc->search_inventory(sd,BLUE_SKULL)) >= 0)
		pc->delitem(sd, n, sd->status.inventory[n].amount, 0, 2, LOG_TYPE_CONSUME);
	
	if ((n = pc->search_inventory(sd,RED_SKULL)) >= 0)
		pc->delitem(sd, n, sd->status.inventory[n].amount, 0, 2,LOG_TYPE_CONSUME);
	
	if ((n = pc->search_inventory(sd,GREEN_SKULL)) >= 0)
		pc->delitem(sd, n, sd->status.inventory[n].amount, 0, 2,LOG_TYPE_CONSUME);
}

/**
 * Get guild data of the Battleground
 * @param bg_id ID of the battleground
 * @return guild of the battleground or NULL.
 */
struct guild* hBG_get_guild(int bg_id)
{
	struct battleground_data *bgd = bg->team_search(bg_id);
	struct hBG_data *hBGd;

	if (bgd == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
		return NULL;

	return hBGd->g;
}

/**
 * Remove all members from a BG Team.
 * @param bg_id ID of the battleground.
 * @param remove Boolean for removal of BG from team_db.
 * @return 0 on failure, 1 on success.
 */
int hBG_team_finalize(int bg_id, bool remove)
{ // Deletes BG Team from db
	int i;
	struct map_session_data *sd;
	struct battleground_data *bgd = bg->team_search(bg_id);
	struct hBG_data *hBGd;
	struct guild *g;

	if (bgd == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
		return 0;

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL)
			continue;

		hBG_send_dot_remove(sd);
		sd->bg_id = 0;

		// Remove Guild Skill Buffs
		status_change_end(&sd->bl, SC_GUILDAURA, INVALID_TIMER);
		status_change_end(&sd->bl, SC_GDSKILL_BATTLEORDER, INVALID_TIMER);
		status_change_end(&sd->bl, SC_GDSKILL_REGENERATION, INVALID_TIMER);

		if (sd->status.guild_id && (g = guild->search(sd->status.guild_id)) != NULL) {
			clif->guild_belonginfo(sd,g);
			clif->guild_basicinfo(sd);
			clif->guild_allianceinfo(sd);
			clif->guild_memberlist(sd);
			clif->guild_skillinfo(sd);
		} else {
			hBG_send_leave_single(sd, sd->status.name, "Leaving Battle...");
		}

		clif->charnameupdate(sd);
		clif->guild_emblem_area(&sd->bl);
	}

	if (remove) {
		idb_remove(bg->team_db, bg_id);
	} else {
		bgd->count = 0;
		hBGd->leader_char_id = 0;
		hBGd->team_score = 0;
		hBGd->created_at = 0;
		memset(&bgd->members, 0, sizeof(bgd->members));
	}

	return 1;
}

/**
 * Give items to the Battleground Team.
 * @param bg_id ID of the battleground.
 * @param nameid ID of the item.
 * @param amount Amount of the Item to be given.
 * @return void;
 */
void hBG_team_getitem(int bg_id, int nameid, int amount)
{
	struct battleground_data *bgd;
	struct map_session_data *sd;
	struct item_data *id;
	struct item it;
	int reward_rate = hBG_config_get("battle_configuration/bg_reward_rates");
	int get_amount, j, flag;

	if (amount < 1 || (bgd = bg->team_search(bg_id)) == NULL || (id = itemdb->exists(nameid)) == NULL)
		return;
	if (nameid != 7828 && nameid != 7829 && nameid != 7773)
		return;
	if (reward_rate != 100)
		amount = amount * reward_rate / 100;

	memset(&it, 0, sizeof(it));
	it.nameid = nameid;
	it.identify = 1;

	for (j = 0; j < MAX_BG_MEMBERS; j++) {
		if ((sd = bgd->members[j].sd) == NULL)
			continue;

		get_amount = amount;

		if ((flag = pc->additem(sd,&it,get_amount,LOG_TYPE_SCRIPT)))
			clif->additem(sd,0,0,flag);
	}
}

/**
 * Give kafra points to the team.
 * @param bg_id ID of the battleground.
 * @param amount Amount of kafra points to be given.
 */
void hBG_team_get_kafrapoints(int bg_id, int amount)
{
	struct battleground_data *bgd;
	struct map_session_data *sd;
	int i, get_amount, reward_rate = hBG_config_get("battle_configuration/bg_reward_rates");

	if ((bgd = bg->team_search(bg_id)) == NULL)
		return;

	if (reward_rate != 100)
		amount = amount * reward_rate/ 100;

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL)
			continue;

		get_amount = amount;
		pc->getcash(sd,0,get_amount);
	}
}

void hBG_add_rank_points(struct map_session_data *sd, int ranktype, int count)
{
	struct hBG_map_session_data *hBGsd;
	char message[100];
	
	nullpo_retv(sd);
	
	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return;
	
	if (ranktype == BG_RANKED) {
		add2limit(hBGsd->stats.ranked_points, count, MAX_FAME);
		sprintf(message, "[Battlegrounds Ranked] Your ranking has increased by %d.", count);
		clif->disp_message(&sd->bl, message, SELF);
		hookStop();
	} else if (ranktype == BG_NORMAL) {
		add2limit(hBGsd->stats.points, count, MAX_FAME);
		sprintf(message, "[Battlegrounds Normal] Your ranking has increased by %d.", count);
		clif->disp_message(&sd->bl, message, SELF);
		hookStop();
	}
}

/* ==============================================================
 bg_arena (0 EoS | 1 Boss | 2 TI | 3 CTF | 4 TD | 5 SC | 6 CON | 7 RUSH | 8 DOM)
 bg_result (0 Won | 1 Tie | 2 Lost)
 ============================================================== */
void hBG_team_rewards(int bg_id, int nameid, int amount, int kafrapoints, int quest_id, const char *var, int add_value, int bg_arena, int bg_result)
{
	struct battleground_data *bgd = NULL;
	struct map_session_data *sd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;
	struct hBG_data *hBGd = NULL;
	struct item_data *id;
	struct item it;
	int j, flag, get_amount,
	reward_rate = hBG_config_get("battle_configuration/hBG_reward_rates"), fame = 0, type = 0;
	
	if (amount < 1 || (bgd = bg->team_search(bg_id)) == NULL || (id = itemdb->exists(nameid)) == NULL)
		return;

	if (reward_rate != 100) { // BG Reward Rates
		amount = amount * reward_rate / 100;
		kafrapoints = kafrapoints * reward_rate / 100;
	}
	
	memset(&it,0,sizeof(it));
	
	bg_result = cap_value(bg_result, 0, 2);
	
	if (nameid == 7828 || nameid == 7829 || nameid == 7773) {
		it.nameid = nameid;
		it.identify = 1;
	} else {
		nameid = 0;
	}

	for (j = 0; j < MAX_BG_MEMBERS; j++) {
		if ((sd = bgd->members[j].sd) == NULL)
			continue;
		else if ((hBGsd = getFromMSD(sd, 1)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
			continue;

		if (quest_id)
			quest->add(sd, quest_id, 0);
		
		pc_setglobalreg(sd, script->add_str(var), pc_readglobalreg(sd,script->add_str(var)) + add_value);

		if (kafrapoints > 0) {
			get_amount = kafrapoints;
			pc->getcash(sd,0,get_amount);
		}

		if (nameid && amount > 0) {
			get_amount = amount;

			if ((flag = pc->additem(sd,&it,get_amount,LOG_TYPE_SCRIPT)))
				clif->additem(sd,0,0,flag);
		}
		
		type = hBG_config_get("battle_configuration/hBG_ranked_mode")?BG_RANKED:BG_NORMAL;
		
		switch (bg_result) {
			case 0: // Won
				add2limit(hBGsd->stats.wins,1,USHRT_MAX);
				fame = 100;
				if (sd->status.char_id == hBGd->leader_char_id) {
					add2limit(hBGsd->stats.wins_as_leader,1,USHRT_MAX);
					fame += 25;
				}
				
				hBG_add_rank_points(sd, fame, type);
				
				switch (bg_arena) {
					case 0:
						add2limit(hBGsd->stats.eos_wins,1,USHRT_MAX);
						break;
					case 1:
						add2limit(hBGsd->stats.boss_wins,1,USHRT_MAX);
						break;
					case 2:
						add2limit(hBGsd->stats.ti_wins,1,USHRT_MAX);
						break;
					case 3:
						add2limit(hBGsd->stats.ctf_wins,1,USHRT_MAX);
						break;
					case 4:
						add2limit(hBGsd->stats.td_wins,1,USHRT_MAX);
						break;
					case 5:
						add2limit(hBGsd->stats.sc_wins,1,USHRT_MAX);
						break;
					case 6:
						add2limit(hBGsd->stats.conquest_wins,1,USHRT_MAX);
						break;
					case 7:
						add2limit(hBGsd->stats.ru_wins,1,USHRT_MAX);
						break;
					case 8:
						add2limit(hBGsd->stats.dom_wins,1,USHRT_MAX);
						break;
				}
				break;
			case 1: // Tie
				add2limit(hBGsd->stats.ties,1,USHRT_MAX);
				fame = 75;
				if (sd->status.char_id == hBGd->leader_char_id) {
					add2limit(hBGsd->stats.ties_as_leader,1,USHRT_MAX);
					fame += 10;
				}
				hBG_add_rank_points(sd, fame, type);
				switch (bg_arena) {
					case 0: add2limit(hBGsd->stats.eos_tie,1,USHRT_MAX); break;
					case 1: add2limit(hBGsd->stats.boss_tie,1,USHRT_MAX); break;
					case 2: add2limit(hBGsd->stats.ti_tie,1,USHRT_MAX); break;
					case 3: add2limit(hBGsd->stats.ctf_tie,1,USHRT_MAX); break;
					case 4: add2limit(hBGsd->stats.td_tie,1,USHRT_MAX); break;
					case 5: add2limit(hBGsd->stats.sc_tie,1,USHRT_MAX); break;
						// No Tie for Conquest or Rush
					case 8: add2limit(hBGsd->stats.dom_tie,1,USHRT_MAX); break;
				}
				break;
			case 2: // Lost
				add2limit(hBGsd->stats.losses,1,USHRT_MAX);
				
				fame = 50;
				
				if (sd->status.char_id == hBGd->leader_char_id)
					add2limit(hBGsd->stats.losses_as_leader,1,USHRT_MAX);
				
				hBG_add_rank_points(sd, fame, type);
				
				switch (bg_arena) {
					case 0: add2limit(hBGsd->stats.eos_lost,1,USHRT_MAX); break;
					case 1: add2limit(hBGsd->stats.boss_lost,1,USHRT_MAX); break;
					case 2: add2limit(hBGsd->stats.ti_lost,1,USHRT_MAX); break;
					case 3: add2limit(hBGsd->stats.ctf_lost,1,USHRT_MAX); break;
					case 4: add2limit(hBGsd->stats.td_lost,1,USHRT_MAX); break;
					case 5: add2limit(hBGsd->stats.sc_lost,1,USHRT_MAX); break;
					case 6: add2limit(hBGsd->stats.conquest_losses,1,USHRT_MAX); break;
					case 7: add2limit(hBGsd->stats.ru_lost,1,USHRT_MAX); break;
					case 8: add2limit(hBGsd->stats.dom_lost,1,USHRT_MAX); break;
				}
				break;
		}
	}
}

/**
 * Build BG Guild Emulation data.
 * @params (void)
 * @return void.
 */
void hBG_build_guild_data(void)
{
	int i, j, k, gskill;
	memset(&bg_guild, 0, sizeof(bg_guild));

	for (i = 1; i <= MAX_BATTLEGROUND_TEAMS; i++) { // Emblem Data - Guild ID's
		FILE* fp = NULL;
		char gpath[256];

		j = i - 1;
		bg_guild[j].emblem_id = 1; // Emblem Index
		bg_guild[j].guild_id = SHRT_MAX - j;
		bg_guild[j].guild_lv = 1;
		bg_guild[j].max_member = MAX_BG_MEMBERS;

		// Skills
		if (j < 3) { // Clan Skills
			for (k = 0; k < MAX_GUILDSKILL; k++) {
				gskill = k + GD_SKILLBASE;
				bg_guild[j].skill[k].id = gskill;
				switch (gskill) {
					case GD_GLORYGUILD:
						bg_guild[j].skill[k].lv = 0;
						break;
					case GD_APPROVAL:
					case GD_KAFRACONTRACT:
					case GD_GUARDRESEARCH:
					case GD_BATTLEORDER:
					case GD_RESTORE:
					case GD_EMERGENCYCALL:
					case GD_DEVELOPMENT:
						bg_guild[j].skill[k].lv = 1;
						break;
					case GD_GUARDUP:
					case GD_REGENERATION:
						bg_guild[j].skill[k].lv = 3;
						break;
					case GD_LEADERSHIP:
					case GD_GLORYWOUNDS:
					case GD_SOULCOLD:
					case GD_HAWKEYES:
						bg_guild[j].skill[k].lv = 5;
						break;
					case GD_EXTENSION:
						bg_guild[j].skill[k].lv = 10;
						break;
				}
			}
		} else { // Other Data
			snprintf(bg_guild[j].name, NAME_LENGTH, "Team %d", i - 3); // Team 1, Team 2 ... Team 10
			strncpy(bg_guild[j].master, bg_guild[j].name, NAME_LENGTH);
			snprintf(bg_guild[j].position[0].name, NAME_LENGTH, "%s Leader", bg_guild[j].name);
			strncpy(bg_guild[j].position[1].name, bg_guild[j].name, NAME_LENGTH);
		}

		sprintf(gpath, "%s/%s/bg_%d.ebm", "plugins","hBG", i);
		if ((fp = fopen(gpath, "rb")) != NULL) {
			fseek(fp, 0, SEEK_END);
			bg_guild[j].emblem_len = (int)ftell(fp);
			fseek(fp, 0, SEEK_SET);
			fread(&bg_guild[j].emblem_data, 1, bg_guild[j].emblem_len, fp);
			fclose(fp);
		} else {
			ShowWarning("Error reading '"CL_WHITE"%s"CL_RESET"' emblem data file.\n", gpath);
		}
	}
	
	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"' v%s emblem data files. [By Smokexyz]\n", pinfo.name, pinfo.version);

	// Guild Data - Guillaume
	strncpy(bg_guild[0].name, "Blue Team", NAME_LENGTH);
	strncpy(bg_guild[0].master, "General Guillaume", NAME_LENGTH);
	strncpy(bg_guild[0].position[0].name, "Blue Team Leader", NAME_LENGTH);
	strncpy(bg_guild[0].position[1].name, "Blue Team", NAME_LENGTH);

	// Guild Data - Croix
	strncpy(bg_guild[1].name, "Red Team", NAME_LENGTH);
	strncpy(bg_guild[1].master, "Prince Croix", NAME_LENGTH);
	strncpy(bg_guild[1].position[0].name, "Red Team Leader", NAME_LENGTH);
	strncpy(bg_guild[1].position[1].name, "Red Team", NAME_LENGTH);

	// Guild Data - Traitors
	strncpy(bg_guild[2].name, "Green Team", NAME_LENGTH);
	strncpy(bg_guild[2].master, "Mercenary", NAME_LENGTH);
	strncpy(bg_guild[2].position[0].name, "Green Team Leader", NAME_LENGTH);
	strncpy(bg_guild[2].position[1].name, "Green Team", NAME_LENGTH);
}

/**
 * Timer function for revealing/hiding mini map positions.
 * Also handles player AFK mechanic.
 * @see DBApply
 * @see hBG_send_xy_timer
 * @param data battleground data pointer.
 * @return int
 */
int hBG_send_xy_timer_sub(union DBKey key, struct DBData *data, va_list ap)
{
	struct battleground_data *bgd = DB->data2ptr(data);
	struct hBG_data *hBGd = getFromBGDATA(bgd, 0);
	char output[128];
	int i, m, idle_announce = hBG_config_get("battle_configuration/hBG_idle_announce"),
		idle_autokick = hBG_config_get("battle_configuration/hBG_idle_autokick");

	nullpo_ret(bgd);
	nullpo_ret(hBGd);

	m = map->mapindex2mapid(bgd->mapindex);
	hBGd->reveal_flag = !hBGd->reveal_flag; // Switch

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		struct map_session_data *sd = bgd->members[i].sd;
		struct hBG_map_session_data *hBGsd = NULL;

		if (sd == NULL || (hBGsd = getFromMSD(sd, 1)) == NULL)
			continue;

		if (idle_autokick && DIFF_TICK(sockt->last_tick, sd->idletime) >= idle_autokick
			&& hBGd->g && map->list[sd->bl.m].flag.battleground)
		{
			sprintf(output, "[Battlegrounds] %s has been kicked for being AFK.", sd->status.name);
			clif->broadcast2(&sd->bl, output, (int)strlen(output)+1, hBGd->color, 0x190, 20, 0, 0, BG);

			bg->team_leave(sd,3);

			clif->message(sd->fd, "You have been kicked from the battleground because of your AFK status.");
			pc->setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 3);
			continue;
		} else if (sd->bl.x != bgd->members[i].x || sd->bl.y != bgd->members[i].y) { // xy update
			bgd->members[i].x = sd->bl.x;
			bgd->members[i].y = sd->bl.y;
			clif->bg_xy(sd);
		}
		
		if (hBGd->reveal_pos && hBGd->reveal_flag && sd->bl.m == m)
			map->foreachinmap(hBG_reveal_pos, m, BL_PC, sd, 1, hBGd->color);
		
		// Message for AFK Idling
		if (idle_announce && DIFF_TICK(sockt->last_tick, sd->idletime) >= idle_announce && !hBGsd->state.afk && hBGd->g)
		{ // Set AFK status and announce to the team.
			hBGsd->state.afk = 1;
			sprintf(output, "%s : %s seems to be away. AFK Warning - Can be kicked out with @reportafk.", hBGd->g->name, sd->status.name);
			hBG_send_chat_message(bgd, sd->bl.id, sd->status.name, output, (int)strlen(output) + 1);
		}
	}

	return 0;
}

/**
 * Timer function for revealing/hiding mini map positions.
 * Also handles player AFK time.
 * @see hBG_send_xy_timer_sub
 */
int hBG_send_xy_timer(int tid, int64 tick, int id, intptr_t data)
{
	bg->team_db->foreach(bg->team_db, hBG_send_xy_timer_sub, tick);
	return 0;
}

/**
 * Add an item to the floor at m (x,y)
 * @param bl pointer to the block list.
 * @param m map index
 * @param x map x co-ordinate
 * @param y map y co-ordinate
 * @param nameid ID of the item to be dropped.
 * @param amount Amount of the item to be dropped.
 * @return count of the item dropped.
 */
int hBG_addflooritem_area(struct block_list* bl, int16 m, int16 x, int16 y, int nameid, int amount)
{
	struct item item_tmp;
	int count, range, i;
	short mx, my;
	
	memset(&item_tmp, 0, sizeof(item_tmp));
	item_tmp.nameid = nameid;
	item_tmp.identify = 1;
	
	if (bl != NULL) m = bl->m;
	
	count = 0;
	range = (int)sqrt((float)amount) +2;
	
	for ( i = 0; i < amount; i++) {
		if (bl != NULL)
			map->search_freecell(bl, 0, &mx, &my, range, range, 0);
		else {
			mx = x; my = y;
			map->search_freecell(NULL, m, &mx, &my, range, range, 1);
		}
		
		count += (map->addflooritem(bl, &item_tmp, 1, m, mx, my, 0, 0, 0, 4, false) != 0) ? 1 : 0;
	}
	
	return count;
}

// @TODO
void hBG_bg_ranking_display(struct map_session_data *sd, bool ranked)
{
	struct hBG_map_session_data *hBGsd = NULL;
	
	nullpo_retv(sd);
	
	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return;
	
	// print shit.
	
}

void hBG_record_mobkills(struct map_session_data *sd, struct mob_data *md)
{
	struct battleground_data *bgd = NULL;
	struct hBG_data *hBGd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;

	nullpo_retv(sd);
	nullpo_retv(md);

	if (map->list[sd->bl.m].flag.battleground && sd->bg_id) {
		int i;
		if ((bgd = bg->team_search(sd->bg_id)) == NULL)
			return;
		if ((hBGd = getFromBGDATA(bgd, 0)) == NULL)
			return;
		if ((hBGsd = getFromMSD(sd, 1)) == NULL)
			return;

		ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd == sd);

		if (i >= MAX_BG_MEMBERS)
			return;

		switch ( md->class_)
		{
		case E_BAPHOMET2:
		case E_LORD_OF_DEATH2:
		case E_DARK_LORD:
		case E_KTULLANUX:
		case E_DARK_SNAKE_LORD:
			add2limit(hBGsd->stats.boss_killed, 1, USHRT_MAX);
			break;
		case E_TURTLE_GENERAL:
		case E_APOCALIPS_H:
			add2limit(hBGsd->stats.guardian_stone_kills, 1, USHRT_MAX);
			break;
		case E_FALLINGBISHOP:
			if (map->list[sd->bl.m].flag.battleground == 2)
				add2limit(hBGsd->stats.ru_captures, 1, USHRT_MAX);
			break;
		case OBJ_NEUTRAL:
			if (strcmpi(map->list[sd->bl.m].name, "bat_a03") == 0)
				add2limit(hBGsd->stats.boss_flags, 1, USHRT_MAX);
			break;
		case BARRICADE_:
			if (strcmpi(map->list[sd->bl.m].name, "bat_a01") == 0)
				add2limit(hBGsd->stats.barricade_kills, 1, USHRT_MAX);
			break;
		}
	}
}

void hBG_record_damage(struct block_list *src, struct block_list *target, int damage)
{
	struct block_list *s_bl = NULL;
	struct map_session_data *sd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;

	if (src == NULL || target == NULL || src == target || damage <= 0)
		return;

	if ((s_bl = battle->get_master(src)) == NULL)
		s_bl = src;

	if (s_bl->type != BL_PC)
		return;

	if ((sd = BL_UCAST(BL_PC, s_bl)) == NULL)
		return;

	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return;

	switch ( target->type)
	{
	case BL_PC:
		{
			struct map_session_data *tsd = NULL;
			struct hBG_map_session_data *hBGtsd = NULL;

			if ((tsd = BL_UCAST(BL_PC, target)) == NULL)
				break;
			if ((hBGtsd = getFromMSD(tsd, 1)) == NULL)
				break;

			if (map->list[src->m].flag.battleground && sd->bg_id) {
				add2limit(hBGsd->stats.total_damage_done, damage, UINT_MAX);
				add2limit(hBGtsd->stats.total_damage_received, damage, UINT_MAX);

				if (hBGsd->stats.best_damage < damage)
					hBGsd->stats.best_damage = damage;
			}
		}
		break;
	case BL_MOB:
		{
			struct mob_data *md = BL_UCAST(BL_MOB, target);
			if (map->list[src->m].flag.battleground && sd->bg_id && md->class_ >= E_BAPHOMET2 && md->class_ <= E_FALLINGBISHOP)
				add2limit(hBGsd->stats.boss_damage, damage, USHRT_MAX);
		}
		break;
	}
}

/**
 * Warps a Team
 * @see hBG_warp
 */
int hBG_team_warp(int bg_id, unsigned short mapidx, short x, short y)
{ // Warps a Team
	int i;
	struct battleground_data *bgd = bg->team_search(bg_id);

	if (bgd == NULL) {
		ShowError("buildin_hBG_team_warp: Invalid teamId %d provided!", bg_id);
		return false;
	}

	if (mapidx == 0) { // BG Cemetery (Spawn Point)
		mapidx = bgd->mapindex;
		x = bgd->x;
		y = bgd->y;
	}

	for (i = 0; i < bgd->count; i++)
		if (bgd->members[i].sd != NULL)
			pc->setpos(bgd->members[i].sd, mapidx, x, y, CLR_TELEPORT);

	return true;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     @Commands
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
 * Display battleground rankings.
 */
ACMD(bgrank)
{
	char mode[7];
	char atcmd_output[256];
	
	memset(atcmd_output, '\0', sizeof(atcmd_output));
	
	if (!*message || sscanf(message, "%7s", mode) < 1) {
		sprintf(atcmd_output, "Please, enter a battleground mode (usage: @bgrank <ranked/normal>).");
		clif->message(fd, atcmd_output);
		return false;
	}
	
	if (strncmpi(mode, "ranked", 7) == 0) {
		hBG_bg_ranking_display(sd, true);
	} else if (strncmpi(mode, "normal", 7) == 0) {
		hBG_bg_ranking_display(sd, true);
	} else {
		sprintf(atcmd_output, "Please, enter a battleground mode (usage: @bgrank <ranked/normal>).");
		clif->message(fd, atcmd_output);
		return false;
	}
	
	return true;
}

ACMD(reportafk)
{
	struct map_session_data *pl_sd = NULL;
	struct hBG_data *hBGd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;
	struct hBG_map_session_data *hBGpl_sd = NULL;
	struct battleground_data *bgd = NULL;
	
	if ((bgd = bg->team_search(sd->bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
		clif->message(fd, "This command is reserved for Battlegrounds Only.");
	else if (!(hBGd->leader_char_id == sd->status.char_id) && hBG_config_get("battle_configuration/hBG_reportafk_leaderonly"))
		clif->message(fd, "This command is reserved for Team Leaders Only.");
	else if (!*message)
		clif->message(fd, "Please, enter the character name (usage: @reportafk <name>).");
	else if ((pl_sd = map->nick2sd(message)) == NULL)
		clif->message(fd, msg_txt(3)); // Character not found.
	else if ((hBGpl_sd = getFromMSD(pl_sd, 0)) == NULL)
		clif->message(fd, "Destination Player is not in battlegrounds.");
	else if (sd->bg_id != pl_sd->bg_id)
		clif->message(fd, "Destination Player is not in your Team.");
	else if (sd == pl_sd)
		clif->message(fd, "You cannot kick yourself.");
	else if (!hBGpl_sd->state.afk)
		clif->message(fd, "The player is not AFK on this Battleground.");
	else
	{ // Everything is fine!
		char atcmd_output[256];
		
		 // Kick the player and send a message.
		bg->team_leave(pl_sd, 2);
		clif->message(pl_sd->fd, "You have been kicked from Battleground because of your AFK status.");
		pc->setpos(pl_sd, pl_sd->status.save_point.map, pl_sd->status.save_point.x, pl_sd->status.save_point.y, 3);
		// Message the source player and announce to team.
		sprintf(atcmd_output, "%s has been successfully kicked.", pl_sd->status.name);
		clif->broadcast2(&sd->bl, atcmd_output, (int)strlen(atcmd_output)+1, hBGd->color, 0x190, 20, 0, 0, BG);
		return true;
	}
	
	return false;
}

/**
 * Change Team Leader.
 */
ACMD(leader)
{
	struct map_session_data *pl_sd = NULL;
	struct hBG_data *hBGd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;
	struct hBG_map_session_data *hBGpl_sd = NULL;
	struct battleground_data *bgd = NULL;
	
	if ((bgd = bg->team_search(sd->bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
		clif->message(fd, "This command is reserved for Battlegrounds Only.");
	else if (sd->ud.skilltimer != INVALID_TIMER)
		clif->message(fd, "Command not allow while casting a skill.");
	else if (!(hBG_config_get("battle_configuration/hBG_leader_change")))
		clif->message(fd, "This command is disabled.");
	else if (!(hBGd->leader_char_id == sd->status.char_id))
		clif->message(fd, "This command is reserved for Team Leaders Only.");
	else if (!*message)
		clif->message(fd, "Please, enter the character name (usage: @leader <name>).");
	else if ((pl_sd = map->nick2sd(message)) == NULL)
		clif->message(fd, msg_txt(3)); // Character not found.
	else if ((hBGpl_sd = getFromMSD(pl_sd, 0)) == NULL)
		clif->message(fd, "Destination Player is not in battlegrounds.");
	else if (sd->bg_id != pl_sd->bg_id)
		clif->message(fd, "Destination Player is not in your Team.");
	else if (sd == pl_sd)
		clif->message(fd, "You are already the Team Leader.");
	else
	{ // Everything is fine... more or less.
		char atcmd_output[256];
		sprintf(atcmd_output, "Team Leader transfered to [%s]", pl_sd->status.name);
		clif->broadcast2(&sd->bl, atcmd_output, (int)strlen(atcmd_output) + 1, hBGd->color, 0x190, 20, 0, 0, BG);
		hBGd->leader_char_id = pl_sd->status.char_id;
		clif->charnameupdate(sd);
		clif->charnameupdate(pl_sd);
		return true;
	}
	return false;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Script Commands
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Send out a battleground announcement.
 * @param mes
 * @param fontColor
 * @param fontType
 * @param fontSize
 * @param fontAlign
 * @param fontY
 */
BUILDIN(hBG_announce)
{
	const char *mes       = script_getstr(st,2);
	const char *fontColor = script_hasdata(st,3) ? script_getstr(st,3) : NULL;
	int         fontType  = script_hasdata(st,4) ? script_getnum(st,4) : 0x190; // default fontType (FW_NORMAL)
	int         fontSize  = script_hasdata(st,5) ? script_getnum(st,5) : 12;    // default fontSize
	int         fontAlign = script_hasdata(st,6) ? script_getnum(st,6) : 0;     // default fontAlign
	int         fontY     = script_hasdata(st,7) ? script_getnum(st,7) : 0;     // default fontY

	clif->broadcast2(NULL, mes, (int)strlen(mes) + 1, (unsigned int)strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, ALL_CLIENT);

	return true;
}

/**
 * Count the number of logins per IP in battleground
 * @return count of accounts on same ip.
 */
BUILDIN(hBG_logincount)
{
	struct map_session_data *sd = script->rid2sd(st);
	int i = 0;

	if (sd)
		i = hBG_countlogin(sd,true);

	script_pushint(st,i);
	return true;
}

/**
 * Create a BG Team.
 * @param map_name Respawn Map Name
 * @param map_x Respawn Map X
 * @param map_y Respawn Map Y
 * @param guild_index BG Guild Index
 * @param ev Logout Event
 * @param dev Die Event
 */
BUILDIN(hBG_team_create)
{
	const char *map_name, *ev = "", *dev = "";
	int x, y, m = 0, guild_index, bg_id;

	map_name = script_getstr(st, 2);
	if (strcmp(map_name,"-") != 0 && (m = mapindex->name2id(map_name)) == 0) {
		script_pushint(st, 0);
		return false;
	}

	x = script_getnum(st, 3);
	y = script_getnum(st, 4);
	guild_index = script_getnum(st, 5);
	ev = script_getstr(st, 6); // Logout Event
	dev = script_getstr(st, 7); // Die Event

	guild_index = cap_value(guild_index, 0, 12);
	bg_id = hBG_create(m, x, y, guild_index, ev, dev);

	script_pushint(st, bg_id);
	return true;
}

/**
 * Create a Queue
 * @param queue_name Name of the Queue
 * @param jev Join Event
 * @param min_level Minimum level to join the queue.
 * @return queue Id
 */
BUILDIN(hBG_queue_create)
{
	const char *queue_name, *jev;
	int min_level = 0;

	queue_name = script_getstr(st, 2);
	jev = script_getstr(st, 3);
	
	if (script_hasdata(st, 4))
		min_level = script_getnum(st, 4);

	script_pushint(st, hBG_queue_create(queue_name, jev, min_level));

	return true;
}


/**
 * Changes/Sets the Queue's Join Event.
 * @param queue_id
 * @param jev On Join Event
 */
BUILDIN(hBG_queue_event)
{
	struct hBG_queue_data *hBGqd;
	const char *join_event;
	int q_id;

	q_id = script_getnum(st,2);

	if ((hBGqd = hBG_queue_search(q_id)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	join_event = script_getstr(st,3);

	safestrncpy(hBGqd->join_event, join_event, sizeof(hBGqd->join_event));

	script_pushint(st, 1);
	return true;
}

/**
 * Makes a player join a queue.
 * @param Queue ID
 */
BUILDIN(hBG_queue_join)
{
	int q_id;
	struct map_session_data *sd = script->rid2sd(st);

	nullpo_retr(false, sd);

	q_id = script_getnum(st,2);

	script_pushint(st, hBG_queue_join(sd, q_id));

	return true;
}

/**
 * Makes party join a queue.
 * @param Party ID
 * @param Queue ID
 */
BUILDIN(hBG_queue_partyjoin)
{
	int q_id, i, party_id;
	struct map_session_data *sd;
	struct party_data *p;

	party_id = script_getnum(st,2);

	if (party_id <= 0 || (p = party->search(party_id)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	q_id = script_getnum(st,3);

	if (hBG_queue_search(q_id) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	for (i = 0; i < MAX_PARTY; i++) {
		if ((sd = p->data[i].sd) == NULL)
			continue;
		hBG_queue_join(sd,q_id);
	}

	script_pushint(st, 1);

	return true;
}

/**
 * Makes a player leave a queue.
 * @param Queue ID
 */
BUILDIN(hBG_queue_leave)
{
	int q_id;
	struct map_session_data *sd = script->rid2sd(st);

	nullpo_retr(false, sd);

	q_id = script_getnum(st,2);

	script_pushint(st, hBG_queue_leave(sd, q_id));

	return true;
}

/**
 * Request queue information
 * @param Queue ID
 * @param Information Type
 *        0) Users
 *        1) Copy user list to $@qmembers$ variable and return count.
 */
BUILDIN(hBG_queue_data)
{
	struct hBG_queue_data *hBGqd;
	int q_id = script_getnum(st,2),
	type = script_getnum(st,3);

	if ((hBGqd = hBG_queue_search(q_id)) == NULL) {
		script_pushint(st,0);
		return false;
	}

	switch (type) {
		case 0:
			script_pushint(st, hBGqd->users);
			return true;
		case 1: // User List
		{
			int j = 0;
			struct map_session_data *sd;
			struct hBG_queue_member *head;
			head = hBGqd->first;
			while (head) {
				if ((sd = head->sd) != NULL) {
					mapreg->setregstr(reference_uid(script->add_str("$@qmembers$"),j),sd->status.name);
					j++;
				}
				head = head->next;
			}
			script_pushint(st,j);
		}
			return true;
		default:
			ShowError("script:hBG_queue_data: unknown queue data type %d.\n", type);
			break;
	}

	script_pushint(st, 0);
	return true;
}

/**
 * Adds all members in queue to a BG team.
 * @param Queue ID
 * @param Max Team Members
 * @param Respawn Map Name
 * @param Respawn Map X
 * @param Respawn Map Y
 * @param BG Guild Index
 * @param Logout Event
 * @param Die Event
 * @return Battleground Id
 */
BUILDIN(hBG_queue2team)
{
	struct hBG_queue_data *hBGqd;
	struct hBG_queue_member *qm;
	const char *map_name, *ev = "", *dev = "";
	int q_id, max, x, y, i, m=0, guild_index, bg_id;

	q_id = script_getnum(st,2);
	if ((hBGqd = hBG_queue_search(q_id)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	max = script_getnum(st,3);
	map_name = script_getstr(st,4);

	if (strcmp(map_name,"-") != 0 && (m = mapindex->name2id(map_name)) == 0) {
		script_pushint(st, 0);
		return false;
	}

	x = script_getnum(st,5);
	y = script_getnum(st,6);
	guild_index = script_getnum(st,7);
	ev = script_getstr(st,8); // Logout Event
	dev = script_getstr(st,9); // Die Event

	guild_index = cap_value(guild_index, 0, 12);

	if ((bg_id = hBG_create(m, x, y, guild_index, ev, dev)) == 0) {
		script_pushint(st, 0);
		return false;
	}

	i = 0; // Counter
	while ((qm = hBGqd->first) != NULL && i < max && i < MAX_BG_MEMBERS) {
		if (qm->sd && hBG_team_join(bg_id, qm->sd)) {
			mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), qm->sd->bl.id);
			hBG_queue_member_remove(hBGqd, qm->sd->bl.id);
			i++;
		} else {
			break; // Failed? Should not. Anyway, to avoid a infinite loop
		}
	}

	mapreg->setreg(script->add_str("$@arenamembersnum"), i);

	script_pushint(st, bg_id);

	return true;
}

/**
 * Joins the first player in the queue to the given team and warps him.
 * @param Queue ID
 * @param Battleground ID
 * @param Spawn Map Name
 * @param Spawn Map X Co-ordinate
 * @param Spawn Map Y Co-ordinate
 */
BUILDIN(hBG_queue2team_single)
{
	const char* map_name;
	struct hBG_queue_data *hBGqd;
	struct map_session_data *sd;
	int x, y, m, bg_id, q_id;

	q_id = script_getnum(st,2);

	if ((hBGqd = hBG_queue_search(q_id)) == NULL || !hBGqd->first || !hBGqd->first->sd) {
		script_pushint(st, 0);
		return false;
	}

	bg_id = script_getnum(st, 3);
	map_name = script_getstr(st, 4);

	if ((m = mapindex->name2id(map_name)) == 0) {
		script_pushint(st, 0);
		return false;
	}

	x = script_getnum(st, 5);
	y = script_getnum(st, 6);
	sd = hBGqd->first->sd;

	if (hBG_team_join(bg_id, sd)) {
		hBG_queue_member_remove(hBGqd, sd->bl.id);
		pc->setpos(sd, m, x, y, CLR_TELEPORT);
		script_pushint(st, 1);
	}

	return true;
}
/**
 * Check if the given BG Queue can start a BG in the given mode.
 * @param Queue ID
 * @param Type
 * @param Teams
 * @param Required Minimum Players
 * @return 1 can start, 0 cannot start.
 */
BUILDIN(hBG_queue_checkstart)
{
	int q_id, result = 0;
	struct hBG_queue_data *hBGqd;

	q_id = script_getnum(st,2);

	if ((hBGqd = hBG_queue_search(q_id)) != NULL) {
		int type, req_min, teams;

		type = script_getnum(st,3);
		teams = script_getnum(st,4);
		req_min = script_getnum(st,5);

		switch (type) {
			case 0: // Lineal, as they Join
			case 1: // Random
				if (hBGqd->users >= (req_min * teams))
					result = 1;
				break;
			default:
				result = 0;
				break;
		}
	}

	script_pushint(st, result);

	return true;
}

/**
 * Build BG Teams from one Queue
 * @param Queue ID
 * @param Minimum Players
 * @param Maximum Players per Team
 * @param Type
 * @param ... Team ID
 */
BUILDIN(hBG_queue2teams)
{ // Send Users from Queue to Teams. Requires previously created teams.
	struct hBG_queue_data *hBGqd;
	int t, bg_id = 0, total_teams = 0, q_id, min, max, type, limit = 0;
	int arg_offset = 6;
	struct map_session_data *sd;

	q_id = script_getnum(st,2); // Queue ID
	if ((hBGqd = hBG_queue_search(q_id)) == NULL) {
		ShowError("buildin_hBG_queue2teams: Non existant queue id received %d.\n", q_id);
		script_pushint(st, 0);
		return false;
	}

	min = script_getnum(st,3); // Min Members per Team
	max = script_getnum(st,4); // Max Members per Team
	type = script_getnum(st,5); // Team Building Method

	t = arg_offset; // Team ID's to build
	while (script_hasdata(st,t) && t < MAX_BATTLEGROUND_TEAMS+arg_offset) {
		bg_id = script_getnum(st,t);
		if (bg->team_search(bg_id) == NULL) {
			ShowError("buildin_hBG_queue2teams: Non existant team Id received %d.\n", bg_id);
			script_pushint(st, 0);
			return false;
		}
		t++;
	}
	total_teams = t - arg_offset;

	if (total_teams < 2) {
		ShowError("buildin_hBG_queue2teams: Less than 2 teams received to build members.\n");
		script_pushint(st, 0);
		return false;
	}

	if (hBGqd->users < min) {
		ShowError("buildin_hBG_queue2teams: Less than minimum %d queue members received (%d).\n", min, (int) hBGqd->users);
		script_pushint(st, 0);
		return false;
	}
	// How many players are we going to take from the Queue
	limit = min(max * total_teams, hBGqd->users);

	switch (type) {
		case 0: // Lineal - Maybe to keep party together
		{
			t = 0;
			int i = 0;
			for (i = 0; i < limit; i++) {
				if ((i%(limit/total_teams)) == 0) // Switch Team
					bg_id = script_getnum(st,t+arg_offset);
				
				if (!hBGqd->first || (sd = hBGqd->first->sd) == NULL)
					break; // No more people to join Teams
				
				hBG_team_join(bg_id, sd);
				hBG_queue_member_remove(hBGqd, sd->bl.id);
				
				// Increment Team counter or break
				if (t++ >= total_teams)
					break;
			}
		}
			break;
		default:
		case 1: // Random
		{
			t = 0;
			int pos = 0, i=0;
			struct hBG_queue_member *qm;

			for (i=0; t < limit; i++) {
				if ((i%(limit/total_teams)) == 0) // Switch Team
					bg_id = script_getnum(st,t+arg_offset);

				pos = 1 + rand() % (limit - i);
				
				if ((qm = hBG_queue_member_get(hBGqd, pos)) == NULL || (sd = qm->sd) == NULL)
					break;

				hBG_team_join(bg_id, sd);
				hBG_queue_member_remove(hBGqd, sd->bl.id);
				
				// Increment Team Counter or break
				if (t++ >= total_teams)
					break;
			}
		}
			break;
	}

	script_pushint(st, 1);

	return true;
}

/**
 * Fill teams with members from the given Queue.
 * @param Queue ID
 * @param Max Players Per Team
 * @param Balanceing method
 * @param Team 1 ... Team 13
 */
BUILDIN(hBG_balance_teams)
{
	struct hBG_queue_data *hBGqd;
	struct hBG_queue_member *head;
	struct battleground_data *bgd, *p_bg;
	int i, c, q_id, bg_id, m_bg_id = 0, max, min, type;
	struct map_session_data *sd;
	bool balanced;

	q_id = script_getnum(st,2);

	if ((hBGqd = hBG_queue_search(q_id)) == NULL || hBGqd->users <= 0) {
		ShowError("buildin_hBG_balance_teams: Non existant Queue Id or the queue is empty.\n");
		script_pushint(st, 0);
		return false;
	}

	max = script_getnum(st,3);
	if (max > MAX_BG_MEMBERS)
		max = MAX_BG_MEMBERS;
	min = MAX_BG_MEMBERS + 1;
	type = script_getnum(st, 4);

	i = 5; // Team IDs to build
	
	while (script_hasdata(st, i) && i-5 < 13) {
		bg_id = script_getnum(st, i);
		if ((bgd = bg->team_search(bg_id)) == NULL) {
			ShowError("buildin_hBG_balance_teams: Non existant team id received %d.\n", bg_id);
			script_pushint(st, 0);
			return false;
		}

		if (bgd->count < min)
			min = bgd->count;
		i++;
	}

	c = i - 5; // Teams Found

	if (c < 2 || min >= max)
		return true; // No Balance Required

	if (type < 3) {
		while ((head = hBGqd->first) != NULL && (sd = head->sd) != NULL) {
			p_bg = NULL;
			balanced = true;
			min = MAX_BG_MEMBERS + 1;

			// Search the Current Minimum and Balance status
			for (i = 0; i < c; i++) {
				bg_id = script_getnum(st,i+5);
				
				if ((bgd = bg->team_search(bg_id)) == NULL)
					break; // Should not happen. Teams already check
				
				if (p_bg && p_bg->count != bgd->count)
					balanced = false; // Teams still with different member count

				if (bgd->count < min) {
					m_bg_id = bg_id;
					min = bgd->count;
				}
				p_bg = bgd;
			}

			if (min >= max) break; // Balance completed

			if (hBG_config_get("battle_configuration/hBG_balanced_queue") && balanced && hBGqd->users < c)
				break; // No required users on queue to keep balance

			hBG_team_join(m_bg_id, sd);
			hBG_queue_member_remove(hBGqd, sd->bl.id);

			if ((bgd = bg->team_search(m_bg_id)) != NULL && bgd->mapindex)
				pc->setpos(sd, bgd->mapindex, bgd->x, bgd->y, CLR_TELEPORT); // Joins and Warps
		}
	} else {
		ShowError("buildin_hBG_balance_teams: Invalid type %d given for argument #3.\n", type);
		script_pushint(st, 0);
		return false;
	}

	script_pushint(st, 1);

	return true;
}

/**
 * Waiting Room to Battleground Teams
 * @param Map Name
 * @param Map X
 * @param Map Y
 * @param BG Guild Index
 * @param Logout Event
 * @param Die Event
 */
BUILDIN(hBG_waitingroom2bg)
{
	struct npc_data *nd;
	struct chat_data *cd;
	const char *map_name, *ev = "", *dev = "";
	int x, y, i, m=0, guild_index, bg_id;
	struct map_session_data *sd;

	nd = (struct npc_data *)map->id2bl(st->oid);

	if (nd == NULL || (cd = (struct chat_data *)map->id2bl(nd->chat_id)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	map_name = script_getstr(st,2);

	if (strcmp(map_name, "-") != 0 && (m = mapindex->name2id(map_name)) == 0) {
		script_pushint(st, 0);
		return false;
	}

	x = script_getnum(st, 3);
	y = script_getnum(st, 4);
	guild_index = script_getnum(st, 5);
	ev = script_getstr(st, 6); // Logout Event
	dev = script_getstr(st, 7); // Die Event

	guild_index = cap_value(guild_index, 0, 12);

	if ((bg_id = hBG_create(m, x, y, guild_index, ev, dev)) == 0) { // Creation failed
		script_pushint(st, 0);
		return false;
	}

	for (i = 0; i < cd->users && i < MAX_BG_MEMBERS; i++) {
		if ((sd = cd->usersd[i]) != NULL && hBG_team_join(bg_id, sd))
			mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), sd->bl.id);
		else
			mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), 0);
	}

	mapreg->setreg(script->add_str("$@arenamembersnum"), i);

	script_pushint(st, bg_id);

	return true;
}

/**
 * Adds the first player from the given NPC's
 * waiting room to BG Team.
 * @param Battleground Id
 * @param Map Name
 * @param Map X
 * @param Map Y
 * @param NPC Name
 */
BUILDIN(hBG_waitingroom2bg_single)
{
	const char* map_name;
	struct npc_data *nd;
	struct chat_data *cd;
	struct map_session_data *sd;
	int x, y, m, bg_id;

	bg_id = script_getnum(st,2);
	map_name = script_getstr(st,3);

	if ((m = mapindex->name2id(map_name)) == 0) {
		script_pushint(st, 0);
		return false; // Invalid Map
	}

	x = script_getnum(st,4);
	y = script_getnum(st,5);
	nd = npc->name2id(script_getstr(st,6));

	if (nd == NULL || (cd = (struct chat_data *)map->id2bl(nd->chat_id)) == NULL || cd->users <= 0) {
		script_pushint(st, 0);
		return false;
	}

	if ((sd = cd->usersd[0]) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	if (hBG_team_join(bg_id, sd)) {
		pc->setpos(sd, m, x, y, CLR_TELEPORT);
		script_pushint(st,1);
	} else {
		script_pushint(st,0);
	}

	return true;
}

/**
 * Set the Respawn Location of a BG team
 * @param Battleground Id
 * @param Map X
 * @param Map Y
 */
BUILDIN(hBG_team_setxy)
{
	struct battleground_data *bgd;
	int bg_id;

	bg_id = script_getnum(st,2);

	if ((bgd = bg->team_search(bg_id)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	bgd->x = script_getnum(st,3);
	bgd->y = script_getnum(st,4);

	script_pushint(st, 1);

	return true;
}

/**
 * Reveal the location of a BG Team on the minimap.
 * @param Battleground ID
 */
BUILDIN(hBG_team_reveal)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id;

	bg_id = script_getnum(st,2);

	if ((bgd = bg->team_search(bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	hBGd->reveal_pos = true; // Reveal Position Mode

	script_pushint(st, 1);

	return true;
}

/**
 * Conceal the location of a BG Team from the minimap.
 * @param Battleground ID
 */
BUILDIN(hBG_team_conceal)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	struct map_session_data *sd;
	int bg_id,i=0;

	bg_id = script_getnum(st,2);

	if ((bgd = bg->team_search(bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL)
			continue;

		hBG_send_dot_remove(sd);
	}

	hBGd->reveal_pos = false; // Conceal Position Mode

	script_pushint(st, 1);

	return true;
}

/**
 * Set Quest for a BG Team
 * @param Battleground ID
 * @param Quest ID
 */
BUILDIN(hBG_team_setquest)
{
	struct battleground_data *bgd;
	struct map_session_data *sd;
	int i, bg_id, qid;

	bg_id = script_getnum(st,2);
	qid = script_getnum(st,3);

	if (bg_id <= 0 || (bgd = bg->team_search(bg_id)) == NULL) {
		ShowError("buildin_hBG_team_setquest: Invalid Team ID %d given.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	if (qid <= 0 || quest->db(qid) == NULL) {
		ShowError("buildin_hBG_team_setquest: Invalid Quest ID %d given.\n", qid);
		script_pushint(st, 0);
		return false;
	}

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL)
			continue;

		quest->add(sd, qid, 0);
	}

	script_pushint(st, 1);

	return true;
}

/**
 * Set Viewpoint for a player.
 * @see hBG_viewpointmap
 */
int hBG_viewpointmap_sub(struct block_list *bl, va_list ap)
{
	struct map_session_data *sd;
	int npc_id, type, x, y, id, color;
	npc_id = va_arg(ap,int);
	type = va_arg(ap,int);
	x = va_arg(ap,int);
	y = va_arg(ap,int);
	id = va_arg(ap,int);
	color = va_arg(ap,int);
	sd = (struct map_session_data *)bl;

	clif->viewpoint(sd,npc_id,type,x,y,id,color);

	return 0;
}

/**
 * Set Viewpoint on minimap for a player.
 * @param Map Name
 * @param Type
 *         0 = display mark for 15 seconds
 *         1 = display mark until dead or teleported
 *         2 = remove mark
 * @param Map X
 * @param Map Y
 * @param ID (Unique ID of the viewpoint)
 * @param Color
 */
BUILDIN(hBG_viewpointmap)
{
	int type,x,y,id,color,m;
	const char *map_name;

	map_name = script_getstr(st,2);

	if ((m = map->mapname2mapid(map_name)) < 0) {
		script_pushint(st, 0);
		return false; // Invalid Map
	}

	type=script_getnum(st,3);
	x=script_getnum(st,4);
	y=script_getnum(st,5);
	id=script_getnum(st,6);
	color=script_getnum(st,7);

	map->foreachinmap(hBG_viewpointmap_sub,m,BL_PC,st->oid,type,x,y,id,color);

	script_pushint(st, 1);

	return true;
}

/**
 * Reveal a monster's location on minimap
 * @param Monster Id
 * @param Type
 *         0 = display mark for 15 seconds
 *         1 = display mark until dead or teleported
 *         2 = remove mark
 * @param Color
 */
BUILDIN(hBG_monster_reveal)
{
	struct block_list *mbl;
	int id = script_getnum(st,2),
	flag = script_getnum(st,3),
	color = script_getnum(st,4);

	if (id == 0 || (mbl = map->id2bl(id)) == NULL || mbl->type != BL_MOB) {
		script_pushint(st, 0);
		return false;
	}

	map->foreachinmap(hBG_viewpointmap_sub, mbl->m, BL_PC, st->oid, flag, mbl->x, mbl->y, mbl->id, color);

	script_pushint(st, 1);

	return true;
}

/**
 * Set monster as an ally to a BG Team.
 * @param Monster ID
 * @param Battleground ID
 */
BUILDIN(hBG_monster_set_team)
{
	struct mob_data *md;
	struct block_list *mbl;
	int id = script_getnum(st,2),
	bg_id = script_getnum(st,3);

	if (id == 0 || (mbl = map->id2bl(id)) == NULL || mbl->type != BL_MOB) {
		script_pushint(st, 0);
		return false;
	}

	md = (TBL_MOB *)mbl;
	md->bg_id = bg_id;

	mob_stop_attack(md);
	mob_stop_walking(md, 0);

	md->target_id = md->attacked_id = 0;

	clif->charnameack(0, &md->bl);

	script_pushint(st, 1);

	return true;
}

/**
 * Set immunity flag to a monster.
 * (making it immune to damage).
 * @param Monster ID
 * @param Flag (0 = Off | 1 = On)
 */
BUILDIN(hBG_monster_immunity)
{
	struct mob_data *md;
	struct block_list *mbl;
	struct hBG_mob_data *hBGmd;

	int id = script_getnum(st,2),
	flag = script_getnum(st,3);

	if (id == 0 || (mbl = map->id2bl(id)) == NULL || mbl->type != BL_MOB) {
		script_pushint(st, 0);
		return false;
	}

	md = (TBL_MOB *)mbl;

	if ((hBGmd = getFromMOBDATA(md, 0)) == NULL){
		CREATE(hBGmd, struct hBG_mob_data, 1);	
		addToMOBDATA(md, hBGmd, 0, true);
	}
	hBGmd->state.immunity = flag;

	return true;
}

/**
 * Leave a Battleground Team
 */
BUILDIN(hBG_leave)
{
	struct map_session_data *sd = script->rid2sd(st);

	if (sd == NULL || sd->bg_id == 0) {
		script_pushint(st, 0);
		return false;
	}

	bg->team_leave(sd,0);

	script_pushint(st, 1);

	return true;
}

/**
 * Finalize battlegrounds and remove
 * teams from the db.
 */
BUILDIN(hBG_destroy)
{
	int bg_id = script_getnum(st, 2);

	if (bg_id <= 0 || bg->team_search(bg_id) == NULL) {
		ShowError("buildin_hBG_destroy: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	hBG_team_finalize(bg_id, true);

	script_pushint(st, 1);

	return true;
}

/**
 * Clean Battlegrounds without removing
 * the teams from the db.
 */
BUILDIN(hBG_clean)
{
	int bg_id = script_getnum(st, 2);

	if (bg_id <= 0 || bg->team_search(bg_id) == NULL) {
		ShowError("buildin_hBG_clean: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	hBG_team_finalize(bg_id, false);

	script_pushint(st, 1);

	return true;
}

/**
 * Get user count within an area in a map.
 * @param Battleground ID
 * @param Map Name
 * @param X1
 * @param Y1
 * @param X2
 * @param Y2
 */
BUILDIN(hBG_getareausers)
{
	struct battleground_data *bgd = NULL;
	struct map_session_data *sd = NULL;
	const char *map_name;
	int m, x0, y0, x1, y1, bg_id;
	int i = 0, c = 0;

	bg_id = script_getnum(st,2);
	map_name = script_getstr(st,3);

	if ((bgd = bg->team_search(bg_id)) == NULL || (m = map->mapname2mapid(map_name)) < 0) {
		script_pushint(st,0);
		return false;
	}

	x0 = script_getnum(st,4);
	y0 = script_getnum(st,5);
	x1 = script_getnum(st,6);
	y1 = script_getnum(st,7);

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL)
			continue;
		else if (sd->bl.m != m || sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1)
			continue;
		c++;
	}

	script_pushint(st, c);
	
	return true;
}

/**
 * Update the score on a battleground map.
 * @param Map Name
 * @param Lion Score
 * @param Eagle Score
 */
BUILDIN(hBG_updatescore)
{
	const char *map_name;
	int m;

	map_name = script_getstr(st,2);

	if ((m = map->mapname2mapid(map_name)) < 0) {
		script_pushint(st, 0);
		return false;
	}

	map->list[m].bgscore_lion = script_getnum(st,3);
	map->list[m].bgscore_eagle = script_getnum(st,4);

	clif->bg_updatescore(m);

	script_pushint(st, 1);

	return true;
}

/**
 * Update Score for a Battleground Team.
 * @param Battleground ID
 * @param Score
 */
BUILDIN(hBG_update_score_team)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id = script_getnum(st,2);
	int score = script_getnum(st,3);

	if (bg_id <= 0) {
		ShowError("buildin_hBG_update_score_team: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	if ((bgd = bg->team_search(bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	hBGd->team_score = score;
	hBG_update_score_team(bgd);

	script_pushint(st, 1);

	return true;
}

/**
 * Get a Team's Guild Index
 * @param Battleground ID
 * @return Guild Index
 */
BUILDIN(hBG_get_team_gid)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id = script_getnum(st,2), guild_id = 0;

	if (bg_id <= 0) {
		ShowError("buildin_hBG_get_team_gid: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	if ((bgd = bg->team_search(bg_id)) != NULL
		&& (hBGd = getFromBGDATA(bgd, 0)) != NULL)
		guild_id = hBGd->g->guild_id;

	script_pushint(st, guild_id);

	return true;
}

/**
 * Get data from a Battleground
 * @param Battleground ID
 * @param Type
 *         0 = User Count
 *         1 = Fill $@bgmembers$ array with user list and return user count.
 *         2 = BG Guild Name
 *         3 = BG Guild Master Name
 *         4 = BG Color
 */
BUILDIN(hBG_get_data)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id = script_getnum(st,2);
	int type = script_getnum(st,3);

	if (bg_id <= 0) {
		ShowError("buildin_hBG_get_data: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	if ((bgd = bg->team_search(bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	switch (type)
	{
		case 0:
			script_pushint(st, bgd->count);
			break;
		case 1: // Users and List
		{
			int i, j = 0;
			struct map_session_data *sd;
			for (i = 0; i < bgd->count; i++) {
				if ((sd = bgd->members[i].sd) == NULL)
					continue;
				mapreg->setregstr(reference_uid(script->add_str("$@bgmembers$"),j),sd->status.name);
				j++;
			}
			script_pushint(st, j);
		}
			break;
		case 2:
			script_pushconststr(st,hBGd->g ? hBGd->g->name : "");
			break;
		case 3:
			script_pushconststr(st,hBGd->g ? hBGd->g->master : "");
			break;
		case 4:
			script_pushint(st,hBGd->color);
			break;

		default:
			ShowError("script:bg_get_data: unknown data identifier %d\n", type);
			break;
	}

	script_pushint(st, 0);

	return true;
}

/**
 * Battleground Get Item
 * @param Battleground ID
 * @param Item ID
 * @param Item Amount
 */
BUILDIN(hBG_getitem)
{
	int bg_id, nameid, amount;

	bg_id = script_getnum(st,2);
	nameid = script_getnum(st,3);
	amount = script_getnum(st,4);


	if (bg_id <= 0 || bg->team_search(bg_id) == NULL) {
		ShowError("buildin_hBG_getitem: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	} else if (nameid <= 0 || itemdb->exists(nameid) == NULL) {
		ShowError("buildin_hBG_getitem: Invalid Item Id %d provided.\n", nameid);
		script_pushint(st, 0);
		return false;
	} else if (amount <= 0) {
		ShowError("buildin_hBG_getitem: Invalid Item amount %d provided.\n", amount);
		script_pushint(st, 0);
		return false;
	}

	hBG_team_getitem(bg_id, nameid, amount);

	script_pushint(st, amount);

	return true;
}

/**
 * Battleground Get Kafra Points
 * @param Battleground ID
 * @param Amount of KP
 */
BUILDIN(hBG_getkafrapoints)
{
	int bg_id, amount;

	bg_id = script_getnum(st, 2);
	amount = script_getnum(st, 3);

	if (bg_id <= 0 || bg->team_search(bg_id) == NULL) {
		ShowError("buildin_hBG_getkafrapoints: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	} else if (amount <= 0) {
		ShowError("buildin_hBG_getkafrapoints: Invalid Kafra Points %d provided.\n", amount);
		script_pushint(st, 0);
		return false;
	}

	hBG_team_get_kafrapoints(bg_id, amount);

	script_pushint(st, amount);

	return true;
}

/**
 * Battleground get Rewards
 * @param Battleground ID
 * @param Item ID
 * @param Item Amount
 * @param Kafra Points
 * @param Quest ID
 * @param Custom Variable (#KAFRAPOINTS/#CASHPOINTS etc..)
 * @param Custom Variable Add Value
 * @param Battleground Arena (0 EoS | 1 Boss | 2 TI | 3 CTF | 4 TD | 5 SC | 6 CON | 7 RUSH | 8 DOM)
 * @param Battleground Result (0 Won | 1 Tie | 2 Lost)
 */
BUILDIN(hBG_reward)
{
	int bg_id, nameid, amount, kafrapoints, quest_id, add_value, bg_arena, bg_result;
	const char *var;

	bg_id = script_getnum(st,2);
	nameid = script_getnum(st,3);
	amount = script_getnum(st,4);
	kafrapoints = script_getnum(st,5);
	quest_id = script_getnum(st,6);
	var = script_getstr(st,7);
	add_value = script_getnum(st,8);
	bg_arena = script_getnum(st,9);
	bg_result = script_getnum(st,10);

	if (bg_id <= 0 || bg->team_search(bg_id) == NULL) {
		ShowError("buildin_hBG_reward: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	if (nameid <= 0 || itemdb->exists(nameid) == NULL) {
		ShowError("buildin_hBG_reward: Invalid Item Id %d provided.\n", nameid);
		script_pushint(st, 0);
		return false;
	}

	if (nameid > 0 && amount <= 0) {
		ShowError("buildin_hBG_reward: Invalid Item amount %d provided.\n", nameid);
		script_pushint(st, 0);
		return false;
	}

	if (kafrapoints < 0) {
		ShowError("buildin_hBG_reward: Invalid Kafra Points %d provided.\n", kafrapoints);
		script_pushint(st, 0);
		return false;
	}

	if (quest_id < 0 || quest->db(quest_id) == NULL) {
		ShowError("buildin_hBG_reward: Invalid Quest ID %d provided.\n", quest_id);
		script_pushint(st, 0);
		return false;
	}

	if (bg_arena < 0) {
		ShowError("buildin_hBG_reward: Invalid BG Arena %d provided. \n", bg_arena);
		script_pushint(st, 0);
		return false;
	}

	if (bg_result < 0 || bg_result > 2) {
		ShowError("buildin_hBG_reward: Invalid BG result type %d provided. (types - 0 Won | 1 Tie | 2 Lost)", bg_result);
		script_pushint(st, 0);
		return false;
	}

	hBG_team_rewards(bg_id, nameid, amount, kafrapoints, quest_id, var, add_value, bg_arena, bg_result);

	script_pushint(st, 1);

	return true;
}

/**
 * Add Item to XY co-ordinates on Floor.
 * @param Map Name
 * @param Map X
 * @param Map Y
 * @param Item ID
 * @param Item Amount
 */
BUILDIN(hBG_flooritem2xy)
{
	int nameid, amount, m, x, y;
	const char *mapname;
	
	mapname = script_getstr(st,2);
	
	if ((m = map->mapname2mapid(mapname)) < 0) {
		// error message is thrown through mapindex->name2id()
		script_pushint(st, 0);
		return false;
	}
	
	x = script_getnum(st,3);
	y = script_getnum(st,4);
	nameid = script_getnum(st,5);
	
	if (itemdb->search(nameid) == NULL) {
		ShowError("buildin_hBG_flooritem2xy: Invalid Item Id %d provided.\n", nameid);
		script_pushint(st, 0);
		return false;
	}
	
	amount = script_getnum(st,6);
	
	if (amount < 1) {
		ShowError("buildin_hBG_flooritem2xy: Invalid Item amount %d provided.\n", amount);
		script_pushint(st, 0);
		return false;
	}
	
	hBG_addflooritem_area(NULL, m, x, y, nameid, amount);

	script_pushint(st, amount);

	return true;
}
/**
 * Warps BG Team to destination or Respawn Point
 * @param BG Team
 * @param Map Name
 * @param Map X
 * @param Map Y
 */
BUILDIN(hBG_warp)
{
	int x, y, mapidx, bg_id;
	const char *map_name;

	bg_id = script_getnum(st,2);
	map_name = script_getstr(st,3);

	if (!strcmp(map_name,"RespawnPoint")) // Cemetery Zone
		mapidx = 0;
	else if ((mapidx = script->mapindexname2id(st,map_name)) == 0)
		return 0; // Invalid Map

	x = script_getnum(st,4);
	y = script_getnum(st,5);

	bg_id = hBG_team_warp(bg_id, mapidx, x, y);

	return true;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Map Server Function Pre-Hooks
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
 * NPC Pre-Hooks
 */
void npc_parse_unknown_mapflag_pre(const char **name, const char **w3, const char **w4, const char **start, const char **buffer, const char **filepath, int **retval)
{
	int16 m = map->mapname2mapid(*name);

	if (strcmpi(*w3, "hBG_topscore") == 0) {
		struct hBG_mapflag *hBG_mf;

		if ((hBG_mf = getFromMAPD(&map->list[m], 0)) == NULL) {
			CREATE(hBG_mf, struct hBG_mapflag, 1);
			hBG_mf->hBG_topscore = 1;
			addToMAPD(&map->list[m], hBG_mf, 0, true);
		}

		hBG_mf->hBG_topscore = 1;

		hookStop();
	}

	return;
}

/**
 * Clif Pre-Hooks
 */
void clif_charnameupdate_pre(struct map_session_data **sd)
{
	unsigned char buf[103];
	int cmd = 0x195, ps;
	struct battleground_data *bgd = bg->team_search((*sd)->bg_id);
	struct hBG_data *hBGd;

	nullpo_retv((*sd));

	if ((*sd)->fakename[0] || bgd == NULL ||
		(hBGd = getFromBGDATA(bgd, 0)) == NULL || hBGd->g == NULL)
		return; //No need to update as the guild was not displayed anyway.

	WBUFW(buf,0) = cmd;
	WBUFL(buf,2) = (*sd)->bl.id;
	memcpy(WBUFP(buf,6), (*sd)->status.name, NAME_LENGTH);
	WBUFB(buf,30) = 0;
	memcpy(WBUFP(buf,54), hBGd->g->name, NAME_LENGTH);
	
	ps = (hBGd->leader_char_id == (*sd)->status.char_id)?0:1;
	memcpy(WBUFP(buf,78), hBGd->g->position[ps].name, NAME_LENGTH);

	// Update nearby clients
	clif->send(buf, 102, &(*sd)->bl, AREA);

	hookStop();
}
//Prevent update Guild Info if you're in BG
void clif_parse_GuildRequestInfo_pre(int *fd, struct map_session_data **sd)
{
	if ((*sd) && (*sd)->bg_id)
		hookStop();
	return;
}

/**
 * Skill Pre-Hooks.
 */
int skill_check_condition_castbegin_pre(struct map_session_data **sd, uint16 *skill_id, uint16 *skill_lv)
{
	nullpo_ret(sd);
	
	if (map->list[(*sd)->bl.m].flag.battleground && (*skill_id >= GD_SKILLBASE && *skill_id <= GD_DEVELOPMENT))
		hookStop(); // Prevent original function from running after return from here.
	
	return 1;
}

int skillnotok_pre(uint16 *skill_id, struct map_session_data **sd)
{
	int16 idx, m;
	nullpo_retr(1, *sd);
	m = (*sd)->bl.m;
	idx = skill->get_index(*skill_id);
 
	if (map->list[m].flag.battleground && (*skill_id >= GD_SKILLBASE && *skill_id <= GD_DEVELOPMENT)) {
	
		if (pc_has_permission(*sd, PC_PERM_DISABLE_SKILL_USAGE)) {
			hookStop();
			return 1;
		}

		if (pc_has_permission(*sd, PC_PERM_SKILL_UNCONDITIONAL)) {
			hookStop();
			return 0; // can do any damn thing they want
		}

		if ((*sd)->blockskill[idx]) {
			clif->skill_fail((*sd), *skill_id, USESKILL_FAIL_SKILLINTERVAL, 0);
			hookStop();
			return 1;
		}
		hookStop();
	}
	return 0;
}

/**
 * Skill cast end.
 * @param src = source block list.
 * @param bl = target block list
 */
int skill_castend_nodamage_id_pre(struct block_list **src, struct block_list **bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag)
{
	struct map_session_data *sd, *dstsd;
	struct status_change *tsc;
	struct status_data *sstatus;
	struct hBG_map_session_data *hBGsd = NULL;
	
	nullpo_retr(1, bl);
	nullpo_retr(1, src);

	if (!map->list[(*src)->m].flag.battleground || *skill_id != GD_EMERGENCYCALL)
		return 0;
	
	sd = BL_CAST(BL_PC, *src);
	dstsd = BL_CAST(BL_PC, *bl);

	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return 0;

	tsc = status->get_sc(*bl);

	sstatus = status->get_status_data(*src);
	
	switch (*skill_id) {
		case GD_EMERGENCYCALL:
		{
			int dx[9]={-1, 1, 0, 0,-1, 1,-1, 1, 0};
			int dy[9]={ 0, 0, 1,-1, 1,-1,-1, 1, 0};
			int i = 0, j = 0;
			struct guild *g;
			
			// i don't know if it actually summons in a circle, but oh well. ;P
			if (sd && (g = hBG_get_guild(sd->bg_id)) != NULL) {
				clif->skill_nodamage(*src, *bl, *skill_id, *skill_lv, 1);
				
				for (i = 0; i < g->max_member; i++, j++) {
					if (j>8) j=0;
					if ((dstsd = g->member[i].sd) != NULL && sd != dstsd && !dstsd->state.autotrade && !pc_isdead(dstsd)) {
						if (map->getcell((*src)->m, *src, (*src)->x + dx[j], (*src)->y + dy[j], CELL_CHKNOREACH))
							dx[j] = dy[j] = 0;
						pc->setpos(dstsd, map_id2index((*src)->m), (*src)->x+dx[j], (*src)->y+dy[j], CLR_RESPAWN);
					}
				}
				guild->block_skill(sd, skill->get_time2(*skill_id, *skill_lv));
			}
		}
			break;
		case HLIF_HEAL:
		case AL_HEAL:
		{
			struct mob_data *dstmd = BL_UCAST(BL_MOB, *bl);
			int heal = skill->calc_heal(*src, *bl, *skill_id, *skill_lv, true);

			if (status->isimmune(*bl) || (dstmd && dstmd->class_ == MOBID_EMPELIUM))
				heal = 0;

			if (dstmd && mob_is_battleground(dstmd))
				heal = 1;

			if (sd && dstsd && sd->status.partner_id == dstsd->status.char_id && (sd->job&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0)
				heal = heal*2;

			if (tsc && tsc->count)
			{
				if (tsc->data[SC_KAITE] && !(sstatus->mode&MD_BOSS))
				{ //Bounce back heal
					if (src == bl)
						heal=0; //When you try to heal yourself under Kaite, the heal is voided.
					else {
						bl = src;
						dstsd = sd;
					}
				} else if (tsc->data[SC_BERSERK]) {
						heal = 0; //Needed so that it actually displays 0 when healing.
				}
			}

			if (sd && dstsd && heal > 0 && sd != dstsd)
			{
				if (map->list[(*src)->m].flag.battleground && sd->bg_id && dstsd->bg_id)
				{
					if (sd->bg_id == dstsd->bg_id)
						add2limit(hBGsd->stats.healing_done, heal, UINT_MAX);
					else
						add2limit(hBGsd->stats.wrong_healing_done, heal, UINT_MAX);
				}
			}
		}
			break;
	}
	
	hookStop();
	return 0;
}

/**
 * Status Pre-Hooks
 */
int status_get_guild_id_pre(const struct block_list **bl)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id;

	nullpo_ret((*bl));

	if ((*bl)->type == BL_PC
		&& (bg_id = bg->team_get_id((struct block_list *)*bl)) > 0
		&& (bgd = bg->team_search(bg_id)) != NULL
		&& (hBGd = getFromBGDATA(bgd, 0)) != NULL
		&& hBGd->g)
	{
		hookStop();
		return hBGd->g->guild_id;
	}

	return 0;
}

int status_get_emblem_id_pre(const struct block_list **bl)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id;
	
	nullpo_ret(bl);

	if ((*bl)->type == BL_PC
		&& (bg_id = bg->team_get_id((struct block_list *)(*bl))) > 0
		&& (bgd = bg->team_search(bg_id)) != NULL
		&& (hBGd = getFromBGDATA(bgd, 0)) != NULL && hBGd->g)
	{
		hookStop();
		return hBGd->g->emblem_id;
	}

	return 0;
}

/**
 * Guild Pre-Hooks
 */
// Check if guild is null and don't run BCT checks if true.
bool guild_isallied_pre(int *guild_id, int *guild_id2)
{
	struct guild *g = guild->search(*guild_id);
	
	if (g == NULL) {
		hookStop();
		return false;
	}
	
	return false;
}

/**
 * Unit Pre-Hooks
 */
int unit_free_pre(struct block_list **bl, clr_type *clrtype)
{
	nullpo_retr(0, (*bl));

	if ((*bl)->type == BL_PC) {
		struct map_session_data *sd = BL_UCAST(BL_PC, (*bl));
		struct hBG_queue_data *hBGqd = NULL;
		struct battleground_data *bgd = NULL;
		struct hBG_data *hBGd = NULL;
		struct hBG_map_session_data *hBGsd = NULL;

		if ((hBGqd = getFromMSD(sd, 0)) && hBG_queue_member_search(hBGqd, sd->bl.id))
			hBG_queue_member_remove(hBGqd, sd->bl.id);

		if (sd->bg_id != 0
			&& (bgd = bg->team_search(sd->bg_id)) != NULL
			&& (hBGd = getFromBGDATA(bgd, 0)) != NULL
			&& (hBGsd = getFromMSD(sd, 1)) != NULL) {
			bg->team_leave(sd, 1);
			hBGsd->stats.total_deserted++;
		}

		removeFromMSD(sd, 1);
	}

	return 0;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Map Server Function Post-Hooks
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Battle Post-Hooks
 */
void battle_consume_ammo(struct map_session_data *sd, int skill_id, int lv)
{
	int qty = 1;
	struct hBG_map_session_data *hBGsd = getFromMSD(sd, 1);

	if (battle->bc->arrow_decrement == 0 || hBGsd == NULL)
		return;

	if (skill)
		qty = max(1, skill->get_ammo_qty(skill_id, lv));

	if (sd->equip_index[EQI_AMMO] >= 0) {
		if (sd->bg_id && map->list[sd->bl.m].flag.battleground)
			add2limit(hBGsd->stats.ammo_used, qty, UINT_MAX);
	}
}

// Check target immunity
int battle_check_target_post(int retVal, struct block_list *src, struct block_list *target, int flag)
{
	if (retVal == 1 && target->type == BL_MOB) {
		struct mob_data *md = BL_UCAST(BL_MOB, target);
		struct hBG_mob_data *hBGmd = NULL;

		if (md == NULL || (hBGmd = getFromMOBDATA(md, 0)) == NULL)
			return retVal;

		if (hBGmd != NULL && hBGmd->state.immunity) {
			hookStop();
			return retVal;
		}
	}

	return retVal;
}

/**
 * Clif Post-Hooks
 */
void clif_parse_LoadEndAck_post(int fd, struct map_session_data *sd)
{
	clif->charnameupdate(sd);
	/* Display emblem on head of char [lucaslsb] */
	if (hBG_enabled && sd->state.changemap && map->list[sd->bl.m].flag.battleground)
		clif->map_type(sd, MAPTYPE_BATTLEFIELD);
	if (hBG_enabled && map->list[sd->bl.m].flag.battleground)
		clif->map_property(sd, MAPPROPERTY_AGITZONE);
	return;
}
//Send charname_update every time you see someone in BG
void clif_getareachar_unit_post(struct map_session_data *sd, struct block_list *bl)
{
	if (bl->type == BL_PC) {
		struct map_session_data *tsd = BL_CAST(BL_PC, bl);
		clif->charnameupdate(tsd);
		return;
	}
}
void clif_parse_UseSkillToId_post(int fd, struct map_session_data *sd)
{
	uint16 skill_id;
	/* uint16 skill_lv; */
	int target_id;
	const struct s_packet_db *packet = clif->packet(RFIFOW(fd,0));
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	
	if (!sd->bg_id)
		return;
	else if ((bgd = bg->team_search(sd->bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
		return;

	/* skill_lv = RFIFOW(fd,packet->pos[0]); */
	skill_id = RFIFOW(fd,packet->pos[1]);
	target_id = RFIFOL(fd,packet->pos[2]);
	
	if (skill_id >= GD_SKILLBASE && skill_id < GD_MAX && hBGd->leader_char_id == sd->status.char_id)
			unit->skilluse_id(&sd->bl, target_id, skill_id, guild->checkskill(hBG_get_guild(sd->bg_id), skill_id));
}

/**
 * Server tells 'sd' player client the abouts of 'dstsd' player
 */
void clif_getareachar_pc_post(struct map_session_data *sd,struct map_session_data *dstsd)
{
	if (sd->bg_id && dstsd->bg_id && sd->bg_id == dstsd->bg_id)
			clif->hpmeter_single(sd->fd, dstsd->bl.id, dstsd->battle_status.hp, dstsd->battle_status.max_hp);
}

/**
 * PC Post hooks
 */
void pc_update_idle_time_post(struct map_session_data* sd, enum e_battle_config_idletime type)
{
	struct hBG_map_session_data *hBGsd = NULL;
	struct battleground_data *bgd = bg->team_search(sd->bg_id);
	struct hBG_data *hBGd = NULL;
	
	nullpo_retv(sd);
	
	if (bgd && (hBGd = getFromBGDATA(bgd, 0)) && (hBGsd = getFromMSD(sd, 1)) && hBGsd->state.afk) {
		char output[256];
		/* Reset AFK status */
		sprintf(output, "%s : %s is no longer AFK.", sd->status.name, hBGd->g->name);
		hBG_send_chat_message(bgd, sd->bl.id, sd->status.name, output, (int)strlen(output) + 1);
		hBGsd->state.afk = 0;
	}
}

bool pc_authok_post(bool ret, struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, const struct mmo_charstatus *st, bool changing_mapservers)
{
	if (sd) {
		WFIFOHEAD(chrif->fd, 14);
		WFIFOW(chrif->fd, 0) = PACKET_INTER_BG_STATS_REQ;
		WFIFOL(chrif->fd, 2) = sd->status.account_id;
		WFIFOL(chrif->fd, 6) = sd->status.char_id;
		WFIFOL(chrif->fd, 10) = sd->fd;
		WFIFOSET(chrif->fd, 14);
	}
	
	return ret;
}

/**
 * Character Interface Post-Hooks
 */
/**
 * Requests saving of hBG Statistics and sends data to char-server.
 *
 * @param sd pointer to map session data.
 * @param flag as an indicator to tell char-server if character is quitting.
 * @return boolean.
 */
bool chrif_save_post(bool ret, struct map_session_data *sd, int flag)
{
	struct hBG_map_session_data *hBGsd = NULL;
	int len = 13 + sizeof(struct hBG_stats);
	
	nullpo_retr(false, sd);
	
	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return ret;

	if (flag == 1) // Logout from BG! Do not save anything.
		return ret;

	WFIFOHEAD(chrif->fd, len);
	WFIFOW(chrif->fd, 0) = PACKET_INTER_BG_STATS_SAVE; // 0x9000 Packet ID
	WFIFOL(chrif->fd, 2) = sd->status.account_id; // Account Id
	WFIFOL(chrif->fd, 6) = sd->status.char_id; // Char Id
	WFIFOB(chrif->fd, 12) = (flag==1); //Flag to tell char-server this character is quitting.
	memcpy(WFIFOP(chrif->fd, 13), &hBGsd->stats, sizeof(struct hBG_stats)); // hBG statistics.
	WFIFOSET(chrif->fd, len);
	
	return ret;
}

/**
 * Status Post Hooks
 */
int status_damage_post(int ret, struct block_list *src, struct block_list *target,int64 in_hp, int64 in_sp, int walkdelay, int flag)
{
	struct map_session_data *sd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;

	nullpo_retr(ret, target);

	if (src == NULL)
		return ret;

	if (src->type != BL_PC || (sd = BL_UCAST(BL_PC, src)) == NULL)
		return ret;
	if (map->list[src->m].flag.battleground == 0)
		return ret;
	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return ret;

	hBG_record_damage(src, target, (int) in_hp);

	return ret;
}

/**
 * Receives and allocates map session data with bg statistics
 * from char-server.
 *
 * @param fd as socket descriptor handle
 */
void hBG_statistics_parsefromchar(int fd)
{
	struct map_session_data *sd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;
	struct hBG_stats *stats = NULL;
	/* int account_id = RFIFOL(fd, 2), char_id = RFIFOL(fd, 6); */
 	int char_fd = RFIFOL(fd,10);
	
	nullpo_retv(sockt->session[char_fd]);

	if ((sd = sockt->session[char_fd]->session_data) == NULL)
		return;

	if ((hBGsd = getFromMSD(sd, 1)) == NULL) {
		CREATE(hBGsd, struct hBG_map_session_data, 1);
		addToMSD(sd, hBGsd, 1, false);
	}
	
	if ((stats = getFromSession(sockt->session[fd], 0)) == NULL)
		memcpy(&hBGsd->stats, RFIFOP(fd, 14), sizeof(struct hBG_stats));
	else
		memcpy(&hBGsd->stats, stats, sizeof(struct hBG_stats));
}

/**
* Battleground Interface Overload [lucaslsb]
*/

/**
 * Remove a player from a team.
 * @param sd pointer to session data.
 * @param flag type of leave.
 * @return Amount of player in the BG or 0 on failure.
 */
int bg_team_leave_overload(struct map_session_data *sd, enum bg_team_leave_type flag)
{ // Single Player leaves team
	int i;
	struct battleground_data *bgd;
	struct hBG_map_session_data *hBGsd;
	struct hBG_data *hBGd;
	struct map_session_data *pl_sd;
	struct guild *g;

	nullpo_ret(sd);
	
	if (!sd->bg_id)
		return 0;
	else if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return 0;
	else if ((bgd = bg->team_search(sd->bg_id)) == NULL)
		return 0;
	else if ((hBGd = getFromBGDATA(bgd, 0)) == NULL)
		return 0;

	// Packets
	hBG_send_dot_remove(sd);
	
	// Reset information.
	sd->bg_id = 0;
	hBGsd->bg_kills = 0;
	
	// Remove battleground items if any.
	hBG_member_remove_bg_items(sd);

	// Remove Guild Skill Buffs
	status_change_end(&sd->bl, SC_GUILDAURA, INVALID_TIMER);
	status_change_end(&sd->bl, SC_GDSKILL_BATTLEORDER, INVALID_TIMER);
	status_change_end(&sd->bl, SC_GDSKILL_REGENERATION, INVALID_TIMER);

	// Refresh Guild Information
	if (sd->status.guild_id && (g = guild->search(sd->status.guild_id)) != NULL) {
		clif->guild_belonginfo(sd, g);
		clif->guild_basicinfo(sd);
		clif->guild_allianceinfo(sd);
		clif->guild_memberlist(sd);
		clif->guild_skillinfo(sd);
		clif->guild_emblem(sd, g);
	} else {
		hBG_send_leave_single(sd, sd->status.name, "Leaving Battle...");
	}

	clif->charnameupdate(sd);
	clif->guild_emblem_area(&sd->bl);

	ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd == sd);

	if (i < MAX_BG_MEMBERS) // Removes member from BG
		memset(&bgd->members[i], 0, sizeof(struct battleground_member_data));
	
	ARR_FIND(0, MAX_BG_MEMBERS, i, hBGd->g->member[i].sd == sd);
	
	if (i < MAX_BG_MEMBERS) // removes member from BG Guild
		memset(&hBGd->g->member[i].sd, 0, sizeof(hBGd->g->member[i].sd));
	
	if (hBGd->leader_char_id == sd->status.char_id)
		hBGd->leader_char_id = 0;
	
	if (--bgd->count > 0) {
		for (i = 0; i < MAX_BG_MEMBERS; i++) { // Update other BG members
			if ((pl_sd = bgd->members[i].sd) == NULL)
				continue;
			
			if (!hBGd->leader_char_id) { // Set new Leader first on the list
				hBGd->leader_char_id = pl_sd->status.char_id;
				clif->charnameupdate(pl_sd);
			}
			
			switch (flag) {
				case 3: hBG_send_expulsion(pl_sd, sd->status.name, "Kicked by AFK Status..."); break;
				case 2: hBG_send_expulsion(pl_sd, sd->status.name, "Kicked by AFK Report..."); break;
				case 1: hBG_send_expulsion(pl_sd, sd->status.name, "User has quit the game..."); break;
				case 0: hBG_send_leave_single(pl_sd, sd->status.name, "Leaving Battle..."); break;
			}
			
			hBG_guild_window_info(pl_sd);
			hBG_send_emblem(pl_sd, hBGd->g);
			hBG_send_guild_member_list(pl_sd);
		}
	}

	if (bgd && strlen(bgd->logout_event) && flag)
		npc->event(sd, bgd->logout_event, 0);
	
	return bgd->count;
}

/**
* Clif Interface Overload [lucaslsb]
*/
void clif_sendbgemblem_area_overload(struct map_session_data *sd)
{
	int cmd = 0x2dd;
	const struct s_packet_db *packet = clif->packet(cmd);
	unsigned char buf[33];
	nullpo_retv(sd);
	if (hBG_enabled)
		return; // Prevents display of conventional emblems
	WBUFW(buf, 0) = cmd;
	WBUFL(buf, 2) = sd->bl.id;
	safestrncpy((char*)WBUFP(buf, 6), sd->status.name, NAME_LENGTH); // name don't show in screen.
	WBUFW(buf, 30) = sd->bg_id;
	clif->send(buf, packet->len, &sd->bl, AREA);
}

void clif_sendbgemblem_single_overload(int fd, struct map_session_data *sd)
{
	int cmd = 0x2dd;
	const struct s_packet_db *packet = clif->packet(cmd);
	nullpo_retv(sd);
	if (hBG_enabled)
		return; // Prevents display of conventional emblems
	WFIFOHEAD(fd, 32);
	WFIFOW(fd, 0) = cmd;
	WFIFOL(fd, 2) = sd->bl.id;
	safestrncpy(WFIFOP(fd, 6), sd->status.name, NAME_LENGTH);
	WFIFOW(fd, 30) = sd->bg_id;
	WFIFOSET(fd, packet->len);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Char Server Functions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
 * Character Server Saving of hBG Statistics
 *
 * @param fd socket descriptor handle
 */
void char_bgstats_tosql(int fd)
{
	struct hBG_stats pstats = {0}, *stats = NULL;
	int account_id = 0, char_id = 0;
	/* int flag = 0; */
	
	nullpo_retv(sockt->session[fd]);
	
	account_id = RFIFOL(fd, 2);
	char_id = RFIFOL(fd, 6);
	/* flag = RFIFOB(fd, 12); */
	
	if ((stats = getFromSession(sockt->session[fd], 0)) == NULL) {
		CREATE(stats, struct hBG_stats, 1);
		addToSession(sockt->session[fd], stats, 0, true);
	}
	
	memcpy(&pstats, RFIFOP(fd, 13), sizeof(struct hBG_stats));
	
	if (memcmp(stats, &pstats, sizeof(struct hBG_stats))) {
		if (SQL_ERROR == SQL->Query(inter->sql_handle,
			"REPLACE INTO `char_bg_stats` ("
			"`char_id`, "
			"`best_damage`, `total_damage_done`, `total_damage_received`, "
			"`ti_wins`, `ti_lost`, `ti_tie`, "
			"`eos_flags`, `eos_bases`, `eos_wins`, `eos_lost`, `eos_tie`, "
			"`boss_killed`, `boss_damage`, `boss_flags`, `boss_wins`, `boss_lost`, `boss_tie`, "
			"`dom_bases`, `dom_off_kills`, `dom_def_kills`, `dom_wins`, `dom_lost`, `dom_tie`, "
			"`td_kills`, `td_deaths`, `td_wins`, `td_lost`, `td_tie`, "
			"`sc_stolen`, `sc_captured`, `sc_dropped`, `sc_wins`, `sc_lost`, `sc_tie`, "
			"`ctf_taken`, `ctf_captured`, `ctf_dropped`, `ctf_wins`, `ctf_lost`, `ctf_tie`, "
			"`emperium_kills`, `barricade_kills`, `guardian_stone_kills`, `conquest_wins`, `conquest_losses`, "
			"`ru_captures`, `ru_wins`, `ru_lost`, `ru_skulls`,"
			"`kill_count`, `death_count`, `wins`, `losses`, `ties`, `wins_as_leader`, `losses_as_leader`, `ties_as_leader`, `total_deserted`, `score`, `points`, `ranked_points`, `ranked_games`,"
			"`sp_heal_potions`, `hp_heal_potions`, `yellow_gemstones`, `red_gemstones`, `blue_gemstones`, `poison_bottles`, `acid_demostration`, `acid_demostration_fail`, "
			"`support_skills_used`, `healing_done`, `wrong_support_skills_used`, `wrong_healing_done`, "
			"`sp_used`, `zeny_used`, `spiritb_used`, `ammo_used`)"
			" VALUES "
			"('%d',"
			"'%d','%u','%u',"
			"'%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d',"
			"'%u','%d','%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d',"
			"'%d','%d','%d',"
			"'%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d',"
			"'%u','%u','%u','%u','%u','%u','%u','%u',"
			"'%u','%u','%u','%u',"
			"'%u','%u','%u','%u')",
			char_id,
			pstats.best_damage, pstats.total_damage_done, pstats.total_damage_received,
			pstats.ti_wins,pstats.ti_lost,pstats.ti_tie,
			pstats.eos_flags,pstats.eos_bases,pstats.eos_wins,pstats.eos_lost,pstats.eos_tie,
			pstats.boss_killed,pstats.boss_damage,pstats.boss_flags,pstats.boss_wins,pstats.boss_lost,pstats.boss_tie,
			pstats.dom_bases,pstats.dom_off_kills,pstats.dom_def_kills,pstats.dom_wins,pstats.dom_lost,pstats.dom_tie,
			pstats.td_kills,pstats.td_deaths,pstats.td_wins,pstats.td_lost,pstats.td_tie,
			pstats.sc_stolen,pstats.sc_captured,pstats.sc_dropped,pstats.sc_wins,pstats.sc_lost,pstats.sc_tie,
			pstats.ctf_taken,pstats.ctf_captured,pstats.ctf_dropped,pstats.ctf_wins,pstats.ctf_lost,pstats.ctf_tie,
			pstats.emperium_kills,pstats.barricade_kills,pstats.guardian_stone_kills,pstats.conquest_wins,pstats.conquest_losses,
			pstats.ru_captures,pstats.ru_wins,pstats.ru_lost, pstats.ru_skulls,
			pstats.kill_count,pstats.death_count,pstats.wins,pstats.losses,pstats.ties,pstats.wins_as_leader,pstats.losses_as_leader,
			pstats.ties_as_leader,pstats.total_deserted,pstats.score,pstats.points,pstats.ranked_points,pstats.ranked_games,
			pstats.sp_heal_potions, pstats.hp_heal_potions, pstats.yellow_gemstones, pstats.red_gemstones,
			pstats.blue_gemstones, pstats.poison_bottles, pstats.acid_demostration, pstats.acid_demostration_fail,
			pstats.support_skills_used, pstats.healing_done, pstats.wrong_support_skills_used, pstats.wrong_healing_done,
			pstats.sp_used, pstats.zeny_used, pstats.spiritb_used, pstats.ammo_used))
		{
			Sql_ShowDebug(inter->sql_handle);
		} else {
			memcpy(stats, &pstats, sizeof(struct hBG_stats));
			ShowInfo("Saved char (AID/CID: %d/%d) - BG Statistics [by Smokexyz].\n", account_id, char_id);
		}
	}
}

void char_bgstats_fromsql(int fd)
{
	struct hBG_stats temp_stats = { 0 }, *stats = NULL;
	int account_id = 0, char_id = 0, char_fd = 0, len = 0;
	struct SqlStmt *stmt = SQL->StmtMalloc(inter->sql_handle);

	if (stmt == NULL) {
		SqlStmt_ShowDebug(stmt);
		return;
	}
	
	account_id = RFIFOL(fd,2);
	char_id = RFIFOL(fd, 6);
	char_fd = RFIFOL(fd, 10);
	
	if (SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT "
		"`best_damage`,`total_damage_done`,`total_damage_received`,`ru_skulls`,`ti_wins`,`ti_lost`,`ti_tie`,`eos_flags`,`eos_bases`,`eos_wins`," // 0-9
		"`eos_lost`,`eos_tie`,`boss_killed`,`boss_damage`,`boss_flags`,`boss_wins`,`boss_lost`,`boss_tie`,`td_kills`,`td_deaths`," //10-19
		"`td_wins`,`td_lost`,`td_tie`,`sc_stolen`,`sc_captured`,`sc_dropped`,`sc_wins`,`sc_lost`,`sc_tie`,`ctf_taken`," //20-29
		"`ctf_captured`,`ctf_dropped`,`ctf_wins`,`ctf_lost`,`ctf_tie`,`emperium_kills`,`barricade_kills`,`guardian_stone_kills`,`conquest_wins`,`conquest_losses`,"//30-39
		"`kill_count`,`death_count`,`wins`,`losses`,`ties`,`wins_as_leader`,`losses_as_leader`,`ties_as_leader`,`total_deserted`,`score`,"//40-49
		"`points`,`sp_heal_potions`,`hp_heal_potions`,`yellow_gemstones`,`red_gemstones`,`blue_gemstones`,`poison_bottles`,`acid_demostration`,`acid_demostration_fail`,`support_skills_used`,"//50-59
		"`healing_done`,`wrong_support_skills_used`,`wrong_healing_done`,`sp_used`,`zeny_used`,`spiritb_used`,`ammo_used`,`ranked_points`,`ranked_games`,`ru_wins`,"//60-69
		"`ru_lost`,`ru_captures`,`dom_bases`,`dom_off_kills`,`dom_def_kills`,`dom_wins`,`dom_lost`,`dom_tie`"//70-79
		" FROM `char_bg_stats` WHERE `char_id` = ?")
		|| SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, sizeof char_id)
		|| SQL_ERROR == SQL->StmtExecute(stmt)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_UINT, &temp_stats.best_damage, sizeof temp_stats.best_damage, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_UINT, &temp_stats.total_damage_done, sizeof temp_stats.total_damage_done, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_UINT, &temp_stats.total_damage_received, sizeof temp_stats.total_damage_received, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &temp_stats.ru_skulls, sizeof temp_stats.ru_skulls, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_USHORT, &temp_stats.ti_wins, sizeof temp_stats.ti_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_USHORT, &temp_stats.ti_lost, sizeof temp_stats.ti_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_USHORT, &temp_stats.ti_tie, sizeof temp_stats.ti_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_USHORT, &temp_stats.eos_flags, sizeof temp_stats.eos_flags, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_USHORT, &temp_stats.eos_bases, sizeof temp_stats.eos_bases, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_USHORT, &temp_stats.eos_wins, sizeof temp_stats.eos_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 10, SQLDT_USHORT, &temp_stats.eos_lost, sizeof temp_stats.eos_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 11, SQLDT_USHORT, &temp_stats.eos_tie, sizeof temp_stats.eos_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 12, SQLDT_USHORT, &temp_stats.boss_killed, sizeof temp_stats.boss_killed, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 13, SQLDT_UINT, &temp_stats.boss_damage, sizeof temp_stats.boss_damage, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 14, SQLDT_USHORT, &temp_stats.boss_flags, sizeof temp_stats.boss_flags, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 15, SQLDT_USHORT, &temp_stats.boss_wins, sizeof temp_stats.boss_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 16, SQLDT_USHORT, &temp_stats.boss_lost, sizeof temp_stats.boss_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 17, SQLDT_USHORT, &temp_stats.boss_tie, sizeof temp_stats.boss_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 18, SQLDT_USHORT, &temp_stats.td_kills, sizeof temp_stats.td_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 19, SQLDT_USHORT, &temp_stats.td_deaths, sizeof temp_stats.td_deaths, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 20, SQLDT_USHORT, &temp_stats.td_wins, sizeof temp_stats.td_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 21, SQLDT_USHORT, &temp_stats.td_lost, sizeof temp_stats.td_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 22, SQLDT_USHORT, &temp_stats.td_tie, sizeof temp_stats.td_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 23, SQLDT_USHORT, &temp_stats.sc_stolen, sizeof temp_stats.sc_stolen, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 24, SQLDT_USHORT, &temp_stats.sc_captured, sizeof temp_stats.sc_captured, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 25, SQLDT_USHORT, &temp_stats.sc_dropped, sizeof temp_stats.sc_dropped, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 26, SQLDT_USHORT, &temp_stats.sc_wins, sizeof temp_stats.sc_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 27, SQLDT_USHORT, &temp_stats.sc_lost, sizeof temp_stats.sc_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 28, SQLDT_USHORT, &temp_stats.sc_tie, sizeof temp_stats.sc_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 29, SQLDT_USHORT, &temp_stats.ctf_taken, sizeof temp_stats.ctf_taken, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 30, SQLDT_USHORT, &temp_stats.ctf_captured, sizeof temp_stats.ctf_captured, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 31, SQLDT_USHORT, &temp_stats.ctf_dropped, sizeof temp_stats.ctf_dropped, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 32, SQLDT_USHORT, &temp_stats.ctf_wins, sizeof temp_stats.ctf_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 33, SQLDT_USHORT, &temp_stats.ctf_lost, sizeof temp_stats.ctf_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 34, SQLDT_USHORT, &temp_stats.ctf_tie, sizeof temp_stats.ctf_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 35, SQLDT_USHORT, &temp_stats.emperium_kills, sizeof temp_stats.emperium_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 36, SQLDT_USHORT, &temp_stats.barricade_kills, sizeof temp_stats.barricade_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 37, SQLDT_USHORT, &temp_stats.guardian_stone_kills, sizeof temp_stats.guardian_stone_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 38, SQLDT_USHORT, &temp_stats.conquest_wins, sizeof temp_stats.conquest_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 39, SQLDT_USHORT, &temp_stats.conquest_losses, sizeof temp_stats.conquest_losses, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 40, SQLDT_USHORT, &temp_stats.kill_count, sizeof temp_stats.kill_count, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 41, SQLDT_USHORT, &temp_stats.death_count, sizeof temp_stats.death_count, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 42, SQLDT_USHORT, &temp_stats.wins, sizeof temp_stats.wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 43, SQLDT_USHORT, &temp_stats.losses, sizeof temp_stats.losses, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 44, SQLDT_USHORT, &temp_stats.ties, sizeof temp_stats.ties, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 45, SQLDT_USHORT, &temp_stats.wins_as_leader, sizeof temp_stats.wins_as_leader, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 46, SQLDT_USHORT, &temp_stats.losses_as_leader, sizeof temp_stats.losses_as_leader, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 47, SQLDT_USHORT, &temp_stats.ties_as_leader, sizeof temp_stats.ties_as_leader, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 48, SQLDT_USHORT, &temp_stats.total_deserted, sizeof temp_stats.total_deserted, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 49, SQLDT_INT, &temp_stats.score, sizeof temp_stats.score, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 50, SQLDT_INT, &temp_stats.points, sizeof temp_stats.points, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 51, SQLDT_UINT, &temp_stats.sp_heal_potions, sizeof temp_stats.sp_heal_potions, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 52, SQLDT_UINT, &temp_stats.hp_heal_potions, sizeof temp_stats.hp_heal_potions, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 53, SQLDT_UINT, &temp_stats.yellow_gemstones, sizeof temp_stats.yellow_gemstones, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 54, SQLDT_UINT, &temp_stats.red_gemstones, sizeof temp_stats.red_gemstones, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 55, SQLDT_UINT, &temp_stats.blue_gemstones, sizeof temp_stats.blue_gemstones, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 56, SQLDT_UINT, &temp_stats.poison_bottles, sizeof temp_stats.poison_bottles, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 57, SQLDT_UINT, &temp_stats.acid_demostration, sizeof temp_stats.acid_demostration, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 58, SQLDT_UINT, &temp_stats.acid_demostration_fail, sizeof temp_stats.acid_demostration_fail, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 59, SQLDT_UINT, &temp_stats.support_skills_used, sizeof temp_stats.support_skills_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 60, SQLDT_UINT, &temp_stats.healing_done, sizeof temp_stats.healing_done, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 61, SQLDT_UINT, &temp_stats.wrong_support_skills_used, sizeof temp_stats.wrong_support_skills_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 62, SQLDT_UINT, &temp_stats.wrong_healing_done, sizeof temp_stats.wrong_healing_done, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 63, SQLDT_UINT, &temp_stats.sp_used, sizeof temp_stats.sp_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 64, SQLDT_UINT, &temp_stats.zeny_used, sizeof temp_stats.zeny_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 65, SQLDT_UINT, &temp_stats.spiritb_used, sizeof temp_stats.spiritb_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 66, SQLDT_UINT, &temp_stats.ammo_used, sizeof temp_stats.ammo_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 67, SQLDT_UINT, &temp_stats.ranked_points, sizeof temp_stats.ranked_points, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 68, SQLDT_USHORT, &temp_stats.ranked_games, sizeof temp_stats.ranked_games, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 69, SQLDT_USHORT, &temp_stats.ru_wins, sizeof temp_stats.ru_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 70, SQLDT_USHORT, &temp_stats.ru_lost, sizeof temp_stats.ru_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 71, SQLDT_USHORT, &temp_stats.ru_captures, sizeof temp_stats.ru_captures, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 72, SQLDT_USHORT, &temp_stats.dom_bases, sizeof temp_stats.dom_bases, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 73, SQLDT_USHORT, &temp_stats.dom_off_kills, sizeof temp_stats.dom_off_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 74, SQLDT_USHORT, &temp_stats.dom_def_kills, sizeof temp_stats.dom_def_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 75, SQLDT_USHORT, &temp_stats.dom_wins, sizeof temp_stats.dom_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 76, SQLDT_USHORT, &temp_stats.dom_lost, sizeof temp_stats.dom_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 77, SQLDT_USHORT, &temp_stats.dom_tie, sizeof temp_stats.dom_tie, NULL, NULL)
		|| SQL_SUCCESS != SQL->StmtNextRow(stmt))
	{
		temp_stats.score = 2000;
	}
	
	ShowInfo("Loaded char (AID/CID: %d/%d) - BG Statistics [by Smokexyz]\n", account_id, char_id);
	
	if ((stats = getFromSession(sockt->session[fd], 0)) == NULL) {
		CREATE(stats, struct hBG_stats, 1);
		memcpy(stats, &temp_stats, sizeof(struct hBG_stats));
		addToSession(sockt->session[fd], stats, 0, true);
	} else if (memcmp(stats, &temp_stats, sizeof(struct hBG_stats))) {
		memcpy(stats, &temp_stats, sizeof(struct hBG_stats));
	}

	SQL->StmtFree(stmt);

	len = 14 + sizeof(struct hBG_stats);
	WFIFOHEAD(fd, len);
	WFIFOW(fd, 0) = PACKET_MAP_BG_STATS_GET;
	WFIFOL(fd, 2) = account_id;
	WFIFOL(fd, 6) = char_id;
	WFIFOL(fd, 10) = char_fd;
	memcpy(WFIFOP(fd, 14), &temp_stats, sizeof(struct hBG_stats));
	WFIFOSET(fd, len);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Battle Configuration Parsing                    *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void hBG_config_read(const char *key, const char *val)
{
	int value = config_switch (val);

	if (strcmpi(key,"battle_configuration/hBG_enabled") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_enabled, defaulting to 0.\n", value);
			return;
		}
		hBG_enabled = value;
	} else if (strcmpi(key, "battle_configuration/hBG_from_town_only") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_from_town_only, defaulting to 0.\n", value);
			return;
		}
		hBG_from_town_only = value;
	} else if (strcmpi(key, "battle_configuration/hBG_ip_check") == 0) {
		if (value < 0) {
			ShowWarning("Received Invalid Setting %d for hBG_ip_check, defaulting to 0.\n", value);
			return;
		}
		hBG_ip_check = value;
	} else if (strcmpi(key, "battle_configuration/hBG_idle_announce") == 0) {
		if (value < 0) {
			ShowWarning("Received Invalid Setting %d for hBG_idle_announce, defaulting to 60 seconds.\n", value);
			hBG_idle_announce = 60;
		} else {
			hBG_idle_announce = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_idle_autokick") == 0) {
		if (value < 0) {
			ShowWarning("Received Invalid Setting %d for hBG_idle_autokick, defaulting to 5 minutes (300s).\n", value);
			hBG_idle_autokick = 300;
		} else {
			hBG_idle_autokick = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_reportafk_leaderonly") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_reportafk_leaderonly, defaulting to 0.\n", value);
			hBG_reportafk_leaderonly = 0;
		} else {
			hBG_reportafk_leaderonly = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_balanced_queue") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_balanced_queue, defaulting to 0.\n", value);
			return;
		}
		hBG_balanced_queue = value;
	} else if (strcmpi(key, "battle_configuration/hBG_reward_rates") == 0) {
		if (value < 0) {
			ShowWarning("Received invalid setting %d for hBG_reward_rates, defaulting to 100.\n", value);
			hBG_reward_rates = 100;
		} else {
			hBG_reward_rates = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_xy_interval") == 0) {
		if (value < 1000) {
			ShowWarning("Received Invalid Setting %d for hBG_xy_interval. (min: %d, max: %d) Defaulting to 1000ms. \n", value, 1000, INT_MAX);
			hBG_xy_interval = 1000;
		} else {
			hBG_xy_interval = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_ranked_mode") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_ranked_mode, defaulting to 0.\n", value);
			hBG_ranked_mode = 0;
		} else {
			hBG_ranked_mode = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_leader_change") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_leader_change, defaulting to 0.\n", value);
			hBG_leader_change = 0;
		} else {
			hBG_leader_change = value;
		}
	}
}

int hBG_config_get(const char *key)
{
	if (strcmpi(key, "battle_configuration/hBG_enabled") == 0)
		return hBG_enabled;
	else if (strcmpi(key, "battle_configuration/hBG_from_town_only") == 0)
		return hBG_from_town_only;
	else if (strcmpi(key, "battle_configuration/hBG_ip_check") == 0)
		return hBG_ip_check;
	else if (strcmpi(key, "battle_configuration/hBG_idle_announce") == 0)
		return hBG_idle_announce;
	else if (strcmpi(key, "battle_configuration/hBG_idle_autokick") == 0)
		return hBG_idle_autokick;
	else if (strcmpi(key, "battle_configuration/hBG_reportafk_leaderonly") == 0)
		return hBG_reportafk_leaderonly;
	else if (strcmpi(key, "battle_configuration/hBG_balanced_queue") == 0)
		return hBG_balanced_queue;
	else if (strcmpi(key, "battle_configuration/hBG_reward_rates") == 0)
		return hBG_reward_rates;
	else if (strcmpi(key, "battle_configuration/hBG_xy_interval") == 0)
		return hBG_xy_interval;
	else if (strcmpi(key, "battle_configuration/hBG_ranked_mode") == 0)
		return hBG_ranked_mode;
	else if (strcmpi(key, "battle_configuration/hBG_leader_change") == 0)
		return hBG_leader_change;

	return 0;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                       Plugin Handling
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* run when server starts */
HPExport void plugin_init(void)
{
	int interval = hBG_config_get("battle_configuration/hBG_xy_interval");

	if (SERVER_TYPE == SERVER_TYPE_CHAR) {
		addPacket(PACKET_INTER_BG_STATS_REQ, 14, char_bgstats_fromsql, hpParse_FromMap);
		addPacket(PACKET_INTER_BG_STATS_SAVE, 13 + sizeof(struct hBG_stats), char_bgstats_tosql, hpParse_FromMap);
	}
	
	if (SERVER_TYPE == SERVER_TYPE_MAP) {
		addPacket(PACKET_MAP_BG_STATS_GET, 14+sizeof(struct hBG_stats), hBG_statistics_parsefromchar, hpChrif_Parse);
		
		/* Function Pre-Hooks */
		addHookPre(npc, parse_unknown_mapflag, npc_parse_unknown_mapflag_pre);
		addHookPre(clif, charnameupdate, clif_charnameupdate_pre);
		addHookPre(clif, pGuildRequestInfo,clif_parse_GuildRequestInfo_pre);
		addHookPre(status, get_guild_id, status_get_guild_id_pre);
		addHookPre(status, get_emblem_id, status_get_emblem_id_pre);
		addHookPre(guild, isallied, guild_isallied_pre);
		addHookPre(skill, check_condition_castbegin, skill_check_condition_castbegin_pre);
		addHookPre(skill, not_ok, skillnotok_pre);
		addHookPre(skill, castend_nodamage_id, skill_castend_nodamage_id_pre);
		addHookPre(unit, free, unit_free_pre);
		
		/* Function Post-Hooks */
		addHookPost(clif, pLoadEndAck, clif_parse_LoadEndAck_post);
		addHookPost(clif, pUseSkillToId, clif_parse_UseSkillToId_post);
		addHookPost(clif, getareachar_pc, clif_getareachar_pc_post);
		addHookPost(clif, getareachar_unit, clif_getareachar_unit_post);
		addHookPost(pc, update_idle_time, pc_update_idle_time_post);
		addHookPost(pc, authok, pc_authok_post);
		addHookPost(chrif, save, chrif_save_post);
		addHookPost(status, damage, status_damage_post);
		
		addHookPost(battle, check_target, battle_check_target_post);
		
		/* @Commands */
		addAtcommand("bgrank", bgrank);
		addAtcommand("reportafk", reportafk);
		addAtcommand("leader", leader);
		
		/* Script Commands */
		addScriptCommand("hBG_team_create","siiiss", hBG_team_create);
		addScriptCommand("hBG_queue_create","ss?", hBG_queue_create);
		addScriptCommand("hBG_queue_event","is", hBG_queue_event);
		addScriptCommand("hBG_queue_join","i", hBG_queue_join);
		addScriptCommand("hBG_queue_partyjoin","ii", hBG_queue_partyjoin);
		addScriptCommand("hBG_queue_leave","i", hBG_queue_leave);
		addScriptCommand("hBG_queue_data","ii", hBG_queue_data);
		addScriptCommand("hBG_queue2team","iisiiiss", hBG_queue2team);
		addScriptCommand("hBG_queue2team_single","iisii", hBG_queue2team_single);
		addScriptCommand("hBG_queue2teams","iiiiii*", hBG_queue2teams);
		addScriptCommand("hBG_queue_checkstart","iiii", hBG_queue_checkstart);
		addScriptCommand("hBG_balance_teams","iiiii*", hBG_balance_teams);
		addScriptCommand("hBG_waitingroom2bg","siiiss", hBG_waitingroom2bg);
		addScriptCommand("hBG_waitingroom2bg_single","isiis", hBG_waitingroom2bg_single);
		addScriptCommand("hBG_team_setxy","iii", hBG_team_setxy);
		addScriptCommand("hBG_team_reveal","i", hBG_team_reveal);
		addScriptCommand("hBG_team_conceal","i", hBG_team_conceal);
		addScriptCommand("hBG_team_setquest","ii", hBG_team_setquest);
		addScriptCommand("hBG_viewpointmap","siiiii", hBG_viewpointmap);
		addScriptCommand("hBG_monster_reveal","iii", hBG_monster_reveal);
		addScriptCommand("hBG_monster_set_team","ii", hBG_monster_set_team);
		addScriptCommand("hBG_monster_immunity","ii", hBG_monster_immunity);
		addScriptCommand("hBG_leave","", hBG_leave);
		addScriptCommand("hBG_destroy","i", hBG_destroy);
		addScriptCommand("hBG_clean","i", hBG_clean);
		addScriptCommand("hBG_get_data","ii", hBG_get_data);
		addScriptCommand("hBG_getareausers","isiiii", hBG_getareausers);
		addScriptCommand("hBG_updatescore","sii", hBG_updatescore);
		addScriptCommand("hBG_team_updatescore", "ii", hBG_update_score_team);
		addScriptCommand("hBG_team_guildid","i", hBG_get_team_gid);
		addScriptCommand("hBG_getitem","iii", hBG_getitem);
		addScriptCommand("hBG_getkafrapoints","ii", hBG_getkafrapoints);
		addScriptCommand("hBG_reward","iiiiisiii", hBG_reward);
		addScriptCommand("hBG_flooritem2xy", "siiii", hBG_flooritem2xy);
		addScriptCommand("hBG_warp", "isii", hBG_warp);
		
		hBG_queue_db = idb_alloc(DB_OPT_RELEASE_DATA);
		timer->add_func_list(hBG_send_xy_timer, "hBG_send_xy_timer");
		timer->add_interval(timer->gettick() + interval , hBG_send_xy_timer, 0, 0, interval);
	}
}

/* triggered when server starts loading, before any server-specific data is set */
HPExport void server_preinit(void)
{
	if (SERVER_TYPE == SERVER_TYPE_MAP) {
		addBattleConf("battle_configuration/hBG_enabled", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_from_town_only", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_ip_check", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_idle_announce", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_idle_autokick", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_balanced_queue", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_reward_rates", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_xy_interval", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_ranked_mode", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_leader_change", hBG_config_read, hBG_config_get, true);
	}
}

/* run when server is ready (online) */
HPExport void server_online(void)
{
	if (SERVER_TYPE == SERVER_TYPE_MAP) {
		hBG_build_guild_data();
		ShowStatus("%s v%s has been initialized. [by Smokexyz]\n", pinfo.name, pinfo.version);
		// clif interface overloading [lucaslsb]
		bg->team_leave = &bg_team_leave_overload;
		clif->sendbgemblem_area = &clif_sendbgemblem_area_overload;
		clif->sendbgemblem_single = &clif_sendbgemblem_single_overload;
	}
}

static int queue_db_final(union DBKey key, struct DBData *data, va_list ap)
{
	struct hBG_queue_data *hBGqd = DB->data2ptr(data);
	
	if (hBGqd)
		hBG_queue_members_finalize(hBGqd); // Unlink all queue members
	
	return 0;
}

/* run when server is shutting down */
HPExport void plugin_final(void)
{
	if (SERVER_TYPE == SERVER_TYPE_MAP) {
		hBG_queue_db->destroy(hBG_queue_db, queue_db_final);
		ShowInfo ("%s v%s has been finalized. [by Smokexyz]\n", pinfo.name, pinfo.version);
	}
}

 

hBG.c: In function ‘atcommand_reportafk’:
hBG.c:2040:31: warning: unused variable ‘hBGsd’ [-Wunused-variable]
  struct hBG_map_session_data *hBGsd = NULL;
                               ^
hBG.c: In function ‘atcommand_leader’:
hBG.c:2084:31: warning: unused variable ‘hBGsd’ [-Wunused-variable]
  struct hBG_map_session_data *hBGsd = NULL;
                               ^
hBG.c: In function ‘status_get_guild_id_pre’:
hBG.c:3776:31: warning: cast discards ‘__attribute__((const))’ qualifier from pointer target type [-Wcast-qual]
   && (bg_id = bg->team_get_id((struct block_list *)*bl)) > 0
                               ^
hBG.c: In function ‘status_get_emblem_id_pre’:
hBG.c:3797:31: warning: cast discards ‘__attribute__((const))’ qualifier from pointer target type [-Wcast-qual]
   && (bg_id = bg->team_get_id((struct block_list *)(*bl))) > 0
                               ^
        PLUGIN  hBG

Using this plugin.

 

Edited by AnnieRuru
use [spoiler]+[code] tag when posting script > 10 lines

Share this post


Link to post
Share on other sites

1 answer to this question

Recommended Posts

  • 0
On 5/14/2018 at 9:04 PM, MikZ said:

Good day!

Help me how to correct these warnings please.

Spoiler


/*
* This file is part of a Hercules Plugin library.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*  __                 _
* / _\_ __ ___   ___ | | _______  ___   _ ____
* \ \| '_ ` _ \ / _ \| |/ / _ \ \/ / | | |_  /
* _\ \ | | | | | (_) |   <  __/>  <| |_| |/ /
* \__/_| |_| |_|\___/|_|\_\___/_/\_\\__, /___|
*                                   |___/
*
* Copyright (c) 2017 Smokexyz ([email protected])
* 
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License <http://www.gnu.org/licenses/> for
* more details.
* * * * * * * * * * * * * * * * * * * * * * * * *
* Hercules Battlegrounds Plugin by [Smokexyz]
* * * * * * * * * * * * * * * * * * * * * * * * */

#include "common/hercules.h" /* Should always be the first Hercules file included! */

#include "common/memmgr.h"
#include "common/mmo.h"
#include "common/socket.h"
#include "common/strlib.h"
#include "common/nullpo.h"
#include "common/timer.h"
#include "common/utils.h"
#include "common/sql.h"

#include "map/chrif.h"
#include "map/atcommand.h"
#include "map/clif.h"
#include "map/pc.h"
#include "map/script.h"
#include "map/npc.h"
#include "map/party.h"
#include "map/mapreg.h"
#include "map/guild.h"
#include "map/chat.h"
#include "map/quest.h"
#include "map/mob.h"
#include "map/map.h"
#include "map/pet.h"
#include "map/homunculus.h"
#include "map/mercenary.h"
#include "map/elemental.h"
#include "map/skill.h"
#include "map/battleground.h"

#include "char/mapif.h"
#include "char/inter.h"

#include "plugins/HPMHooking.h" /* Hooking Macros */
#include "common/HPMDataCheck.h" /* should always be the last Hercules file included! */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Utility Functions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define add2limit(a, b, max) \
	do { \
		if ((max - a) < b) { \
			a = max; \
		} else { \
			a += b; \
		} \
	} while(0)

#define sub2limit(a, b, min) \
	do { \
		if ((b + min) > a) { \
			a = min; \
		} else { \
			a -= b; \
		} \
	} while(0)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    HPM Structure Definition
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
HPExport struct hplugin_info pinfo = {
	"Hercules Battlegrounds",    // Plugin name
	SERVER_TYPE_MAP | SERVER_TYPE_CHAR, // Server Type
	"1.0a",       // Plugin version
	HPM_VERSION, // HPM Version (automatically updated)
};

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Global Variables
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define MAX_BATTLEGROUND_TEAMS 13
#define BLUE_SKULL 8965
#define RED_SKULL 8966
#define GREEN_SKULL 8967

/* Queue Database */
static struct DBMap* hBG_queue_db;
/* Battleground Guild Storage */
struct guild bg_guild[MAX_BATTLEGROUND_TEAMS];
/* Battleground Guild Colors */
const unsigned int bg_colors[MAX_BATTLEGROUND_TEAMS] = {
	0x0000FF, // Blue
	0xFF0000, // Red
	0x00FF00, // Green
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF,
	0xFFFFFF
};

/* Counter to check the next battleground ID */
static unsigned int bg_team_counter = 0;
/* hBG Queue Counter */
static unsigned int hBG_queue_counter = 0;

/**
 * Battle Configuration Variables
 */
int hBG_idle_announce,
	hBG_idle_autokick,
	hBG_reward_rates,
	hBG_ranked_mode,
	hBG_reportafk_leaderonly,
	hBG_balanced_queue,
	hBG_ip_check,
	hBG_from_town_only,
	hBG_enabled,
	hBG_xy_interval,
	hBG_leader_change;

/**
 * BG Fame list types
 */
enum bg_fame_list_types
{
	BG_NORMAL,
	BG_RANKED
};

/**
 * Inter-server communication packet IDs.
 */
enum inter_packet_types {
	PACKET_INTER_BG_STATS_SAVE =  0x9000,
	PACKET_INTER_BG_STATS_REQ,
	PACKET_MAP_BG_STATS_GET,
};

enum bg_mob_types {
	BARRICADE_        = 1906,
	OBJ_NEUTRAL       = 1911,
	E_BAPHOMET2       = 2100,
	E_LORD_OF_DEATH2,
	E_DARK_LORD,
	E_KTULLANUX,
	E_DARK_SNAKE_LORD,
	E_TURTLE_GENERAL,
	E_APOCALIPS_H,
	E_FALLINGBISHOP,
};

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Structure Definitions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * BGD Structure Appendant
 */
struct hBG_data
{
	time_t created_at; // Creation of this Team
	int leader_char_id;
	unsigned int color;
	// BG Guild Link
	struct guild *g;
	bool reveal_pos, reveal_pos2, reveal_flag;
	// Score Board
	int team_score;
};

/**
 * hBG Queue Member Linked List
 */
struct hBG_queue_member
{
	int position;
	struct map_session_data *sd;
	struct hBG_queue_member *next;
};

struct hBG_stats
{
	unsigned int
	best_damage,
	boss_damage,
	total_damage_done,
	total_damage_received;
	
	unsigned short
	// Triple Inferno
	ti_wins,
	ti_lost,
	ti_tie,
	// Tierra EoS
	eos_flags,
	eos_bases,
	eos_wins,
	eos_lost,
	eos_tie,
	// Tierra Bossnia
	boss_killed,
	boss_flags,
	boss_wins,
	boss_lost,
	boss_tie,
	// Tierra Domination
	dom_bases,
	dom_off_kills,
	dom_def_kills,
	dom_wins,
	dom_lost,
	dom_tie,
	// Flavius TD
	td_kills,
	td_deaths,
	td_wins,
	td_lost,
	td_tie,
	// Flavius SC
	sc_stolen,
	sc_captured,
	sc_dropped,
	sc_wins,
	sc_lost,
	sc_tie,
	// Flavius CTF
	ctf_taken,
	ctf_captured,
	ctf_dropped,
	ctf_wins,
	ctf_lost,
	ctf_tie,
	// Conquest
	emperium_kills,
	barricade_kills,
	guardian_stone_kills,
	conquest_wins,
	conquest_losses,
	// Rush
	ru_captures,
	ru_wins,
	ru_lost,
	ru_skulls;
	
	unsigned int // Ammo
	sp_heal_potions,
	hp_heal_potions,
	yellow_gemstones,
	red_gemstones,
	blue_gemstones,
	poison_bottles,
	acid_demostration,
	acid_demostration_fail,
	support_skills_used,
	healing_done,
	wrong_support_skills_used,
	wrong_healing_done,
	sp_used,
	zeny_used,
	spiritb_used,
	ammo_used;
	
	unsigned short
	kill_count,
	death_count,
	wins, losses, ties,
	wins_as_leader,
	losses_as_leader,
	ties_as_leader,
	total_deserted,
	ranked_games;
	
	int score,
	points,
	ranked_points;
};

/**
 * MSD Structure Appendant (class 0)
 */
struct hBG_queue_data
{
	unsigned int q_id, users, min_level;
	struct hBG_queue_member *first, *last;
	char queue_name[50], join_event[EVENT_NAME_LENGTH];
};

/**
 * MSD Structure Appendant (class 1)
 */
struct hBG_map_session_data
{
	unsigned int bg_kills;
	struct {
		unsigned afk : 1;
	} state;
	
	struct hBG_stats stats;
};

/**
 * MOBD Structure Appendant
 */
struct hBG_mob_data
{
	struct {
		unsigned immunity: 1;
	} state;
};

/**
 * MAPD Structure Appendant
 */
struct hBG_mapflag
{
	unsigned hBG_topscore : 1; // No Detect NoMapFlag
};

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Function Forward Declarations
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int hBG_countlogin(struct map_session_data *sd, bool check_bat_room);
int hBG_config_get(const char *key);
struct guild* hBG_get_guild(int bg_id);
struct map_session_data* hBG_getavailablesd(struct battleground_data *bgd);

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Packet Sending Functions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
 * Updates HP bar of a camp member.
 * Packet Ver < 20140613: 02e0 <account id>.L <name>.24B <hp>.W <max hp>.W (ZC_BATTLEFIELD_NOTIFY_HP).
 * Packet Ver >= 20140613: 0a0e <account id>.L <hp>.L <max hp>.L (ZC_BATTLEFIELD_NOTIFY_HP2)
 *
 * @param sd map_session_data to send the packet to.
 * @return void.
 */
void hBG_send_hp_area(struct map_session_data *sd)
{
	unsigned char buf[34];
	
	// packet version can be wrong,
	// due to inconsistend data on other servers.
#if PACKETVER < 20140613
	const int cmd = 0x2e0;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;

	WBUFW(buf, 0) = cmd;
	WBUFL(buf, 2) = sd->status.account_id;
	memcpy(WBUFP(buf, 6), sd->status.name, NAME_LENGTH);

	if (sd->battle_status.max_hp > INT16_MAX) { // To correctly display the %hp bar. [Skotlex]
		WBUFW(buf, 30) = sd->battle_status.hp / (sd->battle_status.max_hp / 100);
		WBUFW(buf, 32) = 100;
	}
	else {
		WBUFW(buf, 30) = sd->battle_status.hp;
		WBUFW(buf, 32) = sd->battle_status.max_hp;
	}
	
	clif->send(buf, packet->len, &sd->bl, BG_AREA_WOS);
#else
	const int cmd = 0xa0e;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;

	WBUFW(buf, 0) = cmd;
	WBUFL(buf, 2) = sd->status.account_id;
	if (sd->battle_status.max_hp > INT32_MAX) {
		WBUFL(buf, 6) = sd->battle_status.hp / (sd->battle_status.max_hp / 100);
		WBUFL(buf, 10) = 100;
	} else {
		WBUFL(buf, 6) = sd->battle_status.hp;
		WBUFL(buf, 10) = sd->battle_status.max_hp;
	}
	
	clif->send(buf, packet->len, &sd->bl, BG_AREA_WOS);
#endif
}

/**
 * Notify a singly client of HP change.
 *
 * @param fd  socket fd to write
 * @param sd  map_session_data containing information to be sent.
 */
void hBG_send_hp_single(int fd, struct map_session_data* sd)
{
	const int cmd = 0x2e0;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;

	WFIFOHEAD(fd, packet->len);
	WFIFOW(fd, 0) = cmd;
	WFIFOL(fd, 2) = sd->bl.id;
	memcpy(WFIFOP(fd,6),sd->status.name, NAME_LENGTH);
	if (sd->battle_status.max_hp > INT16_MAX) {
		WFIFOW(fd, 30) = sd->battle_status.hp/(sd->battle_status.max_hp/100);
		WFIFOW(fd, 32) = 100;
	} else {
		WFIFOW(fd, 30) = sd->battle_status.hp;
		WFIFOW(fd, 32) = sd->battle_status.max_hp;
	}

	WFIFOSET(fd, packet->len);
}

/**
 * Character Guild Name Information Packet
 *
 * @param sd map_session_data to send the packet to.
 * @return void
 */
void hBG_send_guild_info(struct map_session_data *sd)
{
	int fd;
	int cmd = 0x16c;
	struct guild *g;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);

	if (!sd->bg_id || (g = hBG_get_guild(sd->bg_id)) == NULL || packet == NULL)
		return;

	fd = sd->fd;
	WFIFOHEAD(fd, packet->len);
	WFIFOW(fd,0) = 0x16c;
	WFIFOL(fd,2) = g->guild_id;
	WFIFOL(fd,6) = g->emblem_id;
	WFIFOL(fd,10) = 0;
	WFIFOB(fd,14) = 0;
	WFIFOL(fd,15) = 0;
	memcpy(WFIFOP(fd,19), g->name, NAME_LENGTH);

	WFIFOSET(fd,  packet->len);
}

/** 
 * Sends guild skills (ZC_GUILD_SKILLINFO).
 * 0162 <packet len>.W <skill points>.W { <skill id>.W <type>.L <level>.W <sp cost>.W <atk range>.W <skill name>.24B <upgradeable>.B }*
 */
void hBG_send_guild_skillinfo(struct map_session_data* sd)
{
	int fd;
	struct guild* g;
	int i,c;
	
	nullpo_retv(sd);
	
	if (!sd->bg_id || (g = hBG_get_guild(sd->bg_id)) == NULL)
		return;
	
	fd = sd->fd;
	WFIFOHEAD(fd, 6 + MAX_GUILDSKILL*37);
	WFIFOW(fd,0) = 0x0162;
	WFIFOW(fd,4) = g->skill_point;
	for (i = 0, c = 0; i < MAX_GUILDSKILL; i++) {
		if(g->skill[i].id > 0 && guild->check_skill_require(g, g->skill[i].id)) {
			int id = g->skill[i].id;
			int p = 6 + c*37;
			WFIFOW(fd,p+0) = id;
			WFIFOL(fd,p+2) = skill->get_inf(id);
			WFIFOW(fd,p+6) = g->skill[i].lv;
			if ( g->skill[i].lv) {
				WFIFOW(fd, p + 8) = skill->get_sp(id, g->skill[i].lv);
				WFIFOW(fd, p + 10) = skill->get_range(id, g->skill[i].lv);
			} else {
				WFIFOW(fd, p + 8) = 0;
				WFIFOW(fd, p + 10) = 0;
			}
			safestrncpy(WFIFOP(fd,p+12), skill->get_name(id), NAME_LENGTH);
			WFIFOB(fd,p+36)= (g->skill[i].lv < guild->skill_get_max(id) && sd == g->member[0].sd) ? 1 : 0;
			c++;
		}
	}
	WFIFOW(fd,2) = 6 + c*37;
	WFIFOSET(fd,WFIFOW(fd,2));
}

/**
 * Sends Guild Window Information
 * 01b6 <guild id>.L <level>.L <member num>.L <member max>.L <exp>.L <max exp>.L <points>.L <honor>.L <virtue>.L <emblem id>.L <name>.24B <master name>.24B <manage land>.16B <zeny>.L (ZC_GUILD_INFO2)
 * @param sd map_session_data to send the packet to.
 * @return void
 */
void hBG_guild_window_info(struct map_session_data *sd)
{
	int fd;
	int cmd = 0x1b6;
	struct guild *g;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	fd = sd->fd;
	
	if ((g = hBG_get_guild(sd->bg_id)) == NULL || packet == NULL)
		return;
	
	WFIFOHEAD(fd, packet->len); // Hardcoded Length
	WFIFOW(fd, 0)= cmd;
	WFIFOL(fd, 2)= g->guild_id;
	WFIFOL(fd, 6)= g->guild_lv;
	WFIFOL(fd,10)= g->connect_member;
	WFIFOL(fd,14)= g->max_member;
	WFIFOL(fd,18)= g->average_lv;
	WFIFOL(fd,22)= (uint32)cap_value(g->exp,0,INT32_MAX);
	WFIFOL(fd,26)= g->next_exp;
	WFIFOL(fd,30)= 0; // Tax Points
	WFIFOL(fd,34)= 0; // Honor: (left) Vulgar [-100,100] Famed (right)
	WFIFOL(fd,38)= 0; // Virtue: (down) Wicked [-100,100] Righteous (up)
	WFIFOL(fd,42)= g->emblem_id;
	memcpy(WFIFOP(fd,46), g->name, NAME_LENGTH);
	memcpy(WFIFOP(fd,70), g->master, NAME_LENGTH);
	
	//safestrncpy(WFIFOP(fd,94), 0, 0); // "'N' castles"
	WFIFOL(fd, 110) = 0;  // zeny
	
	WFIFOSET(fd, packet->len);
}

/**
 * Sends Guild Emblem to a player
 * @param sd   map_session_data to send the packet to
 * @param g    guild data
 * @return void
 */
void hBG_send_emblem(struct map_session_data *sd, struct guild *g)
{
	int fd;

	nullpo_retv(sd);
	nullpo_retv(g);

	if (g->emblem_len <= 0)
		return;

	fd = sd->fd;
	WFIFOHEAD(fd, g->emblem_len+12);
	WFIFOW(fd,0) = 0x152;
	WFIFOW(fd,2) = g->emblem_len+12;
	WFIFOL(fd,4) = g->guild_id;
	WFIFOL(fd,8) = g->emblem_id;
	memcpy(WFIFOP(fd,12),g->emblem_data,g->emblem_len);

	WFIFOSET(fd, WFIFOW(fd,2));
}

/**
 * Sends guild member list 
 * @param sd  map_session_data to send the packet to
 * @return void
 */
void hBG_send_guild_member_list(struct map_session_data *sd)
{
	int fd, i, c;
	struct battleground_data *bgd;
	struct map_session_data *psd;
	struct hBG_data *hBGd;
	
	nullpo_retv(sd);

	if ((fd = sd->fd) == 0)
		return;
	if (!sd->bg_id || (bgd = bg->team_search(sd->bg_id)) == NULL)
		return;
	else if ((hBGd = getFromBGDATA(bgd, 0)) == NULL)
		return;

	WFIFOHEAD(fd, bgd->count * 104 + 4);
	WFIFOW(fd, 0) = 0x154;

	for (i = 0, c = 0; i < bgd->count; i++) {
		struct hBG_map_session_data *hBGsd;

		if ((psd = bgd->members[i].sd) == NULL)
			continue;

		if ((hBGsd = getFromMSD(psd, 1)) == NULL)
			continue;

		WFIFOL(fd,c*104+ 4) = psd->status.account_id;
		WFIFOL(fd,c*104+ 8) = psd->status.char_id;
		WFIFOW(fd,c*104+12) = psd->status.hair;
		WFIFOW(fd,c*104+14) = psd->status.hair_color;
		WFIFOW(fd,c*104+16) = psd->status.sex;
		WFIFOW(fd,c*104+18) = psd->status.class;
		WFIFOW(fd,c*104+20) = psd->status.base_level;
		WFIFOL(fd,c*104+22) = hBGsd->bg_kills; // Exp slot used to show kills
		WFIFOL(fd,c*104+26) = 1; // Online
		WFIFOL(fd,c*104+30) = hBGd->leader_char_id == psd->status.char_id ? 0 : 1; // Position
		memset(WFIFOP(fd,c*104+34),0,50); // Position Name
		memcpy(WFIFOP(fd,c*104+84),psd->status.name,NAME_LENGTH); // Player Name
		c++;
	}

	WFIFOW(fd, 2)=c*104+4;

	WFIFOSET(fd,WFIFOW(fd,2));
}

/**
 * Send guild leave packet
 * @param sd map_session_data to send the packet to
 * @param *name contains name of the character.
 * @param *mes  contains leave message from player.
 * @return void
 */
void hBG_send_leave_single(struct map_session_data *sd, const char *name, const char *mes)
{
	unsigned char buf[128];
	int cmd = 0x15a;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;
	
	WBUFW(buf, 0) = cmd;
	memcpy(WBUFP(buf, 2), name, NAME_LENGTH);
	memcpy(WBUFP(buf,26), mes, 40);
	
	clif->send(buf, packet->len, &sd->bl, SELF);
}

/**
 * Notifies clients of a battleground message ZC_BATTLEFIELD_CHAT
 * 02dc <packet len>.W <account id>.L <name>.24B <message>.?B
 *
 * @param bgd battleground_data to send the message to
 * @param src_id id of the source of the message.
 * @param name contains the name of the character.
 * @param mes contains the message to be sent.
 * @param len contains the length of the message.
 * @return void.
 */
void hBG_send_chat_message(struct battleground_data *bgd, int src_id, const char *name, const char *mes, int len)
{
	struct map_session_data *sd;
	unsigned char *buf;

	nullpo_retv(bgd);
	nullpo_retv(name);
	nullpo_retv(mes);

	if ((sd = hBG_getavailablesd(bgd)) == NULL)
		return;

	len = (int)strlen(mes);
	Assert_retv(len <= INT16_MAX - NAME_LENGTH - 8);
	buf = (unsigned char*)aMalloc((len + NAME_LENGTH + 8)*sizeof(unsigned char));

	WBUFW(buf, 0) = 0x2dc;

	WBUFW(buf, 2) = len + NAME_LENGTH + 8;
	WBUFL(buf, 4) = src_id;
	memcpy(WBUFP(buf, 8), name, NAME_LENGTH);
	memcpy(WBUFP(buf, 32), mes, len); // [!] no NULL terminator

	clif->send(buf, WBUFW(buf, 2), &sd->bl, BG);

	if (buf)
		aFree(buf);
}

/**
 * Notifies the client of a guild expulsion.
 *
 * @param sd   map_session_data to send the packet to
 * @param *name  contains the name of the character.
 * @param *mes   contains the expulsion message.
 */
void hBG_send_expulsion(struct map_session_data *sd, const char *name, const char *mes)
{
	int fd;
	int cmd = 0x15c;
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;

	fd = sd->fd;
	WFIFOHEAD(fd, packet->len);
	WFIFOW(fd,0) = cmd;
	safestrncpy((char*)WFIFOP(fd,2), name, NAME_LENGTH);
	safestrncpy((char*)WFIFOP(fd,26), mes, 40);
	safestrncpy((char*)WFIFOP(fd,66), "", NAME_LENGTH);
	WFIFOSET(fd, packet->len);
}

/**
 * Notifies a single client of BG score updates
 * 
 * @param sd map_session_data to send the packet to
 * @return void
 */
void hBG_update_score_single(struct map_session_data *sd)
{
	int fd;
	int cmd = 0x2de;
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	struct hBG_mapflag *hBG_mf = getFromMAPD(&map->list[sd->bl.m], 0);
	const struct s_packet_db *packet = clif->packet(cmd);
	
	nullpo_retv(sd);
	
	if (packet == NULL)
		return;
	
	fd = sd->fd;

	WFIFOHEAD(fd, packet->len);
	WFIFOW(fd,0) = cmd;

	if (map->list[sd->bl.m].flag.battleground == 2) { // Score Board on Map. Team vs Team
		WFIFOW(fd,2) = map->list[sd->bl.m].bgscore_lion;
		WFIFOW(fd,4) = map->list[sd->bl.m].bgscore_eagle;
	} else if (map->list[sd->bl.m].flag.battleground == 3
			&& (bgd = bg->team_search(sd->bg_id)) != NULL
			&& (hBGd = getFromBGDATA(bgd, 0)) != NULL) { // Score Board Multiple. Team vs Best Score
		WFIFOW(fd,2) = hBGd->team_score;
		WFIFOL(fd,4) = hBG_mf->hBG_topscore;
	}
	WFIFOSET(fd, packet->len);
}

/**
 * Notifies all clients in a Battleground Team
 *
 * @param bgd battleground_data containing the map_session_datas to send the packet to
 * @return void
 */
void hBG_update_score_team(struct battleground_data *bgd)
{
	unsigned char buf[6];
	struct map_session_data *sd;
	int i, m, cmd = 0x2de;
	struct hBG_data *hBGd = getFromBGDATA(bgd, 0);
	struct hBG_mapflag *hBG_mf;
	const struct s_packet_db *packet = clif->packet(cmd);

	nullpo_retv(bg);

	if ((m = map->mapindex2mapid(bgd->mapindex)) < 0
		|| hBGd == NULL
		|| (hBG_mf = getFromMAPD(&map->list[m], 0)) == NULL
		|| packet == NULL)
		return;

	WBUFW(buf,0) = cmd;
	WBUFW(buf,2) = hBGd->team_score;
	WBUFW(buf,4) = hBG_mf->hBG_topscore;

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL || sd->bl.m != m)
			continue;

		clif->send(buf, packet->len, &sd->bl, SELF);
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    Queue System Functions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Searches hBG_queue_db by q_id
 * @param q_id contains the id of the queue to be searched.
 * @return hBG_queue_data * pointer to the memory location or null if not found.
 */
struct hBG_queue_data* hBG_queue_search(int q_id)
{ // Search a Queue using q_id
	if (!q_id)
		return NULL;
	
	return (struct hBG_queue_data *) idb_get(hBG_queue_db, q_id);
}

/**
 * Creates a Queue
 * @param queue_name contains the name of the queue.
 * @param join_event contains the event run on joining the queue.
 * @param min_level contains the minimum level to be able to join.
 * @return queue_id id of the queue created.
 */
int hBG_queue_create(const char* queue_name, const char* join_event, int min_level)
{
	struct hBG_queue_data *hBGqd;
	
	if (++hBG_queue_counter <= 0)
		hBG_queue_counter = 1;

	CREATE(hBGqd, struct hBG_queue_data, 1);
	hBGqd->q_id = hBG_queue_counter;
	
	safestrncpy(hBGqd->queue_name, queue_name, sizeof(hBGqd->queue_name));
	safestrncpy(hBGqd->join_event, join_event, sizeof(hBGqd->join_event));
	
	hBGqd->first = hBGqd->last = NULL; // First and Last Queue Members
	hBGqd->users = 0;
	hBGqd->min_level = min_level;
	
	idb_put(hBG_queue_db, hBG_queue_counter, hBGqd);

	return hBGqd->q_id;
}

/**
 * Remove all queue members from the queue and free the links.
 * @param hBGqd pointer to the queue data.
 * @return void.
 */
void hBG_queue_members_finalize(struct hBG_queue_data *hBGqd)
{
	struct hBG_queue_member *head, *next;
	
	nullpo_retv(hBGqd);

	head = hBGqd->first;
	while (head) {
		next = head->next;
		
		aFree(head);
		
		head = next;
	}

	hBGqd->first = hBGqd->last = NULL;
	hBGqd->users = 0;
}

/**
 * Add a player to the queue.
 * @param hBGqd pointer to the queue data.
 * @param sd    player to be added to the queue.
 * @return postition of the player in queue.
 */
int hBG_queue_member_add(struct hBG_queue_data *hBGqd, struct map_session_data *sd)
{
	struct hBG_queue_member *hBGqm;

	nullpo_retr(0, hBGqd);
	nullpo_retr(0, sd);

	hBGqd->users++;
	
	CREATE(hBGqm, struct hBG_queue_member, 1);
	
	hBGqm->sd = sd;
	hBGqm->position = hBGqd->users;
	hBGqm->next = NULL;
	
	if (getFromMSD (sd, 0) == NULL)
		addToMSD(sd, hBGqd, 0, false);
	
	if (hBGqd->last == NULL) {
		hBGqd->first = hBGqd->last = hBGqm; // Attach to first position
	} else { // Attach at the end of the queue
		hBGqd->last->next = hBGqm;
		hBGqd->last = hBGqm;
	}
	
	return hBGqm->position;
}

/**
 * Get a member of the queue from position n.
 * @param hBGqd    pointer to the queue data
 * @param position position of the player in queue
 * @return queue_member data or NULL if not found.
 */
struct hBG_queue_member* hBG_queue_member_get(struct hBG_queue_data *hBGqd, int position)
{
	struct hBG_queue_member *head;
	if (!hBGqd) return NULL;

	head = hBGqd->first;
	while (head != NULL) {
		if (head->sd && head->position == position)
			return head;

		head = head->next;
	}

	return NULL;
}

/**
 * Clear a queue and remove from memory.
 * @param hBGqd pointer to queue_data
 * return 1 on success, 0 on failure.
 */
int hBG_queue_destroy(struct hBG_queue_data *hBGqd)
{
	nullpo_ret(hBGqd);
	
	hBG_queue_members_finalize(hBGqd);
	
	idb_remove(hBG_queue_db, hBGqd->q_id);
	
	return 1;
}

/**
 * Remove a member from a queue
 * @param hBGqd pointer to queue data.
 * @param id    block list ID of player in queue.
 * @return position of a player in the queue or 0 if not found.
 */
int hBG_queue_member_remove(struct hBG_queue_data *hBGqd, int id)
{
	struct hBG_queue_member *head, *previous;
	int i;
	
	nullpo_retr(0, hBGqd);

	head = hBGqd->first;
	previous = NULL;

	while (head != NULL) {
		if (head->sd && head->sd->bl.id == id) {
			struct hBG_queue_member *next;
			
			next = head->next;
			i = head->position;
			
			hBGqd->users--;
			
			// De-attach target from the main queue
			if (previous) {
				previous->next = head->next;
			} else {
				hBGqd->first = head->next; // Deleted is on first position
			}
			
			if (head->next == NULL)
				hBGqd->last = previous; // Deleted is on last position
			
			while (next != NULL) {
				next->position--; // Decrement positions of the next in queue.
				next = next->next;
			}
			
			aFree(head);
			
			return i;
		}

		previous = head;
		head = head->next;
	}

	return 0;
}

/**
 * Search a member in the queue by Block List ID.
 * @param hBGqd pointer to queue data.
 * @param id    block list ID of a player in queue.
 * @return position of a player in the queue or 0 if not found.
 */
int hBG_queue_member_search(struct hBG_queue_data *hBGqd, int id)
{
	struct hBG_queue_member *head;
	
	nullpo_retr(0,hBGqd);

	head = hBGqd->first;

	while (head != NULL) {
		if (head->sd && head->sd->bl.id == id)
			return head->position;

		head = head->next;
	}

	return 0; // Not Found
}

/**
 * Add a player to the queue.
 * @param sd pointer to player to be added in queue.
 * @param q_id ID of the queue to be appended.
 * @return 0 on failure, 1 on success.
 */
int hBG_queue_join(struct map_session_data *sd, int q_id)
{
	char output[128];
	struct hBG_queue_data *hBGqd;
	int i = 0;
	int login_ip_count = hBG_config_get("battle_configuration/hBG_ip_check");
	
	nullpo_ret(sd);
	
	if (hBG_config_get("battle_configuration/hBG_from_town_only") && map->list[sd->bl.m].flag.town == 0) {
		clif->message(sd->fd,"You only can join BG queues from Towns or BG Waiting Room.");
		return 0;
	} else if (sd->bg_id) {
		clif->message(sd->fd,"You cannot join queues when already playing Battlegrounds.");
		return 0;
	} else if (sd->sc.data[SC_JAILED]) {
		clif->message(sd->fd,"You cannot join queues when jailed.");
		return 0;
	}
	// Get Queue by ID
	if ((hBGqd = hBG_queue_search(q_id)) == NULL) {
		return 0; // Current Queue don't exists
	} else if ((i = hBG_queue_member_search(hBGqd, sd->bl.id))) { // You cannot join a Queue if you are already in one.
		sprintf(output, "You are already in %s queue at position %d.", hBGqd->queue_name, i);
		clif->message(sd->fd, output);
		return 0;
	} else if (hBGqd && hBGqd->min_level && sd->status.base_level < hBGqd->min_level) {
		sprintf(output,"You cannot join %s queue. Required min level is %ud.", hBGqd->queue_name, hBGqd->min_level);
		clif->message(sd->fd,output);
		return 0;
	} else if (login_ip_count && hBG_countlogin(sd,false) > login_ip_count) {
		sprintf(output,"You cannot join %s queue. A max of %d characters are using your IP address.", hBGqd->queue_name, login_ip_count);
		clif->message(sd->fd,output);
		return 0;
	}

	i = hBG_queue_member_add(hBGqd, sd);
	
	sprintf(output,"You have joined %s queue at position %d.", hBGqd->queue_name, i);
	
	clif->message(sd->fd,output);

	if (hBGqd->join_event[0])
		npc->event_do(hBGqd->join_event);

	return i;
}

/**
 * Process player leaving a queue.
 * @param sd pointer to player leaving the queue.
 * @param q_id ID of the queue to be left.
 * @return 0 on failure, 1 on success.
 */
int hBG_queue_leave(struct map_session_data *sd, int q_id)
{
	char output[128];
	struct hBG_queue_data *qd;

	if ((qd = hBG_queue_search(q_id)) == NULL)
		return 0;

	if (!hBG_queue_member_remove(qd,sd->bl.id)) {
		sprintf(output,"You are not in the %s queue.", qd->queue_name);
		clif->message(sd->fd,output);
		return 0;
	}
	
	sprintf(output, "You have been removed from the %s queue.", qd->queue_name);
	clif->message(sd->fd, output);

	return 1;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Battleground Functions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
 * Return any available player in a Battleground
 * @param bgd pointer to battleground queue.
 * @return map_session_data *sd pointer to player data or NULL if not found.
 */
struct map_session_data* hBG_getavailablesd(struct battleground_data *bgd)
{
	int i;
	nullpo_retr(NULL, bgd);
	ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd != NULL);
	return(i < MAX_BG_MEMBERS) ? bgd->members[i].sd : NULL;
}

/**
 * Count the number of players with the same IP in battlegrounds.
 * @param sd pointer to map session data.
 * @param check_bat_room boolean to include checks in bat_room.
 * @return amount of accounts online.
 */
int hBG_countlogin(struct map_session_data *sd, bool check_bat_room)
{
	int c = 0, m = map->mapname2mapid("bat_room");
	struct map_session_data* pl_sd;
	struct s_mapiterator* iter;
	nullpo_ret(sd);

	iter = mapit_getallusers();
	for (pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter)) {
		if (!(getFromMSD(sd, 0) || map->list[pl_sd->bl.m].flag.battleground || (check_bat_room && pl_sd->bl.m == m)))
			continue;
		if (sockt->session[sd->fd]->client_addr == sockt->session[pl_sd->fd]->client_addr)
			c++;
	}
	mapit->free(iter);
	return c;
}

/**
 * Performs initialization tasks on new battlegrounds.
 * @param m map Index
 * @param rx respawn X co-ordinate
 * @param ry respawn Y co-ordinate
 * @param guild_index Index of the BG guild to be used
 * @param *ev NPC Script event to be called when player logs out.
 * @param *dev NPC Script event to be called when player dies.
 * @return ID of the battleground.
 */
int hBG_create(unsigned short m, short rx, short ry, int guild_index, const char *ev, const char *dev)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;

	CREATE(bgd, struct battleground_data, 1);
	CREATE(hBGd, struct hBG_data, 1);

	if (++bg_team_counter <= 0)
		bg_team_counter = 1;

	bgd->bg_id = bg_team_counter;
	bgd->count = 0;
	bgd->mapindex = m;
	bgd->x = rx;
	bgd->y = ry;

	safestrncpy(bgd->logout_event, ev, sizeof(bgd->logout_event));
	safestrncpy(bgd->die_event, dev, sizeof(bgd->die_event));

	memset(&bgd->members, 0, sizeof(bgd->members));

	hBGd->color = bg_colors[guild_index];
	hBGd->created_at = 0;
	hBGd->g = &bg_guild[guild_index];

	addToBGDATA(bgd, hBGd, 0, true);

	idb_put(bg->team_db, bg_team_counter, bgd);

	return bgd->bg_id;
}

/**
 * Add a player to the Battleground Team
 * @param bg_id Id of the battleground
 * @param sd pointer to the player's session data.
 * @return 0 on failure, 1 on success.
 */
int hBG_team_join(int bg_id, struct map_session_data *sd)
{ // Player joins team
	int i;
	struct battleground_data *bgd = bg->team_search(bg_id);
	struct map_session_data *pl_sd;
	struct hBG_map_session_data *hBGsd;
	struct hBG_data *hBGd;

	if (bgd == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL || sd == NULL || sd->bg_id)
		return 0;

	ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd == NULL);
	
	if (i == MAX_BG_MEMBERS)
		return 0; // No free slots

	// Handle Additional Map Session BG data
	if ((hBGsd = getFromMSD(sd, 1)) == NULL) {
		CREATE(hBGsd, struct hBG_map_session_data, 1);
		addToMSD(sd, hBGsd, 1, false);
	}
	
	hBGsd->bg_kills = 0;
	hBGsd->state.afk = 0;

	// Update player's idle item.
	pc->update_idle_time(sd, BCIDLE_WALK);

	sd->bg_id = bg_id;

	// Battleground Member data
	bgd->members[i].sd = sd;
	bgd->members[i].x = sd->bl.x;
	bgd->members[i].y = sd->bl.y;
	bgd->count++;
	
	// Guild Member Data simulation
	hBGd->g->member[i].sd = sd;

	// Creation Tick = First member joined.
	if (hBGd->created_at == 0)
		hBGd->created_at = sockt->last_tick;

	// First Join = Team Leader
	if (hBGd->leader_char_id == 0)
		hBGd->leader_char_id = sd->status.char_id;

	guild->send_dot_remove(sd);

	hBG_send_guild_info(sd); // Send Guild Name/Emblem under character
	
	clif->charnameupdate(sd); // Update character's nameplate
	
	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((pl_sd = bgd->members[i].sd) == NULL)
			continue;

		// Simulate Guild Information
		hBG_guild_window_info(pl_sd); // Main Guild window information.
		hBG_send_emblem(pl_sd, hBGd->g); // Emblems
		hBG_send_guild_member_list(pl_sd); // Member list
		hBG_send_guild_skillinfo(sd); // Send Guild skill information.

		if (pl_sd != sd)
			hBG_send_hp_single(sd->fd,pl_sd);
	}

	clif->guild_emblem_area(&sd->bl);

	clif->bg_hp(sd);
	clif->bg_xy(sd);

	return 1;
}

/**
 * Reveal a player's position to another player.
 * @param bl pointer to block list.
 * @param ap list of arguments
 * @return 0.
 */
int hBG_reveal_pos(struct block_list *bl, va_list ap)
{
	struct map_session_data *pl_sd, *sd = NULL;
	int flag, color;

	pl_sd = (struct map_session_data *)bl;
	sd = va_arg(ap,struct map_session_data *); // Source
	flag = va_arg(ap,int);
	color = va_arg(ap,int);

	if (pl_sd->bg_id == sd->bg_id)
		return 0; // Same Team

	clif->viewpoint(pl_sd,sd->bl.id,flag,sd->bl.x,sd->bl.y,sd->bl.id,color);
	return 0;
}

/**
 * Remove minimap indicator for player.
 * @param sd pointer to session data.
 * @return 0
 */
int hBG_send_dot_remove(struct map_session_data *sd)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int m;

	if (sd && sd->bg_id && (bgd = bg->team_search(sd->bg_id)) != NULL
	   && (hBGd = getFromBGDATA(bgd, 0)) != NULL) {
		clif->bg_xy_remove(sd);
		if (hBGd->reveal_pos && (m = map->mapindex2mapid(bgd->mapindex)) == sd->bl.m)
			map->foreachinmap(hBG_reveal_pos, m,BL_PC,sd,2,0xFFFFFF);
	}
	return 0;
}

/**
 * Searches and removes battleground game specific 
 * items from the player's inventory.
 * @param sd as struct map_session_data
 */
void hBG_member_remove_bg_items(struct map_session_data *sd)
{
	int n;
	
	nullpo_retv(sd);
	
	if ((n = pc->search_inventory(sd,BLUE_SKULL)) >= 0)
		pc->delitem(sd, n, sd->status.inventory[n].amount, 0, 2, LOG_TYPE_CONSUME);
	
	if ((n = pc->search_inventory(sd,RED_SKULL)) >= 0)
		pc->delitem(sd, n, sd->status.inventory[n].amount, 0, 2,LOG_TYPE_CONSUME);
	
	if ((n = pc->search_inventory(sd,GREEN_SKULL)) >= 0)
		pc->delitem(sd, n, sd->status.inventory[n].amount, 0, 2,LOG_TYPE_CONSUME);
}

/**
 * Get guild data of the Battleground
 * @param bg_id ID of the battleground
 * @return guild of the battleground or NULL.
 */
struct guild* hBG_get_guild(int bg_id)
{
	struct battleground_data *bgd = bg->team_search(bg_id);
	struct hBG_data *hBGd;

	if (bgd == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
		return NULL;

	return hBGd->g;
}

/**
 * Remove all members from a BG Team.
 * @param bg_id ID of the battleground.
 * @param remove Boolean for removal of BG from team_db.
 * @return 0 on failure, 1 on success.
 */
int hBG_team_finalize(int bg_id, bool remove)
{ // Deletes BG Team from db
	int i;
	struct map_session_data *sd;
	struct battleground_data *bgd = bg->team_search(bg_id);
	struct hBG_data *hBGd;
	struct guild *g;

	if (bgd == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
		return 0;

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL)
			continue;

		hBG_send_dot_remove(sd);
		sd->bg_id = 0;

		// Remove Guild Skill Buffs
		status_change_end(&sd->bl, SC_GUILDAURA, INVALID_TIMER);
		status_change_end(&sd->bl, SC_GDSKILL_BATTLEORDER, INVALID_TIMER);
		status_change_end(&sd->bl, SC_GDSKILL_REGENERATION, INVALID_TIMER);

		if (sd->status.guild_id && (g = guild->search(sd->status.guild_id)) != NULL) {
			clif->guild_belonginfo(sd,g);
			clif->guild_basicinfo(sd);
			clif->guild_allianceinfo(sd);
			clif->guild_memberlist(sd);
			clif->guild_skillinfo(sd);
		} else {
			hBG_send_leave_single(sd, sd->status.name, "Leaving Battle...");
		}

		clif->charnameupdate(sd);
		clif->guild_emblem_area(&sd->bl);
	}

	if (remove) {
		idb_remove(bg->team_db, bg_id);
	} else {
		bgd->count = 0;
		hBGd->leader_char_id = 0;
		hBGd->team_score = 0;
		hBGd->created_at = 0;
		memset(&bgd->members, 0, sizeof(bgd->members));
	}

	return 1;
}

/**
 * Give items to the Battleground Team.
 * @param bg_id ID of the battleground.
 * @param nameid ID of the item.
 * @param amount Amount of the Item to be given.
 * @return void;
 */
void hBG_team_getitem(int bg_id, int nameid, int amount)
{
	struct battleground_data *bgd;
	struct map_session_data *sd;
	struct item_data *id;
	struct item it;
	int reward_rate = hBG_config_get("battle_configuration/bg_reward_rates");
	int get_amount, j, flag;

	if (amount < 1 || (bgd = bg->team_search(bg_id)) == NULL || (id = itemdb->exists(nameid)) == NULL)
		return;
	if (nameid != 7828 && nameid != 7829 && nameid != 7773)
		return;
	if (reward_rate != 100)
		amount = amount * reward_rate / 100;

	memset(&it, 0, sizeof(it));
	it.nameid = nameid;
	it.identify = 1;

	for (j = 0; j < MAX_BG_MEMBERS; j++) {
		if ((sd = bgd->members[j].sd) == NULL)
			continue;

		get_amount = amount;

		if ((flag = pc->additem(sd,&it,get_amount,LOG_TYPE_SCRIPT)))
			clif->additem(sd,0,0,flag);
	}
}

/**
 * Give kafra points to the team.
 * @param bg_id ID of the battleground.
 * @param amount Amount of kafra points to be given.
 */
void hBG_team_get_kafrapoints(int bg_id, int amount)
{
	struct battleground_data *bgd;
	struct map_session_data *sd;
	int i, get_amount, reward_rate = hBG_config_get("battle_configuration/bg_reward_rates");

	if ((bgd = bg->team_search(bg_id)) == NULL)
		return;

	if (reward_rate != 100)
		amount = amount * reward_rate/ 100;

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL)
			continue;

		get_amount = amount;
		pc->getcash(sd,0,get_amount);
	}
}

void hBG_add_rank_points(struct map_session_data *sd, int ranktype, int count)
{
	struct hBG_map_session_data *hBGsd;
	char message[100];
	
	nullpo_retv(sd);
	
	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return;
	
	if (ranktype == BG_RANKED) {
		add2limit(hBGsd->stats.ranked_points, count, MAX_FAME);
		sprintf(message, "[Battlegrounds Ranked] Your ranking has increased by %d.", count);
		clif->disp_message(&sd->bl, message, SELF);
		hookStop();
	} else if (ranktype == BG_NORMAL) {
		add2limit(hBGsd->stats.points, count, MAX_FAME);
		sprintf(message, "[Battlegrounds Normal] Your ranking has increased by %d.", count);
		clif->disp_message(&sd->bl, message, SELF);
		hookStop();
	}
}

/* ==============================================================
 bg_arena (0 EoS | 1 Boss | 2 TI | 3 CTF | 4 TD | 5 SC | 6 CON | 7 RUSH | 8 DOM)
 bg_result (0 Won | 1 Tie | 2 Lost)
 ============================================================== */
void hBG_team_rewards(int bg_id, int nameid, int amount, int kafrapoints, int quest_id, const char *var, int add_value, int bg_arena, int bg_result)
{
	struct battleground_data *bgd = NULL;
	struct map_session_data *sd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;
	struct hBG_data *hBGd = NULL;
	struct item_data *id;
	struct item it;
	int j, flag, get_amount,
	reward_rate = hBG_config_get("battle_configuration/hBG_reward_rates"), fame = 0, type = 0;
	
	if (amount < 1 || (bgd = bg->team_search(bg_id)) == NULL || (id = itemdb->exists(nameid)) == NULL)
		return;

	if (reward_rate != 100) { // BG Reward Rates
		amount = amount * reward_rate / 100;
		kafrapoints = kafrapoints * reward_rate / 100;
	}
	
	memset(&it,0,sizeof(it));
	
	bg_result = cap_value(bg_result, 0, 2);
	
	if (nameid == 7828 || nameid == 7829 || nameid == 7773) {
		it.nameid = nameid;
		it.identify = 1;
	} else {
		nameid = 0;
	}

	for (j = 0; j < MAX_BG_MEMBERS; j++) {
		if ((sd = bgd->members[j].sd) == NULL)
			continue;
		else if ((hBGsd = getFromMSD(sd, 1)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
			continue;

		if (quest_id)
			quest->add(sd, quest_id, 0);
		
		pc_setglobalreg(sd, script->add_str(var), pc_readglobalreg(sd,script->add_str(var)) + add_value);

		if (kafrapoints > 0) {
			get_amount = kafrapoints;
			pc->getcash(sd,0,get_amount);
		}

		if (nameid && amount > 0) {
			get_amount = amount;

			if ((flag = pc->additem(sd,&it,get_amount,LOG_TYPE_SCRIPT)))
				clif->additem(sd,0,0,flag);
		}
		
		type = hBG_config_get("battle_configuration/hBG_ranked_mode")?BG_RANKED:BG_NORMAL;
		
		switch (bg_result) {
			case 0: // Won
				add2limit(hBGsd->stats.wins,1,USHRT_MAX);
				fame = 100;
				if (sd->status.char_id == hBGd->leader_char_id) {
					add2limit(hBGsd->stats.wins_as_leader,1,USHRT_MAX);
					fame += 25;
				}
				
				hBG_add_rank_points(sd, fame, type);
				
				switch (bg_arena) {
					case 0:
						add2limit(hBGsd->stats.eos_wins,1,USHRT_MAX);
						break;
					case 1:
						add2limit(hBGsd->stats.boss_wins,1,USHRT_MAX);
						break;
					case 2:
						add2limit(hBGsd->stats.ti_wins,1,USHRT_MAX);
						break;
					case 3:
						add2limit(hBGsd->stats.ctf_wins,1,USHRT_MAX);
						break;
					case 4:
						add2limit(hBGsd->stats.td_wins,1,USHRT_MAX);
						break;
					case 5:
						add2limit(hBGsd->stats.sc_wins,1,USHRT_MAX);
						break;
					case 6:
						add2limit(hBGsd->stats.conquest_wins,1,USHRT_MAX);
						break;
					case 7:
						add2limit(hBGsd->stats.ru_wins,1,USHRT_MAX);
						break;
					case 8:
						add2limit(hBGsd->stats.dom_wins,1,USHRT_MAX);
						break;
				}
				break;
			case 1: // Tie
				add2limit(hBGsd->stats.ties,1,USHRT_MAX);
				fame = 75;
				if (sd->status.char_id == hBGd->leader_char_id) {
					add2limit(hBGsd->stats.ties_as_leader,1,USHRT_MAX);
					fame += 10;
				}
				hBG_add_rank_points(sd, fame, type);
				switch (bg_arena) {
					case 0: add2limit(hBGsd->stats.eos_tie,1,USHRT_MAX); break;
					case 1: add2limit(hBGsd->stats.boss_tie,1,USHRT_MAX); break;
					case 2: add2limit(hBGsd->stats.ti_tie,1,USHRT_MAX); break;
					case 3: add2limit(hBGsd->stats.ctf_tie,1,USHRT_MAX); break;
					case 4: add2limit(hBGsd->stats.td_tie,1,USHRT_MAX); break;
					case 5: add2limit(hBGsd->stats.sc_tie,1,USHRT_MAX); break;
						// No Tie for Conquest or Rush
					case 8: add2limit(hBGsd->stats.dom_tie,1,USHRT_MAX); break;
				}
				break;
			case 2: // Lost
				add2limit(hBGsd->stats.losses,1,USHRT_MAX);
				
				fame = 50;
				
				if (sd->status.char_id == hBGd->leader_char_id)
					add2limit(hBGsd->stats.losses_as_leader,1,USHRT_MAX);
				
				hBG_add_rank_points(sd, fame, type);
				
				switch (bg_arena) {
					case 0: add2limit(hBGsd->stats.eos_lost,1,USHRT_MAX); break;
					case 1: add2limit(hBGsd->stats.boss_lost,1,USHRT_MAX); break;
					case 2: add2limit(hBGsd->stats.ti_lost,1,USHRT_MAX); break;
					case 3: add2limit(hBGsd->stats.ctf_lost,1,USHRT_MAX); break;
					case 4: add2limit(hBGsd->stats.td_lost,1,USHRT_MAX); break;
					case 5: add2limit(hBGsd->stats.sc_lost,1,USHRT_MAX); break;
					case 6: add2limit(hBGsd->stats.conquest_losses,1,USHRT_MAX); break;
					case 7: add2limit(hBGsd->stats.ru_lost,1,USHRT_MAX); break;
					case 8: add2limit(hBGsd->stats.dom_lost,1,USHRT_MAX); break;
				}
				break;
		}
	}
}

/**
 * Build BG Guild Emulation data.
 * @params (void)
 * @return void.
 */
void hBG_build_guild_data(void)
{
	int i, j, k, gskill;
	memset(&bg_guild, 0, sizeof(bg_guild));

	for (i = 1; i <= MAX_BATTLEGROUND_TEAMS; i++) { // Emblem Data - Guild ID's
		FILE* fp = NULL;
		char gpath[256];

		j = i - 1;
		bg_guild[j].emblem_id = 1; // Emblem Index
		bg_guild[j].guild_id = SHRT_MAX - j;
		bg_guild[j].guild_lv = 1;
		bg_guild[j].max_member = MAX_BG_MEMBERS;

		// Skills
		if (j < 3) { // Clan Skills
			for (k = 0; k < MAX_GUILDSKILL; k++) {
				gskill = k + GD_SKILLBASE;
				bg_guild[j].skill[k].id = gskill;
				switch (gskill) {
					case GD_GLORYGUILD:
						bg_guild[j].skill[k].lv = 0;
						break;
					case GD_APPROVAL:
					case GD_KAFRACONTRACT:
					case GD_GUARDRESEARCH:
					case GD_BATTLEORDER:
					case GD_RESTORE:
					case GD_EMERGENCYCALL:
					case GD_DEVELOPMENT:
						bg_guild[j].skill[k].lv = 1;
						break;
					case GD_GUARDUP:
					case GD_REGENERATION:
						bg_guild[j].skill[k].lv = 3;
						break;
					case GD_LEADERSHIP:
					case GD_GLORYWOUNDS:
					case GD_SOULCOLD:
					case GD_HAWKEYES:
						bg_guild[j].skill[k].lv = 5;
						break;
					case GD_EXTENSION:
						bg_guild[j].skill[k].lv = 10;
						break;
				}
			}
		} else { // Other Data
			snprintf(bg_guild[j].name, NAME_LENGTH, "Team %d", i - 3); // Team 1, Team 2 ... Team 10
			strncpy(bg_guild[j].master, bg_guild[j].name, NAME_LENGTH);
			snprintf(bg_guild[j].position[0].name, NAME_LENGTH, "%s Leader", bg_guild[j].name);
			strncpy(bg_guild[j].position[1].name, bg_guild[j].name, NAME_LENGTH);
		}

		sprintf(gpath, "%s/%s/bg_%d.ebm", "plugins","hBG", i);
		if ((fp = fopen(gpath, "rb")) != NULL) {
			fseek(fp, 0, SEEK_END);
			bg_guild[j].emblem_len = (int)ftell(fp);
			fseek(fp, 0, SEEK_SET);
			fread(&bg_guild[j].emblem_data, 1, bg_guild[j].emblem_len, fp);
			fclose(fp);
		} else {
			ShowWarning("Error reading '"CL_WHITE"%s"CL_RESET"' emblem data file.\n", gpath);
		}
	}
	
	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"' v%s emblem data files. [By Smokexyz]\n", pinfo.name, pinfo.version);

	// Guild Data - Guillaume
	strncpy(bg_guild[0].name, "Blue Team", NAME_LENGTH);
	strncpy(bg_guild[0].master, "General Guillaume", NAME_LENGTH);
	strncpy(bg_guild[0].position[0].name, "Blue Team Leader", NAME_LENGTH);
	strncpy(bg_guild[0].position[1].name, "Blue Team", NAME_LENGTH);

	// Guild Data - Croix
	strncpy(bg_guild[1].name, "Red Team", NAME_LENGTH);
	strncpy(bg_guild[1].master, "Prince Croix", NAME_LENGTH);
	strncpy(bg_guild[1].position[0].name, "Red Team Leader", NAME_LENGTH);
	strncpy(bg_guild[1].position[1].name, "Red Team", NAME_LENGTH);

	// Guild Data - Traitors
	strncpy(bg_guild[2].name, "Green Team", NAME_LENGTH);
	strncpy(bg_guild[2].master, "Mercenary", NAME_LENGTH);
	strncpy(bg_guild[2].position[0].name, "Green Team Leader", NAME_LENGTH);
	strncpy(bg_guild[2].position[1].name, "Green Team", NAME_LENGTH);
}

/**
 * Timer function for revealing/hiding mini map positions.
 * Also handles player AFK mechanic.
 * @see DBApply
 * @see hBG_send_xy_timer
 * @param data battleground data pointer.
 * @return int
 */
int hBG_send_xy_timer_sub(union DBKey key, struct DBData *data, va_list ap)
{
	struct battleground_data *bgd = DB->data2ptr(data);
	struct hBG_data *hBGd = getFromBGDATA(bgd, 0);
	char output[128];
	int i, m, idle_announce = hBG_config_get("battle_configuration/hBG_idle_announce"),
		idle_autokick = hBG_config_get("battle_configuration/hBG_idle_autokick");

	nullpo_ret(bgd);
	nullpo_ret(hBGd);

	m = map->mapindex2mapid(bgd->mapindex);
	hBGd->reveal_flag = !hBGd->reveal_flag; // Switch

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		struct map_session_data *sd = bgd->members[i].sd;
		struct hBG_map_session_data *hBGsd = NULL;

		if (sd == NULL || (hBGsd = getFromMSD(sd, 1)) == NULL)
			continue;

		if (idle_autokick && DIFF_TICK(sockt->last_tick, sd->idletime) >= idle_autokick
			&& hBGd->g && map->list[sd->bl.m].flag.battleground)
		{
			sprintf(output, "[Battlegrounds] %s has been kicked for being AFK.", sd->status.name);
			clif->broadcast2(&sd->bl, output, (int)strlen(output)+1, hBGd->color, 0x190, 20, 0, 0, BG);

			bg->team_leave(sd,3);

			clif->message(sd->fd, "You have been kicked from the battleground because of your AFK status.");
			pc->setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 3);
			continue;
		} else if (sd->bl.x != bgd->members[i].x || sd->bl.y != bgd->members[i].y) { // xy update
			bgd->members[i].x = sd->bl.x;
			bgd->members[i].y = sd->bl.y;
			clif->bg_xy(sd);
		}
		
		if (hBGd->reveal_pos && hBGd->reveal_flag && sd->bl.m == m)
			map->foreachinmap(hBG_reveal_pos, m, BL_PC, sd, 1, hBGd->color);
		
		// Message for AFK Idling
		if (idle_announce && DIFF_TICK(sockt->last_tick, sd->idletime) >= idle_announce && !hBGsd->state.afk && hBGd->g)
		{ // Set AFK status and announce to the team.
			hBGsd->state.afk = 1;
			sprintf(output, "%s : %s seems to be away. AFK Warning - Can be kicked out with @reportafk.", hBGd->g->name, sd->status.name);
			hBG_send_chat_message(bgd, sd->bl.id, sd->status.name, output, (int)strlen(output) + 1);
		}
	}

	return 0;
}

/**
 * Timer function for revealing/hiding mini map positions.
 * Also handles player AFK time.
 * @see hBG_send_xy_timer_sub
 */
int hBG_send_xy_timer(int tid, int64 tick, int id, intptr_t data)
{
	bg->team_db->foreach(bg->team_db, hBG_send_xy_timer_sub, tick);
	return 0;
}

/**
 * Add an item to the floor at m (x,y)
 * @param bl pointer to the block list.
 * @param m map index
 * @param x map x co-ordinate
 * @param y map y co-ordinate
 * @param nameid ID of the item to be dropped.
 * @param amount Amount of the item to be dropped.
 * @return count of the item dropped.
 */
int hBG_addflooritem_area(struct block_list* bl, int16 m, int16 x, int16 y, int nameid, int amount)
{
	struct item item_tmp;
	int count, range, i;
	short mx, my;
	
	memset(&item_tmp, 0, sizeof(item_tmp));
	item_tmp.nameid = nameid;
	item_tmp.identify = 1;
	
	if (bl != NULL) m = bl->m;
	
	count = 0;
	range = (int)sqrt((float)amount) +2;
	
	for ( i = 0; i < amount; i++) {
		if (bl != NULL)
			map->search_freecell(bl, 0, &mx, &my, range, range, 0);
		else {
			mx = x; my = y;
			map->search_freecell(NULL, m, &mx, &my, range, range, 1);
		}
		
		count += (map->addflooritem(bl, &item_tmp, 1, m, mx, my, 0, 0, 0, 4, false) != 0) ? 1 : 0;
	}
	
	return count;
}

// @TODO
void hBG_bg_ranking_display(struct map_session_data *sd, bool ranked)
{
	struct hBG_map_session_data *hBGsd = NULL;
	
	nullpo_retv(sd);
	
	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return;
	
	// print shit.
	
}

void hBG_record_mobkills(struct map_session_data *sd, struct mob_data *md)
{
	struct battleground_data *bgd = NULL;
	struct hBG_data *hBGd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;

	nullpo_retv(sd);
	nullpo_retv(md);

	if (map->list[sd->bl.m].flag.battleground && sd->bg_id) {
		int i;
		if ((bgd = bg->team_search(sd->bg_id)) == NULL)
			return;
		if ((hBGd = getFromBGDATA(bgd, 0)) == NULL)
			return;
		if ((hBGsd = getFromMSD(sd, 1)) == NULL)
			return;

		ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd == sd);

		if (i >= MAX_BG_MEMBERS)
			return;

		switch ( md->class_)
		{
		case E_BAPHOMET2:
		case E_LORD_OF_DEATH2:
		case E_DARK_LORD:
		case E_KTULLANUX:
		case E_DARK_SNAKE_LORD:
			add2limit(hBGsd->stats.boss_killed, 1, USHRT_MAX);
			break;
		case E_TURTLE_GENERAL:
		case E_APOCALIPS_H:
			add2limit(hBGsd->stats.guardian_stone_kills, 1, USHRT_MAX);
			break;
		case E_FALLINGBISHOP:
			if (map->list[sd->bl.m].flag.battleground == 2)
				add2limit(hBGsd->stats.ru_captures, 1, USHRT_MAX);
			break;
		case OBJ_NEUTRAL:
			if (strcmpi(map->list[sd->bl.m].name, "bat_a03") == 0)
				add2limit(hBGsd->stats.boss_flags, 1, USHRT_MAX);
			break;
		case BARRICADE_:
			if (strcmpi(map->list[sd->bl.m].name, "bat_a01") == 0)
				add2limit(hBGsd->stats.barricade_kills, 1, USHRT_MAX);
			break;
		}
	}
}

void hBG_record_damage(struct block_list *src, struct block_list *target, int damage)
{
	struct block_list *s_bl = NULL;
	struct map_session_data *sd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;

	if (src == NULL || target == NULL || src == target || damage <= 0)
		return;

	if ((s_bl = battle->get_master(src)) == NULL)
		s_bl = src;

	if (s_bl->type != BL_PC)
		return;

	if ((sd = BL_UCAST(BL_PC, s_bl)) == NULL)
		return;

	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return;

	switch ( target->type)
	{
	case BL_PC:
		{
			struct map_session_data *tsd = NULL;
			struct hBG_map_session_data *hBGtsd = NULL;

			if ((tsd = BL_UCAST(BL_PC, target)) == NULL)
				break;
			if ((hBGtsd = getFromMSD(tsd, 1)) == NULL)
				break;

			if (map->list[src->m].flag.battleground && sd->bg_id) {
				add2limit(hBGsd->stats.total_damage_done, damage, UINT_MAX);
				add2limit(hBGtsd->stats.total_damage_received, damage, UINT_MAX);

				if (hBGsd->stats.best_damage < damage)
					hBGsd->stats.best_damage = damage;
			}
		}
		break;
	case BL_MOB:
		{
			struct mob_data *md = BL_UCAST(BL_MOB, target);
			if (map->list[src->m].flag.battleground && sd->bg_id && md->class_ >= E_BAPHOMET2 && md->class_ <= E_FALLINGBISHOP)
				add2limit(hBGsd->stats.boss_damage, damage, USHRT_MAX);
		}
		break;
	}
}

/**
 * Warps a Team
 * @see hBG_warp
 */
int hBG_team_warp(int bg_id, unsigned short mapidx, short x, short y)
{ // Warps a Team
	int i;
	struct battleground_data *bgd = bg->team_search(bg_id);

	if (bgd == NULL) {
		ShowError("buildin_hBG_team_warp: Invalid teamId %d provided!", bg_id);
		return false;
	}

	if (mapidx == 0) { // BG Cemetery (Spawn Point)
		mapidx = bgd->mapindex;
		x = bgd->x;
		y = bgd->y;
	}

	for (i = 0; i < bgd->count; i++)
		if (bgd->members[i].sd != NULL)
			pc->setpos(bgd->members[i].sd, mapidx, x, y, CLR_TELEPORT);

	return true;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     @Commands
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
 * Display battleground rankings.
 */
ACMD(bgrank)
{
	char mode[7];
	char atcmd_output[256];
	
	memset(atcmd_output, '\0', sizeof(atcmd_output));
	
	if (!*message || sscanf(message, "%7s", mode) < 1) {
		sprintf(atcmd_output, "Please, enter a battleground mode (usage: @bgrank <ranked/normal>).");
		clif->message(fd, atcmd_output);
		return false;
	}
	
	if (strncmpi(mode, "ranked", 7) == 0) {
		hBG_bg_ranking_display(sd, true);
	} else if (strncmpi(mode, "normal", 7) == 0) {
		hBG_bg_ranking_display(sd, true);
	} else {
		sprintf(atcmd_output, "Please, enter a battleground mode (usage: @bgrank <ranked/normal>).");
		clif->message(fd, atcmd_output);
		return false;
	}
	
	return true;
}

ACMD(reportafk)
{
	struct map_session_data *pl_sd = NULL;
	struct hBG_data *hBGd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;
	struct hBG_map_session_data *hBGpl_sd = NULL;
	struct battleground_data *bgd = NULL;
	
	if ((bgd = bg->team_search(sd->bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
		clif->message(fd, "This command is reserved for Battlegrounds Only.");
	else if (!(hBGd->leader_char_id == sd->status.char_id) && hBG_config_get("battle_configuration/hBG_reportafk_leaderonly"))
		clif->message(fd, "This command is reserved for Team Leaders Only.");
	else if (!*message)
		clif->message(fd, "Please, enter the character name (usage: @reportafk <name>).");
	else if ((pl_sd = map->nick2sd(message)) == NULL)
		clif->message(fd, msg_txt(3)); // Character not found.
	else if ((hBGpl_sd = getFromMSD(pl_sd, 0)) == NULL)
		clif->message(fd, "Destination Player is not in battlegrounds.");
	else if (sd->bg_id != pl_sd->bg_id)
		clif->message(fd, "Destination Player is not in your Team.");
	else if (sd == pl_sd)
		clif->message(fd, "You cannot kick yourself.");
	else if (!hBGpl_sd->state.afk)
		clif->message(fd, "The player is not AFK on this Battleground.");
	else
	{ // Everything is fine!
		char atcmd_output[256];
		
		 // Kick the player and send a message.
		bg->team_leave(pl_sd, 2);
		clif->message(pl_sd->fd, "You have been kicked from Battleground because of your AFK status.");
		pc->setpos(pl_sd, pl_sd->status.save_point.map, pl_sd->status.save_point.x, pl_sd->status.save_point.y, 3);
		// Message the source player and announce to team.
		sprintf(atcmd_output, "%s has been successfully kicked.", pl_sd->status.name);
		clif->broadcast2(&sd->bl, atcmd_output, (int)strlen(atcmd_output)+1, hBGd->color, 0x190, 20, 0, 0, BG);
		return true;
	}
	
	return false;
}

/**
 * Change Team Leader.
 */
ACMD(leader)
{
	struct map_session_data *pl_sd = NULL;
	struct hBG_data *hBGd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;
	struct hBG_map_session_data *hBGpl_sd = NULL;
	struct battleground_data *bgd = NULL;
	
	if ((bgd = bg->team_search(sd->bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
		clif->message(fd, "This command is reserved for Battlegrounds Only.");
	else if (sd->ud.skilltimer != INVALID_TIMER)
		clif->message(fd, "Command not allow while casting a skill.");
	else if (!(hBG_config_get("battle_configuration/hBG_leader_change")))
		clif->message(fd, "This command is disabled.");
	else if (!(hBGd->leader_char_id == sd->status.char_id))
		clif->message(fd, "This command is reserved for Team Leaders Only.");
	else if (!*message)
		clif->message(fd, "Please, enter the character name (usage: @leader <name>).");
	else if ((pl_sd = map->nick2sd(message)) == NULL)
		clif->message(fd, msg_txt(3)); // Character not found.
	else if ((hBGpl_sd = getFromMSD(pl_sd, 0)) == NULL)
		clif->message(fd, "Destination Player is not in battlegrounds.");
	else if (sd->bg_id != pl_sd->bg_id)
		clif->message(fd, "Destination Player is not in your Team.");
	else if (sd == pl_sd)
		clif->message(fd, "You are already the Team Leader.");
	else
	{ // Everything is fine... more or less.
		char atcmd_output[256];
		sprintf(atcmd_output, "Team Leader transfered to [%s]", pl_sd->status.name);
		clif->broadcast2(&sd->bl, atcmd_output, (int)strlen(atcmd_output) + 1, hBGd->color, 0x190, 20, 0, 0, BG);
		hBGd->leader_char_id = pl_sd->status.char_id;
		clif->charnameupdate(sd);
		clif->charnameupdate(pl_sd);
		return true;
	}
	return false;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Script Commands
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Send out a battleground announcement.
 * @param mes
 * @param fontColor
 * @param fontType
 * @param fontSize
 * @param fontAlign
 * @param fontY
 */
BUILDIN(hBG_announce)
{
	const char *mes       = script_getstr(st,2);
	const char *fontColor = script_hasdata(st,3) ? script_getstr(st,3) : NULL;
	int         fontType  = script_hasdata(st,4) ? script_getnum(st,4) : 0x190; // default fontType (FW_NORMAL)
	int         fontSize  = script_hasdata(st,5) ? script_getnum(st,5) : 12;    // default fontSize
	int         fontAlign = script_hasdata(st,6) ? script_getnum(st,6) : 0;     // default fontAlign
	int         fontY     = script_hasdata(st,7) ? script_getnum(st,7) : 0;     // default fontY

	clif->broadcast2(NULL, mes, (int)strlen(mes) + 1, (unsigned int)strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, ALL_CLIENT);

	return true;
}

/**
 * Count the number of logins per IP in battleground
 * @return count of accounts on same ip.
 */
BUILDIN(hBG_logincount)
{
	struct map_session_data *sd = script->rid2sd(st);
	int i = 0;

	if (sd)
		i = hBG_countlogin(sd,true);

	script_pushint(st,i);
	return true;
}

/**
 * Create a BG Team.
 * @param map_name Respawn Map Name
 * @param map_x Respawn Map X
 * @param map_y Respawn Map Y
 * @param guild_index BG Guild Index
 * @param ev Logout Event
 * @param dev Die Event
 */
BUILDIN(hBG_team_create)
{
	const char *map_name, *ev = "", *dev = "";
	int x, y, m = 0, guild_index, bg_id;

	map_name = script_getstr(st, 2);
	if (strcmp(map_name,"-") != 0 && (m = mapindex->name2id(map_name)) == 0) {
		script_pushint(st, 0);
		return false;
	}

	x = script_getnum(st, 3);
	y = script_getnum(st, 4);
	guild_index = script_getnum(st, 5);
	ev = script_getstr(st, 6); // Logout Event
	dev = script_getstr(st, 7); // Die Event

	guild_index = cap_value(guild_index, 0, 12);
	bg_id = hBG_create(m, x, y, guild_index, ev, dev);

	script_pushint(st, bg_id);
	return true;
}

/**
 * Create a Queue
 * @param queue_name Name of the Queue
 * @param jev Join Event
 * @param min_level Minimum level to join the queue.
 * @return queue Id
 */
BUILDIN(hBG_queue_create)
{
	const char *queue_name, *jev;
	int min_level = 0;

	queue_name = script_getstr(st, 2);
	jev = script_getstr(st, 3);
	
	if (script_hasdata(st, 4))
		min_level = script_getnum(st, 4);

	script_pushint(st, hBG_queue_create(queue_name, jev, min_level));

	return true;
}


/**
 * Changes/Sets the Queue's Join Event.
 * @param queue_id
 * @param jev On Join Event
 */
BUILDIN(hBG_queue_event)
{
	struct hBG_queue_data *hBGqd;
	const char *join_event;
	int q_id;

	q_id = script_getnum(st,2);

	if ((hBGqd = hBG_queue_search(q_id)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	join_event = script_getstr(st,3);

	safestrncpy(hBGqd->join_event, join_event, sizeof(hBGqd->join_event));

	script_pushint(st, 1);
	return true;
}

/**
 * Makes a player join a queue.
 * @param Queue ID
 */
BUILDIN(hBG_queue_join)
{
	int q_id;
	struct map_session_data *sd = script->rid2sd(st);

	nullpo_retr(false, sd);

	q_id = script_getnum(st,2);

	script_pushint(st, hBG_queue_join(sd, q_id));

	return true;
}

/**
 * Makes party join a queue.
 * @param Party ID
 * @param Queue ID
 */
BUILDIN(hBG_queue_partyjoin)
{
	int q_id, i, party_id;
	struct map_session_data *sd;
	struct party_data *p;

	party_id = script_getnum(st,2);

	if (party_id <= 0 || (p = party->search(party_id)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	q_id = script_getnum(st,3);

	if (hBG_queue_search(q_id) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	for (i = 0; i < MAX_PARTY; i++) {
		if ((sd = p->data[i].sd) == NULL)
			continue;
		hBG_queue_join(sd,q_id);
	}

	script_pushint(st, 1);

	return true;
}

/**
 * Makes a player leave a queue.
 * @param Queue ID
 */
BUILDIN(hBG_queue_leave)
{
	int q_id;
	struct map_session_data *sd = script->rid2sd(st);

	nullpo_retr(false, sd);

	q_id = script_getnum(st,2);

	script_pushint(st, hBG_queue_leave(sd, q_id));

	return true;
}

/**
 * Request queue information
 * @param Queue ID
 * @param Information Type
 *        0) Users
 *        1) Copy user list to $@qmembers$ variable and return count.
 */
BUILDIN(hBG_queue_data)
{
	struct hBG_queue_data *hBGqd;
	int q_id = script_getnum(st,2),
	type = script_getnum(st,3);

	if ((hBGqd = hBG_queue_search(q_id)) == NULL) {
		script_pushint(st,0);
		return false;
	}

	switch (type) {
		case 0:
			script_pushint(st, hBGqd->users);
			return true;
		case 1: // User List
		{
			int j = 0;
			struct map_session_data *sd;
			struct hBG_queue_member *head;
			head = hBGqd->first;
			while (head) {
				if ((sd = head->sd) != NULL) {
					mapreg->setregstr(reference_uid(script->add_str("$@qmembers$"),j),sd->status.name);
					j++;
				}
				head = head->next;
			}
			script_pushint(st,j);
		}
			return true;
		default:
			ShowError("script:hBG_queue_data: unknown queue data type %d.\n", type);
			break;
	}

	script_pushint(st, 0);
	return true;
}

/**
 * Adds all members in queue to a BG team.
 * @param Queue ID
 * @param Max Team Members
 * @param Respawn Map Name
 * @param Respawn Map X
 * @param Respawn Map Y
 * @param BG Guild Index
 * @param Logout Event
 * @param Die Event
 * @return Battleground Id
 */
BUILDIN(hBG_queue2team)
{
	struct hBG_queue_data *hBGqd;
	struct hBG_queue_member *qm;
	const char *map_name, *ev = "", *dev = "";
	int q_id, max, x, y, i, m=0, guild_index, bg_id;

	q_id = script_getnum(st,2);
	if ((hBGqd = hBG_queue_search(q_id)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	max = script_getnum(st,3);
	map_name = script_getstr(st,4);

	if (strcmp(map_name,"-") != 0 && (m = mapindex->name2id(map_name)) == 0) {
		script_pushint(st, 0);
		return false;
	}

	x = script_getnum(st,5);
	y = script_getnum(st,6);
	guild_index = script_getnum(st,7);
	ev = script_getstr(st,8); // Logout Event
	dev = script_getstr(st,9); // Die Event

	guild_index = cap_value(guild_index, 0, 12);

	if ((bg_id = hBG_create(m, x, y, guild_index, ev, dev)) == 0) {
		script_pushint(st, 0);
		return false;
	}

	i = 0; // Counter
	while ((qm = hBGqd->first) != NULL && i < max && i < MAX_BG_MEMBERS) {
		if (qm->sd && hBG_team_join(bg_id, qm->sd)) {
			mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), qm->sd->bl.id);
			hBG_queue_member_remove(hBGqd, qm->sd->bl.id);
			i++;
		} else {
			break; // Failed? Should not. Anyway, to avoid a infinite loop
		}
	}

	mapreg->setreg(script->add_str("$@arenamembersnum"), i);

	script_pushint(st, bg_id);

	return true;
}

/**
 * Joins the first player in the queue to the given team and warps him.
 * @param Queue ID
 * @param Battleground ID
 * @param Spawn Map Name
 * @param Spawn Map X Co-ordinate
 * @param Spawn Map Y Co-ordinate
 */
BUILDIN(hBG_queue2team_single)
{
	const char* map_name;
	struct hBG_queue_data *hBGqd;
	struct map_session_data *sd;
	int x, y, m, bg_id, q_id;

	q_id = script_getnum(st,2);

	if ((hBGqd = hBG_queue_search(q_id)) == NULL || !hBGqd->first || !hBGqd->first->sd) {
		script_pushint(st, 0);
		return false;
	}

	bg_id = script_getnum(st, 3);
	map_name = script_getstr(st, 4);

	if ((m = mapindex->name2id(map_name)) == 0) {
		script_pushint(st, 0);
		return false;
	}

	x = script_getnum(st, 5);
	y = script_getnum(st, 6);
	sd = hBGqd->first->sd;

	if (hBG_team_join(bg_id, sd)) {
		hBG_queue_member_remove(hBGqd, sd->bl.id);
		pc->setpos(sd, m, x, y, CLR_TELEPORT);
		script_pushint(st, 1);
	}

	return true;
}
/**
 * Check if the given BG Queue can start a BG in the given mode.
 * @param Queue ID
 * @param Type
 * @param Teams
 * @param Required Minimum Players
 * @return 1 can start, 0 cannot start.
 */
BUILDIN(hBG_queue_checkstart)
{
	int q_id, result = 0;
	struct hBG_queue_data *hBGqd;

	q_id = script_getnum(st,2);

	if ((hBGqd = hBG_queue_search(q_id)) != NULL) {
		int type, req_min, teams;

		type = script_getnum(st,3);
		teams = script_getnum(st,4);
		req_min = script_getnum(st,5);

		switch (type) {
			case 0: // Lineal, as they Join
			case 1: // Random
				if (hBGqd->users >= (req_min * teams))
					result = 1;
				break;
			default:
				result = 0;
				break;
		}
	}

	script_pushint(st, result);

	return true;
}

/**
 * Build BG Teams from one Queue
 * @param Queue ID
 * @param Minimum Players
 * @param Maximum Players per Team
 * @param Type
 * @param ... Team ID
 */
BUILDIN(hBG_queue2teams)
{ // Send Users from Queue to Teams. Requires previously created teams.
	struct hBG_queue_data *hBGqd;
	int t, bg_id = 0, total_teams = 0, q_id, min, max, type, limit = 0;
	int arg_offset = 6;
	struct map_session_data *sd;

	q_id = script_getnum(st,2); // Queue ID
	if ((hBGqd = hBG_queue_search(q_id)) == NULL) {
		ShowError("buildin_hBG_queue2teams: Non existant queue id received %d.\n", q_id);
		script_pushint(st, 0);
		return false;
	}

	min = script_getnum(st,3); // Min Members per Team
	max = script_getnum(st,4); // Max Members per Team
	type = script_getnum(st,5); // Team Building Method

	t = arg_offset; // Team ID's to build
	while (script_hasdata(st,t) && t < MAX_BATTLEGROUND_TEAMS+arg_offset) {
		bg_id = script_getnum(st,t);
		if (bg->team_search(bg_id) == NULL) {
			ShowError("buildin_hBG_queue2teams: Non existant team Id received %d.\n", bg_id);
			script_pushint(st, 0);
			return false;
		}
		t++;
	}
	total_teams = t - arg_offset;

	if (total_teams < 2) {
		ShowError("buildin_hBG_queue2teams: Less than 2 teams received to build members.\n");
		script_pushint(st, 0);
		return false;
	}

	if (hBGqd->users < min) {
		ShowError("buildin_hBG_queue2teams: Less than minimum %d queue members received (%d).\n", min, (int) hBGqd->users);
		script_pushint(st, 0);
		return false;
	}
	// How many players are we going to take from the Queue
	limit = min(max * total_teams, hBGqd->users);

	switch (type) {
		case 0: // Lineal - Maybe to keep party together
		{
			t = 0;
			int i = 0;
			for (i = 0; i < limit; i++) {
				if ((i%(limit/total_teams)) == 0) // Switch Team
					bg_id = script_getnum(st,t+arg_offset);
				
				if (!hBGqd->first || (sd = hBGqd->first->sd) == NULL)
					break; // No more people to join Teams
				
				hBG_team_join(bg_id, sd);
				hBG_queue_member_remove(hBGqd, sd->bl.id);
				
				// Increment Team counter or break
				if (t++ >= total_teams)
					break;
			}
		}
			break;
		default:
		case 1: // Random
		{
			t = 0;
			int pos = 0, i=0;
			struct hBG_queue_member *qm;

			for (i=0; t < limit; i++) {
				if ((i%(limit/total_teams)) == 0) // Switch Team
					bg_id = script_getnum(st,t+arg_offset);

				pos = 1 + rand() % (limit - i);
				
				if ((qm = hBG_queue_member_get(hBGqd, pos)) == NULL || (sd = qm->sd) == NULL)
					break;

				hBG_team_join(bg_id, sd);
				hBG_queue_member_remove(hBGqd, sd->bl.id);
				
				// Increment Team Counter or break
				if (t++ >= total_teams)
					break;
			}
		}
			break;
	}

	script_pushint(st, 1);

	return true;
}

/**
 * Fill teams with members from the given Queue.
 * @param Queue ID
 * @param Max Players Per Team
 * @param Balanceing method
 * @param Team 1 ... Team 13
 */
BUILDIN(hBG_balance_teams)
{
	struct hBG_queue_data *hBGqd;
	struct hBG_queue_member *head;
	struct battleground_data *bgd, *p_bg;
	int i, c, q_id, bg_id, m_bg_id = 0, max, min, type;
	struct map_session_data *sd;
	bool balanced;

	q_id = script_getnum(st,2);

	if ((hBGqd = hBG_queue_search(q_id)) == NULL || hBGqd->users <= 0) {
		ShowError("buildin_hBG_balance_teams: Non existant Queue Id or the queue is empty.\n");
		script_pushint(st, 0);
		return false;
	}

	max = script_getnum(st,3);
	if (max > MAX_BG_MEMBERS)
		max = MAX_BG_MEMBERS;
	min = MAX_BG_MEMBERS + 1;
	type = script_getnum(st, 4);

	i = 5; // Team IDs to build
	
	while (script_hasdata(st, i) && i-5 < 13) {
		bg_id = script_getnum(st, i);
		if ((bgd = bg->team_search(bg_id)) == NULL) {
			ShowError("buildin_hBG_balance_teams: Non existant team id received %d.\n", bg_id);
			script_pushint(st, 0);
			return false;
		}

		if (bgd->count < min)
			min = bgd->count;
		i++;
	}

	c = i - 5; // Teams Found

	if (c < 2 || min >= max)
		return true; // No Balance Required

	if (type < 3) {
		while ((head = hBGqd->first) != NULL && (sd = head->sd) != NULL) {
			p_bg = NULL;
			balanced = true;
			min = MAX_BG_MEMBERS + 1;

			// Search the Current Minimum and Balance status
			for (i = 0; i < c; i++) {
				bg_id = script_getnum(st,i+5);
				
				if ((bgd = bg->team_search(bg_id)) == NULL)
					break; // Should not happen. Teams already check
				
				if (p_bg && p_bg->count != bgd->count)
					balanced = false; // Teams still with different member count

				if (bgd->count < min) {
					m_bg_id = bg_id;
					min = bgd->count;
				}
				p_bg = bgd;
			}

			if (min >= max) break; // Balance completed

			if (hBG_config_get("battle_configuration/hBG_balanced_queue") && balanced && hBGqd->users < c)
				break; // No required users on queue to keep balance

			hBG_team_join(m_bg_id, sd);
			hBG_queue_member_remove(hBGqd, sd->bl.id);

			if ((bgd = bg->team_search(m_bg_id)) != NULL && bgd->mapindex)
				pc->setpos(sd, bgd->mapindex, bgd->x, bgd->y, CLR_TELEPORT); // Joins and Warps
		}
	} else {
		ShowError("buildin_hBG_balance_teams: Invalid type %d given for argument #3.\n", type);
		script_pushint(st, 0);
		return false;
	}

	script_pushint(st, 1);

	return true;
}

/**
 * Waiting Room to Battleground Teams
 * @param Map Name
 * @param Map X
 * @param Map Y
 * @param BG Guild Index
 * @param Logout Event
 * @param Die Event
 */
BUILDIN(hBG_waitingroom2bg)
{
	struct npc_data *nd;
	struct chat_data *cd;
	const char *map_name, *ev = "", *dev = "";
	int x, y, i, m=0, guild_index, bg_id;
	struct map_session_data *sd;

	nd = (struct npc_data *)map->id2bl(st->oid);

	if (nd == NULL || (cd = (struct chat_data *)map->id2bl(nd->chat_id)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	map_name = script_getstr(st,2);

	if (strcmp(map_name, "-") != 0 && (m = mapindex->name2id(map_name)) == 0) {
		script_pushint(st, 0);
		return false;
	}

	x = script_getnum(st, 3);
	y = script_getnum(st, 4);
	guild_index = script_getnum(st, 5);
	ev = script_getstr(st, 6); // Logout Event
	dev = script_getstr(st, 7); // Die Event

	guild_index = cap_value(guild_index, 0, 12);

	if ((bg_id = hBG_create(m, x, y, guild_index, ev, dev)) == 0) { // Creation failed
		script_pushint(st, 0);
		return false;
	}

	for (i = 0; i < cd->users && i < MAX_BG_MEMBERS; i++) {
		if ((sd = cd->usersd[i]) != NULL && hBG_team_join(bg_id, sd))
			mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), sd->bl.id);
		else
			mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), 0);
	}

	mapreg->setreg(script->add_str("$@arenamembersnum"), i);

	script_pushint(st, bg_id);

	return true;
}

/**
 * Adds the first player from the given NPC's
 * waiting room to BG Team.
 * @param Battleground Id
 * @param Map Name
 * @param Map X
 * @param Map Y
 * @param NPC Name
 */
BUILDIN(hBG_waitingroom2bg_single)
{
	const char* map_name;
	struct npc_data *nd;
	struct chat_data *cd;
	struct map_session_data *sd;
	int x, y, m, bg_id;

	bg_id = script_getnum(st,2);
	map_name = script_getstr(st,3);

	if ((m = mapindex->name2id(map_name)) == 0) {
		script_pushint(st, 0);
		return false; // Invalid Map
	}

	x = script_getnum(st,4);
	y = script_getnum(st,5);
	nd = npc->name2id(script_getstr(st,6));

	if (nd == NULL || (cd = (struct chat_data *)map->id2bl(nd->chat_id)) == NULL || cd->users <= 0) {
		script_pushint(st, 0);
		return false;
	}

	if ((sd = cd->usersd[0]) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	if (hBG_team_join(bg_id, sd)) {
		pc->setpos(sd, m, x, y, CLR_TELEPORT);
		script_pushint(st,1);
	} else {
		script_pushint(st,0);
	}

	return true;
}

/**
 * Set the Respawn Location of a BG team
 * @param Battleground Id
 * @param Map X
 * @param Map Y
 */
BUILDIN(hBG_team_setxy)
{
	struct battleground_data *bgd;
	int bg_id;

	bg_id = script_getnum(st,2);

	if ((bgd = bg->team_search(bg_id)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	bgd->x = script_getnum(st,3);
	bgd->y = script_getnum(st,4);

	script_pushint(st, 1);

	return true;
}

/**
 * Reveal the location of a BG Team on the minimap.
 * @param Battleground ID
 */
BUILDIN(hBG_team_reveal)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id;

	bg_id = script_getnum(st,2);

	if ((bgd = bg->team_search(bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	hBGd->reveal_pos = true; // Reveal Position Mode

	script_pushint(st, 1);

	return true;
}

/**
 * Conceal the location of a BG Team from the minimap.
 * @param Battleground ID
 */
BUILDIN(hBG_team_conceal)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	struct map_session_data *sd;
	int bg_id,i=0;

	bg_id = script_getnum(st,2);

	if ((bgd = bg->team_search(bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL)
			continue;

		hBG_send_dot_remove(sd);
	}

	hBGd->reveal_pos = false; // Conceal Position Mode

	script_pushint(st, 1);

	return true;
}

/**
 * Set Quest for a BG Team
 * @param Battleground ID
 * @param Quest ID
 */
BUILDIN(hBG_team_setquest)
{
	struct battleground_data *bgd;
	struct map_session_data *sd;
	int i, bg_id, qid;

	bg_id = script_getnum(st,2);
	qid = script_getnum(st,3);

	if (bg_id <= 0 || (bgd = bg->team_search(bg_id)) == NULL) {
		ShowError("buildin_hBG_team_setquest: Invalid Team ID %d given.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	if (qid <= 0 || quest->db(qid) == NULL) {
		ShowError("buildin_hBG_team_setquest: Invalid Quest ID %d given.\n", qid);
		script_pushint(st, 0);
		return false;
	}

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL)
			continue;

		quest->add(sd, qid, 0);
	}

	script_pushint(st, 1);

	return true;
}

/**
 * Set Viewpoint for a player.
 * @see hBG_viewpointmap
 */
int hBG_viewpointmap_sub(struct block_list *bl, va_list ap)
{
	struct map_session_data *sd;
	int npc_id, type, x, y, id, color;
	npc_id = va_arg(ap,int);
	type = va_arg(ap,int);
	x = va_arg(ap,int);
	y = va_arg(ap,int);
	id = va_arg(ap,int);
	color = va_arg(ap,int);
	sd = (struct map_session_data *)bl;

	clif->viewpoint(sd,npc_id,type,x,y,id,color);

	return 0;
}

/**
 * Set Viewpoint on minimap for a player.
 * @param Map Name
 * @param Type
 *         0 = display mark for 15 seconds
 *         1 = display mark until dead or teleported
 *         2 = remove mark
 * @param Map X
 * @param Map Y
 * @param ID (Unique ID of the viewpoint)
 * @param Color
 */
BUILDIN(hBG_viewpointmap)
{
	int type,x,y,id,color,m;
	const char *map_name;

	map_name = script_getstr(st,2);

	if ((m = map->mapname2mapid(map_name)) < 0) {
		script_pushint(st, 0);
		return false; // Invalid Map
	}

	type=script_getnum(st,3);
	x=script_getnum(st,4);
	y=script_getnum(st,5);
	id=script_getnum(st,6);
	color=script_getnum(st,7);

	map->foreachinmap(hBG_viewpointmap_sub,m,BL_PC,st->oid,type,x,y,id,color);

	script_pushint(st, 1);

	return true;
}

/**
 * Reveal a monster's location on minimap
 * @param Monster Id
 * @param Type
 *         0 = display mark for 15 seconds
 *         1 = display mark until dead or teleported
 *         2 = remove mark
 * @param Color
 */
BUILDIN(hBG_monster_reveal)
{
	struct block_list *mbl;
	int id = script_getnum(st,2),
	flag = script_getnum(st,3),
	color = script_getnum(st,4);

	if (id == 0 || (mbl = map->id2bl(id)) == NULL || mbl->type != BL_MOB) {
		script_pushint(st, 0);
		return false;
	}

	map->foreachinmap(hBG_viewpointmap_sub, mbl->m, BL_PC, st->oid, flag, mbl->x, mbl->y, mbl->id, color);

	script_pushint(st, 1);

	return true;
}

/**
 * Set monster as an ally to a BG Team.
 * @param Monster ID
 * @param Battleground ID
 */
BUILDIN(hBG_monster_set_team)
{
	struct mob_data *md;
	struct block_list *mbl;
	int id = script_getnum(st,2),
	bg_id = script_getnum(st,3);

	if (id == 0 || (mbl = map->id2bl(id)) == NULL || mbl->type != BL_MOB) {
		script_pushint(st, 0);
		return false;
	}

	md = (TBL_MOB *)mbl;
	md->bg_id = bg_id;

	mob_stop_attack(md);
	mob_stop_walking(md, 0);

	md->target_id = md->attacked_id = 0;

	clif->charnameack(0, &md->bl);

	script_pushint(st, 1);

	return true;
}

/**
 * Set immunity flag to a monster.
 * (making it immune to damage).
 * @param Monster ID
 * @param Flag (0 = Off | 1 = On)
 */
BUILDIN(hBG_monster_immunity)
{
	struct mob_data *md;
	struct block_list *mbl;
	struct hBG_mob_data *hBGmd;

	int id = script_getnum(st,2),
	flag = script_getnum(st,3);

	if (id == 0 || (mbl = map->id2bl(id)) == NULL || mbl->type != BL_MOB) {
		script_pushint(st, 0);
		return false;
	}

	md = (TBL_MOB *)mbl;

	if ((hBGmd = getFromMOBDATA(md, 0)) == NULL){
		CREATE(hBGmd, struct hBG_mob_data, 1);	
		addToMOBDATA(md, hBGmd, 0, true);
	}
	hBGmd->state.immunity = flag;

	return true;
}

/**
 * Leave a Battleground Team
 */
BUILDIN(hBG_leave)
{
	struct map_session_data *sd = script->rid2sd(st);

	if (sd == NULL || sd->bg_id == 0) {
		script_pushint(st, 0);
		return false;
	}

	bg->team_leave(sd,0);

	script_pushint(st, 1);

	return true;
}

/**
 * Finalize battlegrounds and remove
 * teams from the db.
 */
BUILDIN(hBG_destroy)
{
	int bg_id = script_getnum(st, 2);

	if (bg_id <= 0 || bg->team_search(bg_id) == NULL) {
		ShowError("buildin_hBG_destroy: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	hBG_team_finalize(bg_id, true);

	script_pushint(st, 1);

	return true;
}

/**
 * Clean Battlegrounds without removing
 * the teams from the db.
 */
BUILDIN(hBG_clean)
{
	int bg_id = script_getnum(st, 2);

	if (bg_id <= 0 || bg->team_search(bg_id) == NULL) {
		ShowError("buildin_hBG_clean: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	hBG_team_finalize(bg_id, false);

	script_pushint(st, 1);

	return true;
}

/**
 * Get user count within an area in a map.
 * @param Battleground ID
 * @param Map Name
 * @param X1
 * @param Y1
 * @param X2
 * @param Y2
 */
BUILDIN(hBG_getareausers)
{
	struct battleground_data *bgd = NULL;
	struct map_session_data *sd = NULL;
	const char *map_name;
	int m, x0, y0, x1, y1, bg_id;
	int i = 0, c = 0;

	bg_id = script_getnum(st,2);
	map_name = script_getstr(st,3);

	if ((bgd = bg->team_search(bg_id)) == NULL || (m = map->mapname2mapid(map_name)) < 0) {
		script_pushint(st,0);
		return false;
	}

	x0 = script_getnum(st,4);
	y0 = script_getnum(st,5);
	x1 = script_getnum(st,6);
	y1 = script_getnum(st,7);

	for (i = 0; i < MAX_BG_MEMBERS; i++) {
		if ((sd = bgd->members[i].sd) == NULL)
			continue;
		else if (sd->bl.m != m || sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1)
			continue;
		c++;
	}

	script_pushint(st, c);
	
	return true;
}

/**
 * Update the score on a battleground map.
 * @param Map Name
 * @param Lion Score
 * @param Eagle Score
 */
BUILDIN(hBG_updatescore)
{
	const char *map_name;
	int m;

	map_name = script_getstr(st,2);

	if ((m = map->mapname2mapid(map_name)) < 0) {
		script_pushint(st, 0);
		return false;
	}

	map->list[m].bgscore_lion = script_getnum(st,3);
	map->list[m].bgscore_eagle = script_getnum(st,4);

	clif->bg_updatescore(m);

	script_pushint(st, 1);

	return true;
}

/**
 * Update Score for a Battleground Team.
 * @param Battleground ID
 * @param Score
 */
BUILDIN(hBG_update_score_team)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id = script_getnum(st,2);
	int score = script_getnum(st,3);

	if (bg_id <= 0) {
		ShowError("buildin_hBG_update_score_team: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	if ((bgd = bg->team_search(bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	hBGd->team_score = score;
	hBG_update_score_team(bgd);

	script_pushint(st, 1);

	return true;
}

/**
 * Get a Team's Guild Index
 * @param Battleground ID
 * @return Guild Index
 */
BUILDIN(hBG_get_team_gid)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id = script_getnum(st,2), guild_id = 0;

	if (bg_id <= 0) {
		ShowError("buildin_hBG_get_team_gid: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	if ((bgd = bg->team_search(bg_id)) != NULL
		&& (hBGd = getFromBGDATA(bgd, 0)) != NULL)
		guild_id = hBGd->g->guild_id;

	script_pushint(st, guild_id);

	return true;
}

/**
 * Get data from a Battleground
 * @param Battleground ID
 * @param Type
 *         0 = User Count
 *         1 = Fill $@bgmembers$ array with user list and return user count.
 *         2 = BG Guild Name
 *         3 = BG Guild Master Name
 *         4 = BG Color
 */
BUILDIN(hBG_get_data)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id = script_getnum(st,2);
	int type = script_getnum(st,3);

	if (bg_id <= 0) {
		ShowError("buildin_hBG_get_data: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	if ((bgd = bg->team_search(bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL) {
		script_pushint(st, 0);
		return false;
	}

	switch (type)
	{
		case 0:
			script_pushint(st, bgd->count);
			break;
		case 1: // Users and List
		{
			int i, j = 0;
			struct map_session_data *sd;
			for (i = 0; i < bgd->count; i++) {
				if ((sd = bgd->members[i].sd) == NULL)
					continue;
				mapreg->setregstr(reference_uid(script->add_str("$@bgmembers$"),j),sd->status.name);
				j++;
			}
			script_pushint(st, j);
		}
			break;
		case 2:
			script_pushconststr(st,hBGd->g ? hBGd->g->name : "");
			break;
		case 3:
			script_pushconststr(st,hBGd->g ? hBGd->g->master : "");
			break;
		case 4:
			script_pushint(st,hBGd->color);
			break;

		default:
			ShowError("script:bg_get_data: unknown data identifier %d\n", type);
			break;
	}

	script_pushint(st, 0);

	return true;
}

/**
 * Battleground Get Item
 * @param Battleground ID
 * @param Item ID
 * @param Item Amount
 */
BUILDIN(hBG_getitem)
{
	int bg_id, nameid, amount;

	bg_id = script_getnum(st,2);
	nameid = script_getnum(st,3);
	amount = script_getnum(st,4);


	if (bg_id <= 0 || bg->team_search(bg_id) == NULL) {
		ShowError("buildin_hBG_getitem: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	} else if (nameid <= 0 || itemdb->exists(nameid) == NULL) {
		ShowError("buildin_hBG_getitem: Invalid Item Id %d provided.\n", nameid);
		script_pushint(st, 0);
		return false;
	} else if (amount <= 0) {
		ShowError("buildin_hBG_getitem: Invalid Item amount %d provided.\n", amount);
		script_pushint(st, 0);
		return false;
	}

	hBG_team_getitem(bg_id, nameid, amount);

	script_pushint(st, amount);

	return true;
}

/**
 * Battleground Get Kafra Points
 * @param Battleground ID
 * @param Amount of KP
 */
BUILDIN(hBG_getkafrapoints)
{
	int bg_id, amount;

	bg_id = script_getnum(st, 2);
	amount = script_getnum(st, 3);

	if (bg_id <= 0 || bg->team_search(bg_id) == NULL) {
		ShowError("buildin_hBG_getkafrapoints: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	} else if (amount <= 0) {
		ShowError("buildin_hBG_getkafrapoints: Invalid Kafra Points %d provided.\n", amount);
		script_pushint(st, 0);
		return false;
	}

	hBG_team_get_kafrapoints(bg_id, amount);

	script_pushint(st, amount);

	return true;
}

/**
 * Battleground get Rewards
 * @param Battleground ID
 * @param Item ID
 * @param Item Amount
 * @param Kafra Points
 * @param Quest ID
 * @param Custom Variable (#KAFRAPOINTS/#CASHPOINTS etc..)
 * @param Custom Variable Add Value
 * @param Battleground Arena (0 EoS | 1 Boss | 2 TI | 3 CTF | 4 TD | 5 SC | 6 CON | 7 RUSH | 8 DOM)
 * @param Battleground Result (0 Won | 1 Tie | 2 Lost)
 */
BUILDIN(hBG_reward)
{
	int bg_id, nameid, amount, kafrapoints, quest_id, add_value, bg_arena, bg_result;
	const char *var;

	bg_id = script_getnum(st,2);
	nameid = script_getnum(st,3);
	amount = script_getnum(st,4);
	kafrapoints = script_getnum(st,5);
	quest_id = script_getnum(st,6);
	var = script_getstr(st,7);
	add_value = script_getnum(st,8);
	bg_arena = script_getnum(st,9);
	bg_result = script_getnum(st,10);

	if (bg_id <= 0 || bg->team_search(bg_id) == NULL) {
		ShowError("buildin_hBG_reward: Invalid BG Id %d provided.\n", bg_id);
		script_pushint(st, 0);
		return false;
	}

	if (nameid <= 0 || itemdb->exists(nameid) == NULL) {
		ShowError("buildin_hBG_reward: Invalid Item Id %d provided.\n", nameid);
		script_pushint(st, 0);
		return false;
	}

	if (nameid > 0 && amount <= 0) {
		ShowError("buildin_hBG_reward: Invalid Item amount %d provided.\n", nameid);
		script_pushint(st, 0);
		return false;
	}

	if (kafrapoints < 0) {
		ShowError("buildin_hBG_reward: Invalid Kafra Points %d provided.\n", kafrapoints);
		script_pushint(st, 0);
		return false;
	}

	if (quest_id < 0 || quest->db(quest_id) == NULL) {
		ShowError("buildin_hBG_reward: Invalid Quest ID %d provided.\n", quest_id);
		script_pushint(st, 0);
		return false;
	}

	if (bg_arena < 0) {
		ShowError("buildin_hBG_reward: Invalid BG Arena %d provided. \n", bg_arena);
		script_pushint(st, 0);
		return false;
	}

	if (bg_result < 0 || bg_result > 2) {
		ShowError("buildin_hBG_reward: Invalid BG result type %d provided. (types - 0 Won | 1 Tie | 2 Lost)", bg_result);
		script_pushint(st, 0);
		return false;
	}

	hBG_team_rewards(bg_id, nameid, amount, kafrapoints, quest_id, var, add_value, bg_arena, bg_result);

	script_pushint(st, 1);

	return true;
}

/**
 * Add Item to XY co-ordinates on Floor.
 * @param Map Name
 * @param Map X
 * @param Map Y
 * @param Item ID
 * @param Item Amount
 */
BUILDIN(hBG_flooritem2xy)
{
	int nameid, amount, m, x, y;
	const char *mapname;
	
	mapname = script_getstr(st,2);
	
	if ((m = map->mapname2mapid(mapname)) < 0) {
		// error message is thrown through mapindex->name2id()
		script_pushint(st, 0);
		return false;
	}
	
	x = script_getnum(st,3);
	y = script_getnum(st,4);
	nameid = script_getnum(st,5);
	
	if (itemdb->search(nameid) == NULL) {
		ShowError("buildin_hBG_flooritem2xy: Invalid Item Id %d provided.\n", nameid);
		script_pushint(st, 0);
		return false;
	}
	
	amount = script_getnum(st,6);
	
	if (amount < 1) {
		ShowError("buildin_hBG_flooritem2xy: Invalid Item amount %d provided.\n", amount);
		script_pushint(st, 0);
		return false;
	}
	
	hBG_addflooritem_area(NULL, m, x, y, nameid, amount);

	script_pushint(st, amount);

	return true;
}
/**
 * Warps BG Team to destination or Respawn Point
 * @param BG Team
 * @param Map Name
 * @param Map X
 * @param Map Y
 */
BUILDIN(hBG_warp)
{
	int x, y, mapidx, bg_id;
	const char *map_name;

	bg_id = script_getnum(st,2);
	map_name = script_getstr(st,3);

	if (!strcmp(map_name,"RespawnPoint")) // Cemetery Zone
		mapidx = 0;
	else if ((mapidx = script->mapindexname2id(st,map_name)) == 0)
		return 0; // Invalid Map

	x = script_getnum(st,4);
	y = script_getnum(st,5);

	bg_id = hBG_team_warp(bg_id, mapidx, x, y);

	return true;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Map Server Function Pre-Hooks
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
 * NPC Pre-Hooks
 */
void npc_parse_unknown_mapflag_pre(const char **name, const char **w3, const char **w4, const char **start, const char **buffer, const char **filepath, int **retval)
{
	int16 m = map->mapname2mapid(*name);

	if (strcmpi(*w3, "hBG_topscore") == 0) {
		struct hBG_mapflag *hBG_mf;

		if ((hBG_mf = getFromMAPD(&map->list[m], 0)) == NULL) {
			CREATE(hBG_mf, struct hBG_mapflag, 1);
			hBG_mf->hBG_topscore = 1;
			addToMAPD(&map->list[m], hBG_mf, 0, true);
		}

		hBG_mf->hBG_topscore = 1;

		hookStop();
	}

	return;
}

/**
 * Clif Pre-Hooks
 */
void clif_charnameupdate_pre(struct map_session_data **sd)
{
	unsigned char buf[103];
	int cmd = 0x195, ps;
	struct battleground_data *bgd = bg->team_search((*sd)->bg_id);
	struct hBG_data *hBGd;

	nullpo_retv((*sd));

	if ((*sd)->fakename[0] || bgd == NULL ||
		(hBGd = getFromBGDATA(bgd, 0)) == NULL || hBGd->g == NULL)
		return; //No need to update as the guild was not displayed anyway.

	WBUFW(buf,0) = cmd;
	WBUFL(buf,2) = (*sd)->bl.id;
	memcpy(WBUFP(buf,6), (*sd)->status.name, NAME_LENGTH);
	WBUFB(buf,30) = 0;
	memcpy(WBUFP(buf,54), hBGd->g->name, NAME_LENGTH);
	
	ps = (hBGd->leader_char_id == (*sd)->status.char_id)?0:1;
	memcpy(WBUFP(buf,78), hBGd->g->position[ps].name, NAME_LENGTH);

	// Update nearby clients
	clif->send(buf, 102, &(*sd)->bl, AREA);

	hookStop();
}
//Prevent update Guild Info if you're in BG
void clif_parse_GuildRequestInfo_pre(int *fd, struct map_session_data **sd)
{
	if ((*sd) && (*sd)->bg_id)
		hookStop();
	return;
}

/**
 * Skill Pre-Hooks.
 */
int skill_check_condition_castbegin_pre(struct map_session_data **sd, uint16 *skill_id, uint16 *skill_lv)
{
	nullpo_ret(sd);
	
	if (map->list[(*sd)->bl.m].flag.battleground && (*skill_id >= GD_SKILLBASE && *skill_id <= GD_DEVELOPMENT))
		hookStop(); // Prevent original function from running after return from here.
	
	return 1;
}

int skillnotok_pre(uint16 *skill_id, struct map_session_data **sd)
{
	int16 idx, m;
	nullpo_retr(1, *sd);
	m = (*sd)->bl.m;
	idx = skill->get_index(*skill_id);
 
	if (map->list[m].flag.battleground && (*skill_id >= GD_SKILLBASE && *skill_id <= GD_DEVELOPMENT)) {
	
		if (pc_has_permission(*sd, PC_PERM_DISABLE_SKILL_USAGE)) {
			hookStop();
			return 1;
		}

		if (pc_has_permission(*sd, PC_PERM_SKILL_UNCONDITIONAL)) {
			hookStop();
			return 0; // can do any damn thing they want
		}

		if ((*sd)->blockskill[idx]) {
			clif->skill_fail((*sd), *skill_id, USESKILL_FAIL_SKILLINTERVAL, 0);
			hookStop();
			return 1;
		}
		hookStop();
	}
	return 0;
}

/**
 * Skill cast end.
 * @param src = source block list.
 * @param bl = target block list
 */
int skill_castend_nodamage_id_pre(struct block_list **src, struct block_list **bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag)
{
	struct map_session_data *sd, *dstsd;
	struct status_change *tsc;
	struct status_data *sstatus;
	struct hBG_map_session_data *hBGsd = NULL;
	
	nullpo_retr(1, bl);
	nullpo_retr(1, src);

	if (!map->list[(*src)->m].flag.battleground || *skill_id != GD_EMERGENCYCALL)
		return 0;
	
	sd = BL_CAST(BL_PC, *src);
	dstsd = BL_CAST(BL_PC, *bl);

	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return 0;

	tsc = status->get_sc(*bl);

	sstatus = status->get_status_data(*src);
	
	switch (*skill_id) {
		case GD_EMERGENCYCALL:
		{
			int dx[9]={-1, 1, 0, 0,-1, 1,-1, 1, 0};
			int dy[9]={ 0, 0, 1,-1, 1,-1,-1, 1, 0};
			int i = 0, j = 0;
			struct guild *g;
			
			// i don't know if it actually summons in a circle, but oh well. ;P
			if (sd && (g = hBG_get_guild(sd->bg_id)) != NULL) {
				clif->skill_nodamage(*src, *bl, *skill_id, *skill_lv, 1);
				
				for (i = 0; i < g->max_member; i++, j++) {
					if (j>8) j=0;
					if ((dstsd = g->member[i].sd) != NULL && sd != dstsd && !dstsd->state.autotrade && !pc_isdead(dstsd)) {
						if (map->getcell((*src)->m, *src, (*src)->x + dx[j], (*src)->y + dy[j], CELL_CHKNOREACH))
							dx[j] = dy[j] = 0;
						pc->setpos(dstsd, map_id2index((*src)->m), (*src)->x+dx[j], (*src)->y+dy[j], CLR_RESPAWN);
					}
				}
				guild->block_skill(sd, skill->get_time2(*skill_id, *skill_lv));
			}
		}
			break;
		case HLIF_HEAL:
		case AL_HEAL:
		{
			struct mob_data *dstmd = BL_UCAST(BL_MOB, *bl);
			int heal = skill->calc_heal(*src, *bl, *skill_id, *skill_lv, true);

			if (status->isimmune(*bl) || (dstmd && dstmd->class_ == MOBID_EMPELIUM))
				heal = 0;

			if (dstmd && mob_is_battleground(dstmd))
				heal = 1;

			if (sd && dstsd && sd->status.partner_id == dstsd->status.char_id && (sd->job&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0)
				heal = heal*2;

			if (tsc && tsc->count)
			{
				if (tsc->data[SC_KAITE] && !(sstatus->mode&MD_BOSS))
				{ //Bounce back heal
					if (src == bl)
						heal=0; //When you try to heal yourself under Kaite, the heal is voided.
					else {
						bl = src;
						dstsd = sd;
					}
				} else if (tsc->data[SC_BERSERK]) {
						heal = 0; //Needed so that it actually displays 0 when healing.
				}
			}

			if (sd && dstsd && heal > 0 && sd != dstsd)
			{
				if (map->list[(*src)->m].flag.battleground && sd->bg_id && dstsd->bg_id)
				{
					if (sd->bg_id == dstsd->bg_id)
						add2limit(hBGsd->stats.healing_done, heal, UINT_MAX);
					else
						add2limit(hBGsd->stats.wrong_healing_done, heal, UINT_MAX);
				}
			}
		}
			break;
	}
	
	hookStop();
	return 0;
}

/**
 * Status Pre-Hooks
 */
int status_get_guild_id_pre(const struct block_list **bl)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id;

	nullpo_ret((*bl));

	if ((*bl)->type == BL_PC
		&& (bg_id = bg->team_get_id((struct block_list *)*bl)) > 0
		&& (bgd = bg->team_search(bg_id)) != NULL
		&& (hBGd = getFromBGDATA(bgd, 0)) != NULL
		&& hBGd->g)
	{
		hookStop();
		return hBGd->g->guild_id;
	}

	return 0;
}

int status_get_emblem_id_pre(const struct block_list **bl)
{
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	int bg_id;
	
	nullpo_ret(bl);

	if ((*bl)->type == BL_PC
		&& (bg_id = bg->team_get_id((struct block_list *)(*bl))) > 0
		&& (bgd = bg->team_search(bg_id)) != NULL
		&& (hBGd = getFromBGDATA(bgd, 0)) != NULL && hBGd->g)
	{
		hookStop();
		return hBGd->g->emblem_id;
	}

	return 0;
}

/**
 * Guild Pre-Hooks
 */
// Check if guild is null and don't run BCT checks if true.
bool guild_isallied_pre(int *guild_id, int *guild_id2)
{
	struct guild *g = guild->search(*guild_id);
	
	if (g == NULL) {
		hookStop();
		return false;
	}
	
	return false;
}

/**
 * Unit Pre-Hooks
 */
int unit_free_pre(struct block_list **bl, clr_type *clrtype)
{
	nullpo_retr(0, (*bl));

	if ((*bl)->type == BL_PC) {
		struct map_session_data *sd = BL_UCAST(BL_PC, (*bl));
		struct hBG_queue_data *hBGqd = NULL;
		struct battleground_data *bgd = NULL;
		struct hBG_data *hBGd = NULL;
		struct hBG_map_session_data *hBGsd = NULL;

		if ((hBGqd = getFromMSD(sd, 0)) && hBG_queue_member_search(hBGqd, sd->bl.id))
			hBG_queue_member_remove(hBGqd, sd->bl.id);

		if (sd->bg_id != 0
			&& (bgd = bg->team_search(sd->bg_id)) != NULL
			&& (hBGd = getFromBGDATA(bgd, 0)) != NULL
			&& (hBGsd = getFromMSD(sd, 1)) != NULL) {
			bg->team_leave(sd, 1);
			hBGsd->stats.total_deserted++;
		}

		removeFromMSD(sd, 1);
	}

	return 0;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Map Server Function Post-Hooks
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Battle Post-Hooks
 */
void battle_consume_ammo(struct map_session_data *sd, int skill_id, int lv)
{
	int qty = 1;
	struct hBG_map_session_data *hBGsd = getFromMSD(sd, 1);

	if (battle->bc->arrow_decrement == 0 || hBGsd == NULL)
		return;

	if (skill)
		qty = max(1, skill->get_ammo_qty(skill_id, lv));

	if (sd->equip_index[EQI_AMMO] >= 0) {
		if (sd->bg_id && map->list[sd->bl.m].flag.battleground)
			add2limit(hBGsd->stats.ammo_used, qty, UINT_MAX);
	}
}

// Check target immunity
int battle_check_target_post(int retVal, struct block_list *src, struct block_list *target, int flag)
{
	if (retVal == 1 && target->type == BL_MOB) {
		struct mob_data *md = BL_UCAST(BL_MOB, target);
		struct hBG_mob_data *hBGmd = NULL;

		if (md == NULL || (hBGmd = getFromMOBDATA(md, 0)) == NULL)
			return retVal;

		if (hBGmd != NULL && hBGmd->state.immunity) {
			hookStop();
			return retVal;
		}
	}

	return retVal;
}

/**
 * Clif Post-Hooks
 */
void clif_parse_LoadEndAck_post(int fd, struct map_session_data *sd)
{
	clif->charnameupdate(sd);
	/* Display emblem on head of char [lucaslsb] */
	if (hBG_enabled && sd->state.changemap && map->list[sd->bl.m].flag.battleground)
		clif->map_type(sd, MAPTYPE_BATTLEFIELD);
	if (hBG_enabled && map->list[sd->bl.m].flag.battleground)
		clif->map_property(sd, MAPPROPERTY_AGITZONE);
	return;
}
//Send charname_update every time you see someone in BG
void clif_getareachar_unit_post(struct map_session_data *sd, struct block_list *bl)
{
	if (bl->type == BL_PC) {
		struct map_session_data *tsd = BL_CAST(BL_PC, bl);
		clif->charnameupdate(tsd);
		return;
	}
}
void clif_parse_UseSkillToId_post(int fd, struct map_session_data *sd)
{
	uint16 skill_id;
	/* uint16 skill_lv; */
	int target_id;
	const struct s_packet_db *packet = clif->packet(RFIFOW(fd,0));
	struct battleground_data *bgd;
	struct hBG_data *hBGd;
	
	if (!sd->bg_id)
		return;
	else if ((bgd = bg->team_search(sd->bg_id)) == NULL || (hBGd = getFromBGDATA(bgd, 0)) == NULL)
		return;

	/* skill_lv = RFIFOW(fd,packet->pos[0]); */
	skill_id = RFIFOW(fd,packet->pos[1]);
	target_id = RFIFOL(fd,packet->pos[2]);
	
	if (skill_id >= GD_SKILLBASE && skill_id < GD_MAX && hBGd->leader_char_id == sd->status.char_id)
			unit->skilluse_id(&sd->bl, target_id, skill_id, guild->checkskill(hBG_get_guild(sd->bg_id), skill_id));
}

/**
 * Server tells 'sd' player client the abouts of 'dstsd' player
 */
void clif_getareachar_pc_post(struct map_session_data *sd,struct map_session_data *dstsd)
{
	if (sd->bg_id && dstsd->bg_id && sd->bg_id == dstsd->bg_id)
			clif->hpmeter_single(sd->fd, dstsd->bl.id, dstsd->battle_status.hp, dstsd->battle_status.max_hp);
}

/**
 * PC Post hooks
 */
void pc_update_idle_time_post(struct map_session_data* sd, enum e_battle_config_idletime type)
{
	struct hBG_map_session_data *hBGsd = NULL;
	struct battleground_data *bgd = bg->team_search(sd->bg_id);
	struct hBG_data *hBGd = NULL;
	
	nullpo_retv(sd);
	
	if (bgd && (hBGd = getFromBGDATA(bgd, 0)) && (hBGsd = getFromMSD(sd, 1)) && hBGsd->state.afk) {
		char output[256];
		/* Reset AFK status */
		sprintf(output, "%s : %s is no longer AFK.", sd->status.name, hBGd->g->name);
		hBG_send_chat_message(bgd, sd->bl.id, sd->status.name, output, (int)strlen(output) + 1);
		hBGsd->state.afk = 0;
	}
}

bool pc_authok_post(bool ret, struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, const struct mmo_charstatus *st, bool changing_mapservers)
{
	if (sd) {
		WFIFOHEAD(chrif->fd, 14);
		WFIFOW(chrif->fd, 0) = PACKET_INTER_BG_STATS_REQ;
		WFIFOL(chrif->fd, 2) = sd->status.account_id;
		WFIFOL(chrif->fd, 6) = sd->status.char_id;
		WFIFOL(chrif->fd, 10) = sd->fd;
		WFIFOSET(chrif->fd, 14);
	}
	
	return ret;
}

/**
 * Character Interface Post-Hooks
 */
/**
 * Requests saving of hBG Statistics and sends data to char-server.
 *
 * @param sd pointer to map session data.
 * @param flag as an indicator to tell char-server if character is quitting.
 * @return boolean.
 */
bool chrif_save_post(bool ret, struct map_session_data *sd, int flag)
{
	struct hBG_map_session_data *hBGsd = NULL;
	int len = 13 + sizeof(struct hBG_stats);
	
	nullpo_retr(false, sd);
	
	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return ret;

	if (flag == 1) // Logout from BG! Do not save anything.
		return ret;

	WFIFOHEAD(chrif->fd, len);
	WFIFOW(chrif->fd, 0) = PACKET_INTER_BG_STATS_SAVE; // 0x9000 Packet ID
	WFIFOL(chrif->fd, 2) = sd->status.account_id; // Account Id
	WFIFOL(chrif->fd, 6) = sd->status.char_id; // Char Id
	WFIFOB(chrif->fd, 12) = (flag==1); //Flag to tell char-server this character is quitting.
	memcpy(WFIFOP(chrif->fd, 13), &hBGsd->stats, sizeof(struct hBG_stats)); // hBG statistics.
	WFIFOSET(chrif->fd, len);
	
	return ret;
}

/**
 * Status Post Hooks
 */
int status_damage_post(int ret, struct block_list *src, struct block_list *target,int64 in_hp, int64 in_sp, int walkdelay, int flag)
{
	struct map_session_data *sd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;

	nullpo_retr(ret, target);

	if (src == NULL)
		return ret;

	if (src->type != BL_PC || (sd = BL_UCAST(BL_PC, src)) == NULL)
		return ret;
	if (map->list[src->m].flag.battleground == 0)
		return ret;
	if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return ret;

	hBG_record_damage(src, target, (int) in_hp);

	return ret;
}

/**
 * Receives and allocates map session data with bg statistics
 * from char-server.
 *
 * @param fd as socket descriptor handle
 */
void hBG_statistics_parsefromchar(int fd)
{
	struct map_session_data *sd = NULL;
	struct hBG_map_session_data *hBGsd = NULL;
	struct hBG_stats *stats = NULL;
	/* int account_id = RFIFOL(fd, 2), char_id = RFIFOL(fd, 6); */
 	int char_fd = RFIFOL(fd,10);
	
	nullpo_retv(sockt->session[char_fd]);

	if ((sd = sockt->session[char_fd]->session_data) == NULL)
		return;

	if ((hBGsd = getFromMSD(sd, 1)) == NULL) {
		CREATE(hBGsd, struct hBG_map_session_data, 1);
		addToMSD(sd, hBGsd, 1, false);
	}
	
	if ((stats = getFromSession(sockt->session[fd], 0)) == NULL)
		memcpy(&hBGsd->stats, RFIFOP(fd, 14), sizeof(struct hBG_stats));
	else
		memcpy(&hBGsd->stats, stats, sizeof(struct hBG_stats));
}

/**
* Battleground Interface Overload [lucaslsb]
*/

/**
 * Remove a player from a team.
 * @param sd pointer to session data.
 * @param flag type of leave.
 * @return Amount of player in the BG or 0 on failure.
 */
int bg_team_leave_overload(struct map_session_data *sd, enum bg_team_leave_type flag)
{ // Single Player leaves team
	int i;
	struct battleground_data *bgd;
	struct hBG_map_session_data *hBGsd;
	struct hBG_data *hBGd;
	struct map_session_data *pl_sd;
	struct guild *g;

	nullpo_ret(sd);
	
	if (!sd->bg_id)
		return 0;
	else if ((hBGsd = getFromMSD(sd, 1)) == NULL)
		return 0;
	else if ((bgd = bg->team_search(sd->bg_id)) == NULL)
		return 0;
	else if ((hBGd = getFromBGDATA(bgd, 0)) == NULL)
		return 0;

	// Packets
	hBG_send_dot_remove(sd);
	
	// Reset information.
	sd->bg_id = 0;
	hBGsd->bg_kills = 0;
	
	// Remove battleground items if any.
	hBG_member_remove_bg_items(sd);

	// Remove Guild Skill Buffs
	status_change_end(&sd->bl, SC_GUILDAURA, INVALID_TIMER);
	status_change_end(&sd->bl, SC_GDSKILL_BATTLEORDER, INVALID_TIMER);
	status_change_end(&sd->bl, SC_GDSKILL_REGENERATION, INVALID_TIMER);

	// Refresh Guild Information
	if (sd->status.guild_id && (g = guild->search(sd->status.guild_id)) != NULL) {
		clif->guild_belonginfo(sd, g);
		clif->guild_basicinfo(sd);
		clif->guild_allianceinfo(sd);
		clif->guild_memberlist(sd);
		clif->guild_skillinfo(sd);
		clif->guild_emblem(sd, g);
	} else {
		hBG_send_leave_single(sd, sd->status.name, "Leaving Battle...");
	}

	clif->charnameupdate(sd);
	clif->guild_emblem_area(&sd->bl);

	ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd == sd);

	if (i < MAX_BG_MEMBERS) // Removes member from BG
		memset(&bgd->members[i], 0, sizeof(struct battleground_member_data));
	
	ARR_FIND(0, MAX_BG_MEMBERS, i, hBGd->g->member[i].sd == sd);
	
	if (i < MAX_BG_MEMBERS) // removes member from BG Guild
		memset(&hBGd->g->member[i].sd, 0, sizeof(hBGd->g->member[i].sd));
	
	if (hBGd->leader_char_id == sd->status.char_id)
		hBGd->leader_char_id = 0;
	
	if (--bgd->count > 0) {
		for (i = 0; i < MAX_BG_MEMBERS; i++) { // Update other BG members
			if ((pl_sd = bgd->members[i].sd) == NULL)
				continue;
			
			if (!hBGd->leader_char_id) { // Set new Leader first on the list
				hBGd->leader_char_id = pl_sd->status.char_id;
				clif->charnameupdate(pl_sd);
			}
			
			switch (flag) {
				case 3: hBG_send_expulsion(pl_sd, sd->status.name, "Kicked by AFK Status..."); break;
				case 2: hBG_send_expulsion(pl_sd, sd->status.name, "Kicked by AFK Report..."); break;
				case 1: hBG_send_expulsion(pl_sd, sd->status.name, "User has quit the game..."); break;
				case 0: hBG_send_leave_single(pl_sd, sd->status.name, "Leaving Battle..."); break;
			}
			
			hBG_guild_window_info(pl_sd);
			hBG_send_emblem(pl_sd, hBGd->g);
			hBG_send_guild_member_list(pl_sd);
		}
	}

	if (bgd && strlen(bgd->logout_event) && flag)
		npc->event(sd, bgd->logout_event, 0);
	
	return bgd->count;
}

/**
* Clif Interface Overload [lucaslsb]
*/
void clif_sendbgemblem_area_overload(struct map_session_data *sd)
{
	int cmd = 0x2dd;
	const struct s_packet_db *packet = clif->packet(cmd);
	unsigned char buf[33];
	nullpo_retv(sd);
	if (hBG_enabled)
		return; // Prevents display of conventional emblems
	WBUFW(buf, 0) = cmd;
	WBUFL(buf, 2) = sd->bl.id;
	safestrncpy((char*)WBUFP(buf, 6), sd->status.name, NAME_LENGTH); // name don't show in screen.
	WBUFW(buf, 30) = sd->bg_id;
	clif->send(buf, packet->len, &sd->bl, AREA);
}

void clif_sendbgemblem_single_overload(int fd, struct map_session_data *sd)
{
	int cmd = 0x2dd;
	const struct s_packet_db *packet = clif->packet(cmd);
	nullpo_retv(sd);
	if (hBG_enabled)
		return; // Prevents display of conventional emblems
	WFIFOHEAD(fd, 32);
	WFIFOW(fd, 0) = cmd;
	WFIFOL(fd, 2) = sd->bl.id;
	safestrncpy(WFIFOP(fd, 6), sd->status.name, NAME_LENGTH);
	WFIFOW(fd, 30) = sd->bg_id;
	WFIFOSET(fd, packet->len);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Char Server Functions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
 * Character Server Saving of hBG Statistics
 *
 * @param fd socket descriptor handle
 */
void char_bgstats_tosql(int fd)
{
	struct hBG_stats pstats = {0}, *stats = NULL;
	int account_id = 0, char_id = 0;
	/* int flag = 0; */
	
	nullpo_retv(sockt->session[fd]);
	
	account_id = RFIFOL(fd, 2);
	char_id = RFIFOL(fd, 6);
	/* flag = RFIFOB(fd, 12); */
	
	if ((stats = getFromSession(sockt->session[fd], 0)) == NULL) {
		CREATE(stats, struct hBG_stats, 1);
		addToSession(sockt->session[fd], stats, 0, true);
	}
	
	memcpy(&pstats, RFIFOP(fd, 13), sizeof(struct hBG_stats));
	
	if (memcmp(stats, &pstats, sizeof(struct hBG_stats))) {
		if (SQL_ERROR == SQL->Query(inter->sql_handle,
			"REPLACE INTO `char_bg_stats` ("
			"`char_id`, "
			"`best_damage`, `total_damage_done`, `total_damage_received`, "
			"`ti_wins`, `ti_lost`, `ti_tie`, "
			"`eos_flags`, `eos_bases`, `eos_wins`, `eos_lost`, `eos_tie`, "
			"`boss_killed`, `boss_damage`, `boss_flags`, `boss_wins`, `boss_lost`, `boss_tie`, "
			"`dom_bases`, `dom_off_kills`, `dom_def_kills`, `dom_wins`, `dom_lost`, `dom_tie`, "
			"`td_kills`, `td_deaths`, `td_wins`, `td_lost`, `td_tie`, "
			"`sc_stolen`, `sc_captured`, `sc_dropped`, `sc_wins`, `sc_lost`, `sc_tie`, "
			"`ctf_taken`, `ctf_captured`, `ctf_dropped`, `ctf_wins`, `ctf_lost`, `ctf_tie`, "
			"`emperium_kills`, `barricade_kills`, `guardian_stone_kills`, `conquest_wins`, `conquest_losses`, "
			"`ru_captures`, `ru_wins`, `ru_lost`, `ru_skulls`,"
			"`kill_count`, `death_count`, `wins`, `losses`, `ties`, `wins_as_leader`, `losses_as_leader`, `ties_as_leader`, `total_deserted`, `score`, `points`, `ranked_points`, `ranked_games`,"
			"`sp_heal_potions`, `hp_heal_potions`, `yellow_gemstones`, `red_gemstones`, `blue_gemstones`, `poison_bottles`, `acid_demostration`, `acid_demostration_fail`, "
			"`support_skills_used`, `healing_done`, `wrong_support_skills_used`, `wrong_healing_done`, "
			"`sp_used`, `zeny_used`, `spiritb_used`, `ammo_used`)"
			" VALUES "
			"('%d',"
			"'%d','%u','%u',"
			"'%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d',"
			"'%u','%d','%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d','%d',"
			"'%d','%d','%d','%d','%d',"
			"'%d','%d','%d',"
			"'%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d',"
			"'%u','%u','%u','%u','%u','%u','%u','%u',"
			"'%u','%u','%u','%u',"
			"'%u','%u','%u','%u')",
			char_id,
			pstats.best_damage, pstats.total_damage_done, pstats.total_damage_received,
			pstats.ti_wins,pstats.ti_lost,pstats.ti_tie,
			pstats.eos_flags,pstats.eos_bases,pstats.eos_wins,pstats.eos_lost,pstats.eos_tie,
			pstats.boss_killed,pstats.boss_damage,pstats.boss_flags,pstats.boss_wins,pstats.boss_lost,pstats.boss_tie,
			pstats.dom_bases,pstats.dom_off_kills,pstats.dom_def_kills,pstats.dom_wins,pstats.dom_lost,pstats.dom_tie,
			pstats.td_kills,pstats.td_deaths,pstats.td_wins,pstats.td_lost,pstats.td_tie,
			pstats.sc_stolen,pstats.sc_captured,pstats.sc_dropped,pstats.sc_wins,pstats.sc_lost,pstats.sc_tie,
			pstats.ctf_taken,pstats.ctf_captured,pstats.ctf_dropped,pstats.ctf_wins,pstats.ctf_lost,pstats.ctf_tie,
			pstats.emperium_kills,pstats.barricade_kills,pstats.guardian_stone_kills,pstats.conquest_wins,pstats.conquest_losses,
			pstats.ru_captures,pstats.ru_wins,pstats.ru_lost, pstats.ru_skulls,
			pstats.kill_count,pstats.death_count,pstats.wins,pstats.losses,pstats.ties,pstats.wins_as_leader,pstats.losses_as_leader,
			pstats.ties_as_leader,pstats.total_deserted,pstats.score,pstats.points,pstats.ranked_points,pstats.ranked_games,
			pstats.sp_heal_potions, pstats.hp_heal_potions, pstats.yellow_gemstones, pstats.red_gemstones,
			pstats.blue_gemstones, pstats.poison_bottles, pstats.acid_demostration, pstats.acid_demostration_fail,
			pstats.support_skills_used, pstats.healing_done, pstats.wrong_support_skills_used, pstats.wrong_healing_done,
			pstats.sp_used, pstats.zeny_used, pstats.spiritb_used, pstats.ammo_used))
		{
			Sql_ShowDebug(inter->sql_handle);
		} else {
			memcpy(stats, &pstats, sizeof(struct hBG_stats));
			ShowInfo("Saved char (AID/CID: %d/%d) - BG Statistics [by Smokexyz].\n", account_id, char_id);
		}
	}
}

void char_bgstats_fromsql(int fd)
{
	struct hBG_stats temp_stats = { 0 }, *stats = NULL;
	int account_id = 0, char_id = 0, char_fd = 0, len = 0;
	struct SqlStmt *stmt = SQL->StmtMalloc(inter->sql_handle);

	if (stmt == NULL) {
		SqlStmt_ShowDebug(stmt);
		return;
	}
	
	account_id = RFIFOL(fd,2);
	char_id = RFIFOL(fd, 6);
	char_fd = RFIFOL(fd, 10);
	
	if (SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT "
		"`best_damage`,`total_damage_done`,`total_damage_received`,`ru_skulls`,`ti_wins`,`ti_lost`,`ti_tie`,`eos_flags`,`eos_bases`,`eos_wins`," // 0-9
		"`eos_lost`,`eos_tie`,`boss_killed`,`boss_damage`,`boss_flags`,`boss_wins`,`boss_lost`,`boss_tie`,`td_kills`,`td_deaths`," //10-19
		"`td_wins`,`td_lost`,`td_tie`,`sc_stolen`,`sc_captured`,`sc_dropped`,`sc_wins`,`sc_lost`,`sc_tie`,`ctf_taken`," //20-29
		"`ctf_captured`,`ctf_dropped`,`ctf_wins`,`ctf_lost`,`ctf_tie`,`emperium_kills`,`barricade_kills`,`guardian_stone_kills`,`conquest_wins`,`conquest_losses`,"//30-39
		"`kill_count`,`death_count`,`wins`,`losses`,`ties`,`wins_as_leader`,`losses_as_leader`,`ties_as_leader`,`total_deserted`,`score`,"//40-49
		"`points`,`sp_heal_potions`,`hp_heal_potions`,`yellow_gemstones`,`red_gemstones`,`blue_gemstones`,`poison_bottles`,`acid_demostration`,`acid_demostration_fail`,`support_skills_used`,"//50-59
		"`healing_done`,`wrong_support_skills_used`,`wrong_healing_done`,`sp_used`,`zeny_used`,`spiritb_used`,`ammo_used`,`ranked_points`,`ranked_games`,`ru_wins`,"//60-69
		"`ru_lost`,`ru_captures`,`dom_bases`,`dom_off_kills`,`dom_def_kills`,`dom_wins`,`dom_lost`,`dom_tie`"//70-79
		" FROM `char_bg_stats` WHERE `char_id` = ?")
		|| SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, sizeof char_id)
		|| SQL_ERROR == SQL->StmtExecute(stmt)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_UINT, &temp_stats.best_damage, sizeof temp_stats.best_damage, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_UINT, &temp_stats.total_damage_done, sizeof temp_stats.total_damage_done, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_UINT, &temp_stats.total_damage_received, sizeof temp_stats.total_damage_received, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &temp_stats.ru_skulls, sizeof temp_stats.ru_skulls, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_USHORT, &temp_stats.ti_wins, sizeof temp_stats.ti_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_USHORT, &temp_stats.ti_lost, sizeof temp_stats.ti_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_USHORT, &temp_stats.ti_tie, sizeof temp_stats.ti_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_USHORT, &temp_stats.eos_flags, sizeof temp_stats.eos_flags, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_USHORT, &temp_stats.eos_bases, sizeof temp_stats.eos_bases, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_USHORT, &temp_stats.eos_wins, sizeof temp_stats.eos_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 10, SQLDT_USHORT, &temp_stats.eos_lost, sizeof temp_stats.eos_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 11, SQLDT_USHORT, &temp_stats.eos_tie, sizeof temp_stats.eos_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 12, SQLDT_USHORT, &temp_stats.boss_killed, sizeof temp_stats.boss_killed, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 13, SQLDT_UINT, &temp_stats.boss_damage, sizeof temp_stats.boss_damage, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 14, SQLDT_USHORT, &temp_stats.boss_flags, sizeof temp_stats.boss_flags, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 15, SQLDT_USHORT, &temp_stats.boss_wins, sizeof temp_stats.boss_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 16, SQLDT_USHORT, &temp_stats.boss_lost, sizeof temp_stats.boss_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 17, SQLDT_USHORT, &temp_stats.boss_tie, sizeof temp_stats.boss_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 18, SQLDT_USHORT, &temp_stats.td_kills, sizeof temp_stats.td_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 19, SQLDT_USHORT, &temp_stats.td_deaths, sizeof temp_stats.td_deaths, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 20, SQLDT_USHORT, &temp_stats.td_wins, sizeof temp_stats.td_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 21, SQLDT_USHORT, &temp_stats.td_lost, sizeof temp_stats.td_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 22, SQLDT_USHORT, &temp_stats.td_tie, sizeof temp_stats.td_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 23, SQLDT_USHORT, &temp_stats.sc_stolen, sizeof temp_stats.sc_stolen, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 24, SQLDT_USHORT, &temp_stats.sc_captured, sizeof temp_stats.sc_captured, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 25, SQLDT_USHORT, &temp_stats.sc_dropped, sizeof temp_stats.sc_dropped, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 26, SQLDT_USHORT, &temp_stats.sc_wins, sizeof temp_stats.sc_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 27, SQLDT_USHORT, &temp_stats.sc_lost, sizeof temp_stats.sc_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 28, SQLDT_USHORT, &temp_stats.sc_tie, sizeof temp_stats.sc_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 29, SQLDT_USHORT, &temp_stats.ctf_taken, sizeof temp_stats.ctf_taken, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 30, SQLDT_USHORT, &temp_stats.ctf_captured, sizeof temp_stats.ctf_captured, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 31, SQLDT_USHORT, &temp_stats.ctf_dropped, sizeof temp_stats.ctf_dropped, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 32, SQLDT_USHORT, &temp_stats.ctf_wins, sizeof temp_stats.ctf_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 33, SQLDT_USHORT, &temp_stats.ctf_lost, sizeof temp_stats.ctf_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 34, SQLDT_USHORT, &temp_stats.ctf_tie, sizeof temp_stats.ctf_tie, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 35, SQLDT_USHORT, &temp_stats.emperium_kills, sizeof temp_stats.emperium_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 36, SQLDT_USHORT, &temp_stats.barricade_kills, sizeof temp_stats.barricade_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 37, SQLDT_USHORT, &temp_stats.guardian_stone_kills, sizeof temp_stats.guardian_stone_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 38, SQLDT_USHORT, &temp_stats.conquest_wins, sizeof temp_stats.conquest_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 39, SQLDT_USHORT, &temp_stats.conquest_losses, sizeof temp_stats.conquest_losses, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 40, SQLDT_USHORT, &temp_stats.kill_count, sizeof temp_stats.kill_count, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 41, SQLDT_USHORT, &temp_stats.death_count, sizeof temp_stats.death_count, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 42, SQLDT_USHORT, &temp_stats.wins, sizeof temp_stats.wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 43, SQLDT_USHORT, &temp_stats.losses, sizeof temp_stats.losses, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 44, SQLDT_USHORT, &temp_stats.ties, sizeof temp_stats.ties, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 45, SQLDT_USHORT, &temp_stats.wins_as_leader, sizeof temp_stats.wins_as_leader, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 46, SQLDT_USHORT, &temp_stats.losses_as_leader, sizeof temp_stats.losses_as_leader, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 47, SQLDT_USHORT, &temp_stats.ties_as_leader, sizeof temp_stats.ties_as_leader, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 48, SQLDT_USHORT, &temp_stats.total_deserted, sizeof temp_stats.total_deserted, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 49, SQLDT_INT, &temp_stats.score, sizeof temp_stats.score, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 50, SQLDT_INT, &temp_stats.points, sizeof temp_stats.points, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 51, SQLDT_UINT, &temp_stats.sp_heal_potions, sizeof temp_stats.sp_heal_potions, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 52, SQLDT_UINT, &temp_stats.hp_heal_potions, sizeof temp_stats.hp_heal_potions, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 53, SQLDT_UINT, &temp_stats.yellow_gemstones, sizeof temp_stats.yellow_gemstones, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 54, SQLDT_UINT, &temp_stats.red_gemstones, sizeof temp_stats.red_gemstones, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 55, SQLDT_UINT, &temp_stats.blue_gemstones, sizeof temp_stats.blue_gemstones, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 56, SQLDT_UINT, &temp_stats.poison_bottles, sizeof temp_stats.poison_bottles, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 57, SQLDT_UINT, &temp_stats.acid_demostration, sizeof temp_stats.acid_demostration, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 58, SQLDT_UINT, &temp_stats.acid_demostration_fail, sizeof temp_stats.acid_demostration_fail, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 59, SQLDT_UINT, &temp_stats.support_skills_used, sizeof temp_stats.support_skills_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 60, SQLDT_UINT, &temp_stats.healing_done, sizeof temp_stats.healing_done, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 61, SQLDT_UINT, &temp_stats.wrong_support_skills_used, sizeof temp_stats.wrong_support_skills_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 62, SQLDT_UINT, &temp_stats.wrong_healing_done, sizeof temp_stats.wrong_healing_done, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 63, SQLDT_UINT, &temp_stats.sp_used, sizeof temp_stats.sp_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 64, SQLDT_UINT, &temp_stats.zeny_used, sizeof temp_stats.zeny_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 65, SQLDT_UINT, &temp_stats.spiritb_used, sizeof temp_stats.spiritb_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 66, SQLDT_UINT, &temp_stats.ammo_used, sizeof temp_stats.ammo_used, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 67, SQLDT_UINT, &temp_stats.ranked_points, sizeof temp_stats.ranked_points, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 68, SQLDT_USHORT, &temp_stats.ranked_games, sizeof temp_stats.ranked_games, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 69, SQLDT_USHORT, &temp_stats.ru_wins, sizeof temp_stats.ru_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 70, SQLDT_USHORT, &temp_stats.ru_lost, sizeof temp_stats.ru_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 71, SQLDT_USHORT, &temp_stats.ru_captures, sizeof temp_stats.ru_captures, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 72, SQLDT_USHORT, &temp_stats.dom_bases, sizeof temp_stats.dom_bases, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 73, SQLDT_USHORT, &temp_stats.dom_off_kills, sizeof temp_stats.dom_off_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 74, SQLDT_USHORT, &temp_stats.dom_def_kills, sizeof temp_stats.dom_def_kills, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 75, SQLDT_USHORT, &temp_stats.dom_wins, sizeof temp_stats.dom_wins, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 76, SQLDT_USHORT, &temp_stats.dom_lost, sizeof temp_stats.dom_lost, NULL, NULL)
		|| SQL_ERROR == SQL->StmtBindColumn(stmt, 77, SQLDT_USHORT, &temp_stats.dom_tie, sizeof temp_stats.dom_tie, NULL, NULL)
		|| SQL_SUCCESS != SQL->StmtNextRow(stmt))
	{
		temp_stats.score = 2000;
	}
	
	ShowInfo("Loaded char (AID/CID: %d/%d) - BG Statistics [by Smokexyz]\n", account_id, char_id);
	
	if ((stats = getFromSession(sockt->session[fd], 0)) == NULL) {
		CREATE(stats, struct hBG_stats, 1);
		memcpy(stats, &temp_stats, sizeof(struct hBG_stats));
		addToSession(sockt->session[fd], stats, 0, true);
	} else if (memcmp(stats, &temp_stats, sizeof(struct hBG_stats))) {
		memcpy(stats, &temp_stats, sizeof(struct hBG_stats));
	}

	SQL->StmtFree(stmt);

	len = 14 + sizeof(struct hBG_stats);
	WFIFOHEAD(fd, len);
	WFIFOW(fd, 0) = PACKET_MAP_BG_STATS_GET;
	WFIFOL(fd, 2) = account_id;
	WFIFOL(fd, 6) = char_id;
	WFIFOL(fd, 10) = char_fd;
	memcpy(WFIFOP(fd, 14), &temp_stats, sizeof(struct hBG_stats));
	WFIFOSET(fd, len);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                     Battle Configuration Parsing                    *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void hBG_config_read(const char *key, const char *val)
{
	int value = config_switch (val);

	if (strcmpi(key,"battle_configuration/hBG_enabled") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_enabled, defaulting to 0.\n", value);
			return;
		}
		hBG_enabled = value;
	} else if (strcmpi(key, "battle_configuration/hBG_from_town_only") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_from_town_only, defaulting to 0.\n", value);
			return;
		}
		hBG_from_town_only = value;
	} else if (strcmpi(key, "battle_configuration/hBG_ip_check") == 0) {
		if (value < 0) {
			ShowWarning("Received Invalid Setting %d for hBG_ip_check, defaulting to 0.\n", value);
			return;
		}
		hBG_ip_check = value;
	} else if (strcmpi(key, "battle_configuration/hBG_idle_announce") == 0) {
		if (value < 0) {
			ShowWarning("Received Invalid Setting %d for hBG_idle_announce, defaulting to 60 seconds.\n", value);
			hBG_idle_announce = 60;
		} else {
			hBG_idle_announce = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_idle_autokick") == 0) {
		if (value < 0) {
			ShowWarning("Received Invalid Setting %d for hBG_idle_autokick, defaulting to 5 minutes (300s).\n", value);
			hBG_idle_autokick = 300;
		} else {
			hBG_idle_autokick = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_reportafk_leaderonly") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_reportafk_leaderonly, defaulting to 0.\n", value);
			hBG_reportafk_leaderonly = 0;
		} else {
			hBG_reportafk_leaderonly = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_balanced_queue") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_balanced_queue, defaulting to 0.\n", value);
			return;
		}
		hBG_balanced_queue = value;
	} else if (strcmpi(key, "battle_configuration/hBG_reward_rates") == 0) {
		if (value < 0) {
			ShowWarning("Received invalid setting %d for hBG_reward_rates, defaulting to 100.\n", value);
			hBG_reward_rates = 100;
		} else {
			hBG_reward_rates = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_xy_interval") == 0) {
		if (value < 1000) {
			ShowWarning("Received Invalid Setting %d for hBG_xy_interval. (min: %d, max: %d) Defaulting to 1000ms. \n", value, 1000, INT_MAX);
			hBG_xy_interval = 1000;
		} else {
			hBG_xy_interval = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_ranked_mode") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_ranked_mode, defaulting to 0.\n", value);
			hBG_ranked_mode = 0;
		} else {
			hBG_ranked_mode = value;
		}
	} else if (strcmpi(key, "battle_configuration/hBG_leader_change") == 0) {
		if (value < 0 || value > 1) {
			ShowWarning("Received Invalid Setting %d for hBG_leader_change, defaulting to 0.\n", value);
			hBG_leader_change = 0;
		} else {
			hBG_leader_change = value;
		}
	}
}

int hBG_config_get(const char *key)
{
	if (strcmpi(key, "battle_configuration/hBG_enabled") == 0)
		return hBG_enabled;
	else if (strcmpi(key, "battle_configuration/hBG_from_town_only") == 0)
		return hBG_from_town_only;
	else if (strcmpi(key, "battle_configuration/hBG_ip_check") == 0)
		return hBG_ip_check;
	else if (strcmpi(key, "battle_configuration/hBG_idle_announce") == 0)
		return hBG_idle_announce;
	else if (strcmpi(key, "battle_configuration/hBG_idle_autokick") == 0)
		return hBG_idle_autokick;
	else if (strcmpi(key, "battle_configuration/hBG_reportafk_leaderonly") == 0)
		return hBG_reportafk_leaderonly;
	else if (strcmpi(key, "battle_configuration/hBG_balanced_queue") == 0)
		return hBG_balanced_queue;
	else if (strcmpi(key, "battle_configuration/hBG_reward_rates") == 0)
		return hBG_reward_rates;
	else if (strcmpi(key, "battle_configuration/hBG_xy_interval") == 0)
		return hBG_xy_interval;
	else if (strcmpi(key, "battle_configuration/hBG_ranked_mode") == 0)
		return hBG_ranked_mode;
	else if (strcmpi(key, "battle_configuration/hBG_leader_change") == 0)
		return hBG_leader_change;

	return 0;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                       Plugin Handling
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* run when server starts */
HPExport void plugin_init(void)
{
	int interval = hBG_config_get("battle_configuration/hBG_xy_interval");

	if (SERVER_TYPE == SERVER_TYPE_CHAR) {
		addPacket(PACKET_INTER_BG_STATS_REQ, 14, char_bgstats_fromsql, hpParse_FromMap);
		addPacket(PACKET_INTER_BG_STATS_SAVE, 13 + sizeof(struct hBG_stats), char_bgstats_tosql, hpParse_FromMap);
	}
	
	if (SERVER_TYPE == SERVER_TYPE_MAP) {
		addPacket(PACKET_MAP_BG_STATS_GET, 14+sizeof(struct hBG_stats), hBG_statistics_parsefromchar, hpChrif_Parse);
		
		/* Function Pre-Hooks */
		addHookPre(npc, parse_unknown_mapflag, npc_parse_unknown_mapflag_pre);
		addHookPre(clif, charnameupdate, clif_charnameupdate_pre);
		addHookPre(clif, pGuildRequestInfo,clif_parse_GuildRequestInfo_pre);
		addHookPre(status, get_guild_id, status_get_guild_id_pre);
		addHookPre(status, get_emblem_id, status_get_emblem_id_pre);
		addHookPre(guild, isallied, guild_isallied_pre);
		addHookPre(skill, check_condition_castbegin, skill_check_condition_castbegin_pre);
		addHookPre(skill, not_ok, skillnotok_pre);
		addHookPre(skill, castend_nodamage_id, skill_castend_nodamage_id_pre);
		addHookPre(unit, free, unit_free_pre);
		
		/* Function Post-Hooks */
		addHookPost(clif, pLoadEndAck, clif_parse_LoadEndAck_post);
		addHookPost(clif, pUseSkillToId, clif_parse_UseSkillToId_post);
		addHookPost(clif, getareachar_pc, clif_getareachar_pc_post);
		addHookPost(clif, getareachar_unit, clif_getareachar_unit_post);
		addHookPost(pc, update_idle_time, pc_update_idle_time_post);
		addHookPost(pc, authok, pc_authok_post);
		addHookPost(chrif, save, chrif_save_post);
		addHookPost(status, damage, status_damage_post);
		
		addHookPost(battle, check_target, battle_check_target_post);
		
		/* @Commands */
		addAtcommand("bgrank", bgrank);
		addAtcommand("reportafk", reportafk);
		addAtcommand("leader", leader);
		
		/* Script Commands */
		addScriptCommand("hBG_team_create","siiiss", hBG_team_create);
		addScriptCommand("hBG_queue_create","ss?", hBG_queue_create);
		addScriptCommand("hBG_queue_event","is", hBG_queue_event);
		addScriptCommand("hBG_queue_join","i", hBG_queue_join);
		addScriptCommand("hBG_queue_partyjoin","ii", hBG_queue_partyjoin);
		addScriptCommand("hBG_queue_leave","i", hBG_queue_leave);
		addScriptCommand("hBG_queue_data","ii", hBG_queue_data);
		addScriptCommand("hBG_queue2team","iisiiiss", hBG_queue2team);
		addScriptCommand("hBG_queue2team_single","iisii", hBG_queue2team_single);
		addScriptCommand("hBG_queue2teams","iiiiii*", hBG_queue2teams);
		addScriptCommand("hBG_queue_checkstart","iiii", hBG_queue_checkstart);
		addScriptCommand("hBG_balance_teams","iiiii*", hBG_balance_teams);
		addScriptCommand("hBG_waitingroom2bg","siiiss", hBG_waitingroom2bg);
		addScriptCommand("hBG_waitingroom2bg_single","isiis", hBG_waitingroom2bg_single);
		addScriptCommand("hBG_team_setxy","iii", hBG_team_setxy);
		addScriptCommand("hBG_team_reveal","i", hBG_team_reveal);
		addScriptCommand("hBG_team_conceal","i", hBG_team_conceal);
		addScriptCommand("hBG_team_setquest","ii", hBG_team_setquest);
		addScriptCommand("hBG_viewpointmap","siiiii", hBG_viewpointmap);
		addScriptCommand("hBG_monster_reveal","iii", hBG_monster_reveal);
		addScriptCommand("hBG_monster_set_team","ii", hBG_monster_set_team);
		addScriptCommand("hBG_monster_immunity","ii", hBG_monster_immunity);
		addScriptCommand("hBG_leave","", hBG_leave);
		addScriptCommand("hBG_destroy","i", hBG_destroy);
		addScriptCommand("hBG_clean","i", hBG_clean);
		addScriptCommand("hBG_get_data","ii", hBG_get_data);
		addScriptCommand("hBG_getareausers","isiiii", hBG_getareausers);
		addScriptCommand("hBG_updatescore","sii", hBG_updatescore);
		addScriptCommand("hBG_team_updatescore", "ii", hBG_update_score_team);
		addScriptCommand("hBG_team_guildid","i", hBG_get_team_gid);
		addScriptCommand("hBG_getitem","iii", hBG_getitem);
		addScriptCommand("hBG_getkafrapoints","ii", hBG_getkafrapoints);
		addScriptCommand("hBG_reward","iiiiisiii", hBG_reward);
		addScriptCommand("hBG_flooritem2xy", "siiii", hBG_flooritem2xy);
		addScriptCommand("hBG_warp", "isii", hBG_warp);
		
		hBG_queue_db = idb_alloc(DB_OPT_RELEASE_DATA);
		timer->add_func_list(hBG_send_xy_timer, "hBG_send_xy_timer");
		timer->add_interval(timer->gettick() + interval , hBG_send_xy_timer, 0, 0, interval);
	}
}

/* triggered when server starts loading, before any server-specific data is set */
HPExport void server_preinit(void)
{
	if (SERVER_TYPE == SERVER_TYPE_MAP) {
		addBattleConf("battle_configuration/hBG_enabled", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_from_town_only", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_ip_check", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_idle_announce", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_idle_autokick", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_balanced_queue", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_reward_rates", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_xy_interval", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_ranked_mode", hBG_config_read, hBG_config_get, true);
		addBattleConf("battle_configuration/hBG_leader_change", hBG_config_read, hBG_config_get, true);
	}
}

/* run when server is ready (online) */
HPExport void server_online(void)
{
	if (SERVER_TYPE == SERVER_TYPE_MAP) {
		hBG_build_guild_data();
		ShowStatus("%s v%s has been initialized. [by Smokexyz]\n", pinfo.name, pinfo.version);
		// clif interface overloading [lucaslsb]
		bg->team_leave = &bg_team_leave_overload;
		clif->sendbgemblem_area = &clif_sendbgemblem_area_overload;
		clif->sendbgemblem_single = &clif_sendbgemblem_single_overload;
	}
}

static int queue_db_final(union DBKey key, struct DBData *data, va_list ap)
{
	struct hBG_queue_data *hBGqd = DB->data2ptr(data);
	
	if (hBGqd)
		hBG_queue_members_finalize(hBGqd); // Unlink all queue members
	
	return 0;
}

/* run when server is shutting down */
HPExport void plugin_final(void)
{
	if (SERVER_TYPE == SERVER_TYPE_MAP) {
		hBG_queue_db->destroy(hBG_queue_db, queue_db_final);
		ShowInfo ("%s v%s has been finalized. [by Smokexyz]\n", pinfo.name, pinfo.version);
	}
}

 


hBG.c: In function ‘atcommand_reportafk’:
hBG.c:2040:31: warning: unused variable ‘hBGsd’ [-Wunused-variable]
  struct hBG_map_session_data *hBGsd = NULL;
                               ^
hBG.c: In function ‘atcommand_leader’:
hBG.c:2084:31: warning: unused variable ‘hBGsd’ [-Wunused-variable]
  struct hBG_map_session_data *hBGsd = NULL;
                               ^
hBG.c: In function ‘status_get_guild_id_pre’:
hBG.c:3776:31: warning: cast discards ‘__attribute__((const))’ qualifier from pointer target type [-Wcast-qual]
   && (bg_id = bg->team_get_id((struct block_list *)*bl)) > 0
                               ^
hBG.c: In function ‘status_get_emblem_id_pre’:
hBG.c:3797:31: warning: cast discards ‘__attribute__((const))’ qualifier from pointer target type [-Wcast-qual]
   && (bg_id = bg->team_get_id((struct block_list *)(*bl))) > 0
                               ^
        PLUGIN  hBG

Using this plugin.

 

You are using an old hBG.c 

Use the one from this link: https://github.com/lucasljsb/HerculesBG/blob/50a1a3963fe2590a787aab27b27fa2faf9e1f277/src/plugins/hBG.c

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.