Good day!
Help me how to correct these warnings please.
Using this plugin.
Help me how to correct these warnings please.
/*
* 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.id > 0 && guild->check_skill_require(g, g->skill.id)) {
int id = g->skill.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.lv;
if ( g->skill.lv) {
WFIFOW(fd, p + 8) = skill->get_sp(id, g->skill.lv);
WFIFOW(fd, p + 10) = skill->get_range(id, g->skill.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.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.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.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.sd != NULL);
return(i < MAX_BG_MEMBERS) ? bgd->members.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.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.sd = sd;
bgd->members.x = sd->bl.x;
bgd->members.y = sd->bl.y;
bgd->count++;
// Guild Member Data simulation
hBGd->g->member.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.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.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.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.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.x || sd->bl.y != bgd->members.y) { // xy update
bgd->members.x = sd->bl.x;
bgd->members.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.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.sd != NULL)
pc->setpos(bgd->members.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.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) != 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.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.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.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.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.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.sd == sd);
if (i < MAX_BG_MEMBERS) // Removes member from BG
memset(&bgd->members, 0, sizeof(struct battleground_member_data));
ARR_FIND(0, MAX_BG_MEMBERS, i, hBGd->g->member.sd == sd);
if (i < MAX_BG_MEMBERS) // removes member from BG Guild
memset(&hBGd->g->member.sd, 0, sizeof(hBGd->g->member.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.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);
}
}
* 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.id > 0 && guild->check_skill_require(g, g->skill.id)) {
int id = g->skill.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.lv;
if ( g->skill.lv) {
WFIFOW(fd, p + 8) = skill->get_sp(id, g->skill.lv);
WFIFOW(fd, p + 10) = skill->get_range(id, g->skill.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.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.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.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.sd != NULL);
return(i < MAX_BG_MEMBERS) ? bgd->members.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.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.sd = sd;
bgd->members.x = sd->bl.x;
bgd->members.y = sd->bl.y;
bgd->count++;
// Guild Member Data simulation
hBGd->g->member.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.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.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.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.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.x || sd->bl.y != bgd->members.y) { // xy update
bgd->members.x = sd->bl.x;
bgd->members.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.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.sd != NULL)
pc->setpos(bgd->members.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.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) != 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.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.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.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.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.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.sd == sd);
if (i < MAX_BG_MEMBERS) // Removes member from BG
memset(&bgd->members, 0, sizeof(struct battleground_member_data));
ARR_FIND(0, MAX_BG_MEMBERS, i, hBGd->g->member.sd == sd);
if (i < MAX_BG_MEMBERS) // removes member from BG Guild
memset(&hBGd->g->member.sd, 0, sizeof(hBGd->g->member.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.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);
}
}
Code:
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.
Last edited by a moderator: