Thread Tools Display Modes
02-06-12, 04:52 AM   #1
Animor
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Mar 2011
Posts: 136
Pattern matching and "player playing" status

Hello,

I've got two question I hope to get answers to:

1. I'm trying to match a pattern in strings that can come in two ways:
a. "Bases: 3 Points: 150/1600 ..."
b. "Points/Flags: 2 ..."

I want to get the 150 in case it's a string type 'a' (with ####/####). And in case there is no such pattern (type 'b'), I want to get the number - 2 in the example.
I've tried to use:
Code:
string.match(origString, "(%d+)/*")
But it didn't work - I got 3 for string type 'a'. If I use:
Code:
string.match(origString, "(%d+)/")
then I get the 150, but it obviously fails on string type 'b'.
Is there a matching pattern that will catch both cases? Note that the string before the number can alter, it's not always 'Points' for example.

2. When trying to whisper to an offline player, I get error "No player named XXX is currently playing". Is there a way to know that prior to the whisper? Like an API telling me that? I looked but couldn't find one.

Thanks
  Reply With Quote
02-06-12, 06:26 AM   #2
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
#1 - I don't think you're going to be able to get those with one pattern.

You want the values underlined here:
(a) Bases: 3 Points: 150/1600 ...
(b) Points/Flags: 2 ...

But, any pattern I can think of would be unable to distinguish between the values underlined here:
(a) Bases: 3 Points: 150/1600 ...
(b) Points/Flags: 2 ...

If you require a slash immediately after the number, then the pattern will not work to find the deisred number in the (b) string because there is no slash.

If you can be more specific about where these strings are coming from and what you want to do with them, I can probably provide a better solution.

#2 - There are three ways to tell if someone is online or offline:

(1) They are on your friends list.
(2) They are in your guild.
(3) You perform a /who query that matches them.

For addons sending whispers to arbitrary players who are not on your friends list or in your guild, I'd suggest looking at BadBoy_Levels for an example of how to add a name to your friends list for just long enough to get information about them (and then removing them so they are never "really" on the friends list as far as the user is concerned). BB_L checks their level, but the same code would work to see if they were online.

Depending on why you want to do this, however, I'd be very careful. If you're sending instructions to players in your battleground, it shouldn't be an issue, but if you're sending, say, guild invitations via whisper, you're likely to generate a lot of ill will. Personally, I instantly /ignore anyone who sends me an unsolicited whisper about something I don't care about, and pretty much any topic people are whispering me about using an addon is something I don't care about.
  Reply With Quote
02-06-12, 06:57 AM   #3
Animor
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Mar 2011
Posts: 136
Thanks

As for (1), the info is BG score I get from the API GetWorldStateUIInfo(). Some BGs have points/maxpoints, some have only points.
My current workaround is to identify in what kind of BG the player is now, then set a different matching pattern according to the BG type. I was trying to make a generic matching pattern, in order for the code to be more efficient. I thought that using '*' will try to find the longest pattern so it will try to include '/' in the matched pattern, if any can found. I thought that this is the difference between '-' (shortest pattern) and '*' (longest patter). But apparently I was wrong about it, since it doesn't apply to several matches in a single string.

(2) I'm a bit afraid of adding a player to the friends list, then removing it, like you've suggested. It seems to be too intrusive method. I'm afraid that that player might remain in the friend list on unpredictable cases, like a DC at the wrong moment, etc.
"who" query looks too complex and problematic according to this: http://www.wowpedia.org/API_SetWhoToUI

Edit: btw, I'm not sending unsolicited whisper, I hate those gold seller spam addons myself and I use badboy to report them.

Last edited by Animor : 02-06-12 at 07:02 AM.
  Reply With Quote
02-06-12, 07:27 AM   #4
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Battleground-specific code sounds like the way to go. I don't know which event(s) fire when the return values from that function change, but something like this:

Code:
local zoneFunctions = {
    ["Eye of the Storm"] = function(...)
        -- code goes here to deal with Eye of the Storm messages
    end,
    ["Warsong Gulch"] = function(...)
        -- code goes here to deal with Warsong Gulch messages
    end,
}

local fallbackFunction = function(...)
    -- code goes here to deal with unknown zones,
    -- or just leave the function empty
end

local currentFunction

function addon:ZONE_CHANGED_NEW_AREA()
    local zone = GetRealZoneText()
    currentFunction = zoneFunctions[zone] or fallbackFunction
end

function addon:SOME_EVENT(...)
    -- 1. do any zone-independent pre-processing here

    -- 2. pass the args to the relevant function:
    currentFunction(...)

    -- 3. do any zone-independent post-processing here
end
  Reply With Quote
02-06-12, 07:44 AM   #5
Animor
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Mar 2011
Posts: 136
Thanks

I've already used a bit different approach. I will be happy to know if you see any flaws in it:
Code:
function MyAddon:GetBGScore(locationName)
  
  local allianceScore	= ""
  local hordeScore	= ""
  local num1 		= 1
  local num2 		= 2
  local matchString  	= "(%d+)"
  local score1		= 0
  local score2		= 0
  local scoreMsg 	= ""
  
  -- BGs in which score format is ####/####
  if sfind(locationName, "Gilneas") or sfind(locationName, "Basin") or sfind(locationName, "Storm") then
    matchString = "(%d+)/"
  end

  -- For BGs in which the first info line is global (not faction score)
  if sfind(locationName, "Warsong") or sfind(locationName, "Peaks") or sfind(locationName, "Storm") then
    num1 = 2
    num2 = 3
  end

  -- Get factions score from the lines that appear top-middle of the screen
  score1 = tonumber(smatch((select(4, GetWorldStateUIInfo(num1)) or ""), matchString)) or 0
  score2 = tonumber(smatch((select(4, GetWorldStateUIInfo(num2)) or ""), matchString)) or 0	

  -- Location on screen - is first line Alliance or Horde?
  if sfind(string.lower(select(5, GetWorldStateUIInfo(num1))), "alliance") then
    allianceScore	= score1
    hordeScore		= score2
  else
    allianceScore	= score2
    hordeScore		= score1
  end
	
  -- No score in Strand of the Ancients, report instead end of round timer.
  if sfind(locationName, "Strand") then	
    local endtime = smatch((select(4, GetWorldStateUIInfo(8)) or ""), "%d+.*") or L["<no data>"]
    scoreMsg = L["End of round in "]..endtime.. L[" min"]
  else
    scoreMsg = L["Score: "]..allianceScore.."(A) - "..hordeScore.."(H), "
  end
  
  return scoreMsg

end

Last edited by Animor : 02-06-12 at 07:53 AM.
  Reply With Quote
02-06-12, 08:08 AM   #6
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
I'd try to come up with something to reduce the use of string manipulation functions, but other than that I don't see anything obviously wrong.

For example, instead of:
Code:
  local matchString  	= "(%d+)"

  -- BGs in which score format is ####/####
  if sfind(locationName, "Gilneas") or sfind(locationName, "Basin") or sfind(locationName, "Storm") then
    matchString = "(%d+)/"
  end
You could define a table with the full names (so you don't have to run string.find for every possible name) and the string (so you can just perform one table lookup instead of many if/or checks:

Code:
local matchStrings = {
	["Arathi Basin"]     = "(%d+)/",
	["Eye of the Storm"] = "(%d+)/",
	["Warsong Gulch"]    = "(%d+)",
}
Code:
local zoneName = GetRealZoneText()

local matchString = matchStrings[zoneName]
This would save time inside the function call, and make it easier to handle new battlegrounds, or adjust for changes in existing battlegrounds.
  Reply With Quote
02-06-12, 07:33 AM   #7
Ketho
A Pyroguard Emberseer
 
Ketho's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,026
Originally Posted by Animor View Post
Thanks

As for (1), the info is BG score I get from the API GetWorldStateUIInfo(). Some BGs have points/maxpoints, some have only points.
My current workaround is to identify in what kind of BG the player is now, then set a different matching pattern according to the BG type. I was trying to make a generic matching pattern, in order for the code to be more efficient. I thought that using '*' will try to find the longest pattern so it will try to include '/' in the matched pattern, if any can found. I thought that this is the difference between '-' (shortest pattern) and '*' (longest patter). But apparently I was wrong about it, since it doesn't apply to several matches in a single string.
Maybe this thread might also help you a bit on the way

http://www.wowinterface.com/forums/s...ad.php?t=40977
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Pattern matching and "player playing" status


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