Advertisement
Guest User

[Dwarf Fortress] PatrikLundell's regionmanipulator.lua

a guest
Jun 30th, 2017
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 46.99 KB | None | 0 0
  1. --Manipulates the parameters of the region in focus pre embark. Use ? for help.
  2. --NOTE: Manipulations made are NOT permanent. They will be applied to the embark if the user embarks while
  3. --the region is still in focus, but they will be discarded as soon as the focus is shifted. They are also
  4. --lost for any subsequent embarks in the same region (but the previous embark will still retain the effects
  5. --of the changes in place when it was embarked upon). It is unknown what effects manipulations have on
  6. --Adventure Mode, but weird discontinuities are likely at the border between an abandoned/retired embark
  7. --generated while under manipulation influence and the region itself (which is back to its original state).
  8. --[====[
  9.  
  10. regionmanipulator
  11. ========
  12. ]====]
  13.  
  14. local gui = require 'gui'
  15. local dialog = require 'gui.dialogs'
  16. local widgets =require 'gui.widgets'
  17. local guiScript = require 'gui.script'
  18.  
  19. local Main_Page = {}
  20.  
  21. --================================================================
  22. --  The Grid widget defines an pen supporting X/Y character display grid supporting display of
  23. --  a grid larger than the frame allows through a panning viewport. The init function requires
  24. --  the specification of the width and height attributes that defines the grid dimensions.
  25. --  The grid coordinates are 0 based.
  26. --
  27. Grid = defclass (Grid, widgets.Widget)
  28. Grid.ATTRS =
  29.   {width = DEFAULT_NIL,
  30.    height = DEFAULT_NIL}
  31.  
  32. --================================================================
  33.  
  34. function Grid:init ()
  35.   if type (self.width) ~= 'number' or
  36.      type (self.height) ~= 'number' or
  37.      self.width < 0 or
  38.      self.height < 0 then
  39.     error ("Grid widgets have to have their width and height set permanently on initiation")
  40.     return
  41.   end
  42.  
  43.   self.grid = dfhack.penarray.new (self.width, self.height)
  44.  
  45.   self.viewport = {x1 = 0,
  46.                    x2 = self.frame.r - self.frame.l,
  47.                    y1 = 0,
  48.                    y2 = self.frame.b - self.frame.t}  
  49. end
  50.  
  51. --================================================================
  52. --  Pans the viewport in the X and Y dimensions the number of steps specified by the parameters.
  53. --  It will stop the panning at 0, however, and will not pan outside of the grid (a grid smaller)
  54. --  than the frame will still have non grid parts in the frame, of course).
  55. --
  56. function Grid:pan (x, y)
  57.   local x_size = self.viewport.x2 - self.viewport.x1 + 1
  58.   local y_size = self.viewport.y2 - self.viewport.y1 + 1
  59.  
  60.   self.viewport.x1 = self.viewport.x1 + x
  61.  
  62.   if self.viewport.x1 + x_size > self.width then
  63.     self.viewport.x1 = self.width - x_size
  64.   end
  65.  
  66.   if self.viewport.x1 < 0 then
  67.     self.viewport.x1 = 0
  68.   end
  69.  
  70.   self.viewport.x2 = self.viewport.x1 + x_size - 1
  71.  
  72.   self.viewport.y1 = self.viewport.y1 + y
  73.  
  74.   if self.viewport.y1 + y_size > self.height then
  75.     self.viewport.y1 = self.height - y_size
  76.   end
  77.  
  78.   if self.viewport.y1 < 0 then
  79.     self.viewport.y1 = 0
  80.   end
  81.  
  82.   self.viewport.y2 = self.viewport.y1 + y_size - 1
  83. end
  84.  
  85. --================================================================
  86. --  Assigns a value to the specified grid (not frame) coordinates. The 'pen'
  87. --  parameter has to be a DFHack 'pen' table or object.
  88. --
  89. function Grid:set (x, y, pen)
  90.   if x < 0 or x >= self.width then
  91.     error ("Grid:set error: x out of bounds " .. tostring (x) .. " vs 0 - " .. tostring (self.width - 1))
  92.     return
  93.    
  94.   elseif y < 0 or y >= self.height then
  95.     error ("Grid:set error: y out of bounds " .. tostring (y) .. " vs 0 - " .. tostring (self.height - 1))
  96.     return
  97.   end
  98.  
  99.   self.grid:set_tile (x, y, pen)  
  100. end
  101.  
  102. --================================================================
  103. --  Returns the data at position x, y in the grid.
  104. --
  105. function Grid:get (x, y)
  106.   if x < 0 or x >= self.width then
  107.     error ("Grid:set error: x out of bounds " .. tostring (x) .. " vs 0 - " .. tostring (self.width - 1))
  108.     return
  109.    
  110.   elseif y < 0 or y >= self.height then
  111.     error ("Grid:set error: y out of bounds " .. tostring (y) .. " vs 0 - " .. tostring (self.height - 1))
  112.     return
  113.   else
  114.     return self.grid:get_tile (x, y)
  115.   end
  116. end
  117.  
  118. --================================================================
  119. --  Renders the contents within the viewport into the frame.
  120. --
  121. function Grid:onRenderBody (dc)
  122.   self.grid:draw (self.frame.l,
  123.                   self.frame.t,
  124.                   self.viewport.x2 - self.viewport.x1 + 1,
  125.                   self.viewport.y2 - self.viewport.y1 + 1,
  126.                   self.viewport.x1,
  127.                   self.viewport.y1)
  128. end
  129.  
  130. --================================================================
  131. --  
  132. --  An EditField widget that shows whether the value has been modified but not commited.
  133. --  Only works properly if the setText operation is used rather than setting the text
  134. --  field directly. Isn't based on the EditField class because both its operations have
  135. --  to be overridden.
  136. --
  137. MarkEditField = defclass (MarkEditField, widgets.Widget)
  138.  
  139. MarkEditField.ATTRS =
  140.   {text = '',
  141.    text_pen = DEFAULT_NIL,
  142.    on_char = DEFAULT_NIL,
  143.    on_change = DEFAULT_NIL,
  144.    on_submit = DEFAULT_NIL,
  145.    modified_pen = DEFAULT_NIL,
  146.    modified = false}
  147.  
  148. --================================================================
  149.  
  150. function MarkEditField:setText (str)
  151.   self.text = str
  152.   self.modified = false
  153. end
  154.  
  155. --================================================================
  156.  
  157. function MarkEditField:onRenderBody (dc)
  158.   if self.modified then
  159.     dc:pen (self.modified_pen or COLOR_YELLOW):fill (0, 0, dc.width - 1, 0)
  160.   else
  161.     dc:pen (self.text_pen or COLOR_LIGHTCYAN):fill (0, 0, dc.width - 1, 0)
  162.   end
  163.    
  164.   local cursor = '_'
  165.   if not self.active or gui.blink_visible(300) then
  166.     cursor = ' '
  167.   end
  168.  
  169.   local txt = self.text .. cursor
  170.   if #txt > dc.width then
  171.     txt = string.char(27) .. string.sub (txt, #txt - dc.width + 2)
  172.   end
  173.    
  174.   dc:string (txt)
  175. end
  176.  
  177. --================================================================
  178.  
  179. function MarkEditField:onInput (keys)
  180.   if self.on_submit and keys.SELECT then
  181.     self.on_submit (self.text)
  182.     self.modified = false
  183.     return true
  184.        
  185.   elseif keys._STRING then
  186.     local old = self.text
  187.  
  188.     if keys._STRING == 0 then
  189.       self.text = string.sub (old, 1, #old - 1)
  190.            
  191.     else
  192.       local cv = string.char (keys._STRING)
  193.       if not self.on_char or self.on_char (cv, old) then
  194.         self.text = old .. cv
  195.       end
  196.     end
  197.    
  198.     if self.text ~= old then
  199.       self.modified = true
  200.     end
  201.    
  202.     if self.on_change and self.text ~= old then
  203.       self.on_change(self.text, old)
  204.     end
  205.    
  206.     return true
  207.   end
  208. end
  209.  
  210. --================================================================
  211. --================================================================
  212.  
  213. function regionmanipulator ()
  214.   if not dfhack.isWorldLoaded () then
  215.     dfhack.color (COLOR_RED)
  216.     dfhack.print("Error: This script requires a world to be loaded.")
  217.     dfhack.color(COLOR_RESET)
  218.     dfhack.println()
  219.     return
  220.   end
  221.  
  222.   if dfhack.isMapLoaded() then
  223.     dfhack.color (COLOR_RED)
  224.     dfhack.print("Error: This script requires a world to be loaded, but not a map.")
  225.     dfhack.color(COLOR_RESET)
  226.     dfhack.println()
  227.     return
  228.   end
  229.  
  230.   local map_width = df.global.world.world_data.world_width
  231.   local map_height = df.global.world.world_data.world_height
  232.   local x = 0
  233.   local y = 0
  234.   local max_x = 16
  235.   local max_y = 16
  236.   local region = df.global.world.world_data.region_details [0]
  237.   local Edit_Focus
  238.   local Focus = "Main"
  239.  
  240.   local Vertical_River_Image = {[-1] = "North",
  241.                                 [0] = "None",
  242.                                 [1] = "South"}
  243.                                  
  244.   local Horizontal_River_Image = {[-1] = "East",
  245.                                   [0] = "None",
  246.                                   [1] = "West"}
  247.  
  248.   local keybindings = {
  249.     next_edit = {key = "CHANGETAB",
  250.                  desc = "Go to next edit field"},
  251.     prev_edit = {key = "SEC_CHANGETAB",
  252.                  desc = "Go to previous edit field"},
  253.     elevation = {key = "CUSTOM_ALT_E",
  254.                  desc = "Change display to region elevation"},
  255.     biome = {key = "CUSTOM_ALT_B",
  256.              desc = "Change display to region biome"},
  257.     rivers = {key = "CUSTOM_ALT_R",
  258.               desc = "Change display to rivers"},
  259.     flatten = {key = "CUSTOM_ALT_F",
  260.                desc = "Flatten the region to the elevation of the current region tile"},
  261.     up = {key = "CURSOR_UP",
  262.           desc = "Shifts focus 1 step upwards"},
  263.     down = {key = "CURSOR_DOWN",
  264.             desc = "Shifts focus 1 step downwards"},
  265.     left = {key = "CURSOR_LEFT",
  266.             desc = "Shifts focus 1 step to the left"},
  267.     right = {key = "CURSOR_RIGHT",
  268.              desc = "Shift focus 1 step to the right"},
  269.     upleft = {key = "CURSOR_UPLEFT",
  270.               desc = "Shifts focus 1 step up to the left"},
  271.     upright = {key = "CURSOR_UPRIGHT",
  272.                desc = "Shifts focus 1 step up to the right"},
  273.     downleft = {key = "CURSOR_DOWNLEFT",
  274.                 desc = "Shifts focus 1 step down to the left"},
  275.     downright = {key = "CURSOR_DOWNRIGHT",
  276.                  desc = "Shifts focus 1 step down to the right"},
  277.     help = {key = "HELP",
  278.             desc= " Show this help/info"}}
  279.            
  280.   --============================================================
  281.  
  282.   function Range_Color (arg)
  283.     if arg < 100 then
  284.       return COLOR_WHITE
  285.     elseif arg < 110 then
  286.       return COLOR_LIGHTCYAN
  287.     elseif arg < 120 then
  288.       return COLOR_CYAN
  289.     elseif arg < 130 then
  290.       return COLOR_LIGHTBLUE
  291.     elseif arg < 140 then
  292.       return COLOR_BLUE
  293.     elseif arg < 150 then
  294.       return COLOR_LIGHTGREEN
  295.     elseif arg < 160 then
  296.       return COLOR_GREEN
  297.     elseif arg < 170 then
  298.       return COLOR_YELLOW
  299.     elseif arg < 180 then
  300.       return COLOR_LIGHTMAGENTA
  301.     elseif arg < 190 then
  302.       return COLOR_LIGHTRED
  303.     elseif arg < 200 then
  304.       return COLOR_RED
  305.     elseif arg < 210 then
  306.       return COLOR_GREY
  307.     else
  308.       return COLOR_DARKGREY
  309.     end
  310.   end
  311.  
  312.   --============================================================
  313.  
  314.   function River_Elevation_Image (x, y)
  315.     if region.rivers_vertical.active [x] [y] ~= 0 then
  316.       return tostring (region.rivers_vertical.elevation [x] [y])
  317.      
  318.     elseif region.rivers_horizontal.active [x] [y] ~= 0 then
  319.       return tostring (region.rivers_horizontal.elevation [x] [y])
  320.      
  321.     else
  322.       return ""
  323.     end
  324.   end
  325.  
  326.   --============================================================
  327.  
  328.   function Make_Elevation (x, y)
  329.     local end_x = #region.elevation - 1
  330.     local end_y = #region.elevation [0] - 1
  331.     local fg
  332.     local bg
  333.     local tile_color
  334.          
  335.     for k = 0, end_y do
  336.       for i = 0, end_x do
  337.         if i == x and k == y then
  338.           fg = COLOR_BLACK
  339.           bg = Range_Color (region.elevation [i] [k])
  340.           tile_color = true
  341.  
  342.         else
  343.           fg = Range_Color (region.elevation [i] [k])
  344.           bg = COLOR_BLACK
  345.           tile_color = false
  346.         end    
  347.          
  348.         Main_Page.elevationGrid:set (i, k, {ch = tostring (math.abs (region.elevation [i] [k] % 10)),
  349.                                             fg = fg,
  350.                                             bg = bg,
  351.                                             bold = false,
  352.                                             tile = nil,
  353.                                             tile_color = tile_color,
  354.                                             tile_fg = nil,
  355.                                             tile_bg = nil})                                        
  356.       end
  357.     end
  358.   end
  359.  
  360.   --============================================================
  361.  
  362.   function Make_Biome (x, y)
  363.     local end_x = #region.biome - 1
  364.     local end_y = #region.biome [0] - 1
  365.     local fg
  366.     local bg
  367.     local tile_color
  368.    
  369.     for k = 0, end_y do
  370.       for i = 0, end_x do
  371.         if i == x and k == y then
  372.           fg = COLOR_BLACK
  373.           bg = Range_Color (region.biome [i] [k] * 10 + 100)
  374.           tile_color = true
  375.          
  376.         else
  377.           fg = Range_Color (region.biome [i] [k] * 10 + 100)
  378.           bg = COLOR_BLACK
  379.           tile_color = false
  380.         end
  381.        
  382.         Main_Page.biomeGrid:set (i, k, {ch = tostring (region.biome [i] [k]),
  383.                                         fg = fg,
  384.                                         bg = bg,
  385.                                         bold = false,
  386.                                         tile = nil,
  387.                                         tile_color = tile_color,
  388.                                         tile_fg = nil,
  389.                                         tile_bg = nil})
  390.       end
  391.     end
  392.   end
  393.  
  394.   --============================================================
  395.  
  396.   function Fit (Item, Size)
  397.     if string.len (Item) > Size then
  398.       return string.rep ('#', Size)
  399.     else
  400.       return Item .. string.rep (' ', Size - string.len (Item))
  401.     end
  402.   end
  403.  
  404.   --===========================================================================
  405.  
  406.   function Fit_Right (Item, Size)
  407.     if string.len (Item) > Size then
  408.       return string.rep ('#', Size)
  409.     else
  410.       return string.rep (' ', Size - string.len (Item)) .. Item
  411.     end
  412.   end
  413.  
  414.   --===========================================================================
  415.  
  416.   function Make_Rivers (x, y)
  417.     local last = #region.rivers_vertical.elevation - 1
  418.     local ch
  419.     local fg
  420.     local bg
  421.     local tile_color
  422.          
  423.     for k = 0, last do
  424.       for i = 0, last do
  425.         tile_color = (i == x and k == y)
  426.        
  427.         if region.rivers_vertical.active [i] [k] ~= 0 then
  428.           ch = tostring (region.rivers_vertical.elevation [i] [k] % 10)
  429.          
  430.           if i == x and k == y then
  431.             fg = COLOR_BLACK
  432.             bg = Range_Color (region.rivers_vertical.elevation [i] [k])
  433.                            
  434.           else
  435.             fg = Range_Color (region.rivers_vertical.elevation [i] [k])
  436.             bg = COLOR_BLACK
  437.           end  
  438.          
  439.         elseif region.rivers_horizontal.active [i] [k] ~= 0 then
  440.           ch = tostring (region.rivers_horizontal.elevation [i] [k] % 10)
  441.          
  442.           if i == x and k == y then
  443.             fg = COLOR_BLACK
  444.             bg = Range_Color (region.rivers_horizontal.elevation [i] [k])
  445.            
  446.           else
  447.             fg = Range_Color (region.rivers_horizontal.elevation [i] [k])
  448.             bg = COLOR_BLACK
  449.           end  
  450.          
  451.         else
  452.           if i == x and k == y then
  453.             ch = 'X'
  454.             fg = COLOR_DARKGREY
  455.             bg = COLOR_BLACK
  456.            
  457.           else
  458.             ch = '.'
  459.             fg = COLOR_BLACK
  460.             bg = COLOR_DARKGREY
  461.           end
  462.         end
  463.        
  464.         Main_Page.riversGrid:set (i, k, {ch = ch,
  465.                                          fg = fg,
  466.                                          bg = bg,
  467.                                          bold = false,
  468.                                          tile = nil,
  469.                                          tile_color = tile_color,
  470.                                          tile_fg = nil,
  471.                                          tile_bg = nil})
  472.       end
  473.     end
  474.   end
  475.  
  476.   --============================================================
  477.  
  478.    function Set_Edit_Focus (index, active)
  479.       Main_Page.Edit_List [index] [1].active = active
  480.       for i = 2, #Main_Page.Edit_List [index] do
  481.         Main_Page.Edit_List [index] [i].visible = active
  482.       end
  483.    end
  484.    
  485.   --============================================================
  486.  
  487.   function Set_Visibility (item, visible)
  488.     for i, object in ipairs (Main_Page.Visibility_List [item]) do
  489.       object.visible = visible
  490.     end
  491.   end
  492.  
  493.   --============================================================
  494.  
  495.   function Bool_Image (b)
  496.     if b then
  497.       return 'Y'
  498.     else
  499.       return 'N'
  500.     end
  501.   end
  502.  
  503.   --==============================================================
  504.  
  505.   function Update (x, y, pages)  
  506.     Make_Elevation (x, y)
  507.     Make_Biome (x, y)
  508.     Make_Rivers (x, y)
  509.    
  510.     Main_Page.Heading_Label_X:setText (Fit_Right (tostring (x), 2))
  511.     Main_Page.Heading_Label_Y:setText (Fit_Right (tostring (y), 2))
  512.    
  513.     Main_Page.Region_Elevation_Edit:setText (Fit_Right (region.elevation [x] [y], 4))
  514.                                                      
  515.     Main_Page.Region_Biome_Edit:setText (Fit_Right (region.biome [x] [y], 1))
  516.  
  517.     Main_Page.River_Elevation_Edit:setText (Fit_Right (River_Elevation_Image (x, y), 4))
  518.     Set_Visibility ("River_Elevation", River_Elevation_Image (x, y) ~= "")
  519.     if Main_Page.Edit_Focus == 3 and not Main_Page.Edit_List [3] [1].visible then
  520.       Set_Edit_Focus (3, false)
  521.       Set_Edit_Focus (1, true)
  522.       Main_Page.Edit_Focus = 1
  523.     end
  524.    
  525.     Main_Page.Vertical_Edit:setText (Vertical_River_Image [region.rivers_vertical.active [x] [y]]) 
  526.  
  527.     Main_Page.X_Min_Edit:setText (Fit_Right (region.rivers_vertical.x_min [x] [y], 2))
  528.     Main_Page.X_Max_Edit:setText (Fit_Right (region.rivers_vertical.x_max [x] [y], 2))
  529.    
  530.     Set_Visibility ("Vertical", region.rivers_vertical.active [x] [y] ~= 0)
  531.     if region.rivers_vertical.active [x] [y] == 0 then
  532.       if Main_Page.Edit_Focus == 5 then
  533.         Set_Edit_Focus (5, false)
  534.         Set_Edit_Focus (1, true)
  535.         Main_Page.Edit_Focus = 1
  536.       end
  537.    
  538.       if Main_Page.Edit_Focus == 6 then
  539.         Set_Edit_Focus (6, false)
  540.         Set_Edit_Focus (1, true)
  541.         Main_Page.Edit_Focus = 1
  542.       end
  543.     end
  544.  
  545.     Main_Page.Horizontal_Edit:setText (Horizontal_River_Image [region.rivers_horizontal.active [x] [y]])
  546.                          
  547.     Main_Page.Y_Min_Edit:setText (Fit_Right (region.rivers_horizontal.y_min [x] [y], 2))
  548.     Main_Page.Y_Max_Edit:setText (Fit_Right (region.rivers_horizontal.y_max [x] [y], 2))
  549.    
  550.     Set_Visibility ("Horizontal", region.rivers_horizontal.active [x] [y] ~= 0)
  551.     if region.rivers_horizontal.active [x] [y] == 0 then
  552.       if Main_Page.Edit_Focus == 8 then
  553.         Set_Edit_Focus (8, false)
  554.         Set_Edit_Focus (1, true)
  555.         Main_Page.Edit_Focus = 1
  556.       end
  557.    
  558.       if Main_Page.Edit_Focus == 9 then
  559.         Set_Edit_Focus (9, false)
  560.         Set_Edit_Focus (1, true)
  561.         Main_Page.Edit_Focus = 1
  562.       end
  563.     end
  564.    
  565.     Main_Page.Is_Brook_Edit:setText (Bool_Image (df.global.world.world_data.region_map[region.pos.x]:_displace(region.pos.y).flags.is_brook))
  566.   end
  567.  
  568.   --============================================================
  569.  
  570.   RegionManipulatorUi = defclass (RegionManipulatorUi, gui.FramedScreen)
  571.   RegionManipulatorUi.ATTRS = {
  572.     frame_style = gui.GREY_LINE_FRAME,
  573.     frame_title = "Region Manipulator",
  574.   }
  575.  
  576.   --============================================================
  577.  
  578.   function RegionManipulatorUi:onHelp ()
  579.     self.subviews.pages:setSelected (2)
  580.     Focus = "Help"
  581.   end
  582.  
  583.   --============================================================
  584.  
  585.   function Disclaimer ()
  586.     local helptext = {{text = "Help/Info"}, NEWLINE, NEWLINE}
  587.      
  588.     for i, v in pairs (keybindings) do
  589.       table.insert (helptext, {text = v.desc, key = v.key, key_sep = ': '})
  590.       table.insert (helptext, NEWLINE)
  591.     end
  592.  
  593.     table.insert (helptext, NEWLINE)
  594.     local dsc =
  595.       {"The Region Manipulator is used pre embark to manipulate the region where the embark", NEWLINE,
  596.        "is intended to be performed. Due to the way DF works, any manipulation performed on", NEWLINE,
  597.        "the region is lost/discarded once DF's focus is changed to another region and", NEWLINE,
  598.        "is lost when returned. Similarly, Embarking anew in the same region as a previous", NEWLINE,
  599.        "fortress will have the region manipulations performed prior to the previous embark", NEWLINE,
  600.        "reversed on the region level, but their effects are 'frozen' in the fortress itself.", NEWLINE,
  601.        "However, manipulation and manipulation reversal can probably cause interesting effects", NEWLINE,
  602.        "if an adventurer was to visit such a fortress.", NEWLINE,
  603.        "Manipulations are effected immediately in DF, but the 'erase' function inherent in DF", NEWLINE,
  604.        "can be used to remove them (just swich the focus to a different region and back)", NEWLINE,
  605.        "The Region Manipulator allows you to change region level elevations, biomes, and rivers.", NEWLINE,
  606.        "The UI provides edit fields that can be traversed between using <TAB> and shift-<TAB>,", NEWLINE,
  607.        "where you change the value end press enter to commit a value. Changing to a different", NEWLINE,
  608.        "field will cause uncommited changes to be discarded. Some River fields are dependent", NEWLINE,
  609.        "upon the higher level Vertical/Horizontal field being set to a river course and will", NEWLINE,
  610.        "not be displayed until the higher level field makes them relevant. Apart from the", NEWLINE,
  611.        "fields, the UI also contains 'graphic' grid over the region which starts showing the", NEWLINE,
  612.        "Elevation. ALT-b changes that to a reference to the Biome of the region tile, while", NEWLINE,
  613.        "ALT-r changes it to display river elevation information, and ALT-e changes back to the", NEWLINE,
  614.        "region Elevation information. Movement on this grid is performed using the numpad keys.", NEWLINE,
  615.        "In addition to this, there is the ALT-f Flatten Embark command that changes the elevation", NEWLINE,
  616.        "of all tiles to take on the elevation of the current tile. Note that this does NOT change", NEWLINE,
  617.        "river elevations...", NEWLINE,
  618.        "The 'Is Brook' field changes whether you'll embark at a brook or a stream. Note that this", NEWLINE,
  619.        "field is persistent, as it is part of the world tile info, not the generated region data.", NEWLINE,
  620.        "Manipulating rivers is ... messy, but can give rather spectacular results. The River", NEWLINE,
  621.        "Elevation specifies the level at which the water flows, and DF will cut a sheer gorge", NEWLINE,
  622.        "down to that level if below the Region Elevation, or make an 'aqueduct' if above it.", NEWLINE,
  623.        "Waterfalls can be created by making the down river River Elevation lower than the upriver", NEWLINE,
  624.        "one, while the reverse is ignored by DF (water won't jump up).", NEWLINE,
  625.        "The messy part is making and changing river courses, and the author hasn't quite figured", NEWLINE,
  626.        "out what the rules are: you need to experiment. However, it was possible to create a 3*3", NEWLINE,
  627.        "embark where the center tile was surrounded by a bifurcating river that rejoined at the", NEWLINE,
  628.        "other side, creating a natural moat with a waterfall one each side. The embark team was", NEWLINE,
  629.        "spawned at the bottom of the gorge, however, so it was fortunate it was a brook...", NEWLINE,
  630.        "Elevations are color coded. The color ranges are:", NEWLINE,
  631.        {text = "WHITE        < 100, with the actual decile lost.", pen = dfhack.pen.parse {fg = COLOR_WHITE, bg = 0}}, NEWLINE,
  632.        {text = "LIGHT CYAN     100 - 109", pen = dfhack.pen.parse {fg = COLOR_LIGHTCYAN, bg = 0}}, NEWLINE,
  633.        {text = "CYAN           110 - 119", pen = dfhack.pen.parse {fg = COLOR_CYAN, bg = 0}}, NEWLINE,
  634.        {text = "LIGHT BLUE     120 - 129", pen = dfhack.pen.parse {fg = COLOR_LIGHTBLUE, bg = 0}}, NEWLINE,
  635.        {text = "BLUE           130 - 139", pen = dfhack.pen.parse {fg = COLOR_BLUE, bg = 0}}, NEWLINE,
  636.        {text = "LIGHT GREEN    140 - 149", pen = dfhack.pen.parse {fg = COLOR_LIGHTGREEN, bg = 0}}, NEWLINE,
  637.        {text = "GREEN          150 - 159", pen = dfhack.pen.parse {fg = COLOR_GREEN, bg = 0}}, NEWLINE,
  638.        {text = "YELLOW         160 - 169", pen = dfhack.pen.parse {fg = COLOR_YELLOW, bg = 0}}, NEWLINE,
  639.        {text = "LIGHT MAGENTA  170 - 179", pen = dfhack.pen.parse {fg = COLOR_LIGHTMAGENTA, bg = 0}}, NEWLINE,
  640.        {text = "LIGHT RED      180 - 189", pen = dfhack.pen.parse {fg = COLOR_LIGHTRED, bg = 0}}, NEWLINE,
  641.        {text = "RED            190 - 199", pen = dfhack.pen.parse {fg = COLOR_RED, bg = 0}}, NEWLINE,
  642.        {text = "GREY           200 - 219", pen = dfhack.pen.parse {fg = COLOR_GREY, bg = 0}}, NEWLINE,
  643.        {text = "DARK GREY    > 219, with the actual decile lost.", pen = dfhack.pen.parse {fg = COLOR_DARKGREY, bg = 0}}, NEWLINE, NEWLINE,
  644.        "Version 0.5, 2017-06-23", NEWLINE,
  645.        "Caveats: As indicated above, region manipulation has the potential to mess up adventure", NEWLINE,
  646.        "mode seriously. Similarly, changing things in silly ways can result in any kind of", NEWLINE,
  647.        "reaction from DF, so don't be surprised if DF crashes (no crashes have been noted so far)", NEWLINE,
  648.        "or parts of the caverns caves in on embark because you've cut away the walls that should", NEWLINE,
  649.        "have supported them.", NEWLINE
  650.        }
  651.  
  652.     for i, v in pairs (dsc) do
  653.       table.insert (helptext, v)
  654.     end
  655.    
  656.     return helptext
  657.   end
  658.  
  659.   --============================================================
  660.  
  661.   function RegionManipulatorUi:init ()
  662.     self.stack = {}
  663.     self.item_count = 0
  664.     self.keys = {}
  665.    
  666.     Main_Page.Edit_List = {}
  667.     Main_Page.Visibility_List =  {}
  668.     Main_Page.Edit_Focus = 1
  669.    
  670.     Main_Page.Heading_Label =
  671.       widgets.Label {text = {{text = "Help/Info",
  672.                                       key = keybindings.help.key,
  673.                                       key_sep = '()'},
  674.                              " X =   , Y =   ", NEWLINE,
  675.                              "Region Elevation:", NEWLINE,
  676.                              "Region Biome:", NEWLINE,
  677.                              NEWLINE,
  678.                              "Vertical:       Horizontal:", NEWLINE,
  679.                              NEWLINE,
  680.                              NEWLINE,
  681.                              "Is_Brook:"},
  682.                      frame = {l = 1, t = 1, y_align = 0}}
  683.                      
  684.     Main_Page.Heading_Label_X =
  685.       widgets.Label {text = Fit_Right (tostring (x), 2),
  686.                      frame = {l = 19, r = 20, t = 1, yalign = 0}}
  687.                                          
  688.     Main_Page.Heading_Label_Y =
  689.       widgets.Label {text = Fit_Right (tostring (y), 2),
  690.                      frame = {l = 27,
  691.                               r = 28,
  692.                               t = 1,
  693.                               yalign = 0}}
  694.                                          
  695.     Main_Page.Heading_Label_Variable =
  696.       widgets.Label {text = " Region Elevation",
  697.                      frame = {l = 30, t = 1, yalign = 0}}
  698.  
  699.     Main_Page.Region_Elevation_Edit =
  700.       MarkEditField {text = Fit_Right (region.elevation [x] [y], 4),
  701.                      frame = {l = 19,
  702.                               r = 22,
  703.                               t = 2,
  704.                               yalign = 0},
  705.                      active = true,
  706.                      on_submit = self:callback ("updateElevation")}
  707.                      
  708.     Main_Page.Elevation_Edit_Help_Header =
  709.       widgets.Label {text = "Elevation value key",
  710.                      frame = {l = 19, t = 10, yalign = 0},
  711.                      text_pen = COLOR_YELLOW,
  712.                      visible = true}
  713.        
  714.     Main_Page.Elevation_Edit_Help =
  715.       widgets.Label {text = "-999 -   0 is deep underground,\n" ..
  716.                             "           capped to the SMR.\n" ..
  717.                             "   1 -   0 is ocean level.\n" ..
  718.                             " 100 - 149 is normal terrain.\n" ..
  719.                             " 150 - 250 is mountain.",
  720.                      frame = {l = 19, t = 11, yalign = 0},
  721.                      visible = true}
  722.  
  723.     table.insert (Main_Page.Edit_List, {Main_Page.Region_Elevation_Edit,
  724.                                         Main_Page.Elevation_Edit_Help_Header,
  725.                                         Main_Page.Elevation_Edit_Help})
  726.    
  727.     Main_Page.Region_Biome_Edit =
  728.       MarkEditField {text = Fit_Right (region.biome [x] [y], 1),
  729.                      frame = {l = 22,
  730.                               r = 22,
  731.                               t = 3,
  732.                               yalign = 0},
  733.                      active = false,
  734.                      on_submit = self:callback ("updateBiome")}
  735.  
  736.     Main_Page.Biome_Edit_Help =
  737.       widgets.Label {text = {{text = "Take biome from neighbor world tile",
  738.                               pen = COLOR_YELLOW}, NEWLINE,
  739.                              "7: NW 8: N   9: NE", NEWLINE,
  740.                              "4: E  5: Own 6: E", NEWLINE,
  741.                              "1: SW 2: S   3: SE"},
  742.                      frame = {l = 19, t = 10, yalign = 0},                   
  743.                      visible = false}
  744.          
  745.     table.insert (Main_Page.Edit_List, {Main_Page.Region_Biome_Edit,
  746.                                         Main_Page.Biome_Edit_Help})
  747.    
  748.     local River_Elevation_Label_Text = "River Elevation: "
  749.  
  750.     Main_Page.River_Elevation_Label =
  751.       widgets.Label {text = River_Elevation_Label_Text,
  752.                      frame = {l = 1, t = 4, yalign = 0},
  753.                      visible = River_Elevation_Image (x, y) ~= ""}
  754.                      
  755.     Main_Page.River_Elevation_Edit =
  756.       MarkEditField {text = Fit_Right (River_Elevation_Image (x, y), 4),
  757.                      frame = {l = River_Elevation_Label_Text:len () + 1,
  758.                               r = River_Elevation_Label_Text:len () + 4,
  759.                               t = 4,
  760.                               yalign = 0},
  761.                      active = false,
  762.                      visible = River_Elevation_Image (x, y) ~= "",
  763.                      on_submit = self:callback ("updateRiversElevation")}
  764.                        
  765.     Main_Page.River_Elevation_Edit_Help_Header =
  766.       widgets.Label {text = "River Elevation value key",
  767.                      frame = {l = 19, t = 10, yalign = 0},
  768.                      text_pen = COLOR_YELLOW,
  769.                      visible = false}
  770.            
  771.     table.insert (Main_Page.Edit_List, {Main_Page.River_Elevation_Edit,
  772.                                         Main_Page.River_Elevation_Edit_Help_Header,
  773.                                         Main_Page.Elevation_Edit_Help})
  774.                                        
  775.     Main_Page.Visibility_List ["River_Elevation"] = {Main_Page.River_Elevation_Label,
  776.                                                      Main_Page.River_Elevation_Edit}
  777.                                                    
  778.     Main_Page.Vertical_Edit =
  779.       MarkEditField {text = Vertical_River_Image [region.rivers_vertical.active [x] [y]],
  780.                      frame = {l = 11, r = 15, t = 5, yalign = 0},
  781.                      active = false,
  782.                      on_submit = self:callback ("updateRiversVerticalActive")}
  783.                          
  784.     Main_Page.Vertical_Edit_Help =
  785.       widgets.Label {text = {{text = "Vertical River Course",
  786.                               pen = COLOR_YELLOW}, NEWLINE,
  787.                              "None", NEWLINE,
  788.                              "South", NEWLINE,
  789.                              "North"},
  790.                      frame = {l = 19, t = 10, yalign = 0},
  791.                      visible = false}
  792.                          
  793.     table.insert (Main_Page.Edit_List, {Main_Page.Vertical_Edit,
  794.                                         Main_Page.Vertical_Edit_Help})
  795.    
  796.     Main_Page.X_Label =
  797.       widgets.Label {text = "x min:\nX Max:",
  798.                      frame = {l = 1, t = 6, yalign = 0},
  799.                      visible = region.rivers_vertical.active [x] [y] ~= 0}
  800.                      
  801.     Main_Page.X_Min_Edit =
  802.       MarkEditField {text = Fit_Right (region.rivers_vertical.x_min [x] [y], 2),
  803.                      frame = {l = 8, r = 9, t = 6, yalign = 0},
  804.                      active = false,
  805.                      visible = region.rivers_vertical.active [x] [y] ~= 0,
  806.                      on_submit = self:callback ("updateRiversVerticalXMin")}
  807.    
  808.     Main_Page.X_Min_Help_Header =
  809.       widgets.Label {text = "Vertical River x min",
  810.                      frame = {l = 19, t = 10, yalign = 0},
  811.                      text_pen = COLOR_YELLOW,
  812.                      visible = false}
  813.      
  814.     Main_Page.X_Y_Help =
  815.       widgets.Label {text = "0 - 47 in 2 m tiles",
  816.                      frame = {l = 19, t = 11, yalign = 0},
  817.                      visible = false}
  818.                      
  819.     table.insert (Main_Page.Edit_List, {Main_Page.X_Min_Edit,
  820.                                         Main_Page.X_Min_Help_Header,
  821.                                         Main_Page.X_Y_Help})
  822.    
  823.     Main_Page.X_Max_Edit =
  824.       MarkEditField {text = Fit_Right (region.rivers_vertical.x_max [x] [y], 2),
  825.                      frame = {l = 8, r = 9, t = 7, yalign = 0},
  826.                      active = false,
  827.                      visible = region.rivers_vertical.active [x] [y] ~= 0,
  828.                      on_submit = self:callback ("updateRiversVerticalXMax")}
  829.      
  830.     Main_Page.X_Max_Help_Header =
  831.       widgets.Label {text = "Vertical River X Max",
  832.                      frame = {l = 19, t = 10, yalign = 0},
  833.                      text_pen = COLOR_YELLOW,
  834.                      visible = false}
  835.      
  836.     table.insert (Main_Page.Edit_List, {Main_Page.X_Max_Edit,
  837.                                         Main_Page.X_Max_Help_Header,
  838.                                         Main_Page.X_Y_Help})
  839.    
  840.     Main_Page.Visibility_List ["Vertical"] = {Main_Page.X_Label,
  841.                                               Main_Page.X_Min_Edit,
  842.                                               Main_Page.X_Max_Edit}
  843.     Main_Page.Horizontal_Edit =
  844.       MarkEditField {text = Horizontal_River_Image [region.rivers_horizontal.active [x] [y]],
  845.                      frame = {l = 29, r = 33, t = 5, yalign = 0},
  846.                      active = false,
  847.                      on_submit = self:callback ("updateRiversHorizontalActive")}
  848.                          
  849.     Main_Page.Horizontal_Edit_Help =
  850.       widgets.Label {text = {{text = "Horizontal River Course",
  851.                               pen = COLOR_YELLOW}, NEWLINE,
  852.                              "None", NEWLINE,
  853.                              "East", NEWLINE,
  854.                              "West"},
  855.                      frame = {l = 19, t = 10, yalign = 0},
  856.                      visible = false}
  857.                      
  858.     table.insert (Main_Page.Edit_List, {Main_Page.Horizontal_Edit,
  859.                                         Main_Page.Horizontal_Edit_Help})
  860.    
  861.     Main_Page.Y_Label =
  862.       widgets.Label {text = "y min:\nY Max:",
  863.                      frame = {l = 17, t = 6, yalign = 0},
  864.                      visible = region.rivers_horizontal.active [x] [y] ~= 0}
  865.                      
  866.     Main_Page.Y_Min_Edit =
  867.       MarkEditField {text = Fit_Right (region.rivers_horizontal.y_min [x] [y], 2),
  868.                      frame = {l = 24, t = 6, yalign = 0},
  869.                      active = false,
  870.                      visible = region.rivers_horizontal.active [x] [y] ~= 0,
  871.                      on_submit = self:callback ("updateRiversHorizontalYMin")}
  872.  
  873.     Main_Page.Y_Min_Help_Header =
  874.       widgets.Label {text = "Horizontal River y min",
  875.                      frame = {l = 19, t = 10, yalign = 0},
  876.                      text_pen = COLOR_YELLOW,
  877.                      visible = false}
  878.      
  879.     table.insert (Main_Page.Edit_List, {Main_Page.Y_Min_Edit,
  880.                                         Main_Page.Y_Min_Help_Header,
  881.                                         Main_Page.X_Y_Help})
  882.                          
  883.     Main_Page.Y_Max_Edit =
  884.       MarkEditField {text = Fit_Right (region.rivers_horizontal.y_max [x] [y], 2),
  885.                      frame = {l = 24, t = 7, yalign = 0},
  886.                      active = false,
  887.                      visible = region.rivers_horizontal.active [x] [y] ~= 0,
  888.                      on_submit = self:callback ("updateRiversHorizontalYMax")}
  889.                          
  890.     Main_Page.Y_Max_Help_Header =
  891.       widgets.Label {text = "Horizontal River Y Max",
  892.                      frame = {l = 19, t = 10, yalign = 0},
  893.                      text_pen = COLOR_YELLOW,
  894.                      visible = false}
  895.      
  896.     table.insert (Main_Page.Edit_List, {Main_Page.Y_Max_Edit,
  897.                                         Main_Page.Y_Max_Help_Header,
  898.                                         Main_Page.X_Y_Help})
  899.    
  900.     Main_Page.Visibility_List ["Horizontal"] = {Main_Page.Y_Label,
  901.                                                 Main_Page.Y_Min_Edit,
  902.                                                 Main_Page.Y_Max_Edit}
  903.    
  904.     Main_Page.Is_Brook_Edit =
  905.       MarkEditField {text = Bool_Image (df.global.world.world_data.region_map[region.pos.x]:_displace(region.pos.y).flags.is_brook),
  906.                      frame = {l = 22, r = 22, t = 8, yalign = 0},
  907.                      active = false,
  908.                      visible = true,
  909.                      on_submit = self:callback ("updateBrook")}
  910.                      
  911.     Main_Page.Is_Brook_Edit_Help =
  912.       widgets.Label {text = {{text = "Is it a brook or a stream?",
  913.                               pen = COLOR_YELLOW}, NEWLINE,
  914.                              "Y", NEWLINE,
  915.                              "N", NEWLINE},
  916.                      frame = {l = 19, t = 10, yalign = 0},
  917.                      visible = false}
  918.      
  919.     table.insert (Main_Page.Edit_List, {Main_Page.Is_Brook_Edit,
  920.                                         Main_Page.Is_Brook_Edit_Help})
  921.      
  922.     Main_Page.elevationGrid = Grid {frame = {l = 1, t = 11, r = 17, b = 27},
  923.                                     width = 17,
  924.                                     height = 17,
  925.                                     visible = true}
  926.    
  927.     Main_Page.biomeGrid = Grid {frame = {l = 1, t = 11, r = 17, b = 27},
  928.                                 width = 17,
  929.                                 height = 17,
  930.                                 visible = false}
  931.    
  932.     Main_Page.riversGrid = Grid {frame = {l = 1, t = 11, r = 16, b = 26},
  933.                                  width = 16,
  934.                                  height = 16,
  935.                                  visible = false}
  936.  
  937.     Make_Elevation (x, y)
  938.     Make_Biome (x, y)
  939.     Make_Rivers (x, y)
  940.    
  941.     helpPage = widgets.Panel {
  942.         subviews = {widgets.Label {text = Disclaimer (),
  943.                     frame = {l = 1, t = 1, yalign = 0}}}}
  944.                    
  945.     local mainPage = widgets.Panel {
  946.       subviews = {Main_Page.Heading_Label,
  947.                   Main_Page.Heading_Label_X,
  948.                   Main_Page.Heading_Label_Y,
  949.                   Main_Page.Heading_Label_Variable,
  950.                   Main_Page.Region_Elevation_Edit,
  951.                   Main_Page.Elevation_Edit_Help_Header,
  952.                   Main_Page.Elevation_Edit_Help,
  953.                   Main_Page.Region_Biome_Edit,
  954.                   Main_Page.Biome_Edit_Help,
  955.                   Main_Page.River_Elevation_Label,
  956.                   Main_Page.River_Elevation_Edit,
  957.                   Main_Page.River_Elevation_Edit_Help_Header,
  958.                   Main_Page.Vertical_Edit,
  959.                   Main_Page.Vertical_Edit_Help,
  960.                   Main_Page.X_Label,
  961.                   Main_Page.X_Min_Edit,
  962.                   Main_Page.X_Min_Help_Header,
  963.                   Main_Page.X_Y_Help,
  964.                   Main_Page.X_Max_Edit,
  965.                   Main_Page.X_Max_Help_Header,
  966.                   Main_Page.Horizontal_Edit,
  967.                   Main_Page.Horizontal_Edit_Help,
  968.                   Main_Page.Y_Label,
  969.                   Main_Page.Y_Min_Edit,
  970.                   Main_Page.Y_Min_Help_Header,
  971.                   Main_Page.Y_Max_Edit,
  972.                   Main_Page.Y_Max_Help_Header,
  973.                   Main_Page.Is_Brook_Edit,
  974.                   Main_Page.Is_Brook_Edit_Help,
  975.                   Main_Page.elevationGrid,
  976.                   Main_Page.biomeGrid,
  977.                   Main_Page.riversGrid}}
  978.    
  979.     local pages = widgets.Pages
  980.       {subviews = {mainPage,
  981.                    helpPage},view_id = "pages",
  982.                    }
  983.  
  984.     pages:setSelected (1)
  985.     Focus = "Main"
  986.      
  987.     self:addviews {pages}
  988.   end
  989.  
  990.   --============================================================
  991.  
  992.   function RegionManipulatorUi:updateElevation (value)
  993.     if not tonumber (value) or
  994.        tonumber (value) < -999 or
  995.        tonumber (value) > 250 then
  996.       dialog.showMessage ("Error!", "The Elevation legal range is -999 - 250", COLOR_RED)
  997.     else
  998.       region.elevation [x] [y] = tonumber (value)
  999.     end
  1000.    
  1001.     Update (x, y, self.subviews.pages)   
  1002.   end
  1003.  
  1004.   --==============================================================
  1005.  
  1006.   function RegionManipulatorUi:updateBiome (value)
  1007.     if not tonumber (value) or
  1008.        tonumber (value) < 1 or
  1009.        tonumber (value) > 9 then
  1010.       dialog.showMessage ("Error!", "The Biome legal range is 1 - 9", COLOR_RED)
  1011.     else
  1012.       region.biome [x] [y] = tonumber (value)
  1013.     end
  1014.    
  1015.     Update (x, y, self.subviews.pages)   
  1016.   end
  1017.  
  1018.   --==============================================================
  1019.  
  1020.   function RegionManipulatorUi:flattenRegion ()
  1021.     for i = 0, #region.elevation - 1 do
  1022.       for k = 0, #region.elevation [0] -1 do
  1023.         region.elevation [i] [k] = region.elevation [x] [y]
  1024.       end
  1025.     end
  1026.    
  1027.     Make_Elevation (x, y)
  1028.     Update (x, y, self.subviews.pages)
  1029.   end
  1030.  
  1031.   --==============================================================
  1032.  
  1033.   function RegionManipulatorUi:updateRiversElevation (value)
  1034.     if not tonumber (value) or
  1035.        tonumber (value) < -999 or
  1036.        tonumber (value) > 250 then
  1037.       dialog.showMessage ("Error!", "The Elevation legal range is -999 - 250", COLOR_RED)
  1038.  
  1039.     else
  1040.       if region.rivers_horizontal.active [x] [y] ~= 0 then
  1041.         region.rivers_horizontal.elevation [x] [y] = tonumber (value)
  1042.       end
  1043.  
  1044.       if region.rivers_vertical.active [x] [y] ~= 0 then
  1045.         region.rivers_vertical.elevation [x] [y] = tonumber (value)
  1046.       end
  1047.     end
  1048.    
  1049.     Update (x, y, self.subviews.pages)
  1050.   end
  1051.  
  1052.   --==============================================================
  1053.  
  1054.   function RegionManipulatorUi:updateRiversVerticalActive (value)
  1055.     if string.upper (value) == "SOUTH" or
  1056.        string.upper (value) == "NORTH" then
  1057.       if region.rivers_vertical.active [x] [y] == 0 then
  1058.         region.rivers_vertical.x_min [x] [y] = 23
  1059.         region.rivers_vertical.x_max [x] [y] = 25
  1060.  
  1061.         if region.rivers_horizontal.active [x] [y] ~= 0 then
  1062.           region.rivers_vertical.elevation [x] [y] = region.rivers_horizontal.elevation [x] [y]
  1063.          
  1064.         else
  1065.           region.rivers_vertical.elevation [x] [y] = region.elevation [x] [y]
  1066.         end
  1067.       end    
  1068.  
  1069.       if string.upper (value) == "SOUTH" then
  1070.         region.rivers_vertical.active [x] [y] = 1
  1071.       else
  1072.         region.rivers_vertical.active [x] [y] = -1
  1073.       end
  1074.          
  1075.     elseif string.upper (value) == "NONE" then
  1076.       region.rivers_vertical.active [x] [y] = 0
  1077.       region.rivers_vertical.elevation [x] [y] = 100
  1078.       region.rivers_vertical.x_min [x] [y] = -30000
  1079.       region.rivers_vertical.x_max [x] [y] = -30000
  1080.  
  1081.     else
  1082.       dialog.showMessage ("Error!", "The legal values are 'None', 'North', and 'South'", COLOR_RED)    
  1083.     end
  1084.    
  1085.     Update (x, y, self.subviews.pages)
  1086.   end
  1087.  
  1088.   --==============================================================
  1089.  
  1090.   function RegionManipulatorUi:updateRiversVerticalXMin (value)
  1091.     if not tonumber (value) or
  1092.        tonumber (value) < 0 or
  1093.        tonumber (value) > 47 then
  1094.       dialog.showMessage ("Error!", "The X Min legal range is 0 - 47", COLOR_RED)
  1095.    
  1096.     elseif tonumber (value) > region.rivers_vertical.x_max [x] [y] then
  1097.       dialog.showMessage ("Error!", "The X Min value cannot be larger than X Max", COLOR_RED)
  1098.      
  1099.     else
  1100.       region.rivers_vertical.x_min [x] [y] = tonumber (value)
  1101.     end
  1102.    
  1103.     Update (x, y, self.subviews.pages)
  1104.   end
  1105.  
  1106.   --==============================================================
  1107.  
  1108.   function RegionManipulatorUi:updateRiversVerticalXMax (value)
  1109.     if not tonumber (value) or
  1110.        tonumber (value) < 0 or
  1111.        tonumber (value) > 47 then
  1112.       dialog.showMessage ("Error!", "The X Max legal range is 0 - 47", COLOR_RED)
  1113.    
  1114.     elseif tonumber (value) < region.rivers_vertical.x_min [x] [y] then
  1115.       dialog.showMessage ("Error!", "The X Max value cannot be smaller than X Min", COLOR_RED)
  1116.      
  1117.     else
  1118.       region.rivers_vertical.x_max [x] [y] = tonumber (value)
  1119.     end
  1120.    
  1121.     Update (x, y, self.subviews.pages)
  1122.   end
  1123.  
  1124.   --==============================================================
  1125.  
  1126.   function RegionManipulatorUi:updateRiversHorizontalActive (value)
  1127.     if string.upper (value) == "EAST" or
  1128.        string.upper (value) == "WEST" then
  1129.       if region.rivers_horizontal.active [x] [y] == 0 then
  1130.         region.rivers_horizontal.y_min [x] [y] = 23
  1131.         region.rivers_horizontal.y_max [x] [y] = 25
  1132.  
  1133.         if region.rivers_vertical.active [x] [y] ~= 0 then
  1134.           region.rivers_horizontal.elevation [x] [y] = region.rivers_vertical.elevation [x] [y]
  1135.          
  1136.         else
  1137.           region.rivers_horizontal.elevation [x] [y] = region.elevation [x] [y]
  1138.         end
  1139.       end    
  1140.  
  1141.       if string.upper (value) == "WEST" then
  1142.         region.rivers_horizontal.active [x] [y] = 1
  1143.       else
  1144.         region.rivers_horizontal.active [x] [y] = -1
  1145.       end
  1146.          
  1147.     elseif string.upper (value) == "NONE" then
  1148.       region.rivers_horizontal.active [x] [y] = 0
  1149.       region.rivers_horizontal.elevation [x] [y] = 100
  1150.       region.rivers_horizontal.y_min [x] [y] = -30000
  1151.       region.rivers_horizontal.y_max [x] [y] = -30000
  1152.     else
  1153.       dialog.showMessage ("Error!", "The legal values are 'None', 'East', and 'West'", COLOR_RED)    
  1154.     end
  1155.    
  1156.     Update (x, y, self.subviews.pages)
  1157.   end
  1158.  
  1159.   --==============================================================
  1160.  
  1161.   function RegionManipulatorUi:updateRiversHorizontalYMin (value)
  1162.     if not tonumber (value) or
  1163.        tonumber (value) < 0 or
  1164.        tonumber (value) > 47 then
  1165.       dialog.showMessage ("Error!", "The Y Min legal range is 0 - 47", COLOR_RED)
  1166.    
  1167.     elseif tonumber (value) > region.rivers_horizontal.y_max [x] [y] then
  1168.       dialog.showMessage ("Error!", "The Y Min value cannot be larger than Y Max", COLOR_RED)
  1169.      
  1170.     else
  1171.       region.rivers_horizontal.y_min [x] [y] = tonumber (value)
  1172.     end
  1173.    
  1174.     Update (x, y, self.subviews.pages)
  1175.   end
  1176.  
  1177.   --==============================================================
  1178.  
  1179.   function RegionManipulatorUi:updateRiversHorizontalYMax (value)
  1180.     if not tonumber (value) or
  1181.        tonumber (value) < 0 or
  1182.        tonumber (value) > 47 then
  1183.       dialog.showMessage ("Error!", "The Y Max legal range is 0 - 47", COLOR_RED)
  1184.    
  1185.     elseif tonumber (value) < region.rivers_horizontal.y_min [x] [y] then
  1186.       dialog.showMessage ("Error!", "The Y Max value cannot be smaller than Y Min", COLOR_RED)
  1187.      
  1188.     else
  1189.       region.rivers_horizontal.y_max [x] [y] = tonumber (value)
  1190.     end
  1191.    
  1192.     Update (x, y, self.subviews.pages)
  1193.   end
  1194.  
  1195.   --==============================================================
  1196.  
  1197.   function RegionManipulatorUi:updateBrook (value)
  1198.     if string.upper (value) ~= "Y" and
  1199.        string.upper (value) ~= "N" then
  1200.       dialog.showMessage ("Error!", "The legal values are Y and N", COLOR_RED)
  1201.  
  1202.     else
  1203.       df.global.world.world_data.region_map[region.pos.x]:_displace(region.pos.y).flags.is_brook = string.upper (value) == 'Y'
  1204.     end
  1205.    
  1206.     Update (x, y, self.subviews.pages)
  1207.   end
  1208.  
  1209.   --==============================================================
  1210.  
  1211.   function RegionManipulatorUi:onInput (keys)
  1212.     if keys.LEAVESCREEN_ALL  then
  1213.         self:dismiss ()
  1214.     end
  1215.    
  1216.     if keys.LEAVESCREEN then
  1217.       if Focus == "Help" then
  1218.         Focus = "Main"
  1219.         self.subviews.pages:setSelected (1)
  1220.        
  1221.       else
  1222.         self:dismiss ()
  1223.       end
  1224.     end
  1225.  
  1226.     if keys [keybindings.next_edit.key] then
  1227.       local Done = false
  1228.      
  1229.       Set_Edit_Focus (Main_Page.Edit_Focus, false)
  1230.      
  1231.       for i = Main_Page.Edit_Focus + 1, #Main_Page.Edit_List do
  1232.         if Main_Page.Edit_List [i] [1].visible then
  1233.           Set_Edit_Focus (i, true)
  1234.  
  1235.           Main_Page.Edit_Focus = i
  1236.           Done = true
  1237.           break
  1238.         end
  1239.       end
  1240.      
  1241.       if not Done then
  1242.         for i = 1, Main_Page.Edit_Focus - 1 do
  1243.           if Main_Page.Edit_List [i] [1].visible then
  1244.             Set_Edit_Focus (i, true)
  1245.  
  1246.             Main_Page.Edit_Focus = i
  1247.             break
  1248.           end
  1249.         end
  1250.       end
  1251.  
  1252.       Update (x, y, self.subviews.pages)  --  To reset modified but not committed values
  1253.      
  1254.     elseif keys [keybindings.prev_edit.key] then   
  1255.       local Done = false
  1256.      
  1257.       Set_Edit_Focus (Main_Page.Edit_Focus, false)
  1258.      
  1259.       for i = Main_Page.Edit_Focus - 1, 1, -1 do
  1260.         if Main_Page.Edit_List [i] [1].visible then
  1261.           Set_Edit_Focus (i, true)
  1262.  
  1263.           Main_Page.Edit_Focus = i
  1264.           Done = true
  1265.           break
  1266.         end
  1267.       end
  1268.      
  1269.       if not Done then
  1270.         for i = #Main_Page.Edit_List, Main_Page.Edit_Focus + 1, -1 do
  1271.           if Main_Page.Edit_List [i] [1].visible then
  1272.             Set_Edit_Focus (i, true)
  1273.  
  1274.             Main_Page.Edit_Focus = i
  1275.             break
  1276.           end
  1277.         end
  1278.       end
  1279.  
  1280.       Update (x, y, self.subviews.pages)  --  To reset modified but not committed values
  1281.    
  1282.     elseif keys [keybindings.elevation.key] then
  1283.       Main_Page.elevationGrid.visible = true
  1284.       Main_Page.biomeGrid.visible = false
  1285.       Main_Page.riversGrid.visible = false
  1286.      
  1287.     elseif keys [keybindings.biome.key] then
  1288.       Main_Page.elevationGrid.visible = false
  1289.       Main_Page.biomeGrid.visible = true
  1290.       Main_Page.riversGrid.visible = false
  1291.  
  1292.     elseif keys [keybindings.rivers.key] then
  1293.       Main_Page.elevationGrid.visible = false
  1294.       Main_Page.biomeGrid.visible = false
  1295.       Main_Page.riversGrid.visible = true
  1296.  
  1297.     elseif keys [keybindings.flatten.key] then
  1298.       dialog.showYesNoPrompt ("Flatten Terrain?",
  1299.                               "The whole region will be set to an elevation of " .. tostring (region.elevation [x] [y]) .. " on Enter.",
  1300.                               COLOR_WHITE,
  1301.                               NIL,
  1302.                               self:callback ("flattenRegion"))
  1303.      
  1304.     elseif keys [keybindings.up.key] and not keys._STRING then
  1305.       if focus ~= "Help" then
  1306.         if y > 0 then
  1307.           y = y - 1
  1308.         end
  1309.  
  1310.         Update (x, y, self.subviews.pages)
  1311.       end
  1312.          
  1313.     elseif keys [keybindings.down.key] and not keys._STRING then
  1314.       if focus ~= "Help" then
  1315.         if y < max_y - 1 then
  1316.           y = y + 1
  1317.         end
  1318.  
  1319.         Update (x, y, self.subviews.pages)
  1320.       end
  1321.          
  1322.     elseif keys [keybindings.left.key] and not keys._STRING then
  1323.       if focus ~= "Help"  then
  1324.         if x > 0 then
  1325.           x = x - 1
  1326.         end
  1327.      
  1328.         Update (x, y, self.subviews.pages)
  1329.       end
  1330.      
  1331.     elseif keys [keybindings.right.key] and not keys._STRING then
  1332.       if focus ~= "Help" then
  1333.         if x < max_x - 1 then
  1334.           x = x + 1
  1335.         end
  1336.        
  1337.         Update (x, y, self.subviews.pages)
  1338.       end
  1339.      
  1340.     elseif keys [keybindings.upleft.key] and not keys._STRING then
  1341.       if focus ~= "Help" then
  1342.         if x > 0 then
  1343.           x = x - 1
  1344.         end
  1345.      
  1346.         if y > 0 then
  1347.           y = y - 1
  1348.         end
  1349.      
  1350.         Update (x, y, self.subviews.pages)
  1351.       end
  1352.      
  1353.     elseif keys [keybindings.upright.key] and not keys._STRING then
  1354.       if focus ~= "Help" then
  1355.         if x < max_x - 1 then
  1356.           x = x + 1
  1357.         end
  1358.      
  1359.         if y > 0 then
  1360.           y = y - 1
  1361.         end
  1362.      
  1363.         Update (x, y, self.subviews.pages)
  1364.       end
  1365.      
  1366.     elseif keys [keybindings.downleft.key] and not keys._STRING then
  1367.       if focus ~= "Help" then
  1368.         if x > 0 then
  1369.           x = x - 1
  1370.         end
  1371.      
  1372.         if y < max_y - 1 then
  1373.           y = y + 1
  1374.         end
  1375.      
  1376.         Update (x, y, self.subviews.pages)
  1377.       end
  1378.      
  1379.     elseif keys [keybindings.downright.key] and not keys._STRING then
  1380.       if focus ~= "Help" then
  1381.         if x < max_x - 1 then
  1382.           x = x + 1
  1383.         end
  1384.      
  1385.         if y < max_y - 1 then
  1386.           y = y + 1
  1387.         end
  1388.      
  1389.         Update (x, y, self.subviews.pages)
  1390.       end    
  1391.     end
  1392.  
  1393.     self.super.onInput (self, keys)
  1394.   end
  1395.  
  1396.   --============================================================
  1397.  
  1398.   function Show_Viewer ()
  1399.     local screen = RegionManipulatorUi {}
  1400.     persist_screen = screen
  1401.     screen:show ()
  1402.   end
  1403.  
  1404.   --============================================================
  1405.  
  1406.   Show_Viewer ()
  1407. end
  1408.  
  1409. regionmanipulator ()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement