WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   General Authoring Discussion (https://www.wowinterface.com/forums/forumdisplay.php?f=20)
-   -   Detecting World PvP Zones (https://www.wowinterface.com/forums/showthread.php?t=52370)

Choonstertwo 06-14-15 10:43 PM

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.

Choonstertwo 06-15-15 03:42 AM

Thanks, I'll use that approach.

Banknorris 06-15-15 06:15 AM

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).

Choonstertwo 06-15-15 08:03 AM

That's a good idea. Using GetInstanceInfo, I can at least avoid calling SetMapToCurrentZone on every continent except Northrend.

Choonstertwo 06-15-15 09:03 AM

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).

Resike 06-15-15 11:02 AM

Quote:

Originally Posted by Banknorris (Post 309140)
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

semlar 06-15-15 01:30 PM

Presumably you can just use IsInActiveWorldPVP()

There's also GetZonePVPInfo()

gmarco 06-16-15 10:06 AM

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 ...

p3lim 06-16-15 01:53 PM

Quote:

Originally Posted by Banknorris (Post 309140)
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

semlar 06-16-15 03:00 PM

Quote:

Originally Posted by p3lim (Post 309156)
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.

Choonstertwo 06-17-15 06:18 AM

Quote:

Originally Posted by semlar (Post 309146)
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.

Banknorris 06-17-15 08:41 AM

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.

Choonstertwo 06-17-15 09:51 AM

Quote:

Originally Posted by Banknorris (Post 309174)
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?

Banknorris 06-18-15 09:29 AM

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.

semlar 06-18-15 12:21 PM

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

Banknorris 06-18-15 12:25 PM

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.

semlar 06-18-15 01:21 PM

Quote:

Originally Posted by Banknorris (Post 309198)
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.

Banknorris 06-18-15 01:49 PM

Quote:

Originally Posted by semlar (Post 309199)
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.

Choonstertwo 06-18-15 01:53 PM

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.

Banknorris 06-18-15 02:19 PM

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")


All times are GMT -6. The time now is 08:39 PM.

vBulletin © 2020, Jelsoft Enterprises Ltd
© 2004 - 2020 MMOUI