This works, more or less. I love owning stuff with only my guns. By the way, Prometheus R sucks, I'd rather take on fighters with the Akheton SDG.
#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.cfg"
boolmousefileOK = cf.fileExists(filename_mouse, "data/", false)
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", "data/")
-- 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
debugfile = cf.openFile("/home/eigenlambda/debugfile", "w")
]
$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 or mousecontrolmode == 2 then
-- make sure we aint gonna go off the boundaries...
do_boundaries_check(mouseboundaries)
-- end of boundaries check
if mousecontrolmode == 1 then
-- 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)
-- 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
-- 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
if mousecontrolmode == 2 then --airquake mouse mode
debugfile:write("1")
debugfile:flush()
if inited == nil then
plr = hv.Player
cpos = plr.Position + plr.Orientation:rotateVector( ba.createVector(0,-15,-75) )
ccam = gr.createCamera("ccam", cpos, plr.Orientation)
gr.setCamera(ccam)
inited = true
end
debugfile:write("2")
debugfile:write("\n")
debugfile:flush()
if inited == true then
-- the documentation says getVectorFromCoords gives you a normal
-- vector, but the code says it's a normal vector + camera pos
wanted_dir = gr.getVectorFromCoords(mouse_x, mouse_y) - cpos
-- camera alway points towards where the mouse is
-- just like any other first-person shoter
delta = ccam.Orientation:rotateVector(wanted_dir):getOrientation()
ccam:setOrientation(ccam.Orientation*delta)
io.forceMousePosition(scr_width/2, scr_height/2)
cpos = plr.Position + plr.Orientation:unrotateVector( ba.createVector(0,15,-50) )
ccam:setPosition(cpos)
gr.setColor(255,255,255)
-- now let's try to make the player point the same direction
local_wanted_dir = plr.Orientation:rotateVector(wanted_dir)
local_wanted_dir = local_wanted_dir / local_wanted_dir:getMagnitude()
-- compute the cross product with <0,0,1> by hand
xdiff = local_wanted_dir.y
ydiff = -local_wanted_dir.x
-- the magnitude of the cross product is the sine of angle between the vectors
theta = math.asin(math.sqrt(xdiff*xdiff + ydiff+ydiff))
costheta = local_wanted_dir.z -- this was the dot product with <0,0,1>
-- these are needed for everything that follows
rotvel = plr.Physics.RotationalVelocity
rvx = rotvel.x
rvy = rotvel.y
if costheta < 0 then
-- obtuse angle between camera and ship forward
if theta == 0 then
-- pointing in the exact opposite direction
-- so, go in the direction that we're already rotating, fast
-- if we're not rotating, start as quickly as possible
rvr = math.sqrt(rvx*rvx + rvy*rvy)
if rvr == 0 then
controls.Heading = 1
controls.Pitch = 1
else
controls.Heading = 5*rvy
controls.Pitch = 5*rvx
end
else
controls.Heading = -5*ydiff
controls.Pitch = -5*xdiff
end
else
-- ok, heres some theory to explain what happens next
-- next frame's rotvel is calculated as
-- apply_physics( rotdamp, pi->desired_rotvel.xyz.x,
-- pi->rotvel.xyz.x, sim_time,
-- &new_vel.xyz.x, NULL );
-- controls.Heading and controls.Pitch can have
-- values between -1 and 1, from which desired_rotvel
-- is calculated as that number times the maximum
-- rotational speed around the axis in question.
-- rotdamp is a single scalar that determines how fast
-- rotvel becomes desired_rotvel by exponential decay:
-- (rotvel - desired_rotvel)*exp(-frametime/rotdamp)
maxrv = plr.Physics.RotationalVelocityMax
maxrvx = maxrv.x
maxrvy = maxrv.y
rotdamp = plr.Physics.RotationalVelocityDamping
frametime = ba.getFrametime()
-- we need the sign of these for later calculations
if rvx < 0 then
rvxs = -1
else
rvxs = 1
end
if rvy < 0 then
rvys = -1
else
rvys = 1
end
if xdiff < 0 then
xsign = -1
else
if xdiff > 0 then
xsign = 1
else
xsign = 0
end
end
if ydiff < 0 then
ysign = -1
else
if ydiff > 0 then
ysign = 1
else
ysign = 0
end
end
-- i'm not sure about this part
xangle = math.asin(xdiff)
yangle = math.asin(ydiff)
-- so now we calculate how long it will take to center the controls
-- using the integral of rotational momentum assuming full acceleration
-- ignoring the exponential term, which should go away quickly enough
-- i hope
timetocenterx = xsign*(xangle + rotdamp*(xsign + rvx))
timetocentery = ysign*(yangle + rotdamp*(ysign + rvy))
-- how quickly can we stop by applying full reverse?
-- this is much easier, so it can be exact
timeto0x = rotdamp*math.log(-rvxs*maxrvx/(-rvxs*maxrvx+rvx))
timeto0y = rotdamp*math.log(-rvys*maxrvy/(-rvys*maxrvy+rvy))
-- rotate unless we're going to overshoot
-- if so, stop rotating as quickly as possible
if yangle*ysign > .2 or timetocentery > timeto0y then
controls.Heading = -ysign
else
x = math.exp(-frametime/rotdamp)
forceto0 = rvy*x/(1-x) / maxrvy
controls.Heading = -forceto0
end
if xangle*xsign > .1 or timetocenterx > timeto0x then
controls.Pitch = -xsign
else
x = math.exp(-frametime/rotdamp)
forceto0 = rvx*x/(1-x) / maxrvx
controls.Pitch = -forceto0
end
end
-- now ensure that the ship is banked correctly
-- in the future, this should capture whatever keys the player
-- uses to bank and adjust the camera first with them
up = ba.createVector(0,1,0)
camup = ccam.Orientation:rotateVector(up)
plrup = plr.Orientation:rotateVector(up)
should_be_forward = camup:getCrossProduct(plrup)
controls.Bank = should_be_forward.z
-- lastly, fix the HUD
-- first kill the annoying gauges
hu.setHUDGaugeColor( 9,0,0,0,0) --reticle center
hu.setHUDGaugeColor(23,0,0,0,0) --target mini icon
hu.setHUDGaugeColor(19,0,0,0,0) --threat gauge
hu.setHUDGaugeColor( 6,0,0,0,0) --throttle gauge
hu.setHUDGaugeColor(20,0,0,0,0) --afterburner energy
hu.setHUDGaugeColor(21,0,0,0,0) --weapons energy
-- then replace them
gaugey = math.floor(.6*scr_height)
gr.setColor(200, 200, 0, 100)
energy_fraction = plr.WeaponEnergyLeft/plr.WeaponEnergyLeft
gr.drawRectangle(0, gaugey+1, 100*energy_fraction, gaugey+9)
burn_fraction = plr.AfterburnerFuelLeft/plr.AfterburnerFuelMax
gr.drawRectangle(0, gaugey+11, 100*burn_fraction, gaugey+19)
speed = math.floor(plr.Physics:getForwardSpeed()+.5)
gr.drawString(speed, 100, gaugey+11)
if plr.PrimaryTriggerDown then
gr.setColor(100, 0, 0, 64)
gr.drawCircle(5, 105, gaugey+5)
end
-- make aim indicators
vec300 = ba.createVector(0,0,300)
vec1000 = ba.createVector(0,0,1000)
aim300 = plr.Position + plr.Orientation:unrotateVector(vec300)
aim1000 = plr.Position + plr.Orientation:unrotateVector(vec1000)
x,y = aim1000:getScreenCoords()
gr.setColor(150,150,150,150)
if x ~= nil and x ~= false then
gr.drawLine(x+4,y+4,x-4,y-4)
gr.drawLine(x+4,y-4,x-4,y+4)
end
x,y = aim300:getScreenCoords()
if x ~= nil and x ~= false then
gr.drawRectangle(x-6,y-6,x+6,y+6,false)
end
-- now tell the hud to draw
hu.HUDDrawn = true
debugfile:write("5")
debugfile:flush()
end
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