
// @unloadnpc Paradox
// @unloadnpc BTAUPDATE
// @unloadnpc BestTime
// @loadnpc npc/thor/bta.txt


-	script	Paradox	HIDDEN_NPC,{
function BTA_Points; function party_has_duplicate_job;
	OnReset:
		query_sql( "SELECT COUNT(`char_id`) FROM `char` WHERE `online` = 1 ", .@total );
		while( .@count < .@total ){
			query_sql( "SELECT `char_id`,`name` FROM `char` WHERE `online` = 1 ORDER BY `char_id` LIMIT 128 OFFSET "+.@offset, .@char_id, .@name$ );
			.@i = 0;
			.@size = getarraysize(.@name$);
			while( .@i < .@size ){
				attachrid(getcharid(CHAR_ID_ACCOUNT,.@name$[.@i]));
				if(.debug){ 
					announce "[BTA] Resetting BTA Record of online player "+.@name$[.@i],0;	
				}
				bta_tries = 0;
				.@count++;
				.@i++;
			}
			freeloop 0;
			.@offset = .@offset + .@size;
			deletearray .@name$,.@size;
		}
		query_sql ("DELETE FROM `char_reg_num_db` WHERE `key` = 'bta_tries'");
		announce "[System] BTA Retry Counter has been RESET",0;
		end;

	OnGiveReward:
	OnClock2000:
		set .@num_rows, query_sql( "SELECT `party_name`,`player_ids`,`time` FROM `bta_db` ORDER BY `time` ASC",.@party$,.@charIds$,.@time );
		if (.@num_rows > 0) {
			for( set .@i,0; .@i < .@num_rows; set .@i,.@i + 1 ) {
				explode(.@my_array$ ,.@charIds$[.@i], ",");
				set .@arraysize, getarraysize(.@my_array$);
				if (!.@i) {
					// Loop to list out the party names
					for( set .@k,0; .@k < .@arraysize; .@k += 1 ) {
						query_sql("SELECT `name`,`char_id` from `char` WHERE `char_id` = "+.@my_array$[.@k]+"",.@names$,.@cid);
						rodex_sendmail(
							.@cid, "[ Reward ]", "[Boss Time Attack]", "Congratulation!! you party earned Top. "+( .@i+1)+" position in Boss Timed Attack. Here is your reward.",
							0,
							.Reward[0], .Reward[1],
							.Reward[2], .Reward[3]
						);
					}
				} else {
					// Loop to list out the party names
					for( set .@k,0; .@k < .@arraysize; .@k += 1 ) {
						query_sql("SELECT `name`,`char_id` from `char` WHERE `char_id` = "+.@my_array$[.@k]+"",.@names$,.@cid);
					
						rodex_sendmail(
							.@cid, "[ Reward ]", "[Boss Time Attack]", "Congratulation!! you party completed the Boss Timed Attack. Here is your reward.",
							0,
							.Reward2[0], .Reward2[1],
							.Reward2[2], .Reward2[3]
						);
					}
			
				}
			}
			announce "[System] Congratulations to our Top Boss Time Attack Hunters. Check mailbox for your reward.",0;
			query_sql "TRUNCATE TABLE `bta_db`";	
		}

		// Reset BTA Tries
		
		query_sql( "SELECT COUNT(`char_id`) FROM `char` WHERE `online` = 1 ", .@total );
		while( .@count < .@total ){
			query_sql( "SELECT `char_id`,`name` FROM `char` WHERE `online` = 1 ORDER BY `char_id` LIMIT 128 OFFSET "+.@offset, .@char_id, .@name$ );
			.@i = 0;
			.@size = getarraysize(.@name$);
			while( .@i < .@size ){
				attachrid(getcharid(CHAR_ID_ACCOUNT,.@name$[.@i]));
				if(.debug){ 
					announce "[BTA] Resetting BTA Record of online player "+.@name$[.@i],0;	
				}
				bta_tries = 0;
				.@count++;
				.@i++;
			}
			freeloop 0;
			.@offset = .@offset + .@size;
			deletearray .@name$,.@size;
		}
		query_sql ("DELETE FROM `char_reg_num_db` WHERE `key` = 'bta_tries'");
		announce "[System] BTA Retry Counter has been RESET",0;
		end;		


	OnSpectate:
		getmapxy(.@map$, @x, @y, 0);
		if ($@locked && getcharid(CHAR_ID_PARTY) == $PartyChecker ){
			mes "[^0000ffBoss Timed Attack^000000]";
			mes "You can't spectate because you are a member of ongoing event";
			close;
		}
		if (etatus) {
			mes "[^0000ffBoss Timed Attack^000000]";
			mes "Sorry, you are currently joined an event.  Use @event and leave.";
			close;
		}
		if (spectator && strcharinfo(PC_MAP) == "guild_vs2" ) {
			mes "[^0000ffBoss Timed Attack^000000]";
			mes "Sorry, you are currently on spectator mode at PVP Match.  Use @match and leave.";
			close;
		}			
		if (strcharinfo(PC_MAP) == .mapName$) {
			} else {
		
				if (getmapflag(strcharinfo(PC_MAP), mf_pvp) || getmapflag(strcharinfo(PC_MAP), mf_nowarp)) {
				mes "[^0000ffBoss Timed Attack^000000]";
				mes "Sorry, you can't join BTA from this map";
				close;
			}
		}
		if (.deadlock && !Hp) {
			mes "[^0000ffBoss Timed Attack^000000]";
			mes "You may not use event when you are dead.";
			close;
		}
		mes "[^0000ffBoss Timed Attack^000000]";
		mes "What would you like to do?";
		while(1) {
		next;
		switch(select(
			((getgmlevel() < .GMAccess)?":":" > ^FF0000GM Menu^000000:")+
			 " > What is BTA?:"+
			 ((!$@locked && .enable)?" > ^0055FFJoin Boss Timed Attack^000000:":":")+
			 (($@locked && !spectator && .spectator && .qid)?" > ^0055FFWatch BTA Event^000000:":":")+
			 ((spectator)?" > ^0055FFLeave Event Area^000000:":":")+
			 " > Ranking:"+
	 		 " > ^777777Close^000000"
		)) {
		case 1:
			mes "[^0000ffBTA GM Setup^000000]";
			while(1) {
				switch(select(
				((!.enable)?"Status [ ^ff0000Inactive^000000 ]:":"Status [ ^28bf00Active^000000 ]:")+
				"Party Size [ ^28bf00"+.register_min+"^000000 ]:"+
				"Entrance Fee [ ^28bf00"+.register_cost+"^000000 ]:"+
				"Required Item [ ^28bf00"+getitemname(.register_item)+"^000000 ]:"+
				((!.eject)?"Eject on TimesUP? [ ^ff0000No^000000 ]:":"Eject on TimesUP? [ ^28bf00Yes^000000 ]:")+
				((!.spectator)?"Allow Spectator [ ^ff0000No^000000 ]:":"Allow Spectator [ ^28bf00Yes^000000 ]:")+
				((!.dupejobs)?"Allow Duplicate Jobs [ ^ff0000No^000000 ]:":"Allow Duplicate Jobs [ ^28bf00Yes^000000 ]:")+
				((!$@locked)?"Active [ ^ff0000No^000000 ]:":"Active [ ^28bf00Yes^000000 ]:")+
	 			 "- ^777777Set MvP^000000:"+
	 			 "- ^777777Close^000000"
				)) {
					case 1: if (!.enable) {	set .enable,1; dispbottom "BTA is now active"; } else { set .enable,0;	dispbottom "BTA is now disabled"; } break;
					case 2: input .register_min,1; break;
					case 3: input .register_cost,0; break;
					case 4: input .register_item,0; break;
					case 5: if (!.eject) { set .eject,1; dispbottom "BTA Eject on Time is UP"; } else { set .eject,0; dispbottom "BTA Eject is now disabled"; } break;
					case 6: if (!.spectator) { set .spectator,1; dispbottom "BTA spectator is allowed"; } else { set .spectator,0;	dispbottom "BTA spectator is now disabled"; } break;
					case 7: if (!.dupejobs) { set .dupejobs,1; dispbottom "BTA duplicate job is allowed"; } else { set .dupejobs,0; dispbottom "BTA duplicate job is now disabled"; } break;
					case 8: if (!$@locked) { 
							if (.qid) {
								queuedel .qid;
							}
							set $@locked,1;
							dispbottom "BTA room is engaged";
						 } else { 
							killmonster .mapName$,"All";
							// No longer make NPC busy
							if (.qid) {
								queuedel .qid;
							}
							set $@locked, 0;
							set $PartyChecker,0;
							set .status,0;
							mapwarp .mapName$, .mapName$, 81,50;
							dispbottom "BTA room is now ready";
						}
 						break;
					case 9:
						while(1) {
							switch(select(
								"MvP 1 [ ^28bf00"+getmonsterinfo(.MvP1,0)+"^000000 ]:"+
								"MvP 2 [ ^28bf00"+getmonsterinfo(.MvP2,0)+"^000000 ]:"+
								"MvP 3 [ ^28bf00"+getmonsterinfo(.MvP3,0)+"^000000 ]:"+
								"MvP 4 [ ^28bf00"+getmonsterinfo(.MvP4,0)+"^000000 ]:"+
								"MvP 5 [ ^28bf00"+getmonsterinfo(.MvP5,0)+"^000000 ]:"+
	 							"- ^777777Close^000000"
							)) {
								case 1: input .MvP1,0; break;
								case 2: input .MvP2,0; break;
								case 3: input .MvP3,0; break;
								case 4: input .MvP4,0; break;
								case 5: input .MvP5,0; break;
								case 6: close;
							}
								
						}
						break;
					case 10:	close;
				}
			}		
			break;
		case 2:
			mes "[^0000ffBoss Timed Attack^000000]";
			mes "Boss Time Attack is a event that party must eliminate the following MvP (in order): ";
			mes "1: ^ff0000" + getmonsterinfo(.MvP1,0)+"^000000"; 
			mes "2: ^ff0000" + getmonsterinfo(.MvP2,0)+"^000000"; 
			mes "3: ^ff0000" + getmonsterinfo(.MvP3,0)+"^000000"; 
			mes "4: ^ff0000" + getmonsterinfo(.MvP4,0)+"^000000"; 
			mes "5: ^ff0000" + getmonsterinfo(.MvP5,0)+"^000000"; 
			mes "^0055FFRequirements:^000000";		
			mes "Party Member: ^ff0000"+.register_min+"^000000 members";
			if (!.dupejobs) {
				mes "Members: ^ff0000No Same Class^000000";
			} else {
				mes "Members: ^ff0000Same Class Allowed^000000";
			} 
				
			if(.register_cost){
				mes "Zeny: ^ff0000"+callfunc("F_InsertComma",.register_cost)+"^000000z";
			}
			if(.register_item){
				mes "Item: ^ff0000"+getitemname(.register_item)+"^000000 x 1 (Provided by NPC)";
			}	
			mes "^0055FFDisabled Class:^000000";
			for ( .@j = 0; .@j < getarraysize(.noclass); ++.@j ) { // loop with saved job ID
				mes (.@j+1) + ": ^ff0000" + jobname(.noclass[.@j])+"^000000";
			}
			mes "^0055FFMap Restriction:^000000";
			mes "~ ^777777Resu is allowed^000000";
			mes "~ ^777777No Pub / Vend^000000";
			mes "~ ^777777No Homunculus^000000";
			mes "~ ^777777No Pet^000000";
			mes "~ ^777777Full Debuff Upon Entry.^000000";
			mes "-";
			mes "^0055FFReward:^000000";
			mes "Top #1 on the ranking will be rewarded via mail at 8PM.";
			for ( .@j = 0; .@j < getarraysize(.Reward); .@j += 2 ) { // loop with saved job ID
				mes .Reward[.@j+1] + "x ^ff0000" + getitemname(.Reward[.@j])+"^000000";
			}
			mes "-";
			mes "We are also giving reward to pary who can just finish BTA.";
			for ( .@j = 0; .@j < getarraysize(.Reward2); .@j += 2 ) { // loop with saved job ID
				mes .Reward2[.@j+1] + "x ^ff0000" + getitemname(.Reward2[.@j])+"^000000";
			}
			mes "-";
			break;
		case 3:
			// Validate the party leader first
			if (getpartyleader( getcharid(1), 2 ) != getcharid(0)) {
				mes "[^0000ffBoss Timed Attack^000000]";
				mes "Sorry, but this NPC can only be used by the Party Leader";
				break;
			} else 	{		
				// Check Leader's class...Then do deeper scan later against members
	    			// Creator | Soul Linker | Star Gladiator | Gunslinger | Ninja
				if (Class == Job_Creator || Class == Job_Soul_Linker || Class == Job_Star_Gladiator || Class == Job_Gunslinger || Class == Job_Ninja) {
					mes "[^0000ffBoss Timed Attack^000000]";
					mes "Sorry, but your class is not allowed here...";
					break;
				} else {
					// Limit 1 Party Leader talking at a time
					// We're checking if the attached RID is > 0...If it is, the NPC is in use
					if ( getd( ".jnpc_"+getnpcid(0) ) != 0 ) {
						getmapxy(@mapname$,@mapx,@mapy,0,rid2name(getd( ".jnpc_"+getnpcid(0) )));
						if (@mapname$ != .mapNPC$) {
							stopnpctimer;
							setd( ".jnpc_"+getnpcid(0) ),0;
						}
					}
					// If we get through this check then we're fine. We can use the NPC
					if ( getd( ".jnpc_"+getnpcid(0) ) || $@locked == 1 ) {
						mes "[^0000ffBoss Timed Attack^000000]";
						mes "I am currently being used. Try again some time later...";
						break;
					} else {
						setd( ".jnpc_"+getnpcid(0) ),getcharid(3);
						attachnpctimer;
						initnpctimer;
						mes "[^0000ffBoss Timed Attack^000000]";
						mes "Do you want to play a cool time attack game?";
						next;
						switch(select("~ No:~ Yes")) {
							case 1:
								mes "[^0000ffBoss Timed Attack^000000]";
								mes "See you later...";
								stopnpctimer;
								setd( ".jnpc_"+getnpcid(0) ),0;
								close;
							case 2:
								mes "[^0000ffBoss Timed Attack^000000]";
								// Logic to check if there are any duplicate classes
								// Check min party requirements
								// get the charID and accountID of character's party members
								getpartymember getcharid(CHAR_ID_PARTY), 1;	
								getpartymember getcharid(CHAR_ID_PARTY), 2;	 
						
								if ( $@partymembercount != .register_min ) {
									mes "Please form a party of "+ .register_min +" to continue.";
									stopnpctimer;
									setd( ".jnpc_"+getnpcid(0) ),0;
									close;
								}
						
								// loop through both and use 'isloggedin' to count online party members
								for ( set .@i, 0; .@i < $@partymembercount; set .@i, .@i +1 ) {
									if ( isloggedin( $@partymemberaid[.@i], $@partymembercid[.@i] ) ) {
										set .@count_online, .@count_online +1 ;

									}
								}
						
								// We search accountID & charID because a single party can have multiple 
								// characters from the same account. Without searching through the charID, 
								// if a player has 2 characters from the same account inside the party but 
								// only 1 char online, it would count their online char twice.

								if ( .@count_online != .register_min ) {
									mes "All your party members must be online to continue";
									stopnpctimer;
									setd( ".jnpc_"+getnpcid(0) ),0;
									close;
								}
						
								if ( !.dupejobs && party_has_duplicate_job() ) {
									mes "It seems that someone in the party has the same class than another member. Please check the requirements...";
									stopnpctimer;
									setd( ".jnpc_"+getnpcid(0) ),0;
									close;

								} else {
									// Check Disabled Class
									//	get party info
									getpartymember getcharid(CHAR_ID_PARTY), 1;
									getpartymember getcharid(CHAR_ID_PARTY), 2;
							
									// save the attachrd RID. going to use attachrid this time
									.@origin = getcharid(CHAR_ID_ACCOUNT);
							
									// loop through these members and check for forbidden class
									for ( .@i = 0; .@i < $@partymembercount; ++.@i ) {
										if ( isloggedin( $@partymemberaid[.@i], $@partymembercid[.@i] ) ) {
											attachrid $@partymemberaid[.@i];
											if(strcharinfo(PC_MAP) == getvariableofnpc(.mapName$,"Paradox")){ set .@check,.@check+1;}
											if( bta_tries >= .maxtries) { .@maxretries++; }
											for ( .@j = 0; .@j < getarraysize(.noclass); ++.@j ) { // loop with saved job ID
												if ( .noclass[.@j] == BaseJob ) { // if found
													set .@nojob, .@nojob +1 ;
													break; // break if found duplicates
												}
											}
										}
									}
			
									// attachrid back ... surely you don't want the message display on other party members
									attachrid .@origin;
									if(.@check){
										mes "Some of your party members are still at the arena.";
										stopnpctimer;
										setd( ".jnpc_"+getnpcid(0) ),0;
										close;
									}
									if(.@maxretries){
										mes "Some of your party members reached max (^ff0000"+.maxtries+"^000000) BTA retries.";
										stopnpctimer;
										setd( ".jnpc_"+getnpcid(0) ),0;
										close;
									}
									if ( .@nojob ) { // if there are duplicate jobs, the array size is more than 0
										mes "Sorry, we cant allow the following job on your party.";
										for ( .@i = 0; .@i < getarraysize(.noclass); ++.@i )
										{
											mes "- "+ jobname( .noclass[.@i] );
										}
										stopnpctimer;
										setd( ".jnpc_"+getnpcid(0) ),0;
										close;
									}
									else {
										// Check Zeny Amount
										if(.register_cost){
											if(Zeny < .register_cost) {
												mes "Sorry you need ^ff0000"+callfunc("F_InsertComma",.register_cost)+"^000000z";
												stopnpctimer;
												setd( ".jnpc_"+getnpcid(0) ),0;
												close;
											}

										} else if(.register_item){
											if(countitem(.register_item) < 1) {
												mes "Sorry you need " + getitemname(.register_item) + " x 1";
												stopnpctimer;
												setd( ".jnpc_"+getnpcid(0) ),0;
												close;
											}

										}
 										if(.register_cost){
											// Remove Zeny
											set Zeny, Zeny - .register_cost;
										}
										if(.register_item){
											// Remove Zeny
											delitem .register_item,1;
										}

									// Remove the attached RID
									// Warp the party and start the event
									// Map Party Name
									set $@locked,1;
									stopnpctimer;
									setd( ".jnpc_"+getnpcid(0) ),0;
									set $NPCParty$,strcharinfo(1);
									set $PartyChecker,getcharid(CHAR_ID_PARTY);
									//Initialize Queue
									.qid = queue();
									queueopt .qid, QUEUEOPT_LOGOUT, strnpcinfo(0)+"::OnLogOut";
									queueopt .qid, QUEUEOPT_MAPCHANGE, strnpcinfo(0)+"::OnMapChange";	
										getpartymember($PartyChecker,2);
       									set .@partymembercount, $@partymembercount;
       									copyarray .@partymemberaid[0], $@partymemberaid[0], .@partymembercount;
      									for (set .@i, 0; .@i < .@partymembercount; .@i ++) {
              									if (attachrid(.@partymemberaid[.@i])) {
											queueadd .qid, getcharid(3);
											bta_tries++;
											sc_end SC_ALL;	
											warp .mapName$,.warpx,.warpy;
               									}
       									}
									donpcevent "Paradox::OnEnable";
								}
							}
							break;
						}
					}

						// Timers utilized to clear the attached RID
						if (getd( ".jnpc_"+getnpcid(0) )) {
							OnTimer1000:
								.@is_occupied = getd( ".jnpc_"+getnpcid(0) );
								if ( .@is_occupied && .@is_occupied == playerattached() ) {
									attachnpctimer;
									initnpctimer;
								} else {
									OnTimerQuit:
										stopnpctimer;
										setd( ".jnpc_"+getnpcid(0) ),0;
								}
							end;
						}
						end;
					}
				}
				end;
		case 4: 
			getmapxy(.@map$, @x, @y, 0);
			set slastmap$,.@map$;
			set slastx,@x;
			set slasty,@y;
			set spectator,1;
			set shp,Hp;
			set ssp,Sp;
			setoption Option_Invisible, 1;
			sc_start SC_XMAS, 1600000, 0;
			warp .mapName$,.wwarpx,.wwarpy;
			close;
		case 5:
			set spectator,0;
			set Hp,shp;
			set Sp,ssp;
			setoption Option_Invisible, 0;
			sc_end(SC_XMAS);
			warp slastmap$,slastx,slasty;
			close;
		case 6:
			set .@num_rows, query_sql( "SELECT `party_name`,`player_ids`,`time` FROM `bta_db` ORDER BY `time` ASC LIMIT 5",.@party$,.@charIds$,.@time );
			if (.@num_rows > 0) {
				for( set .@i,0; .@i < .@num_rows; set .@i,.@i + 1 ) {
					set .@h,.@time[.@i] % 86400 / 3600;
					set .@m,.@time[.@i] % 3600 / 60; 
					set .@s,.@time[.@i] % 60;
					set .@h$, .@h+" hr"+((.@h <= 1)?"":"s"); 
					set .@m$, .@m+" min"+((.@m <= 1)?"":"s");
					set .@s$, .@s+" second"+((.@s <= 1)?"":"s");
					set .@time$,""+.@h$+" "+.@m$+" "+.@s$+"";

					mes "[ ^0000ff Rank "+( .@i + 1 )+"^000000 ]";
					mes "Party: ^ff0000"+.@party$[.@i]+"^000000";
					mes "Time: "+.@time$;

					// Explode the character Ids
					explode(.@my_array$ ,.@charIds$[.@i], ",");
					set .@arraysize, getarraysize(.@my_array$);
			
					// Loop to list out the party names
					for( set .@k,0; .@k < .@arraysize; set .@k,.@k + 1 ) {
						query_sql("SELECT `name` from `char` WHERE `char_id` = "+.@my_array$[.@k]+"",@names$);
						mes "Player " + (.@k+1) + ": " + @names$;
					}
					mes "  ";
				}
			}else{
				mes "No Record Found.";
			}
			break;
			
		case 7: 
			close;
		}
		}
		end;


	// =====================================================================================
	// - End Monster Labels -
	// =====================================================================================
	OnEnable:
		donpcevent "BestTime::OnStart";
		for(set .@i,2; .@i > 0; set .@i,.@i-1){
			if (!$@locked) {
				end;
			}
			announce "[ BTA ] Party [ "+getpartyname($PartyChecker)+" ] is now ready for Boss Time Attack. For those who wanted to watch, type @bta and chose Watch BTA Event.",16;
			sleep 30 * .onesec;
		}
		playbgmall("118",.mapName$);
		if (.globalAnnounce == 1 && $@locked) {
			sleep2 5000;
			announce "Boss Time Attack: We will start in 5",0;
			sleep2 1500;
			announce "Boss Time Attack: 4",0;
			sleep2 1500;
			announce "Boss Time Attack: 3",0;
			sleep2 1500;
			announce "Boss Time Attack: 2",0;
			sleep2 1500;
			announce "Boss Time Attack: 1",0;
			sleep2 1500;
			announce "Boss Time Attack: GO!",0;
			sleep2 1500;
		}
		if (!.globalAnnounce && $@locked) {
			sleep2 5000;
			mapannounce .mapName$,"Boss Time Attack: We will start in 5",0;
			sleep2 1500;
			mapannounce .mapName$,"Boss Time Attack: 4",0;
			sleep2 1500;
			mapannounce .mapName$,"Boss Time Attack: 3",0;
			sleep2 1500;
			mapannounce .mapName$,"Boss Time Attack: 2",0;
			sleep2 1500;
			mapannounce .mapName$,"Boss Time Attack: 1",0;
			sleep2 1500;
			mapannounce .mapName$,"Boss Time Attack: GO!",0;
			sleep2 1500;
		}
		if ( $@locked) {
			soundeffectall "6_Startgame.wav", 0,.mapName$,0,0,100,100;
			killmonster .mapName$,"All";
			sleep2 1000;
			set .MOBStartTick, gettimetick(2);
			set .MOBKillTime, 0;
			set .MOBKillCount, 0;
			set .status,1;
			set .i,0;
			query_sql( "SELECT `party_name`,`player_ids`,`time` FROM `bta_db` ORDER BY `time` ASC LIMIT 1",.@party$,.@charIds$,.@time );
			if(.@time) {
				set .@h,.@time[.@i] % 86400 / 3600;
				set .@m,.@time[.@i] % 3600 / 60;
				set .@s,.@time[.@i] % 60;
				set .@h$, .@h+" hr"+((.@h <= 1)?"":"s"); 
				set .@m$, .@m+" min"+((.@m <= 1)?"":"s");
				set .@s$, .@s+" second"+((.@s <= 1)?"":"s");
				set .@time$,""+.@h$+" "+.@m$+" "+.@s$+"";
				mapannounce .mapName$,"[BEAT TIME] You will have to beat the best time of [ "+.@party$+" ] party with a time of "+.@time$+".  Your party will be ejected if you fail to beat the best time.",0;
				set .timerinit,1;
				donpcevent "BestTime::OnStart";
			}
			goto OnSpawn;
		}
		end;

					
	OnSpawn:
		if (.globalAnnounce == 1) {
			if (.i == 0) announce "Boss Time Attack: "+getmonsterinfo(.MvP1,0)+" has been summoned. Use @bta to watch ongoing Boss Timed Attack.",0;
			if (.i == 1) announce "Boss Time Attack: "+getmonsterinfo(.MvP2,0)+" has been summoned. Use @bta to watch ongoing Boss Timed Attack.",0;
			if (.i == 2) announce "Boss Time Attack: "+getmonsterinfo(.MvP3,0)+" has been summoned. Use @bta to watch ongoing Boss Timed Attack.",0;
			if (.i == 3) announce "Boss Time Attack: "+getmonsterinfo(.MvP4,0)+" has been summoned. Use @bta to watch ongoing Boss Timed Attack.",0;
			if (.i == 4) announce "Boss Time Attack: "+getmonsterinfo(.MvP5,0)+" has been summoned. Use @bta to watch ongoing Boss Timed Attack.",0;
	   	 } else {
			if (.i == 0) mapannounce .mapName$,"Boss Time Attack: "+getmonsterinfo(MvP1,0)+" has been summoned.",0;
			if (.i == 1) mapannounce .mapName$,"Boss Time Attack: "+getmonsterinfo(MvP2,0)+" has been summoned.",0;
			if (.i == 2) mapannounce .mapName$,"Boss Time Attack: "+getmonsterinfo(MvP3,0)+" has been summoned.",0;
			if (.i == 3) mapannounce .mapName$,"Boss Time Attack: "+getmonsterinfo(MvP4,0)+" has been summoned.",0;
			if (.i == 4) mapannounce .mapName$,"Boss Time Attack: "+getmonsterinfo(MvP5,0)+" has been summoned.",0;
		}
		if (.i == 0) monster .mapName$,.0,.0,getmonsterinfo(.MvP1,0),.MvP1,1,"Paradox::OnBTAKilled";
		if (.i == 1) monster .mapName$,.0,.0,getmonsterinfo(.MvP2,0),.MvP2,1,"Paradox::OnBTAKilled";
		if (.i == 2) monster .mapName$,.0,.0,getmonsterinfo(.MvP3,0),.MvP3,1,"Paradox::OnBTAKilled";
		if (.i == 3) monster .mapName$,.0,.0,getmonsterinfo(.MvP4,0),.MvP4,1,"Paradox::OnBTAKilled";
		if (.i == 4) monster .mapName$,.0,.0,getmonsterinfo(.MvP5,0),.MvP5,1,"Paradox::OnBTAKilled";
		end;

	OnBTAKilled:
		set .MOBKillCount, .MOBKillCount + 1;
		set .i,.i + 1;
		if(.MOBKillCount < 5){
			goto OnSpawn;
		}else{
			goto OnBTAKilledall;
		}
		end;

	OnBTAKilledall:
		set .timerinit,0;
		set .@k,gettimetick(2) - .MOBStartTick;
		set .@h,.@k % 86400 / 3600;
		set .@m,.@k % 3600 / 60;
		set .@s,.@k % 60;
		set .@h$, .@h+" hour"+((.@h <= 1)?"":"s");
		set .@m$, .@m+" minute"+((.@m <= 1)?"":"s");
		set .@s$, .@s+" second"+((.@s <= 1)?"":"s");
		set .@time$,""+.@h$+" "+.@m$+" "+.@s$+"";
		if (.globalAnnounce == 1) {
			announce "Boss Time Attack: Time ~ "+.@time$+".",0;
		}else{
			mapannounce .mapName$,"Boss Time Attack: Time ~ "+.@time$+".",0;
		}

		queuedel .qid;

		// ToDo - Insert data into table
		// First check if there are any party name that are the same
		BTA_Points(.@k);

		// Warp party to their save point
		sleep2 10000;
		// Kill any NPCs inside
		killmonster .mapName$,"All";
		
		// No longer make NPC busy
		set $@locked, 0;
		mapwarp .mapName$, .mapName$, 81,50;
		end;

	OnTimesUP:
		if (.eject) {
			playbgmall("93",.mapName$);
			if (.qid) queuedel .qid;
			announce "[ BTA ] Party [ "+getpartyname($PartyChecker)+" ] failed to beat the best time.",16;
			killmonster .mapName$,"All";
			set $@locked, 0;
			set $PartyChecker,0;
			set .status,0;
			mapwarp .mapName$, .mapName$, 81,50;	
		}
		end;	
	
	OnPCLoginEvent:
		if (spectator) {
			set spectator,0;
			set Hp,shp;
			set Sp,ssp;
			setoption Option_Invisible, 0;
			sc_end(SC_XMAS);
			warp slastmap$,slastx,slasty;	
		}
		end;

	OnMapChange:
		end;


	OnLogOut:
		queueremove .qid, getcharid(3);
		if (!queuesize(.qid)){
			set .timerinit,0;
			playbgmall("93",.mapName$);
			announce "[ BTA ] Party [ "+getpartyname($PartyChecker)+" ] has been wiped out at Boss Timed Attack.",16;
			if (.qid) queuedel .qid;
			killmonster .mapName$,"All";
			set $@locked, 0;
			set $PartyChecker,0;
			set .status,0;
			mapwarp .mapName$, .mapName$, 81,50;
		} else {
      			getpartymember($PartyChecker,2);
        		set .@partymembercount, $@partymembercount;
        		copyarray .@partymemberaid[0], $@partymemberaid[0], .@partymembercount;
        		for (set .@i, 0; .@i < .@partymembercount; .@i ++) {

               			if (attachrid(.@partymemberaid[.@i])) {
   					if(strcharinfo(PC_MAP) == .mapName$ && Hp > 1) {
						set .@count,.@count + 1;
					}
                		}
        		}
			if(.@count <= 1){
				set .timerinit,0;
				playbgmall("93",.mapName$);
				announce "[ BTA ] Party [ "+getpartyname($PartyChecker)+" ] has been wiped out at Boss Timed Attack.",16;
				if(.qid) queuedel .qid;
				killmonster .mapName$,"All";
				set $@locked, 0;
				set $PartyChecker,0;
				set .status,0;
				mapwarp .mapName$, .mapName$, 81,50;
			}
		}

		end;


	OnPCDieEvent:
		if(getcharid(CHAR_ID_PARTY) == $PartyChecker && $@locked && .status ){
       			getpartymember(getcharid(CHAR_ID_PARTY),2);
        		set .@partymembercount, $@partymembercount;
        		copyarray .@partymemberaid[0], $@partymemberaid[0], .@partymembercount;
        		for (set .@i, 0; .@i < .@partymembercount; .@i ++) {

               			if (attachrid(.@partymemberaid[.@i])) {
   					if(strcharinfo(PC_MAP) == .mapName$ && Hp > 1) {
						set .@count,.@count + 1;
					}
                		}
        		}
			if(!.@count){
				set .timerinit,0;
				playbgmall("93",.mapName$);
				if(.qid) queuedel .qid;
				announce "[ BTA ] Party [ "+getpartyname($PartyChecker)+" ] has been wiped out at Boss Timed Attack.",16;
				killmonster .mapName$,"All";
				set $@locked, 0;
				set $PartyChecker,0;
				set .status,0;
				mapwarp .mapName$, .mapName$, 81,50;
			}

		}
		end;

	OnPCLoadMapEvent:
		if (strcharinfo(PC_MAP) == .mapName$ && !$@locked) {
			if (spectator) {
				set spectator,0;
				set Hp,shp;
				set Sp,ssp;
				setoption Option_Invisible, 0;
				sc_end(SC_XMAS);
				warp slastmap$,slastx,slasty;
			} else {
				warp $mapSave$,$@mapSaveCordX,$@mapSaveCordY;
			}
		}
		end;	


function	party_has_duplicate_job	{
    set .@party_id, getarg( 0, getcharid(1) );

    // Need to have a party.
    if ( !.@party_id )
    {
            return -1;
    }

    // Loading party members variables
    getpartymember .@party_id, 1;
    getpartymember .@party_id, 2;

    // Keep rid attached.
    set .@rid, playerattached();


    // Check all members
    for ( set .@i,0; .@i<$@partymembercount; set .@i, .@i+1 )
    {

        // Online user
        if ( isloggedin( $@partymemberaid[.@i], $@partymembercid[.@i]) )
        {
            // Attach the member to access "Class"
            attachrid( $@partymemberaid[.@i] );
			savepoint $mapSave$, $@mapSaveCordX, $@mapSaveCordY;
            if ( compare( .@tmp_class$ + "|", "|" + Class + "|" ) )
            {
                if ( .@rid )
                    attachrid(.@rid);
                else
                    detachrid;
                return 1;
            }
            set .@tmp_class$, .@tmp_class$ + "|" + Class;
        }

        // Offline user (use sql)
        else
        {
            set .@sql$, .@sql$ + ( .@sql_i ? "OR " : "" ) + "`char_id`='" + $@partymembercid[.@i] + "' ";
            set .@sql_i, .@sql_i + 1;
        }
    }

    // SQL for offline users
    if ( getstrlen(.@sql$) )
    {
        // get class from offline members
        set .@count, query_sql("SELECT `class` FROM `char` WHERE " + .@sql$, .@class );

        // Check the class.
        for ( set .@i, 0; .@i<.@count; set .@i, .@i+1 )
        {
            if ( compare( .@tmp_class$ + "|", "|" + .@class[.@i] + "|" ) )
            {
                if ( .@rid )
                    attachrid(.@rid);
                else
                    detachrid;
                return 1;
            }
            set .@tmp_class$, .@tmp_class$ + "|" + .@class[.@i];
        }
    }

    // Restore RID.
    if ( .@rid )
        attachrid(.@rid);
    else
        detachrid;

    return 0;
}

function	BTA_Points	{
	set .@num_rows, query_sql("SELECT `id`,`player_ids` FROM `bta_db` WHERE `party_name` = '"+getpartyname(getcharid(1))+"'", .@id, .@charIds$);
	if (.@num_rows > 0) {
		set .@continue,0;
		for( set .@i,0; .@i < .@num_rows; set .@i,.@i + 1 ) {
			getpartymember getcharid(1),1;
			
			// Explode the character Ids
			explode(.@my_array$ ,.@charIds$, ",");
			set .@arraysize, getarraysize(.@my_array$);
			
			for ( set .@k, 0; .@k < $@partymembercount; set .@k , .@k + 1 ) {
				// Loop to list out the party names
				for( set .@j,0; .@j < .@arraysize; set .@j,.@j + 1 ) {
					// Convert to number to compare character IDs
					set $@playerNumber, .@my_array$[.@j];
					if ($@partymembercid[.@k] == $@playerNumber) {
						set .@continue,1;
						break;
					} else {
						set .@continue,0;
					}
				}
				if (.@continue == 0) {
					break;
				}
			}
		}
		if (.@continue == 0) {
			for ( set .@m, 0; .@m < $@partymembercount; set .@m , .@m + 1 ) {
				if (.@m == $@partymembercount - 1) {
					set .@name1$,.@name1$ + $@partymembercid[.@m];
				} else {
					set .@name1$,.@name1$ + $@partymembercid[.@m] + ",";
				}
			}
			query_sql "INSERT INTO `bta_db` (`party_name`,`player_ids`,`time`) VALUES ('"+getpartyname(getcharid(1))+"','"+.@name1$+"','"+getarg(0)+"')";
		} else {
			query_sql("UPDATE `bta_db` SET `time`='"+getarg(0)+"' WHERE `id`='"+.@id+"'");
		}
	} else {
		getpartymember getcharid(1),1;
		for ( set .@i, 0; .@i < $@partymembercount; set .@i , .@i + 1 ) {
			if (.@i == $@partymembercount - 1) {
				set .@name1$,.@name1$ + $@partymembercid[.@i];
			} else {
				set .@name1$,.@name1$ + $@partymembercid[.@i] + ",";
			}
		}
		query_sql "INSERT INTO `bta_db` (`party_name`,`player_ids`,`time`) VALUES ('"+getpartyname(getcharid(1))+"','"+.@name1$+"','"+getarg(0)+"')";
	}
	return;
}

	/////////////////
	// Configuration
	/////////////////

	OnInit:
		set .debug, 0;
		set .maxtries,3;
		setarray .noclass[0],24,25,4049,4019,4047;		// List of disabled class
		set .eject,0;
		set .enable,1;						// Disable BTA at startup
		set .spectator,1;					// Enable Spectator in the arena
		set .register_cost, 300000;				// Zeny Requirements
		set .register_item, 0;					// Item Requirements
		set .register_min, 3;					// Party Members Needed	
		setarray .Reward[0],14003,5,7179,2;			// Set Reward Item
		setarray .Reward2[0],14003,5,30259,2;			// Set Reward Item
		set .MvP1,1147;	// Maya
		set .MvP2,1115;	// Eddga
		set .MvP3,1583;	// Tao
		set .MvP4,1251;	// Stormy
		set .MvP5,1734;	// Kiel
		set .deadlock,1;					// Prevent spectate when dead
		set .GMAccess,99;					// GM level to access setup.
		set .globalAnnounce,1;					// 0 - Map Announcement, 1 - Global Announcement
		set .onesec,1000;					// will handle announcement in seconds
		set .dupejobs,0;
	
		// Get Party Name
		set $NPCParty$,"";

		
		// NPC Setup 
		set .mapNPC$,"prontera";		// NPC Location
		set $mapSave$,"prontera";		// Save Location
		set $@mapSaveCordX,145;			// X-Coordinate where player save point is set
		set $@mapSaveCordY,93;			// Y-Coordinate where player save point is set

		set .mapName$,"guild_vs5";		// Event Location
		set .spawnCordX,50;			// X-Coordinate where the monster spawns
		set .spawnCordY,55;			// Y-Coordinate where the monster spawns
		set .warpx,20;				// X-Coordinate where the party members warped
		set .warpy,49;				// Y-Coordinate where the party members warped
		set .wwarpx,28;				// X-Coordinate where the watchers warped
		set .wwarpy,50;				// Y-Coordinate where the warchers warped
		setcell(.mapName$, 0, 0, 300, 300, cell_nochat, true);
		set .timerinit,0;

		bindatcmd "bta","Paradox::OnSpectate",0,99;
		bindatcmd "btareset","Paradox::OnReset",99,99;
		bindatcmd "btareward","Paradox::OnGiveReward",99,99;
		end;


}



-	script	BTAUPDATE	HIDDEN_NPC,{
	OnInit:	

	while( 1 ){
			set .Time,30;		// Announce every x Minute.
			query_sql( "SELECT `party_name`,`player_ids`,`time` FROM `bta_db` ORDER BY `time` ASC LIMIT 1",.@party$,.@charIds$,.@time );
			if(!.@time)end;
			set .@h,.@time[.@i] % 86400 / 3600;
			set .@m,.@time[.@i] % 3600 / 60;
			set .@s,.@time[.@i] % 60;
			set .@h$, .@h+" hr"+((.@h <= 1)?"":"s"); 
			set .@m$, .@m+" min"+((.@m <= 1)?"":"s");
			set .@s$, .@s+" second"+((.@s <= 1)?"":"s");
			set .@time$,""+.@h$+" "+.@m$+" "+.@s$+"";
			announce "[Update] Boss Time Attack Rank 1 party is [ "+.@party$+" ] with a time of "+.@time$+".",0;
			sleep ( .Time * 60000 );
	}
	end;
}



guild_vs5,49,47,1	script	BestTime	HIDDEN_NPC,{
end;

OnStart:
	query_sql( "SELECT `party_name`,`player_ids`,`time` FROM `bta_db` ORDER BY `time` ASC LIMIT 1",.@party$,.@charIds$,.@time );
	if(!.@time) end;
        set .@dif, strnpcinfo(2);
        set .remind[.@dif], 0;
        set .starttime[.@dif], gettimetick(2);
        do {
		if (!getvariableofnpc(.timerinit,"Paradox")) {
               		set .remaintime[.@dif], .@time + .starttime[.@dif] - gettimetick(2);
              		set .@hour[.@dif], .remaintime[.@dif] / 3600 ;
               		set .@min[.@dif], .remaintime[.@dif] % 3600 / 60 ;
              		set .@sec[.@dif], .remaintime[.@dif] % 3600 % 60 ;
               		delwaitingroom strnpcinfo(0);
                	waitingroom "Best Time = "+( ( .@hour[.@dif] )?( .@hour[.@dif] +":"):"" )+( ( .@min[.@dif] < 10 )?"0"+ .@min[.@dif]: .@min[.@dif] )+":"+( ( .@sec[.@dif] < 10 )?"0"+ .@sec[.@dif]: .@sec[.@dif] ), 0;
			end;
		}
                set .remaintime[.@dif], .@time + .starttime[.@dif] - gettimetick(2);
                set .@hour[.@dif], .remaintime[.@dif] / 3600 ;
                set .@min[.@dif], .remaintime[.@dif] % 3600 / 60 ;
                set .@sec[.@dif], .remaintime[.@dif] % 3600 % 60 ;
                delwaitingroom strnpcinfo(0);
                waitingroom "Time Left = "+( ( .@hour[.@dif] )?( .@hour[.@dif] +":"):"" )+( ( .@min[.@dif] < 10 )?"0"+ .@min[.@dif]: .@min[.@dif] )+":"+( ( .@sec[.@dif] < 10 )?"0"+ .@sec[.@dif]: .@sec[.@dif] ), 0;
                sleep 995;

        } while ( .remaintime[.@dif] > 1 );
        set .remaintime[.@dif], 0;
        delwaitingroom "BestTime#"+ .@dif;
	donpcevent "Paradox::OnTimesUP";	
        end;
}