Advertisement
Guest User

Untitled

a guest
Apr 5th, 2015
305
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.78 KB | None | 0 0
  1.  
  2. -------------------------------------------------------------------------------------------------------------------------------------------------
  3. -- GTAS_PlotIterators - Part of Really Advanced Setup Mod
  4. --
  5. -- A big thank you to whoward69 for writing this code.
  6. --
  7. -- GTAS_PlotAreaSpiralIterator has been changed by GeneralTso.
  8. -- The passed value "centre" has been replaced by "rMin". More comments available near the function itself.
  9. -------------------------------------------------------------------------------------------------------------------------------------------------
  10.  
  11. -- Plot iterator functions
  12. --   All functions create an iterator centered on pPlot starting in the specified sector and working in the given direction around the ring/area
  13. --   PlotRingIterator(pPlot, r, sector, anticlock) returns each plot around a border of radius r
  14. --   GTAS_PlotAreaSpiralIterator(pPlot, r, sector, anticlock, inwards, centre) returns each plot within an area of radius r in concentric rings
  15. --   PlotAreaSweepIterator(pPlot, r, sector, anticlock, inwards, centre) returns each plot within an area of radius r by radial
  16. --
  17. -- By converting the Map (x,y) co-ordinates to hex (x,y,z) co-ordinates we can simply walk the edges of the bounding hex
  18. -- To walk an edge we keep one of x, y or z invariant, iterate the others from 0 to r-1 and r-1 to 0  (r-1 otherwise we include each vertex twice)
  19. --
  20. -- By using Lua coroutines we can keep the walking code (fairly) simple
  21. --
  22. -- Use these functions as follows
  23. --
  24. --    for pEdgePlot in PlotRingIterator(pPlot, r, sector, anticlock) do
  25. --      print(pEdgePlot:GetX(), pEdgePlot:GetY())
  26. --    end
  27. --
  28. --    for pAreaPlot in GTAS_PlotAreaSpiralIterator(pPlot, r, sector, anticlock, inwards, centre) do
  29. --      print(pAreaPlot:GetX(), pAreaPlot:GetY())
  30. --    end
  31. --
  32. --    for pAreaPlot in PlotAreaSweepIterator(pPlot, r, sector, anticlock, inwards, centre) do
  33. --      print(pAreaPlot:GetX(), pAreaPlot:GetY())
  34. --    end
  35. --
  36.  
  37. SECTOR_NORTH = 1
  38. SECTOR_NORTHEAST = 2
  39. SECTOR_SOUTHEAST = 3
  40. SECTOR_SOUTH = 4
  41. SECTOR_SOUTHWEST = 5
  42. SECTOR_NORTHWEST = 6
  43.  
  44. DIRECTION_CLOCKWISE = false
  45. DIRECTION_ANTICLOCKWISE = true
  46.  
  47. DIRECTION_OUTWARDS = false
  48. DIRECTION_INWARDS = true
  49.  
  50. CENTRE_INCLUDE = true
  51. CENTRE_EXCLUDE = false
  52.  
  53. function PlotRingIterator(pPlot, r, sector, anticlock)
  54.   --print(string.format("PlotRingIterator((%i, %i), r=%i, s=%i, d=%s)", pPlot:GetX(), pPlot:GetY(), r, (sector or SECTOR_NORTH), (anticlock and "rev" or "fwd")))
  55.   -- The important thing to remember with hex-coordinates is that x+y+z = 0
  56.   -- so we never actually need to store z as we can always calculate it as -(x+y)
  57.   -- See http://keekerdc.com/2011/03/hexagon-grids-coordinate-systems-and-distance-calculations/
  58.  
  59.   if (pPlot ~= nil and r > 0) then
  60.     local hex = ToHexFromGrid({x=pPlot:GetX(), y=pPlot:GetY()})
  61.     local x, y = hex.x, hex.y
  62.  
  63.     -- Along the North edge of the hex (x-r, y+r, z) to (x, y+r, z-r)
  64.     local function north(x, y, r, i) return {x=x-r+i, y=y+r} end
  65.     -- Along the North-East edge (x, y+r, z-r) to (x+r, y, z-r)
  66.     local function northeast(x, y, r, i) return {x=x+i, y=y+r-i} end
  67.     -- Along the South-East edge (x+r, y, z-r) to (x+r, y-r, z)
  68.     local function southeast(x, y, r, i) return {x=x+r, y=y-i} end
  69.     -- Along the South edge (x+r, y-r, z) to (x, y-r, z+r)
  70.     local function south(x, y, r, i) return {x=x+r-i, y=y-r} end
  71.     -- Along the South-West edge (x, y-r, z+r) to (x-r, y, z+r)
  72.     local function southwest(x, y, r, i) return {x=x-i, y=y-r+i} end
  73.     -- Along the North-West edge (x-r, y, z+r) to (x-r, y+r, z)
  74.     local function northwest(x, y, r, i) return {x=x-r, y=y+i} end
  75.  
  76.     local side = {north, northeast, southeast, south, southwest, northwest}
  77.     if (sector) then
  78.       for i=(anticlock and 1 or 2), sector, 1 do
  79.         table.insert(side, table.remove(side, 1))
  80.       end
  81.     end
  82.  
  83.     -- This coroutine walks the edges of the hex centered on pPlot at radius r
  84.     local next = coroutine.create(function ()
  85.       if (anticlock) then
  86.         for s=6, 1, -1 do
  87.           for i=r, 1, -1 do
  88.             coroutine.yield(side[s](x, y, r, i))
  89.           end
  90.         end
  91.       else
  92.         for s=1, 6, 1 do
  93.           for i=0, r-1, 1 do
  94.             coroutine.yield(side[s](x, y, r, i))
  95.           end
  96.         end
  97.       end
  98.  
  99.       return nil
  100.     end)
  101.  
  102.     -- This function returns the next edge plot in the sequence, ignoring those that fall off the edges of the map
  103.     return function ()
  104.       local pEdgePlot = nil
  105.       local success, hex = coroutine.resume(next)
  106.       --if (hex ~= nil) then print(string.format("hex(%i, %i, %i)", hex.x, hex.y, -1 * (hex.x+hex.y))) else print("hex(nil)") end
  107.  
  108.       while (success and hex ~= nil and pEdgePlot == nil) do
  109.         pEdgePlot = Map.GetPlot(ToGridFromHex(hex.x, hex.y))
  110.         if (pEdgePlot == nil) then success, hex = coroutine.resume(next) end
  111.       end
  112.  
  113.       return success and pEdgePlot or nil
  114.     end
  115.   else
  116.     -- Iterators have to return a function, so return a function that returns nil
  117.     return function () return nil end
  118.   end
  119. end
  120.  
  121. -- Passed variable "centre" (boolean) removed and passed variable "rMin" added by GeneralTso.
  122. -- Passed variable "r" name was change to "rMax" for clarity.
  123. -- This new value is the minimum radius. Only plots from rMin to rMax are now returned.
  124. -- rMin = 0 works the same as centre = true, while rMin = 1 works the same as centre = false.
  125. function GTAS_PlotAreaSpiralIterator(pPlot, rMin, rMax, sector, anticlock, inwards)
  126.   -- print(string.format("GTAS_PlotAreaSpiralIterator((%i, %i), r=%i, s=%i, d=%s, w=%s, rMin=%i)", pPlot:GetX(), pPlot:GetY(), r, (sector or SECTOR_NORTH), (anticlock and "rev" or "fwd"), (inwards and "in" or "out"), rMin))
  127.   -- This coroutine walks each ring in sequence
  128.   local next = coroutine.create(function ()
  129.     if (rMin == 0 and not inwards) then
  130.       coroutine.yield(pPlot)
  131.     end
  132.  
  133.     if (inwards) then
  134.       for i=rMax, rMin, -1 do
  135.         for pEdgePlot in PlotRingIterator(pPlot, i, sector, anticlock) do
  136.           coroutine.yield(pEdgePlot)
  137.         end
  138.       end
  139.     else
  140.       for i=rMin, rMax, 1 do
  141.         for pEdgePlot in PlotRingIterator(pPlot, i, sector, anticlock) do
  142.           coroutine.yield(pEdgePlot)
  143.         end
  144.       end
  145.     end
  146.  
  147.     if (rMin == 0 and inwards) then
  148.       coroutine.yield(pPlot)
  149.     end
  150.  
  151.     return nil
  152.   end)
  153.  
  154.   -- This function returns the next plot in the sequence
  155.   return function ()
  156.     local success, pAreaPlot = coroutine.resume(next)
  157.     return success and pAreaPlot or nil
  158.   end
  159. end
  160.  
  161. function PlotAreaSpiralIterator(pPlot, r, sector, anticlock, inwards, centre)
  162.   --print(string.format("PlotAreaSpiralIterator((%i, %i), r=%i, s=%i, d=%s, w=%s, c=%s)", pPlot:GetX(), pPlot:GetY(), r, (sector or SECTOR_NORTH), (anticlock and "rev" or "fwd"), (inwards and "in" or "out"), (centre and "yes" or "no")))
  163.   -- This coroutine walks each ring in sequence
  164.   local next = coroutine.create(function ()
  165.     if (centre and not inwards) then
  166.       coroutine.yield(pPlot)
  167.     end
  168.  
  169.     if (inwards) then
  170.       for i=r, 1, -1 do
  171.         for pEdgePlot in PlotRingIterator(pPlot, i, sector, anticlock) do
  172.           coroutine.yield(pEdgePlot)
  173.         end
  174.       end
  175.     else
  176.       for i=1, r, 1 do
  177.         for pEdgePlot in PlotRingIterator(pPlot, i, sector, anticlock) do
  178.           coroutine.yield(pEdgePlot)
  179.         end
  180.       end
  181.     end
  182.  
  183.     if (centre and inwards) then
  184.       coroutine.yield(pPlot)
  185.     end
  186.  
  187.       return nil
  188.   end)
  189.  
  190.   -- This function returns the next plot in the sequence
  191.   return function ()
  192.     local success, pAreaPlot = coroutine.resume(next)
  193.     return success and pAreaPlot or nil
  194.   end
  195. end
  196.  
  197.  
  198. function PlotAreaSweepIterator(pPlot, r, sector, anticlock, inwards, centre)
  199.   print(string.format("PlotAreaSweepIterator((%i, %i), r=%i, s=%i, d=%s, w=%s, c=%s)", pPlot:GetX(), pPlot:GetY(), r, (sector or SECTOR_NORTH), (anticlock and "rev" or "fwd"), (inwards and "in" or "out"), (centre and "yes" or "no")))
  200.   -- This coroutine walks each radial in sequence
  201.   local next = coroutine.create(function ()
  202.     if (centre and not inwards) then
  203.       coroutine.yield(pPlot)
  204.     end
  205.  
  206.     local iterators = {}
  207.     for i=1, r, 1 do
  208.       iterators[i] = PlotRingIterator(pPlot, i, sector, anticlock)
  209.     end
  210.  
  211.     for s=1, 6, 1 do
  212.       -- In ring (n+1) there are (n+1)*6 or 6n + 6 plots,
  213.       -- so we need to call the (n+1)th iterator six more times than the nth, or once more per outer loop
  214.       -- eg for 3 rings we need a plot from ring 1, 2, 3, 2, 3, 3 repeated 6 times
  215.       if (inwards) then
  216.         for i=r, 1, -1 do
  217.           for j=r, i, -1 do
  218.             coroutine.yield(iterators[j]())
  219.           end
  220.         end
  221.       else
  222.         for i=1, r, 1 do
  223.           for j=i, r, 1 do
  224.             coroutine.yield(iterators[j]())
  225.           end
  226.         end
  227.       end
  228.     end
  229.  
  230.     if (centre and inwards) then
  231.       coroutine.yield(pPlot)
  232.     end
  233.  
  234.     return nil
  235.   end)
  236.  
  237.   -- This function returns the next plot in the sequence
  238.   return function ()
  239.     local success, pAreaPlot = coroutine.resume(next)
  240.     return success and pAreaPlot or nil
  241.   end
  242. end
  243.  
  244.  
  245. --
  246. -- Test functions
  247. --
  248.  
  249. highlights = {
  250.   ["RED"]     = {x=1.0, y=0.0, z=0.0, w=1.0},
  251.   ["GREEN"]  = {x=0.0, y=1.0, z=0.0, w=1.0},
  252.   ["BLUE"]    = {x=0.0, y=0.0, z=1.0, w=1.0},
  253.   ["CYAN"]    = {x=0.0, y=1.0, z=1.0, w=1.0},
  254.   ["YELLOW"]  = {x=1.0, y=1.0, z=0.0, w=1.0},
  255.   ["MAGENTA"] = {x=1.0, y=0.0, z=1.0, w=1.0},
  256.   ["BLACK"]   = {x=0.5, y=0.5, z=0.5, w=1.0}
  257. }
  258.  
  259. function TestPlotHighlight(pPlot, highlight)
  260.   -- print(pPlot:GetX(), pPlot:GetY())
  261.   if (highlight ~= nil) then
  262.     Events.SerialEventHexHighlight(ToHexFromGrid(Vector2(pPlot:GetX(), pPlot:GetY())), true, highlight)
  263.   end
  264. end
  265.  
  266. function TestPlotRingIterator(pPlot, r, sector, anticlock, highlight)
  267.   for pEdgePlot in PlotRingIterator(pPlot, r, sector, anticlock) do
  268.     TestPlotHighlight(pEdgePlot, highlight)
  269.   end
  270. end
  271.  
  272. function TestGTAS_PlotAreaSpiralIterator(pPlot, r, sector, anticlock, inwards, centre, highlight)
  273.   for pAreaPlot in GTAS_PlotAreaSpiralIterator(pPlot, r, sector, anticlock, inwards, centre) do
  274.     TestPlotHighlight(pAreaPlot, highlight)
  275.   end
  276. end
  277.  
  278. function TestPlotAreaSweepIterator(pPlot, r, sector, anticlock, inwards, centre, highlight)
  279.   for pAreaPlot in PlotAreaSweepIterator(pPlot, r, sector, anticlock, inwards, centre) do
  280.     TestPlotHighlight(pAreaPlot, highlight)
  281.   end
  282. end
  283.  
  284. -- TestPlotRingIterator(Players[0]:GetCapitalCity():Plot(), 4, SECTOR_NORTH, DIRECTION_CLOCKWISE, highlights.RED)
  285. -- TestGTAS_PlotAreaSpiralIterator(Players[0]:GetCapitalCity():Plot(), 3, SECTOR_SOUTH, DIRECTION_ANTICLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE)
  286. -- TestPlotAreaSweepIterator(Players[0]:GetCapitalCity():Plot(), 3, SECTOR_SOUTH, DIRECTION_ANTICLOCKWISE, DIRECTION_OUTWARDS, CENTRE_INCLUDE)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement