Resolves some Battleground issues (#4725)

* Queue data will now be kept available until a Battleground event is over.
* Players can now join an active Battleground.
* Adds a more detailed queue state tracking feature.
* When a battleground is being prepared and not enough players click accept, stop the battleground from beginning.
* When a player logs off or leaves a queue they will now properly be removed from the queue.
* Cleans up MinPlayers and MaxPlayers parsing to not accept values less than 1.
* Resolves players not being able to join an active battleground (up to MaxPlayers) unless someone quit early.
* Adds a team size priority check to avoid adding more players to a larger team.
* Fixes battlechat messages.
* Adds a battle_config to disable the ability for players on maps with MF_NOWARP to join Battlegrounds.
* Adds a new optional ActiveEvent label to the database.
* Fixes a typo in Flavius 2 during unbooking process.
* Cleans up the behavior of the Battle Therapists to use areapercentheal and areawarp.
* Fixes KVM score not properly set on the first Battleground.
* Fixes the global timer checks not ending the main timers on Flavius and Tierra Gorge.
* Added an extra bg_reserve on global timer checks in case someone tries to join the battleground just before it's ended.
* Fixed OnReadyCheck being called on global timer checks, causing the battlegrounds to start when there were no players on the map.
* Fixed a bug on Tierra Gorge where multiple barricade walls could be stacked.
* Fixes Croix also receiving 9 badges when Guillaume wins.
* Adjusts StartDelay default to 0.
* Add a database setting to give the ability to enable or disable joining as an individual, party, or guild.
* Add a database setting to restrict jobs from entering Battlegrounds.
* Better documents script commands bg_reserve and bg_unbook.
* Other fixes and cleanups.
Thanks to @roSBK and @Daegaladh, @admkakaroto, @Artuvazro, and @Atemo!
Co-authored-by: Daegaladh <Daegaladh@users.noreply.github.com>
Co-authored-by: Atemo <Atemo@users.noreply.github.com>
This commit is contained in:
Aleos 2020-05-25 12:39:36 -04:00 committed by GitHub
parent e6bffc11fe
commit 14c388b401
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 940 additions and 376 deletions

View File

@ -30,3 +30,7 @@ bg_flee_penalty: 20
// Interval before updating the bg-member map mini-dots (milliseconds)
bg_update_interval: 1000
// Before a player is warped into a Battleground from the Battleground Queue,
// check to see if the player's current map has MF_NOWARP.
bgqueue_nowarp_mapflag: no

View File

@ -354,9 +354,10 @@
334: Total Domination
// Battlegrounds Queue
337: You may not join a battleground queue when you're in a battleground map.
337: You can't apply to a battleground queue from this map.
338: You can't apply to a battleground queue due to recently deserting a battleground. Time remaining: %d minutes and %d seconds.
339: You can't apply to a battleground queue for %d seconds due to recently leaving one.
340: Participants were unable to join. Delaying entry for more participants.
// Templates for @who output
343: Name: %s

View File

@ -29,7 +29,12 @@
# MinLevel Minimum level required to join the battleground. (Default: 1)
# MaxLevel Maximum level to join the battleground. (Default: MAX_LEVEL value)
# Deserter Amount of time in seconds a player is marked deserter. (Default: 600)
# StartDelay Amount of time in seconds once a queue is filled before a start message is sent to players. (Default: 30)
# StartDelay Amount of time in seconds once a queue is filled before players are warped. (Default: 0)
# Join: Which application type is accepted. The entryqueuelist.lub can visually disable these options.
# Solo Able to join a queue as an individual. (Default: true)
# Party Able to join a queue as a party. (Default: true)
# Guild Able to join a queue as a guild. (Default: true)
# JobRestrictions List of jobs that are unable to join the battleground.
# Locations: Battleground location settings.
# - Map The map on which the battleground will be played.
# StartEvent NPC event triggered when the battleground starts.
@ -38,12 +43,14 @@
# RespawnY Y coordinate for warping on death.
# DeathEvent NPC event triggered when a player dies.
# QuitEvent NPC event triggered when a player quits.
# ActiveEvent NPC event triggered when a player joints an active battleground.
# Variable Name of BG ID variable used in the battleground script.
# TeamB: TeamB settings.
# RespawnX X coordinate for warping on death.
# RespawnY Y coordinate for warping on death.
# DeathEvent NPC event triggered when a player dies.
# QuitEvent NPC event triggered when a player quits.
# ActiveEvent NPC event triggered when a player joints an active battleground.
# Variable Name of BG ID variable used in the battleground script.
###########################################################################
@ -53,121 +60,151 @@ Header:
Body:
- Id: 1
Name: "Tierra Gorge"
Name: Tierra Gorge
MinPlayers: 6
MinLevel: 80
JobRestrictions:
Novice: true
SuperNovice: true
Novice_High: true
Baby: true
Super_Baby: true
Super_Novice_E: true
Super_Baby_E: true
Locations:
- Map: "bat_a01"
StartEvent: "start#bat_a01::OnReadyCheck"
- Map: bat_a01
StartEvent: start#bat_a01::OnReadyCheck
TeamA:
RespawnX: 50
RespawnY: 374
QuitEvent: "start#bat_a01::OnGuillaumeQuit"
Variable: "$@TierraBG1_id1"
QuitEvent: start#bat_a01::OnGuillaumeQuit
ActiveEvent: start#bat_a01::OnGuillaumeActive
Variable: $@TierraBG1_id1
TeamB:
RespawnX: 42
RespawnY: 16
QuitEvent: "start#bat_a01::OnCroixQuit"
Variable: "$@TierraBG1_id2"
- Map: "bat_a02"
StartEvent: "start#bat_a02::OnReadyCheck"
QuitEvent: start#bat_a01::OnCroixQuit
ActiveEvent: start#bat_a01::OnCroixActive
Variable: $@TierraBG1_id2
- Map: bat_a02
StartEvent: start#bat_a02::OnReadyCheck
TeamA:
RespawnX: 50
RespawnY: 374
QuitEvent: "start#bat_a02::OnGuillaumeQuit"
Variable: "$@TierraBG2_id1"
QuitEvent: start#bat_a02::OnGuillaumeQuit
ActiveEvent: start#bat_a02::OnGuillaumeActive
Variable: $@TierraBG2_id1
TeamB:
RespawnX: 42
RespawnY: 16
QuitEvent: "start#bat_a02::OnCroixQuit"
Variable: "$@TierraBG2_id2"
QuitEvent: start#bat_a02::OnCroixQuit
ActiveEvent: start#bat_a02::OnCroixActive
Variable: $@TierraBG2_id2
- Id: 2
Name: "Flavius"
Name: Flavius
MinPlayers: 6
MinLevel: 80
JobRestrictions:
Novice: true
SuperNovice: true
Novice_High: true
Baby: true
Super_Baby: true
Super_Novice_E: true
Super_Baby_E: true
Locations:
- Map: "bat_b01"
StartEvent: "start#bat_b01::OnReadyCheck"
- Map: bat_b01
StartEvent: start#bat_b01::OnReadyCheck
TeamA:
RespawnX: 10
RespawnY: 290
QuitEvent: "start#bat_b01::OnGuillaumeQuit"
Variable: "$@FlaviusBG1_id1"
QuitEvent: start#bat_b01::OnGuillaumeQuit
ActiveEvent: start#bat_b01::OnGuillaumeActive
Variable: $@FlaviusBG1_id1
TeamB:
RespawnX: 390
RespawnY: 10
QuitEvent: "start#bat_b01::OnCroixQuit"
Variable: "$@FlaviusBG1_id2"
- Map: "bat_b02"
StartEvent: "start#bat_b02::OnReadyCheck"
QuitEvent: start#bat_b01::OnCroixQuit
ActiveEvent: start#bat_b01::OnCroixActive
Variable: $@FlaviusBG1_id2
- Map: bat_b02
StartEvent: start#bat_b02::OnReadyCheck
TeamA:
RespawnX: 10
RespawnY: 290
QuitEvent: "start#bat_b02::OnGuillaumeQuit"
Variable: "$@FlaviusBG2_id1"
QuitEvent: start#bat_b02::OnGuillaumeQuit
ActiveEvent: start#bat_b02::OnGuillaumeActive
Variable: $@FlaviusBG2_id1
TeamB:
RespawnX: 390
RespawnY: 10
QuitEvent: "start#bat_b02::OnCroixQuit"
Variable: "$@FlaviusBG2_id2"
QuitEvent: start#bat_b02::OnCroixQuit
ActiveEvent: start#bat_b02::OnCroixActive
Variable: $@FlaviusBG2_id2
- Id: 3
Name: "KVM (Level 80 and up)"
Name: KVM (Level 80 and up)
MinPlayers: 5
MinLevel: 80
Locations:
- Map: "bat_c01"
StartEvent: "KvM01_BG::OnStart"
- Map: bat_c01
StartEvent: KvM01_BG::OnStart
TeamA:
RespawnX: 52
RespawnY: 129
DeathEvent: "KvM01_BG::OnGuillaumeDie"
QuitEvent: "KvM01_BG::OnGuillaumeQuit"
Variable: "$@KvM01BG_id1"
DeathEvent: KvM01_BG::OnGuillaumeDie
QuitEvent: KvM01_BG::OnGuillaumeQuit
ActiveEvent: KvM01_BG::OnGuillaumeActive
Variable: $@KvM01BG_id1
TeamB:
RespawnX: 147
RespawnY: 55
DeathEvent: "KvM01_BG::OnCroixDie"
QuitEvent: "KvM01_BG::OnCroixQuit"
Variable: "$@KvM01BG_id2"
DeathEvent: KvM01_BG::OnCroixDie
QuitEvent: KvM01_BG::OnCroixQuit
ActiveEvent: KvM01_BG::OnCroixActive
Variable: $@KvM01BG_id2
- Id: 4
Name: "KVM (Level 60~79)"
Name: KVM (Level 60~79)
MinPlayers: 5
MinLevel: 60
MaxLevel: 79
Locations:
- Map: "bat_c02"
StartEvent: "KvM02_BG::OnStart"
- Map: bat_c02
StartEvent: KvM02_BG::OnStart
TeamA:
RespawnX: 52
RespawnY: 129
DeathEvent: "KvM02_BG::OnGuillaumeDie"
QuitEvent: "KvM02_BG::OnGuillaumeQuit"
Variable: "$@KvM02BG_id1"
DeathEvent: KvM02_BG::OnGuillaumeDie
QuitEvent: KvM02_BG::OnGuillaumeQuit
ActiveEvent: KvM02_BG::OnGuillaumeActive
Variable: $@KvM02BG_id1
TeamB:
RespawnX: 147
RespawnY: 55
DeathEvent: "KvM02_BG::OnCroixDie"
QuitEvent: "KvM02_BG::OnCroixQuit"
Variable: "$@KvM02BG_id2"
DeathEvent: KvM02_BG::OnCroixDie
QuitEvent: KvM02_BG::OnCroixQuit
ActiveEvent: KvM02_BG::OnCroixActive
Variable: $@KvM02BG_id2
- Id: 5
Name: "KVM (Level 59 and below"
Name: KVM (Level 59 and below
MinPlayers: 5
MaxLevel: 59
Locations:
- Map: "bat_c03"
StartEvent: "KvM03_BG::OnStart"
- Map: bat_c03
StartEvent: KvM03_BG::OnStart
TeamA:
RespawnX: 52
RespawnY: 129
DeathEvent: "KvM03_BG::OnGuillaumeDie"
QuitEvent: "KvM03_BG::OnGuillaumeQuit"
Variable: "$@KvM03BG_id1"
DeathEvent: KvM03_BG::OnGuillaumeDie
QuitEvent: KvM03_BG::OnGuillaumeQuit
ActiveEvent: KvM03_BG::OnGuillaumeActive
Variable: $@KvM03BG_id1
TeamB:
RespawnX: 147
RespawnY: 55
DeathEvent: "KvM03_BG::OnCroixDie"
QuitEvent: "KvM03_BG::OnCroixQuit"
Variable: "$@KvM03BG_id2"
DeathEvent: KvM03_BG::OnCroixDie
QuitEvent: KvM03_BG::OnCroixQuit
ActiveEvent: KvM03_BG::OnCroixActive
Variable: $@KvM03BG_id2
Footer:
Imports:

View File

@ -29,7 +29,12 @@
# MinLevel Minimum level required to join the battleground. (Default: 1)
# MaxLevel Maximum level to join the battleground. (Default: MAX_LEVEL value)
# Deserter Amount of time in seconds a player is marked deserter. (Default: 600)
# StartDelay Amount of time in seconds once a queue is filled before a start message is sent to players. (Default: 30)
# StartDelay Amount of time in seconds once a queue is filled before players are warped. (Default: 0)
# Join: Which application type is accepted. The entryqueuelist.lub can visually disable these options.
# Solo Able to join a queue as an individual. (Default: true)
# Party Able to join a queue as a party. (Default: true)
# Guild Able to join a queue as a guild. (Default: true)
# JobRestrictions List of jobs that are unable to join the battleground.
# Locations: Battleground location settings.
# - Map The map on which the battleground will be played.
# StartEvent NPC event triggered when the battleground starts.
@ -38,12 +43,14 @@
# RespawnY Y coordinate for warping on death.
# DeathEvent NPC event triggered when a player dies.
# QuitEvent NPC event triggered when a player quits.
# ActiveEvent NPC event triggered when a player joints an active battleground.
# Variable Name of BG ID variable used in the battleground script.
# TeamB: TeamB settings.
# RespawnX X coordinate for warping on death.
# RespawnY Y coordinate for warping on death.
# DeathEvent NPC event triggered when a player dies.
# QuitEvent NPC event triggered when a player quits.
# ActiveEvent NPC event triggered when a player joints an active battleground.
# Variable Name of BG ID variable used in the battleground script.
###########################################################################

View File

@ -9393,19 +9393,19 @@ Example:
---------------------------------------
*bg_reserve("<battleground_name>");
*bg_reserve("<battleground_map_name>"{,<ended>});
Reserves a slot for the given Battleground for the Battleground UI System.
Reserves a Battleground map for the Battleground UI System. When a map is booked it prevents another similar
queue from being created and will allow players to join an active Battlegrounds event.
Note: 'bg_reserve' and 'bg_unbook' prevent the Battlegrounds queue from joining players in an active Battleground.
If <ended> is true, then the Battleground is marked as over to prevent new players from joining. This state is meant
for the period where players can get their Badges.
---------------------------------------
*bg_unbook("<battleground_name>");
*bg_unbook("<battleground_map_name>");
Removes a spot for the given Battleground for the Battleground UI System.
Note: 'bg_reserve' and 'bg_unbook' prevent the Battlegrounds queue from joining players in an active Battleground.
Removes a Battleground map for the Battleground UI System. When a map is unbooked it allows a queue to be created.
---------------------------------------

View File

@ -58,25 +58,21 @@ OnStop:
OnTimer1000:
stopnpctimer;
if (!getbattleflag("feature.bgqueue"))
initnpctimer;
set .@chk_bat_a01,getmapusers("bat_b01");
if (.@chk_bat_a01 < 1) {
set $@FlaviusBG1, 0;
if( $@FlaviusBG1_id1 ) { bg_destroy $@FlaviusBG1_id1; set $@FlaviusBG1_id1, 0; }
if( $@FlaviusBG1_id2 ) { bg_destroy $@FlaviusBG1_id2; set $@FlaviusBG1_id2, 0; }
if (getbattleflag("feature.bgqueue")) {
if (bg_get_data($@FlaviusBG1_id1, 0) == 0 && bg_get_data($@FlaviusBG1_id2, 0) == 0) {
donpcevent "countdown#bat_b01::OnStop";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_b01", true;
$@FlaviusBG1 = 0;
if( $@FlaviusBG1_id1 ) { bg_destroy $@FlaviusBG1_id1; $@FlaviusBG1_id1 = 0; }
if( $@FlaviusBG1_id2 ) { bg_destroy $@FlaviusBG1_id2; $@FlaviusBG1_id2 = 0; }
if (getbattleflag("feature.bgqueue"))
bg_unbook "bat_b01";
end;
} else
donpcevent "start#bat_b01::OnReadyCheck";
end;
}
if (getbattleflag("feature.bgqueue"))
initnpctimer;
initnpctimer;
end;
}
// Flavius Battleground Engine
//============================================================
bat_b01,15,15,3 script start#bat_b01 844,{
@ -139,13 +135,14 @@ OnReset:
donpcevent "guardian#bat_b01_b::OnEnable";
donpcevent "cell#bat_b01_a::OnRed";
donpcevent "cell#bat_b01_b::OnRed";
donpcevent "time#bat_b01::OnEnable";
disablenpc "Guillaume Vintenar#b01_a";
disablenpc "Croix Vintenar#b01_b";
disablenpc "Vintenar#bat_b01_aover";
disablenpc "Vintenar#bat_b01_bover";
bg_warp $@FlaviusBG1_id1,"bat_b01",87,75;
bg_warp $@FlaviusBG1_id2,"bat_b01",311,224;
end;
OnGuillaumeActive:
warp "bat_b01",87,75;
end;
OnCroixActive:
warp "bat_b01",311,224;
end;
OnGuillaumeQuit:
@ -181,6 +178,8 @@ OnMyMobDead:
enablenpc "Guillaume Vintenar#b01_a";
enablenpc "Croix Vintenar#b01_b";
donpcevent "time#bat_b01::OnStop";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_b01", true;
}
else {
set $@Croix_ScoreBG1,1;
@ -215,6 +214,8 @@ OnMyMobDead:
enablenpc "Guillaume Vintenar#b01_a";
enablenpc "Croix Vintenar#b01_b";
donpcevent "time#bat_b01::OnStop";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_b01", true;
}
else {
set $@Guill_ScoreBG1,1;
@ -314,12 +315,14 @@ bat_b01,10,294,3 script Battle Therapist#b01_a 95,{
OnTimer25000:
specialeffect EF_SANCTUARY;
enablenpc "bat_b01_rp1_a_warp";
// enablenpc "bat_b01_rp1_a_warp";
areapercentheal "bat_b01",0,280,20,300,100,100;
areawarp "bat_b01",0,280,20,300,"bat_b01",87,73;
end;
OnTimer26000:
disablenpc "bat_b01_rp1_a_warp";
end;
// OnTimer26000:
// disablenpc "bat_b01_rp1_a_warp";
// end;
OnTimer26500:
stopnpctimer;
@ -332,22 +335,25 @@ OnEnable:
end;
OnStop:
disablenpc "bat_b01_rp1_a_warp";
// disablenpc "bat_b01_rp1_a_warp";
disablenpc "Battle Therapist#b01_a";
stopnpctimer;
end;
}
/*
// replaced by areapercentheal and areawarp to prevent enqueue issue
bat_b01,10,290,0 script bat_b01_rp1_a_warp 45,10,10,{
OnInit:
disablenpc "bat_b01_rp1_a_warp";
end;
OnTouch_:
OnTouch:
percentheal 100,100;
warp "bat_b01",87,73;
end;
}
*/
bat_b01,389,14,3 script Battle Therapist#b01_b 95,{
specialeffect2 EF_HEAL;
@ -359,12 +365,14 @@ bat_b01,389,14,3 script Battle Therapist#b01_b 95,{
OnTimer25000:
specialeffect EF_SANCTUARY;
enablenpc "bat_b01_rp1_b_warp";
// enablenpc "bat_b01_rp1_b_warp";
areapercentheal "bat_b01",379,0,399,20,100,100;
areawarp "bat_b01",379,0,399,20,"bat_b01",312,225;
end;
OnTimer26000:
disablenpc "bat_b01_rp1_b_warp";
end;
// OnTimer26000:
// disablenpc "bat_b01_rp1_b_warp";
// end;
OnTimer26500:
stopnpctimer;
@ -377,15 +385,16 @@ OnEnable:
end;
OnStop:
disablenpc "bat_b01_rp1_b_warp";
// disablenpc "bat_b01_rp1_b_warp";
disablenpc "Battle Therapist#b01_b";
stopnpctimer;
end;
}
bat_b01,389,10,0 script bat_b01_rp1_b_warp 45,9,9,{
/*
bat_b01,389,10,0 script bat_b01_rp1_b_warp 45,10,10,{
OnInit:
disablenpc "bat_b01_rp1_a_warp";
disablenpc "bat_b01_rp1_b_warp";
end;
OnTouch:
@ -393,6 +402,7 @@ OnTouch:
warp "bat_b01",312,225;
end;
}
*/
bat_b01,87,76,0 script A_CODE#bat_b01 -1,5,5,{
OnTouch:
@ -490,6 +500,8 @@ OnTimer1830000:
bg_warp $@FlaviusBG1_id2,"bat_b01",390,10;
enablenpc "Vintenar#bat_b01_aover";
enablenpc "Vintenar#bat_b01_bover";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_b01", true;
end;
OnTimer1900000:
@ -526,11 +538,11 @@ bat_b01,10,294,3 script Vintenar#bat_b01_aover 419,{
set .@A_B_gap,$@Guill_ScoreBG1 - $@Croix_ScoreBG1;
if ($@FlaviusBG1_id1 == getcharid(4)) {
if (.@A_B_gap > 0)
callfunc "F_BG_Badge",1,"Guillaume","Flavius";
callfunc "F_BG_Badge",1,"Guillaume","Flavius"; //Guillaume wins
else if (.@A_B_gap == 0)
callfunc "F_BG_Badge",0,"Guillaume","Flavius";
callfunc "F_BG_Badge",0,"Guillaume","Flavius"; //Tie
else
callfunc "F_BG_Badge",0,"Guillaume","Flavius";
callfunc "F_BG_Badge",0,"Guillaume","Flavius"; //Croix wins
}
else {
mes "[Axl Rose]";
@ -551,11 +563,11 @@ bat_b01,389,14,3 script Vintenar#bat_b01_bover 415,{
set .@A_B_gap,$@Guill_ScoreBG1 - $@Croix_ScoreBG1;
if ($@FlaviusBG1_id2 == getcharid(4)) {
if (.@A_B_gap > 0)
callfunc "F_BG_Badge",1,"Croix","Flavius";
callfunc "F_BG_Badge",0,"Croix","Flavius"; //Guillaume wins
else if (.@A_B_gap == 0)
callfunc "F_BG_Badge",0,"Croix","Flavius";
callfunc "F_BG_Badge",0,"Croix","Flavius"; //Tie
else
callfunc "F_BG_Badge",1,"Croix","Flavius";
callfunc "F_BG_Badge",1,"Croix","Flavius"; //Croix wins
}
else {
mes "[Swandery]";

View File

@ -59,21 +59,18 @@ OnStop:
OnTimer1000:
stopnpctimer;
if (!getbattleflag("feature.bgqueue"))
initnpctimer;
set .@chk_bat_a01,getmapusers("bat_b02");
if (.@chk_bat_a01 < 1) {
set $@FlaviusBG2, 0;
if( $@FlaviusBG2_id1 ) { bg_destroy $@FlaviusBG2_id1; set $@FlaviusBG2_id1, 0; }
if( $@FlaviusBG2_id2 ) { bg_destroy $@FlaviusBG2_id2; set $@FlaviusBG2_id2, 0; }
if (getbattleflag("feature.bgqueue")) {
bg_unbook "bat_b01";
end;
} else
donpcevent "start#bat_b01::OnReadyCheck";
if (bg_get_data($@FlaviusBG2_id1, 0) == 0 && bg_get_data($@FlaviusBG2_id2, 0) == 0) {
donpcevent "countdown#bat_b02::OnStop";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_b02", true;
$@FlaviusBG2 = 0;
if( $@FlaviusBG2_id1 ) { bg_destroy $@FlaviusBG2_id1; $@FlaviusBG2_id1 = 0; }
if( $@FlaviusBG2_id2 ) { bg_destroy $@FlaviusBG2_id2; $@FlaviusBG2_id2 = 0; }
if (getbattleflag("feature.bgqueue"))
bg_unbook "bat_b02";
end;
}
if (getbattleflag("feature.bgqueue"))
initnpctimer;
initnpctimer;
end;
}
@ -89,7 +86,7 @@ OnReadyCheck:
if( $@FlaviusBG2 )
end;
if (!getbattleflag("feature.bgqueue")) {
set .@Guillaume, getwaitingroomstate(0,"Lieutenant Huvas");
set .@Guillaume, getwaitingroomstate(0,"Lieutenant Huvas");
set .@Croix, getwaitingroomstate(0,"Lieutenant Yukon");
if( !.@Guillaume && !.@Croix ) {
donpcevent "#bat_b02_timer::OnStop";
@ -102,8 +99,8 @@ OnReadyCheck:
set $@FlaviusBG2_Victory, 0;
set $@Croix_ScoreBG2, 0;
set $@Guill_ScoreBG2, 0;
bg_updatescore "bat_b02",$@Guill_ScoreBG2,$@Croix_ScoreBG2;
if (!getbattleflag("feature.bgqueue")) {
donpcevent "Lieutenant Huvas::OnEnterBG";
donpcevent "Lieutenant Yukon::OnEnterBG";
@ -140,13 +137,14 @@ OnReset:
donpcevent "guardian#bat_b02_b::OnEnable";
donpcevent "cell#bat_b02_a::OnRed";
donpcevent "cell#bat_b02_b::OnRed";
donpcevent "time#bat_b02::OnEnable";
disablenpc "Guillaume Vintenar#b02_a";
disablenpc "Croix Vintenar#b02_b";
disablenpc "Vintenar#bat_b02_aover";
disablenpc "Vintenar#bat_b02_bover";
bg_warp $@FlaviusBG2_id1,"bat_b02",87,75;
bg_warp $@FlaviusBG2_id2,"bat_b02",311,224;
end;
OnGuillaumeActive:
warp "bat_b02",87,75;
end;
OnCroixActive:
warp "bat_b02",311,224;
end;
OnGuillaumeQuit:
@ -182,6 +180,8 @@ OnMyMobDead:
enablenpc "Guillaume Vintenar#b02_a";
enablenpc "Croix Vintenar#b02_b";
donpcevent "time#bat_b02::OnStop";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_b02", true;
}
else {
set $@Croix_ScoreBG2,1;
@ -216,6 +216,8 @@ OnMyMobDead:
enablenpc "Guillaume Vintenar#b02_a";
enablenpc "Croix Vintenar#b02_b";
donpcevent "time#bat_b02::OnStop";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_b02", true;
}
else {
set $@Guill_ScoreBG2,1;
@ -315,12 +317,14 @@ bat_b02,10,294,3 script Battle Therapist#b02_a 95,{
OnTimer25000:
specialeffect EF_SANCTUARY;
enablenpc "bat_b02_rp1_a_warp";
// enablenpc "bat_b02_rp1_a_warp";
areapercentheal "bat_b02",0,280,20,300,100,100;
areawarp "bat_b02",0,280,20,300,"bat_b02",87,73;
end;
OnTimer26000:
disablenpc "bat_b02_rp1_a_warp";
end;
// OnTimer26000:
// disablenpc "bat_b02_rp1_a_warp";
// end;
OnTimer26500:
stopnpctimer;
@ -333,22 +337,24 @@ OnEnable:
end;
OnStop:
disablenpc "bat_b02_rp1_a_warp";
// disablenpc "bat_b02_rp1_a_warp";
disablenpc "Battle Therapist#b02_a";
stopnpctimer;
end;
}
/*
bat_b02,10,290,0 script bat_b02_rp1_a_warp 45,10,10,{
OnInit:
disablenpc "bat_b02_rp1_a_warp";
end;
OnTouch_:
OnTouch:
percentheal 100,100;
warp "bat_b02",87,73;
end;
}
*/
bat_b02,389,14,3 script Battle Therapist#b02_b 95,{
specialeffect2 EF_HEAL;
@ -360,12 +366,14 @@ bat_b02,389,14,3 script Battle Therapist#b02_b 95,{
OnTimer25000:
specialeffect EF_SANCTUARY;
enablenpc "bat_b02_rp1_b_warp";
areapercentheal "bat_b02",379,0,399,20,100,100;
areawarp "bat_b02",379,0,399,20,"bat_b02",312,225;
// enablenpc "bat_b02_rp1_b_warp";
end;
OnTimer26000:
disablenpc "bat_b02_rp1_b_warp";
end;
// OnTimer26000:
// disablenpc "bat_b02_rp1_b_warp";
// end;
OnTimer26500:
stopnpctimer;
@ -378,15 +386,16 @@ OnEnable:
end;
OnStop:
disablenpc "bat_b02_rp1_b_warp";
// disablenpc "bat_b02_rp1_b_warp";
disablenpc "Battle Therapist#b02_b";
stopnpctimer;
end;
}
bat_b02,389,10,0 script bat_b02_rp1_b_warp 45,9,9,{
/*
bat_b02,389,10,0 script bat_b02_rp1_b_warp 45,10,10,{
OnInit:
disablenpc "bat_b02_rp1_a_warp";
disablenpc "bat_b02_rp1_b_warp";
end;
OnTouch:
@ -394,18 +403,19 @@ OnTouch:
warp "bat_b02",312,225;
end;
}
*/
bat_b02,87,76,0 script A_CODE#bat_b02 -1,5,5,{
OnTouch:
if (checkquest(2070) < 0)
//setquest 2070;
setquest 2070;
end;
}
bat_b02,312,224,0 script B_CODE#bat_b02 -1,5,5,{
OnTouch:
if (checkquest(2070) < 0)
//setquest 2070;
setquest 2070;
end;
}
@ -491,6 +501,8 @@ OnTimer1830000:
bg_warp $@FlaviusBG2_id2,"bat_b02",390,10;
enablenpc "Vintenar#bat_b02_aover";
enablenpc "Vintenar#bat_b02_bover";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_b02", true;
end;
OnTimer1900000:
@ -527,11 +539,11 @@ bat_b02,10,294,3 script Vintenar#bat_b02_aover 419,{
set .@A_B_gap,$@Guill_ScoreBG2 - $@Croix_ScoreBG2;
if ($@FlaviusBG2_id1 == getcharid(4)) {
if (.@A_B_gap > 0)
callfunc "F_BG_Badge",1,"Guillaume","Flavius";
callfunc "F_BG_Badge",1,"Guillaume","Flavius"; //Guillaume wins
else if (.@A_B_gap == 0)
callfunc "F_BG_Badge",0,"Guillaume","Flavius";
callfunc "F_BG_Badge",0,"Guillaume","Flavius"; //Tie
else
callfunc "F_BG_Badge",0,"Guillaume","Flavius";
callfunc "F_BG_Badge",0,"Guillaume","Flavius"; //Croix wins
}
else {
mes "[Axl Rose]";
@ -552,11 +564,11 @@ bat_b02,389,14,3 script Vintenar#bat_b02_bover 415,{
set .@A_B_gap,$@Guill_ScoreBG2 - $@Croix_ScoreBG2;
if ($@FlaviusBG2_id2 == getcharid(4)) {
if (.@A_B_gap > 0)
callfunc "F_BG_Badge",1,"Croix","Flavius";
callfunc "F_BG_Badge",0,"Croix","Flavius"; //Guillaume wins
else if (.@A_B_gap == 0)
callfunc "F_BG_Badge",0,"Croix","Flavius";
callfunc "F_BG_Badge",0,"Croix","Flavius"; //Tie
else
callfunc "F_BG_Badge",1,"Croix","Flavius";
callfunc "F_BG_Badge",1,"Croix","Flavius"; //Croix wins
}
else {
mes "[Swandery]";

View File

@ -155,6 +155,14 @@ OnCroixDie:
}
end;
OnGuillaumeActive:
warp "bat_c01",61,120;
end;
OnCroixActive:
warp "bat_c01",138,63;
end;
OnStart:
disablenpc "KVM Officer#KVM01A";
disablenpc "KVM Officer#KVM01B";
@ -224,6 +232,7 @@ OnTimer61000:
end;
}
}
bg_updatescore "bat_c01",.Guillaume_Count,.Croix_Count;
set $@KvM01BG, 2; // Playing
bg_warp $@KvM01BG_id1,"bat_c01",61,120;
bg_warp $@KvM01BG_id2,"bat_c01",138,63;
@ -292,6 +301,8 @@ OnStop:
bg_warp $@KvM01BG_id1,"bat_c01",53,128;
bg_warp $@KvM01BG_id2,"bat_c01",146,55;
donpcevent "KvM01_BG_Out::OnBegin";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_c01", true;
end;
}
@ -333,7 +344,6 @@ OnTimer60000:
disablenpc "KVM Officer#KVM01B";
mapwarp "bat_c01","bat_room",154,150;
maprespawnguildid "bat_c01",0,3; // Just in case someone else
bg_updatescore "bat_c01",5,5;
set $@KvM01BG, 0;
OnGuillaumeJoin:

View File

@ -155,6 +155,14 @@ OnCroixDie:
}
end;
OnGuillaumeActive:
warp "bat_c02",62,119;
end;
OnCroixActive:
warp "bat_c02",137,64;
end;
OnStart:
disablenpc "KVM Officer#KVM02A";
disablenpc "KVM Officer#KVM02B";
@ -224,6 +232,7 @@ OnTimer61000:
end;
}
}
bg_updatescore "bat_c02",.Guillaume_Count,.Croix_Count;
set $@KvM02BG, 2; // Playing
bg_warp $@KvM02BG_id1,"bat_c02",62,119;
bg_warp $@KvM02BG_id2,"bat_c02",137,64;
@ -292,6 +301,8 @@ OnStop:
bg_warp $@KvM02BG_id1,"bat_c02",53,128;
bg_warp $@KvM02BG_id2,"bat_c02",146,55;
donpcevent "KvM02_BG_Out::OnBegin";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_c02", true;
end;
}
@ -333,7 +344,6 @@ OnTimer60000:
disablenpc "KVM Officer#KVM02B";
mapwarp "bat_c02","bat_room",154,150;
maprespawnguildid "bat_c02",0,3; // Just in case someone else
bg_updatescore "bat_c02",5,5;
set $@KvM02BG, 0;
OnGuillaumeJoin:

View File

@ -155,6 +155,14 @@ OnCroixDie:
}
end;
OnGuillaumeActive:
warp "bat_c03",62,119;
end;
OnCroixActive:
warp "bat_c03",137,64;
end;
OnStart:
disablenpc "KVM Officer#KVM03A";
disablenpc "KVM Officer#KVM03B";
@ -224,6 +232,7 @@ OnTimer61000:
end;
}
}
bg_updatescore "bat_c03",.Guillaume_Count,.Croix_Count;
set $@KvM03BG, 2; // Playing
bg_warp $@KvM03BG_id1,"bat_c03",62,119;
bg_warp $@KvM03BG_id2,"bat_c03",137,64;
@ -292,6 +301,8 @@ OnStop:
bg_warp $@KvM03BG_id1,"bat_c03",53,128;
bg_warp $@KvM03BG_id2,"bat_c03",146,55;
donpcevent "KvM03_BG_Out::OnBegin";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_c03", true;
end;
}
@ -333,7 +344,6 @@ OnTimer60000:
disablenpc "KVM Officer#KVM03B";
mapwarp "bat_c03","bat_room",154,150;
maprespawnguildid "bat_c03",0,3; // Just in case someone else
bg_updatescore "bat_c03",5,5;
set $@KvM03BG, 0;
OnGuillaumeJoin:

View File

@ -58,21 +58,18 @@ OnStop:
OnTimer1000:
stopnpctimer;
if (!getbattleflag("feature.bgqueue"))
initnpctimer;
set .@chk_bat_a01,getmapusers("bat_a01");
if (.@chk_bat_a01 < 1) {
set $@TierraBG1,0; set $@TierraBG1_Victory, 0;
if( $@TierraBG1_id1 ) { bg_destroy $@TierraBG1_id1; set $@TierraBG1_id1, 0; }
if( $@TierraBG1_id2 ) { bg_destroy $@TierraBG1_id2; set $@TierraBG1_id2, 0; }
if (getbattleflag("feature.bgqueue")) {
if (bg_get_data($@TierraBG1_id1, 0) == 0 && bg_get_data($@TierraBG1_id2, 0) == 0) {
donpcevent "countdown#bat_a01::OnStop";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_a01", true;
$@TierraBG1 = 0; $@TierraBG1_Victory = 0;
if( $@TierraBG1_id1 ) { bg_destroy $@TierraBG1_id1; $@TierraBG1_id1 = 0; }
if( $@TierraBG1_id2 ) { bg_destroy $@TierraBG1_id2; $@TierraBG1_id2 = 0; }
if (getbattleflag("feature.bgqueue"))
bg_unbook "bat_a01";
end;
} else
donpcevent "start#bat_a01::OnReadyCheck";
end;
}
if (getbattleflag("feature.bgqueue"))
initnpctimer;
initnpctimer;
end;
}
@ -126,6 +123,14 @@ OnEnable:
disablenpc "Croix Vintenar#a01_b";
end;
OnGuillaumeActive:
warp "bat_a01",352,342;
end;
OnCroixActive:
warp "bat_a01",353,52;
end;
OnGuillaumeQuit:
OnCroixQuit:
if (getbattleflag("feature.bgqueue"))
@ -183,6 +188,8 @@ OnMyMobDead:
mapannounce "bat_a01", "Croix Vintenar Swandery: We destroyed Guillaume's Food Storage. We won that! Wow!",bc_map,"0xFFCE00";
bg_warp $@TierraBG1_id1,"bat_a01",50,374;
bg_warp $@TierraBG1_id2,"bat_a01",42,16;
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_a01", true;
}
end;
}
@ -206,6 +213,8 @@ OnMyMobDead:
mapannounce "bat_a01", "Guillaume Vintenar Axl Rose : We destroyed Croix's Food Storage. We won that! Wow!",bc_map,"0xFFCE00";
bg_warp $@TierraBG1_id1,"bat_a01",50,374;
bg_warp $@TierraBG1_id2,"bat_a01",42,16;
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_a01", true;
}
end;
}
@ -364,8 +373,10 @@ bat_a01,185,270,1 script Guillaume Blacksmith#a01 851,{
mes "[Guillaume Blacksmith]";
mes "Wow! It's done.";
mes "We are relieved.";
delitem 7049,50; //Stone
donpcevent "barricade#bat_a01_a::OnEnable";
if (mobcount("bat_a01","barricade#bat_a01_a::OnMyMobDead") < 17) {
delitem 7049,50; //Stone
donpcevent "barricade#bat_a01_a::OnEnable";
}
close2;
disablenpc "Guillaume Blacksmith#a01";
end;
@ -448,8 +459,10 @@ bat_a01,170,121,5 script Croix Blacksmith#bat_a01 851,{
mes "[Croix Blacksmith]";
mes "Wow! It's done.";
mes "We are relieved.";
delitem 7049,50; //Stone
donpcevent "barricade#bat_a01_b::OnEnable";
if (mobcount("bat_a01","barricade#bat_a01_b::OnMyMobDead") < 17) {
delitem 7049,50; //Stone
donpcevent "barricade#bat_a01_b::OnEnable";
}
close2;
disablenpc "Croix Blacksmith#bat_a01";
end;
@ -500,35 +513,39 @@ OnEnable:
end;
OnStop:
disablenpc "bat_a01_rp1_a_warp";
// disablenpc "bat_a01_rp1_a_warp";
disablenpc "Battle Therapist#a01_a";
stopnpctimer;
end;
OnTimer25000:
specialeffect EF_SANCTUARY;
enablenpc "bat_a01_rp1_a_warp";
// enablenpc "bat_a01_rp1_a_warp";
areapercentheal "bat_a01",41,365,61,385,100,100;
areawarp "bat_a01",41,365,61,385,"bat_a01",352,342;
end;
OnTimer26000:
disablenpc "bat_a01_rp1_a_warp";
end;
// OnTimer26000:
// disablenpc "bat_a01_rp1_a_warp";
// end;
OnTimer26500:
donpcevent "Battle Therapist#a01_a::OnEnable";
end;
}
/*
bat_a01,51,375,0 script bat_a01_rp1_a_warp -1,10,10,{
OnInit:
disablenpc "bat_a01_rp1_a_warp";
end;
OnTouch_:
OnTouch:
percentheal 100,100;
warp "bat_a01",352,342;
end;
}
*/
bat_a01,45,19,3 script Battle Therapist#a01_b 95,{
specialeffect2 EF_HEAL;
@ -550,25 +567,28 @@ OnEnable:
end;
OnStop:
disablenpc "bat_a01_rp1_b_warp";
// disablenpc "bat_a01_rp1_b_warp";
disablenpc "Battle Therapist#a01_b";
stopnpctimer;
end;
OnTimer25000:
specialeffect EF_SANCTUARY;
enablenpc "bat_a01_rp1_b_warp";
areapercentheal "bat_a01",33,7,53,27,100,100;
areawarp "bat_a01",33,7,53,27,"bat_a01",353,52;
// enablenpc "bat_a01_rp1_b_warp";
end;
OnTimer26000:
disablenpc "bat_a01_rp1_b_warp";
end;
// OnTimer26000:
// disablenpc "bat_a01_rp1_b_warp";
// end;
OnTimer26500:
donpcevent "Battle Therapist#a01_b::OnEnable";
end;
}
/*
bat_a01,43,17,0 script bat_a01_rp1_b_warp -1,10,10,{
OnInit:
disablenpc "bat_a01_rp1_b_warp";
@ -579,6 +599,7 @@ OnTouch:
warp "bat_a01",353,52;
end;
}
*/
bat_a01,60,216,3 script Valley Ghost#bat_a01_n 950,{
specialeffect2 EF_HEAL;
@ -597,18 +618,21 @@ OnEnable:
OnTimer25000:
specialeffect EF_SANCTUARY;
enablenpc "bat_a01_rp1_n_warp";
areapercentheal "bat_a01",45,203,65,223,100,100;
areawarp "bat_a01",45,203,65,223,"bat_a01",301,209;
// enablenpc "bat_a01_rp1_n_warp";
end;
OnTimer26000:
disablenpc "bat_a01_rp1_n_warp";
end;
// OnTimer26000:
// disablenpc "bat_a01_rp1_n_warp";
// end;
OnTimer26500:
donpcevent "Valley Ghost#bat_a01_n::OnEnable";
end;
}
/*
bat_a01,55,213,0 script bat_a01_rp1_n_warp -1,10,10,{
OnInit:
disablenpc "bat_a01_rp1_n_warp";
@ -619,6 +643,7 @@ OnTouch:
warp "bat_a01",301,209;
end;
}
*/
bat_a01,194,267,0 script barri_warp_up#bat_a01_a -1,7,0,{
OnTouch:

View File

@ -57,21 +57,19 @@ OnStop:
OnTimer1000:
stopnpctimer;
if (!getbattleflag("feature.bgqueue"))
initnpctimer;
set .@chk_bat_a02,getmapusers("bat_a02");
if (.@chk_bat_a02 < 1) {
set $@TierraBG2,0; set $@TierraBG2_Victory, 0;
if( $@TierraBG2_id1 ) { bg_destroy $@TierraBG2_id1; set $@TierraBG2_id1, 0; }
if( $@TierraBG2_id2 ) { bg_destroy $@TierraBG2_id2; set $@TierraBG2_id2, 0; }
if (getbattleflag("feature.bgqueue")) {
if (!bg_get_data($@TierraBG2_id1, 0) && !bg_get_data($@TierraBG2_id2, 0)) {
donpcevent "countdown#bat_a02::OnStop";
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_a02", true;
mapwarp "bat_a02","bat_room",154,150;
$@TierraBG2 = 0; $@TierraBG2_Victory = 0;
if( $@TierraBG2_id1 ) { bg_destroy $@TierraBG2_id1; $@TierraBG2_id1 = 0; }
if( $@TierraBG2_id2 ) { bg_destroy $@TierraBG2_id2; $@TierraBG2_id2 = 0; }
if (getbattleflag("feature.bgqueue"))
bg_unbook "bat_a02";
end;
} else
donpcevent "start#bat_a02::OnReadyCheck";
end;
}
if (getbattleflag("feature.bgqueue"))
initnpctimer;
initnpctimer;
end;
}
@ -125,6 +123,14 @@ OnEnable:
disablenpc "Croix Vintenar#a02_b";
end;
OnGuillaumeActive:
warp "bat_a02",352,342;
end;
OnCroixActive:
warp "bat_a02",353,52;
end;
OnGuillaumeQuit:
OnCroixQuit:
if (getbattleflag("feature.bgqueue"))
@ -182,6 +188,8 @@ OnMyMobDead:
mapannounce "bat_a02", "Croix Vintenar Swandery: We destroyed Guillaume's Food Storage. We won that! Wow!",bc_map,"0xFFCE00";
bg_warp $@TierraBG2_id1,"bat_a02",50,374;
bg_warp $@TierraBG2_id2,"bat_a02",42,16;
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_a02", true;
}
end;
}
@ -205,6 +213,8 @@ OnMyMobDead:
mapannounce "bat_a02", "Guillaume Vintenar Axl Rose : We destroyed Croix's Food Storage. We won that! Wow!",bc_map,"0xFFCE00";
bg_warp $@TierraBG2_id1,"bat_a02",50,374;
bg_warp $@TierraBG2_id2,"bat_a02",42,16;
if (getbattleflag("feature.bgqueue"))
bg_reserve "bat_a02", true;
}
end;
}
@ -363,8 +373,10 @@ bat_a02,185,270,1 script Guillaume Blacksmith#a02 851,{
mes "[Guillaume Blacksmith]";
mes "Wow! It's done.";
mes "We are relieved.";
delitem 7049,50; //Stone
donpcevent "barricade#bat_a02_a::OnEnable";
if (mobcount("bat_a02","barricade#bat_a02_a::OnMyMobDead") < 17) {
delitem 7049,50; //Stone
donpcevent "barricade#bat_a02_a::OnEnable";
}
close2;
disablenpc "Guillaume Blacksmith#a02";
end;
@ -447,8 +459,10 @@ bat_a02,170,121,5 script Croix Blacksmith#bat_a02 851,{
mes "[Croix Blacksmith]";
mes "Wow! It's done.";
mes "We are relieved.";
delitem 7049,50; //Stone
donpcevent "barricade#bat_a02_b::OnEnable";
if (mobcount("bat_a02","barricade#bat_a02_b::OnMyMobDead") < 17) {
delitem 7049,50; //Stone
donpcevent "barricade#bat_a02_b::OnEnable";
}
close2;
disablenpc "Croix Blacksmith#bat_a02";
end;
@ -499,35 +513,39 @@ OnEnable:
end;
OnStop:
disablenpc "bat_a02_rp1_a_warp";
// disablenpc "bat_a02_rp1_a_warp";
disablenpc "Battle Therapist#a02_a";
stopnpctimer;
end;
OnTimer25000:
specialeffect EF_SANCTUARY;
enablenpc "bat_a02_rp1_a_warp";
// enablenpc "bat_a02_rp1_a_warp";
areapercentheal "bat_a02",41,365,61,385,100,100;
areawarp "bat_a02",41,365,61,385,"bat_a02",352,342;
end;
OnTimer26000:
disablenpc "bat_a02_rp1_a_warp";
end;
// OnTimer26000:
// disablenpc "bat_a02_rp1_a_warp";
// end;
OnTimer26500:
donpcevent "Battle Therapist#a02_a::OnEnable";
end;
}
/*
bat_a02,51,375,0 script bat_a02_rp1_a_warp -1,10,10,{
OnInit:
disablenpc "bat_a02_rp1_a_warp";
end;
OnTouch_:
OnTouch:
percentheal 100,100;
warp "bat_a02",352,342;
end;
}
*/
bat_a02,45,19,3 script Battle Therapist#a02_b 95,{
specialeffect2 EF_HEAL;
@ -549,25 +567,28 @@ OnEnable:
end;
OnStop:
disablenpc "bat_a02_rp1_b_warp";
// disablenpc "bat_a02_rp1_b_warp";
disablenpc "Battle Therapist#a02_b";
stopnpctimer;
end;
OnTimer25000:
specialeffect EF_SANCTUARY;
enablenpc "bat_a02_rp1_b_warp";
// enablenpc "bat_a02_rp1_b_warp";
areapercentheal "bat_a02",33,7,53,27,100,100;
areawarp "bat_a02",33,7,53,27,"bat_a02",353,52;
end;
OnTimer26000:
disablenpc "bat_a02_rp1_b_warp";
end;
// OnTimer26000:
// disablenpc "bat_a02_rp1_b_warp";
// end;
OnTimer26500:
donpcevent "Battle Therapist#a02_b::OnEnable";
end;
}
/*
bat_a02,43,17,0 script bat_a02_rp1_b_warp -1,10,10,{
OnInit:
disablenpc "bat_a02_rp1_b_warp";
@ -578,6 +599,7 @@ OnTouch:
warp "bat_a02",353,52;
end;
}
*/
bat_a02,60,216,3 script Valley Ghost#bat_a02_n 950,{
specialeffect2 EF_HEAL;
@ -596,18 +618,21 @@ OnEnable:
OnTimer25000:
specialeffect EF_SANCTUARY;
enablenpc "bat_a02_rp1_n_warp";
// enablenpc "bat_a02_rp1_n_warp";
areapercentheal "bat_a02",45,203,65,223,100,100;
areawarp "bat_a02",45,203,65,223,"bat_a02",301,209;
end;
OnTimer26000:
disablenpc "bat_a02_rp1_n_warp";
end;
// OnTimer26000:
// disablenpc "bat_a02_rp1_n_warp";
// end;
OnTimer26500:
donpcevent "Valley Ghost#bat_a02_n::OnEnable";
end;
}
/*
bat_a02,55,213,0 script bat_a02_rp1_n_warp -1,10,10,{
OnInit:
disablenpc "bat_a02_rp1_n_warp";
@ -618,6 +643,7 @@ OnTouch:
warp "bat_a02",301,209;
end;
}
*/
bat_a02,194,267,0 script barri_warp_up#bat_a02_a -1,7,0,{
OnTouch:

View File

@ -8951,6 +8951,7 @@ static const struct _battle_data {
{ "idletime_hom_option", &battle_config.idletime_hom_option, 0x1F, 0x1, 0xFFF, },
{ "devotion_standup_fix", &battle_config.devotion_standup_fix, 1, 0, 1, },
{ "feature.bgqueue", &battle_config.feature_bgqueue, 1, 0, 1, },
{ "bgqueue_nowarp_mapflag", &battle_config.bgqueue_nowarp_mapflag, 0, 0, 1, },
{ "homunculus_exp_gain", &battle_config.homunculus_exp_gain, 10, 0, 100, },
{ "rental_item_novalue", &battle_config.rental_item_novalue, 1, 0, 1, },

View File

@ -675,6 +675,7 @@ struct Battle_Config
int idletime_hom_option;
int devotion_standup_fix;
int feature_bgqueue;
int bgqueue_nowarp_mapflag;
int homunculus_exp_gain;
int rental_item_novalue;

View File

@ -32,6 +32,7 @@ using namespace rathena;
BattlegroundDatabase battleground_db;
std::unordered_map<int, std::shared_ptr<s_battleground_data>> bg_team_db;
std::vector<std::shared_ptr<s_battleground_queue>> bg_queues;
int bg_queue_count = 1;
const std::string BattlegroundDatabase::getDefaultLocation() {
return std::string(db_path) + "/battleground_db.yml";
@ -75,6 +76,11 @@ uint64 BattlegroundDatabase::parseBodyNode(const YAML::Node &node) {
if (!this->asInt32(node, "MinPlayers", min))
return 0;
if (min < 1) {
this->invalidWarning(node["MinPlayers"], "Minimum players %d cannot be less than 1, capping to 1.\n", min);
min = 1;
}
if (min * 2 > MAX_BG_MEMBERS) {
this->invalidWarning(node["MinPlayers"], "Minimum players %d exceeds MAX_BG_MEMBERS, capping to %d.\n", min, MAX_BG_MEMBERS / 2);
min = MAX_BG_MEMBERS / 2;
@ -92,6 +98,11 @@ uint64 BattlegroundDatabase::parseBodyNode(const YAML::Node &node) {
if (!this->asInt32(node, "MaxPlayers", max))
return 0;
if (max < 1) {
this->invalidWarning(node["MaxPlayers"], "Maximum players %d cannot be less than 1, capping to 1.\n", max);
max = 1;
}
if (max * 2 > MAX_BG_MEMBERS) {
this->invalidWarning(node["MaxPlayers"], "Maximum players %d exceeds MAX_BG_MEMBERS, capping to %d.\n", max, MAX_BG_MEMBERS / 2);
max = MAX_BG_MEMBERS / 2;
@ -158,7 +169,77 @@ uint64 BattlegroundDatabase::parseBodyNode(const YAML::Node &node) {
bg->start_delay = delay;
} else {
if (!exists)
bg->start_delay = 30;
bg->start_delay = 0;
}
if (this->nodeExists(node, "Join")) {
const YAML::Node &joinNode = node["Join"];
if (this->nodeExists(joinNode, "Solo")) {
bool active;
if (!this->asBool(joinNode, "Solo", active))
return 0;
bg->solo = active;
} else {
if (!exists)
bg->solo = true;
}
if (this->nodeExists(joinNode, "Party")) {
bool active;
if (!this->asBool(joinNode, "Party", active))
return 0;
bg->party = active;
} else {
if (!exists)
bg->party = true;
}
if (this->nodeExists(joinNode, "Guild")) {
bool active;
if (!this->asBool(joinNode, "Guild", active))
return 0;
bg->guild = active;
} else {
if (!exists)
bg->guild = true;
}
} else {
if (!exists) {
bg->solo = true;
bg->party = true;
bg->guild = true;
}
}
if (this->nodeExists(node, "JobRestrictions")) {
const YAML::Node &jobsNode = node["JobRestrictions"];
for (const auto &jobit : jobsNode) {
std::string job_name = jobit.first.as<std::string>(), job_name_constant = "JOB_" + job_name;
int64 constant;
if (!script_get_constant(job_name_constant.c_str(), &constant)) {
this->invalidWarning(node["JobRestrictions"], "Job %s does not exist.\n", job_name.c_str());
continue;
}
bool active;
if (!this->asBool(jobsNode, job_name, active))
return 0;
if (active)
bg->job_restrictions.push_back(static_cast<int32>(constant));
else
util::vector_erase_if_exists(bg->job_restrictions, static_cast<int32>(constant));
}
}
if (this->nodeExists(node, "Locations")) {
@ -174,9 +255,9 @@ uint64 BattlegroundDatabase::parseBodyNode(const YAML::Node &node) {
if (!this->asString(location, "Map", map_name))
return 0;
map_entry.mapid = map_mapname2mapid(map_name.c_str());
map_entry.mapindex = mapindex_name2id(map_name.c_str());
if (map_entry.mapid == -1) {
if (map_entry.mapindex == 0) {
this->invalidWarning(location["Map"], "Invalid battleground map name %s, skipping.\n", map_name.c_str());
return 0;
}
@ -245,6 +326,18 @@ uint64 BattlegroundDatabase::parseBodyNode(const YAML::Node &node) {
}
}
if (this->nodeExists(team[it], "ActiveEvent")) {
if (!this->asString(team[it], "ActiveEvent", team_ptr->active_event))
return 0;
team_ptr->active_event.resize(EVENT_NAME_LENGTH);
if (team_ptr->active_event.find("::On") == std::string::npos) {
this->invalidWarning(team["ActiveEvent"], "Battleground ActiveEvent label %s should begin with '::On', skipping.\n", team_ptr->active_event.c_str());
return 0;
}
}
if (this->nodeExists(team[it], "Variable")) {
if (!this->asString(team[it], "Variable", team_ptr->bg_id_var))
return 0;
@ -284,6 +377,21 @@ std::shared_ptr<s_battleground_type> bg_search_name(const char *name)
return nullptr;
}
/**
* Search for a Battleground queue based on the given queue ID
* @param queue_id: Queue ID
* @return s_battleground_queue on success or nullptr on failure
*/
std::shared_ptr<s_battleground_queue> bg_search_queue(int queue_id)
{
for (const auto &queue : bg_queues) {
if (queue_id == queue->queue_id)
return queue;
}
return nullptr;
}
/**
* Search for an available player in Battleground
* @param bg: Battleground data
@ -293,7 +401,12 @@ struct map_session_data* bg_getavailablesd(s_battleground_data *bg)
{
nullpo_retr(nullptr, bg);
return (bg->members.size() != 0) ? bg->members[0].sd : nullptr;
for (const auto &member : bg->members) {
if (member.sd != nullptr)
return member.sd;
}
return nullptr;
}
/**
@ -514,7 +627,7 @@ int bg_create(uint16 mapindex, s_battleground_team* team)
bg->cemetery.y = team->warp_y;
bg->logout_event = team->quit_event.c_str();
bg->die_event = team->death_event.c_str();
bg->members.clear();
bg->active_event = team->active_event.c_str();
return bg->id;
}
@ -569,7 +682,7 @@ void bg_send_message(struct map_session_data *sd, const char *mes, int len)
{
nullpo_retv(sd);
if (!sd->bg_id)
if (sd->bg_id == 0)
return;
std::shared_ptr<s_battleground_data> bgteam = util::umap_find(bg_team_db, sd->bg_id);
@ -617,7 +730,7 @@ TIMER_FUNC(bg_send_xy_timer)
}
/**
* Mark a Battleground as ready to begin queuing
* Mark a Battleground as ready to begin queuing for a free map
* @param tid: Timer ID
* @param tick: Timer
* @param id: ID
@ -625,14 +738,18 @@ TIMER_FUNC(bg_send_xy_timer)
*/
static TIMER_FUNC(bg_on_ready_loopback)
{
s_battleground_queue *queue = (s_battleground_queue*)data;
int queue_id = (int)data;
std::shared_ptr<s_battleground_queue> queue = bg_search_queue(queue_id);
nullpo_retr(1, queue);
if (queue == nullptr) {
ShowError("bg_on_ready_loopback: Invalid battleground queue %d.\n", queue_id);
return 1;
}
std::shared_ptr<s_battleground_type> bg = battleground_db.find(queue->id);
if (bg) {
bg_queue_on_ready(bg->name.c_str(), std::shared_ptr<s_battleground_queue>(queue));
bg_queue_on_ready(bg->name.c_str(), queue);
return 0;
} else {
ShowError("bg_on_ready_loopback: Can't find battleground %d in the battlegrounds database.\n", queue->id);
@ -641,7 +758,7 @@ static TIMER_FUNC(bg_on_ready_loopback)
}
/**
* Reset Battleground queue data
* Reset Battleground queue data if players don't accept in time
* @param tid: Timer ID
* @param tick: Timer
* @param id: ID
@ -649,31 +766,32 @@ static TIMER_FUNC(bg_on_ready_loopback)
*/
static TIMER_FUNC(bg_on_ready_expire)
{
s_battleground_queue *queue = (s_battleground_queue*)data;
int queue_id = (int)data;
std::shared_ptr<s_battleground_queue> queue = bg_search_queue(queue_id);
nullpo_retr(1, queue);
queue->in_ready_state = false;
queue->map->isReserved = false; // Remove reservation to free up for future queue
queue->map = nullptr;
queue->accepted_players = 0; // Reset the queue count
if (queue == nullptr) {
ShowError("bg_on_ready_expire: Invalid battleground queue %d.\n", queue_id);
return 1;
}
std::string bg_name = battleground_db.find(queue->id)->name;
for (const auto &sd : queue->teama_members) {
sd->bg_queue_accept_state = false;
clif_bg_queue_apply_result(BG_APPLY_QUEUE_FINISHED, bg_name.c_str(), sd);
clif_bg_queue_entry_init(sd);
}
for (const auto &sd : queue->teamb_members) {
sd->bg_queue_accept_state = false;
clif_bg_queue_apply_result(BG_APPLY_QUEUE_FINISHED, bg_name.c_str(), sd);
clif_bg_queue_entry_init(sd);
}
bg_queue_clear(queue, true);
return 0;
}
/**
* Start a Battleground
* Start a Battleground when all players have accepted
* @param tid: Timer ID
* @param tick: Timer
* @param id: ID
@ -681,9 +799,13 @@ static TIMER_FUNC(bg_on_ready_expire)
*/
static TIMER_FUNC(bg_on_ready_start)
{
s_battleground_queue *queue = (s_battleground_queue*)data;
int queue_id = (int)data;
std::shared_ptr<s_battleground_queue> queue = bg_search_queue(queue_id);
nullpo_retr(1, queue);
if (queue == nullptr) {
ShowError("bg_on_ready_start: Invalid battleground queue %d.\n", queue_id);
return 1;
}
queue->tid_start = INVALID_TIMER;
bg_queue_start_battleground(queue);
@ -702,7 +824,7 @@ bool bg_player_is_in_bg_map(struct map_session_data *sd)
for (const auto &pair : battleground_db) {
for (const auto &it : pair.second->maps) {
if (it.mapid == sd->bl.m)
if (it.mapindex == sd->mapindex)
return true;
}
}
@ -724,7 +846,7 @@ static bool bg_queue_check_status(struct map_session_data* sd, const char *name)
if (sd->sc.data[SC_ENTRY_QUEUE_APPLY_DELAY]) { // Exclude any player who's recently left a battleground queue
char buf[CHAT_SIZE_MAX];
sprintf(buf, msg_txt(sd, 339), (get_timer(sd->sc.data[SC_ENTRY_QUEUE_APPLY_DELAY]->timer)->tick - gettick()) / 1000); // You can't apply to a battleground queue for %d seconds due to recently leaving one.
sprintf(buf, msg_txt(sd, 339), static_cast<int32>((get_timer(sd->sc.data[SC_ENTRY_QUEUE_APPLY_DELAY]->timer)->tick - gettick()) / 1000)); // You can't apply to a battleground queue for %d seconds due to recently leaving one.
clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], buf, false, SELF);
return false;
@ -732,9 +854,9 @@ static bool bg_queue_check_status(struct map_session_data* sd, const char *name)
if (sd->sc.data[SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT]) { // Exclude any player who's recently deserted a battleground
char buf[CHAT_SIZE_MAX];
t_tick status_tick = get_timer(sd->sc.data[SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT]->timer)->tick, tick = gettick();
int32 status_tick = static_cast<int32>(DIFF_TICK(get_timer(sd->sc.data[SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT]->timer)->tick, gettick()) / 1000);
sprintf(buf, msg_txt(sd, 338), ((status_tick - tick) / 1000) / 60, ((status_tick - tick) / 1000) % 60); // You can't apply to a battleground queue due to recently deserting a battleground. Time remaining: %d minutes and %d seconds.
sprintf(buf, msg_txt(sd, 338), status_tick / 60, status_tick % 60); // You can't apply to a battleground queue due to recently deserting a battleground. Time remaining: %d minutes and %d seconds.
clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], buf, false, SELF);
return false;
@ -755,43 +877,64 @@ bool bg_queue_check_joinable(std::shared_ptr<s_battleground_type> bg, struct map
{
nullpo_retr(false, sd);
if (bg->min_lvl && sd->status.base_level < bg->min_lvl) { // Check min level if min_lvl isn't 0
for (const auto &job : bg->job_restrictions) { // Check class requirement
if (sd->class_ == job) {
clif_bg_queue_apply_result(BG_APPLY_PLAYER_CLASS, name, sd);
return false;
}
}
if (bg->min_lvl > 0 && sd->status.base_level < bg->min_lvl) { // Check minimum level requirement
clif_bg_queue_apply_result(BG_APPLY_PLAYER_LEVEL, name, sd);
return false;
}
if (bg->max_lvl && sd->status.base_level > bg->max_lvl) { // Check max level if max_lvl isn't 0
if (bg->max_lvl > 0 && sd->status.base_level > bg->max_lvl) { // Check maximum level requirement
clif_bg_queue_apply_result(BG_APPLY_PLAYER_LEVEL, name, sd);
return false;
}
if (!bg_queue_check_status(sd, name))
if (!bg_queue_check_status(sd, name)) // Check status blocks
return false;
if (bg_player_is_in_bg_map(sd)) { // Is the player currently in a battleground map? Reject them.
clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You may not join a battleground queue when you're in a battleground map.
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
return false;
}
return true; // Return true if all conditions are met.
if (battle_config.bgqueue_nowarp_mapflag > 0 && map_getmapflag(sd->bl.m, MF_NOWARP)) { // Check player's current position for mapflag check
clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
return false;
}
return true;
}
/**
* Sub function for reserving a slot in the Battleground if it's joinable
* Mark a map as reserved for a Battleground
* @param name: Battleground map name
* @param state: Whether to mark reserved or not
* @param ended: Whether the Battleground event is complete; players getting prize
* @return True on success or false otherwise
*/
bool bg_queue_reservation(const char *name, bool state)
bool bg_queue_reservation(const char *name, bool state, bool ended)
{
int16 mapid = map_mapname2mapid(name);
uint16 mapindex = mapindex_name2id(name);
for (const auto &pair : battleground_db) {
// Bound checking isn't needed since we iterate within battleground_db's bound.
for (auto &it : pair.second->maps) {
if (it.mapid == mapid) {
it.isReserved = state;
for (auto &pair : battleground_db) {
for (auto &map : pair.second->maps) {
if (map.mapindex == mapindex) {
map.isReserved = state;
for (auto &queue : bg_queues) {
if (queue->map == &map) {
if (ended) // The ended flag is applied from bg_reserve (bg_unbook clears it for the next queue)
queue->state = QUEUE_STATE_ENDED;
if (!state)
bg_queue_clear(queue, true);
}
}
return true;
}
}
@ -800,6 +943,33 @@ bool bg_queue_reservation(const char *name, bool state)
return false;
}
/**
* Join as an individual into a Battleground
* @param name: Battleground name
* @param sd: Player who requested to join the battlegrounds
*/
void bg_queue_join_solo(const char *name, struct map_session_data *sd)
{
if (!sd) {
ShowError("bg_queue_join_solo: Tried to join non-existent player\n.");
return;
}
std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
if (!bg) {
ShowWarning("bq_queue_join_solo: Could not find battleground \"%s\" requested by %s (AID: %d / CID: %d)\n", name, sd->status.name, sd->status.account_id, sd->status.char_id);
return;
}
if (!bg->solo) {
clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
return;
}
bg_queue_join_multi(name, sd, { sd }); // Join as solo
}
/**
* Join a party onto the same side of a Battleground
* @param name: Battleground name
@ -807,6 +977,11 @@ bool bg_queue_reservation(const char *name, bool state)
*/
void bg_queue_join_party(const char *name, struct map_session_data *sd)
{
if (!sd) {
ShowError("bg_queue_join_party: Tried to join non-existent player\n.");
return;
}
struct party_data *p = party_search(sd->status.party_id);
if (!p) {
@ -824,6 +999,11 @@ void bg_queue_join_party(const char *name, struct map_session_data *sd)
std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
if (bg) {
if (!bg->party) {
clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
return;
}
int p_online = 0;
for (const auto &it : p->party.member) {
@ -835,7 +1015,7 @@ void bg_queue_join_party(const char *name, struct map_session_data *sd)
clif_bg_queue_apply_result(BG_APPLY_PLAYER_COUNT, name, sd);
return; // Too many party members online
}
std::vector<struct map_session_data *> list;
for (const auto &it : p->party.member) {
@ -865,6 +1045,11 @@ void bg_queue_join_party(const char *name, struct map_session_data *sd)
*/
void bg_queue_join_guild(const char *name, struct map_session_data *sd)
{
if (!sd) {
ShowError("bg_queue_join_guild: Tried to join non-existent player\n.");
return;
}
if (!sd->guild) {
clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
return; // Someone has bypassed the client check for being in a guild
@ -878,6 +1063,11 @@ void bg_queue_join_guild(const char *name, struct map_session_data *sd)
std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
if (bg) {
if (!bg->guild) {
clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
return;
}
struct guild* g = sd->guild;
if (g->connect_member > bg->max_players) {
@ -932,43 +1122,55 @@ void bg_queue_join_multi(const char *name, struct map_session_data *sd, std::vec
}
for (const auto &queue : bg_queues) {
if (queue->id != bg->id)
continue;
if (queue->in_ready_state)
if (queue->id != bg->id || queue->state == QUEUE_STATE_SETUP_DELAY || queue->state == QUEUE_STATE_ENDED)
continue;
// Make sure there's enough space on one side to join as a party/guild in this queue
if (queue->teama_members.size() + list.size() > bg->required_players && queue->teamb_members.size() + list.size() > bg->required_players) {
if (queue->teama_members.size() + list.size() > bg->max_players && queue->teamb_members.size() + list.size() > bg->max_players) {
break;
}
bool r = rnd() % 2 != 0;
std::vector<map_session_data *>* team = r ? &queue->teamb_members : &queue->teama_members;
std::vector<map_session_data *> *team = r ? &queue->teamb_members : &queue->teama_members;
// If the designated team is full, put the player into the other team
if (team->size() + list.size() > bg->required_players) {
team = r ? &queue->teama_members : &queue->teamb_members;
if (queue->state == QUEUE_STATE_ACTIVE) {
// If one team has lesser members try to balance (on an active BG)
if (r && queue->teama_members.size() < queue->teamb_members.size())
team = &queue->teama_members;
else if (!r && queue->teamb_members.size() < queue->teama_members.size())
team = &queue->teamb_members;
} else {
// If the designated team is full, put the player into the other team
if (team->size() + list.size() > bg->required_players)
team = r ? &queue->teama_members : &queue->teamb_members;
}
while (!list.empty() && team->size() < bg->required_players) {
while (!list.empty() && team->size() < bg->max_players) {
struct map_session_data *sd2 = list.back();
list.pop_back();
if (!sd2 || sd2->bg_queue)
if (!sd2 || sd2->bg_queue_id > 0)
continue;
if (!bg_queue_check_joinable(bg, sd2, name))
continue;
sd2->bg_queue = queue;
sd2->bg_queue_id = queue->queue_id;
team->push_back(sd2);
clif_bg_queue_apply_result(BG_APPLY_ACCEPT, name, sd2);
clif_bg_queue_apply_notify(name, sd2);
}
// Enough players have joined
if (queue->teamb_members.size() == bg->required_players && queue->teama_members.size() == bg->required_players)
if (queue->state == QUEUE_STATE_ACTIVE) { // Battleground is already active
for (auto &pl_sd : *team) {
if (queue->map->mapindex == pl_sd->mapindex)
continue;
pc_set_bg_queue_timer(pl_sd);
clif_bg_queue_lobby_notify(name, pl_sd);
}
} else if (queue->state == QUEUE_STATE_SETUP && queue->teamb_members.size() >= bg->required_players && queue->teama_members.size() >= bg->required_players) // Enough players have joined
bg_queue_on_ready(name, queue);
return;
@ -981,10 +1183,11 @@ void bg_queue_join_multi(const char *name, struct map_session_data *sd, std::vec
/**
* Clear Battleground queue for next one
* @param queue: Queue to clean up
* @param ended: If a Battleground has ended through normal means (by script command bg_unbook)
*/
static void bg_queue_clear(s_battleground_queue *queue)
void bg_queue_clear(std::shared_ptr<s_battleground_queue> queue, bool ended)
{
if (!queue)
if (queue == nullptr)
return;
if (queue->tid_requeue != INVALID_TIMER) {
@ -1002,49 +1205,47 @@ static void bg_queue_clear(s_battleground_queue *queue)
queue->tid_start = INVALID_TIMER;
}
if (queue->map != nullptr) {
queue->map->isReserved = false; // Remove reservation to free up for future queue
queue->map = nullptr;
if (ended) {
if (queue->map != nullptr) {
queue->map->isReserved = false; // Remove reservation to free up for future queue
queue->map = nullptr;
}
for (const auto &sd : queue->teama_members)
sd->bg_queue_id = 0;
for (const auto &sd : queue->teamb_members)
sd->bg_queue_id = 0;
queue->teama_members.clear();
queue->teamb_members.clear();
queue->teama_members.shrink_to_fit();
queue->teamb_members.shrink_to_fit();
queue->accepted_players = 0;
queue->state = QUEUE_STATE_SETUP;
}
queue->in_ready_state = false;
queue->accepted_players = 0; // Reset the queue count
}
/**
* Sub function for leaving a Battleground queue
* @param sd: Player leaving
* @param lista: List of players in queue data
* @param listb: List of players in second queue data
* @param members: List of players in queue data
* @return True on success or false otherwise
*/
static bool bg_queue_leave_sub(struct map_session_data *sd, std::vector<map_session_data *> lista, std::vector<map_session_data *> listb)
static bool bg_queue_leave_sub(struct map_session_data *sd, std::vector<map_session_data *> &members)
{
if (!sd)
return false;
auto list_it = lista.begin();
auto list_it = members.begin();
while (list_it != lista.end()) {
struct map_session_data *player = *list_it;
if (player == sd) {
if (sd->bg_queue->in_ready_state) {
sd->bg_queue->accepted_players = 0;
sd->bg_queue->in_ready_state = false;
sd->bg_queue_accept_state = false;
}
lista.erase(list_it);
if (lista.empty() && listb.empty()) { // If there are no players left in the queue, discard it
for (auto &queue : bg_queues) {
if (sd->bg_queue == queue)
bg_queue_clear(queue.get());
}
}
while (list_it != members.end()) {
if (*list_it == sd) {
members.erase(list_it);
sc_start(nullptr, &sd->bl, SC_ENTRY_QUEUE_APPLY_DELAY, 100, 1, 60000);
sd->bg_queue = nullptr;
sd->bg_queue_id = 0;
pc_delete_bg_queue_timer(sd);
return true;
} else {
list_it++;
@ -1061,14 +1262,26 @@ static bool bg_queue_leave_sub(struct map_session_data *sd, std::vector<map_sess
*/
bool bg_queue_leave(struct map_session_data *sd)
{
if (!sd || !sd->bg_queue)
if (!sd || sd->bg_queue_id == 0)
return false;
if (!bg_queue_leave_sub(sd, sd->bg_queue->teama_members, sd->bg_queue->teamb_members) && !bg_queue_leave_sub(sd, sd->bg_queue->teamb_members, sd->bg_queue->teama_members)) {
ShowError("bg_queue_leave: Couldn't find player %s in battlegrounds queue.\n", sd->status.name);
return false;
} else
return true;
pc_delete_bg_queue_timer(sd);
for (auto &queue : bg_queues) {
if (sd->bg_queue_id == queue->queue_id) {
if (!bg_queue_leave_sub(sd, queue->teama_members) && !bg_queue_leave_sub(sd, queue->teamb_members)) {
ShowError("bg_queue_leave: Couldn't find player %s in battlegrounds queue.\n", sd->status.name);
return false;
} else {
if ((queue->state == QUEUE_STATE_SETUP || queue->state == QUEUE_STATE_SETUP_DELAY) && queue->teama_members.empty() && queue->teamb_members.empty()) // If there are no players left in the queue (that hasn't started), discard it
bg_queue_clear(queue, true);
return true;
}
}
}
return false;
}
/**
@ -1086,29 +1299,27 @@ bool bg_queue_on_ready(const char *name, std::shared_ptr<s_battleground_queue> q
return false;
}
queue->accepted_players = 0; // Reset the counter just in case.
if (queue->teama_members.size() != queue->required_players || queue->teamb_members.size() != queue->required_players)
if (queue->teama_members.size() < queue->required_players || queue->teamb_members.size() < queue->required_players)
return false; // Return players to the queue and stop reapplying the timer
s_battleground_map *bgmap = nullptr;
bool map_reserved = false;
for (auto &it : bg->maps) {
if (!it.isReserved) {
it.isReserved = true;
bgmap = &it;
queue->map = &it;
for (auto &map : bg->maps) {
if (!map.isReserved) {
map.isReserved = true;
map_reserved = true;
queue->map = &map;
break;
}
}
if (!bgmap) { // All the battleground maps are reserved. Set a timer to check for an open battleground every 10 seconds.
queue->tid_requeue = add_timer(gettick() + 10000, bg_on_ready_loopback, 0, (intptr_t)queue.get());
if (!map_reserved) { // All the battleground maps are reserved. Set a timer to check for an open battleground every 10 seconds.
queue->tid_requeue = add_timer(gettick() + 10000, bg_on_ready_loopback, 0, (intptr_t)queue->queue_id);
return false;
}
queue->in_ready_state = true;
queue->tid_expire = add_timer(gettick() + 20000, bg_on_ready_expire, 0, (intptr_t)queue.get());
queue->state = QUEUE_STATE_SETUP_DELAY;
queue->tid_expire = add_timer(gettick() + 20000, bg_on_ready_expire, 0, (intptr_t)queue->queue_id);
for (const auto &sd : queue->teama_members)
clif_bg_queue_lobby_notify(name, sd);
@ -1119,25 +1330,150 @@ bool bg_queue_on_ready(const char *name, std::shared_ptr<s_battleground_queue> q
return true;
}
/**
* Send a player into an active Battleground
* @param sd: Player to send in
* @param queue: Queue data
*/
void bg_join_active(map_session_data *sd, std::shared_ptr<s_battleground_queue> queue)
{
if (sd == nullptr || queue == nullptr)
return;
// Check player's current position for mapflag check
if (battle_config.bgqueue_nowarp_mapflag > 0 && map_getmapflag(sd->bl.m, MF_NOWARP)) {
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
bg_queue_leave(sd);
clif_bg_queue_entry_init(sd);
return;
}
int bg_id_team_1 = static_cast<int>(mapreg_readreg(add_str(queue->map->team1.bg_id_var.c_str())));
std::shared_ptr<s_battleground_data> bgteam_1 = util::umap_find(bg_team_db, bg_id_team_1);
for (auto &pl_sd : queue->teama_members) {
if (sd != pl_sd)
continue;
if (bgteam_1 == nullptr) {
bg_queue_leave(sd);
clif_bg_queue_apply_result(BG_APPLY_RECONNECT, battleground_db.find(queue->id)->name.c_str(), sd);
clif_bg_queue_entry_init(sd);
return;
}
clif_bg_queue_entry_init(pl_sd);
bg_team_join(bg_id_team_1, pl_sd, true);
npc_event(pl_sd, bgteam_1->active_event.c_str(), 0);
return;
}
int bg_id_team_2 = static_cast<int>(mapreg_readreg(add_str(queue->map->team2.bg_id_var.c_str())));
std::shared_ptr<s_battleground_data> bgteam_2 = util::umap_find(bg_team_db, bg_id_team_2);
for (auto &pl_sd : queue->teamb_members) {
if (sd != pl_sd)
continue;
if (bgteam_2 == nullptr) {
bg_queue_leave(sd);
clif_bg_queue_apply_result(BG_APPLY_RECONNECT, battleground_db.find(queue->id)->name.c_str(), sd);
clif_bg_queue_entry_init(sd);
return;
}
clif_bg_queue_entry_init(pl_sd);
bg_team_join(bg_id_team_2, pl_sd, true);
npc_event(pl_sd, bgteam_2->active_event.c_str(), 0);
return;
}
return;
}
/**
* Check to see if any players in the queue are on a map with MF_NOWARP and remove them from the queue
* @param queue: Queue data
* @return True if the player is on a map with MF_NOWARP or false otherwise
*/
bool bg_mapflag_check(std::shared_ptr<s_battleground_queue> queue) {
if (queue == nullptr || battle_config.bgqueue_nowarp_mapflag == 0)
return false;
bool found = false;
for (const auto &sd : queue->teama_members) {
if (map_getmapflag(sd->bl.m, MF_NOWARP)) {
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
bg_queue_leave(sd);
clif_bg_queue_entry_init(sd);
found = true;
}
}
for (const auto &sd : queue->teamb_members) {
if (map_getmapflag(sd->bl.m, MF_NOWARP)) {
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
bg_queue_leave(sd);
clif_bg_queue_entry_init(sd);
found = true;
}
}
if (found) {
queue->state = QUEUE_STATE_SETUP; // Set back to queueing state
queue->accepted_players = 0; // Reset acceptance count
// Free map to avoid creating a reservation delay
if (queue->map != nullptr) {
queue->map->isReserved = false;
queue->map = nullptr;
}
// Announce failure to remaining players
for (const auto &sd : queue->teama_members)
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 340), false, SELF); // Participants were unable to join. Delaying entry for more participants.
for (const auto &sd : queue->teamb_members)
clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 340), false, SELF); // Participants were unable to join. Delaying entry for more participants.
}
return found;
}
/**
* Update the Battleground queue when the player accepts the invite
* @param queue: Battleground queue
* @param sd: Player data
*/
void bg_queue_on_accept_invite(std::shared_ptr<s_battleground_queue> queue, struct map_session_data *sd)
void bg_queue_on_accept_invite(struct map_session_data *sd)
{
nullpo_retv(sd);
sd->bg_queue_accept_state = true;
std::shared_ptr<s_battleground_queue> queue = bg_search_queue(sd->bg_queue_id);
if (queue == nullptr) {
ShowError("bg_queue_on_accept_invite: Couldn't find player %s in battlegrounds queue.\n", sd->status.name);
return;
}
queue->accepted_players++;
clig_bg_queue_ack_lobby(true, map_mapid2mapname(queue->map->mapid), map_mapid2mapname(queue->map->mapid), sd);
clif_bg_queue_ack_lobby(true, mapindex_id2name(queue->map->mapindex), mapindex_id2name(queue->map->mapindex), sd);
if (queue->accepted_players == queue->required_players * 2) {
queue->tid_start = add_timer(gettick() + battleground_db.find(queue->id)->start_delay * 1000, bg_on_ready_start, 0, (intptr_t)queue.get());
if (queue->state == QUEUE_STATE_ACTIVE) // Battleground is already active
bg_join_active(sd, queue);
else if (queue->state == QUEUE_STATE_SETUP_DELAY) {
if (queue->accepted_players == queue->required_players * 2) {
if (queue->tid_expire != INVALID_TIMER) {
delete_timer(queue->tid_expire, bg_on_ready_expire);
queue->tid_expire = INVALID_TIMER;
}
if (queue->tid_expire != INVALID_TIMER) {
delete_timer(queue->tid_expire, bg_on_ready_expire);
queue->tid_expire = INVALID_TIMER;
// Check player's current position for mapflag check
if (battle_config.bgqueue_nowarp_mapflag > 0 && bg_mapflag_check(queue))
return;
queue->tid_start = add_timer(gettick() + battleground_db.find(queue->id)->start_delay * 1000, bg_on_ready_start, 0, (intptr_t)queue->queue_id);
}
}
}
@ -1146,31 +1482,33 @@ void bg_queue_on_accept_invite(std::shared_ptr<s_battleground_queue> queue, stru
* Begin the Battleground from the given queue
* @param queue: Battleground queue
*/
void bg_queue_start_battleground(s_battleground_queue *queue)
void bg_queue_start_battleground(std::shared_ptr<s_battleground_queue> queue)
{
if (queue == nullptr)
return;
std::shared_ptr<s_battleground_type> bg = battleground_db.find(queue->id);
if (!bg) {
queue->map->isReserved = false; // Remove reservation to free up for future queue
queue->map = nullptr;
bg_queue_clear(queue, true);
ShowError("bg_queue_start_battleground: Could not find battleground ID %d in battlegrounds database.\n", queue->id);
return;
}
uint16 map_idx = map_id2index(queue->map->mapid);
// Check player's current position for mapflag check
if (battle_config.bgqueue_nowarp_mapflag > 0 && bg_mapflag_check(queue))
return;
uint16 map_idx = queue->map->mapindex;
int bg_team_1 = bg_create(map_idx, &queue->map->team1);
int bg_team_2 = bg_create(map_idx, &queue->map->team2);
for (const auto &sd : queue->teama_members) {
sd->bg_queue = nullptr;
sd->bg_queue_accept_state = false;
clif_bg_queue_entry_init(sd);
bg_team_join(bg_team_1, sd, true);
}
for (const auto &sd : queue->teamb_members) {
sd->bg_queue = nullptr;
sd->bg_queue_accept_state = false;
clif_bg_queue_entry_init(sd);
bg_team_join(bg_team_2, sd, true);
}
@ -1178,11 +1516,9 @@ void bg_queue_start_battleground(s_battleground_queue *queue)
mapreg_setreg(add_str(queue->map->team1.bg_id_var.c_str()), bg_team_1);
mapreg_setreg(add_str(queue->map->team2.bg_id_var.c_str()), bg_team_2);
npc_event_do(queue->map->bgcallscript.c_str());
queue->teama_members.clear();
queue->teamb_members.clear();
queue->teama_members.shrink_to_fit();
queue->teamb_members.shrink_to_fit();
bg_queue_clear(queue);
queue->state = QUEUE_STATE_ACTIVE;
bg_queue_clear(queue, false);
}
/**
@ -1195,13 +1531,14 @@ static void bg_queue_create(int bg_id, int req_players)
{
auto queue = std::make_shared<s_battleground_queue>();
queue->queue_id = bg_queue_count++;
queue->id = bg_id;
queue->required_players = req_players;
queue->accepted_players = 0;
queue->tid_expire = INVALID_TIMER;
queue->tid_start = INVALID_TIMER;
queue->tid_requeue = INVALID_TIMER;
queue->in_ready_state = false;
queue->state = QUEUE_STATE_SETUP;
bg_queues.push_back(queue);
}

View File

@ -27,32 +27,43 @@ struct s_battleground_data {
struct point cemetery; ///< Respawn point for players who die
std::string logout_event; ///< NPC Event to call on log out events
std::string die_event; ///< NPC Event to call on death events
std::string active_event; ///< NPC Event to call on players joining an active battleground
};
struct s_battleground_team {
int16 warp_x, warp_y; ///< Team respawn coordinates
std::string quit_event, ///< Team NPC Event to call on log out events
death_event, ///< Team NPC Event to call on death events
active_event, ///< Team NPC Event to call on players joining an active battleground
bg_id_var; ///< Team NPC variable name
};
struct s_battleground_map {
int id; ///< Battleground ID
int16 mapid; ///< ID of the map
uint16 mapindex; ///< Index of the map
s_battleground_team team1, team2; ///< Team data
std::string bgcallscript; ///< Script to be called when players join the battleground
bool isReserved; ///< Reserve BG maps that are used so that the system won't create multiple BG instances on the same map
};
/// Enum for queue state tracking
enum e_queue_state : uint16 {
QUEUE_STATE_SETUP = 0, ///< The initial setup of a queue (a required amount of players hasn't been met)
QUEUE_STATE_SETUP_DELAY, ///< The initial setup of a queue but a required amount of players have accepted and the delay timer is active
QUEUE_STATE_ACTIVE, ///< The queue is active script side and more players can join (players may or may not be on the field)
QUEUE_STATE_ENDED, ///< The queue is no longer joinable (players are getting prizes)
};
/// Battlegrounds client interface queue system [MasterOfMuppets]
struct s_battleground_queue {
int queue_id; ///< Battlegrounds Queue ID
int id; ///< Battlegrounds database ID
std::vector<map_session_data *> teama_members; ///< List of members on team A
std::vector<map_session_data *> teamb_members; ///< List of members on team B
int required_players; ///< Amount of players required on each side to start
int max_players; ///< Maximum amount of players on each side
int accepted_players; ///< Amount of players who accepted the offer to enter the battleground
bool in_ready_state; ///< Is this BG queue waiting for players to enter the BG?
e_queue_state state; ///< See @e_queue_state
int tid_expire; ///< Timer ID associated with the time out at the ready to enter window
int tid_start; ///< Timer ID associated with the start delay
int tid_requeue; ///< Timer ID associated with requeuing this group if all BG maps are reserved
@ -69,6 +80,10 @@ struct s_battleground_type {
std::vector<s_battleground_map> maps; ///< List of battleground locations
uint32 deserter_time; ///< Amount of time a player is marked deserter (seconds)
uint32 start_delay; ///< Amount of time before the start message is sent to players (seconds)
bool solo; ///< Ability to join a queue as an individual.
bool party; ///< Ability to join a queue as a party.
bool guild; ///< Ability to join a queue as a guild.
std::vector<int32> job_restrictions; ///< List of jobs that are unable to join.
};
/// Enum of responses when applying for a Battleground
@ -109,15 +124,17 @@ public:
extern BattlegroundDatabase battleground_db;
extern std::unordered_map<int, std::shared_ptr<s_battleground_data>> bg_team_db;
extern std::vector<std::shared_ptr<s_battleground_queue>> bg_queues;
std::shared_ptr<s_battleground_type> bg_search_name(const char *name);
std::shared_ptr<s_battleground_queue> bg_search_queue(int queue_id);
void bg_send_dot_remove(struct map_session_data *sd);
int bg_team_get_id(struct block_list *bl);
struct map_session_data *bg_getavailablesd(s_battleground_data *bg);
bool bg_queue_reservation(const char *name, bool state);
#define bg_queue_reserve(name) (bg_queue_reservation(name, true))
#define bg_queue_unbook(name) (bg_queue_reservation(name, false))
bool bg_queue_reservation(const char *name, bool state, bool ended);
#define bg_queue_reserve(name, end) (bg_queue_reservation(name, true, end))
#define bg_queue_unbook(name) (bg_queue_reservation(name, false, false))
int bg_create(uint16 mapindex, s_battleground_team* team);
bool bg_team_join(int bg_id, struct map_session_data *sd, bool is_queue);
@ -126,13 +143,15 @@ int bg_team_leave(struct map_session_data *sd, bool quit, bool deserter);
bool bg_team_warp(int bg_id, unsigned short mapindex, short x, short y);
bool bg_player_is_in_bg_map(struct map_session_data *sd);
bool bg_queue_check_joinable(std::shared_ptr<s_battleground_type> bg, struct map_session_data *sd, const char *name);
void bg_queue_join_solo(const char *name, struct map_session_data *sd);
void bg_queue_join_party(const char *name, struct map_session_data *sd);
void bg_queue_join_guild(const char *name, struct map_session_data *sd);
void bg_queue_join_multi(const char *name, struct map_session_data *sd, std::vector<map_session_data *> list);
void bg_queue_clear(std::shared_ptr<s_battleground_queue> queue, bool ended);
bool bg_queue_leave(struct map_session_data *sd);
bool bg_queue_on_ready(const char *name, std::shared_ptr<s_battleground_queue> queue);
void bg_queue_on_accept_invite(std::shared_ptr<s_battleground_queue> queue, struct map_session_data *sd);
void bg_queue_start_battleground(s_battleground_queue *queue);
void bg_queue_on_accept_invite(struct map_session_data *sd);
void bg_queue_start_battleground(std::shared_ptr<s_battleground_queue> queue);
bool bg_member_respawn(struct map_session_data *sd);
void bg_send_message(struct map_session_data *sd, const char *mes, int len);

View File

@ -609,13 +609,12 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target
case BG_SAMEMAP_WOS:
case BG:
case BG_WOS:
if( sd && sd->bg_id && (bg = util::umap_find(bg_team_db, sd->bg_id)))
if( sd && sd->bg_id > 0 && (bg = util::umap_find(bg_team_db, sd->bg_id)))
{
for( i = 0; i < bg->members.size(); i++ )
{
if( (sd = bg->members[i].sd) == NULL || !(fd = sd->fd) )
for (const auto &member : bg->members) {
if((sd = member.sd) == nullptr || (fd = sd->fd) == 0)
continue;
if( sd->bl.id == bl->id && (type == BG_WOS || type == BG_SAMEMAP_WOS || type == BG_AREA_WOS) )
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;
@ -17630,12 +17629,12 @@ void clif_parse_bg_queue_apply_request(int fd, struct map_session_data *sd)
safestrncpy(name, RFIFOCP(fd, 4), NAME_LENGTH);
if (sd->bg_queue) {
ShowWarning("clif_parse_bg_queue_apply_request: Received duplicate queue application: %d from player %s (AID:%d CID:%d).\n", type, sd->status.name, sd->status.account_id, sd->status.char_id);
if (sd->bg_queue_id > 0) {
//ShowWarning("clif_parse_bg_queue_apply_request: Received duplicate queue application: %d from player %s (AID:%d CID:%d).\n", type, sd->status.name, sd->status.account_id, sd->status.char_id);
clif_bg_queue_apply_result(BG_APPLY_DUPLICATE, name, sd); // Duplicate application warning
return;
} else if (type == 1) // Solo
bg_queue_join_multi(name, sd, { sd });
bg_queue_join_solo(name, sd);
else if (type == 2) // Party
bg_queue_join_party(name, sd);
else if (type == 4) // Guild
@ -17670,9 +17669,9 @@ void clif_bg_queue_apply_notify(const char *name, struct map_session_data *sd)
{
nullpo_retv(sd);
std::shared_ptr<s_battleground_queue> queue = sd->bg_queue;
std::shared_ptr<s_battleground_queue> queue = bg_search_queue(sd->bg_queue_id);
if (!queue) {
if (queue == nullptr) {
ShowError("clif_bg_queue_apply_notify: Player is not in a battleground queue.\n");
return;
}
@ -17712,8 +17711,10 @@ void clif_parse_bg_queue_cancel_request(int fd, struct map_session_data *sd)
bool success;
if (sd->bg_queue) {
if (sd->bg_queue->in_ready_state)
if (sd->bg_queue_id > 0) {
std::shared_ptr<s_battleground_queue> queue = bg_search_queue(sd->bg_queue_id);
if (queue && queue->state == QUEUE_STATE_SETUP_DELAY)
return; // Make the cancel button do nothing if the entry window is open. Otherwise it'll crash the game when you click on both the queue status and entry status window.
else
success = bg_queue_leave(sd);
@ -17751,11 +17752,11 @@ void clif_parse_bg_queue_lobby_reply(int fd, struct map_session_data *sd)
{
nullpo_retv(sd);
if(sd->bg_queue) {
if(sd->bg_queue_id > 0) {
uint8 result = RFIFOB(fd, 2);
if(result == 1) { // Accept
bg_queue_on_accept_invite(sd->bg_queue, sd);
bg_queue_on_accept_invite(sd);
} else if(result == 2) { // Decline
bg_queue_leave(sd);
clif_bg_queue_entry_init(sd);
@ -17765,7 +17766,7 @@ void clif_parse_bg_queue_lobby_reply(int fd, struct map_session_data *sd)
/// Plays a gong sound, signaling that someone has accepted the invite to enter a battleground.
/// 0x8e1 <result>.B <battleground name>.24B <lobby name>.24B (ZC_REPLY_ACK_LOBBY_ADMISSION)
void clig_bg_queue_ack_lobby(bool result, const char *name, const char *lobbyname, struct map_session_data *sd)
void clif_bg_queue_ack_lobby(bool result, const char *name, const char *lobbyname, struct map_session_data *sd)
{
nullpo_retv(sd);

View File

@ -833,7 +833,7 @@ void clif_bg_queue_apply_result(e_bg_queue_apply_ack result, const char *name, s
void clif_bg_queue_apply_notify(const char *name, struct map_session_data *sd);
void clif_bg_queue_entry_init(struct map_session_data *sd);
void clif_bg_queue_lobby_notify(const char *name, struct map_session_data *sd);
void clig_bg_queue_ack_lobby(bool result, const char *name, const char *lobbyname, struct map_session_data *sd);
void clif_bg_queue_ack_lobby(bool result, const char *name, const char *lobbyname, struct map_session_data *sd);
// Instancing
void clif_instance_create(int instance_id, int num);

View File

@ -2063,7 +2063,7 @@ int map_quit(struct map_session_data *sd) {
if (sd->bg_id)
bg_team_leave(sd, true, true);
if (sd->bg_queue != nullptr)
if (sd->bg_queue_id > 0)
bg_queue_leave(sd);
if( sd->status.clan_id )

View File

@ -354,6 +354,54 @@ int pc_get_group_level(struct map_session_data *sd) {
return sd->group_level;
}
/**
* Remove a player from queue after timeout
* @param tid: Timer ID
* @param tick: Timer
* @param id: ID
* @return 0 on success or 1 otherwise
*/
static TIMER_FUNC(pc_on_expire_active)
{
map_session_data *sd = (map_session_data *)data;
nullpo_retr(1, sd);
sd->tid_queue_active = INVALID_TIMER;
bg_queue_leave(sd);
clif_bg_queue_entry_init(sd);
return 0;
}
/**
* Function used to set timer externally
* @param sd: Player data
*/
void pc_set_bg_queue_timer(map_session_data *sd) {
nullpo_retv(sd);
if (sd->tid_queue_active != INVALID_TIMER) {
delete_timer(sd->tid_queue_active, pc_on_expire_active);
sd->tid_queue_active = INVALID_TIMER;
}
sd->tid_queue_active = add_timer(gettick() + 20000, pc_on_expire_active, 0, (intptr_t)sd);
}
/**
* Function used to delete timer externally
* @param sd: Player data
*/
void pc_delete_bg_queue_timer(map_session_data *sd) {
nullpo_retv(sd);
if (sd->tid_queue_active != INVALID_TIMER) {
delete_timer(sd->tid_queue_active, pc_on_expire_active);
sd->tid_queue_active = INVALID_TIMER;
}
}
static TIMER_FUNC(pc_invincible_timer){
struct map_session_data *sd;
@ -1471,6 +1519,7 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_
sd->expiration_tid = INVALID_TIMER;
sd->autotrade_tid = INVALID_TIMER;
sd->respawn_tid = INVALID_TIMER;
sd->tid_queue_active = INVALID_TIMER;
#ifdef SECURE_NPCTIMEOUT
// Initialize to defaults/expected
@ -1617,9 +1666,8 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_
sd->bonus_script.head = NULL;
sd->bonus_script.count = 0;
// Initialize BG queue pointer
sd->bg_queue = nullptr;
sd->bg_queue_accept_state = false;
// Initialize BG queue
sd->bg_queue_id = 0;
#if PACKETVER >= 20150513
sd->hatEffectIDs = NULL;
@ -13417,6 +13465,7 @@ void do_init_pc(void) {
add_timer_func_list(pc_global_expiration_timer, "pc_global_expiration_timer");
add_timer_func_list(pc_expiration_timer, "pc_expiration_timer");
add_timer_func_list(pc_autotrade_timer, "pc_autotrade_timer");
add_timer_func_list(pc_on_expire_active, "pc_on_expire_active");
add_timer(gettick() + autosave_interval, pc_autosave, 0, 0);

View File

@ -634,10 +634,6 @@ struct map_session_data {
bool changed; // if true, should sync with charserver on next mailbox request
} mail;
// Battlegrounds queue system [MasterOfMuppets]
std::shared_ptr<s_battleground_queue> bg_queue;
bool bg_queue_accept_state; // Set this to true when someone has accepted the invite to join BGs
//Quest log system
int num_quests; ///< Number of entries in quest_log
int avail_quests; ///< Number of Q_ACTIVE and Q_INACTIVE entries in quest log (index of the first Q_COMPLETE entry)
@ -668,7 +664,9 @@ struct map_session_data {
int debug_line;
const char* debug_func;
int bg_id;
// Battlegrounds queue system [MasterOfMuppets]
int bg_id, bg_queue_id;
int tid_queue_active; ///< Timer ID associated with players joining an active BG
#ifdef SECURE_NPCTIMEOUT
/**
@ -1296,6 +1294,9 @@ struct sg_data {
};
extern const struct sg_data sg_info[MAX_PC_FEELHATE];
void pc_set_bg_queue_timer(map_session_data *sd);
void pc_delete_bg_queue_timer(map_session_data *sd);
void pc_setinvincibletimer(struct map_session_data* sd, int val);
void pc_delinvincibletimer(struct map_session_data* sd);

View File

@ -20016,20 +20016,21 @@ BUILDIN_FUNC(bg_get_data)
/**
* Reserves a slot for the given Battleground.
* bg_reserve(<"bg_name">);
* bg_reserve("<battleground_map_name>"{,<ended>});
*/
BUILDIN_FUNC(bg_reserve)
{
const char *str = script_getstr(st, 2);
bool ended = script_hasdata(st, 3) ? script_getnum(st, 3) != 0 : false;
if (!bg_queue_reserve(str))
if (!bg_queue_reserve(str, ended))
ShowWarning("buildin_bg_reserve: Could not reserve battleground with name %s\n", str);
return SCRIPT_CMD_SUCCESS;
}
/**
* Removes a spot for the given Battleground.
* bg_unbook(<"bg_name">);
* bg_unbook("<battleground_map_name>");
*/
BUILDIN_FUNC(bg_unbook)
{
@ -20075,7 +20076,7 @@ BUILDIN_FUNC(bg_info)
size_t i;
for (i = 0; i < bg->maps.size(); i++)
setd_sub_str(st, nullptr, ".@bgmaps$", i, map_mapid2mapname(bg->maps[i].mapid), nullptr);
setd_sub_str(st, nullptr, ".@bgmaps$", i, mapindex_id2name(bg->maps[i].mapindex), nullptr);
setd_sub_num(st, nullptr, ".@bgmapscount", 0, i, nullptr);
script_pushint(st, i);
break;
@ -25143,7 +25144,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(bg_updatescore,"sii"),
BUILDIN_DEF(bg_join,"i????"),
BUILDIN_DEF(bg_create,"sii??"),
BUILDIN_DEF(bg_reserve,"s"),
BUILDIN_DEF(bg_reserve,"s?"),
BUILDIN_DEF(bg_unbook,"s"),
BUILDIN_DEF(bg_info,"si"),