I've written a few scripts to help myself perform some of the most tedious routines involved in setting up and converting models in Max. No reason to not share them, so here you go:
1. reset_Xform_on_selected.ms - this is for reseting xform on everything right before exporting the ship. Because reseting xform on an object messes up the transforms of its children, you'd usually have to either unlink everything, reset xform and then re-link everything, which can get really tedious. This script does that for you, so all you have to do is select everything and run the script.
2. setup_turret_vecs.ms - this is for setting up fvecs/uvecs. It has a notable limitation of not being able to handle angled turrets for which xform has already been reseted, but that doesn't bother me since I always take care to not do that in a working file.
3. scale_orbs_for_export.ms - this is for allowing you to easily setup subsystem/thruster orbs in Max. Instead of placing those points as dummies, place them as spheres with a size of your choosing. Then, before exporting run the script and it should scale each point so that they'll end up being the right size in PCS2. Note: reseting XForms must be done before running this script, not after.
4. old_turrets_to_spicious_style.ms - do you have turrets setup the old way and they won't work when imported in new PCS2 builds? Running this script should convert the old-style turret hierarchy to the one expected by Spicious's newer builds.
All are written on Max 2009; I think they'll work on somewhat earlier versions too, but I don't know for sure. I'm sure there's bugs and some things I've missed, so feel free to point those out, although I won't promise to fix any issues I don't myself find important. Don't forget to read the comments inside the script for more details of use.
Note: all of the scripts tend to act based on object names: for example, setup_turret_vecs assumes that all objects whose name matches *turret* (except those which match *turret*-arm* or *turret*-destroyed*) are indeed turret bases, and strange things are bound to happen if any other objects have names which match that.
Finally, if you've written or know of any other maxscripts which are useful for modders, post/link them here!
EDIT: reset_Xform_on_selected had a bug which caused the objects to not get linked back together - fixed.
EDIT2: reset_Xform_on_selected now resets only objects which are selected, whereas the previous version(s) reseted selected objects + all their children. It also now automatically collapses the stack of every reseted object.
EDIT3: setup-turret-vecs wasn't correctly inverting the third fvec component, leading to turrets firing in reverse, and it also didn't overwrite already existing properties as advertised. Both fixed.
EDIT4: reverted the bogus fvec fix mentioned above.
reset_Xform_on_selected.ms
-- This script resets xform on all selected nodes. The built-in reset xform
-- function is inadequate because it cannot handle linked objects correctly.
-- This script unlinks each object from its children first before reseting
-- its xform and then linking the children back.
--
-- NOTE: this script seems to sometimes not work on objects which have
-- an active subobject selection.
undo "Reset XForm on selected" on (
for obj in selection do (
children = #()
for child in obj.children do (
append children child
)
for child in children do (
child.parent = undefined
)
collapseStack obj
ResetXForm obj
collapseStack obj
if children.count >= 1 then (
for child in children do (
child.parent = obj
)
)
)
)
setup-turret-vecs.ms
-- This script helps in setting up fvec/uvec values for turrets.
-- However, for angled turrets it'll only work as long as the turret
-- retains its rotation; if you've reseted xform on an angled turret
-- already, then its own rotation information has been lost and the
-- script no longer works right.
--
-- Instructions: select the turrets you wish to setup, run the script
-- and adjust the sliders until the fvec (green) points along the
-- direction of the barrels and uvec (blue) points directly upwards,
-- then hit "Apply".
--
-- IMPORTANT NOTE:
--
-- It's unlikely that you can setup all turrets at once; most likely
-- you'll have to do them in groups. The script uses the turret's
-- existing rotation as a starting point, and if the selection contains
-- turrets which have been rotated in different ways then the script
-- will "suggest" different kinds of fvecs/uvecs for them, in which
-- case you will simply have to setup them separately.
turrets = for turret in selection where ((matchPattern turret.name pattern:"*turret*") and (not matchPattern turret.name pattern:"*turret*-arm*") and (not matchPattern turret.name pattern:"*turret*-destroyed*")) collect turret
rollout turretVecSetup "FS2O Turret fvec/uvec setup" (
slider scale_helpers "Scale helpers" orient:#vertical type:#float range:[0,5,1] height:100
slider rot_x "Rotate X" orient:#horizontal type:#integer ticks:2 range:[0,3,0] width:100
slider rot_y "Rotate Y" orient:#horizontal type:#integer ticks:2 range:[0,3,0] width:100
slider rot_z "Rotate Z" orient:#horizontal type:#integer ticks:2 range:[0,3,0] width:100
button apply_btn "Apply"
button exit_btn "Exit"
fn update_helpers = (
for turret in turrets do (
fvec_helper = getnodebyname(turret.name + "_fvec_helper")
uvec_helper = getnodebyname(turret.name + "_uvec_helper")
uvec_helper.rotation = turret.rotation
in coordsys turret (
rotate uvec_helper (eulerangles (rot_x.value * 90) (rot_y.value * 90) (rot_z.value * 90))
)
uvec_helper.pos = turret.pos
in coordsys uvec_helper (
fvec_helper.rotation = uvec_helper.rotation
rotate fvec_helper (eulerangles 0 -90 0)
)
)
)
fn clean_up = (
for turret in turrets do (
fvec_helper = getnodebyname(turret.name + "_fvec_helper")
uvec_helper = getnodebyname(turret.name + "_uvec_helper")
if fvec_helper != undefined then delete fvec_helper
if uvec_helper != undefined then delete uvec_helper
)
)
on turretVecSetup open do (
for turret in turrets do (
fvec_helper = cylinder name:(turret.name + "_fvec_helper") radius:1 height:20 wirecolor:(color 0 255 0)
uvec_helper = cone name:(turret.name + "_uvec_helper") radius1:3 radius2:0 height:10 wirecolor:(color 0 0 255)
uvec_helper.rotation = turret.rotation
in coordsys turret (
fvec_helper.pos = [0,0,0]
uvec_helper.pos = [0,0,0]
)
)
update_helpers()
)
on turretVecSetup close do (
clean_up()
)
on scale_helpers changed val do (
for turret in turrets do (
fvec_helper = getnodebyname(turret.name + "_fvec_helper")
uvec_helper = getnodebyname(turret.name + "_uvec_helper")
in coordsys local (
ResetScale fvec_helper
ResetScale uvec_helper
fvec_helper.objectoffsetscale = [scale_helpers.value,scale_helpers.value,scale_helpers.value]
uvec_helper.objectoffsetscale = [scale_helpers.value,scale_helpers.value,scale_helpers.value]
)
)
)
on rot_x changed val do (
update_helpers()
)
on rot_y changed val do (
update_helpers()
)
on rot_z changed val do (
update_helpers()
)
on apply_btn pressed do (
overwrote_props = false
for turret in turrets do (
props = getUserPropBuffer turret
fvec_helper = getnodebyname(turret.name + "_fvec_helper")
uvec_helper = getnodebyname(turret.name + "_uvec_helper")
in coordsys uvec_helper (
fvec_helper.pos = [-10,0,0]
uvec_helper.pos = [0,0,10]
)
fvec = normalize -(turret.pos - fvec_helper.pos)
uvec = normalize -(turret.pos - uvec_helper.pos)
fvec.x = (formattedPrint fvec.x format:"2.3f") as float
fvec.y = (formattedPrint fvec.y format:"2.3f") as float
fvec.z = (formattedPrint fvec.z format:"2.3f") as float
uvec.x = (formattedPrint uvec.x format:"2.3f") as float
uvec.y = (formattedPrint uvec.y format:"2.3f") as float
uvec.z = (formattedPrint uvec.z format:"2.3f") as float
fvec_prop = "$fvec: " + fvec.x as string + "," + fvec.z as string + "," + fvec.y as string
uvec_prop = "$uvec: " + uvec.x as string + "," + uvec.z as string + "," + uvec.y as string
if (matchPattern props pattern:"*?vec*") then (
props = ""
overwrote_props = true
print (turret.name + " already had an fvec, uvec or both set, all old subobject properties overwritten!")
)
props += "\r\n" + fvec_prop + "\r\n" + uvec_prop + "\r\n"
setUserPropBuffer turret props
delete fvec_helper
delete uvec_helper
)
if overwrote_props then (
rollout props_overwritten_note "Subobject properties overwritten" (
label note1_lbl "All previous subobject properties of turrets which already had fvec/uvec set were overwritten."
label note2_lbl "Look in the maxscript listener to see a list of those turrets."
label note3_lbl "Undo is available."
button ok_btn "Ok"
on ok_btn pressed do (
destroyDialog props_overwritten_note
)
)
createDialog props_overwritten_note width:600 height:100
)
)
on exit_btn pressed do (
clean_up()
destroyDialog turretVecSetup
)
)
createDialog turretVecSetup
scale_orbs_for_export.ms
orbs= #()
for b in $bay* where (matchpattern b.name pattern:"*-*") do (
append orbs b
)
for p in $path* where (matchpattern p.name pattern:"*-*") do (
append orbs p
)
for s in $subsystem* do (
append orbs s
)
for t in $thruster* where not (matchpattern t.name pattern:"thrusters*") do (
append orbs t
)
for o in orbs do (
upscale = (o.max.x - o.min.x) / 2
downscale = 1 / (o.max.x - o.min.x)
scale o [downscale,downscale,downscale]
ResetScale o
scale o [upscale,upscale,upscale]
)
old_turrets_to_spicious_style.ms
for t in $turret* where not (matchpattern t.name pattern:"*-destroyed") and not (matchpattern t.name pattern:"*-arm") do (
for h in t.children where (matchpattern h.name pattern:"*helper*") do (
for a in t.children where (matchpattern a.name pattern:"*-arm") do (
h.parent = a
)
for f in h.children where (matchpattern f.name pattern:"*firepoints*") do (
f.name = substituteString f.name "firepoints" "multifirepoints"
)
)
)