Thread Tools Display Modes
10-16-16, 05:45 AM   #1
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
WorldMap POIs

I have this little mod, which shows where does your Flight Master's Whistle will take you by fading out every other flight point POI on the map, and restore them on cast fail/success and so on. However i have a minor issue that if i interrupt the cast with jumping it properly restores the alpha of the other POIs, however if i interrupt the cast by moving then it's not. And for the love of god i can't figure out why.

Lua Code:
  1. local AddonName, Addon = ...
  2.  
  3. local Whistle = { }
  4. Addon.Whistle = Whistle
  5.  
  6. Whistle.events = CreateFrame("Frame")
  7. Whistle.events:RegisterEvent("ADDON_LOADED")
  8.  
  9. Whistle.events:SetScript("OnEvent", function(self, event, ...)
  10.     --print(event, ...)
  11.     Whistle[event](Whistle, ...)
  12. end)
  13.  
  14. Whistle.data = { }
  15.  
  16. function Whistle:ADDON_LOADED(addon)
  17.     if addon == AddonName then
  18.         self:RegisterEvents()
  19.  
  20.         --[[hooksecurefunc("WorldMapFrame_AnimAlphaIn", function(self, delay)
  21.             if delay then
  22.                 self:Restore()
  23.             end
  24.         end)]]
  25.  
  26.         --[[WorldMapFrame.AnimAlphaIn:HookScript("OnFinished", function(this)
  27.             self:Restore()
  28.         end)]]
  29.  
  30.         GameTooltip:HookScript("OnTooltipSetItem", function(self)
  31.             local name, link = self:GetItem()
  32.             if link then
  33.                 local id = string.match(link, "item:(%d*)")
  34.                 if id and id == "141605" then
  35.                     self:AddDoubleLine(Whistle:Update(true))
  36.                 end
  37.             end
  38.         end)
  39.  
  40.         self.events:UnregisterEvent("ADDON_LOADED")
  41.     end
  42. end
  43.  
  44. function Whistle:RegisterEvents()
  45.     self.events:RegisterEvent("PLAYER_ENTERING_WORLD")
  46.     self.events:RegisterUnitEvent("UNIT_SPELLCAST_START", "player")
  47.     self.events:RegisterUnitEvent("UNIT_SPELLCAST_STOP", "player")
  48.     self.events:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTED", "player")
  49.     self.events:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player")
  50. end
  51.  
  52. function Whistle:PLAYER_ENTERING_WORLD()
  53.     self:Restore()
  54. end
  55.  
  56. function Whistle:UNIT_SPELLCAST_START(unit, spell, rank, lineID, spellID)
  57.     if spellID ~= 227334 then
  58.         return
  59.     end
  60.  
  61.     self.lineID = lineID
  62.  
  63.     self:Update()
  64. end
  65.  
  66. function Whistle:UNIT_SPELLCAST_STOP(unit, spell, rank, lineID, spellID)
  67.     if lineID ~= self.lineID or spellID ~= 227334 then
  68.         return
  69.     end
  70.  
  71.     self:Restore()
  72. end
  73.  
  74. function Whistle:UNIT_SPELLCAST_INTERRUPTED(unit, spell, rank, lineID, spellID)
  75.     if lineID ~= self.lineID or spellID ~= 227334 then
  76.         return
  77.     end
  78.  
  79.     self:Restore()
  80. end
  81.  
  82. function Whistle:UNIT_SPELLCAST_SUCCEEDED(unit, spell, rank, lineID, spellID)
  83.     if lineID ~= self.lineID or spellID ~= 227334 then
  84.         return
  85.     end
  86.  
  87.     self:Restore()
  88. end
  89.  
  90. function Whistle:Update(noFade)
  91.     table.wipe(self.data)
  92.  
  93.     for i = 1, GetNumMapLandmarks() do
  94.         local name = "WorldMapFramePOI"..i
  95.         local poi = _G[name]
  96.         local poiTexture = _G[name.."Texture"]
  97.  
  98.         if not poi then
  99.             return
  100.         end
  101.  
  102.         local ULx, ULy, LLx, LLy, URx, URy, LRx, LRy = poiTexture:GetTexCoord()
  103.  
  104.         if poiTexture:GetTexture() == "Interface\\Minimap\\POIIcons" and ULx == 0.70703125 and ULy== 0.423828125 and LLx == 0.70703125 and LLy == 0.45703125 and URx == 0.7734375 and URy == 0.423828125 and LRx == 0.7734375 and LRy == 0.45703125 then
  105.             local point1 = { }
  106.             local point2 = { }
  107.  
  108.             --local _, parent, _, px, py = _G["WorldMapPlayerUpper"]:GetPoint(1)
  109.  
  110.             local unitX, unitY = GetPlayerMapPosition("player")
  111.  
  112.             local scale = _G["WorldMapPlayersFrame"]:GetScale()
  113.             --local px = pos[4] * scale
  114.             --local py = pos[5] * scale
  115.  
  116.             point1.x = unitX * WorldMapButton:GetWidth() * scale
  117.             point1.y = -1 * unitY * WorldMapButton:GetHeight() * scale
  118.  
  119.             local _, _, _, x, y = poi:GetPoint(1)
  120.  
  121.             local scale = _G["WorldMapPOIFrame"]:GetScale()
  122.             x = x * scale
  123.             y = y * scale
  124.  
  125.             point2.x = x
  126.             point2.y = y
  127.  
  128.             local distance = self:GetDistance(point1, point2)
  129.  
  130.             self.data[#self.data + 1] = { }
  131.             self.data[#self.data][1] = name
  132.             self.data[#self.data][2] = distance
  133.  
  134.             table.sort(self.data, function(a, b) return a[2] < b[2] end)
  135.         end
  136.     end
  137.  
  138.     if not noFade then
  139.         for i = 2, #self.data do
  140.             local name = self.data[i][1]
  141.  
  142.             _G[name]:SetAlpha(0.5)
  143.         end
  144.     end
  145.  
  146.     return _G[self.data[1][1]].name
  147. end
  148.  
  149. function Whistle:Restore()
  150.     for i = 1, #self.data do
  151.         local poi = _G[self.data[i][1]]
  152.  
  153.         if not poi then
  154.             return
  155.         end
  156.  
  157.         poi:SetAlpha(1)
  158.     end
  159.  
  160.     table.wipe(self.data)
  161. end
  162.  
  163. function Whistle:GetDistance(point1, point2)
  164.     local x = point1.x - point2.x
  165.     local y = point1.y - point2.y
  166.  
  167.     local distance = math.sqrt((x^2) + (y^2))
  168.  
  169.     return distance
  170. end

Last edited by Resike : 10-16-16 at 05:49 AM.
  Reply With Quote
10-16-16, 11:08 PM   #2
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,323
From what I can tell, it's a bug with the WorldMapFrame Alpha animations. I have a working version that reapplies the alpha when the animations finish (both fade in and fade out, though only fade out is necessary).

PS: I have a much more efficient version in the works, I just need to iron out a few hiccups and it'll be ready to release if you're interested.
Though in all honesty, hunting around for which flight point is highlighted takes almost as long as the cast time itself. The tooltip modification is a good idea though.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 10-16-16 at 11:13 PM.
  Reply With Quote
10-17-16, 12:14 AM   #3
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,323
Here's what I have so far. The biggest hurdle is supporting the player viewing a different zone while using the flight whistle. There seems to be a delay with unregistering and restoring events that are currently running and can easily send you into a limited infinite loop. For now, I cut out the POI fading and left in the tooltip modification. This should also tell you precisely how many yards you are from the flight point it'll choose.

Lua Code:
  1. local GetNearestFlightPath; do--    name,distance=function()
  2.     local function GetRealCoordBounds()
  3.         local _,zx1,zy1,zx2,zy2=GetCurrentMapDungeonLevel();
  4.         zx1,zy1,zx2,zy2=zx1 or 0,zy1 or 0,zx2 or 0,zy2 or 0;
  5.         if zx1~=0 and zy1~=0 and zx2~=0 and zy2~=0 then return zx1,zy1,zx2,zy2; end--   Level-Specific Coords
  6.  
  7.         _,zx1,zy1,zx2,zy2=GetCurrentMapZone();
  8.         zx1,zy1,zx2,zy2=zx1 or 0,zy1 or 0,zx2 or 0,zy2 or 0;
  9.         if zx1~=0 and zy1~=0 and zx2~=0 and zy2~=0 then return zx1,zy1,zx2,zy2; end--   General Map Coords
  10.  
  11.         return nil,nil,nil,nil;--   No real coords
  12.     end
  13.  
  14.     local function GetRealCoords(x,y)
  15.         if not (x and y and x~=0 and y~=0) then return nil,nil; end--   Invalid coords
  16.  
  17.         local zx1,zy1,zx2,zy2=GetRealCoordBounds();
  18.         if not zx1 then return nil,nil; end--   No real coords
  19.  
  20.         return (zx2-zx1)*x+zx1,(zy2-zy1)*y+zy1;
  21.     end
  22.  
  23.     function GetNearestFlightPath()
  24. --      Disable event to save CPU
  25.         local framelist={GetFramesRegisteredForEvent("WORLD_MAP_UPDATE")};
  26.         for _,frame in ipairs(framelist) do frame:UnregisterEvent("WORLD_MAP_UPDATE"); end
  27.  
  28. --      Save MapID and select current zone (MapID is invalid if viewing a continent, store that too)
  29.         local mapid,continent=GetCurrentMapAreaID(),GetCurrentMapContinent();
  30.         SetMapToCurrentZone();
  31.  
  32.         local py,px=UnitPosition("player");
  33.         local lowdist,lowname;
  34.         for i=1,GetNumMapLandmarks() do
  35.             local id,name,_,_,x,y=GetMapLandmarkInfo(i);
  36.             x,y=GetRealCoords(x,y);
  37.  
  38.             if id==5 then-- Flight paths are landmark ID 5
  39.                 local dist=(px-x)^2+(py-y)^2;
  40.                 if not lowdist or dist<lowdist then
  41.                     lowdist,lowname=dist,name;--    Capture our shortest distance
  42.                 end
  43.             end
  44.         end
  45.         if lowdist then lowdist=lowdist^0.5; end--  Apply square root outside of loop to save CPU
  46.  
  47. --      Restore map and enable event
  48.         if mapid>=0 then SetMapByID(mapid); else SetMapZoom(continent); end
  49.         for _,frame in ipairs(framelist) do frame:RegisterEvent("WORLD_MAP_UPDATE"); end
  50.  
  51.         return lowname,lowdist;--   Most significant return is the name, distance is secondary
  52.     end
  53. end
  54.  
  55. GameTooltip:HookScript("OnTooltipSetItem",function(self,...)--  Hook Flight Whistle tooltip
  56.     local _,link=self:GetItem();
  57.     if link and link:find("|Hitem:141605[:|]") then
  58.         local name,dist=GetNearestFlightPath();
  59.         if name and dist then self:AddDoubleLine(name,BreakUpLargeNumbers(math.floor(dist)).." yds",0.5,0.5,0.5,0.5,0.5,0.5); end
  60.     end
  61. end);
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
10-20-16, 09:09 AM   #4
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Yeah thanks works nice. However i would still like to highlight the fligh POI itself, maybe i'll dich the alpha changes, and just recolor the flightmap POI to red or something.
  Reply With Quote
10-20-16, 09:50 AM   #5
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Maybe you can use SetVertexColor(1, 1, 1, alpha) on the texture instead?
__________________
Grab your sword and fight the Horde!
  Reply With Quote
10-20-16, 04:31 PM   #6
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,323
Originally Posted by Resike View Post
Yeah thanks works nice. However i would still like to highlight the fligh POI itself, maybe i'll dich the alpha changes, and just recolor the flightmap POI to red or something.
Be careful choosing your color. Red is already used to denote Horde flight points. Blue is for Alliance. They appear to be separate texture indices, so be aware of color channel filtering when changing the colors of these. I had fixes for alpha modification, but the problem I was running against was supporting the player being able to look at other zones in the map without disrupting the addon or causing glitches.



Originally Posted by Lombra View Post
Maybe you can use SetVertexColor(1, 1, 1, alpha) on the texture instead?
Setting alpha using :SetVertexColor() is no different than :SetAlpha(). I've had related problems on another addon that had translucent colored textures and the alpha animation on the parent frame would always screw up the transparency.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 10-20-16 at 04:48 PM.
  Reply With Quote
10-21-16, 04:12 AM   #7
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Maybe i should just force show the POI's highlight texture then, and disable the OnLeave script while the cast is happening.
  Reply With Quote
10-21-16, 04:12 PM   #8
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,323
Here's working alpha changes and getting WorldMapPing to help out. Also properly checks if we're in the Broken Isles continent and not in Dalaran. Flight Whistle is usable, but fails with a wrong zone error there.
Lua Code:
  1. --------------------------
  2. --[[    Settings    ]]
  3. --------------------------
  4. local FadeAlpha=0.5;
  5.  
  6. ----------------------------------
  7. --[[    Helper Functions    ]]
  8. ----------------------------------
  9. local function DummyFunc() end--    Surprise for later
  10.  
  11. local GetNearestFlightPath; do--    name,distance=function()
  12.     local function GetRealCoordBounds()
  13.         local _,zx1,zy1,zx2,zy2=GetCurrentMapDungeonLevel();
  14.         zx1,zy1,zx2,zy2=zx1 or 0,zy1 or 0,zx2 or 0,zy2 or 0;
  15.         if zx1~=0 and zy1~=0 and zx2~=0 and zy2~=0 then return zx1,zy1,zx2,zy2; end--   Level-Specific Coords
  16.  
  17.         _,zx1,zy1,zx2,zy2=GetCurrentMapZone();
  18.         zx1,zy1,zx2,zy2=zx1 or 0,zy1 or 0,zx2 or 0,zy2 or 0;
  19.         if zx1~=0 and zy1~=0 and zx2~=0 and zy2~=0 then return zx1,zy1,zx2,zy2; end--   General Map Coords
  20.  
  21.         return nil,nil,nil,nil;--   No real coords
  22.     end
  23.  
  24.     local function GetRealCoords(x,y)
  25.         if not (x and y and x~=0 and y~=0) then return nil,nil; end--   Invalid coords
  26.  
  27.         local zx1,zy1,zx2,zy2=GetRealCoordBounds();
  28.         if not zx1 then return nil,nil; end--   No real coords
  29.  
  30.         return (zx2-zx1)*x+zx1,(zy2-zy1)*y+zy1;
  31.     end
  32.  
  33.     function GetNearestFlightPath()
  34. --      Disable event to save CPU
  35.         local framelist={GetFramesRegisteredForEvent("WORLD_MAP_UPDATE")};
  36.         for _,frame in ipairs(framelist) do frame:UnregisterEvent("WORLD_MAP_UPDATE"); end
  37.  
  38. --      Save MapID and select current zone (MapID is invalid if viewing a continent, store that too)
  39.         local mapid,continent=GetCurrentMapAreaID(),GetCurrentMapContinent();
  40.         SetMapToCurrentZone();
  41.  
  42.         local lowdist,lowname;
  43.         if GetCurrentMapContinent()==8 and GetCurrentMapZone()~=3 then--    Only work on outdoor Broken Isles zones (exclude Dalaran; Flight Whistle doesn't work there)
  44.             local py,px=UnitPosition("player");
  45.             for i=1,GetNumMapLandmarks() do
  46.                 local id,name,_,_,x,y=GetMapLandmarkInfo(i);
  47.                 x,y=GetRealCoords(x,y);
  48.  
  49.                 if id==5 then-- Flight paths are landmark ID 5
  50.                     local dist=(px-x)^2+(py-y)^2;
  51.                     if not lowdist or dist<lowdist then
  52.                         lowdist,lowname=dist,name;--    Capture our shortest distance
  53.                     end
  54.                 end
  55.             end
  56.             if lowdist then lowdist=lowdist^0.5; end--  Apply square root outside of loop to save CPU
  57.         end
  58.  
  59. --      Restore map and enable event
  60.         if mapid>=0 then SetMapByID(mapid); else SetMapZoom(continent); end
  61.         for _,frame in ipairs(framelist) do frame:RegisterEvent("WORLD_MAP_UPDATE"); end
  62.  
  63.         return lowname,lowdist;--   Most significant return is the name, distance is secondary
  64.     end
  65. end
  66.  
  67. local NearestFlightPoint; do--  Tooltip pulls live data, POIs will use cached data since messing with WORLD_MAP_UPDATE causes problems there
  68.     local function UpdateFlightPointData()
  69.         NearestFlightPoint=GetNearestFlightPath();
  70.         C_Timer.After(0.5,UpdateFlightPointData);
  71.     end
  72.     UpdateFlightPointData();
  73. end
  74.  
  75. --------------------------
  76. --[[    API and Hooks   ]]
  77. --------------------------
  78. local LastPOIState=false;
  79. local function FadePOIs(fade)
  80.     if fade==nil then
  81.         fade=LastPOIState;--    Try to reapply if we're doing an update run
  82.     else
  83.         if fade==LastPOIState then return; end--    Don't run this function again if we're setting the state to what's already applied
  84.         LastPOIState=fade;--    Update our upvalue
  85.     end
  86.  
  87.     do  local px,py=GetPlayerMapPosition("player");--   Simple map presence check
  88.         if not (px and py and px~=0 and py~=0) then fade=false; end--   Force restore if we're not on the map
  89.     end
  90.  
  91. --  Find our nearest flight path
  92.     local name=NearestFlightPoint;
  93.     if not name then fade=false; end--  Don't fade if we didn't find any flight paths
  94.  
  95. --  Apply fade to POIs
  96.     for i=1,math.min(GetNumMapLandmarks(),NUM_WORLDMAP_POIS) do--   Sanity check (don't run on POIs that haven't been created yet)
  97.         local poi=_G["WorldMapFramePOI"..i];
  98.         if poi.landmarkType==5 then--   Flight paths are landmark ID 5
  99.             poi:SetAlpha((poi.name~=name and fade) and FadeAlpha or 1);
  100.  
  101.             if poi.name==name and fade then
  102.                 WorldMapPing:SetPoint("CENTER",poi);--  Move WorldMapPing
  103.                 WorldMapPing.SetPoint=DummyFunc;--  Stop WorldMapButton_OnUpdate() from resetting our position
  104.                 WorldMapPing.Ping:Play();-- Play animation
  105.             end
  106.         else
  107.             poi:SetAlpha(1);--  Update in case map changed and we have new POIs
  108.         end
  109.     end
  110. end
  111.  
  112. --  Hook switching zone maps and WorldMapFrame animations
  113. local function UpdateFade() FadePOIs(nil); end
  114. hooksecurefunc("WorldMap_UpdateLandmarks",UpdateFade);
  115. WorldMapFrame.AnimAlphaIn:HookScript("OnFinished",UpdateFade);
  116. WorldMapFrame.AnimAlphaOut:HookScript("OnFinished",UpdateFade);
  117. WorldMapPing.Ping:HookScript("OnStop",function(self) WorldMapPing.SetPoint=nil; end);-- Restore normal behavior by removing our modification
  118.  
  119. --  Hook Flight Whistle tooltip
  120. GameTooltip:HookScript("OnTooltipSetItem",function(self,...)
  121.     local _,link=self:GetItem();
  122.     if link and link:find("|Hitem:141605[:|]") then
  123.         local name,dist=GetNearestFlightPath();
  124.         if name and dist then self:AddDoubleLine(name,BreakUpLargeNumbers(math.floor(dist)).." yds",0.5,0.5,0.5,0.5,0.5,0.5); end
  125.     end
  126. end);
  127.  
  128. --------------------------
  129. --[[    Event Handler   ]]
  130. --------------------------
  131. local EventFrame=CreateFrame("Frame");
  132. EventFrame:RegisterUnitEvent("UNIT_SPELLCAST_START","player");
  133. EventFrame:RegisterUnitEvent("UNIT_SPELLCAST_STOP","player");
  134. EventFrame:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTED","player");
  135. EventFrame:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED","player");
  136. EventFrame:SetScript("OnEvent",function(self,event,unit,_,_,_,spellid)
  137.     if spellid==227334 then--   SpellID of Flight Whistle
  138.         FadePOIs(event=="UNIT_SPELLCAST_START");--  Fade on start, restore on others
  139.     end
  140. end);

This was originally part of the code I posted previously. I just cut out the WorldMap stuff from the post until I could get it to stop freezing for 2 seconds every time you tried to use the Flight Whistle. The solution was to cache the closest flight point every so often instead of on demand for the WorldMap code.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 10-21-16 at 05:53 PM.
  Reply With Quote
10-23-16, 04:41 AM   #9
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Yeah that looks cool. I think you should release this as an addon, it could be useful for a lot of people.
  Reply With Quote
10-23-16, 06:26 PM   #10
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
I made an addon that marked the nearest flight point with a flashing icon back when legion launched, but it's not always the point that the whistle takes you to. I'm not sure if it's simply due to differences in elevation that an addon can't account for, or if they use a more complicated system that takes into account your current subzone.

It's particularly obvious in suramar city, where you can be taken to the flight point in the crimson thicket despite being "closer" to the one in meredil on the map.
  Reply With Quote
10-24-16, 06:08 AM   #11
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by semlar View Post
I made an addon that marked the nearest flight point with a flashing icon back when legion launched, but it's not always the point that the whistle takes you to. I'm not sure if it's simply due to differences in elevation that an addon can't account for, or if they use a more complicated system that takes into account your current subzone.

It's particularly obvious in suramar city, where you can be taken to the flight point in the crimson thicket despite being "closer" to the one in meredil on the map.
I'm not sure every time i tried it showed the proper flight point for me. I could be wrong if you are in a very high mountain or in the perimeter of the zone.
  Reply With Quote
10-24-16, 03:35 PM   #12
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,323
It would be helpful if they had an API that would tell us which flight points we discovered as the whistle won't take us to unknown ones.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » WorldMap POIs


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