Selaa lähdekoodia

- Fixed item Nemesis.
- Fixed Tarot Card being used on Emperium.
- First Part of BattleGround Implementation (please wait).

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@13550 54d463be-8e91-2dee-dedb-b68131a5f0ec

zephyrus 16 vuotta sitten
vanhempi
commit
e9153a3c17
21 muutettua tiedostoa jossa 1044 lisäystä ja 215 poistoa
  1. 1 1
      db/item_db.txt
  2. 2 2
      src/map/Makefile.in
  3. 101 26
      src/map/battle.c
  4. 12 0
      src/map/battle.h
  5. 421 133
      src/map/clif.c
  6. 21 0
      src/map/clif.h
  7. 5 6
      src/map/guild.c
  8. 5 0
      src/map/map.c
  9. 3 2
      src/map/map.h
  10. 45 0
      src/map/mob.c
  11. 4 0
      src/map/mob.h
  12. 35 10
      src/map/npc.c
  13. 54 9
      src/map/pc.c
  14. 3 0
      src/map/pc.h
  15. 267 0
      src/map/script.c
  16. 21 11
      src/map/skill.c
  17. 1 0
      src/map/skill.h
  18. 18 14
      src/map/status.c
  19. 3 1
      src/map/unit.c
  20. 14 0
      vcproj-8/map-server_sql.vcproj
  21. 8 0
      vcproj-8/map-server_txt.vcproj

+ 1 - 1
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#

+ 2 - 2
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
 

+ 101 - 26
src/map/battle.c

@@ -24,6 +24,7 @@
 #include "guild.h"
 #include "party.h"
 #include "battle.h"
+#include "battleground.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -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,        },
 };
 
 

+ 12 - 0
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);

+ 421 - 133
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;i<MAX_GUILDALLIANCE;i++){
@@ -6225,14 +6278,13 @@ int clif_guild_memberlist(struct map_session_data *sd)
 	int fd;
 	int i,c;
 	struct guild *g;
-
 	nullpo_retr(0, sd);
 
-	fd=sd->fd;
-	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;i<MAX_GUILDPOSITION;i++){
@@ -6292,11 +6346,13 @@ int clif_guild_positioninfolist(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 * 16 + 4);
 	WFIFOW(fd, 0)=0x160;
 	for(i=0;i<MAX_GUILDPOSITION;i++){
@@ -6356,14 +6412,13 @@ int clif_guild_memberpositionchanged(struct guild *g,int idx)
 int clif_guild_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)
+	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;i<MAX_GUILDEXPULSION;i++){
@@ -6572,7 +6630,7 @@ int clif_guild_message(struct guild *g,int account_id,const char *mes,int len)
 	memcpy(WBUFP(buf,4), mes, len);
 
 	if ((sd = guild_getavailablesd(g)) != NULL)
-		clif_send(buf, WBUFW(buf,2), &sd->bl, 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;
+}
+
 /*==========================================
  * パケットデバッグ
  *------------------------------------------*/

+ 21 - 0
src/map/clif.h

@@ -23,6 +23,7 @@ struct s_vending;
 struct party;
 struct party_data;
 struct guild;
+struct battleground_data;
 struct quest;
 #include <stdarg.h>
 
@@ -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);

+ 5 - 6
src/map/guild.c

@@ -373,12 +373,11 @@ int guild_send_xy_timer_sub(DBKey key,void *data,va_list ap)
 	for(i=0;i<g->max_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;

+ 5 - 0
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();

+ 3 - 2
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;

+ 45 - 0
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:

+ 4 - 0
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);

+ 35 - 10
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"))

+ 54 - 9
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;
 }

+ 3 - 0
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);

+ 267 - 0
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 <map>,<x1>,<y1>,<x2>,<y2>,<hp>,<sp>
+ *------------------------------------------*/
+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},
 };

+ 21 - 11
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;

+ 1 - 0
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

+ 18 - 14
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];

+ 3 - 1
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]

+ 14 - 0
vcproj-8/map-server_sql.vcproj

@@ -95,6 +95,9 @@
 			<Tool
 				Name="VCAppVerifierTool"
 			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
 			<Tool
 				Name="VCPostBuildEventTool"
 			/>
@@ -186,6 +189,9 @@
 			<Tool
 				Name="VCAppVerifierTool"
 			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
 			<Tool
 				Name="VCPostBuildEventTool"
 			/>
@@ -353,6 +359,14 @@
 				RelativePath="..\src\map\battle.h"
 				>
 			</File>
+			<File
+				RelativePath="..\src\map\battleground.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\map\battleground.h"
+				>
+			</File>
 			<File
 				RelativePath="..\src\map\chat.c"
 				>

+ 8 - 0
vcproj-8/map-server_txt.vcproj

@@ -218,6 +218,14 @@
 				RelativePath="..\src\map\battle.h"
 				>
 			</File>
+			<File
+				RelativePath="..\src\map\battleground.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\map\battleground.h"
+				>
+			</File>
 			<File
 				RelativePath="..\src\map\chat.c"
 				>