From 071be58854f037749f5ec160f1a0d50fc41b78eb Mon Sep 17 00:00:00 2001 From: zephyrus Date: Thu, 26 Feb 2009 21:27:12 +0000 Subject: - Fixed item Nemesis. - Fixed Tarot Card being used on Emperium. - First Part of BattleGround Implementation (please wait). git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@13550 54d463be-8e91-2dee-dedb-b68131a5f0ec --- db/item_db.txt | 2 +- src/map/Makefile.in | 4 +- src/map/battle.c | 127 ++++++++-- src/map/battle.h | 12 + src/map/clif.c | 554 +++++++++++++++++++++++++++++++---------- src/map/clif.h | 21 ++ src/map/guild.c | 11 +- src/map/map.c | 5 + src/map/map.h | 5 +- src/map/mob.c | 45 ++++ src/map/mob.h | 4 + src/map/npc.c | 45 +++- src/map/pc.c | 63 ++++- src/map/pc.h | 3 + src/map/script.c | 267 ++++++++++++++++++++ src/map/skill.c | 32 ++- src/map/skill.h | 1 + src/map/status.c | 32 +-- src/map/unit.c | 4 +- vcproj-8/map-server_sql.vcproj | 14 ++ vcproj-8/map-server_txt.vcproj | 8 + 21 files changed, 1044 insertions(+), 215 deletions(-) diff --git a/db/item_db.txt b/db/item_db.txt index dee2c115a..d9cc8a637 100644 --- a/db/item_db.txt +++ b/db/item_db.txt @@ -775,7 +775,7 @@ 1538,Spike_,Spike,4,20,,700,85,,1,2,0x00008110,7,2,2,4,40,1,8,{ bonus bCritical,40; bonus bDefRate,-67; bonus bDef2Rate,-67; },{},{} 1539,Golden_Mace_,Golden Mace,4,20,,800,110,,1,2,0x00008110,7,2,2,4,40,1,8,{ bonus2 bAddRace,RC_Undead,10; bonus bUnbreakableWeapon,0; },{},{} 1540,Grand_Cross_,Grand Cross,4,20,,1500,140,,1,1,0x00008110,7,2,2,4,40,1,8,{ bonus bAtkEle,Ele_Holy; skill "PR_TURNUNDEAD",3; bonus3 bAutoSpell,"PR_TURNUNDEAD",3,100; bonus2 bSPDrainValueRace,RC_Undead,1; bonus2 bSPGainRace,RC_Undead,3; },{},{} -1541,Nemesis,Nemesis,4,20,,900,120,,1,3,0x00008110,7,2,2,4,60,1,8,{ bonus3 bAutoSpell,"AL_CRUCIS",1+getrefine(),100; bonusautoscript "{ sc_start SC_INCBASEATK,20000,50; }",10; },{},{} +1541,Nemesis,Nemesis,4,20,,900,120,,1,0,0x00008110,7,2,2,4,60,1,8,{ bonus3 bAutoSpell,"AL_CRUCIS",1+getrefine(),100; bonusautoscript "{ sc_start SC_INCBASEATK,20000,50; }",10; },{},{} 1542,Millitant_Morning_Star,Millitant Morning Star,4,0,,0,105,,1,0,0x0004C5B3,7,2,2,3,80,1,8,{ bonus bStr,1; bonus bDex,1; bonus2 bAddRace,RC_DemiHuman,75; bonus2 bIgnoreDefRate,RC_DemiHuman,20; bonus bUnbreakableWeapon,0; },{},{} 1543,Millitant_Morning_Star_,Millitant Morning Star,4,0,,0,105,,1,0,0x0004C5B3,7,2,2,3,80,1,8,{ bonus bStr,1; bonus bDex,1; bonus2 bAddRace,RC_DemiHuman,75; bonus bUnbreakableWeapon,0; bonusautoscript "{ sc_start SC_STUN,6000,0; }",50,BF_WEAPON,1; },{},{} //1544#Luna_Kaleet# diff --git a/src/map/Makefile.in b/src/map/Makefile.in index f1eccdf8d..931b86c6a 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -15,7 +15,7 @@ COMMON_SQL_H = ../common/sql.h MAP_OBJ = map.o chrif.o clif.o pc.o status.o npc.o \ npc_chat.o chat.o path.o itemdb.o mob.o script.o \ - storage.o skill.o atcommand.o battle.o \ + storage.o skill.o atcommand.o battle.o battleground.o \ intif.o trade.o party.o vending.o guild.o pet.o \ log.o mail.o date.o unit.o homunculus.o mercenary.o quest.o MAP_TXT_OBJ = $(MAP_OBJ:%=obj_txt/%) \ @@ -24,7 +24,7 @@ MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) \ obj_sql/mapreg_sql.o MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ chat.h itemdb.h mob.h script.h path.h \ - storage.h skill.h atcommand.h battle.h \ + storage.h skill.h atcommand.h battle.h battleground.h \ intif.h trade.h party.h vending.h guild.h pet.h \ log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h mapreg.h diff --git a/src/map/battle.c b/src/map/battle.c index f9bbd08b6..b1bc7287d 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -24,6 +24,7 @@ #include "guild.h" #include "party.h" #include "battle.h" +#include "battleground.h" #include #include @@ -277,12 +278,18 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i nullpo_retr(0, bl); - if (!damage) + if( !damage ) return 0; - if( mob_ksprotected(src, bl) ) return 0; + if( bl->type == BL_MOB ) + { // Event Emperiums works like GvG Emperiums + struct mob_data *md = BL_CAST(BL_MOB, bl); + if( map[bl->m].flag.battleground && (md->class_ == 1914 || md->class_ == 1915) && flag&BF_SKILL ) + return 0; // Crystal Cannot receive magic damage on battlegrounds + } + if (bl->type == BL_PC) { sd=(struct map_session_data *)bl; //Special no damage states @@ -521,6 +528,42 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i return damage; } +/*========================================== + * Calculates BG related damage adjustments. + *------------------------------------------*/ +int battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int damage, int div_, int skill_num, int skill_lv, int flag) +{ + if( !damage ) return 0; + switch( skill_num ) + { + case PA_PRESSURE: + case HW_GRAVITATION: + case NJ_ZENYNAGE: + break; + default: + if( flag&BF_SKILL ) + { //Skills get a different reduction than non-skills. [Skotlex] + if( flag&BF_WEAPON ) + damage = damage * battle_config.bg_weapon_damage_rate/100; + if( flag&BF_MAGIC ) + damage = damage * battle_config.bg_magic_damage_rate/100; + if( flag&BF_MISC ) + damage = damage * battle_config.bg_misc_damage_rate/100; + } + else + { //Normal attacks get reductions based on range. + if( flag&BF_SHORT ) + damage = damage * battle_config.bg_short_damage_rate/100; + if( flag&BF_LONG ) + damage = damage * battle_config.bg_long_damage_rate/100; + } + + if( !damage ) damage = 1; + } + + return damage; +} + /*========================================== * Calculates GVG related damage adjustments. *------------------------------------------*/ @@ -536,7 +579,7 @@ int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int dama if (bl->type == BL_MOB) md=(struct mob_data *)bl; - + if(md && md->guardian_data) { if(class_ == MOBID_EMPERIUM && flag&BF_SKILL) //Skill immunity. @@ -2083,19 +2126,25 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo { //There is a total damage value if(!wd.damage2) { wd.damage=battle_calc_damage(src,target,wd.damage,wd.div_,skill_num,skill_lv,wd.flag); - if (map_flag_gvg2(target->m)) + if( map_flag_gvg2(target->m) ) wd.damage=battle_calc_gvg_damage(src,target,wd.damage,wd.div_,skill_num,skill_lv,wd.flag); + else if( map[target->m].flag.battleground ) + wd.damage=battle_calc_bg_damage(src,target,wd.damage,wd.div_,skill_num,skill_lv,wd.flag); } else if(!wd.damage) { wd.damage2=battle_calc_damage(src,target,wd.damage2,wd.div_,skill_num,skill_lv,wd.flag); - if (map_flag_gvg2(target->m)) + if( map_flag_gvg2(target->m) ) wd.damage2=battle_calc_gvg_damage(src,target,wd.damage2,wd.div_,skill_num,skill_lv,wd.flag); + else if( map[target->m].flag.battleground ) + wd.damage=battle_calc_bg_damage(src,target,wd.damage2,wd.div_,skill_num,skill_lv,wd.flag); } else { int d1=wd.damage+wd.damage2,d2=wd.damage2; wd.damage=battle_calc_damage(src,target,d1,wd.div_,skill_num,skill_lv,wd.flag); - if (map_flag_gvg2(target->m)) + if( map_flag_gvg2(target->m) ) wd.damage=battle_calc_gvg_damage(src,target,wd.damage,wd.div_,skill_num,skill_lv,wd.flag); + else if( map[target->m].flag.battleground ) + wd.damage=battle_calc_bg_damage(src,target,wd.damage,wd.div_,skill_num,skill_lv,wd.flag); wd.damage2=(d2*100/d1)*wd.damage/100; if(wd.damage > 1 && wd.damage2 < 1) wd.damage2=1; wd.damage-=wd.damage2; @@ -2494,8 +2543,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list ad.damage = ad.damage>0?1:-1; ad.damage=battle_calc_damage(src,target,ad.damage,ad.div_,skill_num,skill_lv,ad.flag); - if (map_flag_gvg2(target->m)) + if( map_flag_gvg2(target->m) ) ad.damage=battle_calc_gvg_damage(src,target,ad.damage,ad.div_,skill_num,skill_lv,ad.flag); + else if( map[target->m].flag.battleground ) + ad.damage=battle_calc_bg_damage(src,target,ad.damage,ad.div_,skill_num,skill_lv,ad.flag); return ad; } @@ -2721,8 +2772,10 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * md.damage=battle_attr_fix(src, target, md.damage, s_ele, tstatus->def_ele, tstatus->ele_lv); md.damage=battle_calc_damage(src,target,md.damage,md.div_,skill_num,skill_lv,md.flag); - if (map_flag_gvg2(target->m)) + if( map_flag_gvg2(target->m) ) md.damage=battle_calc_gvg_damage(src,target,md.damage,md.div_,skill_num,skill_lv,md.flag); + else if( map[target->m].flag.battleground ) + md.damage=battle_calc_bg_damage(src,target,md.damage,md.div_,skill_num,skill_lv,md.flag); if (skill_num == NJ_ZENYNAGE && sd) { //Time to Pay Up. @@ -3210,6 +3263,8 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if( !((agit_flag || agit2_flag) && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id ) return 0; // Disable guardians/emperiums owned by Guilds on non-woe times. + if( md->state.inmunity && flag&BCT_ENEMY ) + return 0; break; } } @@ -3261,10 +3316,9 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f return 0; // You can't target anything out of your duel } } - if (map_flag_gvg(m) && !sd->status.guild_id && - t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->guardian_data) + if( map_flag_gvg(m) && !sd->status.guild_id && t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->guardian_data ) return 0; //If you don't belong to a guild, can't target guardians/emperium. - if (t_bl->type != BL_PC) + if( t_bl->type != BL_PC ) state |= BCT_ENEMY; //Natural enemy. break; } @@ -3315,28 +3369,34 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if( map_flag_vs(m) ) { //Check rivalry settings. - if (flag&(BCT_PARTY|BCT_ENEMY)) { + int sbg_id = 0, tbg_id = 0; + if( map[m].flag.battleground ) + { + sbg_id = bg_team_get_id(s_bl); + tbg_id = bg_team_get_id(t_bl); + } + if( flag&(BCT_PARTY|BCT_ENEMY) ) + { int s_party = status_get_party_id(s_bl); - if ( - !(map[m].flag.pvp && map[m].flag.pvp_noparty) && - !(map_flag_gvg(m) && map[m].flag.gvg_noparty) && - s_party && s_party == status_get_party_id(t_bl) - ) + if( s_party && s_party == status_get_party_id(t_bl) && !(map[m].flag.pvp && map[m].flag.pvp_noparty) && !(map_flag_gvg(m) && map[m].flag.gvg_noparty) && (!map[m].flag.battleground || sbg_id == tbg_id) ) state |= BCT_PARTY; else state |= BCT_ENEMY; } - if (flag&(BCT_GUILD|BCT_ENEMY)) { + if( flag&(BCT_GUILD|BCT_ENEMY) ) + { int s_guild = status_get_guild_id(s_bl); int t_guild = status_get_guild_id(t_bl); - if( !(map[m].flag.pvp && map[m].flag.pvp_noguild) && s_guild && t_guild && (s_guild == t_guild || guild_isallied(s_guild, t_guild)) ) + if( !(map[m].flag.pvp && map[m].flag.pvp_noguild) && s_guild && t_guild && (s_guild == t_guild || guild_isallied(s_guild, t_guild)) && (!map[m].flag.battleground || sbg_id == tbg_id) ) state |= BCT_GUILD; else state |= BCT_ENEMY; } - if (state&BCT_ENEMY && battle_config.pk_mode && !map_flag_gvg(m) && - s_bl->type == BL_PC && t_bl->type == BL_PC) - { //Prevent novice engagement on pk_mode (feature by Valaris) + if( state&BCT_ENEMY && map[m].flag.battleground && sbg_id && sbg_id == tbg_id ) + state &= ~BCT_ENEMY; + + if( state&BCT_ENEMY && battle_config.pk_mode && !map_flag_gvg(m) && s_bl->type == BL_PC && t_bl->type == BL_PC ) + { // Prevent novice engagement on pk_mode (feature by Valaris) TBL_PC *sd = (TBL_PC*)s_bl, *sd2 = (TBL_PC*)t_bl; if ( (sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE || @@ -3345,15 +3405,19 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f (int)sd2->status.base_level < battle_config.pk_min_level || (battle_config.pk_level_range && abs((int)sd->status.base_level - (int)sd2->status.base_level) > battle_config.pk_level_range) ) - state&=~BCT_ENEMY; + state &= ~BCT_ENEMY; } - } else { //Non pvp/gvg, check party/guild settings. - if (flag&BCT_PARTY || state&BCT_ENEMY) { + } + else + { //Non pvp/gvg, check party/guild settings. + if( flag&BCT_PARTY || state&BCT_ENEMY ) + { int s_party = status_get_party_id(s_bl); if(s_party && s_party == status_get_party_id(t_bl)) state |= BCT_PARTY; } - if (flag&BCT_GUILD || state&BCT_ENEMY) { + if( flag&BCT_GUILD || state&BCT_ENEMY ) + { int s_guild = status_get_guild_id(s_bl); int t_guild = status_get_guild_id(t_bl); if(s_guild && t_guild && (s_guild == t_guild || guild_isallied(s_guild, t_guild))) @@ -3768,6 +3832,17 @@ static const struct _battle_data { { "auction_maximumprice", &battle_config.auction_maximumprice, 500000000, 0, MAX_ZENY, }, { "gm_viewequip_min_lv", &battle_config.gm_viewequip_min_lv, 0, 0, 99, }, { "homunculus_auto_vapor", &battle_config.homunculus_auto_vapor, 0, 0, 1, }, +// BattleGround Settings + { "bg_update_interval", &battle_config.bg_update_interval, 1000, 100, INT_MAX, }, + { "bg_guild_id1", &battle_config.bg_guild_id1, 0, 0, INT_MAX, }, + { "bg_guild_id2", &battle_config.bg_guild_id2, 0, 0, INT_MAX, }, + { "bg_short_attack_damage_rate", &battle_config.bg_short_damage_rate, 80, 0, INT_MAX, }, + { "bg_long_attack_damage_rate", &battle_config.bg_long_damage_rate, 80, 0, INT_MAX, }, + { "bg_weapon_attack_damage_rate", &battle_config.bg_weapon_damage_rate, 60, 0, INT_MAX, }, + { "bg_magic_attack_damage_rate", &battle_config.bg_magic_damage_rate, 60, 0, INT_MAX, }, + { "bg_misc_attack_damage_rate", &battle_config.bg_misc_damage_rate, 60, 0, INT_MAX, }, + { "bg_flee_penalty", &battle_config.bg_flee_penalty, 20, 0, INT_MAX, }, + { "bg_idle_announce", &battle_config.bg_idle_announce, 0, 0, INT_MAX, }, }; diff --git a/src/map/battle.h b/src/map/battle.h index 4326fb6ee..20b1b9b2b 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -43,6 +43,7 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag // ダメージ最終計算 int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,int div_,int skill_num,int skill_lv,int flag); int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int damage,int div_,int skill_num,int skill_lv,int flag); +int battle_calc_bg_damage(struct block_list *src,struct block_list *bl,int damage,int div_,int skill_num,int skill_lv,int flag); enum { // 最終計算のフラグ BF_WEAPON = 0x0001, @@ -460,6 +461,17 @@ extern struct Battle_Config int auction_maximumprice; int gm_viewequip_min_lv; int homunculus_auto_vapor; //Keep Homunculus from Vaporizing when master dies. [L0ne_W0lf] + // [BattleGround Settings] + int bg_update_interval; + int bg_guild_id1; + int bg_guild_id2; + int bg_short_damage_rate; + int bg_long_damage_rate; + int bg_weapon_damage_rate; + int bg_magic_damage_rate; + int bg_misc_damage_rate; + int bg_flee_penalty; + int bg_idle_announce; } battle_config; void do_init_battle(void); diff --git a/src/map/clif.c b/src/map/clif.c index 94f0dceef..739805f04 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -25,6 +25,7 @@ #include "atcommand.h" #include "intif.h" #include "battle.h" +#include "battleground.h" #include "mob.h" #include "party.h" #include "unit.h" @@ -231,6 +232,7 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target struct map_session_data *sd, *tsd; struct party_data *p = NULL; struct guild *g = NULL; + struct battleground_data *bg = NULL; int x0 = 0, x1 = 0, y0 = 0, y1 = 0, fd; struct s_mapiterator* iter; @@ -415,6 +417,7 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target case GUILD_SAMEMAP_WOS: case GUILD: case GUILD_WOS: + case GUILD_NOBG: if (sd && sd->status.guild_id) g = guild_search(sd->status.guild_id); @@ -425,10 +428,13 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target if( !(fd=sd->fd) ) continue; + if( type == GUILD_NOBG && sd->state.bg_id ) + continue; + if( sd->bl.id == bl->id && (type == GUILD_WOS || type == GUILD_SAMEMAP_WOS || type == GUILD_AREA_WOS) ) continue; - if( type != GUILD && type != GUILD_WOS && sd->bl.m != bl->m ) + if( type != GUILD && type != GUILD_NOBG && type != GUILD_WOS && sd->bl.m != bl->m ) continue; if( (type == GUILD_AREA || type == GUILD_AREA_WOS) && (sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1) ) @@ -459,6 +465,38 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target } break; + case BG_AREA: + case BG_AREA_WOS: + x0 = bl->x - AREA_SIZE; + y0 = bl->y - AREA_SIZE; + x1 = bl->x + AREA_SIZE; + y1 = bl->y + AREA_SIZE; + case BG_SAMEMAP: + case BG_SAMEMAP_WOS: + case BG: + case BG_WOS: + if( sd && sd->state.bg_id && (bg = bg_team_search(sd->state.bg_id)) != NULL ) + { + for( i = 0; i < MAX_BG_MEMBERS; i++ ) + { + if( (sd = bg->members[i].sd) == NULL || !(fd = sd->fd) ) + continue; + if( sd->bl.id == bl->id && (type == BG_WOS || type == BG_SAMEMAP_WOS || type == BG_AREA_WOS) ) + continue; + if( type != BG && type != BG_WOS && sd->bl.m != bl->m ) + continue; + if( (type == BG_AREA || type == BG_AREA_WOS) && (sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1) ) + continue; + if( packet_db[sd->packet_ver][RBUFW(buf,0)].len ) + { // packet must exist for the client version + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + } + } + } + break; + default: ShowError("clif_send: Unrecognized type %d\n",type); return -1; @@ -774,8 +812,8 @@ static int clif_set_unit_idle(struct block_list* bl, unsigned char* buffer, bool if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this? - WBUFL(buf,22) = status_get_emblem_id(bl); - WBUFL(buf,26) = status_get_guild_id(bl); + WBUFL(buf,22) = clif_bg_emblem_id(bl); + WBUFL(buf,26) = clif_bg_guild_id(bl); } WBUFW(buf,28) = vd->hair_color; @@ -789,8 +827,8 @@ static int clif_set_unit_idle(struct block_list* bl, unsigned char* buffer, bool WBUFB(buf,40) = 0; return packet_len(0x7c); } - WBUFL(buf,34) = status_get_guild_id(bl); - WBUFW(buf,38) = status_get_emblem_id(bl); + WBUFL(buf,34) = clif_bg_guild_id(bl); + WBUFW(buf,38) = clif_bg_emblem_id(bl); WBUFW(buf,40) = (sd)? sd->status.manner : 0; #if PACKETVER >= 7 if (!type) { @@ -870,8 +908,8 @@ static int clif_set_unit_walking(struct block_list* bl, struct unit_data* ud, un WBUFW(buf,32) = vd->hair_color; WBUFW(buf,34) = vd->cloth_color; WBUFW(buf,36) = (sd)? sd->head_dir : 0; - WBUFL(buf,38) = status_get_guild_id(bl); - WBUFW(buf,42) = status_get_emblem_id(bl); + WBUFL(buf,38) = clif_bg_guild_id(bl); + WBUFW(buf,42) = clif_bg_emblem_id(bl); WBUFW(buf,44) = (sd)? sd->status.manner : 0; #if PACKETVER < 7 WBUFW(buf,46) = (sc)? sc->opt3 : 0; @@ -2060,6 +2098,9 @@ int clif_guild_xy(struct map_session_data *sd) *------------------------------------------*/ int clif_guild_xy_single(int fd, struct map_session_data *sd) { + if( sd->state.bg_id ) + return 0; + WFIFOHEAD(fd,packet_len(0x1eb)); WFIFOW(fd,0)=0x1eb; WFIFOL(fd,2)=sd->status.account_id; @@ -2152,10 +2193,12 @@ int clif_updatestatus(struct map_session_data *sd,int type) break; case SP_HP: WFIFOL(fd,4)=sd->battle_status.hp; - if (battle_config.disp_hpmeter) + if( battle_config.disp_hpmeter ) clif_hpmeter(sd); - if (!battle_config.party_hp_mode && sd->status.party_id) + if( !battle_config.party_hp_mode && sd->status.party_id ) clif_party_hp(sd); + if( sd->state.bg_id ) + clif_bg_hp(sd); break; case SP_SP: WFIFOL(fd,4)=sd->battle_status.sp; @@ -3352,9 +3395,9 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d if(dstsd->spiritball > 0) clif_spiritball_single(sd->fd, dstsd); - if((sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting. - (battle_config.disp_hpmeter && (gmlvl = pc_isGM(sd)) >= battle_config.disp_hpmeter && gmlvl >= pc_isGM(dstsd)) - ) + if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting. + (sd->state.bg_id && sd->state.bg_id == dstsd->state.bg_id) || //BattleGround + (battle_config.disp_hpmeter && (gmlvl = pc_isGM(sd)) >= battle_config.disp_hpmeter && gmlvl >= pc_isGM(dstsd)) ) clif_hpmeter_single(sd->fd, dstsd->bl.id, dstsd->battle_status.hp, dstsd->battle_status.max_hp); // display link (sd - dstsd) to sd @@ -5585,26 +5628,29 @@ int clif_hpmeter(struct map_session_data *sd) WBUFW(buf,0) = 0x106; WBUFL(buf,2) = sd->status.account_id; - if (sd->battle_status.max_hp > SHRT_MAX) { //To correctly display the %hp bar. [Skotlex] + if( sd->battle_status.max_hp > SHRT_MAX ) + { //To correctly display the %hp bar. [Skotlex] WBUFW(buf,6) = sd->battle_status.hp/(sd->battle_status.max_hp/100); WBUFW(buf,8) = 100; - } else { + } + else + { WBUFW(buf,6) = sd->battle_status.hp; WBUFW(buf,8) = sd->battle_status.max_hp; } - for (i = 0; i < fd_max; i++) { - if (session[i] && session[i]->func_parse == clif_parse && - (sd2 = (struct map_session_data*)session[i]->session_data) && - sd != sd2 && sd2->state.active) { - if (sd2->bl.m != sd->bl.m || - sd2->bl.x < x0 || sd2->bl.y < y0 || - sd2->bl.x > x1 || sd2->bl.y > y1 || - (level = pc_isGM(sd2)) < battle_config.disp_hpmeter || - level < pc_isGM(sd)) - continue; - WFIFOHEAD (i, packet_len(0x106)); - memcpy (WFIFOP(i,0), buf, packet_len(0x106)); - WFIFOSET (i, packet_len(0x106)); + + for( i = 0; i < fd_max; i++ ) + { + if( session[i] && session[i]->func_parse == clif_parse && (sd2 = (struct map_session_data*)session[i]->session_data) && sd != sd2 && sd2->state.active ) + { + if( sd2->bl.m != sd->bl.m || sd2->bl.x < x0 || sd2->bl.y < y0 || sd2->bl.x > x1 || sd2->bl.y > y1 ) + continue; // Not in the Visual Area + if( battle_config.disp_hpmeter && (level = pc_isGM(sd2)) >= battle_config.disp_hpmeter && level >= pc_isGM(sd) ) + { + WFIFOHEAD(i,packet_len(0x106)); + memcpy(WFIFOP(i,0),buf,packet_len(0x106)); + WFIFOSET(i,packet_len(0x106)); + } } } @@ -6045,16 +6091,16 @@ int clif_guild_created(struct map_session_data *sd,int flag) /*========================================== * ギルド所属通知 *------------------------------------------*/ -int clif_guild_belonginfo(struct map_session_data *sd,struct guild *g) +int clif_guild_belonginfo(struct map_session_data *sd, struct guild *g) { int ps,fd; - nullpo_retr(0, sd); + if( sd->state.bg_id ) + return clif_bg_belonginfo(sd); nullpo_retr(0, g); fd=sd->fd; ps=guild_getposition(g,sd); - WFIFOHEAD(fd,packet_len(0x16c)); memset(WFIFOP(fd,0),0,packet_len(0x16c)); WFIFOW(fd,0)=0x16c; @@ -6150,20 +6196,25 @@ int clif_guild_basicinfo(struct map_session_data *sd) { int fd,i,t; struct guild *g; - struct guild_castle *gc=NULL; + struct guild_castle *gc = NULL; + struct battleground_data *bg = NULL; nullpo_retr(0, sd); + fd = sd->fd; - fd=sd->fd; - g=guild_search(sd->status.guild_id); - if(g==NULL) + if( sd->state.bg_id && (g = bg_guild_get(sd->state.bg_id)) != NULL ) + bg = bg_team_search(sd->state.bg_id); + else + g = guild_search(sd->status.guild_id); + + if( g == NULL ) return 0; WFIFOHEAD(fd,packet_len(0x1b6)); WFIFOW(fd, 0)=0x1b6;//0x150; WFIFOL(fd, 2)=g->guild_id; WFIFOL(fd, 6)=g->guild_lv; - WFIFOL(fd,10)=g->connect_member; + WFIFOL(fd,10)=bg?bg->count:g->connect_member; WFIFOL(fd,14)=g->max_member; WFIFOL(fd,18)=g->average_lv; WFIFOL(fd,22)=g->exp; @@ -6196,11 +6247,13 @@ int clif_guild_allianceinfo(struct map_session_data *sd) struct guild *g; nullpo_retr(0, sd); + if( !sd->state.bg_id || (g = bg_guild_get(sd->state.bg_id)) == NULL ) + g = guild_search(sd->status.guild_id); - fd=sd->fd; - g=guild_search(sd->status.guild_id); - if(g==NULL) + if( g == NULL ) return 0; + + fd = sd->fd; WFIFOHEAD(fd, MAX_GUILDALLIANCE * 32 + 4); WFIFOW(fd, 0)=0x14c; for(i=c=0;ifd; - if (!fd) + if( (fd = sd->fd) == 0 ) return 0; - g=guild_search(sd->status.guild_id); - if(g==NULL) + if( sd->state.bg_id ) + return clif_bg_memberlist(sd); + if( (g = guild_search(sd->status.guild_id)) == NULL ) return 0; WFIFOHEAD(fd, g->max_member * 104 + 4); @@ -6268,11 +6320,13 @@ int clif_guild_positionnamelist(struct map_session_data *sd) struct guild *g; nullpo_retr(0, sd); + if( !sd->state.bg_id || (g = bg_guild_get(sd->state.bg_id)) == NULL ) + g = guild_search(sd->status.guild_id); - fd=sd->fd; - g=guild_search(sd->status.guild_id); - if(g==NULL) + if( g == NULL ) return 0; + + fd = sd->fd; WFIFOHEAD(fd, MAX_GUILDPOSITION * 28 + 4); WFIFOW(fd, 0)=0x166; for(i=0;istate.bg_id || (g = bg_guild_get(sd->state.bg_id)) == NULL ) + g = guild_search(sd->status.guild_id); - fd=sd->fd; - g=guild_search(sd->status.guild_id); - if(g==NULL) + if( g == NULL ) return 0; + + fd = sd->fd; WFIFOHEAD(fd, MAX_GUILDPOSITION * 16 + 4); WFIFOW(fd, 0)=0x160; for(i=0;ifd; - - if(g->emblem_len<=0) + fd = sd->fd; + if( g->emblem_len <= 0 ) return 0; + WFIFOHEAD(fd,g->emblem_len+12); WFIFOW(fd,0)=0x152; WFIFOW(fd,2)=g->emblem_len+12; @@ -6385,8 +6440,8 @@ void clif_guild_emblem_area(struct block_list* bl) // (emblem in the flag npcs and emblem over the head in agit maps) [FlavioJS] WBUFW(buf,0) = 0x1B4; WBUFL(buf,2) = bl->id; - WBUFL(buf,6) = status_get_guild_id(bl); - WBUFW(buf,10) = status_get_emblem_id(bl); + WBUFL(buf,6) = clif_bg_guild_id(bl); + WBUFW(buf,10) = clif_bg_emblem_id(bl); clif_send(buf, 12, bl, AREA_WOS); } @@ -6400,12 +6455,13 @@ int clif_guild_skillinfo(struct map_session_data* sd) int i,c; nullpo_retr(0, sd); + if( !sd->state.bg_id || (g = bg_guild_get(sd->state.bg_id)) == NULL ) + g = guild_search(sd->status.guild_id); - fd = sd->fd; - g = guild_search(sd->status.guild_id); - if(g == NULL) + if( g == NULL ) return 0; + fd = sd->fd; WFIFOHEAD(fd, 6 + MAX_GUILDSKILL*37); WFIFOW(fd,0) = 0x0162; WFIFOW(fd,4) = g->skill_point; @@ -6505,7 +6561,7 @@ int clif_guild_leave(struct map_session_data *sd,const char *name,const char *me WBUFW(buf, 0)=0x15a; memcpy(WBUFP(buf, 2),name,NAME_LENGTH); memcpy(WBUFP(buf,26),mes,40); - clif_send(buf,packet_len(0x15a),&sd->bl,GUILD); + clif_send(buf,packet_len(0x15a),&sd->bl,GUILD_NOBG); return 0; } @@ -6522,7 +6578,7 @@ int clif_guild_expulsion(struct map_session_data *sd,const char *name,const char safestrncpy((char*)WBUFP(buf, 2),name,NAME_LENGTH); safestrncpy((char*)WBUFP(buf,26),mes,40); safestrncpy((char*)WBUFP(buf,66),"",NAME_LENGTH); // account name (not used for security reasons) - clif_send(buf,packet_len(0x15c),&sd->bl,GUILD); + clif_send(buf,packet_len(0x15c),&sd->bl,GUILD_NOBG); return 0; } @@ -6536,11 +6592,13 @@ int clif_guild_expulsionlist(struct map_session_data *sd) struct guild *g; nullpo_retr(0, sd); + if( !sd->state.bg_id || (g = bg_guild_get(sd->state.bg_id)) == NULL ) + g = guild_search(sd->status.guild_id); - fd=sd->fd; - g=guild_search(sd->status.guild_id); - if(g==NULL) + if( g == NULL ) return 0; + + fd = sd->fd; WFIFOHEAD(fd,4 + MAX_GUILDEXPULSION * 88); WFIFOW(fd,0)=0x163; for(i=c=0;ibl, GUILD); + clif_send(buf, WBUFW(buf,2), &sd->bl, GUILD_NOBG); if(buf) aFree(buf); @@ -7080,7 +7138,7 @@ int clif_refresh(struct map_session_data *sd) int clif_charnameack (int fd, struct block_list *bl) { unsigned char buf[103]; - int cmd = 0x95; + int cmd = 0x95, i, ps = -1; nullpo_retr(0, bl); @@ -7097,7 +7155,7 @@ int clif_charnameack (int fd, struct block_list *bl) //Requesting your own "shadow" name. [Skotlex] if (ssd->fd == fd && ssd->disguise) - WBUFL(buf,2) = -bl->id; + WBUFL(buf,2) = -bl->id; if (strlen(ssd->fakename)>1) { memcpy(WBUFP(buf,6), ssd->fakename, NAME_LENGTH); @@ -7108,8 +7166,16 @@ int clif_charnameack (int fd, struct block_list *bl) if (ssd->status.party_id > 0) p = party_search(ssd->status.party_id); - if (ssd->status.guild_id > 0) - g = guild_search(ssd->status.guild_id); + if (ssd->state.bg_id > 0) + { + g = bg_guild_get(ssd->state.bg_id); + ps = 0; + } + else if( ssd->status.guild_id > 0 && (g = guild_search(ssd->status.guild_id)) != NULL ) + { + ARR_FIND(0, g->max_member, i, g->member[i].account_id == ssd->status.account_id && g->member[i].char_id == ssd->status.char_id); + if( i < g->max_member ) ps = g->member[i].position; + } if (p == NULL && g == NULL) break; @@ -7120,26 +7186,11 @@ int clif_charnameack (int fd, struct block_list *bl) else WBUFB(buf,30) = 0; - if (g) + if (g && ps >= 0 && ps < MAX_GUILDPOSITION) { - int i, ps = -1; - for(i = 0; i < g->max_member; i++) { - if (g->member[i].account_id == ssd->status.account_id && - g->member[i].char_id == ssd->status.char_id ) - { - ps = g->member[i].position; - break; - } - } - if (ps >= 0 && ps < MAX_GUILDPOSITION) - { - memcpy(WBUFP(buf,54), g->name,NAME_LENGTH); - memcpy(WBUFP(buf,78), g->position[ps].name, NAME_LENGTH); - } else { //Assume no guild. - WBUFB(buf,54) = 0; - WBUFB(buf,78) = 0; - } - } else { + memcpy(WBUFP(buf,54), g->name,NAME_LENGTH); + memcpy(WBUFP(buf,78), g->position[ps].name, NAME_LENGTH); + } else { //Assume no guild. WBUFB(buf,54) = 0; WBUFB(buf,78) = 0; } @@ -7161,27 +7212,39 @@ int clif_charnameack (int fd, struct block_list *bl) case BL_MOB: { struct mob_data *md = (struct mob_data *)bl; + struct guild *g; + struct battleground_data *bg; nullpo_retr(0, md); memcpy(WBUFP(buf,6), md->name, NAME_LENGTH); - if (md->guardian_data && md->guardian_data->guild_id) { + if( md->guardian_data && md->guardian_data->guild_id ) + { WBUFW(buf, 0) = cmd = 0x195; WBUFB(buf,30) = 0; memcpy(WBUFP(buf,54), md->guardian_data->guild_name, NAME_LENGTH); memcpy(WBUFP(buf,78), md->guardian_data->castle->castle_name, NAME_LENGTH); - } else if (battle_config.show_mob_info) { + } + else if( md->state.bg_id && (bg = bg_team_search(md->state.bg_id)) != NULL && (g = bg->g) != NULL ) + { + WBUFW(buf, 0) = cmd = 0x195; + WBUFB(buf,30) = 0; + memcpy(WBUFP(buf,54), g->name, NAME_LENGTH); + memcpy(WBUFP(buf,78), g->position[0].name, NAME_LENGTH); + } + else if( battle_config.show_mob_info ) + { char mobhp[50], *str_p = mobhp; - WBUFW(buf, 0) = cmd = 0x195; - if (battle_config.show_mob_info&4) + if( battle_config.show_mob_info&4 ) str_p += sprintf(str_p, "Lv. %d | ", md->level); - if (battle_config.show_mob_info&1) + if( battle_config.show_mob_info&1 ) str_p += sprintf(str_p, "HP: %u/%u | ", md->status.hp, md->status.max_hp); - if (battle_config.show_mob_info&2) + if( battle_config.show_mob_info&2 ) str_p += sprintf(str_p, "HP: %d%% | ", get_percentage(md->status.hp, md->status.max_hp)); //Even thought mobhp ain't a name, we send it as one so the client //can parse it. [Skotlex] - if (str_p != mobhp) { + if( str_p != mobhp ) + { *(str_p-3) = '\0'; //Remove trailing space + pipe. memcpy(WBUFP(buf,30), mobhp, NAME_LENGTH); WBUFB(buf,54) = 0; @@ -7216,7 +7279,7 @@ int clif_charnameack (int fd, struct block_list *bl) int clif_charnameupdate (struct map_session_data *ssd) { unsigned char buf[103]; - int cmd = 0x195; + int cmd = 0x195, ps = -1, i; struct party_data *p = NULL; struct guild *g = NULL; @@ -7230,37 +7293,32 @@ int clif_charnameupdate (struct map_session_data *ssd) memcpy(WBUFP(buf,6), ssd->status.name, NAME_LENGTH); - if (ssd->status.party_id > 0) + if( ssd->status.party_id > 0 ) p = party_search(ssd->status.party_id); - if (ssd->status.guild_id > 0) - g = guild_search(ssd->status.guild_id); + if( ssd->state.bg_id > 0 ) + { + g = bg_guild_get(ssd->state.bg_id); + ps = 0; + } + else if( ssd->status.guild_id > 0 && (g = guild_search(ssd->status.guild_id)) != NULL ) + { + ARR_FIND(0, g->max_member, i, g->member[i].account_id == ssd->status.account_id && g->member[i].char_id == ssd->status.char_id); + if( i < g->max_member ) ps = g->member[i].position; + } - if (p) + if( p ) memcpy(WBUFP(buf,30), p->party.name, NAME_LENGTH); else WBUFB(buf,30) = 0; - if (g) + if( g && ps >= 0 && ps < MAX_GUILDPOSITION ) + { + memcpy(WBUFP(buf,54), g->name,NAME_LENGTH); + memcpy(WBUFP(buf,78), g->position[ps].name, NAME_LENGTH); + } + else { - int i, ps = -1; - for(i = 0; i < g->max_member; i++) { - if (g->member[i].account_id == ssd->status.account_id && - g->member[i].char_id == ssd->status.char_id ) - { - ps = g->member[i].position; - break; - } - } - if (ps >= 0 && ps < MAX_GUILDPOSITION) - { - memcpy(WBUFP(buf,54), g->name,NAME_LENGTH); - memcpy(WBUFP(buf,78), g->position[ps].name, NAME_LENGTH); - } else { //Assume no guild. - WBUFB(buf,54) = 0; - WBUFB(buf,78) = 0; - } - } else { WBUFB(buf,54) = 0; WBUFB(buf,78) = 0; } @@ -7860,6 +7918,8 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) clif_party_hp(sd); // Show hp after displacement [LuzZza] } + if( sd->state.bg_id ) clif_bg_hp(sd); // BattleGround System + if(map[sd->bl.m].flag.pvp) { if(!battle_config.pk_mode) { // remove pvp stuff for pk_mode [Valaris] if (!map[sd->bl.m].flag.pvp_nocalcrank) @@ -7887,10 +7947,10 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) } } - if(map_flag_gvg(sd->bl.m)) + if( map_flag_gvg(sd->bl.m) || map[sd->bl.m].flag.battleground ) { clif_set0199(sd,3); - if (battle_config.gvg_flee_penalty != 100) + if( battle_config.gvg_flee_penalty != 100 || battle_config.bg_flee_penalty != 100 ) status_calc_bl(&sd->bl, SCB_FLEE); //Apply flee penalty } @@ -8142,7 +8202,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) y = ((RFIFOB(fd,packet_db[sd->packet_ver][cmd].pos[0]+1) & 0x3f) << 4) + (RFIFOB(fd,packet_db[sd->packet_ver][cmd].pos[0] + 2) >> 4); //Set last idle time... [Skotlex] - sd->idletime = last_tick; + pc_update_last_action(sd); unit_walktoxy(&sd->bl, x, y, 4); } @@ -8434,7 +8494,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, } pc_delinvincibletimer(sd); - sd->idletime = last_tick; + pc_update_last_action(sd); unit_attack(&sd->bl, target_id, action_type != 0); break; case 0x02: // sitdown @@ -8794,7 +8854,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) pc_delinvincibletimer(sd); //Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + pc_update_last_action(sd); n = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0])-2; if(n <0 || n >= MAX_INVENTORY) @@ -9307,7 +9367,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) } // Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + pc_update_last_action(sd); if( pc_cant_act(sd) ) return; @@ -9433,7 +9493,7 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, short skil } //Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + pc_update_last_action(sd); if( skillnotok(skillnum, sd) ) return; @@ -10158,9 +10218,11 @@ void clif_parse_GuildCheckMaster(int fd, struct map_session_data *sd) *------------------------------------------*/ void clif_parse_GuildRequestInfo(int fd, struct map_session_data *sd) { - if (!sd->status.guild_id) + if( !sd->status.guild_id && !sd->state.bg_id ) return; - switch(RFIFOL(fd,2)){ + + switch( RFIFOL(fd,2) ) + { case 0: // ギルド基本情報、同盟敵対情報 clif_guild_basicinfo(sd); clif_guild_allianceinfo(sd); @@ -10221,9 +10283,15 @@ void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd) *------------------------------------------*/ void clif_parse_GuildRequestEmblem(int fd,struct map_session_data *sd) { - struct guild* g = guild_search(RFIFOL(fd,2)); - if(g!=NULL) + struct guild* g; + int guild_id = RFIFOL(fd,2); + + if( (g = guild_search(guild_id)) != NULL ) clif_guild_emblem(sd,g); + else if( guild_id == battle_config.bg_guild_id1 ) + clif_bg_emblem(sd, &bg_guild[0]); + else if( guild_id == battle_config.bg_guild_id2 ) + clif_bg_emblem(sd, &bg_guild[1]); } /*========================================== @@ -10300,6 +10368,12 @@ void clif_parse_GuildLeave(int fd,struct map_session_data *sd) clif_displaymessage(fd, msg_txt(228)); return; } + if( sd->state.bg_id ) + { + clif_displaymessage(fd, "You can't leave battleground guilds."); + return; + } + guild_leave(sd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),(char*)RFIFOP(fd,14)); } @@ -10309,8 +10383,8 @@ void clif_parse_GuildLeave(int fd,struct map_session_data *sd) *------------------------------------------*/ void clif_parse_GuildExpulsion(int fd,struct map_session_data *sd) { - if(map[sd->bl.m].flag.guildlock) - { //Guild locked. + if( map[sd->bl.m].flag.guildlock || sd->state.bg_id ) + { // Guild locked. clif_displaymessage(fd, msg_txt(228)); return; } @@ -10346,7 +10420,10 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - guild_send_message(sd, text, textlen); + if( sd->state.bg_id ) + bg_send_message(sd, text, textlen); + else + guild_send_message(sd, text, textlen); } /*========================================== @@ -10432,7 +10509,7 @@ void clif_parse_GuildOpposition(int fd, struct map_session_data *sd) *------------------------------------------*/ void clif_parse_GuildBreak(int fd, struct map_session_data *sd) { - if(map[sd->bl.m].flag.guildlock) + if( map[sd->bl.m].flag.guildlock ) { //Guild locked. clif_displaymessage(fd, msg_txt(228)); return; @@ -12677,6 +12754,217 @@ void clif_readbook(int fd, int book_id, int page) WFIFOSET(fd,10); } +/*------------------------------------------ + * BattleGround Packets + *------------------------------------------*/ +int clif_bg_hp(struct map_session_data *sd) +{ + unsigned char buf[16]; + nullpo_retr(0, sd); + + WBUFW(buf,0)=0x106; + WBUFL(buf,2) = sd->status.account_id; + if( sd->battle_status.max_hp > SHRT_MAX ) + { // To correctly display the %hp bar. [Skotlex] + WBUFW(buf,6) = sd->battle_status.hp/(sd->battle_status.max_hp/100); + WBUFW(buf,8) = 100; + } + else + { + WBUFW(buf,6) = sd->battle_status.hp; + WBUFW(buf,8) = sd->battle_status.max_hp; + } + clif_send(buf, packet_len(0x106), &sd->bl, BG_AREA_WOS); + return 0; +} + +int clif_bg_xy(struct map_session_data *sd) +{ + unsigned char buf[10]; + nullpo_retr(0, sd); + + WBUFW(buf,0)=0x1eb; + WBUFL(buf,2)=sd->status.account_id; + WBUFW(buf,6)=sd->bl.x; + WBUFW(buf,8)=sd->bl.y; + clif_send(buf, packet_len(0x1eb), &sd->bl, BG_SAMEMAP_WOS); + return 0; +} + +int clif_bg_xy_remove(struct map_session_data *sd) +{ + unsigned char buf[10]; + nullpo_retr(0, sd); + + WBUFW(buf,0)=0x1eb; + WBUFL(buf,2)=sd->status.account_id; + WBUFW(buf,6)=-1; + WBUFW(buf,8)=-1; + clif_send(buf,packet_len(0x1eb),&sd->bl,BG_SAMEMAP_WOS); + return 0; +} + +int clif_bg_belonginfo(struct map_session_data *sd) +{ + int fd; + struct guild *g; + nullpo_retr(0, sd); + + if( !sd->state.bg_id || (g = bg_guild_get(sd->state.bg_id)) == NULL ) + return 0; + + fd = sd->fd; + WFIFOHEAD(fd,packet_len(0x16c)); + memset(WFIFOP(fd,0),0,packet_len(0x16c)); + WFIFOW(fd,0) = 0x16c; + WFIFOL(fd,2) = g->guild_id; + WFIFOL(fd,6) = g->emblem_id; + WFIFOL(fd,10) = 0; + memcpy(WFIFOP(fd,19), g->name, NAME_LENGTH); + WFIFOSET(fd,packet_len(0x16c)); + return 1; +} + +int clif_bg_guild_id(struct block_list *bl) +{ + struct battleground_data *bg; + int bg_id; + nullpo_retr(0, bl); + + if( (bg_id = bg_team_get_id(bl)) > 0 && (bg = bg_team_search(bg_id)) != NULL && bg->g ) + return bg->g->guild_id; + else + return status_get_guild_id(bl); +} + +int clif_bg_emblem_id(struct block_list *bl) +{ + struct battleground_data *bg; + int bg_id; + nullpo_retr(0, bl); + + if( (bg_id = bg_team_get_id(bl)) > 0 && (bg = bg_team_search(bg_id)) != NULL && bg->g ) + return bg->g->emblem_id; + else + return status_get_emblem_id(bl); +} + +int clif_bg_emblem(struct map_session_data *sd, struct guild *g) +{ + int fd; + + nullpo_retr(0, sd); + nullpo_retr(0, g); + fd = sd->fd; + + if( g->emblem_len <= 0 ) + return 0; + + 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)); + return 0; +} + +int clif_bg_memberlist(struct map_session_data *sd) +{ + int fd, i, c; + struct battleground_data *bg; + struct map_session_data *psd; + nullpo_retr(0, sd); + + if( (fd = sd->fd) == 0 ) + return 0; + if( !sd->state.bg_id || (bg = bg_team_search(sd->state.bg_id)) == NULL ) + return 0; + + WFIFOHEAD(fd,bg->count * 104 + 4); + WFIFOW(fd,0) = 0x154; + for( i = 0, c = 0; i < bg->count; i++ ) + { + if( (psd = bg->members[i].sd) == 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) = 0; + WFIFOL(fd,c*104+26) = 1; + WFIFOL(fd,c*104+30) = c; + memset(WFIFOP(fd,c*104+34),0,50); + memcpy(WFIFOP(fd,c*104+84),psd->status.name,NAME_LENGTH); + c++; + } + WFIFOW(fd, 2)=c*104+4; + WFIFOSET(fd,WFIFOW(fd,2)); + return 0; +} + +int clif_bg_leave(struct map_session_data *sd, const char *name, const char *mes) +{ + unsigned char buf[128]; + nullpo_retr(0, sd); + + WBUFW(buf,0)=0x15a; + memcpy(WBUFP(buf, 2),name,NAME_LENGTH); + memcpy(WBUFP(buf,26),mes,40); + clif_send(buf,packet_len(0x15a),&sd->bl,BG); + return 0; +} + +int clif_bg_leave_single(struct map_session_data *sd, const char *name, const char *mes) +{ + int fd; + nullpo_retr(0, sd); + + fd = sd->fd; + WFIFOHEAD(fd,66); + WFIFOW(fd,0) = 0x15a; + memcpy(WFIFOP(fd,2), name, NAME_LENGTH); + memcpy(WFIFOP(fd,26), mes, 40); + WFIFOSET(fd,66); + return 0; +} + +int clif_bg_message(struct battleground_data *bg, int account_id, const char *mes, int len) +{ + struct map_session_data *sd; + unsigned char *buf; + + buf = (unsigned char*)aMallocA((len + 4)*sizeof(unsigned char)); + + WBUFW(buf, 0) = 0x17f; + WBUFW(buf, 2) = len + 4; + memcpy(WBUFP(buf,4), mes, len); + + if( (sd = bg_getavailablesd(bg)) != NULL ) + clif_send(buf, WBUFW(buf,2), &sd->bl, BG); + if( buf ) aFree(buf); + return 0; +} + +int clif_bg_expulsion_single(struct map_session_data *sd, const char *name, const char *mes) +{ + int fd; + nullpo_retr(0, sd); + + fd = sd->fd; + WFIFOHEAD(fd, 90); + WFIFOW(fd,0) = 0x15c; + safestrncpy((char*)WFIFOP(fd,2), name, NAME_LENGTH); + safestrncpy((char*)WFIFOP(fd,26), mes, 40); + safestrncpy((char*)WFIFOP(fd,66), "", NAME_LENGTH); + WFIFOSET(fd,90); + return 0; +} + /*========================================== * パケットデバッグ *------------------------------------------*/ diff --git a/src/map/clif.h b/src/map/clif.h index b64d94b48..87c6a2953 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -23,6 +23,7 @@ struct s_vending; struct party; struct party_data; struct guild; +struct battleground_data; struct quest; #include @@ -90,10 +91,17 @@ typedef enum send_target { GUILD_SAMEMAP_WOS, GUILD_AREA, GUILD_AREA_WOS, + GUILD_NOBG, DUEL, DUEL_WOS, CHAT_MAINCHAT, // everyone on main chat SELF, + BG, // BattleGround System + BG_WOS, + BG_SAMEMAP, + BG_SAMEMAP_WOS, + BG_AREA, + BG_AREA_WOS, } send_target; int clif_setip(const char* ip); @@ -330,6 +338,19 @@ int clif_guild_xy(struct map_session_data *sd); int clif_guild_xy_single(int fd, struct map_session_data *sd); int clif_guild_xy_remove(struct map_session_data *sd); +// Battleground +int clif_bg_hp(struct map_session_data *sd); +int clif_bg_xy(struct map_session_data *sd); +int clif_bg_xy_remove(struct map_session_data *sd); +int clif_bg_belonginfo(struct map_session_data *sd); +int clif_bg_guild_id(struct block_list *bl); +int clif_bg_emblem_id(struct block_list *bl); +int clif_bg_emblem(struct map_session_data *sd, struct guild *g); +int clif_bg_memberlist(struct map_session_data *sd); +int clif_bg_leave(struct map_session_data *sd, const char *name, const char *mes); +int clif_bg_leave_single(struct map_session_data *sd, const char *name, const char *mes); +int clif_bg_message(struct battleground_data *bg, int account_id, const char *mes, int len); +int clif_bg_expulsion_single(struct map_session_data *sd, const char *name, const char *mes); // atcommand int clif_displaymessage(const int fd,const char* mes); diff --git a/src/map/guild.c b/src/map/guild.c index 8f9137943..5296f5970 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -373,12 +373,11 @@ int guild_send_xy_timer_sub(DBKey key,void *data,va_list ap) for(i=0;imax_member;i++){ //struct map_session_data* sd = g->member[i].sd; struct map_session_data* sd = map_charid2sd(g->member[i].char_id); // temporary crashfix - if( sd != NULL ) { - if(sd->guild_x!=sd->bl.x || sd->guild_y!=sd->bl.y){ - clif_guild_xy(sd); - sd->guild_x=sd->bl.x; - sd->guild_y=sd->bl.y; - } + if( sd != NULL && (sd->guild_x != sd->bl.x || sd->guild_y != sd->bl.y) && !sd->state.bg_id ) + { + clif_guild_xy(sd); + sd->guild_x = sd->bl.x; + sd->guild_y = sd->bl.y; } } return 0; diff --git a/src/map/map.c b/src/map/map.c index 5dbdaae04..f80b9c226 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -31,6 +31,7 @@ #include "party.h" #include "unit.h" #include "battle.h" +#include "battleground.h" #include "script.h" #include "mapreg.h" #include "guild.h" @@ -1514,6 +1515,8 @@ int map_quit(struct map_session_data *sd) if (sd->npc_timer_id != -1) //Cancel the event timer. npc_timerevent_quit(sd); + if( sd->state.bg_id ) + bg_team_leave(sd,1); npc_script_event(sd, NPCE_LOGOUT); //Unit_free handles clearing the player related data, @@ -3272,6 +3275,7 @@ void do_final(void) do_final_skill(); do_final_status(); do_final_unit(); + do_final_battleground(); map_db->destroy(map_db, map_db_final); @@ -3504,6 +3508,7 @@ int do_init(int argc, char *argv[]) do_init_mercenary(); do_init_npc(); do_init_unit(); + do_init_battleground(); #ifndef TXT_ONLY /* mail system [Valaris] */ if (log_config.sql_logs) log_sql_init(); diff --git a/src/map/map.h b/src/map/map.h index 02314318e..8fcfc6195 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -157,13 +157,13 @@ enum { #define DEFAULT_AUTOSAVE_INTERVAL 5*60*1000 //Specifies maps where players may hit each other -#define map_flag_vs(m) (map[m].flag.pvp || map[m].flag.gvg_dungeon || map[m].flag.gvg || ((agit_flag || agit2_flag) && map[m].flag.gvg_castle)) +#define map_flag_vs(m) (map[m].flag.pvp || map[m].flag.gvg_dungeon || map[m].flag.gvg || ((agit_flag || agit2_flag) && map[m].flag.gvg_castle) || map[m].flag.battleground) //Specifies maps that have special GvG/WoE restrictions #define map_flag_gvg(m) (map[m].flag.gvg || ((agit_flag || agit2_flag) && map[m].flag.gvg_castle)) //Specifies if the map is tagged as GvG/WoE (regardless of agit_flag status) #define map_flag_gvg2(m) (map[m].flag.gvg || map[m].flag.gvg_castle) // No Kill Steal Protection -#define map_flag_ks(m) (map[m].flag.town || map[m].flag.pvp || map[m].flag.gvg) +#define map_flag_ks(m) (map[m].flag.town || map[m].flag.pvp || map[m].flag.gvg || map[m].flag.battleground) //This stackable implementation does not means a BL can be more than one type at a time, but it's //meant to make it easier to check for multiple types at a time on invocations such as map_foreach* calls [Skotlex] @@ -434,6 +434,7 @@ struct map_data { unsigned gvg : 1; // Now it identifies gvg versus maps that are active 24/7 unsigned gvg_dungeon : 1; // Celest unsigned gvg_noparty : 1; + unsigned battleground : 1; // [BattleGround System] unsigned nozenypenalty : 1; unsigned notrade : 1; unsigned noskill : 1; diff --git a/src/map/mob.c b/src/map/mob.c index 2691dc45f..634df71ab 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -661,6 +661,51 @@ int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobnam return md->bl.id; } +/*========================================== + * Summoning BattleGround [Zephyrus] + *------------------------------------------*/ +int mob_spawn_bg(const char* mapname, short x, short y, const char* mobname, int class_, const char* event, int bg_id) +{ + struct mob_data *md = NULL; + struct spawn_data data; + int m; + + if( (m = map_mapname2mapid(mapname)) < 0 ) + { + ShowWarning("mob_spawn_bg: Map [%s] not found.\n", mapname); + return 0; + } + + memset(&data, 0, sizeof(struct spawn_data)); + data.m = m; + data.num = 1; + if( class_ <= 0 ) + { + class_ = mob_get_random_id(-class_-1,1,99); + if( !class_ ) return 0; + } + + data.class_ = class_; + if( (x <= 0 || y <= 0) && !map_search_freecell(NULL, m, &x, &y, -1,-1, 0) ) + { + ShowWarning("mob_spawn_bg: Couldn't locate a spawn cell for guardian class %d (bg_id %d) at map %s\n",class_, bg_id, map[m].name); + return 0; + } + + data.x = x; + data.y = y; + safestrncpy(data.name, mobname, sizeof(data.name)); + safestrncpy(data.eventname, event, sizeof(data.eventname)); + if( !mob_parse_dataset(&data) ) + return 0; + + md = mob_spawn_dataset(&data); + mob_spawn(md); + md->state.bg_id = bg_id; // BG Team ID + + return md->bl.id; +} + /*========================================== * Reachability to a Specification ID existence place * state indicates type of 'seek' mob should do: diff --git a/src/map/mob.h b/src/map/mob.h index bef8324d4..472e0bc54 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -112,6 +112,8 @@ struct mob_data { int provoke_flag; // Celest unsigned npc_killmonster: 1; //for new killmonster behavior unsigned rebirth: 1; // NPC_Rebirth used + unsigned inmunity: 1; // Monster Cannot be attacked + unsigned int bg_id; // BattleGround System } state; struct guardian_data* guardian_data; struct { @@ -208,6 +210,7 @@ int mob_once_spawn_area(struct map_session_data* sd,int m,int x0,int y0,int x1,i bool mob_ksprotected (struct block_list *src, struct block_list *target); int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobname, int class_, const char* event, int guardian, bool has_index); // Spawning Guardians [Valaris] +int mob_spawn_bg(const char* mapname, short x, short y, const char* mobname, int class_, const char* event, int bg_id); int mob_guardian_guildchange(struct block_list *bl,va_list ap); //Change Guardian's ownership. [Skotlex] int mob_randomwalk(struct mob_data *md,unsigned int tick); @@ -227,6 +230,7 @@ void mob_heal(struct mob_data *md,unsigned int heal); #define mob_stop_walking(md, type) unit_stop_walking(&(md)->bl, type) #define mob_stop_attack(md) unit_stop_attack(&(md)->bl) +#define mob_is_battleground(md) ( map[(md)->bl.m].flag.battleground && ((md)->class_ == 1906 || ((md)->class_ >= 1909 && (md)->class_ <= 1915)) ) void mob_clear_spawninfo(); int do_init_mob(void); diff --git a/src/map/npc.c b/src/map/npc.c index 1014cc832..0a37986c8 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2651,13 +2651,18 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con map[m].flag.nozenypenalty=state; } else if (!strcmpi(w3,"pvp")) { - map[m].flag.pvp=state; - if (state) { - if (map[m].flag.gvg || map[m].flag.gvg_dungeon || map[m].flag.gvg_castle) - ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing GvG flags from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); - map[m].flag.gvg=0; - map[m].flag.gvg_dungeon=0; - map[m].flag.gvg_castle=0; + map[m].flag.pvp = state; + if( state && (map[m].flag.gvg || map[m].flag.gvg_dungeon || map[m].flag.gvg_castle) ) + { + map[m].flag.gvg = 0; + map[m].flag.gvg_dungeon = 0; + map[m].flag.gvg_castle = 0; + ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing GvG flags from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); + } + if( state && map[m].flag.battleground ) + { + map[m].flag.battleground = 0; + ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing BattleGround flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); } } else if (!strcmpi(w3,"pvp_noparty")) @@ -2697,12 +2702,17 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con else if (!strcmpi(w3,"pvp_nocalcrank")) map[m].flag.pvp_nocalcrank=state; else if (!strcmpi(w3,"gvg")) { - map[m].flag.gvg=state; - if (state && map[m].flag.pvp) + map[m].flag.gvg = state; + if( state && map[m].flag.pvp ) { - map[m].flag.pvp=0; + map[m].flag.pvp = 0; ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing PvP flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); } + if( state && map[m].flag.battleground ) + { + map[m].flag.battleground = 0; + ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing BattleGround flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); + } } else if (!strcmpi(w3,"gvg_noparty")) map[m].flag.gvg_noparty=state; @@ -2714,6 +2724,21 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con map[m].flag.gvg_castle=state; if (state) map[m].flag.pvp=0; } + else if (!strcmpi(w3,"battleground")) { + map[m].flag.battleground = state; + if( state && map[m].flag.pvp ) + { + map[m].flag.pvp = 0; + ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing PvP flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); + } + if( state && (map[m].flag.gvg || map[m].flag.gvg_dungeon || map[m].flag.gvg_castle) ) + { + map[m].flag.gvg = 0; + map[m].flag.gvg_dungeon = 0; + map[m].flag.gvg_castle = 0; + ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing GvG flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); + } + } else if (!strcmpi(w3,"noexppenalty")) map[m].flag.noexppenalty=state; else if (!strcmpi(w3,"nozenypenalty")) diff --git a/src/map/pc.c b/src/map/pc.c index a4ed7a62e..00827a055 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -14,6 +14,7 @@ #include "atcommand.h" // get_atcommand_level() #include "battle.h" // battle_config +#include "battleground.h" #include "chrif.h" #include "clif.h" #include "date.h" // is_day_of_*() @@ -81,6 +82,28 @@ int pc_class2idx(int class_) { return class_; } +void pc_update_last_action(struct map_session_data *sd) +{ + struct battleground_data *bg; + int i; + + sd->idletime = last_tick; + if( sd->state.bg_id && (bg = bg_team_search(sd->state.bg_id)) != NULL ) + { // Update Battleground Idle Timer + ARR_FIND(0, MAX_BG_MEMBERS, i, bg->members[i].sd == sd); + if( i == MAX_BG_MEMBERS) + return; + + if( bg->members[i].afk && bg->g ) + { + char output[128]; + sprintf(output, "%s : %s is no longer away...", bg->g->name, sd->status.name); + clif_bg_message(bg, 0, output, strlen(output)); + bg->members[i].afk = 0; + } + } +} + int pc_isGM(struct map_session_data* sd) { return sd->gmlevel; @@ -3740,6 +3763,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y skill_clear_unitgroup(&sd->bl); party_send_dot_remove(sd); //minimap dot fix [Kevin] guild_send_dot_remove(sd); + bg_send_dot_remove(sd); if (sd->regen.state.gc) sd->regen.state.gc = 0; } @@ -5139,10 +5163,12 @@ void pc_respawn(struct map_session_data* sd, uint8 clrtype) { if( !pc_isdead(sd) ) return; // not applicable + if( sd->state.bg_id && bg_member_respawn(sd) ) + return; // member revived by battleground pc_setstand(sd); pc_setrestartvalue(sd,3); - if(pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, clrtype)) + if( pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, clrtype) ) clif_resurrection(&sd->bl, 1); //If warping fails, send a normal stand up packet. } @@ -5231,6 +5257,13 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) pc_setglobalreg(sd,"PC_DIE_COUNTER",sd->die_counter+1); pc_setglobalreg(sd,"killerrid",src?src->id:0); + if( sd->state.bg_id ) + { + struct battleground_data *bg; + if( (bg = bg_team_search(sd->state.bg_id)) != NULL && bg->die_event[0] ) + npc_event(sd, bg->die_event, 0); + } + npc_script_event(sd,NPCE_DIE); if ( sd && sd->spiritball && (sd->class_&MAPID_BASEMASK)==MAPID_GUNSLINGER ) // maybe also monks' spiritballs ? @@ -5436,30 +5469,42 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) } // pvp // disable certain pvp functions on pk_mode [Valaris] - if (map[sd->bl.m].flag.gvg_dungeon || - (map[sd->bl.m].flag.pvp && !battle_config.pk_mode && !map[sd->bl.m].flag.pvp_nocalcrank)) - { //Pvp points always take effect on gvg_dungeon maps. + if( map[sd->bl.m].flag.gvg_dungeon || (map[sd->bl.m].flag.pvp && !battle_config.pk_mode && !map[sd->bl.m].flag.pvp_nocalcrank) ) + { // Pvp points always take effect on gvg_dungeon maps. sd->pvp_point -= 5; sd->pvp_lost++; - if (src && src->type == BL_PC) { + if( src && src->type == BL_PC ) + { struct map_session_data *ssd = (struct map_session_data *)src; ssd->pvp_point++; ssd->pvp_won++; } - if( sd->pvp_point < 0 ){ + if( sd->pvp_point < 0 ) + { sd->pvp_point=0; add_timer(tick+1000, pc_respawn_timer,sd->bl.id,0); return 1|8; } } //GvG - if(map_flag_gvg(sd->bl.m)){ - add_timer(tick+1000, pc_respawn_timer,sd->bl.id,0); + if( map_flag_gvg(sd->bl.m) ) + { + add_timer(tick+1000, pc_respawn_timer, sd->bl.id, 0); return 1|8; } + else if( sd->state.bg_id ) + { + struct battleground_data *bg = bg_team_search(sd->state.bg_id); + if( bg && bg->mapindex > 0 ) + { // Respawn by BG + add_timer(tick+1000, pc_respawn_timer, sd->bl.id, 0); + return 1|8; + } + } + //Reset "can log out" tick. - if (battle_config.prevent_logout) + if( battle_config.prevent_logout ) sd->canlog_tick = gettick() - battle_config.prevent_logout; return 1; } diff --git a/src/map/pc.h b/src/map/pc.h index a22f0c5ad..e04038943 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -115,6 +115,7 @@ struct map_session_data { unsigned noks : 3; // [Zeph Kill Steal Protection] bool changemap; struct guild *gmaster_flag; + unsigned int bg_id; } state; struct { unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; @@ -715,6 +716,8 @@ extern int night_timer_tid; int map_day_timer(int tid, unsigned int tick, int id, intptr data); // by [yor] int map_night_timer(int tid, unsigned int tick, int id, intptr data); // by [yor] +void pc_update_last_action(struct map_session_data *sd); + // Rental System void pc_inventory_rentals(struct map_session_data *sd); int pc_inventory_rental_clear(struct map_session_data *sd); diff --git a/src/map/script.c b/src/map/script.c index 05779ed9e..f69dc2665 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -35,6 +35,7 @@ #include "status.h" #include "chat.h" #include "battle.h" +#include "battleground.h" #include "party.h" #include "guild.h" #include "atcommand.h" @@ -4065,6 +4066,38 @@ BUILDIN_FUNC(areawarp) return 0; } +/*========================================== + * areapercentheal ,,,,,, + *------------------------------------------*/ +static int buildin_areapercentheal_sub(struct block_list *bl,va_list ap) +{ + int hp, sp; + hp = va_arg(ap, int); + sp = va_arg(ap, int); + pc_percentheal((TBL_PC *)bl,hp,sp); + return 0; +} +BUILDIN_FUNC(areapercentheal) +{ + int hp,sp,m; + const char *mapname; + int x0,y0,x1,y1; + + mapname=script_getstr(st,2); + x0=script_getnum(st,3); + y0=script_getnum(st,4); + x1=script_getnum(st,5); + y1=script_getnum(st,6); + hp=script_getnum(st,8); + sp=script_getnum(st,9); + + if( (m=map_mapname2mapid(mapname))< 0) + return 0; + + map_foreachinarea(buildin_areapercentheal_sub,m,x0,y0,x1,y1,BL_PC,hp,sp); + return 0; +} + /*========================================== * warpchar [LuzZza] * Useful for warp one player from @@ -5782,6 +5815,7 @@ BUILDIN_FUNC(getcharid) case 1: script_pushint(st,sd->status.party_id); break; case 2: script_pushint(st,sd->status.guild_id); break; case 3: script_pushint(st,sd->status.account_id); break; + case 4: script_pushint(st,sd->state.bg_id); break; default: ShowError("buildin_getcharid: invalid parameter (%d).\n", num); script_pushint(st,0); @@ -13277,6 +13311,228 @@ BUILDIN_FUNC(setqueststatus) return 0; } +/*========================================== + * BattleGround System + *------------------------------------------*/ +BUILDIN_FUNC(waitingroom2bg) +{ + struct npc_data *nd; + struct chat_data *cd; + const char *map_name, *ev = "", *dev = ""; + int x, y, i, mapindex = 0, guild_index, bg_id, n; + struct map_session_data *sd; + + if( script_hasdata(st,8) ) + nd = npc_name2id(script_getstr(st,8)); + else + 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 0; + } + + map_name = script_getstr(st,2); + if( strcmp(map_name,"-") != 0 ) + { + mapindex = mapindex_name2id(map_name); + if( mapindex == 0 ) + { // Invalid Map + script_pushint(st,0); + return 0; + } + } + + 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, 1); + if( (bg_id = bg_create(mapindex, x, y, guild_index, ev, dev)) == 0 ) + { // Creation failed + script_pushint(st,0); + return 0; + } + + n = cd->users; + for( i = 0; i < n && i < MAX_BG_MEMBERS; i++ ) + { + if( (sd = cd->usersd[i]) != NULL && bg_team_join(bg_id, sd) ) + mapreg_setreg(add_str("$@arenamembers") + (i<<24), sd->bl.id); + else + mapreg_setreg(add_str("$@arenamembers") + (i<<24), 0); + } + + mapreg_setreg(add_str("$@arenamembersnum"), i); + script_pushint(st,bg_id); + return 0; +} + +BUILDIN_FUNC(waitingroom2bg_single) +{ + const char* map_name; + struct npc_data *nd; + struct chat_data *cd; + struct map_session_data *sd; + int x, y, mapindex, bg_id; + + bg_id = script_getnum(st,2); + map_name = script_getstr(st,3); + if( (mapindex = mapindex_name2id(map_name)) == 0 ) + return 0; // 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 ) + return 0; + + if( (sd = cd->usersd[0]) == NULL ) + return 0; + + if( bg_team_join(bg_id, sd) ) + { + pc_setpos(sd, mapindex, x, y, 3); + script_pushint(st,1); + } + else + script_pushint(st,0); + + return 0; +} + +BUILDIN_FUNC(bg_warp) +{ + int x, y, mapindex, bg_id; + const char* map_name; + + bg_id = script_getnum(st,2); + map_name = script_getstr(st,3); + if( (mapindex = mapindex_name2id(map_name)) == 0 ) + return 0; // Invalid Map + x = script_getnum(st,4); + y = script_getnum(st,5); + bg_team_warp(bg_id, mapindex, x, y); + return 0; +} + +BUILDIN_FUNC(bg_monster) +{ + int class_ = 0, x = 0, y = 0, bg_id = 0; + const char *str,*map, *evt=""; + + bg_id = script_getnum(st,2); + map = script_getstr(st,3); + x = script_getnum(st,4); + y = script_getnum(st,5); + str = script_getstr(st,6); + class_ = script_getnum(st,7); + if( script_hasdata(st,8) ) evt = script_getstr(st,8); + check_event(st, evt); + script_pushint(st, mob_spawn_bg(map,x,y,str,class_,evt,bg_id)); + return 0; +} + +BUILDIN_FUNC(setmobdata) +{ + struct mob_data *md; + struct block_list *mbl; + int id = script_getnum(st,2), + type = script_getnum(st,3), + value = script_getnum(st,4); + + if( (mbl = map_id2bl(id)) == NULL || mbl->type != BL_MOB ) + return 0; + md = (TBL_MOB *)mbl; + switch( type ) + { + case 0: md->state.inmunity = value > 0 ? 1 : 0; break; + default: + ShowError("script:setmobdata: unknown data identifier %d\n", type); + return 1; + } + + return 0; +} + +BUILDIN_FUNC(bg_leave) +{ + struct map_session_data *sd = script_rid2sd(st); + if( sd == NULL || !sd->state.bg_id ) + return 0; + + bg_team_leave(sd,0); + return 0; +} + +BUILDIN_FUNC(bg_destroy) +{ + int bg_id = script_getnum(st,2); + bg_team_delete(bg_id); + return 0; +} + +BUILDIN_FUNC(bg_getareausers) +{ + const char *str; + int m, x0, y0, x1, y1, bg_id; + int i = 0, c = 0; + struct battleground_data *bg = NULL; + struct map_session_data *sd; + + bg_id = script_getnum(st,2); + str = script_getstr(st,3); + + if( (bg = bg_team_search(bg_id)) == NULL || (m = map_mapname2mapid(str)) < 0 ) + { + script_pushint(st,0); + return 0; + } + + 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 = bg->members[i].sd) == NULL ) + continue; + 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 0; +} + +BUILDIN_FUNC(bg_get_data) +{ + struct battleground_data *bg; + int bg_id = script_getnum(st,2), + type = script_getnum(st,3); + + if( (bg = bg_team_search(bg_id)) == NULL ) + { + script_pushint(st,0); + return 0; + } + + switch( type ) + { + case 0: script_pushint(st, bg->count); break; + default: + ShowError("script:bg_get_data: unknown data identifier %d\n", type); + break; + } + + return 0; +} // declarations that were supposed to be exported from npc_chat.c #ifdef PCRE_SUPPORT @@ -13637,5 +13893,16 @@ struct script_function buildin_func[] = { BUILDIN_DEF(agitstart2,""), BUILDIN_DEF(agitend2,""), BUILDIN_DEF(agitcheck2,""), + // BattleGround + BUILDIN_DEF(waitingroom2bg,"siiiss?"), + BUILDIN_DEF(waitingroom2bg_single,"isiis"), + BUILDIN_DEF(bg_warp,"isii"), + BUILDIN_DEF(bg_monster,"isiisi*"), + BUILDIN_DEF(bg_leave,""), + BUILDIN_DEF(bg_destroy,"i"), + BUILDIN_DEF(areapercentheal,"siiiiii"), + BUILDIN_DEF(setmobdata,"iii"), + BUILDIN_DEF(bg_get_data,"ii"), + BUILDIN_DEF(bg_getareausers,"isiiii"), {NULL,NULL,NULL}, }; diff --git a/src/map/skill.c b/src/map/skill.c index a1fe80c06..95783ed5e 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -22,6 +22,7 @@ #include "mob.h" #include "npc.h" #include "battle.h" +#include "battleground.h" #include "party.h" #include "itemdb.h" #include "script.h" @@ -347,7 +348,7 @@ int skillnotok (int skillid, struct map_session_data *sd) return 1; if(map_flag_gvg(m) && skill_get_nocast (skillid) & 4) return 1; - if((agit_flag || agit2_flag) && skill_get_nocast (skillid) & 8) + if(map[m].flag.battleground && skill_get_nocast (skillid) & 8) return 1; if(map[m].flag.restricted && map[m].zone && skill_get_nocast (skillid) & (8*map[m].zone)) return 1; @@ -1278,7 +1279,7 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in nullpo_retr(0, src); - if (src != target && map_flag_gvg(target->m)) + if (src != target && (map_flag_gvg(target->m) || map[target->m].flag.battleground)) return 0; //No knocking back in WoE if (count == 0) return 0; //Actual knockback distance is 0. @@ -2417,7 +2418,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int unsigned int dir = map_calc_dir(bl, src->x, src->y); // teleport to target (if not on WoE grounds) - if( !map_flag_gvg(src->m) && unit_movepos(src, bl->x, bl->y, 0, 1) ) + if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground && unit_movepos(src, bl->x, bl->y, 0, 1) ) clif_slide(src, bl->x, bl->y); // cause damage and knockback if the path to target was a straight one @@ -2847,7 +2848,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int sc_start(src,SC_HIDING,100,skilllv,skill_get_time(skillid,skilllv)); break; case NJ_KIRIKAGE: - if (!map_flag_gvg(src->m)) + if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground ) { //You don't move on GVG grounds. short x, y; map_search_freecell(bl, 0, &x, &y, 1, 1, 0); @@ -2980,8 +2981,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in int heal = skill_calc_heal(src, bl, skilllv); int heal_get_jobexp; - if( status_isimmune(bl) || (dstmd && dstmd->class_ == MOBID_EMPERIUM) ) + if( status_isimmune(bl) ) heal=0; + if( dstmd && (dstmd->class_ == MOBID_EMPERIUM || mob_is_battleground(dstmd)) ) + heal=0; // Emperium - BattleGround Mobs cannot be Healed if( sd ) { if( (i = pc_skillheal_bonus(sd, skillid)) ) @@ -3053,7 +3056,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; case ALL_RESURRECTION: - if(sd && map_flag_gvg(bl->m)) + if(sd && (map_flag_gvg(bl->m) || map[bl->m].flag.battleground)) { //No reviving in WoE grounds! clif_skill_fail(sd,skillid,0,0); break; @@ -5018,8 +5021,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case CG_TAROTCARD: { int eff, count = -1; - if (rand() % 100 > skilllv * 8) { - if (sd) clif_skill_fail(sd,skillid,0,0); + if( rand() % 100 > skilllv * 8 || (dstmd && ((dstmd->guardian_data && dstmd->class_ == MOBID_EMPERIUM) || mob_is_battleground(dstmd))) ) + { + if( sd ) + clif_skill_fail(sd,skillid,0,0); + map_freeblock_unlock(); return 0; } @@ -5980,7 +5986,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk break; case NJ_SHADOWJUMP: { - if (!map_flag_gvg(src->m)) + if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground ) { //You don't move on GVG grounds. unit_movepos(src, x, y, 1, 0); clif_slide(src,x,y); @@ -6479,7 +6485,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli case HT_FREEZINGTRAP: case MA_FREEZINGTRAP: case HT_BLASTMINE: - if( map_flag_gvg(src->m) ) + if( map_flag_gvg(src->m) || map[src->m].flag.battleground ) limit *= 4; // longer trap times in WOE [celest] if( battle_config.vs_traps_bctall && map_flag_vs(src->m) && (src->type&battle_config.vs_traps_bctall) ) target = BCT_ALL; @@ -7015,6 +7021,9 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns else { int heal = sg->val2; + struct mob_data *md = BL_CAST(BL_MOB, bl); + if( md && mob_is_battleground(md) ) + break; if( tstatus->hp >= tstatus->max_hp ) break; if( tsc ) @@ -8629,7 +8638,7 @@ int skill_delayfix (struct block_list *bl, int skill_id, int skill_lv) time /=2; break; case AS_SONICBLOW: - if (!map_flag_gvg(bl->m) && sc->data[SC_SPIRIT]->val2 == SL_ASSASIN) + if (!map_flag_gvg(bl->m) && !map[bl->m].flag.battleground && sc->data[SC_SPIRIT]->val2 == SL_ASSASIN) time /= 2; break; } @@ -9668,6 +9677,7 @@ struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count, group->src_id = src->id; group->party_id = status_get_party_id(src); group->guild_id = status_get_guild_id(src); + group->bg_id = bg_team_get_id(src); group->group_id = skill_get_new_group_id(); group->unit = (struct skill_unit *)aCalloc(count,sizeof(struct skill_unit)); group->unit_count = count; diff --git a/src/map/skill.h b/src/map/skill.h index cb7656878..6d32e449b 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -125,6 +125,7 @@ struct skill_unit_group { int src_id; int party_id; int guild_id; + int bg_id; int map; int target_flag; //Holds BCT_* flag for battle_check_target int bl_flag; //Holds BL_* flag for map_foreachin* functions diff --git a/src/map/status.c b/src/map/status.c index f7da7d505..9acc9da02 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -686,8 +686,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s if ((sce=sc->data[SC_ENDURE]) && !sce->val4) { //Endure count is only reduced by non-players on non-gvg maps. //val4 signals infinite endure. [Skotlex] - if (src && src->type != BL_PC && !map_flag_gvg(target->m) - && --(sce->val2) < 0) + if (src && src->type != BL_PC && !map_flag_gvg(target->m) && !map[target->m].flag.battleground && --(sce->val2) < 0) status_change_end(target, SC_ENDURE, -1); } if ((sce=sc->data[SC_GRAVITATION]) && sce->val3 == BCT_SELF) @@ -3614,8 +3613,13 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change static signed short status_calc_flee(struct block_list *bl, struct status_change *sc, int flee) { - if (bl->type == BL_PC && map_flag_gvg(bl->m)) //GVG grounds flee penalty, placed here because it's "like" a status change. [Skotlex] - flee -= flee * battle_config.gvg_flee_penalty/100; + if( bl->type == BL_PC ) + { + if( map_flag_gvg(bl->m) ) + flee -= flee * battle_config.gvg_flee_penalty/100; + else if( map[bl->m].flag.battleground ) + flee -= flee * battle_config.bg_flee_penalty/100; + } if(!sc || !sc->count) return cap_value(flee,1,SHRT_MAX); @@ -4025,14 +4029,14 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * static unsigned short status_calc_dmotion(struct block_list *bl, struct status_change *sc, int dmotion) { - if(!sc || !sc->count || map_flag_gvg(bl->m)) + if( !sc || !sc->count || map_flag_gvg(bl->m) || map[bl->m].flag.battleground ) return cap_value(dmotion,0,USHRT_MAX); - if (sc->data[SC_ENDURE]) + if( sc->data[SC_ENDURE] ) return 0; - if (sc->data[SC_CONCENTRATION]) + if( sc->data[SC_CONCENTRATION] ) return 0; - if(sc->data[SC_RUN]) + if( sc->data[SC_RUN] ) return 0; return (unsigned short)cap_value(dmotion,0,USHRT_MAX); @@ -4777,11 +4781,11 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( status_isdead(bl) ) return 0; - if( bl->type == BL_MOB ) + if( bl->type == BL_MOB && type != SC_SAFETYWALL && type != SC_PNEUMA ) { struct mob_data *md = BL_CAST(BL_MOB,bl); - if( md->class_ == MOBID_EMPERIUM && type != SC_SAFETYWALL && type != SC_PNEUMA ) - return 0; //Emperium can't be afflicted by status changes + if( md->class_ == MOBID_EMPERIUM || mob_is_battleground(md) ) + return 0; //Emperium/BG Monsters can't be afflicted by status changes } sd = BL_CAST(BL_PC, bl); @@ -5180,7 +5184,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_ENDURE: val2 = 7; // Hit-count [Celest] - if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !val4 ) + if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground && !val4 ) { struct map_session_data *tsd; if( sd ) @@ -5473,7 +5477,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_ROGUE) val3 -= 40; val4 = 10+val1*2; //SP cost. - if (map_flag_gvg(bl->m)) val4 *= 5; + if (map_flag_gvg(bl->m) || map[bl->m].flag.battleground) val4 *= 5; break; case SC_CLOAKING: if (!sd) //Monsters should be able to walk with no penalties. [Skotlex] @@ -5772,7 +5776,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val { // Inherits Status From Source const enum sc_type types[] = { SC_AUTOGUARD, SC_DEFENDER, SC_REFLECTSHIELD, SC_ENDURE }; enum sc_type type2; - int i = map_flag_gvg(bl->m)?2:3; + int i = (map_flag_gvg(bl->m) || map[bl->m].flag.battleground)?2:3; while( i >= 0 ) { type2 = types[i]; diff --git a/src/map/unit.c b/src/map/unit.c index 7260930fe..dce211fc9 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -20,6 +20,7 @@ #include "guild.h" #include "status.h" #include "battle.h" +#include "battleground.h" #include "chat.h" #include "trade.h" #include "vending.h" @@ -1585,7 +1586,7 @@ int unit_skillcastcancel(struct block_list *bl,int type) return 0; if (sd && (sd->special_state.no_castcancel2 || - (sd->special_state.no_castcancel && !map_flag_gvg(bl->m)))) //fixed flags being read the wrong way around [blackhole89] + (sd->special_state.no_castcancel && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground))) //fixed flags being read the wrong way around [blackhole89] return 0; } @@ -1792,6 +1793,7 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l } party_send_dot_remove(sd);//minimap dot fix [Kevin] guild_send_dot_remove(sd); + bg_send_dot_remove(sd); if( map[bl->m].users <= 0 || sd->state.debug_remove_map ) {// this is only place where map users is decreased, if the mobs were removed too soon then this function was executed too many times [FlavioJS] diff --git a/vcproj-8/map-server_sql.vcproj b/vcproj-8/map-server_sql.vcproj index 484876763..9cbc76e50 100644 --- a/vcproj-8/map-server_sql.vcproj +++ b/vcproj-8/map-server_sql.vcproj @@ -95,6 +95,9 @@ + @@ -186,6 +189,9 @@ + @@ -353,6 +359,14 @@ RelativePath="..\src\map\battle.h" > + + + + diff --git a/vcproj-8/map-server_txt.vcproj b/vcproj-8/map-server_txt.vcproj index 4bf415daf..7b33d0c9d 100644 --- a/vcproj-8/map-server_txt.vcproj +++ b/vcproj-8/map-server_txt.vcproj @@ -218,6 +218,14 @@ RelativePath="..\src\map\battle.h" > + + + + -- cgit v1.2.3-60-g2f50