Quantcast
Detecting World PvP Zones - WoWInterface
Thread Tools Display Modes
06-14-15, 10:43 PM   #1
Choonstertwo
A Chromatic Dragonspawn
 
Choonstertwo's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2011
Posts: 194
Detecting World PvP Zones

Someone has recently commented on my KillingBlow_Enhanced AddOn that it doesn't work in Ashran when PvP only mode (i.e. only report killing blows when in PvP zones) is enabled. To detect if the current zone is a PvP zone, I'm calling IsInInstance and checking if the instance type (second return value) is "pvp" or "arena".

Is there an easy way to detect whether the current zone is a World PvP zone? The World Battlefield API section didn't have any obvious solution to this.
  Reply With Quote
06-15-15, 03:42 AM   #2
Choonstertwo
A Chromatic Dragonspawn
 
Choonstertwo's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2011
Posts: 194
Thanks, I'll use that approach.
  Reply With Quote
06-15-15, 06:15 AM   #3
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
I try to avoid to use SetMapToCurrentZone() as much as I can (so far I could totally avoid it) because it will interfere with the user watching another map. The alternative approach that works well is to use GetInstanceInfo()

Code:
local _,_,_,_,_,_,_,zone = GetInstanceInfo()
if zone==1191 then
	print("I am in Ashran")
elseif zone==732 then
	print("I am in Tol Barad")
end
This approach does NOT work in Wintergrasp though because when you are there you will get the 571 return which is the Northrend id both during Wintergrasp battle or between battles (when it is like any Northrend zone).
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill

Last edited by Banknorris : 06-15-15 at 06:20 AM.
  Reply With Quote
06-15-15, 08:03 AM   #4
Choonstertwo
A Chromatic Dragonspawn
 
Choonstertwo's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2011
Posts: 194
That's a good idea. Using GetInstanceInfo, I can at least avoid calling SetMapToCurrentZone on every continent except Northrend.
  Reply With Quote
06-15-15, 09:03 AM   #5
Choonstertwo
A Chromatic Dragonspawn
 
Choonstertwo's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2011
Posts: 194
Just for future reference:


When you enter a new continent/instance (including when you first log in), PLAYER_ENTERING_WORLD and ZONE_CHANGED_NEW_AREA are fired in that order. When PLAYER_ENTERING_WORLD fires, GetInstanceInfo returns the correct instance map ID but GetCurrentMapAreaID returns the area ID of the continent. When ZONE_CHANGED_NEW_AREA fires, GetCurrentMapAreaID returns the correct area ID (after you call SetMapToCurrentZone).

Last edited by Choonstertwo : 06-15-15 at 09:05 AM.
  Reply With Quote
06-15-15, 11:02 AM   #6
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,289
Originally Posted by Banknorris View Post
I try to avoid to use SetMapToCurrentZone() as much as I can (so far I could totally avoid it) because it will interfere with the user watching another map. The alternative approach that works well is to use GetInstanceInfo()

Code:
local _,_,_,_,_,_,_,zone = GetInstanceInfo()
if zone==1191 then
	print("I am in Ashran")
elseif zone==732 then
	print("I am in Tol Barad")
end
This approach does NOT work in Wintergrasp though because when you are there you will get the 571 return which is the Northrend id both during Wintergrasp battle or between battles (when it is like any Northrend zone).
You can use this to detect if the battle is active or not:

http://wowprogramming.com/docs/api/GetWorldPVPAreaInfo
  Reply With Quote
06-15-15, 01:30 PM   #7
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,059
Presumably you can just use IsInActiveWorldPVP()

There's also GetZonePVPInfo()
  Reply With Quote
06-16-15, 10:06 AM   #8
gmarco
A Frostmaul Preserver
 
gmarco's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2009
Posts: 290
I do something like this in "remgank" :

Lua Code:
  1. local _, instanceType = IsInInstance()
  2.         if REMGANK_ENABLE == false or instanceType == "arena" or instanceType == "pvp" or (instanceType == "none" and GetZonePVPInfo() == "combat") then
  3.             -- REMGANK_ENABLE == false Monitoring is disabled
  4.             -- arena is, obviously, an arena.
  5.             -- pvp is a battleground.
  6.             -- none with GetZonePVPInfo() == "combat" is an outdoor PvP zone like Wintergrasp.
  7.             self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
  8.         else
  9.             -- If not in a pvp zone, register CLEU:
  10.             self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
  11.         end
  12.         return
  13.     end

It seems to work for me ...
__________________
This is Unix-Land. In quiet nights, you can hear the Windows machines reboot.
  Reply With Quote
06-16-15, 01:53 PM   #9
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,702
Originally Posted by Banknorris View Post
I try to avoid to use SetMapToCurrentZone() as much as I can (so far I could totally avoid it) because it will interfere with the user watching another map.
This method is safe:

Lua Code:
  1. local oldAreaID = GetCurrentMapAreaID()
  2. SetMapToCurrentZone()
  3.  
  4. -- store the current area ID
  5. local areaID = GetCurrentMapAreaID()
  6.  
  7. SetMapByID(oldAreaID)
  8.  
  9. -- do things
  Reply With Quote
06-16-15, 03:00 PM   #10
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,059
Originally Posted by p3lim View Post
This method is safe:

Lua Code:
  1. local oldAreaID = GetCurrentMapAreaID()
  2. SetMapToCurrentZone()
  3.  
  4. -- store the current area ID
  5. local areaID = GetCurrentMapAreaID()
  6.  
  7. SetMapByID(oldAreaID)
  8.  
  9. -- do things
No it isn't, you don't take into account the previous map level. Also, changing the map resets its zoom (if you use the scroll wheel on the world map).

This would also set the map to the wrong zone if you're currently inside of a microdungeon.

There are other things to consider when changing the map, like how extremely cpu intensive addons like Routes and Gatherer would react.

The only safeish method for actively changing the current map is to unregister WORLD_MAP_UPDATE from every frame that's watching it, do your thing and swap the map back to what it previously was, then re-register the event to those frames.

I don't recommend anyone do that unless they fully comprehend how the map works.
  Reply With Quote
06-17-15, 06:18 AM   #11
Choonstertwo
A Chromatic Dragonspawn
 
Choonstertwo's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2011
Posts: 194
Originally Posted by semlar View Post
Presumably you can just use IsInActiveWorldPVP()
Do you know whether that returns true only during an active battle or any time you're in a World PvP zone? Do you know which event to listen for to know when the return value changes? Unfortunately I don't think trial accounts have access to any world PvP zones, so I can't test it myself.

The default UI only seems to call it when you right click on a unit on the world map to determine whether or not you can report them as AFK.

WoW Programming doesn't have any documentation for it and Wowpedia doesn't have it listed at all.
  Reply With Quote
06-17-15, 08:41 AM   #12
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
I really don't know how Ashran works but from what I could test:
1) IsInActiveWorldPVP() always return false
2) You can't be there for long if you are not accepted to the battle, you will be teleported out
3) When you are accepted BATTLEFIELD_MGR_ENTERED triggers
4) When you leave Ashran BATTLEFIELD_MGR_EJECTED triggers
5) You are not put into an instance group like Tol Barad and Wintergrasp

In Tol Barad (and Wintergrasp)
1) IsInActiveWorldPVP() return true if in the area of an active battle even if you didn't accept the invite
2) You can't be there for long if you are not accepted to the battle, you will be teleported out
3) When you are accepted BATTLEFIELD_MGR_ENTERED triggers
4) When you leave battle area BATTLEFIELD_MGR_EJECTED triggers (but I am still in Tol Barad Peninsula).
5) Tol Barad and Tol Barad Peninsula shares the same GetInstanceInfo() returns
6) When the battle finishes BATTLEFIELD_MGR_STATE_CHANGED triggered
7) Only when I left the instance group or moved out of the Tol Barad battle area (and entering in Tol Barad Peninsula) was that BATTLEFIELD_MGR_EJECTED triggered.

BATTLEFIELD_MGR_ENTERED
BATTLEFIELD_MGR_EJECTED
BATTLEFIELD_MGR_STATE_CHANGE
arg1 is the battleID: 21 Tol Barad, 24 Ashran, 1 for Wintergrasp.
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill

Last edited by Banknorris : 06-17-15 at 10:32 AM.
  Reply With Quote
06-17-15, 09:51 AM   #13
Choonstertwo
A Chromatic Dragonspawn
 
Choonstertwo's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2011
Posts: 194
Originally Posted by Banknorris View Post
I really don't know how Ashran works but from what I could test:
Thanks for that. So it's safe to assume that the user is in an active World PvP zone from when BATTLEFIELD_MGR_ENTERED fires up until BATTLEFIELD_MGR_EJECTED, BATTLEFIELD_MGR_STATE_CHANGED or ZONE_CHANGED_NEW_AREA fires?
  Reply With Quote
06-18-15, 09:29 AM   #14
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
This is working perfectly in all three places (Ashran, Tol Barad and Wintergrasp):
Lua Code:
  1. local f = CreateFrame("Frame")
  2.  
  3. f:SetScript("OnEvent",function(self,event,...)
  4.     if event=="PLAYER_ENTERING_WORLD" then
  5.         local _,_,_,_,_,_,_,instance_id = GetInstanceInfo()
  6.         if instance_id==1191 or IsInActiveWorldPVP() then
  7.             f.in_active_world_combat_zone = true
  8.         else
  9.             f.in_active_world_combat_zone = false
  10.         end
  11.     elseif event=="BATTLEFIELD_MGR_ENTERED" then
  12.         if ...==1 or ...==21 or ...==24 then
  13.             f.in_active_world_combat_zone = true
  14.         end
  15.     elseif event=="BATTLEFIELD_MGR_EJECTED" then
  16.         if ...==1 or ...==21 or ...==24 then
  17.             f.in_active_world_combat_zone = false
  18.         end
  19.     elseif event=="BATTLEFIELD_MGR_STATE_CHANGE" then
  20.         if (...==1 or ...==21) and IsInActiveWorldPVP()==false then
  21.             f.in_active_world_combat_zone = false
  22.         end
  23.     end
  24.     print(f.in_active_world_combat_zone)
  25. end)
  26. f:RegisterEvent("PLAYER_ENTERING_WORLD")
  27. f:RegisterEvent("BATTLEFIELD_MGR_ENTERED")
  28. f:RegisterEvent("BATTLEFIELD_MGR_EJECTED")
  29. f:RegisterEvent("BATTLEFIELD_MGR_STATE_CHANGE")
Side note: I noticed that GetInstanceInfo() does not return the right id after ZONE_CHANGED_NEW_AREA (it returns the area you just left instead), at least when running into and out of Ashran.
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill

Last edited by Banknorris : 06-18-15 at 01:48 PM.
  Reply With Quote
06-18-15, 12:21 PM   #15
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,059
Ashran doesn't appear to be considered world pvp by IsInActiveWorldPVP() but GetZonePVPInfo() returns "combat" for the type and "true" for the second argument (which is incorrectly documented as meaning FFA and I'm not entirely sure what it means).

Depending on your definition of active pvp, I think something like this should work.

Lua Code:
  1. local function IsAreaActivePVP()
  2.     local _, instanceType = IsInInstance()
  3.     if instanceType == 'pvp' then return true end
  4.     local pvpType, isSubZonePVP = GetZonePVPInfo()
  5.     if pvpType == 'arena' or (pvpType == 'combat' and (isSubZonePVP or IsInActiveWorldPVP())) then return true end
  6.     return false
  7. end

Last edited by semlar : 06-18-15 at 01:37 PM.
  Reply With Quote
06-18-15, 12:25 PM   #16
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
Semlar, Choonsters asked for events as well, because even if your function works there is still the problem when to call it. I tested my solution so unless someone points any flaw on it, I would say the problem is solved.
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill
  Reply With Quote
06-18-15, 01:21 PM   #17
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,059
Originally Posted by Banknorris View Post
Semlar, Choonsters asked for events as well, because even if your function works there is still the problem when to call it. I tested my solution so unless someone points any flaw on it, I would say the problem is solved.
Your solution relies on hard-coded magic numbers to address specific problematic zones which makes it less flexible for future additions. Also, while the topic title specifies "detecting world pvp zones", what he's really interested in is detecting whether the player is in an area that should be considered a pvp zone, which presumably includes world pvp, battlegrounds, arenas, and open-world arenas like Gurubashi and FFA events.

The events to watch are ZONE_CHANGED_NEW_AREA for traveling between major zones, potentially ZONE_CHANGED for subzones, PLAYER_ENTERING_WORLD specifically for catching reloaded UIs (because zone information is not accurate between other loading screens), and if those events don't occur when starting a battle like wintergrasp then include the BATTLEFIELD_MGR events.

You're also missing brackets in your BATTLEFIELD_MGR_STATE_CHANGE condition, so it probably isn't going to behave like you're expecting.

Last edited by semlar : 06-18-15 at 01:46 PM.
  Reply With Quote
06-18-15, 01:49 PM   #18
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
Originally Posted by semlar View Post
You're also missing brackets in your BATTLEFIELD_MGR_STATE_CHANGE condition, so it probably isn't going to behave like you're expecting.
Oops, fixed.
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill
  Reply With Quote
06-18-15, 01:53 PM   #19
Choonstertwo
A Chromatic Dragonspawn
 
Choonstertwo's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2011
Posts: 194
Thanks for all the responses. I already have arenas and BGs working, but I hadn't actually considered FFA PvP zones (I never did much PvP myself); I was only thinking of the three World PvP zones (Ashran, Tol Barad and Wintergrasp). That said, I think PvP only mode should cover all types of PvP zone like Semlar said.

Unless someone finds a flaw in it, I'll probably go with Semlar's solution (GetZonePVPInfo/IsInActiveWorldPVP) and check it at zone change events (PLAYER_ENTERING_WORLD, ZONE_CHANGED and ZONE_CHANGED_NEW_AREA) and World PvP events (BATTLEFIELD_MGR_*).

Does any event fire when entering or exiting the floor of the Gurubashi Arena (i.e. the FFA zone)? It looks like the subzone covers the whole arena and the surrounding area, so ZONE_CHANGED may not be useful.

Edit: Just realised I can probably test this myself on a trial account. I'll probably do it tomorrow.

Last edited by Choonstertwo : 06-18-15 at 02:08 PM.
  Reply With Quote
06-18-15, 02:19 PM   #20
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
Just went to Gurubashi Arena and ZONE_CHANGED triggers when you enter or leave the circular center area (the arena). In some points if you are very close to the edge you can cross the zone without going to the ground level but I don't think that is relevant.

UNIT_FACTION also triggers but when you leave the center area you still keep the FFA status for a while. Maybe you can use UnitIsPVPFreeForAll("player") when UNIT_FACTION triggers (arg1 being "player"), to check if you are or not in a FFA combat. That would avoid you to use ZONE_CHANGED.

I still prefer my solution (for world pvp) because BATTLEFIELD_MGR_* triggers only rarely and most of times will be relevant for your problem. For battlegrounds and arenas all you need to do is call IsInInstance() when PLAYER_ENTERING_WORLD triggers (I know you are already doing that). So apparently is totally possible to avoid using ZONE_CHANGED and ZONE_CHANGED_NEW_AREA.

Here my complete solution attempt:
Lua Code:
  1. local Ashran_instance_id = 1191
  2. local Ashran_battle_id = 24
  3.  
  4. local f = CreateFrame("Frame")
  5.  
  6. f:SetScript("OnEvent",function(self,event,...)
  7.     local pvp_old = f.pvp
  8.     if event=="PLAYER_ENTERING_WORLD" then
  9.         local _,instance_type = IsInInstance()
  10.         if instance_type=="pvp" or instance_type=="arena" then
  11.             f.instance = true
  12.         else
  13.             f.instance = false         
  14.             local _,_,_,_,_,_,_,instance_id = GetInstanceInfo()
  15.             if instance_id==Ashran_instance_id or IsInActiveWorldPVP() then
  16.                 f.world = true
  17.             else
  18.                 f.world = false
  19.             end
  20.         end
  21.     elseif event=="BATTLEFIELD_MGR_ENTERED" then
  22.         f.world = true
  23.     elseif event=="BATTLEFIELD_MGR_EJECTED" then
  24.         f.world = false
  25.     elseif event=="BATTLEFIELD_MGR_STATE_CHANGE" then
  26.         if ...~=Ashran_battle_id and IsInActiveWorldPVP()==false then
  27.             f.world = false
  28.         end
  29.     elseif event=="UNIT_FACTION" and ...=="player" then
  30.         if UnitIsPVPFreeForAll("player")==true then
  31.             f.ffa = true
  32.         else
  33.             f.ffa = false
  34.         end
  35.     end
  36.     f.pvp = f.instance or f.world or f.ffa or false
  37.     if f.pvp~=pvp_old then
  38.         print("pvp area:",f.pvp)
  39.     end
  40. end)
  41. f:RegisterEvent("PLAYER_ENTERING_WORLD")
  42. f:RegisterEvent("BATTLEFIELD_MGR_ENTERED")
  43. f:RegisterEvent("BATTLEFIELD_MGR_EJECTED")
  44. f:RegisterEvent("BATTLEFIELD_MGR_STATE_CHANGE")
  45. f:RegisterEvent("UNIT_FACTION")
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill

Last edited by Banknorris : 06-19-15 at 06:37 AM.
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Detecting World PvP Zones

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off