From 4cc9d5f91cf6276e28cc02bb75fc4158d28d553b Mon Sep 17 00:00:00 2001
From: shennetsind <ind@henn.et>
Date: Tue, 18 Mar 2014 14:59:53 -0300
Subject: BG Queue Fixes & +++

Fixed issue where players would be able to join a ongoing game when queueing by meeting the criteria.
Fixed/Implemented the maximum_afk_seconds setting.
Fixed issue with the maxPlayers arena setting that'd cause the maximum to be less than specified.
Added a new battlegrounds.conf setting "allowedTypes" for arenas in order for further customisation.
Expect a few more soon.
Special Thanks to AnnieRuru

Signed-off-by: shennetsind <ind@henn.et>
---
 conf/battlegrounds.conf |  14 +++++++
 src/map/battleground.c  | 103 +++++++++++++++++++++++++++++++++++++++++-------
 src/map/battleground.h  |  16 ++++++--
 src/map/map.c           |   2 +-
 src/map/script.c        |   2 +-
 5 files changed, 118 insertions(+), 19 deletions(-)

diff --git a/conf/battlegrounds.conf b/conf/battlegrounds.conf
index 6864d1584..0aa81d35d 100644
--- a/conf/battlegrounds.conf
+++ b/conf/battlegrounds.conf
@@ -10,6 +10,15 @@
 //====================================================
 //= Link~u! <description> <link to wiki/topic>
 //= http://hercules.ws/board/topic/928-memory-slasher-may-30-patch/
+//====================================================
+//= Fields (TODO/INCOMPLETE)
+//= arenas: ({
+//=		//- allowedTypes defines what kind of applications the arena will accept, setting is not case-sensitive and is ok with whitespaces
+//= 		allowedTypes: "Solo | Party" //Arena Accepts solo and party-type joins
+//=     	allowedTypes: "guild|party" //Arena Accepts solo and guild-type joins
+//=			allowedTypes: "All" //Arena Accepts solo, party and guild-type joins
+//=		//- fillAnnounce (optional arena param)
+//= })
 battlegrounds: (
 {
 	/* feature is not complete */
@@ -24,6 +33,7 @@ battlegrounds: (
 	arenas: ({
 		name: "Tierra Gorge" //must match the name in client files
 		event: "Tierra_BG2::OnPlayerListReady"
+		allowedTypes: "All" /* Solo, Party and Guild */
 		minLevel: 80
 		maxLevel: 150
 		reward: {/* amount of badges awarded on each case */
@@ -41,6 +51,7 @@ battlegrounds: (
 	},{
 		name: "Flavius" //must match the name in client files
 		event: "start#bat_b01::OnPlayerListReady"
+		allowedTypes: "All" /* Solo, Party and Guild */
 		minLevel: 80
 		maxLevel: 150
 		reward: {/* amount of badges awarded on each case */
@@ -58,6 +69,7 @@ battlegrounds: (
 	},{
 		name: "KVM (Level 80 and up)" //must match the name in client files
 		event: "KvM03_BG::OnPlayerListReady"
+		allowedTypes: "All" /* Solo, Party and Guild */
 		minLevel: 80
 		maxLevel: 150
 		reward: {/* amount of badges awarded on each case */
@@ -75,6 +87,7 @@ battlegrounds: (
 	},{
 		name: "KVM (Level 60~79)" //must match the name in client files
 		event: "KvM03_BG::OnPlayerListReady"
+		allowedTypes: "All" /* Solo, Party and Guild */
 		minLevel: 60
 		maxLevel: 79
 		reward: {/* amount of badges awarded on each case */
@@ -92,6 +105,7 @@ battlegrounds: (
 	},{
 		name: "KVM (Level 59 and below)" //must match the name in client files
 		event: "KvM03_BG::OnPlayerListReady"
+		allowedTypes: "All" /* Solo, Party and Guild */
 		minLevel: 1
 		maxLevel: 59
 		reward: {/* amount of badges awarded on each case */
diff --git a/src/map/battleground.c b/src/map/battleground.c
index 65f475124..3640b8344 100644
--- a/src/map/battleground.c
+++ b/src/map/battleground.c
@@ -113,7 +113,7 @@ bool bg_team_join(int bg_id, struct map_session_data *sd) {
 }
 
 /// Single Player leaves team
-int bg_team_leave(struct map_session_data *sd, int flag) {
+int bg_team_leave(struct map_session_data *sd, enum bg_team_leave_type flag) {
 	int i, bg_id;
 	struct battleground_data *bgd;
 	char output[128];
@@ -137,10 +137,18 @@ int bg_team_leave(struct map_session_data *sd, int flag) {
 	}
 
 	if( --bgd->count != 0 ) {
-		if( flag )
-			sprintf(output, "Server : %s has quit the game...", sd->status.name);
-		else
-			sprintf(output, "Server : %s is leaving the battlefield...", sd->status.name);
+		switch( flag ) {
+			default:
+			case BGTL_QUIT:
+				sprintf(output, "Server : %s has quit the game...", sd->status.name);
+				break;
+			case BGTL_LEFT:
+				sprintf(output, "Server : %s is leaving the battlefield...", sd->status.name);
+				break;
+			case BGTL_AFK:
+				sprintf(output, "Server : %s has been afk-kicked from the battlefield...", sd->status.name);
+				break;
+		}
 		clif->bg_message(bgd, 0, "Server", output, strlen(output) + 1);
 	}
 
@@ -252,6 +260,34 @@ int bg_send_xy_timer(int tid, int64 tick, int id, intptr_t data) {
 	bg->team_db->foreach(bg->team_db, bg->send_xy_timer_sub, tick);
 	return 0;
 }
+
+enum bg_queue_types bg_str2teamtype (const char *str) {
+	char temp[200], *parse;
+	enum bg_queue_types type = BGQT_INVALID;
+	
+	safestrncpy(temp, str, 200);
+	
+	parse = strtok(temp,"|");
+	
+	while (parse != NULL) {
+		normalize_name(parse," ");
+		if( strcmpi(parse,"all") == 0 )
+			type |= BGQT_INDIVIDUAL|BGQT_PARTY|BGQT_GUILD;
+		else if( strcmpi(parse,"party") == 0 )
+			type |= BGQT_PARTY;
+		else if( strcmpi(parse,"guild") == 0 )
+			type |= BGQT_GUILD;
+		else if( strcmpi(parse,"solo") == 0 )
+			type |= BGQT_INDIVIDUAL;
+		else {
+			ShowError("bg_str2teamtype: '%s' unknown type, skipping...\n",parse);
+		}
+		parse = strtok(NULL,"|");
+	}
+	
+	return type;
+}
+
 void bg_config_read(void) {
 	config_t bg_conf;
 	config_setting_t *data = NULL;
@@ -274,7 +310,7 @@ void bg_config_read(void) {
 		safestrncpy(bg->gdelay_var, delay_var, BG_DELAY_VAR_LENGTH);
 		
 		libconfig->setting_lookup_int(settings, "maximum_afk_seconds", &bg->mafksec);
-		
+				
 		libconfig->setting_lookup_bool(settings, "feature_off", &offline);
 
 		if( offline == 0 )
@@ -286,12 +322,13 @@ void bg_config_read(void) {
 			for(i = 0; i < arena_count; i++) {
 				config_setting_t *arena = libconfig->setting_get_elem(arenas, i);
 				config_setting_t *reward;
-				const char *aName, *aEvent, *aDelayVar;
+				const char *aName, *aEvent, *aDelayVar, *aTeamTypes;
 				int minLevel = 0, maxLevel = 0;
 				int prizeWin, prizeLoss, prizeDraw;
 				int minPlayers, maxPlayers, minTeamPlayers;
 				int maxDuration;
 				int fillup_duration = 0, pregame_duration = 0;
+				enum bg_queue_types allowedTypes;
 				
 				bg->arena[i] = NULL;
 				
@@ -361,6 +398,12 @@ void bg_config_read(void) {
 					continue;
 				}
 				
+				
+				if( !libconfig->setting_lookup_string(arena, "allowedTypes", &aTeamTypes) ) {
+					ShowError("bg_config_read: failed to find 'allowedTypes' for arena '%s'/#%d\n",aName,i);
+					continue;
+				}
+				
 				libconfig->setting_lookup_int(arena, "maxDuration", &maxDuration);
 				
 				if( maxDuration < 0 ) {
@@ -381,6 +424,7 @@ void bg_config_read(void) {
 					pregame_duration = 20;
 				}
 
+				allowedTypes = bg->str2teamtype(aTeamTypes);
 				
 				CREATE( bg->arena[i], struct bg_arena, 1 );
 				
@@ -403,6 +447,7 @@ void bg_config_read(void) {
 				bg->arena[i]->pregame_duration = pregame_duration;
 				bg->arena[i]->fillup_duration = fillup_duration;
 				bg->arena[i]->ongoing = false;
+				bg->arena[i]->allowed_types = allowedTypes;
 
 			}
 			bg->arenas = arena_count;
@@ -452,7 +497,7 @@ void bg_queue_ready_ack (struct bg_arena *arena, struct map_session_data *sd, bo
 					count++;
 			}
 		}
-		/* check if all are ready then cancell timer, and start game  */
+		/* check if all are ready then cancel timer, and start game  */
 		if( count == queue->items ) {
 			timer->delete(arena->begin_timer,bg->begin_timer);
 			arena->begin_timer = INVALID_TIMER;
@@ -527,6 +572,10 @@ void bg_begin(struct bg_arena *arena) {
 		bg->match_over(arena,true);
 	} else {
 		arena->ongoing = true;
+		
+		if( bg->afk_timer_id == INVALID_TIMER && bg->mafksec > 0 )
+			bg->afk_timer_id = timer->add(timer->gettick()+10000,bg->afk_timer,0,0);
+		
 		/* TODO: make this a arena-independant var? or just .@? */
 		mapreg->setreg(script->add_str("$@bg_queue_id"),arena->queue_id);
 		mapreg->setregstr(script->add_str("$@bg_delay_var$"),bg->gdelay_var);
@@ -557,10 +606,6 @@ void bg_begin(struct bg_arena *arena) {
 		mapreg->setreg(script->add_str("$@bg_member_size"),count);
 		
 		npc->event_do(arena->npc_event);
-		/* we split evenly? */
-		/* but if a party of say 10 joins, it cant be split evenly unless by luck there are 10 soloers in the queue besides them */
-		/* not sure how to split T_T needs more info */
-		/* currently running only on solo mode so we do it evenly */
 	}
 }
 int bg_begin_timer(int tid, int64 tick, int id, intptr_t data) {
@@ -569,6 +614,28 @@ int bg_begin_timer(int tid, int64 tick, int id, intptr_t data) {
 	return 0;
 }
 
+int bg_afk_timer(int tid, int64 tick, int id, intptr_t data) {
+	struct s_mapiterator* iter;
+	struct map_session_data* sd;
+	int count = 0;
+
+	iter = mapit_getallusers();
+	for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) {
+		if( !sd->bg_queue.arena || !sd->bg_id )
+			continue;
+		if( DIFF_TICK(sockt->last_tick, sd->idletime) < bg->mafksec )
+			bg->team_leave(sd,BGTL_AFK);
+		count++;
+	}
+	mapit->free(iter);
+	
+	if( count )
+		bg->afk_timer_id = timer->add(timer->gettick()+10000,bg->afk_timer,0,0);
+	else
+		bg->afk_timer_id = INVALID_TIMER;
+	return 0;
+}
+
 void bg_queue_pregame(struct bg_arena *arena) {
 	struct hQueue *queue = &script->hq[arena->queue_id];
 	int i;
@@ -605,7 +672,7 @@ void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_q
 	struct hQueue *queue;
 	int i, count = 0;
 	
-	if( arena->begin_timer != INVALID_TIMER ) {
+	if( arena->begin_timer != INVALID_TIMER || arena->ongoing ) {
 		clif->bgqueue_ack(sd,BGQA_FAIL_QUEUING_FINISHED,arena->id);
 		return;
 	}
@@ -636,7 +703,7 @@ void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_q
 			break;
 	}
 	
-	if( !(queue = script->queue(arena->queue_id)) || (queue->items+count) >= arena->max_players ) {
+	if( !(queue = script->queue(arena->queue_id)) || (queue->items+count) > arena->max_players ) {
 		clif->bgqueue_ack(sd,BGQA_FAIL_PPL_OVERAMOUNT,arena->id);
 		return;
 	}
@@ -684,6 +751,10 @@ void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_q
 enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, struct bg_arena *arena, enum bg_queue_types type) {
 	int tick;
 	unsigned int tsec;
+	
+	if( !(arena->allowed_types & type) )
+		return BGQA_FAIL_TYPE_INVALID;
+	
 	if ( sd->status.base_level > arena->max_level || sd->status.base_level < arena->min_level )
 		return BGQA_FAIL_LEVEL_INCORRECT;
 	
@@ -810,6 +881,7 @@ void battleground_defaults(void) {
 	bg->queue_on = false;
 	
 	bg->mafksec = 0;
+	bg->afk_timer_id = INVALID_TIMER;
 	bg->arena = NULL;
 	bg->arenas = 0;
 	/* */
@@ -844,6 +916,9 @@ void battleground_defaults(void) {
 	bg->send_message = bg_send_message;
 	bg->send_xy_timer_sub = bg_send_xy_timer_sub;
 	bg->send_xy_timer = bg_send_xy_timer;
+	bg->afk_timer = bg_afk_timer;
+	/* */
+	bg->str2teamtype = bg_str2teamtype;
 	/* */
 	bg->config_read = bg_config_read;
 }
diff --git a/src/map/battleground.h b/src/map/battleground.h
index ed7347566..05c4eb060 100644
--- a/src/map/battleground.h
+++ b/src/map/battleground.h
@@ -26,6 +26,12 @@ enum bg_queue_types {
 	BGQT_GUILD      = 0x4,
 };
 
+enum bg_team_leave_type {
+	BGTL_LEFT = 0x0,
+	BGTL_QUIT = 0x1,
+	BGTL_AFK  = 0x2,
+};
+
 struct battleground_member_data {
 	unsigned short x, y;
 	struct map_session_data *sd;
@@ -62,12 +68,13 @@ struct bg_arena {
 	unsigned short fillup_duration;
 	unsigned short pregame_duration;
 	bool ongoing;
+	enum bg_queue_types allowed_types;
 };
 
 struct battleground_interface {
 	bool queue_on;
 	/* */
-	int mafksec;
+	int mafksec, afk_timer_id;
 	char gdelay_var[BG_DELAY_VAR_LENGTH];
 	/* */
 	struct bg_arena **arena;
@@ -97,13 +104,16 @@ struct battleground_interface {
 	bool (*team_warp) (int bg_id, unsigned short map_index, short x, short y);
 	void (*send_dot_remove) (struct map_session_data *sd);
 	bool (*team_join) (int bg_id, struct map_session_data *sd);
-	int (*team_leave) (struct map_session_data *sd, int flag);
+	int (*team_leave) (struct map_session_data *sd, enum bg_team_leave_type flag);
 	bool (*member_respawn) (struct map_session_data *sd);
 	int (*create) (unsigned short map_index, short rx, short ry, const char *ev, const char *dev);
 	int (*team_get_id) (struct block_list *bl);
 	bool (*send_message) (struct map_session_data *sd, const char *mes, int len);
 	int (*send_xy_timer_sub) (DBKey key, DBData *data, va_list ap);
-	int (*send_xy_timer) (int tid, int64 tick, int id, intptr_t data);	
+	int (*send_xy_timer) (int tid, int64 tick, int id, intptr_t data);
+	int (*afk_timer) (int tid, int64 tick, int id, intptr_t data);
+	/* */
+	enum bg_queue_types (*str2teamtype) (const char *str);
 	/* */
 	void (*config_read) (void);
 };
diff --git a/src/map/map.c b/src/map/map.c
index a7e83cae3..51b717a16 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -1685,7 +1685,7 @@ int map_quit(struct map_session_data *sd) {
 		npc->event_dequeue(sd);
 
 	if( sd->bg_id && !sd->bg_queue.arena ) /* TODO: dump this chunk after bg_queue is fully enabled */
-		bg->team_leave(sd,1);
+		bg->team_leave(sd,BGTL_QUIT);
 
 	if( sd->state.autotrade && runflag != MAPSERVER_ST_SHUTDOWN && !hChSys.closing )
 		pc->autotrade_update(sd,PAUC_REMOVE);
diff --git a/src/map/script.c b/src/map/script.c
index 17eba6b21..01a7e6410 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -16350,7 +16350,7 @@ BUILDIN(bg_leave)
 	if( sd == NULL || !sd->bg_id )
 		return true;
 
-	bg->team_leave(sd,0);
+	bg->team_leave(sd,BGTL_LEFT);
 	return true;
 }
 
-- 
cgit v1.2.3-70-g09d2