Hard Light Productions Forums
FreeSpace Releases => Scripting Releases => Topic started by: Sushi on February 08, 2011, 10:26:33 am
-
I figure this probably needs it's own topic.
This is a slightly modified version of the mouse script found here:
http://www.hard-light.net/wiki/index.php/Script_-_Scripted_Mouse
The main difference is that the middle mouse button, instead of recentering the mouse, toggles the "joystick-like" mode the mouse script provides on and off. You can quickly switch between "normal" mouse control and "Freelancer-like" mouse control, which can be handy at times.
The other change is that the "Boundary Limit" configuration attribute was removed, since it was basically redundant. The limit for mouse motion is now more simply defined by the sensitivity setting.
Installing this is the same as installing the normal scripted mouse (see link above). Just use the code below in the file instead of the normal mouse script.
Things it would be nice to improve:
- Transition between mouse modes can be a bit jarring. Smoothing this out would be a nice addition (my stab at it has so far failed)
- It would be nice to have more options for how to toggle than middle mouse button (such as using the keyboard)
data/tables/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("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 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()
mouse_center_x = scr_width / 2
mouse_center_y = scr_height / 2
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
togglescriptmouse = false
old_h = 0
old_p = 0
-- if file exists
if boolmousefileOK then
-- reset all the variables to nil
mousesensitivity = nil
mousesensitivitymode = nil
mousecontrolmode = nil
mousedeadzone = nil
mouseinvert = 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(sensitivity, center_x, center_y)
f_mouse_x = nil
f_mouse_y = nil
-- Do we go outside sensitivity zone
f_mouse_x = cap_value(center_x - sensitivity, center_x + sensitivity, mouse_x)
f_mouse_y = cap_value(center_y - sensitivity, center_y + sensitivity, mouse_y)
-- 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_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
-- get control values
mouse_x = io.getMouseX()
mouse_y = io.getMouseY()
controls = ba.getControlInfo()
-- if center mouse button hasn't been been pressed in long enough and is being pressed now
-- reset the mouse
if mouse_reset_counter > 0.33 and io.isMouseButtonDown(MOUSE_MIDDLE_BUTTON) then
togglescriptmouse = not togglescriptmouse
if togglescriptmouse == true then
controls.Heading = old_h
controls.Pitch = old_p
mouse_x = mouse_center_x + (mousesensitivity * old_h)
mouse_y = mouse_center_y + (mousesensitivity * old_p)
io.forceMousePosition(mouse_x, mouse_y)
end
mouse_reset_counter = 0
else
mouse_reset_counter = mouse_reset_counter + frametime
end
if togglescriptmouse == true then
ba.setControlMode(LUA_FULL_CONTROLS)
io.MouseControlStatus = false
if mousecontrolmode == 1 then
-- make sure we aint gonna go off the boundaries...
do_boundaries_check(mousesensitivity, mouse_center_x, mouse_center_y)
-- 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
drawpos_x = mouse_center_x + (current_h * mousesensitivity)
drawpos_y = mouse_center_y + (current_p * mousesensitivity)
-- draw cursor
draw_cursor()
end
else
ba.setControlMode(NORMAL_CONTROLS)
io.MouseControlStatus = true
old_h = cap_value(-1.0, 1.0, controls.Heading)
old_p = cap_value(-1.0, 1.0, controls.Pitch)
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
Also, here's a sample configuration file:
data/config/mouse_script.cfg
Sensitivity: 250
Sensitivity Curve: 1.0
Control Mode: 1
Deadzone: 2
Mouse Invert: 0
Indicator Color: 255, 255, 0, 50
-
Nice. :)
-
Related script: http://www.hard-light.net/forums/index.php/topic,44634.0.html (http://www.hard-light.net/forums/index.php/topic,44634.0.html)
Note that the script would only work if you have WLCoolman's Pre-commit Build, at least as far as I know.
Has anybody used this script before? Is there any significant differences between Nuke's code and Sushi's code?
-
my code kinda dates back to when scripting was kinda new and not quite set in its ways. im actually somewhat supprised that it still works. it also raped physics. wanderer did the second incarnation of the script which had much better features than what i had in mine. it also took advantages to new c code implemented by wanderer to give better access to input variables. sushi's script is the third incarnation, which should be the most up to date of all of the above. i havent used it yet, since i usually fly stick. so im not quite sure how it compares to the first two.
-
my code kinda dates back to when scripting was kinda new and not quite set in its ways. im actually somewhat supprised that it still works. it also raped physics. wanderer did the second incarnation of the script which had much better features than what i had in mine. it also took advantages to new c code implemented by wanderer to give better access to input variables. sushi's script is the third incarnation, which should be the most up to date of all of the above. i havent used it yet, since i usually fly stick. so im not quite sure how it compares to the first two.
The new feature is the in-mission toggle. It's basically the same as Wanderer's incarnation (the one on the wiki, linked in the first post) but the middle mouse button toggles the "freelancer-like-mouse" mode on and off instead of just re centering it. So (for example) you can fly with normal mouse control, then when you get into a turning fight where you would normally be dragging the mouse all over to keep turning, you could switch to joy-mouse mode and turn continuously without having to pick up and reset the mouse.
It was JR2's idea, and I thought it was a good one, so I went ahead and implemented it.
-
im trying to run your mouse codes... cant seem to get them running? im a coding idiot :(
tried PPjoy awhile ago, it worked but left me dizzy and nauseated since the movement isn't as smooth say as freelancer
(to my memory)
How to I make this work? lay man's please :)
-
im trying to run your mouse codes... cant seem to get them running? im a coding idiot :(
tried PPjoy awhile ago, it worked but left me dizzy and nauseated since the movement isn't as smooth say as freelancer
(to my memory)
How to I make this work? lay man's please :)
1. Open notepad. Paste in the first file (highlighted in green). Save the file as "mouse-sct.tbm"
2. Do the same thing for the second file, saving it as "mouse_script.cfg"
3. Go to your Freespace2 directory. Open the "data" folder, then the "tables" folder (create it if it does not exist). Put mouse-sct.tbm inside of data/tables.
4. Open or create a Freespace2/data/config directory and put mouse_script.cfg there.
5. Run the game with any reasonably recent build (including 3.6.12).
That's it! You should be able to toggle between regular mouse control and "freelancer-like" mouse control by clicking the middle mouse button.
-
Thanks sushiman!
Got the controls to work... will have the new controls "reviewed" by my younger brothers and cousins that i coerced to play freespace over 8 years ago!
I'll also give it a good run and see if i can adapt to using it as well. thanks!
-
I'm all for the joystick improvement but I think the activation would be better with a keyboard key. I have to break the bound of the middle mouse button (button 3) and restart the launcher to make it work. 'Shields Manager' script uses '0' to enable/disable itself and it works great.
Anyway this script needs work, its dynamic acceleration blows, the faster I move the mouse on the pad the slower the ship moves, it's backwards, but it has a future because I managed to get it close to what I want with this configuration:
Sensitivity: 362
Sensitivity Curve: 3.9
Control Mode: 1
Deadzone: 2
Mouse Invert: 0
Boundary Limit: 0
Indicator Color: 255, 255, 0, 64
but why I can't see the cursor? is that option removed? I can see the cursor in 'joystick mode' but is not what I expected, I like the concept but the functionality IMO should be the same as 'mouse mode' in the center, the approximation to a real joystick I don't think is useful at all, it requires to move the mouse like crazy. A Merge between both modes & with a reverse dynamic acceleration fix, would be IMO the perfect mouse driver, good enough to incorporate it into the next release of FS2O.
-
If it ever makes a release as an official part of FS2O, I think there are some who will commit mass homicide as they are afraid that the mouse's accuracy plus the joystick's ability to not have to stop turning every 2 seconds will put them at a disadvantage.
-
Those would the "5 guys" that can do goood with keyboard and only a little mouse. Old-school people, I used to be one of them but I grew up and I'm progress-wise oriented now.
-
The option to toggle via keyboard (probably just specify the key in the config) would be a nice feature. I don't have time to implement it right now though, so someone else will have to.
Can't speak to the dynamic acceleration bit, I didn't write that (it was part of the existing script).
-
Nuke did, right?
-
Nuke did, right?
I think the script originates with Nuke, although I think Wanderer may have worked on it too at some point.
-
Can somebody please give a quick "status report" on the implementation of this in FS2O?
-
Can somebody please give a quick "status report" on the implementation of this in FS2O?
It's working and you can use it right now?
-
Can somebody please give a quick "status report" on the implementation of this in FS2O?
It's working and you can use it right now?
You know what I meant.
-
No, I don't. What are you asking?
-
Ok, sorry then.
I know this already works with the scripting system (I use it). What I'd like to know is if it will actually be integrated into SCP as an option as it was voted.
-
...over the cold, bloodied bodies of the joystick elitists. :doubt:
-
Currently, the only thing standing in the way of most controls-related features is the way the pilot files are set up. Even though anyone can make a new control, they'll quickly run into the problem of not being able to save any mappings to it... meaning that players would not be able to change which key maps to the new control(s) like most of the other controls (excluding the F1 - F12 keys).
FSO version 3.7 will feature a new style of pilot file that will be future proof, which means versions 3.7 and later should be able to convert/load up any version of pilot file without hassle.
-
...over the cold, bloodied bodies of the joystick elitists. :doubt:
What gives you that idea?
The thing is, this feature is not on our (very loosely defined, not in any way binding) list of features we would like to have in FSO. As always, the most difficult thing in this regard is to find a programmer who cares enough to implement this.
-
The thing is, this feature is not on our (very loosely defined, not in any way binding) list of features we would like to have in FSO. As always, the most difficult thing in this regard is to find a programmer who cares enough to implement this.
So it was decided by the community that they didn't want this feature in FSO? Or you just mean the main coders?
-
The thing is, this feature is not on our (very loosely defined, not in any way binding) list of features we would like to have in FSO. As always, the most difficult thing in this regard is to find a programmer who cares enough to implement this.
So it was decided by the community that they didn't want this feature in FSO? Or you just mean the main coders?
All he means is that nobody has stepped up to code it in. (It won't make 3.6.16, certainly. Maybe somebody will pick it up for later.)
-
The thing is, this feature is not on our (very loosely defined, not in any way binding) list of features we would like to have in FSO. As always, the most difficult thing in this regard is to find a programmer who cares enough to implement this.
So it was decided by the community that they didn't want this feature in FSO? Or you just mean the main coders?
All he means is that nobody has stepped up to code it in. (It won't make 3.6.16, certainly. Maybe somebody will pick it up for later.)
I might give it a shot once 3.7 rolls out, due to reasons stated earlier.
-
...over the cold, bloodied bodies of the joystick elitists. :doubt:
What gives you that idea?
The thing is, this feature is not on our (very loosely defined, not in any way binding) list of features we would like to have in FSO. As always, the most difficult thing in this regard is to find a programmer who cares enough to implement this.
It was brought up some time ago and there was quite a bit of squealing. I can dig up the posts if you'd like.
-
id do it but allow that control method to be disabled by the host in multi. this should make elitest snobs happy and let everyone else use the features in sp and mp to their hearts content. i really dont care so long as ships cant outperform their table specs with any particular input device.
but yea this is a ways out. ive been waiting for some serious input upgrades for years, and likely will be waiting for years to come. 3.7 has always been the mantra.
-
id do it but allow that control method to be disabled by the host in multi. this should make elitest snobs happy and let everyone else use the features in sp and mp to their hearts content.
I... don't see how this control method would pose any "threat" to the "elitest snobs." But then again I'm not an elitest nor a snob so...
ive been waiting for some serious input upgrades for years
Where's your list? :D
-
buried under years of forum posts, i honestly dont remember half the things on it. but il give you the abridged version:
multiple sticks.
separate mouse binds from joystick binds (allow mouse+joystick configs).
alternate mouse modes (everything from mouse scripts).
reversible throttle axis (split forward/reverse axis or hold/toggle for reverse throttle button).
lateral/vertical thrust and freelook axes.
support for custom control functions (axes and buttons) to be defined so as to be used by scripted and sexped features. probibly best table defined and then accessible through hooks and sexps.
should point out that a lot of that stuff has been scripted to some degree. but configuring those scripts for personal preference is not very user friendly. hince the last idea. many have been around since the day the fs2 source had been released (and most of them aren't even exclusively mine).
-
Sushi, thank you so much for the script and for the instructions. This works perfectly in "BSG Diaspora" mod, but is there a way to make this work in the Babylon Project???
Anyone, please let me know how, because as it is right now, it won't work in Babylon.
-
You'd need a newer engine that supports scripting and works with TBP. IIRC BSG uses 3.6.9? So try using that build with TBP.
-
er... Diaspora would need a minimum of 3.6.18? Not 3.6.9?
-
Whoopsie. For some reason I mentally thought Beyond the Red Line instead. :ick:
-
:D
rockelino: the script should work with The Babylon Project if you grab the latest Zathras mod from this thread (http://www.hard-light.net/forums/index.php?topic=85449.0), then install the mouse script in the Zathras mod folder.
-
So... Is there's any simple way to map this toggle to space bar?
And even further, have 2 modes (switchable via cfg)-
1) key press toggles mouse joystick| classic mouse
2) mouse joustick by default, hold space bar to aim in classic mode
Apreciate your answers.
-
Sure thing, just have a go at modifying the script yourself. :)
-
Hi, I can't seem to get this to work. I did exactly this as suggested:
1. Open notepad. Paste in the first file (highlighted in green). Save the file as "mouse-sct.tbm"
2. Do the same thing for the second file, saving it as "mouse_script.cfg"
3. Go to your Freespace2 directory. Open the "data" folder, then the "tables" folder (create it if it does not exist). Put mouse-sct.tbm inside of data/tables.
4. Open or create a Freespace2/data/config directory and put mouse_script.cfg there.
5. Run the game with any reasonably recent build (including 3.6.12).
I've tried with a range of builds to no avail.
Any ideas?
-
Post a debug log please. Instructions can be found here (http://www.hard-light.net/forums/index.php?topic=56279.msg1180359#msg1180359)
-
This is for 3.7.0, is it ok to use this build?
[attachment deleted by an evil time traveler]
-
Thanks, me and DahBlount are looking into it now.
[Edit] It looks like FSO isn't even loading up mouse-sct.tbm. Are you sure you saved it as a .tbm and not a .txt?
Some editors, such as Microsoft's Notepad require you to change the file format, even if you put a file extension on the name.
Try using the two attached files. Place the mouse-sct.tbm in /data/tables/ and mouse_script.cfg in /data/config/
Note, to enable/disable the mouse-as-joy script in-game, you press the middle mouse button.
[attachment deleted by an evil time traveler]
-
SCRIPTING: Beginning initialization sequence...
SCRIPTING: Beginning Lua initialization...
LUA: Opening LUA state...
LUA: Initializing base Lua libraries...
LUA: Beginning ADE initialization
ADE: Initializing enumeration constants...
ADE: Assigning Lua session...
SCRIPTING: Beginning main hook parse sequence....
Wokka! Error opening file (scripting.tbl)!
TABLES: Unable to parse 'scripting.tbl'! Error code = 5.
It appears as though the Scripting table isn't being loaded properly, however it still attempted to load some sct.tbm files. The mouse-sct.tbm file did not appear during the parse so you should check to make sure that the files aren't saved as XXX.cfg.txt and XXX-sct.tbm.txt. I would recommend moving to a nightly build and downloading the MediaVPs 2014 as well.
-
Well, the name is mouse-sct.tbm, but it is a text file, I don't think I can save as any other type in notepad? Image attached.
Sorry if I'm being stupid. I'll try a nightly build.
[attachment deleted by an evil time traveler]
-
Turn on file extensions in windows, then just edit the filename in the folder where it lives.
-
In case you missed the edit:
Thanks, me and DahBlount are looking into it now.
[Edit] It looks like FSO isn't even loading up mouse-sct.tbm. Are you sure you saved it as a .tbm and not a .txt?
Some editors, such as Microsoft's Notepad require you to change the file format, even if you put a file extension on the name.
Try using the two attached files. Place the mouse-sct.tbm in /data/tables/ and mouse_script.cfg in /data/config/
Note, to enable/disable the mouse-as-joy script in-game, you press the middle mouse button.
-
Ah yes, I was indeed being stupid.
I only played for 2 minutes and already prefer it over normal mouse play.
Thank you both for your help.
-
Happens to the best of us, too. Happy fragging. ;)
-
sorry to necro so hard but if anyone's interested, here's a small modification of the code allow for keyboard toggle. the key for this toggle can be configured in the config file
#Conditional Hooks
$Application: FS2_Open
$On Mission Start:
[
keyrelease = false;
--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
elseif type == "p" then
return_array[1] = parse_string(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("Mouse Toggle Key:", mousefile, "p", use_same_line)
if temp_val == -2 then
break
elseif temp_val ~= -1 then
ba.print("\tMouse Toggle Key: " .. temp_arr[1] .. "\n")
ToggleKey = 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 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()
mouse_center_x = scr_width / 2
mouse_center_y = scr_height / 2
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
togglescriptmouse = false
old_h = 0
old_p = 0
-- if file exists
if boolmousefileOK then
-- reset all the variables to nil
mousesensitivity = nil
mousesensitivitymode = nil
mousecontrolmode = nil
mousedeadzone = nil
mouseinvert = nil
mousecolor = nil
ToggleKey = "d"
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(sensitivity, center_x, center_y)
f_mouse_x = nil
f_mouse_y = nil
-- Do we go outside sensitivity zone
f_mouse_x = cap_value(center_x - sensitivity, center_x + sensitivity, mouse_x)
f_mouse_y = cap_value(center_y - sensitivity, center_y + sensitivity, mouse_y)
-- 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_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 ---
------------------------
]
$State: GS_STATE_GAME_PLAY
$On Key Released: [
if hv.Key:lower() == ToggleKey then
keyrelease = true
end
]
$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
-- get control values
mouse_x = io.getMouseX()
mouse_y = io.getMouseY()
controls = ba.getControlInfo()
-- if center mouse button hasn't been been pressed in long enough and is being pressed now
-- reset the mouse
if mouse_reset_counter > 0.33 and keyrelease then
keyrelease = false
togglescriptmouse = not togglescriptmouse or keyhold
if togglescriptmouse == true then
controls.Heading = old_h
controls.Pitch = old_p
mouse_x = mouse_center_x + (mousesensitivity * old_h)
mouse_y = mouse_center_y + (mousesensitivity * old_p)
io.forceMousePosition(mouse_x, mouse_y)
end
mouse_reset_counter = 0
else
mouse_reset_counter = mouse_reset_counter + frametime
end
if togglescriptmouse == true then
ba.setControlMode(LUA_FULL_CONTROLS)
io.MouseControlStatus = false
if mousecontrolmode == 1 then
-- make sure we aint gonna go off the boundaries...
do_boundaries_check(mousesensitivity, mouse_center_x, mouse_center_y)
-- 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
drawpos_x = mouse_center_x + (current_h * mousesensitivity)
drawpos_y = mouse_center_y + (current_p * mousesensitivity)
-- draw cursor
draw_cursor()
end
else
ba.setControlMode(NORMAL_CONTROLS)
io.MouseControlStatus = true
old_h = cap_value(-1.0, 1.0, controls.Heading)
old_p = cap_value(-1.0, 1.0, controls.Pitch)
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
the config will look like this
Sensitivity: 250
Sensitivity Curve: 1.0
Control Mode: 1
Deadzone: 2
Mouse Invert: 1
Mouse Toggle Key: z
Indicator Color: 255, 255, 0, 50
-
And what about the use of quick-time events via scripted mouse events?
-
Do them in lua.
-
I know I'm necroing hard, but anyway: Is there some progress with this mouse script since 2016? I really like how it works, especially pink_supervisor's modification which supports keyboard instead of mouse middle button. However, is there any way to reset the mouse every time you press the toggle button? The way it works now, when you switch to standard mouse control (eg. for aiming), the cursor is messed up when you switch back. The ship usually starts turning like a mad dog in an unpredictable direction. One would say the script simply needs a line where it says to reset the mouse every time the toggle button is pressed. I can't script absolutely anything, but is there anybody who could improve this script, after all those years? In any other way I find it quite amazing.
-
The wiki version hasn't been edited either, so sadly no progress. Scripts often tend to get broken after a while, this would be another case. :(
-
FYI I've updated this script to work with recent nightlies, use fewer global variables, and also account for some more edge cases. If anyone wants a copy just let me know.
-
thanks wookieejedi, I'd definitely appreciate a copy, if you'd be so kind :nod:
-
Here ya go:
Use the key for '(Multiplayer) Message All' to toggle it (hint you can rebind that key to make it the middle mouse button). Just download that file and drop it in your tables folder.
[attachment eaten by a Shivan]
-
Hmm, maybe put it on MODDB or something? Just thinking forward. I've got a copy of the new file you just posted, so if anyone needs it I should be able to provide it if anything happens to wookieejedi's source.
-
Thanks, sounds good. It's actually on my GitHub page here, I just attached it so it was easier to DL:
https://github.com/wookieejedi/FSO-Scripts/tree/master/Joystick-Mouse (https://github.com/wookieejedi/FSO-Scripts/tree/master/Joystick-Mouse)
-
Thank you! This is indeed an amazing work! There´s just one thing: In "joystick" mode a can see the standard in-game cursor. Shouldn´t it be invisible?
-
That's a good question, and while ideally it should be invisible that's the only way I could get the re-centering to work. When I hide the cursor the re-centering no longer worked, thus I figured it was an okay tradeoff to allow the cursor to stay :)
-
Any way to make the cursor a transparent color when in joystick mode?
-
I'll check. It would require an extra file to be downloaded, but if it does work then it would definitely make it worth it.
-
Okay actually found another way to do it, now the cursor is hidden.
Git link if attachment ever goes away: https://github.com/wookieejedi/FSO-Scripts/tree/master/Joystick-Mouse (https://github.com/wookieejedi/FSO-Scripts/tree/master/Joystick-Mouse)
-
Sweet, thanks!
-
I´m sorry to bother, but I keep getting a startup error with the most recent tbl:
[string "mouse-sct.tbm - On Game Init"]:415: 'end' expected (to close 'function' at line 407) near '<eof>'
------------------------------------------------------------------
ADE Debug:
------------------------------------------------------------------
------------------------------------------------------------------
------------------------------------------------------------------
stack traceback:
------------------------------------------------------------------
1: Userdata [Controls]
2: Userdata [Audio]
3: Userdata [Base]
4: Userdata [BitOps]
5: Userdata [CFile]
6: Userdata [Graphics]
7: Userdata [HookVariables]
8: Userdata [HUD]
9: Userdata [Mission]
10: Userdata [Campaign]
11: Userdata [Options]
12: Userdata [Parsing]
13: Userdata [Tables]
14: Userdata [Testing]
15: Userdata [Time]
16: Userdata [UserInterface]
17: Userdata [Unicode]
------------------------------------------------------------------
-
Thanks for letting me know! I fixed it on Git, and here's the new version:
[attachment eaten by a Shivan]
-
Thanks for letting me know! I fixed it on Git, and here's the new version:
Thanks, this one works! The cursor´s still blinking from time to time, but it´s by far the best mouse-to-joystick so far. Great work, great thanks :yes:
-
Yeah, there wasn't really a feasible way to fix that slight flickering, which isn't too bad as you mentioned. Glad it's useful for you!
-
If you found a way to hide the cursor, isn't it flicking in / out some sort of bug? Or is it a byproduct of the way it was hidden?
-
Bit of a by-product the way it was hidden. Honestly in my tests I didn't see any flickering, but it is possible I suppose that it could flicker somewhat randomly on other machines if the FPS slightly changes (the cursor flickering would not be a constant thing, and from the report seems like it happens very sporadically).
-
Bit of a by-product the way it was hidden. Honestly in my tests I didn't see any flickering, but it is possible I suppose that it could flicker somewhat randomly on other machines if the FPS slightly changes (the cursor flickering would not be a constant thing, and from the report seems like it happens very sporadically).
So capping the FPS or locking it in some way should fix it?
-
Possibly...I'm not entirely sure since I couldn't reproduce the bug on my end to test if FPS capping would work. I should note that I do play the game with FPS capped.