Files
gtav-src/tools_ng/dcc/current/max2012/scripts/startup/mloPortal.ms
T
2025-09-29 00:52:08 +02:00

495 lines
14 KiB
Plaintext
Executable File

-- Rockstar mloPortal Object
-- Rockstar North
-- 14/10/2005
-- by Greg Smith
--
--
-- 12/03/2007 -- DHM --
-- Add multiple portal objects parameter block and associated UI
-- Add version update event handler to cope with this change
-- Remove "Door/Window Object" rollout
--
-- 04/03/2010 -- Luke Openshaw
-- Check for rollout initialisation before accessing pick button rollout controls
-- or Max 2010 will crash like the piece of shit that it is
--
-- 28/02/2012 -- Matt Harrad
-- Added set size from scale function and button.
--
-- helper object for milo portal setup
--
global RsAudioOcclusionFile = RsMakeSafeSlashes (RsProjectGetAudioDir() + "/assets/Objects/Core/Audio/GAMEOBJECTS/ENVIRONMENT/PORTAL_SETTINGS.XML")
global gRsExtraAudioOccluderFile = RsMakeSafeSlashes (RsConfigGetExtraAudioOcclusionDir())
global RsSyncAudioOcclusion = true
plugin helper GtaMloPortal
name:"Gta MloPortal"
classID:#(0xa697b45, 0x197567c7)
category:"Gta"
extends:RSGrid
version:2
(
parameters extraParams rollout:extraRollout
(
AudioOcclusionHash type:#string
)
rollout extraRollout "Audio Occlusion"
(
hyperlink hlp "Help" color:blue address:"https://devstar.rockstargames.com/wiki/index.php/Milo_and_Portals#Audio_Occluders" align:#right
dotnetControl edtAudioOccl "Combobox" height:25 width:154 offset:[-8,0]
button btnUpdateAudioFile "Update Occluder List"
group "Add Occluder Info"(
edittext txtFolder "Folder"
spinner txtValue "Occ Value" range:[0,1,0] scale:0.01 indeterminate:true
button btnAddAudOccl "Add new Occluder to XML"
)
fn UpdateAudioFile =
(
-- Update global path to extraOccluder xml
gRsExtraAudioOccluderFile = RsMakeSafeSlashes (RsConfigGetExtraAudioOcclusionDir())
local occlFiles = #(RsAudioOcclusionFile)
edtAudioOccl.Items.Clear()
if RsIsDLCProj() and (RsFileExists gRsExtraAudioOccluderFile) then
(
append occlFiles gRsExtraAudioOccluderFile
)
local occluderItems = #("")
for i = 1 to occlFiles.count do(
if RsSyncAudioOcclusion and i == 1 do
(
gRsPerforce.sync occlFiles silent:true
RsSyncAudioOcclusion = false
)
if RsFileExists occlFiles[i] then
(
local docNav = dotnetobject "System.Xml.XPath.XPathDocument" occlFiles[i]
local nav = docNav.CreateNavigator()
local strExpression = dotnetobject "System.String" "//PortalSettings/@name"
local NodeIter = nav.Select strExpression
while (NodeIter.MoveNext()) do
(
append occluderItems NodeIter.Current.Value
)
)
else
(
gRsUlog.LogWarning ("No audio occlusion file found at \""+occlFiles[i]+"\"") quiet:false
if undefined!=AudioOcclusionHash and ""!=AudioOcclusionHash then
(
local occluderItems = #("", AudioOcclusionHash)
edtAudioOccl.items.addrange occluderItems
edtAudioOccl.SelectedIndex = 1
)
)
)
edtAudioOccl.items.addrange occluderItems
local itemIndex = findItem occluderItems AudioOcclusionHash
if 0!=itemIndex then( edtAudioOccl.SelectedIndex = (itemIndex-1) )
AudioOcclusionHash = edtAudioOccl.Text
txtFolder.text = ""
txtValue.value = 0
)
on btnAddAudOccl pressed do (
local newOcclName = edtAudioOccl.Text
format "edtAudioOccl.Text: %\n" (edtAudioOccl.Text as string)
for i = 0 to edtAudioOccl.Items.Count - 1 do (
if (edtAudioOccl.Items.Item i) == newOcclName then return false
)
local occlFile = RsAudioOcclusionFile
format "occlFile: %\n" (occlFile as string)
-- Create a new file if dlc specific one doesn't exist.
if(RsIsDLCProj()) then (
occlFile = gRsExtraAudioOccluderFile
if not (RsFileExists gRsExtraAudioOccluderFile) then (
local xdoc = XmlDocument()
xdoc.Init()
elem = xdoc.createelement "Objects" appendTo:xdoc.document
xdoc.save occlFile
xdoc.Release()
)
)
if((newOcclName != "") and (RsFileExists occlFile)) then(
if not (gRsPerforce.readOnlyP4Check #(occlFile)) then return false
local clnum = gRsPerforce.createChangelist ("Adding '" + newOcclName + "' to audio occluders")
gRsPerforce.add_or_edit #(occlFile) queueAdd:true
gRsPerforce.addToChangelist clnum #(occlFile)
try(
local doc = XmlDocument()
doc.load occlFile
obj = RsGetXMLElement doc.document "Objects"
local occls = #()
for i = 0 to ((obj.childnodes.count) - 1) do(
append occls (((obj.childnodes.Item i).Attributes.item 0).Value)
)
local found = false
for o in occls while not found do(
found = (o == newOcclName)
)
if(found) then (
return false
)else(
folderName = txtFolder.text
maxOcclValue = txtValue.value
local att = #(#("name",newOcclName))
if(folderName != "" and folderName != " ") then (append att #("folder",folderName))
ps = doc.createelement "PortalSettings" attrs:att appendTo:obj
maxOccl = doc.createelement "MaxOcclusion" value:maxOcclValue appendTo:ps
doc.save occlFile
doc.Release()
AudioOcclusionHash = newOcclName
gRsPerforce.postExportAdd changelistNum:clnum
UpdateAudioFile()
)
)catch(
format "Exception: %\n" (getCurrentException())
stack()
)
)
)
on btnUpdateAudioFile pressed do
(
UpdateAudioFile()
)
on extraRollout open do
(
UpdateAudioFile()
edtAudioOccl.DropDownWidth = 300
)
on edtAudioOccl SelectedIndexChanged e do
(
AudioOcclusionHash = edtAudioOccl.SelectedItem
)
)
parameters objParams rollout:objRollout
(
LinkFirst type:#node ui:btnFirst
LinkSecond type:#node ui:btnSecond
)
rollout objRollout "Rooms"
(
fn isRoom obj =
(
isKindOf obj GtaMloRoom
)
label lblFirst "1st:" width:18 offset:[-6,0] across:2 align:#left
pickbutton btnFirst "none" width:124 offset:[4,-3] filter:isRoom autoDisplay:true align:#right
label lblSecond "2nd:" width:18 offset:[-6,0] across:2 align:#left
pickbutton btnSecond "none" width:124 offset:[4,-3] filter:isRoom autoDisplay:true align:#right
label lblRgtClick "(rightclick buttons to clear)" offset:[0,-2]
label lblAudioOccl "Audio Occlusion:" align:#left
button btnFlip "Flip Portal" width:120 offset:[0,8] tooltip:"Flips this portal"
button btnRetard "Am I Retarded?" width:120 offset:[0,-4] tooltip:"Does this portal probably need to be flipped?"
button btnSizeFromScale "Set Size From Scale" width:120 tooltip:"Set the size of the portal from its scale."
fn CalcPortalVec portalObj =
(
portalPt = [ 0.0, 0.0, 5.0 ]
portalPt = portalPt * portalObj.transform
portalVec = portalPt - portalObj.position
portalVec = normalize portalVec
return portalVec
)
fn RetardationCheck =
(
portalObj = selection[1]
room1 = portalObj.LinkFirst
room2 = portalObj.LinkSecond
bbMin = [10000, 10000, 10000]
bbMax = [-10000, -10000, -10000]
if room1 != undefined do
(
for roomObj in room1.children do
(
if roomObj.position.x < bbMin.x then bbMin.x = roomObj.position.x
if roomObj.position.y < bbMin.y then bbMin.y = roomObj.position.y
if roomObj.position.z < bbMin.z then bbMin.z = roomObj.position.z
if roomObj.position.x > bbMax.x then bbMax.x = roomObj.position.x
if roomObj.position.y > bbMax.y then bbMax.y = roomObj.position.y
if roomObj.position.z > bbMax.z then bbMax.z = roomObj.position.z
)
centroid = (bbMin + bbMax) / 2
roomVec = portalObj.position - centroid
roomVec = normalize roomVec
portalVec = CalcPortalVec portalObj
if (dot portalVec roomVec) < 0 then return true
return false
)
if room2 != undefined do
(
for roomObj in room2.children do
(
if roomObj.position.x < bbMin.x then bbMin.x = roomObj.position.x
if roomObj.position.y < bbMin.y then bbMin.y = roomObj.position.y
if roomObj.position.z < bbMin.z then bbMin.z = roomObj.position.z
if roomObj.position.x > bbMax.x then bbMax.x = roomObj.position.x
if roomObj.position.y > bbMax.y then bbMax.y = roomObj.position.y
if roomObj.position.z > bbMax.z then bbMax.z = roomObj.position.z
)
centroid = (bbMin + bbMax) / 2
roomVec = portalObj.position - centroid
roomVec = normalize roomVec
portalPt = [ 0.0, 0.0, 5.0 ]
portalPt = portalPt * portalObj.transform
portalVec = portalPt - portalObj.position
portalVec = normalize portalVec
if (dot portalVec roomVec) > 0 then return true
return false
)
--else (
-- messagebox "Portal has no rooms."
-- )
return true
)
fn sizeFromScale =
(
portal = selection[1]
portal.grid.length = portal.grid.length*portal.scale.y
portal.grid.width = portal.grid.width*portal.scale.x
portal.scale = [1,1,1]
)
on btnFirst rightClick do
(
this.linkFirst = undefined
)
on btnSecond rightClick do
(
this.linkSecond = undefined
)
on btnFlip pressed do
(
portalVec = CalcPortalVec selection[1]
if (dot portalVec [0.0,0.0,1.0]) > 0.95 or (dot portalVec [0.0,0.0,1.0]) < -0.95 then
(
rotatePortal = eulerangles 180 0 0
rotate selection[1] rotatePortal
)
else
(
rotatePortal = eulerangles 0 0 180
rotate selection[1] rotatePortal
)
)
on btnRetard pressed do
(
if RetardationCheck() == true then messagebox "This portal is probably reversed. If it does not behave correctly in game, flip it and re-export."
else messagebox "Portal seems OK."
)
on btnSizeFromScale pressed do sizeFromScale()
)
-- Unused but maintained for backwards compatibility
parameters objParams2 --DHM -- rollout:objRollout2
(
PortalObject type:#node -- DHM -- ui:btnPortalObject
on PortalObject set val do (
if objRollout2 == undefined then return false
if val != undefined then (
objRollout2.btnPortalObject.caption = val.name
) else(
objRollout2.btnPortalObject.caption = "none"
)
)
)
parameters objParams3 rollout:objRollout3
(
PortalObjects type:#nodeTab tabSizeVariable:true
)
-- Interface rollout to allow multiple objects to be attached to Mlo Portal objects
rollout objRollout3 "Door/Window Objects"
(
listbox lbObjects "Objects:" height:4 align:#left toolTip:"List of objects attached to the Portal" selection:0
button btnAdd "Add (by Pick)" width:100 toolTip:"Add a mesh/poly/ref object by clicking here and then picking the object to add from a viewport"
button btnRemove "Delete" width:100 toolTip:"Select an object in the list and click here to remove the object from the Portal"
fn updateListBox =
(
-- Populate our listbox
if (portalObjects != undefined) do
(
lbObjects.items = for obj in portalObjects where (obj != undefined) collect obj.name
)
)
on lbObjects doubleClicked objNum do
(
if (objNum != 0) do
(
undo "select door/window object" on
(
select portalObjects[objNum]
)
)
)
-- Rollout open event handler
on objRollout3 open do
(
-- Take this opportunity to get rid of invalid list-items:
local newArray = for obj in portalObjects where isValidNode obj collect obj
portalObjects = newArray
updateListBox()
)
fn objFilterFn obj =
(
(isKindOf obj Editable_Poly) or (isKindOf obj Editable_mesh) or (isRefObj obj)
)
-- Add button event handler
on btnAdd pressed do
(
-- This check is done at run-time (and a variable array is used) so that we
-- can support more attached objects in the future (if required)
if (portalObjects.count == 4) do
(
MessageBox( "Portals can only have upto 4 attached objects. No more objects may be attached to this Portal." )
return 0
)
obj = pickObject "Select object to attach to Portal" filter:objFilterFn
-- Append to our PortalObjects parameter array only if the object
-- isn't already attached
if (obj != undefined) and ((findItem portalObjects obj) == 0) do
(
append portalObjects obj
)
-- Update the rollout list:
updateListBox()
)
-- Remove button event handler
on btnRemove pressed do
(
if (lbObjects.selection == 0) then
(
MessageBox( "You must select an object to remove from the Portal first." )
)
else
(
-- Remove from our PortalObjects parameter array
deleteItem PortalObjects lbObjects.selection
updateListBox()
)
)
)
-- Our update event handler
-- Here we maintain backwards compatibility by moving the single reference in
-- objParams2 to the objParams3 array.
on update do
(
-- Update version 1 instances to version 2
-- by moving the reference in objParams2 to objParams3 and then setting the
-- objParams2.PortalObject to undefined
if ( version == 1 ) then
(
if ( this.PortalObject != undefined ) then
(
this.PortalObjects = append this.PortalObjects this.PortalObject
this.PortalObject = undefined
)
)
)
)
MiloPortalColourChangeCallback = "
for obj in selection where (getAttrClass obj == \"Gta MloPortal\") do
(
if ((getAttr obj (getAttrIndex \"Gta MloPortal\" \"Mirror Type\")) == 0) then
(
obj.Grid.colour = ([0, 255, 255] as color)
) else
(
obj.grid.colour = orange
)
)
"
gRsExtraAttrCommands.setCmd #updateMLOPortals class:"Gta MloPortal" attrs:#() cmd:MiloPortalColourChangeCallback priority:5