// Copyright (c) Hemagx, licensed under GNU GPL.
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
// Support is not provided upon share/re-sell
#define HERCULES_CORE
#include "ebg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "map.h"
#include "clif.h"
#include "pc.h"
#include "itemdb.h"
#include "homunculus.h"
#include "mercenary.h"
#include "pet.h"
#include "battleground.h"
#include "npc.h"
#include "../common/conf.h"
#include "../common/showmsg.h"
#include "../common/mapindex.h"
#include "../common/malloc.h"
#include "../common/random.h"
#include "../common/timer.h"
#include "../common/strlib.h"
#include "../common/utils.h"
#include "../common/mapindex.h"
#include "../common/sql.h"
enum item_types ebg_get_item_type(const char *name)
{
if(!strcmpi(name,"IT_HEALING"))
return IT_HEALING;
else if(!strcmpi(name,"IT_UNKNOWN"))
return IT_UNKNOWN;
else if(!strcmpi(name,"IT_USABLE"))
return IT_USABLE;
else if(!strcmpi(name,"IT_ETC"))
return IT_ETC;
else if(!strcmpi(name,"IT_WEAPON"))
return IT_WEAPON;
else if(!strcmpi(name,"IT_ARMOR"))
return IT_ARMOR;
else if(!strcmpi(name,"IT_CARD"))
return IT_CARD;
else if(!strcmpi(name,"IT_PETEGG"))
return IT_PETEGG;
else if(!strcmpi(name,"IT_PETARMOR"))
return IT_PETARMOR;
else if(!strcmpi(name,"IT_UNKNOWN2"))
return IT_UNKNOWN2;
else if(!strcmpi(name,"IT_AMMO"))
return IT_AMMO;
else if(!strcmpi(name,"IT_DELAYCONSUME"))
return IT_DELAYCONSUME;
else if(!strcmpi(name,"IT_CASH"))
return IT_CASH;
else
return IT_MAX;
}
void ebg_mapflags(void)
{
config_t ebg_mapflags;
config_setting_t *maps = NULL;
const char *config_filename = "ebg/maps_flags.conf";
if (libconfig->read_file(&ebg_mapflags, config_filename))
return;
maps = libconfig->lookup(&ebg_mapflags, "maps");
if (maps != NULL)
{
config_setting_t *maps_e;
config_setting_t *black_list_items;
config_setting_t *white_list_items;
config_setting_t *black_list_item_type;
const char *name;
const char *mapname;
int i,h,v;
int maps_count = 0, black_list_items_count = 0, white_list_items_count = 0, black_list_item_type_count = 0,
map_id = 0, map_index = 0,hp_modifer = 0, walkspeed_modifer = 0, block_type = 0;
maps_count = libconfig->setting_length(maps);
for (i = 0; i < maps_count; i++)
{
maps_e = libconfig->setting_get_elem(maps, i);
if (!libconfig->setting_lookup_string(maps_e, "name", &name))
{
ShowError("map_flag_db: missing map_name name, skipping... (%s:%d)\n",
config_setting_source_file(maps_e), config_setting_source_line(maps_e));
libconfig->setting_remove_elem(maps,i);
--maps_count;
--i;
continue;
}
if ( ( map_index = mapindex->name2id(name) ) == 0)
{
ShowError("map_flag_db: unknow map %s, Skipping... \n", name);
continue;
}
map_id = map->mapindex2mapid(map_index);
mapname = name;
if (libconfig->setting_lookup_int(maps_e, "hp_modifer", &hp_modifer))
map->list[map_id].hp_modifer = hp_modifer;
if (libconfig->setting_lookup_int(maps_e, "walkspeed_modifer", &walkspeed_modifer))
map->list[map_id].walkspeed_modifer = walkspeed_modifer;
if (libconfig->setting_lookup_int(maps_e, "block_type", &block_type))
{
map->list[map_id].noitem = block_type;
if( (black_list_items = libconfig->setting_get_member(maps_e, "black_list_items")) != NULL )
{
black_list_items_count = libconfig->setting_length(black_list_items);
for(h = 0; h < libconfig->setting_length(black_list_items); h++) {
config_setting_t *item = libconfig->setting_get_elem(black_list_items, h);
name = config_setting_name(item);
if( !map->zone_str2itemid(name) ) {
ShowError("map_flag_db: unknown item (%s) in black_list_items for map '%s', skipping item...\n",name,mapname);
libconfig->setting_remove_elem(black_list_items,h);
--black_list_items_count;
--h;
continue;
}
if( !libconfig->setting_get_bool(item) )
--black_list_items_count;
}
CREATE( map->list[map_id].itemblacklist, int, black_list_items_count );
for(h = 0, v = 0; h < libconfig->setting_length(black_list_items); h++)
{
config_setting_t *item = libconfig->setting_get_elem(black_list_items, h);
if ( libconfig->setting_get_bool(item) )
{
name = config_setting_name(item);
map->list[map_id].itemblacklist[v++] = map->zone_str2itemid(name);
map->list[map_id].itemblacklist_count = v;
}
}
}
if( (white_list_items = libconfig->setting_get_member(maps_e, "white_list_items")) != NULL )
{
white_list_items_count = libconfig->setting_length(white_list_items);
for(h = 0; h < libconfig->setting_length(white_list_items); h++) {
config_setting_t *item = libconfig->setting_get_elem(white_list_items, h);
name = config_setting_name(item);
if( !map->zone_str2itemid(name) ) {
ShowError("map_flag_db: unknown item (%s) in white_list_items for map '%s', skipping item...\n",name,mapname);
libconfig->setting_remove_elem(white_list_items,h);
--white_list_items_count;
--h;
continue;
}
if( !libconfig->setting_get_bool(item) )
--white_list_items_count;
}
CREATE( map->list[map_id].itemwhitelist, int, white_list_items_count );
for(h = 0, v = 0; h < libconfig->setting_length(white_list_items); h++)
{
config_setting_t *item = libconfig->setting_get_elem(white_list_items, h);
if ( libconfig->setting_get_bool(item) )
{
name = config_setting_name(item);
map->list[map_id].itemwhitelist[v++] = map->zone_str2itemid(name);
map->list[map_id].itemwhitelist_count = v;
}
}
}
if( (black_list_item_type = libconfig->setting_get_member(maps_e, "black_list_item_type")) != NULL )
{
black_list_item_type_count = libconfig->setting_length(black_list_item_type);
for(h = 0; h < libconfig->setting_length(black_list_item_type); h++) {
config_setting_t *item = libconfig->setting_get_elem(black_list_item_type, h);
name = config_setting_name(item);
if( ebg_get_item_type(name) == IT_MAX ) {
ShowError("map_flag_db: unknown item type (%s) in black_list_item_type for map '%s', skipping item...\n",name,mapname);
libconfig->setting_remove_elem(black_list_item_type,h);
--black_list_item_type_count;
--h;
continue;
}
if( !libconfig->setting_get_bool(item) )
--black_list_item_type_count;
CREATE( map->list[map_id].item_block_type, int, black_list_item_type_count );
for(h = 0, v = 0; h < libconfig->setting_length(black_list_item_type); h++)
{
config_setting_t *item2 = libconfig->setting_get_elem(black_list_item_type, h);
if ( libconfig->setting_get_bool(item2) )
{
name = config_setting_name(item2);
map->list[map_id].item_block_type[v++] = ebg_get_item_type(name);
map->list[map_id].item_block_type_count = v;
}
}
}
}
}
}
}
}
int ebg_chose_captain (int bg_id)
{
struct battleground_data *bgd;
int random, members[MAX_BG_MEMBERS] = {0}, count = 0, i = 0, current = 0;
if ( ( bgd = bg->team_search(bg_id) ) == NULL )
return 0;
for( i = 0; i < MAX_BG_MEMBERS; i++)
{
if ( bgd->members[i].sd )
{
members[count] = i;
count++;
}
}
random = rnd_value(0,count - 1);
current = members[random];
ShowDebug(">> %d %p\n", current, current >= 0 ? bgd->members[current].sd : NULL);
ShowDebug("%d\n", bgd->members[current].sd->bl.id);
bgd->members[current].sd->state.size = 2;
clif->specialeffect(&bgd->members[current].sd->bl,422,AREA);
pc->setpos(bgd->members[current].sd, bgd->members[current].sd->mapindex, bgd->members[current].sd->bl.x, bgd->members[current].sd->bl.y, CLR_TELEPORT);
bgd->members[current].sd->ebg.is_captian = 1;
return bgd->members[current].sd->bl.id;
}
int ebg_end_captian (int bg_id)
{
struct battleground_data *bgd;
int i;
if ( ( bgd = bg->team_search(bg_id) ) == NULL )
return 0;
for( i = 0; i < MAX_BG_MEMBERS; i++)
{
if ( !bgd->members[i].sd )
continue;
if ( bgd->members[i].sd->ebg.is_captian )
{
bgd->members[i].sd->ebg.is_captian = 0;
bgd->members[i].sd->state.size = 0;
clif->specialeffect(&bgd->members[i].sd->bl,420,AREA);
pc->setpos(bgd->members[i].sd, bgd->members[i].sd->mapindex, bgd->members[i].sd->bl.x, bgd->members[i].sd->bl.y, CLR_TELEPORT);
}
}
return 1;
}
int ebg_end_bg_spectat (int bg_id )
{
struct battleground_data *bgd;
int i;
if ( ( bgd = bg->team_search(bg_id) ) == NULL )
return 0;
for( i = 0; i < MAX_BG_MEMBERS; i++)
{
if ( !bgd->members[i].sd )
continue;
if ( bgd->members[i].sd->state.spectat )
{
bgd->members[i].sd->sc.option &= ~OPTION_INVISIBLE;
if (bgd->members[i].sd->disguise != -1 )
status->set_viewdata(&bgd->members[i].sd->bl, bgd->members[i].sd->disguise);
else
status->set_viewdata(&bgd->members[i].sd->bl, bgd->members[i].sd->status.class_);
map->list[bgd->members[i].sd->bl.m].users_pvp++;
if( map->list[bgd->members[i].sd->bl.m].flag.pvp && !map->list[bgd->members[i].sd->bl.m].flag.pvp_nocalcrank ) {
bgd->members[i].sd->pvp_timer = timer->add( timer->gettick() + 200, pc->calc_pvprank_timer, bgd->members[i].sd->bl.id, 0 );
}
map->foreachinmovearea(clif->insight, &bgd->members[i].sd->bl, AREA_SIZE, bgd->members[i].sd->bl.x, bgd->members[i].sd->bl.y, BL_ALL, &bgd->members[i].sd->bl);
bgd->members[i].sd->state.spectat = false;
clif->changeoption(&bgd->members[i].sd->bl);
}
}
return 1;
}
void ebg_bg_update_score (struct map_session_data *target, struct block_list *src)
{
target->ebg.death++;
if (src)
{
switch(src->type)
{
case BL_MOB:
return;
break;
case BL_PET:
src = &((TBL_PET*)src)->msd->bl;
break;
case BL_MER:
src = &((TBL_MER*)src)->master->bl;
break;
case BL_HOM:
src = &((TBL_HOM*)src)->master->bl;
break;
}
}
if (src && src->type == BL_PC)
{
struct map_session_data *sd = (struct map_session_data *)src;
if (target->ebg.is_captian)
{
sd->ebg.captian_kill++;
target->ebg.captain_death++;
}
else
sd->ebg.kill++;
}
}
int ebg_return_alive_members (struct battleground_data *bgd)
{
int count = 0,i;
for( i = 0; i < MAX_BG_MEMBERS; i++)
{
if( !bgd->members[i].sd )
continue;
if ( !bgd->members[i].sd->state.spectat && !pc_isdead(bgd->members[i].sd))
count++;
}
return count;
}
int ebg_get_captian_rid ( struct battleground_data *bgd )
{
int i;
for (i = 0; i < MAX_BG_MEMBERS; i++)
{
if (bgd->members[i].sd)
{
if ( bgd->members[i].sd->ebg.is_captian )
return bgd->members[i].sd->bl.id;
}
}
return 0;
}
int ebg_set_freeforall ( int id, const char *joinevent, const char *dieevent, const char *quitevent, const char *map_name, int x, int y )
{
int map_index;
if ( !ebg_ffa_isvaildid(id) )
return 0;
safestrncpy(bg_freeforall[id].join_event, joinevent, sizeof(bg_freeforall[id].join_event));
safestrncpy(bg_freeforall[id].die_event, dieevent, sizeof(bg_freeforall[id].die_event));
safestrncpy(bg_freeforall[id].quit_event, quitevent, sizeof(bg_freeforall[id].quit_event));
if( strcmp(map_name,"-") != 0 )
{
map_index = mapindex->name2id(map_name);
if( map_index == 0 )
return 0;
bg_freeforall[id].mapindex = map_index;
bg_freeforall[id].x = x;
bg_freeforall[id].y = y;
}
return 1;
}
int ebg_join_freeforall ( int id, struct map_session_data *sd )
{
int i;
if ( !ebg_ffa_isvaildid(id) )
return 0;
//Do we have free slot ?
if ( bg_freeforall[id].count == MAX_FREEFORALLMEMBERS )
return -1;
for ( i = 0; i < MAX_FREEFORALLMEMBERS; i++ )
{
if ( bg_freeforall[id].members[i].sd )
continue;
bg_freeforall[id].members[i].sd = sd;
bg_freeforall[id].count++;
sd->ebg.pvp_id = id;
}
npc->event(sd,bg_freeforall[id].join_event,0);
return 1;
}
int ebg_die_freeforall ( struct map_session_data *sd )
{
npc->event(sd,bg_freeforall[sd->ebg.pvp_id].die_event,0);
return 1;
}
int ebg_quit_freeforall ( struct map_session_data *sd )
{
int i;
struct map_session_data *dsd;
for ( i = 0; i < MAX_FREEFORALLMEMBERS; i++ )
{
if ( !bg_freeforall[sd->ebg.pvp_id].members[i].sd )
continue;
dsd = bg_freeforall[sd->ebg.pvp_id].members[i].sd;
if ( dsd->bl.id == sd->bl.id )
{
bg_freeforall[sd->ebg.pvp_id].count--;
sd->ebg.pvp_id = 0;
sd->ebg.death = 0;
sd->ebg.kill = 0;
memset(&bg_freeforall[sd->ebg.pvp_id].members[i], 0, sizeof(bg_freeforall[sd->ebg.pvp_id].members[0]));
break;
}
}
npc->event(sd,bg_freeforall[sd->ebg.pvp_id].quit_event,0);
return 1;
}
int ebg_destory_freeforall ( int id )
{
int i;
struct map_session_data *sd;
if ( !ebg_ffa_isvaildid(id) )
return 0;
for ( i = 0; i < MAX_FREEFORALLMEMBERS; i++ )
{
if ( (sd = bg_freeforall[id].members[i].sd) != NULL )
{
sd->ebg.pvp_id = 0;
sd->ebg.death = 0;
sd->ebg.kill = 0;
}
memset(&bg_freeforall[id].members[i], 0, sizeof(bg_freeforall[id].members[0]));
}
bg_freeforall[id].count = 0;
return 1;
}
int ebg_giveprizeffa( int id )
{
int i, points;
struct map_session_data *sd;
if ( !ebg_ffa_isvaildid(id) )
return 0;
for ( i = 0; i < MAX_FREEFORALLMEMBERS; i++ )
{
sd = bg_freeforall[id].members[i].sd;
if (sd)
{
points = 0;
if ( sd->ebg.kill < 1 )
continue;
if ( sd->ebg.death > 0 )
points = (int)0.5 * ( sd->ebg.kill / sd->ebg.death );
else
points = (int)0.5 * sd->ebg.kill;
points = cap_value(points,1,10);
points += pc_readglobalreg(sd,script->add_str("ebg_points"));
pc_setglobalreg(sd,script->add_str("ebg_points"),points);
}
}
return 1;
}
void ebg_init_ranking_user ( struct map_session_data *sd )
{
char *data = NULL;
char esc_name[2*NAME_LENGTH+1];
if ( SQL_ERROR == SQL->Query(map->mysql_handle, "SELECT * FROM lts_ranking WHERE char_id = %d", sd->status.char_id) )
{
Sql_ShowDebug(map->mysql_handle);
return;
}
if( !(SQL_SUCCESS == SQL->NextRow(map->mysql_handle) &&
SQL_SUCCESS == SQL->GetData(map->mysql_handle, 0, &data, NULL) &&
data != NULL) )
{
SQL->EscapeString(map->mysql_handle,esc_name,sd->status.name);
if ( SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO lts_ranking VALUES ( NULL, %d,0,0,0,'%s')", sd->status.char_id, esc_name))
{
Sql_ShowDebug(map->mysql_handle);
return;
}
}
if ( SQL_ERROR == SQL->Query(map->mysql_handle, "SELECT score FROM captian_ranking WHERE char_id = %d", sd->status.char_id) )
{
Sql_ShowDebug(map->mysql_handle);
return;
}
if( !(SQL_SUCCESS == SQL->NextRow(map->mysql_handle) &&
SQL_SUCCESS == SQL->GetData(map->mysql_handle, 0, &data, NULL) &&
data != NULL) )
{
SQL->EscapeString(map->mysql_handle,esc_name,sd->status.name);
if ( SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO captian_ranking VALUES ( NULL, %d,0,'%s')", sd->status.char_id, esc_name))
{
Sql_ShowDebug(map->mysql_handle);
return;
}
}
else
{
sd->ebg.captain_score = atoi(data);
}
}
int ebg_save_ranking ( int flag, int id1, int id2 )
{
if(flag == EBG_LTS)
{
struct battleground_data *bgd1 = bg->team_search(id1);
struct battleground_data *bgd2 = bg->team_search(id2);
struct map_session_data *sd;
int i;
if ( !bgd1 || !bgd2 )
return 0;
// Go through first team
for ( i = 0; i < MAX_BG_MEMBERS; i++ )
{
if ( !bgd1->members[i].sd )
continue;
sd = bgd1->members[i].sd;
if ( SQL_ERROR == SQL->Query(map->mysql_handle, "UPDATE lts_ranking SET `kill` = `kill` + %d, death = death + %d, kdr = (`kill` / death) WHERE char_id = %d",sd->ebg.kill, sd->ebg.death, sd->status.char_id) )
{
Sql_ShowDebug(map->mysql_handle);
continue;
}
}
for ( i = 0; i < MAX_BG_MEMBERS; i++ )
{
if ( !bgd2->members[i].sd )
continue;
sd = bgd2->members[i].sd;
if ( SQL_ERROR == SQL->Query(map->mysql_handle, "UPDATE lts_ranking SET `kill` = `kill` + %d, death = death + %d, kdr = (`kill` / death) WHERE char_id = %d",sd->ebg.kill, sd->ebg.death, sd->status.char_id) )
{
Sql_ShowDebug(map->mysql_handle);
continue;
}
}
}else if ( flag == EBG_CAPTAIN )
{
struct battleground_data *bgd1 = bg->team_search(id1);
struct battleground_data *bgd2 = bg->team_search(id2);
struct map_session_data *sd;
int i, score;
if ( !bgd1 || !bgd2 )
return 0;
for ( i = 0; i < MAX_BG_MEMBERS; i++ )
{
if ( !bgd1->members[i].sd )
continue;
sd = bgd1->members[i].sd;
score = sd->ebg.captain_score - sd->ebg.captain_death;
sd->ebg.captain_death = 0;
score = cap_value(score,0,INT_MAX);
if ( SQL_ERROR == SQL->Query(map->mysql_handle, "UPDATE captian_ranking SET `score` =%d WHERE char_id = %d", score, sd->status.char_id) )
{
Sql_ShowDebug(map->mysql_handle);
continue;
}
}
for ( i = 0; i < MAX_BG_MEMBERS; i++ )
{
if ( !bgd2->members[i].sd )
continue;
sd = bgd2->members[i].sd;
score = sd->ebg.captain_score - sd->ebg.captain_death;
sd->ebg.captain_death = 0;
score = cap_value(score,0,INT_MAX);
if ( SQL_ERROR == SQL->Query(map->mysql_handle, "UPDATE captian_ranking SET `score` =%d WHERE char_id = %d", score, sd->status.char_id) )
{
Sql_ShowDebug(map->mysql_handle);
continue;
}
}
}
return 1;
}
void ebg_init (void)
{
ebg_mapflags();
}