--April 2013 --Matt Rennie --Tool to reconnect animated normal maps on heads to joysticks filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms") RsCollectToolUsageData (getThisScriptFilename()) filein (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/FN_RSTA_Rigging.ms") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- foundPLayerShader = undefined geoNames = #( --names from fbx file #( ), #( --names for gta "head_000_", "Teef_000_" ) ) normalsXmlFile = undefined wrinkleFolder = undefined -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- fn swapChars textString charFrom charTo = ( flt = filterString textString charFrom thisNewString = "" for i = 1 to flt.count do ( endStr = "" if i < flt.count do ( endStr = charTo ) thisNewString = thisNewString+flt[i]+endStr ) return thisNewString ) fn copyTexture initialPath finalPath = ( initStr = initialPath newFile = finalPath -- initStr = "X://gta5//art//peds//Story_Characters//CS_TracyDiSanto//From_3L//2012-04-17_RockStar_GTAV_TracyDiSanto_v05//textures//HEAD_Wrinkle_Mask_0.tga" thisFile = initStr --clearListener() flt = filterString thisFile "//" origThisFile = thisFile thisFile = swapChars thisFile "//" "\\" flt = filterString newFile "//" thisNewFile = swapChars newFile "//" "\\" origNewFile = newFile ex = doesFileExist thisFile if ex == true then ( -- format ("\n"+"************** FILE EXISTS **********************"+"\n") --newPath = swapChars thisNewFile "//" "\\" --file exists so we should delete the original free thisFile deleteFile thisFile ex2 = doesFileExist thisFile if ex2 == true then ( format ("\t"+"file deletion FAILED."+"\n") format ("\t"+(thisFile as string)+"\n") ) else ( -- format ("\t"+"file deletion SUCCESS!"+"\n") ) -- newFile = "c:\\textureCopy\\Head_Wrinkle_Mask_0.tga" format ("\n\n"+"copying From: "+"\n\t"+origthisFile+"\n"+"To: "+"\n\t"+origNewFile+"\n\n\n") --newFile = copyFile thisFile thisNewFile newFile = copyFile origThisFile origNewFile -- format ("\n\n"+"File copy status: "+(newFile as string)+"\n") ex2 = doesFileExist origNewFile if ex2 == true then ( --print ("Copied to "+thisNewFile) ) else ( print "Copy failed. :(" ) ) else ( print ("Couldn't find "+thisFile) ) return thisNewFile ) fn moveWrinkleMap wrinklePath mapNames = --copies wrinkles from original source 3lateral folder to characters textures\highres folder ( --first we need to find the real texture folder thisStr = findString wrinklePath "From" --searching for 'From' as textures are always inside a From_3l or From3L folder realFolder = undefined if thisStr != undefined then ( realFolder = substring wrinklePath 1 (thisStr - 1) ---messagebox ("Found "+realFolder) ) else ( if queryBox ("Warning! Could not define character texture folder."+"\n"+"Please Click Yes to select character\\textures\\highres folder"+"\n"+"or No to cancel script.") beep:true then ( realFolder = getOpenFileName caption:"Textures Folder" types:"Tga files (head*diff*.tga)|head_*diff*.tga|All Files (*.*)|*.*|" ) else ( contin = false ) ) if realFolder != undefined then --now we do the real stuff ( for wm = 1 to mapNames[2].count do ( --first off check if the map already exists in the realFolder fileName = filenameFromPath mapNames[1][wm] mPath = (realFolder+"textures\\highres\\"+fileName) bPath = swapChars mPath "\\" "//" mPath = bPath --messagebox ("Looking for: "+(mPath) as string) --print ("Looking for existing: "+(mPath) as string) fileExists = doesFileExist (mPath) --dont think i need this with the 4 funcitonality format ("fileExists for "+(mPath)+" = "+(fileExists as string)+"\n") --if it does then check out of p4 then copy the new one over the top if fileExists == true then ( print "Existing wrinkle Found!" --messagebox "Copying over existing wrinkle" thisFile = (mPath) thisFile = swapChars thisFile "//" "\\" --thisFile = copyFile mapNames[1][wm] (thisFile) newTexture = copyTexture mapNames[1][wm] mPath format ("Replacement texture: "+(newTexture as string)+"\n") newTexture1 = getFiles newTexture if newTexture1.count == 1 do ( newTexture1 = newTexture1[1] -- gRsPerforce.add_or_edit #( mPath ) silent:true queueAdd:false gRsPerforce.add_or_edit #( newTexture1 ) silent:true queueAdd:false --messagebox "Found existing wrinkle" --now replace mapNames[1][wm] with the new path print ("Replacing entry "+(wm as string)+" with "+newTexture1) -- mapNames[1][wm] = mPath -- newTexture = execute newTexture mapNames[1][wm] = newTexture1 ) ) --else copy the new one to realfolder and add to p4 else ( --messagebox ("adding new wrinkle to "+mpath) --print ("adding new wrinkle to "+mpath) thisFile = mPath -- flt = filterString thisFile "//" -- thisFile = "" -- for i = 1 to flt.count do -- ( -- thisFile = thisFile+flt[i]+"\\" -- ) thisFile = swapChars thisFile "//" "\\" --thisFile = copyFile mapNames[1][wm] (thisFile) newTexture = copytexture mapNames[1][wm] mPath if newTexture == false do ( format ("Copy of "+mPath +" FAILED!") ) format ("New texture: "+(newTexture as string)+"\n") newTexture1 = getFiles newTexture if newTexture1.count == 1 then ( newTexture1 = newTexture1[1] -- gRsPerforce.add_or_edit #( mPath ) silent:true queueAdd:false gRsPerforce.add_or_edit #( newTexture1 ) silent:true queueAdd:false --now replace mapNames[1][wm] with the new path print ("Replacing entry "+(wm as string)+" with "+newTexture1) -- mapNames[1][wm] = mPath -- newTexture = execute newTexture mapNames[1][wm] = newTexture1 ) else (c format ("WARNING!: "+(newTexture1.count as string)) ) ) ) ) else ( --messagebox ("realFolder == undefined") -- break() contin = false ) ) fn getNodeByNameWildcard nameString = ( thisNode = undefined for o in objects do ( nameLength = nameString.count thisName = nameString as Name ObjectName = ((substring (o.name) 1 nameLength) as Name) if objectName == thisName do ( thisNode = o debugprint ("WOOT "+o.name+" == "+thisName) ) ) return thisNode ) -- function to generate an expression fn generateExpressionIM expObj expCont scalarObjects scalarNames scalarConts expString= ( --TEMPHACK findSoff = "ScaleOffset" -- print ("ExpString: "+(expString as string)) findSO = findString expString findSoff if findSO != undefined do ( findSoff2 = "ScaleOffset + 1" findSo2 = findString expString findSoff2 if findSo2 != undefined then ( --expString = substring expString findSO2 findSoff2.count expString = ("( 0"+(substring expString (findSoff2.count + 2) -1)) print "Removing ScaleOffset + 1" print ("ExpString reset to : "+(expString as string)) ) else ( expString = substring expString findSo findSoff.count print "Removing ScaleOffset" print ("ExpString reset to : "+(expString as string)) ) ) /* need to pass in: 1) expObj = name of object the expression is for 2) expCont = controller the expression is on (as a string) 3) scalarObjects = name of objects used as drivers as an array of string 4) scalarNames = name of scalars - do this as an array (of strings) so we cna loop through multiple scalars 5) scalarConts = controller the scalars point to - do this as array (of strings) with an entry for each item in the scalarNames array 6) expString = full expression string */ --first off we'll check if we need to do the scale by scale fixup to the expstring -- if findString expCont "cale" == true do -- ( -- foundScale = undefined -- for i in scalarConts do -- ( -- if findString i "cale" == true do -- ( -- foundScale = true -- ) -- ) -- -- if foundScale == true do -- ( -- messagebox ("applying scale fixup for "+(expObj as string)) -- break() -- scaleFixUpScaleByScale expString -- ) -- ) if generateScaleOffsetNode == false then ( expString = ("("+expString+")") debugPrint "----------------------------------------------------------------------------" debugPrint "\r\n" debugPrint ("Creating expression on "+expObj+". Scalar of "+(scalarObjects as string)) debugPrint ("Using expression:") debugPrint expString debugPrint "\r\n" debugPrint "----------------------------------------------------------------------------" fcStr = ( "$"+expObj+expCont) --rebuild the string so it can be used below local newfcStr = execute fcStr debugPrint ("newfcStr = "+(fcStr as string)) if scalarNames.count != 0 do ( for i = 1 to scalarNames.count do --this should loop through the array of scalars and their controllers and create a scalar for each ( SVN = scalarNames[i] debugPrint ("SVN = "+(SVN as string)) scalContStr = (scalarConts[i] as string) debugPrint ("scalCont = "+scalContStr) scalCont = execute scalContStr newfcStr.AddScalarTarget SVN scalCont --add scalar pointing to the controller of the scalar object ) ) debugPrint ("setting expression to :\r\n"+expString) newfcStr.SetExpression expString debugPrint ("Expression created on "+expObj+" for "+expCont) debugPrint "```````````````````````````````````````````````````````" ) else ( --first test if theres a scaleOffsetJoystick and if not merge it in offsetJS = getNodeByName "ScaleOffset" if offsetJS == undefined do ( mergeMaxFile rsOffsetJSFile ) offsetJS = getNodeByName "ScaleOffset" if offsetJS != undefined then ( setUserPropBuffer offsetJS "exportTrans = true" in coordsys parent offsetJS.position.controller[2].Y_position = -1 ) expString = ("("+expString+")") debugPrint "----------------------------------------------------------------------------" debugPrint "\r\n" debugPrint ("Creating expression on "+expObj+". Scalar of "+(scalarObjects as string)) debugPrint ("Using expression:") debugPrint expString debugPrint "\r\n" debugPrint "----------------------------------------------------------------------------" fcStr = ( "$"+expObj+expCont) --rebuild the string so it can be used below local newfcStr = execute fcStr debugPrint ("newfcStr = "+(fcStr as string)) if scalarNames.count != 0 do ( for i = 1 to scalarNames.count do --this should loop through the array of scalars and their controllers and create a scalar for each ( SVN = scalarNames[i] debugPrint ("SVN = "+(SVN as string)) scalContStr = (scalarConts[i] as string) debugPrint ("scalCont = "+scalContStr) scalCont = execute scalContStr newfcStr.AddScalarTarget SVN scalCont --add scalar pointing to the controller of the scalar object ) ) --SCALEOFFSETTEMPDISABLED --SVN2 = "ScaleOffset" -- SVN2Cont = $ScaleOffset.pos.controller.Zero_Pos_XYZ.controller.Y_Position.controller.Limited_Controller__Bezier_Float.Controller -- SVN2Cont = $ScaleOffset.pos.controller.Zero_Pos_XYZ.controller.Y_Position.controller -- newFcStr.AddScalarTarget SVN2 SVN2Cont debugPrint ("setting expression to :\r\n"+expString) newfcStr.SetExpression expString debugPrint ("Expression created on "+expObj+" for "+expCont) debugPrint "```````````````````````````````````````````````````````" ) ) fn addBonesToExpressionSet selectionSetName nodesToAdd = ( expSet = selectionSets[selectionSetName] tmpObjs = #() if expSet != undefined then ( for ss = 1 to expSet.count do ( append tmpObjs expSet[ss] ) ) else ( expSet = #() ) for ts = 1 to nodesToAdd.count do ( appendIfUnique tmpObjs nodesToAdd[ts] debugPrint ("adding "+nodesToAdd[ts].name+" to "+selectionSetName+" selection set") ) deleteItem selectionSets selectionSetName selectionSets[selectionSetName] = tmpObjs ) fn createNormalsJoystick jsname jpos = ( jstyle = 2 -- 2 = vertical slider foundJS = getnodeByName jsName if foundJS == undefined then ( debugprint (jsName+" not found so initialising creation...") createJoystick jsname jstyle jpos 1 --now add animated normals track thisJS = getNodeByName jsname setUserPropBuffer thisJs ("translateTrackType=TRACK_ANIMATED_NORMAL_MAPS") --now set params for text and joytstick bounding box thing to not be frozen as gray then freeze surrBox = (getNodeByName ("RECT_"+jsName)) surrBox.showFrozenInGray = false surrBox.isFrozen = true textItem = (getNodeByName ("TEXT_"+jsName)) textItem.showFrozenInGray = false textItem.isFrozen = true --now add joysticks to expression set selectionSetName = "*EXPRESSIONS" thisJSArray = #() append thisJSArray thisJS addBonesToExpressionSet selectionSetName thisJSArray ) else ( debugprint (jsName+" found so skipping creation.") ) ) fn parseNormalsXML = ( jp = 0.5 jCount = 0 jHeight = 0 if normalsXmlFile == undefined do ( normalsXmlFile = getOpenFileName caption:"Normals XML File" types:"XML Data (*slider*.xml)|*slider*.xml|All Files (*.*)|*.*|" ) debugPrint ("Picked "+normalsXmlFile) mappingXmlFile = normalsXmlFile xmlDoc = XmlDocument() xmlDoc.init() xmlDoc.load mappingXmlFile xmlRoot = xmlDoc.document.DocumentElement if normalsXmlFile != undefined then ( -- Parse the XML dataElems = xmlRoot.childnodes --print "Beginning Normal XML Parse..." if ((progBar != undefined) and (progBar.isDisplayed)) do (destroyDialog progBar) createDialog progBar width:400 Height:30 for i = 0 to (dataElems.Count - 1 ) do ( a = ((dataElems.count as float) / 100) progBar.prog.value = (1.*i/a) maskExpStringArray = #() --array of expression strings maskNameArray = #() --array of mask textures maskSliderArray = #() --array of sliders maskDriverSpnObjArray = #() --array of driver objects which are custom attributes maskDriverSpnNameArray = #() --array of names of custom attributes maskDriverSpnScalarNameArray = #() --array of scalar names for custom attributes maskDriverJSObjArray = #() -- array of joysticks used as drivers maskDriverJSTransformArray = #() --array of transform used from joysticks maskDriverJSScalarNameArray = #() --array of scalar names from joysticks dataElement = dataElems.itemof(i) debugPrint ("i = "+(i as string)) debugPrint ("dataElementName = "+(dataElement.name)) if dataElement.name == "mask" do ( elementAttrs = dataElement.attributes debugPrint ("Found "+(elementAttrs.count as string)+" attributes") for ea = 0 to (elementAttrs.count - 1 ) do ( currentElem = elementAttrs.itemOf(ea) --now we can test for the values if (currentElem.Name as string) == "maskExpString" do ( maskExpString = (currentElem.value as string) append maskExpStringArray maskExpString ) if (currentElem.Name as string) == "maskName" do ( maskName= (currentElem.value as string) append maskNameArray maskName ) if (currentElem.Name as string) == "maskSlider" do ( maskSlider = (currentElem.value as string) append maskSliderArray maskSlider ) ) --now we look at the children dataElemChildren = dataElement.childNodes for c = 0 to (dataElemChildren.count - 1) do ( --ok we're now looking at the driven for this node childElement = dataElemChildren.itemOf[c] childAttrs = childElement.attributes for cA = 0 to (childAttrs.count - 1) do ( currentChildElem = childAttrs.itemOf(cA) if currentChildElem.name == "maskDriverJSObj" do ( append maskDriverJSObjArray currentChildElem.value ) if currentChildElem.name == "maskDriverJSTransform" do ( append maskDriverJSTransformArray currentChildElem.value ) if currentChildElem.name == "maskDriverJSScalarName" do ( append maskDriverJSScalarNameArray currentChildElem.value ) if currentChildElem.name == "maskDriverSpnObj" do ( append maskDriverSpnObjArray currentChildElem.value ) if currentChildElem.name == "maskDriverSpnName" do ( append maskDriverSpnNameArray currentChildElem.value ) if currentChildElem.name == "maskDriverSpnScalarName" do ( append maskDriverSpnScalarNameArray currentChildElem.value ) ) ) --now we need to build the joysticks --first off we need to make the joystick parent text so we can move them all around at once.... textParent = undefined textParent = getNodeByName "TEXT_Normals" if textParent == undefined do ( textParent = text size:0.1 kerning:0 leading:0 pos:[0.81,-0.0,0.105736] isSelected:on textParent.name = "TEXT_Normals" textParent.text = "Normals" in coordsys world textParent.rotation = (quat 0.707107 0 0 0.707107) textParent.render_displayRenderMesh = true textParent.thickness = 0.0025 textParent.sides = 3 max modify mode modPanel.addModToSelection (Edit_Poly ()) ui:on collapsestack textParent ) jCount = jCount+1 divider = 2.3 if jCount < 5 then --1 to 4 ( jp = (0+((jCount as float)/ divider )) jHeight = -0.0 ) else ( if JCount < 9 then -- 5 to 8 ( jp = (0+(((jCount as float)- 4) / divider )) jHeight = -0.15 ) else ( if JCount < 13 then --9 to 12 ( jp = (0+(((jCount as float)- 8) / divider )) jHeight = -0.3 ) else ( if JCount <17 then --13 to 16 ( jp = (0+(((jCount as float)- 12) / divider )) jHeight = -0.60 ) else ( if JCount <21 then --17 to 20 ( jp = (0+(((jCount as float) - 16) / divider )) jHeight = -0.75 ) else ( jp = (0+(((jCount as float) - 20) / divider )) jHeight = -0.9 ) ) ) ) ) jPos = [(0.5 +( jp / 3.5)),-0.5,jHeight] jsName = maskSliderArray[1] debugprint ("jsName: "+jsName) createNormalsJoystick jsname jpos thisJS = getNodeByName jsName select thisJS RSTA_FreezeTransform() setUserPropBuffer thisJS "translateTrackType = TRACK_ANIMATED_NORMAL_MAPS" thisJsPar = thisJS.parent thisJSPar.parent = textParent -- in coordsys parent thisJSPar.position.controller.z_position = 0.0 in coordsys parent thisJSPar.position[3] = 0.0 expObj = ("'"+maskSliderArray[1]+"'") expCont = (".position.controller[2].Y_Position.controller") scalarObjects = #() scalarNames = #() scalarConts = #() --now we need to first setup the expressions from joysticks --we need to create the paths for the driver controllers ( be they joysticks or cAtts) theseConts = #() for c = 1 to maskDriverJSObjArray.count do ( thisTrans = (substring maskDriverJSTransformArray[c] 3 60) thisContObjStr = ("$"+maskDriverJSObjArray[c]+"."+thisTrans+".controller[2]."+maskDriverJSTransformArray[c]+".controller") append scalarObjects maskDriverJSObjArray[c] append scalarConts thisContObjStr append scalarNames maskDriverJSScalarNameArray[c] ) for c = 1 to maskDriverSpnScalarNameArray.count do ( tmpScalarCont = ("$"+maskDriverSpnObjArray[c]+".modifiers[#Attribute_Holder]."+maskDriverSpnObjArray[c]+"_A"+"."+maskDriverSpnNameArray[c]+"_CA.controller") append scalarObjects maskDriverSpnObjArray[c] append scalarConts tmpScalarCont append scalarNames maskDriverSpnScalarNameArray[c] ) expString = maskExpStringArray[1] --before we add the expression we need to change the expCont into a float Expression execStr = ("$"+expObj+expCont+" = Float_Expression()") execute execStr generateExpressionIM expObj expCont scalarObjects scalarNames scalarConts expString ) ) if ((progBar != undefined) and (progBar.isDisplayed)) do (destroyDialog progBar) --now position and scale the parent of all the normal joysticks rootObject = getNodeByName "TEXT_Normals" in coordsys world rootObject.position = [0.45,0,1.6] in coordsys world rootObject.scale = [0.25,0.25,0.25] hide rootObject ) else ( messagebox "Please select a valid xml file." Beep:true ) ) fn queryMat = --function which queries shader names to see if shaders in scene are old school or new PLAYER style ( for i = 1 to 24 do ( if meditMaterials[i].name == "Upper_RAGE" do ( foundPLayerShader = true ) ) ) fn setupWrinkleShader = ( defaultFilePath = maxfilepath normalsXmlFile = getOpenFileName caption:"Normals XML File" types:"XML Data (*slider*.xml)|*slider*.xml|All Files (*.*)|*.*|" filename:defaultFilePath wrinkleFolder = getOpenFileName caption:"Wrinkle Folder " types:"Tga files (HEAD_Wrinkle_A.tga)|HEAD_Wrinkle_A.tga|All Files (*.*)|*.*|" filename:defaultFilePath queryMat() if shaderType == "Player" then ( for i = 1 to 24 do ( head = getNodeByNameWildcard geoNames[2][1] teef = getNodeByNameWildcard geoNames[2][2] if meditMaterials[i].name == "Head_RAGE" do ( thisShader = meditMaterials[i].materialList[1] matToUse = meditMaterials[i] head.material = matToUse debugprint "Updating head shader" -- And set it to the correct default shader for characters shadertoset = "ped_wrinkle_cs.sps" RstSetShaderName thisShader shadertoset --now need to find the wrinkleMap folder if wrinkleFolder != undefined do ( debugprint ("wrinkleFolder = "+wrinkleFolder) --now we strip the wrinkleFolder path to prior to the texture name so we have the folder pathLength = wrinkleFolder.count imageLength = pathlength - 18 wrinklePath = (substring wrinkleFolder 1 imageLength) debugprint ("Folder = "+wrinklePath) wrinkleMasks = #( #( (wrinklePath+"HEAD_Wrinkle_Mask_0.tga"), (wrinklePath+"HEAD_Wrinkle_Mask_1.tga"), (wrinklePath+"HEAD_Wrinkle_Mask_2.tga"), (wrinklePath+"HEAD_Wrinkle_Mask_3.tga"), (wrinklePath+"HEAD_Wrinkle_Mask_4.tga"), (wrinklePath+"HEAD_Wrinkle_Mask_5.tga"), (wrinklePath+"HEAD_Wrinkle_A.tga"), (wrinklePath+"HEAD_Wrinkle_B.tga") ), #( "Wrinkle Mask 0", "Wrinkle Mask 1", "Wrinkle Mask 2", "Wrinkle Mask 3", "Wrinkle Mask 4", "Wrinkle Mask 5", "Wrinkle A", "Wrinkle B" ) ) --NOW WE NEED TO COPY THE WRINKLES TO THE CHARACTERS TEXTURES\HIGHRES\ FOLDER moveWrinkleMap wrinklePath wrinkleMasks shdrParams = RstGetVariableCount thisShader if shdrParams != undefined do ( -- for sParam = 1 to shdrParams.count do for sParam = 1 to shdrParams do ( thisParam = RstGetVariableName thisShader sParam for wm = 1 to wrinkleMasks[2].count do ( if thisParam == wrinkleMasks[2][wm] do ( print ("wrinkleMasks[1]["+(wm as string)+"]: "+(wrinkleMasks[1][wm] as string)) --now we need to set this parameter to be wrinkleMasks[1][wm] RstSetVariable thisShader sParam wrinkleMasks[1][wm] ) ) ) ) ) ) if meditMaterials[i].name == "Hair 2_RAGE" do ( matToUse = meditMaterials[i] teef.material = matToUse debugprint ("updating TEEF shader") ) ) ) else ( head = getNodeByNameWildcard geoNames[2][1] if head == undefined do ( thisGeoName = undefined if (substring geoNames[2][1] 1 1 ) == "H" do ( thisGeoName = ("h"+(substring geoNames[2][1] 2 60 ) ) ) head = getNodeByNameWildcard thisGeoName ) teef = getNodeByNameWildcard geoNames[2][2] if teef == undefined do ( thisGeoName = undefined if (substring geoNames[2][1] 1 1 ) == "T" do ( thisGeoName = ("t"+(substring geoNames[2][1] 2 60 ) ) ) teef = getNodeByNameWildcard thisGeoName ) thisShader = meditMaterials[13].materialList[1] matToUse = meditMaterials[13] head.material = matToUse debugprint "Updating head shader" -- And set it to the correct default shader for characters shadertoset = "ped_wrinkle_cs.sps" RstSetShaderName thisShader shadertoset wrinkleMasks = #( #( undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined ), #( undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined ) ) --now need to find the wrinkleMap folder if wrinkleFolder != undefined then ( debugprint ("wrinkleFolder = "+wrinkleFolder) --now we strip the wrinkleFolder path to prior to the texture name so we have the folder pathLength = wrinkleFolder.count imageLength = pathlength - 18 wrinklePath = (substring wrinkleFolder 1 imageLength) debugprint ("Folder = "+wrinklePath) wrinkleMasks = #( #( (wrinklePath+"HEAD_Wrinkle_Mask_0.tga"), (wrinklePath+"HEAD_Wrinkle_Mask_1.tga"), (wrinklePath+"HEAD_Wrinkle_Mask_2.tga"), (wrinklePath+"HEAD_Wrinkle_Mask_3.tga"), (wrinklePath+"HEAD_Wrinkle_Mask_4.tga"), (wrinklePath+"HEAD_Wrinkle_Mask_5.tga"), (wrinklePath+"HEAD_Wrinkle_A.tga"), (wrinklePath+"HEAD_Wrinkle_B.tga") ), #( "Wrinkle Mask 0", "Wrinkle Mask 1", "Wrinkle Mask 2", "Wrinkle Mask 3", "Wrinkle Mask 4", "Wrinkle Mask 5", "Wrinkle A", "Wrinkle B" ) ) moveWrinkleMap wrinklePath wrinkleMasks shdrParams = RstGetVariableCount thisShader for sParam = 1 to shdrParams do ( thisParam = RstGetVariableName thisShader sParam for wm = 1 to wrinkleMasks[2].count do ( if thisParam == wrinkleMasks[2][wm] do ( print ("wrinkleMasks[1]["+(wm as string)+"]: "+(wrinkleMasks[1][wm] as string)) --now we need to set this parameter to be wrinkleMasks[1][wm] RstSetVariable thisShader sParam wrinkleMasks[1][wm] ) ) ) ) else ( print "Warning wrinkleFolder == undefined" ) ) --now we need to loop through all the other materials and set them to this wrinkle version for slot = 14 to 24 do ( if (classof meditmaterials[slot][1] as string) == "Rage_Shader" do ( thisShader = meditMaterials[slot][1] RstSetShaderName thisShader shadertoset shdrParams = RstGetVariableCount thisShader for sParam = 1 to shdrParams do ( thisParam = RstGetVariableName thisShader sParam for wm = 1 to wrinkleMasks[2].count do ( if thisParam == wrinkleMasks[2][wm] do ( print ("wrinkleMasks[1]["+(wm as string)+"]: "+(wrinkleMasks[1][wm] as string)) --now we need to set this parameter to be wrinkleMasks[1][wm] RstSetVariable thisShader sParam wrinkleMasks[1][wm] ) ) ) ) ) parseNormalsXML() ) setupWrinkleShader()