Here's code for the main part of the addon that I whipped up. It uses metatables to handle falling back to a generic song table. Be sure the file containing this code loads first in your ToC.
Lua Code:
-- Grab access to our shared addon table
local _,Addon=...;
-- Set up our default song table and metatable for fallback
local DefaultSongTable={};
local FallbackMeta={__index=DefaultSongTable};
local SongTables={Alliance={},Horde={}};-- Build faction-based song tables
for _,tbl in pairs(SongTables) do setmetatable(tbl,FallbackMeta); end-- Set our fallback metatable
SongTables.Default=DefaultSongTable;-- Register the default song table
Addon.SongTables=SongTables;-- Enable access to our song tables through the shared addon table
local CurrentSong;
local function PlaySongForMap(mapid)
-- Select the song table and grab the song for the map
local song=(SongTables[UnitFactionGroup("player")] or DefaultSongTable)[mapid];
-- Play the new song if different or stop if there is none
if song and song~=CurrentSong then
PlayMusic(song);
elseif not song then
StopMusic();
end
-- Update our saved variable
CurrentSong=song;
end
local EventFrame=CreateFrame("Frame");
EventFrame:RegisterEvent("PLAYER_ENTERING_WORLD");-- Player enters from loading screen
EventFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA");-- Zones changed
EventFrame:RegisterEvent("ZONE_CHANGED_INDOORS");-- Some indoor zone changing requires this
EventFrame:SetScript("OnEvent",function()
-- We don't want to mess around with the map while the user is looking at it, but we need our MapID, so we'll do some tricky stuff
if WorldMapFrame:IsShown() then
-- Get a list of frames listening for map updates and disable them
local frames={GetFramesRegisteredByEvent("WORLD_MAP_UPDATE")};
for _,frame in ipairs(frames) do frame:UnregisterEvent("WORLD_MAP_UPDATE"); end
-- Save old MapID and select current zone (MapID is invalid if viewing a continent, store that too)
local mapid,continent=GetCurrentMapAreaID(),GetCurrentMapContinent();
SetMapToCurrentZone();
-- We have the zone we want, find and play our song
PlaySongForMap(GetCurrentMapAreaID());
-- Restore the map and re-enable the frames so the user would never know we did anything
if mapid>=0 then SetMapByID(mapid); else SetMapZoom(continent); end
for _,frame in ipairs(frames) do frame:RegisterEvent("WORLD_MAP_UPDATE"); end
else
-- User isn't looking at the map, we'll use a more straightforward approach
SetMapToCurrentZone();
PlaySongForMap(GetCurrentMapAreaID());
end
end);
In your sound packs placed in other Lua files in the same addon, you can register songs like this.
Lua Code:
-- Grab access to our shared addon table
local _,Addon=...;
-- Alliance and Horde have their own songs, though it's a good idea to define a default anyway
Addon.SongTable.Default[123]="Path\\To\\DefaultSong";
Addon.SongTable.Alliance[123]="Path\\To\\AllianceSong";
Addon.SongTable.Horde[123]="Path\\To\\HordeSong";
-- Alliance has their own song, Horde uses default
Addon.SongTable.Default[345]="Path\\To\\DefaultSong";
Addon.SongTable.Alliance[345]="Path\\To\\AllianceSong";
-- Horde has their own song, Alliance uses default
Addon.SongTable.Default[567]="Path\\To\\DefaultSong";
Addon.SongTable.Horde[567]="Path\\To\\HordeSong";
-- Both factions use the default
Addon.SongTable.Default[789]="Path\\To\\DefaultSong";
PS: The first return of
UnitFactionGroup() is locale-independant, so it doesn't need to be localized.