Finally, a new release.

This fixes the 'aqmouse does nothing when the computer isn't slow enough' bug. It also provides a method to toggle suspending aqmouse control- hold the middle mouse button for more than 100ms, and also provides an improved reticle that shows you where your shots are going to be when they reach the distance to your target.

as always, put aqmouse-sct.tbl in $FS2_DIR/aqmouse/data/tables and use -mod whateverelse,aqmouse

`$State: GS_STATE_GAME_PLAY`

$On Frame:

[

frametime = ba.getFrametime()

if middle_button_time == nil then

middle_button_time = 0

end

if io.isMouseButtonDown(MOUSE_MIDDLE_BUTTON) then

middle_button_time = middle_button_time + frametime

else

middle_button_time = 0

end

-- if the middle button is pressed for more that .1s,

-- toggle suspension of aqmouse

if middle_button_time > .1 then

if suspended then

suspended = false

else

suspended = true

inited = false

gr.setCamera()

end

end

if suspended then

gr.setColor(255,255,255)

gr.drawString("aqmouse suspended",0,0)

else

-- if the setting changes, take note of it to set it back later

-- in order to avoid stepping on the users toes too much

if io.MouseControlStatus == true then

mouse_reset_on_end = true

io.MouseControlStatus = false

end

-- get control values

mouse_x = io.getMouseX()

mouse_y = io.getMouseY()

controls = ba.getControlInfo()

if not inited 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

scr_width = gr.getScreenWidth()

scr_height = gr.getScreenHeight()

else

-- 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)

clocate = ba.createVector(0,15,-50)

cpos = plr.Position + ccam.Orientation:unrotateVector(clocate)

ccam:setPosition(cpos)

-- 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

rvxs = sign(rvx)

rvys = sign(rvy)

xsign = sign(xdiff)

ysign = sign(ydiff)

-- the angle is the inverse sine of the cross product

xangle = math.asin(xdiff)

yangle = math.asin(ydiff)

-- how quickly can we stop by applying full reverse?

timeto0x = rotdamp*math.log(-rvxs*maxrvx/(-rvxs*maxrvx+rvx))

timeto0y = rotdamp*math.log(-rvys*maxrvy/(-rvys*maxrvy+rvy))

-- x ~= x is how you check for NaN in lua

-- we will get NaN as math.log(0) when rvx == 0, so rvxs == 0

if timeto0x ~= timeto0x then

timeto0x = 0

end

if timeto0y ~= timeto0y then

timeto0y = 0

end

-- how far do we go until we stop

-- integral of rotational velocity from now until timeto0x from now

-- assuming full acceleration against the direction we're going in

angleto0x = -rvxs*maxrvx*timeto0x + rotdamp*(-rvxs*maxrvx*timeto0x-rvx)*(math.exp(-timeto0x/rotdamp)-1)

angleto0y = -rvys*maxrvy*timeto0y + rotdamp*(-rvys*maxrvy*timeto0y-rvy)*(math.exp(-timeto0y/rotdamp)-1)

-- calculate how fast to rotate

xfactor = math.exp(-frametime/rotdamp)

if yangle*ysign > angleto0y*ysign then

controls.Heading = -(rvy - (yangle-rvy*frametime)/(rotdamp*(xfactor-1)))/maxrvy

else

forceto0 = rvy*xfactor/(1-xfactor) / maxrvy

controls.Heading = -forceto0

end

if xangle*xsign > angleto0x*xsign then

controls.Pitch = -(rvx - (xangle-rvx*frametime)/(rotdamp*(xfactor-1)))/maxrvx

else

forceto0 = rvx*xfactor/(1-xfactor) / 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.WeaponEnergyMax

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

-- now to make the aim gauge. this tells you where on screen your

-- shots are going to be when they get out to the target distance

gr.setColor(0, 255, 0, 255)

if plr.Target then

r = (plr.Target.Position - plr.Position):getMagnitude()

aimr = plr.Position + plr.Orientation:unrotateVector(ba.createVector(0,0,r))

x,y = aimr:getScreenCoords()

if x ~= false then

gr.drawLine(x-9,y-9,x-6,y-9,false)

gr.drawLine(x-9,y-9,x-9,y-6,false)

gr.drawLine(x-9,y+9,x-6,y+9,false)

gr.drawLine(x-9,y+9,x-9,y+6,false)

gr.drawLine(x+9,y-9,x+6,y-9,false)

gr.drawLine(x+9,y-9,x+9,y-6,false)

gr.drawLine(x+9,y+9,x+6,y+9,false)

gr.drawLine(x+9,y+9,x+9,y+6,false)

end

end

-- now tell the hud to draw

hu.HUDDrawn = 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

inited = false -- this line should not be needed

]

#End