Script - Scripted Mouse

From FreeSpace Wiki
Revision as of 08:49, 20 February 2010 by Wanderer (talk | contribs) (fixing bug)
Jump to: navigation, search

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:

[

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

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

   -- find any instances of the keyword
   key_s, key_e = line_to_parse:find(keyword)

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

   result = line_to_parse:match("%d+", e_key)
   return tonumber(result)
end

function find_4_numbers_after_keyword(line_to_parse, keyword)

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

   -- find any instances of the keyword
   key_s, key_e = line_to_parse:find(keyword)

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

   -- make sure r is an array
   r = {}
   i = 1

   -- stuff the array
   for p in line_to_parse:gmatch("%d+") do
      r[i] = p
      r[i] = tonumber(r[i])
      if r[i] > 255 then
         r[i] = 255
      elseif r[i] < 0 then
         r[i] = 0
      end
      i = i + 1
   end
   return r
end

function parse_mousefile_line(line_to_parse, mousefile)
   -- check for sensitivity
   if mousesensitivity == nil then
      mousesensitivity = find_after_keyword(line_to_parse, "Sensitivity:")
      if mousesensitivity ~= nil then
         if mousesensitivity < 100 then
            mousesensitivity = 100
         elseif mousesensitivity > 600 then
            mousesensitivity = 600
         end
      end
   -- if we already have sensitivity, check for sensitivity curve
   elseif mousesensitivitymode == nil then
      mousesensitivitymode = find_after_keyword(line_to_parse, "Sensitivity Curve:")
      if mousesensitivitymode ~= nil then
         if mousesensitivitymode < 0 then
            mousesensitivitymode = 1
         elseif mousesensitivitymode > 6 then
            mousesensitivitymode = 6
         end
      end
   -- if we have all the above, go for control mode
   elseif mousecontrolmode == nil then
      mousecontrolmode = find_after_keyword(line_to_parse, "Control Mode:")
   -- if we have all the above, go for deadzone
   elseif mousedeadzone == nil then
      mousedeadzone = find_after_keyword(line_to_parse, "Deadzone:")
      if mousedeadzone ~= nil then
         if mousedeadzone < 0 then
            mousedeadzone = 0
         end
      end
   -- if we have all the above, go for mouse invert
   elseif mouseinvert == nil then
      mouseinvert = find_after_keyword(line_to_parse, "Mouse Invert:")
      if mouseinvert ~= 1 then
         mouseinvert = 0
      end
   -- if we have all the above, go for mouse boundaries
   elseif mouseboundaries == nil then
      mouseboundaries = find_after_keyword(line_to_parse, "Boundary Limit:")
   -- if we have all the above, go for mouse colors
   elseif mousecolor == nil then
      mousecolors = find_4_numbers_after_keyword(line_to_parse, "Indicator Color:")
   -- all found - set the position to end of file
   else
      mousefile:seek("end")
   end
end

-----------------------------------------------------------------------
-- check if the file containing mouse references exists
-----------------------------------------------------------------------
filename_mouse = "mouse_script.txt"
boolmousefileOK = cf.fileExists(filename_mouse, "data/text/", 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")

   -- pick first line
   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
   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)

      -- 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
      ba.warning("Scripted mouse's init failed")
   end
else
   ba.warning("File '" .. filename_mouse .."' not found")
end

]

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

[

------------------------
------ 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
------------------------
--- end of functions ---
------------------------

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

   -- 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
   if io.MouseControlStatus == true then
      mouse_reset_on_end = true
      io.MouseControlStatus = false
   end

   -- 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
         if mousecolors == nil then
            gr.setColor(0,64,220,196)
         else
            gr.setColor(mousecolors[1],mousecolors[2],mousecolors[3],mousecolors[4])
         end

         -- 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
         if no_bitmap == true then
            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
   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.txt, placed into .../data/text/ 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).