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