Hard Light Productions Forums

FreeSpace Releases => Scripting Releases => Topic started by: Nuke on January 18, 2007, 06:44:41 am

Title: remote controlled turrets revisited
Post by: Nuke on January 18, 2007, 06:44:41 am
i revamped the script to run on current builds. fly a ship with a turret01a (medusa works) while using this script. switch to outside view. now you can manipulate and fire the turret with the mouse. now there is a problem im just not figuring out. so long as your ship is in its default orientation (its position as placed in fred) it works fine. but you roll or turn into some funky position and your aim goes way off. anyone have any ideas?

Code: [Select]
#Global Hooks
$GameInit:
[

w = gr.getScreenWidth()
h = gr.getScreenHeight()
cx = w/2
cy = h/2

if w >= 1024 then
wf = w / 1024
hf = h / 768
awh = (wf + hf) / 2
hires = true
else
wf = w / 640
hf = h / 480
awh = ((wf + hf) / 2) * 0.625
hires = false
end

mousejoy = function(deadzone) --mousejoy function, returns a value from -1 to 1 depending on the mouse's position
local X = io.getMouseX()
local Y = io.getMouseY()

if hires then
X = (X / 511.5) - 1
Y = (Y / 383.5) - 1
else
X = (X / 319.5) - 1
Y = (Y / 239.5) - 1
end

local Mx = X --theese are for the menu, -1 to 1 without deadzone applied
local My = Y

local tweak = 1 / (1 - deadzone)

if X < deadzone and X > -deadzone then
X=0
else
if X > 0 then
X = (X - deadzone) * tweak
elseif X < 0 then
X = (X + deadzone) * tweak
end
end

if Y < deadzone and Y > -deadzone then
Y=0
else
if Y > 0 then
Y = (Y - deadzone) * tweak
elseif Y < 0 then
Y = (Y + deadzone) * tweak
end
end

return X, Y, Mx, My
end

mousegauge = function(eks,why) --just a bunch of loops to draw the various hashes for the gauges
gr.setColor(150,255,150,200) --big hashes

for i=cx-(54*awh), cx+(54*awh), 12*awh do
gr.drawLine(i,cy - (108*awh),i,cy - (96*awh))
end
for i=cy-(54*awh), cy+(54*awh), 12*awh do
gr.drawLine(cx - (108*awh),i,cx - (96*awh),i)
end

gr.setColor(50,255,50,150) --small hashes

for i=cx-(48*awh), cx+(48*awh), 12*awh do
gr.drawLine(i,cy - (108*awh),i,cy - (100*awh))
end
for i=cy-(48*awh), cy+(48*awh), 12*awh do
gr.drawLine(cx - (108*awh),i,cx - (100*awh),i)
end

gr.setColor(200,200,255,255) --indicators

gr.drawCircle(7.5*awh,cx+(eks*54*awh),cy-(104*awh))
gr.drawCircle(7.5*awh,cx-(104*awh),cy+(why*54*awh))
end

]
$Simulation:
[

player = mn.Ships["Alpha 1"]
X,Y,U,V = mousejoy(0.1)

if player:isValid() then
pgun = player["turret01a"]

ori = pgun.Orientation
ori.h = ori.h + X *2*ba.getFrametime()
pgun.Orientation = ori

ori = pgun.GunOrientation
ori.p = ori.p + Y *2*ba.getFrametime()

if ori.p > 0 then
ori.p = 0
elseif ori.p < -math.pi/2 then
ori.p = -math.pi/2
end

pgun.GunOrientation = ori

if io.isMouseButtonDown(MOUSE_LEFT_BUTTON) then
pgun:fireWeapon(1, 1000)
end
end

]
$HUD:
[

mousegauge(X, Y)

]
#End
Title: Re: remote controlled turrets revisited
Post by: Herra Tohtori on January 18, 2007, 07:00:27 am
i revamped the script to run on current builds. fly a ship with a turret01a (medusa works) while using this script. switch to outside view. now you can manipulate and fire the turret with the mouse. now there is a problem im just not figuring out. so long as your ship is in its default orientation (its position as placed in fred) it works fine. but you roll or turn into some funky position and your aim goes way off. anyone have any ideas?

Code: [Select]
#Global Hooks
$GameInit:
[

w = gr.getScreenWidth()
h = gr.getScreenHeight()
cx = w/2
cy = h/2

if w >= 1024 then
wf = w / 1024
hf = h / 768
awh = (wf + hf) / 2
hires = true
else
wf = w / 640
hf = h / 480
awh = ((wf + hf) / 2) * 0.625
hires = false
end

mousejoy = function(deadzone) --mousejoy function, returns a value from -1 to 1 depending on the mouse's position
local X = io.getMouseX()
local Y = io.getMouseY()

if hires then
X = (X / 511.5) - 1
Y = (Y / 383.5) - 1
else
X = (X / 319.5) - 1
Y = (Y / 239.5) - 1
end

local Mx = X --theese are for the menu, -1 to 1 without deadzone applied
local My = Y

local tweak = 1 / (1 - deadzone)

if X < deadzone and X > -deadzone then
X=0
else
if X > 0 then
X = (X - deadzone) * tweak
elseif X < 0 then
X = (X + deadzone) * tweak
end
end

if Y < deadzone and Y > -deadzone then
Y=0
else
if Y > 0 then
Y = (Y - deadzone) * tweak
elseif Y < 0 then
Y = (Y + deadzone) * tweak
end
end

return X, Y, Mx, My
end

mousegauge = function(eks,why) --just a bunch of loops to draw the various hashes for the gauges
gr.setColor(150,255,150,200) --big hashes

for i=cx-(54*awh), cx+(54*awh), 12*awh do
gr.drawLine(i,cy - (108*awh),i,cy - (96*awh))
end
for i=cy-(54*awh), cy+(54*awh), 12*awh do
gr.drawLine(cx - (108*awh),i,cx - (96*awh),i)
end

gr.setColor(50,255,50,150) --small hashes

for i=cx-(48*awh), cx+(48*awh), 12*awh do
gr.drawLine(i,cy - (108*awh),i,cy - (100*awh))
end
for i=cy-(48*awh), cy+(48*awh), 12*awh do
gr.drawLine(cx - (108*awh),i,cx - (100*awh),i)
end

gr.setColor(200,200,255,255) --indicators

gr.drawCircle(7.5*awh,cx+(eks*54*awh),cy-(104*awh))
gr.drawCircle(7.5*awh,cx-(104*awh),cy+(why*54*awh))
end

]
$Simulation:
[

player = mn.Ships["Alpha 1"]
X,Y,U,V = mousejoy(0.1)

if player:isValid() then
pgun = player["turret01a"]

ori = pgun.Orientation
ori.h = ori.h + X *2*ba.getFrametime()
pgun.Orientation = ori

ori = pgun.GunOrientation
ori.p = ori.p + Y *2*ba.getFrametime()

if ori.p > 0 then
ori.p = 0
elseif ori.p < -math.pi/2 then
ori.p = -math.pi/2
end

pgun.GunOrientation = ori

if io.isMouseButtonDown(MOUSE_LEFT_BUTTON) then
pgun:fireWeapon(1, 1000)
end
end

]
$HUD:
[

mousegauge(X, Y)

]
#End

It sounds like you're missing a co-ordinate conversion from ship-relative to global XYZ co-ordinates in some point. It doesn't matter as long as ship's axes are aligned with global co-ordinate axes, but when they arent, it screws things up.

What does the turret orientation function do? Does it return turret's alignment vector in relation to global co-ordinates or in relation to ship-relative co-ordinates?
Title: Re: remote controlled turrets revisited
Post by: Nuke on January 18, 2007, 04:23:58 pm
ok, all the important stuff is in $Simulation: everything else is just my usual vars for multires and mouse functions, same from my mouse script. all they do is return mouse coords in a -1 to 1 format.

essentially it lets you move your turret, base with mouse x and gun with mouse y. pgun.Orientation is the orientation of the turret base in p,b,h. its read, stored in a var, which is modified then put back. this is for the turret base yaw. it does the same thing for the barrel object, pgun.GunOrientation, but it locks it to 90 degrees. what i dont understand is why the turret rotation can work fine, yet the firing normal is somehere else. as far as i know, GunOrientation is also supposed to affect the turret normal.
Title: Re: remote controlled turrets revisited
Post by: WMCoolmon on January 20, 2007, 02:27:57 am
Basically it looks like the problem is in aiturret.cpp

Code: [Select]
ship_get_global_turret_gun_info(&Objects[parent_objnum], ss, &gpos, &gvec, use_angles, &predicted_enemy_pos);

// Fire in the direction the turret is facing, not right at the target regardless of turret dir.
vm_vec_sub(&v2e, &predicted_enemy_pos, &gpos);

"gvec" appears to be the direction that the turret is actually facing. It's used for checks about whether the weapon can fire or not. However, the actual firing vector used is the vector from the turret to the enemy. Because the decision to fire is based on the actual turret position, it doesn't cause a gross inaccuracy (Like firing from the turret's ass), but if you're seeing a minor inaccuracy in your tests, that might just be it.

I think I might be able to fix this easily, but I have to proceed carefully, since this particular segment of code is used everytime a turret is fired, and the last time turrets were broken, nobody spoke up for months. :rolleyes:
Title: Re: remote controlled turrets revisited
Post by: Nuke on January 20, 2007, 06:57:58 am
well when it all merges youl also have to shuffel in your turret changes with bobs. turrets will just need to be scrutinized more when code freeze time comes. if it helps i got a screenshot of the orientation matric being applies, the top 3 rows are for the base and the bottom 3 are for the gun. the first 3 rows are the matrix row 4 is the p'h'b and row 5 is row 4 converted to degrees. i was thinking that the matrix was merely incomplete, but if it was then why is the turret rotating properly, regaurdless of the ships orientation.



[attachment deleted by admin]
Title: Re: remote controlled turrets revisited
Post by: Bobboau on January 20, 2007, 09:23:05 am
oh, my god you have no idea how ****ed up the turret\subobject rotation system is. the turrets have copys of matraceise made from the positions of there guns used to figure out were there target is but not to rotate the model there are like four seperate matraciese that are for diferent aspects of that (when all of this could be handled by one) and then I added another matrix into the mess fortunately I blocked it off whenever I could (and WOW was that ever a hack). and there is always the ever present issue of the agnles2matrix function being about as acurate as rolling a rock down a mountainside.

my code should be all in now, so he's going to have to deal with it post merge, wich is better for both of us realy.
Title: Re: remote controlled turrets revisited
Post by: Nuke on January 20, 2007, 09:42:08 am
well im sorta thinking about what id need to do fully scripted turrets which dont even touch the internal c code. rc turrets are doable as is but the trickey part would be to interface a scripted turret with ai. i sorta want some functions that use orientations, like createWeapon() to have the option of using a normal instead. i really dont think anyone would notice if a prometheus shot is on its side, or a missile either. also cameras would be better if handeled by normals, then you can just set the normal to whatever you want to "film" and maybe another to say which end is up, sorta like a tripod axis. ive spent the last 3 or 4 days trying to understand the math behind matricies and i still dont get it.

anyway i was meaning to ask you bob if that thing in your turret build that lets us set the front, up and side axes is used to create an orientation matrix. if so id love to have that function in scripting. i dont need to understand matricies if i have a function that makes one for me.
Title: Re: remote controlled turrets revisited
Post by: Bobboau on January 20, 2007, 09:58:28 am
well, it's a commonly used function within the code base, actualy it's such a minor thing I think the actual function doesn't get used that much.

if I knew how to make a function with optional parameters for LUA I'd have it done by the time it took ne to write this responce.

in the code getting/setting an fvec is literaly matrix.fvec,

there is a vm_vector_2_matrix(matrix *m,vec3d *fvec,vec3d *uvec,vec3d *rvec) function you'd probly like access too as well (the nice thing about that function is the last two parameters can be set to NULL and it'll fake them for you)
Title: Re: remote controlled turrets revisited
Post by: Nuke on January 20, 2007, 10:09:39 am
im not really sure if most of the built in functions im calling are written in c or in lua. anyway alot of stuff i want to do requires manupulatiion of spacial stuff, theese include:

ils carrier landing
atmospheric flight physics
battlemechs :D
freelancer style flight/turret control
blindfire weps
rtt panel gauges/working controls
ect.
Title: Re: remote controlled turrets revisited
Post by: WMCoolmon on January 20, 2007, 09:31:14 pm
if I knew how to make a function with optional parameters for LUA I'd have it done by the time it took ne to write this responce.

You use a pipe (|) along with the normal format characters, so for a function like you're thinking, you'd do something like:

Code: [Select]
ade_get_args(L, "o|oo", l_Vector.Get(&fvec), l_Vector.Get(&uvec), l_Vector.Get(&rvec));
Everything after the pipe is considered as optional by Lua, and the variables are left alone unless they're set to something.
Title: Re: remote controlled turrets revisited
Post by: Bobboau on January 20, 2007, 10:32:42 pm
so how do I tell how many parameters were passed
Title: Re: remote controlled turrets revisited
Post by: WMCoolmon on January 21, 2007, 02:24:26 am
ade_get_args always returns the number of arguments gotten, or 0 in the case of a critical error (missing required argument or required argument with an invalid type).

However there is one bit of an oddity when using it. If the modder passes an argument of the wrong type to an optional argument, ade_get_args will act as if no argument was passed (besides passing an error as well). So it's a good idea to get in the habit of setting optional variables to something either obviously invalid or reasonable (if there is no invalid value), and checking for NULLity on all pointers. Besides doing something bizarre with an array to allow individual variables, I didn't see any better way to handle optional variables of the wrong type. I can certainly implement that functionality if it's needed, but I'd like to see a case first.

In this case:
0 (something seriously wrong, "." probably used instead of ":")
1 (fvector object was valid)
2 (fvector object && (u vector object was valid and specified OR r vector object was valid and specified))
3 (fvector, u vector, and r vector object were valid and specified)

However Lua will throw an error if the fvector object and the rvector object were specified, but the uvector object was set to nil. This is changeable, of course, but would require adding additional syntax to ade_get_args and complexity to the function definition. It's something I thought about, but never finished, but I figured you could in theory do something like this:
Code: [Select]
ade_get_args(L, "o|[ol]o", l_Vector.Get(&fvec), l_Vector.Get(&uvec), NULL, l_Vector.Get(&rvec));
But again, I'd want to see a (in this case compelling) need for the functionality.
Title: Re: remote controlled turrets revisited
Post by: Nuke on January 25, 2007, 04:03:04 am
heh, they work!

remember fly with a medusa and aim with the mouse and use this build (http://fs2source.warpcore.org/temp/wmc/sfo_fix.zip)

its not perfect, it will fire a maxim no matter what, it doesnt actually fire the turret but rather creates a weapon paralell to its bore. the sight could stand for some work and the controls are abit touchey.

Code: [Select]
#Global Hooks
$GameInit:
[

w = gr.getScreenWidth()
h = gr.getScreenHeight()
cx = w/2
cy = h/2

if w >= 1024 then
wf = w / 1024
hf = h / 768
awh = (wf + hf) / 2
hires = true
else
wf = w / 640
hf = h / 480
awh = ((wf + hf) / 2) * 0.625
hires = false
end

mousejoy = function(deadzone) --mousejoy function, returns a value from -1 to 1 depending on the mouse's position
local X = io.getMouseX()
local Y = io.getMouseY()

if hires then
X = (X / 511.5) - 1
Y = (Y / 383.5) - 1
else
X = (X / 319.5) - 1
Y = (Y / 239.5) - 1
end

local Mx = X --theese are for the menu, -1 to 1 without deadzone applied
local My = Y

local tweak = 1 / (1 - deadzone)

if X < deadzone and X > -deadzone then
X=0
else
if X > 0 then
X = (X - deadzone) * tweak
elseif X < 0 then
X = (X + deadzone) * tweak
end
end

if Y < deadzone and Y > -deadzone then
Y=0
else
if Y > 0 then
Y = (Y - deadzone) * tweak
elseif Y < 0 then
Y = (Y + deadzone) * tweak
end
end

return X, Y, Mx, My
end

mousegauge = function(eks,why) --just a bunch of loops to draw the various hashes for the gauges
gr.setColor(150,255,150,200) --big hashes

for i=cx-(54*awh), cx+(54*awh), 12*awh do
gr.drawLine(i,cy - (108*awh),i,cy - (96*awh))
end
for i=cy-(54*awh), cy+(54*awh), 12*awh do
gr.drawLine(cx - (108*awh),i,cx - (96*awh),i)
end

gr.setColor(50,255,50,150) --small hashes

for i=cx-(48*awh), cx+(48*awh), 12*awh do
gr.drawLine(i,cy - (108*awh),i,cy - (100*awh))
end
for i=cy-(48*awh), cy+(48*awh), 12*awh do
gr.drawLine(cx - (108*awh),i,cx - (100*awh),i)
end

gr.setColor(200,200,255,255) --indicators

gr.drawCircle(7.5*awh,cx+(eks*54*awh),cy-(104*awh))
gr.drawCircle(7.5*awh,cx-(104*awh),cy+(why*54*awh))
end

printmatrix = function(ori,v) --function to help understand the mystyries of the orientation matrix
gr.setColor(200,200,200,200)
gr.drawString(ori[1],150,100+v)
gr.drawString(ori[2],300,100+v)
gr.drawString(ori[3],450,100+v)
gr.drawString(ori.p, 600,100+v)
gr.drawString(ori.p*180/math.pi,800,100+v)
gr.drawString(ori[4],150,115+v)
gr.drawString(ori[5],300,115+v)
gr.drawString(ori[6],450,115+v)
gr.drawString(ori.h, 600,115+v)
gr.drawString(ori.h*180/math.pi,800,115+v)
gr.drawString(ori[7],150,130+v)
gr.drawString(ori[8],300,130+v)
gr.drawString(ori[9],450,130+v)
gr.drawString(ori.b, 600,130+v)
gr.drawString(ori.b*180/math.pi,800,130+v)
end

]
$Simulation:
[

player = mn.Ships["Alpha 1"]
X,Y,U,V = mousejoy(0.15)

if player:isValid() then
pgun = player["turret01a"]

thing0 = player.Position + player.Orientation:unrotateVector(pgun.Position)

bori = pgun.Orientation
thing1 = bori:unrotateVector(ba.createVector(0,0,-100))

bori.h = bori.h + X * ba.getFrametime()
pgun.Orientation = bori

gori = pgun.GunOrientation
gori.p = gori.p + Y * ba.getFrametime()

if gori.p > 0 then
gori.p = 0
elseif gori.p < -math.pi/2 then
gori.p = -math.pi/2
end

pgun.GunOrientation = gori

thing2 = gori:unrotateVector(ba.createVector(0,100,0))
thing2 = bori:unrotateVector(thing2)

thing1 = player.Orientation:unrotateVector(thing1) + thing0
thing2 = player.Orientation:unrotateVector(thing2) + thing0

thing3 = (player.Orientation:unrotateVector(ba.createVector(0,0,1)) - thing0) + thing2

if io.isMouseButtonDown(MOUSE_LEFT_BUTTON) then
mn.createWeapon(tb.WeaponClasses["Maxim"],thing3:getOrientation(),thing0,player,-1)
end
end

]
$HUD:
[

mousegauge(X, Y)

if thing2:getScreenCoords() then
local b,e = thing2:getScreenCoords()
gr.setColor(0,100,200,74)
gr.drawCircle(9,b*wf,e*hf)
end

--testfuncs
--printmatrix(bori,0)
--printmatrix(gori,75)
--printmatrix(player.Orientation,150)

]
#End


i also got blindfire working, even though its a total bastardization of the above code, full of atrocities which would frighten even dave b himself i dare not post it :D
Title: Re: remote controlled turrets revisited
Post by: Gregster2k on January 27, 2007, 04:28:21 am
Nuke, you are crazy, but awesomely so. Soon in the not so distant future we will have Starlancer running on the FS2_Open engine. :drevil:

<3 scripting.
Title: Re: remote controlled turrets revisited
Post by: Nuke on January 27, 2007, 01:29:11 pm
i can also do freelancer style flight. but im gonna need to come up with a better way to convert 2d screen coords to a 3d vector.
Title: Re: remote controlled turrets revisited
Post by: Scooby_Doo on January 27, 2007, 11:21:56 pm
heh, they work!

remember fly with a medusa and aim with the mouse and use this build (http://fs2source.warpcore.org/temp/wmc/sfo_fix.zip)

its not perfect, it will fire a maxim no matter what, it doesnt actually fire the turret but rather creates a weapon paralell to its bore. the sight could stand for some work and the controls are abit touchey.

Code: [Select]
#Global Hooks
$GameInit:
[

w = gr.getScreenWidth()
h = gr.getScreenHeight()
cx = w/2
cy = h/2

if w >= 1024 then
wf = w / 1024
hf = h / 768
awh = (wf + hf) / 2
hires = true
else
wf = w / 640
hf = h / 480
awh = ((wf + hf) / 2) * 0.625
hires = false
end

mousejoy = function(deadzone) --mousejoy function, returns a value from -1 to 1 depending on the mouse's position
local X = io.getMouseX()
local Y = io.getMouseY()

if hires then
X = (X / 511.5) - 1
Y = (Y / 383.5) - 1
else
X = (X / 319.5) - 1
Y = (Y / 239.5) - 1
end

local Mx = X --theese are for the menu, -1 to 1 without deadzone applied
local My = Y

local tweak = 1 / (1 - deadzone)

if X < deadzone and X > -deadzone then
X=0
else
if X > 0 then
X = (X - deadzone) * tweak
elseif X < 0 then
X = (X + deadzone) * tweak
end
end

if Y < deadzone and Y > -deadzone then
Y=0
else
if Y > 0 then
Y = (Y - deadzone) * tweak
elseif Y < 0 then
Y = (Y + deadzone) * tweak
end
end

return X, Y, Mx, My
end

mousegauge = function(eks,why) --just a bunch of loops to draw the various hashes for the gauges
gr.setColor(150,255,150,200) --big hashes

for i=cx-(54*awh), cx+(54*awh), 12*awh do
gr.drawLine(i,cy - (108*awh),i,cy - (96*awh))
end
for i=cy-(54*awh), cy+(54*awh), 12*awh do
gr.drawLine(cx - (108*awh),i,cx - (96*awh),i)
end

gr.setColor(50,255,50,150) --small hashes

for i=cx-(48*awh), cx+(48*awh), 12*awh do
gr.drawLine(i,cy - (108*awh),i,cy - (100*awh))
end
for i=cy-(48*awh), cy+(48*awh), 12*awh do
gr.drawLine(cx - (108*awh),i,cx - (100*awh),i)
end

gr.setColor(200,200,255,255) --indicators

gr.drawCircle(7.5*awh,cx+(eks*54*awh),cy-(104*awh))
gr.drawCircle(7.5*awh,cx-(104*awh),cy+(why*54*awh))
end

printmatrix = function(ori,v) --function to help understand the mystyries of the orientation matrix
gr.setColor(200,200,200,200)
gr.drawString(ori[1],150,100+v)
gr.drawString(ori[2],300,100+v)
gr.drawString(ori[3],450,100+v)
gr.drawString(ori.p, 600,100+v)
gr.drawString(ori.p*180/math.pi,800,100+v)
gr.drawString(ori[4],150,115+v)
gr.drawString(ori[5],300,115+v)
gr.drawString(ori[6],450,115+v)
gr.drawString(ori.h, 600,115+v)
gr.drawString(ori.h*180/math.pi,800,115+v)
gr.drawString(ori[7],150,130+v)
gr.drawString(ori[8],300,130+v)
gr.drawString(ori[9],450,130+v)
gr.drawString(ori.b, 600,130+v)
gr.drawString(ori.b*180/math.pi,800,130+v)
end

]
$Simulation:
[

player = mn.Ships["Alpha 1"]
X,Y,U,V = mousejoy(0.15)

if player:isValid() then
pgun = player["turret01a"]

thing0 = player.Position + player.Orientation:unrotateVector(pgun.Position)

bori = pgun.Orientation
thing1 = bori:unrotateVector(ba.createVector(0,0,-100))

bori.h = bori.h + X * ba.getFrametime()
pgun.Orientation = bori

gori = pgun.GunOrientation
gori.p = gori.p + Y * ba.getFrametime()

if gori.p > 0 then
gori.p = 0
elseif gori.p < -math.pi/2 then
gori.p = -math.pi/2
end

pgun.GunOrientation = gori

thing2 = gori:unrotateVector(ba.createVector(0,100,0))
thing2 = bori:unrotateVector(thing2)

thing1 = player.Orientation:unrotateVector(thing1) + thing0
thing2 = player.Orientation:unrotateVector(thing2) + thing0

thing3 = (player.Orientation:unrotateVector(ba.createVector(0,0,1)) - thing0) + thing2

if io.isMouseButtonDown(MOUSE_LEFT_BUTTON) then
mn.createWeapon(tb.WeaponClasses["Maxim"],thing3:getOrientation(),thing0,player,-1)
end
end

]
$HUD:
[

mousegauge(X, Y)

if thing2:getScreenCoords() then
local b,e = thing2:getScreenCoords()
gr.setColor(0,100,200,74)
gr.drawCircle(9,b*wf,e*hf)
end

--testfuncs
--printmatrix(bori,0)
--printmatrix(gori,75)
--printmatrix(player.Orientation,150)

]
#End


i also got blindfire working, even though its a total bastardization of the above code, full of atrocities which would frighten even dave b himself i dare not post it :D

Keep working on the blindfire! I know I'll need and Saga will need it for their Excalibur  :)
Title: Re: remote controlled turrets revisited
Post by: Nuke on January 28, 2007, 02:33:14 am
im gonna have to rethink the blindfire mode. i need to find out if bobs turret stuff got compiled into one of wmcs scripting builds. im gonna set up blindfire so it has to run on a forward facing multi or single part turret. this makes the movement alot smoother cause its not undergoing a yx rotation. now i dont need to use turrets at all for blindfire. infact for your standard blindfire i could do it entirely with mn.createWeapon(). the reason i want to use turrets is so that i can do gimballed gatling guns. nothing like a big honking sixpack throwing its weight around. :D

also  i plan to do everything in an advanced weapons suite. which would support everything from blindfire (with and without turrets), freelacer mode (it will use parts of my mouse script), commandable turrets, and maybe even bolt on turret support. il have all my functions in a main script and a bunch of tbms for each feature. im also gonna use some config files for some of the features. that way it should make using the features in a mod alot easyer.

unfortunately for the next few days i gotta be at work. so im not really gonna do any scripting till like tuesday.
Title: Re: remote controlled turrets revisited
Post by: Nuke on January 31, 2007, 07:59:04 am
i created a cool little function to turn mouse coords (from my joymouse function), into a normal.

Code: [Select]
mjtonormal = function(X,Y) --converts mousejoy coords into a 3d normal, i think
local Z = (1 - math.abs(X)) * (1 - math.abs(Y))
local N = ba.createVector(X,Y,Z)
local nf = 1 / (N:getMagnitude())

N = N * nf

return N
end

*fixed a bug


it can likewise also turn an objects screen coords to a normal, assuming theyre scaled on a -1 to 1 range. this is mainly for freelancer/rc turret mode. for blindfire i can do some vector math, subtract one ships position from the other to get a vector to it and thin normalize it. normalizing a vector is fairly easy devide 1 by the magnatude of your vector and multiply the result with the vector.

now i need to figure out how to interpolate normals. i can get the normals of where i want the gun to face, but i need to set up the turret so that it always tries to make itself point along that normal. it would be very easy to directly tie in the turret rotation with the given normal. but i want to intrepolate it so that it takes time for the turret to lign up. in other words it needs to animate.
Title: Re: remote controlled turrets revisited
Post by: Mav on February 07, 2007, 04:19:09 pm
Looks like there's a lot of good developements happening here  8) :yes: .


But - just a short idea - :   For blindfire (as in the WC3 Excalibur) - couldn't one just FRED it? I mean, mounting the gun bank on a turret instead of as primary bank of the ship itself, and then setting the turret to locked by default, only unlocking it while the player presses the trigger... ?

That way the usual turret code would take care of directions and such (of course being only as accurate as usual turrets; well, then set the turret-ai to highest level if you wish a good-aiming blindfire :) ) .

(Actually, I think I already have a ship that could use it ;) - the model's only an alpha version right now, though.)


So, would this be an idea? Or would this make things too unwieldy?
For ai-ships one shouldn't need the FRED stuff, as they'll anyway fire at what they want.

Of course, the turret would need to aim at the players target - what I think it does in retail, but I seem to remember a discussion about that to be changed - which is of course a good idea for most other turret uses, but for this use, one would need to be able to specify the turret to use the old target-selection routines, should newer ones be implemented.
Title: Re: remote controlled turrets revisited
Post by: Nuke on February 08, 2007, 08:16:21 am
you could but it would feel less like a hack unless you scripted it in. this way i can not only have blindfire but also manually aimable guns for player flown capships and bombers, commandable turrets, i can even put a turret on a ship that doesnt have one. i also wouldnt trust freespac's artifitial stupidity and atrocious turret code to do my aiming for me. :D plus the added bonus is you dont have to crowd your level with sexps, especially difficult if you want the feature top be presistand throughout your entire campaign.
Title: Re: remote controlled turrets revisited
Post by: takashi on March 29, 2007, 07:14:15 pm
i would love a function that makes your ship AI controlled when you controll the turret, and vice versa. with a turret view.

maybe in 3.7.90.....
Title: Re: remote controlled turrets revisited
Post by: Nuke on March 29, 2007, 08:29:45 pm
why when you can do both at once :D
Title: Re: remote controlled turrets revisited
Post by: WMCoolmon on April 02, 2007, 02:59:19 pm
Nuke, what would be the idea function(s) for optimizing a script like this? I was thinking that a pointTurretAt3DPoint() function would be useful for something like this, and for other things. (Like a cutscene where you want a small ship to fly by a larger ship, while all of the larger ship's turrets track the smaller ship). But the more math I can move into the C environment, the faster the script will go.
Title: Re: remote controlled turrets revisited
Post by: Nuke on April 03, 2007, 01:03:55 am
that woyuld be awesome. currently, im using loop to go through the subsystems and check $name string in the subsystems properties for a #pt. if it finds it it will then look for other options in the name string like the rotation speed and the manual control flag. all this data is passed to the turret function which loops through the arrays and does all the math involved in manipulating the turret. big thing is im not actually firing the turret, im creating a weapon projectile with createWeapon(). im using about 6-8 calls of un/rotatesVector() per turret. using the script on a ship like the aeolas will essentially half your framerate. so doing 120 lines worth of scripot in a single function would be a hell of alot faster. volition's hackish turret code might be a mess but its a hell of alot faster than what i can do with script.
Title: Re: remote controlled turrets revisited
Post by: WMCoolmon on April 03, 2007, 02:25:42 am
Do you have a script example posted?

I'd like to make it a little more usable than just a "run_Nukes_script_43" function in scripting. Something like "force turret target point" and then have a little point object you can create and move around (which I believe is already in the code) and move all the attached turrets. That way you'd just have to calculate the one 3D point based on the current mouse position. I don't know how you're doing it now.
Title: Re: remote controlled turrets revisited
Post by: Nuke on April 03, 2007, 05:13:44 am
heres the latest version, im still trying to fix the functions that i broke during my attempt to optimise it. its also full of other experemental stuff too. but it should give you an idea of what ive been up to. im not sure it will even run in this condition. should run on your new build. just remember to put #pt (#pt-m for manual mode, not sure if thats currently working though) into the name string in the subobject properties.

Code: [Select]
#Global Hooks
$GameInit:
[
--[[=============================]]--
--[[======= function defs =======]]--
--[[=============================]]--

-------------------------------
----------screen vars----------
-------------------------------

setscreenvars = function() --scalers and constants for multi res support
local w = gr.getScreenWidth()
local h = gr.getScreenHeight()
local cx = w/2
local cy = h/2
local wf = 0
local hf = 0
local awh = 0
local hires = false

if w >= 1024 then
wf = w / 1024
hf = h / 768
awh = (wf + hf) / 2
hires = true
else
wf = w / 640
hf = h / 480
awh = ((wf + hf) / 2) * 0.625
hires = false
end

return w,h,cx,cy,wf,hf,awh,hires
end

----------------------------
----------controls----------
----------------------------

mousejoy = function(deadzone) --mousejoy function, returns a value from -1 to 1 depending on the mouse's position
local X = io.getMouseX()
local Y = io.getMouseY()

if hires then
X = (X / 511.5) - 1
Y = (Y / 383.5) - 1
else
X = (X / 319.5) - 1
Y = (Y / 239.5) - 1
end

if deadzone == 1 then --now supports full on and full off mode
return 0,0,X,Y
elseif deadzone == 0 then
return X,Y,X,Y
else
local Mx = X --theese are for the menu, -1 to 1 without deadzone applied
local My = Y
local tweak = 1 / (1 - deadzone)

if X < deadzone and X > -deadzone then
X=0
else
if X > 0 then
X = (X - deadzone) * tweak
elseif X < 0 then
X = (X + deadzone) * tweak
end
end

if Y < deadzone and Y > -deadzone then
Y=0
else
if Y > 0 then
Y = (Y - deadzone) * tweak
elseif Y < 0 then
Y = (Y + deadzone) * tweak
end
end

return X, Y, Mx, My
end
end

mjtonormal = function(X,Y) --converts screen coords to normal
N = ba.createVector(X * 0.741 ,-Y * 0.741 * (h/w) ,1)
N = normalize(N) --make its length 1, otherwise its not a normal
return N
end

-------------------------
----------Maths----------
-------------------------

round = function(number) --rounds to nearest whole number, for some stupid reason, lua doesnt have one
local W,F = math.modf(number)
if F < 0 then
if F <= -0.5 then W = W - 1 end
else
if F >= 0.5 then W = W + 1 end
end

return W
end

normalize = function(norm) --takes a vector and scales it to a length of 1
local len = math.sqrt( (norm.x^2) + (norm.y^2) + (norm.z^2) )
norm = norm / len
return norm
end

multmat = function(mat1,mat2) --multiply a couple 3x3 matricies
local mat3 = {}

mat3[1] = (mat1[1] * mat2[1]) + (mat1[2] * mat2[4]) + (mat1[3] * mat2[7])
mat3[2] = (mat1[1] * mat2[2]) + (mat1[2] * mat2[5]) + (mat1[3] * mat2[8])
mat3[3] = (mat1[1] * mat2[3]) + (mat1[2] * mat2[6]) + (mat1[3] * mat2[9])
mat3[4] = (mat1[4] * mat2[1]) + (mat1[5] * mat2[4]) + (mat1[6] * mat2[7])
mat3[5] = (mat1[4] * mat2[2]) + (mat1[5] * mat2[5]) + (mat1[6] * mat2[8])
mat3[6] = (mat1[4] * mat2[3]) + (mat1[5] * mat2[6]) + (mat1[6] * mat2[9])
mat3[7] = (mat1[7] * mat2[1]) + (mat1[8] * mat2[4]) + (mat1[9] * mat2[7])
mat3[8] = (mat1[7] * mat2[2]) + (mat1[8] * mat2[5]) + (mat1[9] * mat2[8])
mat3[9] = (mat1[7] * mat2[3]) + (mat1[8] * mat2[6]) + (mat1[9] * mat2[9])

return mat3
end

appmat = function(mat,vec) --apply a matrix
local x = (mat[1] * vec[1]) + (mat[2] * vec[2]) + (mat[3] * vec[3])
local y = (mat[4] * vec[1]) + (mat[5] * vec[2]) + (mat[6] * vec[3])
local z = (mat[7] * vec[1]) + (mat[8] * vec[2]) + (mat[9] * vec[3])

vec[1],vec[2],vec[3] = x,y,z

return vec
end

prirotpoint = function(vec,angs) --rotates a point around principle axes
local matx = {1,0,0,0,1,0,0,0,1}
local maty = {1,0,0,0,1,0,0,0,1} --create 3x3 matrix arrays for xyz and fill it in with an identity matrix
local matz = {1,0,0,0,1,0,0,0,1}

matx[5] = math.cos(angs[1])
matx[6] = math.sin(angs[1])
matx[8] = -math.sin(angs[1])
matx[9] = math.cos(angs[1])

maty[1] = math.cos(angs[2])
maty[3] = -math.sin(angs[2]) --fill in the nessicary parts of the matrix for each axis
maty[7] = math.sin(angs[2])
maty[9] = math.cos(angs[2])

matz[1] = math.cos(angs[3])
matz[2] = math.sin(angs[3])
matz[4] = -math.sin(angs[3])
matz[5] = math.cos(angs[3])

local mat = multmat(matx,maty) --multiply our matrixies
mat = multmat(mat,matz) --to get total matrix
vec = appmat(mat,vec) --apply the matrix
return vec
end

rotpoint = function(vec,ang,axis) --rotate around arbitrary axis, axis is a normal defining axis of rotation, ang is amount
local mat = {}

local c = math.cos(ang)
local s = math.sin(ang)
local t = 1 - c

mat[1] = t * axis[1]^2 + c
mat[2] = t * axis[1] * axis[2] + s * axis[3]
mat[3] = t * axis[1] * axis[3] - s * axis[2]

mat[4] = t * axis[1] * axis[2] - s * axis[3]
mat[5] = t * axis[2]^2 + c
mat[6] = t * axis[2] * axis[3] + s * axis[1]

mat[7] = t * axis[1] * axis[3] + s * axis[2]
mat[8] = t * axis[2] * axis[3] - s * axis[1]
mat[9] = t * axis[3]^2 + c

vec = appmat(mat,vec) --apply the matrix
return vec
end

---------------------------------------
----------procedural graphics----------
---------------------------------------

blindfirereticle = function(x,y)
x, y = x*wf, y*hf

gr.setColor(192,192,64,200)

gr.drawGradientLine(x + (8*awh), y, x + (2*awh), y )
gr.drawGradientLine(x - (8*awh), y, x - (2*awh), y )
gr.drawGradientLine(x, y + (8*awh), x, y + (2*awh) )
gr.drawGradientLine(x, y - (8*awh), x, y - (2*awh) )
end

mousereticle = function(x,y)
x, y = x*wf, y*hf

gr.setColor(32,32,50,50)
gr.drawCircle(12*awh,x,y)
gr.setColor(64,64,96,200)

for i=0, 359, 1 do
rot = i * (math.pi/180)
gr.drawPixel(x + (math.sin(rot)*12*awh), y + (math.cos(rot)*12*awh) )
end

gr.setColor(96,96,144,255)
gr.drawPixel(x,y)
end

prograderet = function(x,y,vel)
x, y = x*wf, y*hf

gr.setColor(72,192,72,222)

gr.drawGradientLine(x + (12*awh), y + (12*awh), x + (6*awh), y + (6*awh) )
gr.drawGradientLine(x - (12*awh), y - (12*awh), x - (6*awh), y - (6*awh) )
gr.drawGradientLine(x - (12*awh), y + (12*awh), x - (6*awh), y + (6*awh) )
gr.drawGradientLine(x + (12*awh), y - (12*awh), x + (6*awh), y - (6*awh) )

vel = tostring(vel)

gr.setColor(128,192,128,222)
gr.drawString(vel, x - (gr.getStringWidth(vel) / 2), y - (2*awh) )
end

----------------------------------
----------test functions----------
----------------------------------


printmatrix = function(ori,v) --function to help understand the mystyries of the orientation matrix
gr.setColor(200,200,200,200)
gr.drawString(ori[1],150,100+v)
gr.drawString(ori[2],300,100+v)
gr.drawString(ori[3],450,100+v)
gr.drawString(ori.p, 600,100+v)
gr.drawString(ori.p*180/math.pi,800,100+v)
gr.drawString(ori[4],150,115+v)
gr.drawString(ori[5],300,115+v)
gr.drawString(ori[6],450,115+v)
gr.drawString(ori.h, 600,115+v)
gr.drawString(ori.h*180/math.pi,800,115+v)
gr.drawString(ori[7],150,130+v)
gr.drawString(ori[8],300,130+v)
gr.drawString(ori[9],450,130+v)
gr.drawString(ori.b, 600,130+v)
gr.drawString(ori.b*180/math.pi,800,130+v)
end

printvector = function(vec, hpos, vpos)
gr.drawString(vec.x,hpos - 200 , vpos)
gr.drawString(vec.y,hpos, vpos)
gr.drawString(vec.z,hpos + 200 , vpos)
end


------------------------------------
--------general fire control--------
------------------------------------


plotlead = function(weaponvel, plr, tgt, retvec) --lead function, complements of wanderer, slightly modified
local targetpos = tgt.Position
local targetvel = tgt.Physics.Velocity
local lenghttargetvel = targetvel:getMagnitude()
local playerpos = plr.Position
local plrtotrg = playerpos - targetpos
local lenghtplrtotrg = plrtotrg:getMagnitude()
local trgangle = plrtotrg:getDotProduct(targetvel)
local a = (( weaponvel * weaponvel ) - ( lenghttargetvel * lenghttargetvel ))
local b = ( 2 * trgangle )
local c = -( lenghtplrtotrg * lenghtplrtotrg )
local discrim = ((b * b) - 4 * a * c)
local leadx = 0
local leady = 0

if discrim >= 0 and a ~= 0 then
local multipl1 = (( -b + math.sqrt(discrim)) / ( 2 * a))
local multipl2 = (( -b - math.sqrt(discrim)) / ( 2 * a))
local targetmult = nil

if multipl1 >=0 and multipl1 <= multipl2 and multipl2 >= 0 then
targetmult = multipl1
elseif multipl1 >=0 and multipl2 < 0 then
targetmult = multipl1
elseif multipl2 >=0 then
targetmult = multipl2
else
targetmult = nil
end

if targetmult ~= nil then
local leadvel = targetvel/(1/targetmult)
local leadpos = targetpos + leadvel

if retvec then --sometimes i want a vector rather than a screen coord
return leadpos
elseif leadpos:getScreenCoords() ~= false then
leadx, leady = leadpos:getScreenCoords() --rather than just simply draw the coords, il scale and return them so my code can **** with them
leadx = leadx * wf --drawleadreticle(leadx,leady) pft, my way is better :D
leady = leady * hf --theese factors make things so much easyer
return leadx, leady, leadpos --yep, thats what i need there
else
return -1, -1, leadpos --return -1-1 if this all fails, so it doesnt tweak my math
end
end
    end
end

nukelead = function(tgt, srcv, wvel) --pretty much the same math as wandereds, but reduced in size
local epos = tgt.Position
local evel = tgt.Physics.Velocity
local vlen = evel:getMagnitude()
local edis = srcv - epos
local dlen = edis:getMagnitude()
local trig = edis:getDotProduct(evel)
local a = (wvel^2) - (vlen^2)
local b = trig * 2
local c = -(dlen^2)
local d = (b^2) - 4 * a * c

if d >= 0 and a ~= 0 then
local m1 = ( -b + math.sqrt(d) ) / ( 2 * a)
local m2 = ( -b - math.sqrt(d) ) / ( 2 * a)

if (m1 >= 0 and m1 <= m2 and m2 >= 0) or (m1 >= 0 and m2 < 0) then
return epos + ( evel / (1 / m1) )
elseif m2 >=0 then
return epos + ( evel / (1 / m2) )
else
return epos
end
else
return epos
end
end


getwepvel = function(player)
local banks = player.PrimaryBanks
local vel = 0

if banks.Linked then
local div = 0
local num = #banks

for i=1, num do
vel = vel + banks[i].WeaponClass.Speed
div = div + 1
end

vel = vel / div
else
vel = banks[1].WeaponClass.Speed
end

return vel
end

----------------------------
--------turret funcs--------
----------------------------

getturretsubs = function(player) --returns a list of turet subobject numbers and other options
local curnum = 1
local gunnums = {} --subsystem indices
local arms = {} --p/sbank weaponclasses
local foregun = {} --this option tells turrets to gimbal forward, and within what cone, for ships like apis with turreted blindfire
local mantarg = {} --uses manual targeting
local trackrate ={} --turret tracking rate

for i=1, #player do
local ssname = player[i].Name
if string.find(ssname, "#pt") then --use the built in lua funcs or die!
gunnums[curnum] = i

if player[i].PrimaryBanks:isValid() then
arms[curnum] = player[i].PrimaryBanks[1].WeaponClass --only supporting the first s or p bank
elseif player[i].SecondaryBanks:isValid() then
arms[curnum] = player[i].SecondaryBanks[1].WeaponClass --maybe more later
else
arms[curnum] = tb.WeaponClasses["@Subach HL-7"] --incase nothihng works, we still have good ol hl7
end

local a,cone = string.find(ssname, "-f")
if a ~= nil then
foregun[curnum] = tonumber(string.sub(ssname, cone+1, cone+3))
end

if string.find(ssname, "-m") then mantarg[curnum] = true else mantarg[curnum] = false end

local b,rate = string.find(ssname, "-r")
if b ~= nil then
trackrate[curnum] = tonumber(string.sub(ssname, rate+1, rate+3))
else
trackrate[curnum] = 10
end

curnum = curnum + 1
end
end

return gunnums, arms, foregun, mantarg ,trackrate
end


getturretgunpos = function(player,tsub) --find the turret firing point
local pos = player.Position + player.Orientation:unrotateVector(tsub.Position) + tsub.GunPosition
local top = nil

if tsub.Position.y + tsub.GunPosition.y >= tsub.Position.y then
top = true
else
top = false
end

return pos,top
end


getturretangs = function(pori,ppos,tpos,top) --find the angles the turret must rotate to hit a location
local tpos = tpos - ppos --subtract player from tpos to get the player at center
local tpos = pori:rotateVector(tpos) --bring coorsd into player space (tm), now its a 2d problem

local hyp = math.sqrt( (tpos.z^2) + (tpos.x^2) ) --get hypotenuce, tpos.z is opposite and tpos.x is adjacent
local yawangle = math.acos(tpos.z/hyp) --use acos to determine rotation
if tpos.x < 0 then yawangle = -yawangle end --turn it around if its backwards, now lets figure gun pitch

local opp = math.sqrt( (tpos.x^2) + (tpos.z^2) ) --figure out our adjacet in order to get our hypotenuce
hyp = math.sqrt( (tpos.y^2) + (opp^2) ) --this time tpos.y is our adjacent
local pitchangle = math.asin(opp/hyp)
if (top and tpos.y < 0) or (top == false and tpos.y >= 0) then
pitchangle = -pitchangle --give a negative pitch value if the guns are not in the turret arc
end --we can use this later for forward facing freelancer style turrets

gr.drawString(math.deg(yawangle),100,100)
gr.drawString(math.deg(pitchangle),100,120)
return yawangle, pitchangle
end


getturretnorm = function(player,tsub,top) --gets turret firing normal
local gnorm = nil

if top then
gnorm = ba.createVector(0,1,0)
else
gnorm = ba.createVector(0,-1,0)
end

gnorm = tsub.GunOrientation:unrotateVector(gnorm) --unrotate the up vector to the gun
gnorm = tsub.Orientation:unrotateVector(gnorm) --then unrotate the gun normal to the base
gnorm = player.Orientation:unrotateVector(gnorm) --then to the ship

return gnorm --were done
end


fireturret = function(plr,wep,pos,dir) --fires the guns, simple for now
if io.isMouseButtonDown(MOUSE_LEFT_BUTTON) then
mn.createWeapon(wep,dir:getOrientation(),pos,plr,-1)
end
end


rcturret = function(player,target) --ship player, str turret name, bool underside gun, weaponclass
local guns,tweps,fore,manual,track = getturretsubs(player) --get our subobject numbers for our weapons, and options too

if guns[1] ~= nil then --bail if no turrets
for i=1, #guns do
local gun = guns[i]
local gpnt, top = getturretgunpos(player, player[gun]) --find firing point and wether its an upper turret or lower turret
local tpos = nil
local wep = tweps[i]
local dis = wep.Speed

if manual[i] then
tpos = mjtonormal(U,V)
tpos = player.Orientation:unrotateVector(tpos)

if target:isValid() then
dis = target.Position:getDistance(gpnt)
tpos = player.Position + ( tpos * dis ) --converge on target
else
tpos = gpnt + ( tpos * dis ) --no target, go straight
end
else
if target:isValid() then
dis = target.Position:getDistance(gpnt)
tpos = nukelead(target, gpnt, wep.Speed) --find target lead solution if needed
else
tpos = gpnt + player.Orientation:unrotateVector(ba.createVector(0,0,1)) --or just fire sgraight if no target
end
end

local bh, gp = getturretangs(player.Orientation ,gpnt ,tpos, top) --calculate gun pitch and heading in order to hit target

--[[if fore[i] and top then
local cone = fore[i] * math.pi/180 --keep forguns pointed inside the cone

gp = gp + math.pi
bh = bh + math.pi

gr.drawString(bh,100,100)

if gp < (math.pi/2) - cone then
gp = (math.pi/2) - cone
elseif gp > (math.pi/2) + cone then
gp = (math.pi/2) + cone
end

if bh > math.pi + cone then
bh = math.pi + cone
elseif bh < math.pi - cone then
bh = math.pi - cone
end

elseif fore[i] and top == false then


else]]

if top then --limit our pitch for upper and lower guns
--if gp > 0 then gp = 0 end
else
--gp = gp + math.pi
bh = bh + math.pi
--if gp > math.pi/2 then gp = math.pi/2 end
end

local bori = player[gun].Orientation --rotate base

-- local radis = bori.h - bh

-- if radis < 0 then
-- if radis < -math.pi then radis = -(radis + math.pi) end
-- else
-- if radis > math.pi then radis = -(radis - math.pi) end
-- end

-- if radis > 0.02 then
-- bori.h = bori.h - (0.8 * ba.getFrametime())
-- if bori.h < -math.pi then bori.h = bori.h + (math.pi*2) end
-- elseif radis < -0.02 then
-- bori.h = bori.h + (0.8 * ba.getFrametime())
-- if bori.h > math.pi then bori.h = bori.h - (math.pi*2) end
-- else
bori.h = bh
-- end

player[gun].Orientation = bori

local gori = player[gun].GunOrientation --rotate gun

-- radis = gori.p - gp

-- if radis < 0 then
-- if radis < -math.pi then radis = -(radis + math.pi) end
-- else
-- if radis > math.pi then radis = -(radis - math.pi) end
-- end

-- if radis > 0.02 then
-- gori.p = gori.p - (0.8 * ba.getFrametime())
-- if gori.p < -math.pi then gori.h = gori.h + (math.pi*2) end
-- elseif radis < 0.02 then
-- gori.p = gori.p + (0.8 * ba.getFrametime())
-- if gori.p > math.pi then gori.h = gori.h - (math.pi*2) end
-- else
gori.p = gp
-- end

player[gun].GunOrientation = gori

local aim = getturretnorm(player, player[gun], top) * dis --aim normal

fireturret(player,wep,gpnt,aim)

aim = gpnt + aim

if aim:getScreenCoords() then blindfirereticle(aim:getScreenCoords()) end
end
end
end


-------------------------------
--------blindfire funcs--------
-------------------------------

getblindfireguns = function() --returns a list of all guns with blindfire. theese are the dummy weapons that tell when and where to launch a real one
local num = 1
local weaps = {}
local cones = {}
local autos = {}

for i=1, #mn.Weapons do
local wepname = mn.Weapons[i].Class.Name

if string.find(wepname, "#bf") then
weaps[num] = mn.Weapons[i]

local cone, cvar = string.find(wepname, "-c") --cone is just a place holder as i only need the second number, but i can use the var later

if cvar ~= nil then
cone = tonumber( string.sub(wepname, cvar+1, cvar+3) ) --get the two numbers after the -c tag and convert them to number
else
cone = 10 --if the tag isnt in the weapon name, use a default of 15
end

cones[num] = cone

if string.find(wepname, "-a") then autos[num] = false else autos[num] = true end

num = num + 1
end
end

return weaps, cones, autos --list of weapon objects
end


blindfire = function(plr, tgt) --like the one for turrets sept for standrard guns
local guns, cones, autos = getblindfireguns()

if guns[1] ~= nil then
local tvec = nil

for i=1, #guns do
local gpos = guns[i].Position
local cone = math.cos( cones[i] * math.pi / 180 )
local man = autos[i]

if man then
tvec = mjtonormal(U,V)
if tvec.z < cone then tvec = ba.createVector(0,0,1) end
tvec = plr.Orientation:unrotateVector(tvec)
else
if tgt:isValid() then
tvec = nukelead(tgt,gpos,guns[i].Class.Speed)
tvec = tvec - gpos

local tvec2 = normalize( plr.Orientation:rotateVector(tvec) )
if tvec2.z < cone then tvec = plr.Orientation:unrotateVector( ba.createVector(0,0,1) ) end
else
tvec = plr.Orientation:unrotateVector(ba.createVector(0,0,1)) --if our target doesnt exist, feed it some bull
end
end

local wpn = guns[i].Class.Name --get our weapons name
local wnend = string.find(wpn, "#")
wpn = string.sub(wpn, 1, wnend-1) --remove everything after and including #
local newgun = tb.WeaponClasses[wpn] --now get the regular weaponclass

mn.createWeapon(newgun,tvec:getOrientation(),gpos,plr,-1)

guns[i].LifeLeft = 0.0
end
end
end

--[[===============================================]]--
--[[======= function calls and initial vars =======]]--
--[[===============================================]]--

w,h,cx,cy,wf,hf,awh,hires = setscreenvars()

]
$Simulation:
[

player = mn.Ships["Alpha 1"]

if player:isValid() then target = player.Target end

if io.isMouseButtonDown(MOUSE_RIGHT_BUTTON) then
X,Y,U,V = mousejoy(1)
else
X,Y,U,V = mousejoy(0)
end

]
$HUD:
[

if player:isValid() then
rcturret(player,target)
blindfire(player,target)
end

--[[ newtonian
if player:isValid() then
if lvel == nil then lvel = ba.createVector(0,0,0) end
if ppos == nil then ppos = player.Position end

lvel = lvel + ( ((player.Physics.VelocityDesired*1000) / player.Model.Mass) * ba.getFrametime() ) --reads max velocity as max output in kilonewtons
wvel = ppos + lvel

lmag = lvel:getMagnitude()
lmag = lmag / ba.getFrametime()
gr.drawString( round(lmag), 100 ,100)

Vx,Vy = (wvel + (lvel*lmag) ):getScreenCoords()

player.Position = wvel
player.Physics.Velocity = wvel
ppos = wvel
end

if Vx then prograderet( Vx, Vy, round(lmag) ) end
]]

mousereticle(io.getMouseX(),io.getMouseY())

]
#End

*edit* bugfixes
Title: Re: remote controlled turrets revisited
Post by: Nuke on April 05, 2007, 07:16:57 am
ok i killed that damn bug flat and beefed up my getturretangs() function. now it returns the angular values in a slightly more sane manor. ready to be plugged directly into the base's/gun's heading/pitch without further modification. i dont really want a direct plugging though, i want to apply limiters and also animate the motion at a user definable rate. the limiters on the pitch are fairly easy to do, as is the rate, but im tired so il deal with it later.

Code: [Select]
#Global Hooks
$GameInit:
[
--[[=============================]]--
--[[======= function defs =======]]--
--[[=============================]]--

-------------------------------
----------screen vars----------
-------------------------------

setscreenvars = function() --scalers and constants for multi res support
local w = gr.getScreenWidth()
local h = gr.getScreenHeight()
local cx = w/2
local cy = h/2
local wf = 0
local hf = 0
local awh = 0
local hires = false

if w >= 1024 then
wf = w / 1024
hf = h / 768
awh = (wf + hf) / 2
hires = true
else
wf = w / 640
hf = h / 480
awh = ((wf + hf) / 2) * 0.625
hires = false
end

return w,h,cx,cy,wf,hf,awh,hires
end

----------------------------
----------controls----------
----------------------------

mousejoy = function(deadzone) --mousejoy function, returns a value from -1 to 1 depending on the mouse's position
local X = io.getMouseX()
local Y = io.getMouseY()

if hires then
X = (X / 511.5) - 1
Y = (Y / 383.5) - 1
else
X = (X / 319.5) - 1
Y = (Y / 239.5) - 1
end

if deadzone == 1 then --now supports full on and full off mode
return 0,0,X,Y
elseif deadzone == 0 then
return X,Y,X,Y
else
local Mx = X --theese are for the menu, -1 to 1 without deadzone applied
local My = Y
local tweak = 1 / (1 - deadzone)

if X < deadzone and X > -deadzone then
X=0
else
if X > 0 then
X = (X - deadzone) * tweak
elseif X < 0 then
X = (X + deadzone) * tweak
end
end

if Y < deadzone and Y > -deadzone then
Y=0
else
if Y > 0 then
Y = (Y - deadzone) * tweak
elseif Y < 0 then
Y = (Y + deadzone) * tweak
end
end

return X, Y, Mx, My
end
end

mjtonormal = function(X,Y) --converts screen coords to normal
N = ba.createVector(X * 0.741 ,-Y * 0.741 * (h/w) ,1)
N = normalize(N) --make its length 1, otherwise its not a normal
return N
end

-------------------------
----------Maths----------
-------------------------

round = function(number) --rounds to nearest whole number, for some stupid reason, lua doesnt have one
local W,F = math.modf(number)
if F < 0 then
if F <= -0.5 then W = W - 1 end
else
if F >= 0.5 then W = W + 1 end
end

return W
end

normalize = function(norm) --takes a vector and scales it to a length of 1
local len = math.sqrt( (norm.x^2) + (norm.y^2) + (norm.z^2) )
norm = norm / len
return norm
end

multmat = function(mat1,mat2) --multiply a couple 3x3 matricies
local mat3 = {}

mat3[1] = (mat1[1] * mat2[1]) + (mat1[2] * mat2[4]) + (mat1[3] * mat2[7])
mat3[2] = (mat1[1] * mat2[2]) + (mat1[2] * mat2[5]) + (mat1[3] * mat2[8])
mat3[3] = (mat1[1] * mat2[3]) + (mat1[2] * mat2[6]) + (mat1[3] * mat2[9])
mat3[4] = (mat1[4] * mat2[1]) + (mat1[5] * mat2[4]) + (mat1[6] * mat2[7])
mat3[5] = (mat1[4] * mat2[2]) + (mat1[5] * mat2[5]) + (mat1[6] * mat2[8])
mat3[6] = (mat1[4] * mat2[3]) + (mat1[5] * mat2[6]) + (mat1[6] * mat2[9])
mat3[7] = (mat1[7] * mat2[1]) + (mat1[8] * mat2[4]) + (mat1[9] * mat2[7])
mat3[8] = (mat1[7] * mat2[2]) + (mat1[8] * mat2[5]) + (mat1[9] * mat2[8])
mat3[9] = (mat1[7] * mat2[3]) + (mat1[8] * mat2[6]) + (mat1[9] * mat2[9])

return mat3
end

appmat = function(mat,vec) --apply a matrix
local x = (mat[1] * vec[1]) + (mat[2] * vec[2]) + (mat[3] * vec[3])
local y = (mat[4] * vec[1]) + (mat[5] * vec[2]) + (mat[6] * vec[3])
local z = (mat[7] * vec[1]) + (mat[8] * vec[2]) + (mat[9] * vec[3])

vec[1],vec[2],vec[3] = x,y,z

return vec
end

prirotpoint = function(vec,angs) --rotates a point around principle axes
local matx = {1,0,0,0,1,0,0,0,1}
local maty = {1,0,0,0,1,0,0,0,1} --create 3x3 matrix arrays for xyz and fill it in with an identity matrix
local matz = {1,0,0,0,1,0,0,0,1}

matx[5] = math.cos(angs[1])
matx[6] = math.sin(angs[1])
matx[8] = -math.sin(angs[1])
matx[9] = math.cos(angs[1])

maty[1] = math.cos(angs[2])
maty[3] = -math.sin(angs[2]) --fill in the nessicary parts of the matrix for each axis
maty[7] = math.sin(angs[2])
maty[9] = math.cos(angs[2])

matz[1] = math.cos(angs[3])
matz[2] = math.sin(angs[3])
matz[4] = -math.sin(angs[3])
matz[5] = math.cos(angs[3])

local mat = multmat(matx,maty) --multiply our matrixies
mat = multmat(mat,matz) --to get total matrix
vec = appmat(mat,vec) --apply the matrix
return vec
end

rotpoint = function(vec,ang,axis) --rotate around arbitrary axis, axis is a normal defining axis of rotation, ang is amount
local mat = {}

local c = math.cos(ang)
local s = math.sin(ang)
local t = 1 - c

mat[1] = t * axis[1]^2 + c
mat[2] = t * axis[1] * axis[2] + s * axis[3]
mat[3] = t * axis[1] * axis[3] - s * axis[2]

mat[4] = t * axis[1] * axis[2] - s * axis[3]
mat[5] = t * axis[2]^2 + c
mat[6] = t * axis[2] * axis[3] + s * axis[1]

mat[7] = t * axis[1] * axis[3] + s * axis[2]
mat[8] = t * axis[2] * axis[3] - s * axis[1]
mat[9] = t * axis[3]^2 + c

vec = appmat(mat,vec) --apply the matrix
return vec
end

---------------------------------------
----------procedural graphics----------
---------------------------------------

blindfirereticle = function(x,y)
x, y = x*wf, y*hf

gr.setColor(192,192,64,200)

gr.drawGradientLine(x + (8*awh), y, x + (2*awh), y )
gr.drawGradientLine(x - (8*awh), y, x - (2*awh), y )
gr.drawGradientLine(x, y + (8*awh), x, y + (2*awh) )
gr.drawGradientLine(x, y - (8*awh), x, y - (2*awh) )
end

mousereticle = function(x,y)
x, y = x*wf, y*hf

gr.setColor(32,32,50,50)
gr.drawCircle(12*awh,x,y)
gr.setColor(64,64,96,200)

for i=0, 359, 1 do
rot = i * (math.pi/180)
gr.drawPixel(x + (math.sin(rot)*12*awh), y + (math.cos(rot)*12*awh) )
end

gr.setColor(96,96,144,255)
gr.drawPixel(x,y)
end

prograderet = function(x,y,vel)
x, y = x*wf, y*hf

gr.setColor(72,192,72,222)

gr.drawGradientLine(x + (12*awh), y + (12*awh), x + (6*awh), y + (6*awh) )
gr.drawGradientLine(x - (12*awh), y - (12*awh), x - (6*awh), y - (6*awh) )
gr.drawGradientLine(x - (12*awh), y + (12*awh), x - (6*awh), y + (6*awh) )
gr.drawGradientLine(x + (12*awh), y - (12*awh), x + (6*awh), y - (6*awh) )

vel = tostring(vel)

gr.setColor(128,192,128,222)
gr.drawString(vel, x - (gr.getStringWidth(vel) / 2), y - (2*awh) )
end

----------------------------------
----------test functions----------
----------------------------------


printmatrix = function(ori,v) --function to help understand the mystyries of the orientation matrix
gr.setColor(200,200,200,200)
gr.drawString(ori[1],150,100+v)
gr.drawString(ori[2],300,100+v)
gr.drawString(ori[3],450,100+v)
gr.drawString(ori.p, 600,100+v)
gr.drawString(ori.p*180/math.pi,800,100+v)
gr.drawString(ori[4],150,115+v)
gr.drawString(ori[5],300,115+v)
gr.drawString(ori[6],450,115+v)
gr.drawString(ori.h, 600,115+v)
gr.drawString(ori.h*180/math.pi,800,115+v)
gr.drawString(ori[7],150,130+v)
gr.drawString(ori[8],300,130+v)
gr.drawString(ori[9],450,130+v)
gr.drawString(ori.b, 600,130+v)
gr.drawString(ori.b*180/math.pi,800,130+v)
end

printvector = function(vec, hpos, vpos)
gr.drawString(vec.x,hpos - 200 , vpos)
gr.drawString(vec.y,hpos, vpos)
gr.drawString(vec.z,hpos + 200 , vpos)
end


------------------------------------
--------general fire control--------
------------------------------------


plotlead = function(weaponvel, plr, tgt, retvec) --lead function, complements of wanderer, slightly modified
local targetpos = tgt.Position
local targetvel = tgt.Physics.Velocity
local lenghttargetvel = targetvel:getMagnitude()
local playerpos = plr.Position
local plrtotrg = playerpos - targetpos
local lenghtplrtotrg = plrtotrg:getMagnitude()
local trgangle = plrtotrg:getDotProduct(targetvel)
local a = (( weaponvel * weaponvel ) - ( lenghttargetvel * lenghttargetvel ))
local b = ( 2 * trgangle )
local c = -( lenghtplrtotrg * lenghtplrtotrg )
local discrim = ((b * b) - 4 * a * c)
local leadx = 0
local leady = 0

if discrim >= 0 and a ~= 0 then
local multipl1 = (( -b + math.sqrt(discrim)) / ( 2 * a))
local multipl2 = (( -b - math.sqrt(discrim)) / ( 2 * a))
local targetmult = nil

if multipl1 >=0 and multipl1 <= multipl2 and multipl2 >= 0 then
targetmult = multipl1
elseif multipl1 >=0 and multipl2 < 0 then
targetmult = multipl1
elseif multipl2 >=0 then
targetmult = multipl2
else
targetmult = nil
end

if targetmult ~= nil then
local leadvel = targetvel/(1/targetmult)
local leadpos = targetpos + leadvel

if retvec then --sometimes i want a vector rather than a screen coord
return leadpos
elseif leadpos:getScreenCoords() ~= false then
leadx, leady = leadpos:getScreenCoords() --rather than just simply draw the coords, il scale and return them so my code can **** with them
leadx = leadx * wf --drawleadreticle(leadx,leady) pft, my way is better :D
leady = leady * hf --theese factors make things so much easyer
return leadx, leady, leadpos --yep, thats what i need there
else
return -1, -1, leadpos --return -1-1 if this all fails, so it doesnt tweak my math
end
end
    end
end

nukelead = function(tgt, srcv, wvel) --pretty much the same math as wandereds, but reduced in size
local epos = tgt.Position
local evel = tgt.Physics.Velocity
local vlen = evel:getMagnitude()
local edis = srcv - epos
local dlen = edis:getMagnitude()
local trig = edis:getDotProduct(evel)
local a = (wvel^2) - (vlen^2)
local b = trig * 2
local c = -(dlen^2)
local d = (b^2) - 4 * a * c

if d >= 0 and a ~= 0 then
local m1 = ( -b + math.sqrt(d) ) / ( 2 * a)
local m2 = ( -b - math.sqrt(d) ) / ( 2 * a)

if (m1 >= 0 and m1 <= m2 and m2 >= 0) or (m1 >= 0 and m2 < 0) then
return epos + ( evel / (1 / m1) )
elseif m2 >=0 then
return epos + ( evel / (1 / m2) )
else
return epos
end
else
return epos
end
end


getwepvel = function(player)
local banks = player.PrimaryBanks
local vel = 0

if banks.Linked then
local div = 0
local num = #banks

for i=1, num do
vel = vel + banks[i].WeaponClass.Speed
div = div + 1
end

vel = vel / div
else
vel = banks[1].WeaponClass.Speed
end

return vel
end

----------------------------
--------turret funcs--------
----------------------------

getturretsubs = function(player) --returns a list of turet subobject numbers and other options
local curnum = 1
local gunnums = {} --subsystem indices
local arms = {} --p/sbank weaponclasses
local foregun = {} --this option tells turrets to gimbal forward, and within what cone, for ships like apis with turreted blindfire
local mantarg = {} --uses manual targeting
local trackrate ={} --turret tracking rate

for i=1, #player do
local ssname = player[i].Name
if string.find(ssname, "#pt") then --use the built in lua funcs or die!
gunnums[curnum] = i

if player[i].PrimaryBanks:isValid() then
arms[curnum] = player[i].PrimaryBanks[1].WeaponClass --only supporting the first s or p bank
elseif player[i].SecondaryBanks:isValid() then
arms[curnum] = player[i].SecondaryBanks[1].WeaponClass --maybe more later
else
arms[curnum] = tb.WeaponClasses["@Subach HL-7"] --incase nothihng works, we still have good ol hl7
end

local a,cone = string.find(ssname, "-f")
if a ~= nil then
foregun[curnum] = math.rad(tonumber(string.sub(ssname, cone+1, cone+3))) --get the gimbal cone in degrees and convert it to radians
end

if string.find(ssname, "-m") then mantarg[curnum] = true else mantarg[curnum] = false end

local b,rate = string.find(ssname, "-r")
if b ~= nil then
trackrate[curnum] = tonumber(string.sub(ssname, rate+1, rate+3))
else
trackrate[curnum] = 10
end

curnum = curnum + 1
end
end

return gunnums, arms, foregun, mantarg ,trackrate
end


getturretgunpos = function(player,tsub) --find the turret firing point
local pos = player.Position + player.Orientation:unrotateVector(tsub.Position) + tsub.GunPosition
local top = nil

if tsub.Position.y + tsub.GunPosition.y >= tsub.Position.y then
top = true
else
top = false
end

return pos,top
end


getturretangs = function(pori,ppos,tpos,top) --find the angles the turret must rotate to hit a location
local tpos = tpos - ppos --subtract player from tpos to get the player at center
local tpos = pori:rotateVector(tpos) --bring coorsd into player space (tm), now its a 2d problem

local hyp = math.sqrt( (tpos.z^2) + (tpos.x^2) ) --get hypotenuce, tpos.z is opposite and tpos.x is adjacent
local yawangle = math.acos(tpos.z/hyp) --use acos to determine rotation
if tpos.x < 0 then yawangle = -yawangle end --turn it around if its backwards, now lets figure gun pitch

local opp = math.sqrt( (tpos.x^2) + (tpos.z^2) ) --figure out our adjacet in order to get our hypotenuce
hyp = math.sqrt( (tpos.y^2) + (opp^2) ) --this time tpos.y is our adjacent
local pitchangle = math.asin(opp/hyp)
if (top and tpos.y < 0) or (top == false and tpos.y >= 0) then
pitchangle = -pitchangle --give a negative pitch value if the guns are not in the turret arc
pitchangle = pitchangle + math.pi --rotate 180
end --we can use this later for forward facing freelancer style turrets

if top == false then yawangle = yawangle + math.pi end --turn around underside turrets

--gr.drawString(math.deg(yawangle),100,100) --testing prints
--gr.drawString(math.deg(pitchangle),100,120)
return yawangle, pitchangle
end


getturretnorm = function(player,tsub,top) --gets turret firing normal
local gnorm = nil

if top then
gnorm = ba.createVector(0,1,0)
else
gnorm = ba.createVector(0,-1,0)
end

gnorm = tsub.GunOrientation:unrotateVector(gnorm) --unrotate the up vector to the gun
gnorm = tsub.Orientation:unrotateVector(gnorm) --then unrotate the gun normal to the base
gnorm = player.Orientation:unrotateVector(gnorm) --then to the ship

return gnorm --were done
end


fireturret = function(plr,wep,pos,dir) --fires the guns, simple for now
if io.isMouseButtonDown(MOUSE_LEFT_BUTTON) then
mn.createWeapon(wep,dir:getOrientation(),pos,plr,-1)
end
end


rcturret = function(player,target) --ship player, str turret name, bool underside gun, weaponclass
local guns,tweps,fore,manual,track = getturretsubs(player) --get our subobject numbers for our weapons, and options too

if guns[1] ~= nil then --bail if no turrets
for i=1, #guns do
local gun = guns[i]
local gpnt, top = getturretgunpos(player, player[gun]) --find firing point and wether its an upper turret or lower turret
local tpos = nil
local wep = tweps[i]
local dis = wep.Speed

if manual[i] then
tpos = mjtonormal(U,V)
tpos = player.Orientation:unrotateVector(tpos)

if target:isValid() then
dis = target.Position:getDistance(gpnt)
tpos = player.Position + ( tpos * dis ) --converge on target
else
tpos = gpnt + ( tpos * dis ) --no target, go straight
end
else
if target:isValid() then
dis = target.Position:getDistance(gpnt)
tpos = nukelead(target, gpnt, wep.Speed) --find target lead solution if needed
else
tpos = gpnt + player.Orientation:unrotateVector(ba.createVector(0,0,1)) --or just fire sgraight if no target
end
end

local bh, gp = getturretangs(player.Orientation ,gpnt ,tpos, top) --calculate gun pitch and heading in order to hit target

gr.drawString("Turret "..tostring(i).." Heading: "..string.sub(tostring(math.deg(bh)),1,5).." , Pitch: "..string.sub(tostring(math.deg(gp)),1,5), 30, 30 + (i*20) ) --test print

local bori = player[gun].Orientation --get base rotation

local radis = bori.h - bh

gr.drawString(math.deg(bori.h))

-- if bh > bori.h + 0.01 then
-- bori.h = bori.h - ( track[i] * 0.1 * ba.getFrametime() )
-- elseif bh < bori.h - 0.01 then
-- bori.h = bori.h + ( track[i] * 0.1 * ba.getFrametime() )
-- else
bori.h = bh
-- end

gr.drawString(math.deg(bori.h))

-- local dir = nil

-- if radis >= 0 then dir = 0.01 else dir = -0.01 end
-- if math.abs(radis) > math.pi then dir = -dir end

-- if math.abs(radis) > 0.02 then
-- bori.h = bori.h - ( track[i] * ba.getFrametime() * dir ) --animate rotation

-- if top then --make sure were not too rotated
-- if bori.h > math.pi then
-- bori.h = bori.h - (math.pi*2)
-- elseif bori.h < -math.pi then
-- bori.h = bori.h + (math.pi*2)
-- end
-- else --tops are on a -180 to 180 scale, bots are 0 to 360
-- if bori.h > math.pi * 2 then
-- bori.h = bori.h - (math.pi*2)
-- elseif bori.h < 0 then
-- bori.h = bori.h + (math.pi*2)
-- end
-- end
-- else
-- bori.h = bh --unless your so close that animation becomes stupid
-- end

player[gun].Orientation = bori --rotate base

local gori = player[gun].GunOrientation --get gun rotation

gori.p = gp

player[gun].GunOrientation = gori --rotate gun

local aim = getturretnorm(player, player[gun], top) * dis --aim normal

fireturret(player,wep,gpnt,aim)

aim = gpnt + aim

if aim:getScreenCoords() then blindfirereticle(aim:getScreenCoords()) end
end
end
end


-------------------------------
--------blindfire funcs--------
-------------------------------

getblindfireguns = function() --returns a list of all guns with blindfire. theese are the dummy weapons that tell when and where to launch a real one
local num = 1
local weaps = {}
local cones = {}
local autos = {}

for i=1, #mn.Weapons do
local wepname = mn.Weapons[i].Class.Name

if string.find(wepname, "#bf") then
weaps[num] = mn.Weapons[i]

local cone, cvar = string.find(wepname, "-c") --cone is just a place holder as i only need the second number, but i can use the var later

if cvar ~= nil then
cone = tonumber( string.sub(wepname, cvar+1, cvar+3) ) --get the two numbers after the -c tag and convert them to number
else
cone = 10 --if the tag isnt in the weapon name, use a default of 15
end

cones[num] = cone

if string.find(wepname, "-a") then autos[num] = false else autos[num] = true end

num = num + 1
end
end

return weaps, cones, autos --list of weapon objects
end


blindfire = function(plr, tgt) --like the one for turrets sept for standrard guns
local guns, cones, autos = getblindfireguns()

if guns[1] ~= nil then
local tvec = nil

for i=1, #guns do
local gpos = guns[i].Position
local cone = math.cos( cones[i] * math.pi / 180 )
local man = autos[i]

if man then
tvec = mjtonormal(U,V)
if tvec.z < cone then tvec = ba.createVector(0,0,1) end
tvec = plr.Orientation:unrotateVector(tvec)
else
if tgt:isValid() then
tvec = nukelead(tgt,gpos,guns[i].Class.Speed)
tvec = tvec - gpos

local tvec2 = normalize( plr.Orientation:rotateVector(tvec) )
if tvec2.z < cone then tvec = plr.Orientation:unrotateVector( ba.createVector(0,0,1) ) end
else
tvec = plr.Orientation:unrotateVector(ba.createVector(0,0,1)) --if our target doesnt exist, feed it some bull
end
end

local wpn = guns[i].Class.Name --get our weapons name
local wnend = string.find(wpn, "#")
wpn = string.sub(wpn, 1, wnend-1) --remove everything after and including #
local newgun = tb.WeaponClasses[wpn] --now get the regular weaponclass

mn.createWeapon(newgun,tvec:getOrientation(),gpos,plr,-1)

guns[i].LifeLeft = 0.0
end
end
end

--[[===============================================]]--
--[[======= function calls and initial vars =======]]--
--[[===============================================]]--

w,h,cx,cy,wf,hf,awh,hires = setscreenvars()

]
$Simulation:
[

player = mn.Ships["Alpha 1"]

if player:isValid() then target = player.Target end

if io.isMouseButtonDown(MOUSE_RIGHT_BUTTON) then
X,Y,U,V = mousejoy(1)
else
X,Y,U,V = mousejoy(0)
end

]
$HUD:
[

if player:isValid() then
rcturret(player,target)
blindfire(player,target)
end

--[[ newtonian
if player:isValid() then
if lvel == nil then lvel = ba.createVector(0,0,0) end
if ppos == nil then ppos = player.Position end

lvel = lvel + ( ((player.Physics.VelocityDesired*1000) / player.Model.Mass) * ba.getFrametime() ) --reads max velocity as max output in kilonewtons
wvel = ppos + lvel

lmag = lvel:getMagnitude()
lmag = lmag / ba.getFrametime()
gr.drawString( round(lmag), 100 ,100)

Vx,Vy = (wvel + (lvel*lmag) ):getScreenCoords()

player.Position = wvel
player.Physics.Velocity = wvel
ppos = wvel
end

if Vx then prograderet( Vx, Vy, round(lmag) ) end
]]

mousereticle(io.getMouseX(),io.getMouseY())

]
#End

Title: Re: remote controlled turrets revisited
Post by: takashi on April 14, 2007, 11:51:56 am
head build needed?
Title: Re: remote controlled turrets revisited
Post by: Nuke on April 18, 2007, 12:15:43 am
it runs in the latest head. but this highly, and i mean highly experimental.
Title: Re: remote controlled turrets revisited
Post by: takashi on April 18, 2007, 11:10:06 pm
thanks for the warning