Script - Scripted Mouse: Difference between revisions

Wanderer (talk | contribs)
m fixing bug
Wanderer (talk | contribs)
edited the parser, moved config file to data/config dir, changed it to .cfg to improve scripts portability
Line 11: Line 11:
[
[


-- couple of functions to make things go easier
--NEW PARSER
function find_after_keyword(line_to_parse, keyword)
----------------------
-- parser functions --
----------------------


  -- make sure both strings are in lower case
--- get newline and make sure its lowercase
   line_to_parse = line_to_parse:lower()
function get_next_line(nfile)
   keyword = keyword:lower()
  -- read the line
   nline = nfile:read("*l")
   -- change to lowercase
  if nline ~= nil then
      nline = nline:lower()
  end
  return nline
end


--- find keyword and return the place where it ends
function find_keyword(line_to_parse, keyword)
   -- find any instances of the keyword
   -- find any instances of the keyword
   key_s, key_e = line_to_parse:find(keyword)
   keyword = keyword:lower()
  local key_s, key_e = line_to_parse:find(keyword)


   -- if we cant find a thing
   -- if we cant find a thing
Line 26: Line 38:
   end
   end


   result = line_to_parse:match("%d+", e_key)
   -- check if the line has been commented away
  return tonumber(result)
  local comment_s, comment_e = line_to_parse:find("--")
end


function find_4_numbers_after_keyword(line_to_parse, keyword)
  if comment_s == nil then
      return key_e
  elseif comment_s < key_s then
      return nil
  end


   -- make sure both strings are in lower case
   return key_e
  line_to_parse = line_to_parse:lower()
end
  keyword = keyword:lower()


   -- find any instances of the keyword
--- specific parsing funcs to make things easier to read ---
   key_s, key_e = line_to_parse:find(keyword)
--- string or rather substring parser
function parse_string(start_key, line_to_parse)
  local substring = line_to_parse:sub(start_key)
   -- remove empty spaces
  local substring_start = substring:find("%a")
   substring = substring:sub(substring_start)
  return substring
end


  -- if we cant find a thing
--- function to parse numbers
   if key_s == nil then
function parse_number(start_key, line_to_parse)
      return nil
   local result = line_to_parse:sub(start_key)
   end
   local r_value = result:match('[0-9%.]+')
 
   r_value = tonumber(r_value)
  -- make sure r is an array
   return r_value
   r = {}
end
   i = 1


--- function to parse arrays of numbers
function parse_number_array(start_key, line_to_parse)
   -- stuff the array
   -- stuff the array
   for p in line_to_parse:gmatch("%d+") do
  local r = { }
       r[i] = p
  local p
      r[i] = tonumber(r[i])
   for p in line_to_parse:gmatch('[0-9%.]+') do
       if r[i] > 255 then
       p = tonumber(p)
        r[i] = 255
       p = math.floor(p)
       elseif r[i] < 0 then
       table.insert(r, p)
        r[i] = 0
      end
      i = i + 1
   end
   end
   return r
   return r
end
end


function parse_mousefile_line(line_to_parse, mousefile)
--- function to parse things
   -- check for sensitivity
function parse_entry(keyword, mousefile, type, use_same_line)
   if mousesensitivity == nil then
   local new_entry = nil
       mousesensitivity = find_after_keyword(line_to_parse, "Sensitivity:")
  local return_val
       if mousesensitivity ~= nil then
  local return_array = {}
         if mousesensitivity < 100 then
  local c_line
            mousesensitivity = 100
   if use_same_line == false then
         elseif mousesensitivity > 600 then
       c_line = get_next_line(mousefile)
             mousesensitivity = 600
       if c_line == nil then
         -- end of file
        return -2, false, return_array
      end
      while c_line:len() == 0 do
         c_line = get_next_line(mousefile)
        if c_line == nil then
             -- end of file
            return -2, false, return_array
         end
         end
       end
       end
   -- if we already have sensitivity, check for sensitivity curve
      current_start_line = c_line
  elseif mousesensitivitymode == nil then
  else
      mousesensitivitymode = find_after_keyword(line_to_parse, "Sensitivity Curve:")
      c_line = use_same_line
      if mousesensitivitymode ~= nil then
  end
        if mousesensitivitymode < 0 then
 
             mousesensitivitymode = 1
  local c_key = nil
         elseif mousesensitivitymode > 6 then
   while c_key == nil do
             mousesensitivitymode = 6
      -- we didn't find the thing...
      c_key = find_keyword(c_line, keyword)
      if c_key == nil then
        local comment_s = nil
        comment_s = c_line:find("//")
        if comment_s ~= nil then
            c_line = get_next_line(mousefile)
            if c_line == nil then
              -- end of file
              return -2, false, return_array
            end
            while c_line:len() == 0 do
              c_line = get_next_line(mousefile)
              if c_line == nil then
                  return -2, false, return_array
              end
             end
         else
            -- try next entry
             return -1, c_line, return_array
         end
         end
       end
       end
   -- if we have all the above, go for control mode
   end
   elseif mousecontrolmode == nil then
  if type == "n" then
       mousecontrolmode = find_after_keyword(line_to_parse, "Control Mode:")
      -- soo... parse a number
  -- if we have all the above, go for deadzone
      return_array[1] = parse_number(c_key, c_line)
  elseif mousedeadzone == nil then
      return_val = #return_array
      mousedeadzone = find_after_keyword(line_to_parse, "Deadzone:")
      return return_val, false, return_array
      if mousedeadzone ~= nil then
  elseif type == "array_n" then
        if mousedeadzone < 0 then
      -- soo... parse an array of numbers
             mousedeadzone = 0
      return_array = parse_number_array(c_key, c_line)
      return_val = #return_array
      return return_val, false, return_array
  end
  return -1, c_line, return_array
end
 
function cap_value(min_val, max_val, value)
  if min_val > value then
      value = min_val
   elseif max_val < value then
      value = max_val
  end
  return value
end
 
-- actual parsing function
function parse_mousefile(mousefile)
  use_same_line = false
  local current_start_line = use_same_line
  local not_new_entry = false
  local entry_start = 1
  local still_parsing = true
 
  while still_parsing == true do
 
      if use_same_line == false then
        use_same_line = get_next_line(mousefile)
      end
 
      if use_same_line == nil then
        -- end of file
        still_parsing = false
        break
      end
 
       if use_same_line:len() == 0 then
        use_same_line = false
      else
        current_start_line = use_same_line
        if entry_start ~= nil then
            while entry_start ~= nil do
              if not_new_entry == false then
                  ba.print("\nScripted Mouse Loading\n")
              end
 
              local temp_val = nil
              local temp_arr = nil
              entry_start = nil
 
              temp_val, use_same_line, temp_arr = parse_entry("Sensitivity:", mousefile, "n", use_same_line)
              if temp_val == -2 then
                  break
              elseif temp_val ~= -1 then
                  temp_arr[1] = cap_value(100, 600, temp_arr[1])
                  ba.print("\tSensitivity: " .. temp_arr[1] .. "\n")
                  mousesensitivity = temp_arr[1]
              end
 
              temp_val, use_same_line, temp_arr = parse_entry("Sensitivity Curve:", mousefile, "n", use_same_line)
              if temp_val == -2 then
                  break
              elseif temp_val ~= -1 then
                  temp_arr[1] = cap_value(0, 6, temp_arr[1])
                  ba.print("\tSensitivity Curve: " .. temp_arr[1] .. "\n")
                  mousesensitivitymode = temp_arr[1]
              end
 
              temp_val, use_same_line, temp_arr = parse_entry("Control Mode:", mousefile, "n", use_same_line)
              if temp_val == -2 then
                  break
              elseif temp_val ~= -1 then
                  ba.print("\tControl Mode: " .. temp_arr[1] .. "\n")
                  mousecontrolmode = temp_arr[1]
              end
 
              temp_val, use_same_line, temp_arr = parse_entry("Deadzone:", mousefile, "n", use_same_line)
              if temp_val == -2 then
                  break
              elseif temp_val ~= -1 then
                  temp_arr[1] = cap_value(0, 300, temp_arr[1])
                  ba.print("\tDeadzone: " .. temp_arr[1] .. "\n")
                  mousedeadzone = temp_arr[1]
              end
 
              temp_val, use_same_line, temp_arr = parse_entry("Mouse Invert:", mousefile, "n", use_same_line)
              if temp_val == -2 then
                  break
              elseif temp_val ~= -1 then
                  if temp_arr[1] ~= 0 then
                    temp_arr[1] = 1
                  end
                  ba.print("\tMouse Invert: " .. temp_arr[1] .. "\n")
                  mouseinvert = temp_arr[1]
              end
 
              temp_val, use_same_line, temp_arr = parse_entry("Boundary Limit:", mousefile, "n", use_same_line)
              if temp_val == -2 then
                  break
              elseif temp_val ~= -1 then
                  ba.print("\tBoundary Limit: " .. temp_arr[1] .. "\n")
                  mouseboundaries = temp_arr[1]
              end
 
              temp_val, use_same_line, temp_arr = parse_entry("Indicator Color:", mousefile, "array_n", use_same_line)
              if temp_val == -2 then
                  break
              elseif temp_val ~= -1 then
                  ba.print("\tIndicator Color: " .. temp_val .. "\n")
                  mousecolors = temp_arr
              end
 
              if use_same_line ~= false then
                  ba.warning("Bogus string in mouse config file: " .. use_same_line)
              end
             end
        else
            use_same_line = false
         end
         end
       end
       end
   -- if we have all the above, go for mouse invert
  end
   elseif mouseinvert == nil then
end
       mouseinvert = find_after_keyword(line_to_parse, "Mouse Invert:")
--NEW PARSER
      if mouseinvert ~= 1 then
 
        mouseinvert = 0
function verify_mouse_data()
       end
   -- make sure we have a number in deadzone var and not nil
   -- if we have all the above, go for mouse boundaries
   if mousedeadzone == nil then
   elseif mouseboundaries == nil then
       mousedeadzone = 0
       mouseboundaries = find_after_keyword(line_to_parse, "Boundary Limit:")
  end
   -- if we have all the above, go for mouse colors
 
   elseif mousecolor == nil then
  -- define some variables
       mousecolors = find_4_numbers_after_keyword(line_to_parse, "Indicator Color:")
  mouse_reset_counter = nil
   -- all found - set the position to end of file
  missiontime_old = 0
  missiontime = nil
 
  -- if mouse invert was set to true, then invert the mouse (set it to '-1')
  -- otherwise define the multiplier as '1'
  if mouseinvert == 1 then
      mouseinvert = -1
  else
       mouseinvert = 1
  end
 
   -- check if boundaries are valid
   if mouseboundaries == nil then
       mouseboundaries = 1
  end
 
   -- check that defined control area is not larger than the actual area which can be controlled
  local max_limits
   max_limits = mousesensitivity * 2 + mousedeadzone * 2 + 10
  scr_width = gr.getScreenWidth()
  scr_height = gr.getScreenHeight()
  if max_limits > scr_width or max_limits > scr_height then
       ba.warning("Mouse control area defined to be larger than the window size, please resize")
  end
 
   --setup mouse bitmap
  mouse_bm = gr.loadTexture("mouse_ret_2.dds", true)
  if mouse_bm:isValid() then
      no_bitmap = false
      mouse_bm_w = mouse_bm:getWidth() / 2
      mouse_bm_h = mouse_bm:getHeight() / 2
   else
   else
       mousefile:seek("end")
       no_bitmap = true
   end
   end
end
end
Line 115: Line 308:
-- check if the file containing mouse references exists
-- check if the file containing mouse references exists
-----------------------------------------------------------------------
-----------------------------------------------------------------------
filename_mouse = "mouse_script.txt"
filename_mouse = "mouse_script.cfg"
boolmousefileOK = cf.fileExists(filename_mouse, "data/text/", true)
boolmousefileOK = cf.fileExists(filename_mouse, "data/config/", true)
boolscriptmouse = false
boolscriptmouse = false


Line 133: Line 326:
   -- open the file in read only mode
   -- open the file in read only mode
   mousefile = cf.openFile(filename_mouse, "r")
   mousefile = cf.openFile(filename_mouse, "r")
 
   -- do the parsing thing
   -- pick first line
  parse_mousefile(mousefile)
  new_line = mousefile:read("*l")
 
  while new_line ~= nil do
      -- parse line and then jump on to the next line until end of file
      parse_mousefile_line(new_line,mousefile)
      new_line = mousefile:read("*l")
  end
 
   -- all data read.. time to close the file
   -- all data read.. time to close the file
   mousefile:close()
   mousefile:close()
Line 152: Line 337:
       boolscriptmouse = true
       boolscriptmouse = true
       ba.setControlMode(LUA_FULL_CONTROLS)
       ba.setControlMode(LUA_FULL_CONTROLS)
      verify_mouse_data()


      -- make sure we have a number in deadzone var and not nil
      if mousedeadzone == nil then
        mousedeadzone = 0
      end
      -- define some variables
      mouse_reset_counter = nil
      missiontime_old = 0
      missiontime = nil
      -- if mouse invert was set to true, then invert the mouse (set it to '-1')
      -- otherwise define the multiplier as '1'
      if mouseinvert == 1 then
        mouseinvert = -1
      else
        mouseinvert = 1
      end
      -- check if boundaries are valid
      if mouseboundaries == nil then
        mouseboundaries = 1
      end
      -- check that defined control area is not larger than the actual area which can be controlled
      local max_limits
      max_limits = mousesensitivity * 2 + mousedeadzone * 2 + 10
      scr_width = gr.getScreenWidth()
      scr_height = gr.getScreenHeight()
      if max_limits > scr_width or max_limits > scr_height then
        ba.warning("Mouse control area defined to be larger than the window size, please resize")
      end
      --setup mouse bitmap
      mouse_bm = gr.loadTexture("mouse_ret_2.dds", true)
      if mouse_bm:isValid() then
        no_bitmap = false
        mouse_bm_w = mouse_bm:getWidth() / 2
        mouse_bm_h = mouse_bm:getHeight() / 2
      else
        no_bitmap = true
      end
   else
   else
       ba.warning("Scripted mouse's init failed")
       ba.warning("Scripted mouse's init failed")
Line 200: Line 345:
   ba.warning("File '" .. filename_mouse .."' not found")
   ba.warning("File '" .. filename_mouse .."' not found")
end
end
]
$Application: FS2_Open
$State: GS_STATE_GAME_PLAY
$On Frame:
[


------------------------
------------------------
Line 277: Line 414:
         io.forceMousePosition(mouse_x, f_mouse_y)
         io.forceMousePosition(mouse_x, f_mouse_y)
       end
       end
  end
end
function draw_cursor()
  if no_bitmap == true then
      -- no bitmap defined, so use normal lines
      gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x + 20, drawpos_y - 20)
      gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x - 20, drawpos_y + 20)
      gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x + 20, drawpos_y + 20)
      gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x - 20, drawpos_y - 20)
  else
      -- draw the bitmap centered on the spot
      gr.drawMonochromeImage(mouse_bm, drawpos_x - mouse_bm_w, drawpos_y - mouse_bm_h, drawpos_x + mouse_bm_w, drawpos_y + mouse_bm_h)
  end
end
function check_mouse_reset()
  if mouse_reset_counter == nil then
      mouse_center_x = io.getMouseX()
      mouse_center_y = io.getMouseY()
      mouse_reset_counter = 0
  end
end
function force_mouse_control_status()
  if io.MouseControlStatus == true then
      mouse_reset_on_end = true
      io.MouseControlStatus = false
  end
end
function set_mouse_colors()
  if mousecolors[1] == nil then
      gr.setColor(0,64,220,196)
  else
      gr.setColor(mousecolors[1],mousecolors[2],mousecolors[3],mousecolors[4])
   end
   end
end
end
Line 282: Line 455:
--- end of functions ---
--- end of functions ---
------------------------
------------------------
]
$Application: FS2_Open
$State: GS_STATE_GAME_PLAY
$On Frame:
[


if boolscriptmouse == true then
if boolscriptmouse == true then
   -- check for center button reset...
   -- check for center button reset...
   if mouse_reset_counter == nil then
   check_mouse_reset()
      mouse_center_x = io.getMouseX()
      mouse_center_y = io.getMouseY()
      mouse_reset_counter = 0
  end


   -- get frametime (used to increment the timer)
   -- get frametime (used to increment the timer)
Line 301: Line 478:


   -- if the setting changes make sure to reset it to false
   -- if the setting changes make sure to reset it to false
   if io.MouseControlStatus == true then
   force_mouse_control_status()
      mouse_reset_on_end = true
      io.MouseControlStatus = false
  end


   -- check if missiontime is actually running or not
   -- check if missiontime is actually running or not
Line 342: Line 516:


         -- define the color of the cursor
         -- define the color of the cursor
         if mousecolors == nil then
         -- could use color inheritance!!!
            gr.setColor(0,64,220,196)
         set_mouse_colors()
         else
            gr.setColor(mousecolors[1],mousecolors[2],mousecolors[3],mousecolors[4])
        end


         -- get the actual control values
         -- get the actual control values
Line 363: Line 534:


         -- draw cursor
         -- draw cursor
         if no_bitmap == true then
         draw_cursor()
            gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x + 20, drawpos_y - 20)
            gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x - 20, drawpos_y + 20)
            gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x + 20, drawpos_y + 20)
            gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x - 20, drawpos_y - 20)
        else
            gr.drawMonochromeImage(mouse_bm, drawpos_x - mouse_bm_w, drawpos_y - mouse_bm_h, drawpos_x + mouse_bm_w, drawpos_y + mouse_bm_h)
        end
       end
       end
   else
   else
Line 395: Line 559:


==Configuration file==
==Configuration file==
Filename '''mouse_script.txt''', placed into '''.../data/text/''' directory
Filename '''mouse_script.cfg''', placed into '''.../data/config/''' directory
<pre>Sensitivity:        350
<pre>Sensitivity:        350
Sensitivity Curve:  1.5
Sensitivity Curve:  1.5

Revision as of 16:43, 20 February 2010

Function

Draws mouse flight icon and modifies the mouse controls

Table entry

For example script_mouse-sct.tbm

#Conditional Hooks

$Application: FS2_Open
$On Mission Start:

[

--NEW PARSER
----------------------
-- parser functions --
----------------------

--- get newline and make sure its lowercase
function get_next_line(nfile)
   -- read the line
   nline = nfile:read("*l")
   -- change to lowercase
   if nline ~= nil then
      nline = nline:lower()
   end
   return nline
end

--- find keyword and return the place where it ends
function find_keyword(line_to_parse, keyword)
   -- find any instances of the keyword
   keyword = keyword:lower()
   local key_s, key_e = line_to_parse:find(keyword)

   -- if we cant find a thing
   if key_s == nil then
      return nil
   end

   -- check if the line has been commented away
   local comment_s, comment_e = line_to_parse:find("--")

   if comment_s == nil then
      return key_e
   elseif comment_s < key_s then
      return nil
   end

   return key_e
end

--- specific parsing funcs to make things easier to read ---
--- string or rather substring parser
function parse_string(start_key, line_to_parse)
   local substring = line_to_parse:sub(start_key)
   -- remove empty spaces
   local substring_start = substring:find("%a")
   substring = substring:sub(substring_start)
   return substring
end

--- function to parse numbers
function parse_number(start_key, line_to_parse)
   local result = line_to_parse:sub(start_key)
   local r_value = result:match('[0-9%.]+')
   r_value = tonumber(r_value)
   return r_value
end

--- function to parse arrays of numbers
function parse_number_array(start_key, line_to_parse)
   -- stuff the array
   local r = { }
   local p
   for p in line_to_parse:gmatch('[0-9%.]+') do
      p = tonumber(p)
      p = math.floor(p)
      table.insert(r, p)
   end
   return r
end

--- function to parse things
function parse_entry(keyword, mousefile, type, use_same_line)
   local new_entry = nil
   local return_val
   local return_array = {}
   local c_line
   if use_same_line == false then
      c_line = get_next_line(mousefile)
      if c_line == nil then
         -- end of file
         return -2, false, return_array
      end
      while c_line:len() == 0 do
         c_line = get_next_line(mousefile)
         if c_line == nil then
            -- end of file
            return -2, false, return_array
         end
      end
      current_start_line = c_line
   else
      c_line = use_same_line
   end

   local c_key = nil
   while c_key == nil do
      -- we didn't find the thing...
      c_key = find_keyword(c_line, keyword)
      if c_key == nil then
         local comment_s = nil
         comment_s = c_line:find("//")
         if comment_s ~= nil then
            c_line = get_next_line(mousefile)
            if c_line == nil then
               -- end of file
               return -2, false, return_array
            end
            while c_line:len() == 0 do
               c_line = get_next_line(mousefile)
               if c_line == nil then
                  return -2, false, return_array
               end
            end
         else
            -- try next entry
            return -1, c_line, return_array
         end
      end
   end
   if type == "n" then
      -- soo... parse a number
      return_array[1] = parse_number(c_key, c_line)
      return_val = #return_array
      return return_val, false, return_array
   elseif type == "array_n" then
      -- soo... parse an array of numbers
      return_array = parse_number_array(c_key, c_line)
      return_val = #return_array
      return return_val, false, return_array
   end
   return -1, c_line, return_array
end

function cap_value(min_val, max_val, value)
   if min_val > value then
      value = min_val
   elseif max_val < value then
      value = max_val
   end
   return value
end

-- actual parsing function
function parse_mousefile(mousefile)
   use_same_line = false
   local current_start_line = use_same_line
   local not_new_entry = false
   local entry_start = 1
   local still_parsing = true

   while still_parsing == true do

      if use_same_line == false then
         use_same_line = get_next_line(mousefile)
      end

      if use_same_line == nil then
         -- end of file
         still_parsing = false
         break
      end

      if use_same_line:len() == 0 then
         use_same_line = false
      else
         current_start_line = use_same_line
         if entry_start ~= nil then
            while entry_start ~= nil do
               if not_new_entry == false then
                  ba.print("\nScripted Mouse Loading\n")
               end

               local temp_val = nil
               local temp_arr = nil
               entry_start = nil

               temp_val, use_same_line, temp_arr = parse_entry("Sensitivity:", mousefile, "n", use_same_line)
               if temp_val == -2 then
                  break
               elseif temp_val ~= -1 then
                  temp_arr[1] = cap_value(100, 600, temp_arr[1])
                  ba.print("\tSensitivity: " .. temp_arr[1] .. "\n")
                  mousesensitivity = temp_arr[1]
               end

               temp_val, use_same_line, temp_arr = parse_entry("Sensitivity Curve:", mousefile, "n", use_same_line)
               if temp_val == -2 then
                  break
               elseif temp_val ~= -1 then
                  temp_arr[1] = cap_value(0, 6, temp_arr[1])
                  ba.print("\tSensitivity Curve: " .. temp_arr[1] .. "\n")
                  mousesensitivitymode = temp_arr[1]
               end

               temp_val, use_same_line, temp_arr = parse_entry("Control Mode:", mousefile, "n", use_same_line)
               if temp_val == -2 then
                  break
               elseif temp_val ~= -1 then
                  ba.print("\tControl Mode: " .. temp_arr[1] .. "\n")
                  mousecontrolmode = temp_arr[1]
               end

               temp_val, use_same_line, temp_arr = parse_entry("Deadzone:", mousefile, "n", use_same_line)
               if temp_val == -2 then
                  break
               elseif temp_val ~= -1 then
                  temp_arr[1] = cap_value(0, 300, temp_arr[1])
                  ba.print("\tDeadzone: " .. temp_arr[1] .. "\n")
                  mousedeadzone = temp_arr[1]
               end

               temp_val, use_same_line, temp_arr = parse_entry("Mouse Invert:", mousefile, "n", use_same_line)
               if temp_val == -2 then
                  break
               elseif temp_val ~= -1 then
                  if temp_arr[1] ~= 0 then
                     temp_arr[1] = 1
                  end
                  ba.print("\tMouse Invert: " .. temp_arr[1] .. "\n")
                  mouseinvert = temp_arr[1]
               end

               temp_val, use_same_line, temp_arr = parse_entry("Boundary Limit:", mousefile, "n", use_same_line)
               if temp_val == -2 then
                  break
               elseif temp_val ~= -1 then
                  ba.print("\tBoundary Limit: " .. temp_arr[1] .. "\n")
                  mouseboundaries = temp_arr[1]
               end

               temp_val, use_same_line, temp_arr = parse_entry("Indicator Color:", mousefile, "array_n", use_same_line)
               if temp_val == -2 then
                  break
               elseif temp_val ~= -1 then
                  ba.print("\tIndicator Color: " .. temp_val .. "\n")
                  mousecolors = temp_arr
               end

               if use_same_line ~= false then
                  ba.warning("Bogus string in mouse config file: " .. use_same_line)
               end
            end
         else
            use_same_line = false
         end
      end
   end
end
--NEW PARSER

function verify_mouse_data()
   -- make sure we have a number in deadzone var and not nil
   if mousedeadzone == nil then
      mousedeadzone = 0
   end

   -- define some variables
   mouse_reset_counter = nil
   missiontime_old = 0
   missiontime = nil

   -- if mouse invert was set to true, then invert the mouse (set it to '-1')
   -- otherwise define the multiplier as '1'
   if mouseinvert == 1 then
      mouseinvert = -1
   else
      mouseinvert = 1
   end

   -- check if boundaries are valid
   if mouseboundaries == nil then
      mouseboundaries = 1
   end

   -- check that defined control area is not larger than the actual area which can be controlled
   local max_limits
   max_limits = mousesensitivity * 2 + mousedeadzone * 2 + 10
   scr_width = gr.getScreenWidth()
   scr_height = gr.getScreenHeight()
   if max_limits > scr_width or max_limits > scr_height then
      ba.warning("Mouse control area defined to be larger than the window size, please resize")
   end

   --setup mouse bitmap
   mouse_bm = gr.loadTexture("mouse_ret_2.dds", true)
   if mouse_bm:isValid() then
      no_bitmap = false
      mouse_bm_w = mouse_bm:getWidth() / 2
      mouse_bm_h = mouse_bm:getHeight() / 2
   else
      no_bitmap = true
   end
end

-----------------------------------------------------------------------
-- check if the file containing mouse references exists
-----------------------------------------------------------------------
filename_mouse = "mouse_script.cfg"
boolmousefileOK = cf.fileExists(filename_mouse, "data/config/", true)
boolscriptmouse = false

-- if file exists
if boolmousefileOK then
   -- reset all the variables to nil
   mousesensitivity = nil
   mousesensitivitymode = nil
   mousecontrolmode = nil
   mousedeadzone = nil
   mouseinvert = nil
   mouseboundaries = nil
   mousecolor = nil
   mousecolors = {}

   -- open the file in read only mode
   mousefile = cf.openFile(filename_mouse, "r")
   -- do the parsing thing
   parse_mousefile(mousefile)
   -- all data read.. time to close the file
   mousefile:close()

   -- if these three were found from the cfg file...
   if mousesensitivity and mousesensitivitymode and mousecontrolmode then

      -- set script to actually run, allow lua to override c coded controls
      boolscriptmouse = true
      ba.setControlMode(LUA_FULL_CONTROLS)
      verify_mouse_data()

   else
      ba.warning("Scripted mouse's init failed")
   end
else
   ba.warning("File '" .. filename_mouse .."' not found")
end

------------------------
------ functions -------
------------------------
function mouse_control_A(value, centervalue, axis)
   -- get the actual difference from centerpoint
   delta = value - centervalue

   -- default multiplier to +1
   multiplier = 1

   -- if we are handling negative values set multiplier to -1
   -- and make sure we deal only with positive values
   if delta < 0 then
      multiplier = -1
      delta = math.abs(delta)
   end

   -- deduct deadzone from the delta
   delta = delta - mousedeadzone
   if delta < 0 then
      delta = 0
   end

   -- scale delta from 0 to 1 according to defined sensitivity
   delta = delta / mousesensitivity
   if delta > 1 then
      delta = 1
   end

   -- if we do not have extreme values
   -- apply the defined sensitivity curve
   if (delta > 0) and (delta < 1) then
      delta = math.pow(delta, mousesensitivitymode)
   end

   -- apply the multiplier
   delta = delta * multiplier

   return delta
end
------------------------
function do_boundaries_check(limit)
   f_mouse_x = nil
   f_mouse_y = nil

   -- do we go over width limits
   if mouse_x <= limit then
      f_mouse_x = limit
   elseif mouse_x >= (scr_width - limit) then
      f_mouse_x = scr_width - limit
   end

   -- do we go over height limits
   if mouse_y <= limit then
      f_mouse_y = limit
   elseif mouse_y >= (scr_height - limit) then
      f_mouse_y = scr_height - limit
   end

   -- reset the cursor to the nearest boundary
   if f_mouse_x ~= nil or f_mouse_y ~= nil then
      if f_mouse_x and f_mouse_y then
         io.forceMousePosition(f_mouse_x, f_mouse_y)
      elseif f_mouse_x then
         io.forceMousePosition(f_mouse_x, mouse_y)
      else
         io.forceMousePosition(mouse_x, f_mouse_y)
      end
   end
end

function draw_cursor()
   if no_bitmap == true then
      -- no bitmap defined, so use normal lines
      gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x + 20, drawpos_y - 20)
      gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x - 20, drawpos_y + 20)
      gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x + 20, drawpos_y + 20)
      gr.drawGradientLine(drawpos_x, drawpos_y, drawpos_x - 20, drawpos_y - 20)
   else
      -- draw the bitmap centered on the spot
      gr.drawMonochromeImage(mouse_bm, drawpos_x - mouse_bm_w, drawpos_y - mouse_bm_h, drawpos_x + mouse_bm_w, drawpos_y + mouse_bm_h)
   end
end

function check_mouse_reset()
   if mouse_reset_counter == nil then
      mouse_center_x = io.getMouseX()
      mouse_center_y = io.getMouseY()
      mouse_reset_counter = 0
   end
end

function force_mouse_control_status()
   if io.MouseControlStatus == true then
      mouse_reset_on_end = true
      io.MouseControlStatus = false
   end
end

function set_mouse_colors()
   if mousecolors[1] == nil then
      gr.setColor(0,64,220,196)
   else
      gr.setColor(mousecolors[1],mousecolors[2],mousecolors[3],mousecolors[4])
   end
end
------------------------
--- end of functions ---
------------------------

]

$Application: FS2_Open
$State: GS_STATE_GAME_PLAY
$On Frame:

[

if boolscriptmouse == true then
   -- check for center button reset...
   check_mouse_reset()

   -- get frametime (used to increment the timer)
   frametime = ba.getFrametime()

   -- make sure missiontime and old missiontime exist
   if missiontime ~= nil then
      missiontime_old = missiontime
   end
   missiontime = mn.getMissionTime()

   -- if the setting changes make sure to reset it to false
   force_mouse_control_status()

   -- check if missiontime is actually running or not
   if missiontime ~= missiontime_old then

      -- after pause ends (ie. missiontime starts running again)
      -- reset the mouse to the center
      if end_of_pause == true then
         io.forceMousePosition(mouse_center_x, mouse_center_y)
         end_of_pause = nil
      end

      -- increment the center mouse button down counter
      if io.isMouseButtonDown(MOUSE_MIDDLE_BUTTON) then
         mouse_reset_counter = mouse_reset_counter + frametime
      else
         mouse_reset_counter = 0
      end

      -- if center mouse button has been pressed long enough
      -- reset the mouse
      if mouse_reset_counter > 0.1 then
         io.forceMousePosition(mouse_center_x, mouse_center_y)
         mouse_reset_counter = 0
      end

      -- get control values
      mouse_x = io.getMouseX()
      mouse_y = io.getMouseY()
      controls = ba.getControlInfo()

      if mousecontrolmode == 1 then

         -- make sure we aint gonna go off the boundaries...
         do_boundaries_check(mouseboundaries)
         -- end of boundaries check

         -- define the color of the cursor
         -- could use color inheritance!!!
         set_mouse_colors()

         -- get the actual control values
         current_h = mouse_control_A(mouse_x, mouse_center_x, "x")
         current_p = mouseinvert * mouse_control_A(mouse_y, mouse_center_y, "y")

         -- increment, not replace the existing values
         controls.Heading = current_h + controls.Heading
         controls.Pitch = current_p + controls.Pitch

         -- get draw position
         center_x = scr_width / 2
         center_y = scr_height / 2
         drawpos_x = center_x + (current_h * 300)
         drawpos_y = center_y + (current_p * 300)

         -- draw cursor
         draw_cursor()
      end
   else
      end_of_pause = true
   end
end

]

$Application: FS2_Open
$On Mission End:

[

boolscriptmouse = false
ba.setControlMode(NORMAL_CONTROLS)
if mouse_reset_on_end == true then
   io.MouseControlStatus = true
end

]

#End

Configuration file

Filename mouse_script.cfg, placed into .../data/config/ directory

Sensitivity:         350
Sensitivity Curve:   1.5
Control Mode:        1
Deadzone:            2
Mouse Invert:        0
Boundary Limit:      20
Indicator Color:     255, 255, 0, 64
  • Sensitivity is basically defines the amount of pixels from the center of the screen that the script will read (limited from 100 to 600)
  • Sensitivity Curve is exponent for the value
  • Control Mode is just option to toggle the - possible, not yet implemented - alternate control modes on
  • Deadzone defines the deadzone for the control input
  • Mouse Invert allows mouse controls to be inverted
  • Boundary Limit defines the limit for the cursor from the edge of the screen.
  • Indicator Color defines the used draw color of the mouse flight indicator

Recommendations... (sensitivity + deadzone + boundary limit) * 2 should be greater than the smaller dimension of the screen.

Additional files

Script will accept mouse_ret_2.dds as the mouse indicator but should the effect be missing the script should revert to simple 2d draw icon (icon is automatically centered).