Jump to content

Coda Script Collection


AndalayBay

Recommended Posts

NOTICE: shadeMe changed the way background scripts work since these scripts were written. They no longer work. Previously a background script kept running until it was terminated with return(0,1). That is no longer the case. Now background scripts terminate with a simple return statement, just like foreground scripts. I have replaced the script with the new version.

First, if you aren't familiar with Coda, I suggest you check out the introduction here. This thread will provide Coda scripts for a variety of tasks.

Many of these scripts will walk through an array of cells in which a particular object has been placed. My main use of this function is to ground floating trees and rocks in exterior cells.

Get List of Cells for Object

CODA(GetUsage)

var cellUsage
var baseObject
var instance

; list all cells where object has been placed
begin
	baseObject = getFormByEditorID("BMSwampRose01")
	cellUsage = GetCellUseList(baseObject)
	foreach instance <- cellUsage
		printC("Cell "//$instance)
	loop
end

Save this script as GetUsage.coda in Data\BGSEE\Coda. This script assumes that the specified object has been instantiated at least once. It produces a list like this:

 [CSE]            Cell 01011EEF
 [CSE]            Cell 01011EF1
 [CSE]            Cell 0100237F
 [CSE]            Cell 01002395
 [CSE]            Cell 010037CB
 [CSE]            Cell 010037CE
 [CSE]            Cell 01011F0B
 [CSE]            Cell 010024B3
 [CSE]            Cell 0103658A
 [CSE]            Cell 010036DC
 [CSE]            Cell 010369FB
...

If you want the list of cell forms to use in another script, just remove "Cell "// from the printC statement in the script above, so it's printC($instance) instead. Now that we have a list of cells for the object we want to fix, we'll copy that list into an array in the next script.

If you remove "Cell " from the print statement so you just get a list of form ID's, then you can use this regular expression to convert the list of form ID's into arAppend statements that are used in the script below:

Find: ([0-9A-F]{8})
Replace: arAppend\(arCells, GetFormByFormID\(0x$1\)\)

Make sure Regular Expression is checked off in the search/replace dialogue box.

Grounding Floating Trees

There are some commands in Coda that require the object be loaded into the Render Window. If that's the case, you'll find "The parameter reference needs to be loaded in the render window." next to the command in the Coda command documentation. Since that takes time, the script is run in the background. This script uses the FloorRef command, which is one such case. This script will also add a random rotation. If you don't need that, just remove the SetRefRotation command. The full script needed an array with 1550 elements. I will truncate the array in the code below since you'll have to replace it with the list of cells for the object you are fixing. Also shadeMe has deprecated the ArrayInsert command. Now it's arAppend which will expand the size of the array as required so we just set the size to 1 when we create the array.

CODA(MoveTrees, "2.0")
; This must be run as a background script. Set polling interval to 2 seconds.

var arCells
var cell
var objectRef
var baseToComp
var currHeight
var newHeight
var randomNum
var treesMoved
var waiting
var doOnce
var cellCounter
var arRefs
var arSz

begin
	if (doOnce == 0)
		; since this is a background script, make sure the init phase happens only once
		arCells = ArrayCreate (1)
		arAppend(arCells, GetFormByFormID(0x010364F3))
		arAppend(arCells, GetFormByFormID(0x01011EE3))
		arAppend(arCells, GetFormByFormID(0x01011EE5))
		; rest of arAppend statements as needed

		baseToComp = getFormByEditorID("BMEmpParasolSmall01")
		waiting = 0
		cellCounter = 0
		treesMoved = 0

		doOnce = 1
	endIf
	
	if (waiting == 1)
		; we waited last time and the cell should now be loaded in its entirety
		; so off to the next state
		waiting = 2
	endIf
	
	arSz = ArraySize(arCells)
	while cellCounter < arSz
		cell = arCells[cellCounter]
		arRefs = GetCellObjects(cell)

		if (ArraySize(arRefs))
			if (waiting == 0)
				; processing the cell for the first time, let's load it up
				LoadRefIntoRenderWindow(arRefs[0])

				; wait for a bit until it loads
				printC("waiting...")
				waiting = 1
				break()
			elseIf (waiting == 2)
				; cell is in a usable state, do stuff now
				printC("fixing refs...")

				; list form ID of cell in case object needs adjustment
                ; some wound up underwater, so I moved them manually
				printC("Processing cell "//$arCells[cellCounter])
	
				forEach objectRef <- arRefs
					if (GetRefBaseform(objectRef) == baseToComp)
						; fix height and set rotation
						; these trees are actually statics so we can rotate them
						randomNum = RandomNumber(0, 359)
						SetRefRotation(objectRef, "Z", randomNum)
						currHeight = getRefPosition(objectRef, "Z")
						; we know they're floating, so don't need this line
                        ; if they aren't, remove the semi-colon from the next line
						;setRefPosition(objectRef, "Z", currHeight + 30000)
						floorRef(objectRef)
						newHeight = getRefPosition(objectRef, "Z")
						printC("Ref "//$objectRef//" - Old height: "//fmtNum("%0.4f", currHeight, 0)//", New height: "//fmtNum("%0.4f", newHeight, 0))
						; this sinks the object a bit
                        ; change 15 to whatever you need for the depth the object should be sunk into the ground
						setRefPosition(objectRef, "Z", newHeight - 15)
						markAsModified(objectRef, 1)
						treesMoved += 1
					endif
				loop
				; this cell is done, on to the next
				waiting = 0
				cellCounter += 1
			endif
		else
			; nothing in this cell, continue on
			cellCounter += 1
		endif
	loop

	if (waiting == 0)
		printC($treesMoved//" trees moved.")
		; remove the script from the background queue
		return(0, 1)
	endIf

end

Save this script as MoveTrees.coda in the Data\BGSEE\Coda directory. The file name does not have to match the name in the parentheses next to the Coda keyword at the top of the script. Since this is a background script, you have to specify a polling time, which was set to 2 seconds in this case. Once you've changed this script to suit your purposes, you run it with

runCodaScript movetrees 1

in the Console Window command prompt. The runCodaScript command needs the file name, not the script name after the Coda declaration at the top of the script. Since this is a background script, the background parameter is set to 1 in the run script command. Lastly, note the return command at the end of the script to remove it from the background queue.

The printC commands in the script can be removed if you wish. I use them to monitor running of the script. It might be a background script, but I don't attempt to do anything else while it's running...

Edited by AndalayBay
Replaced code with new version
Link to comment
Share on other sites

Here are the scripts I wrote for removing the VWD flag from objects placed in interior cells. These objects should not have the VWD flag set. Many of them were statics so I have no idea why the flag was set.

First, here's the script to list the cells that have objects with the flag set:

CODA(ListVWDInteriors)

var cell
var cellEditorID
var firstChars
var WS
var wsTemp
var object
var vwd

; list Items in interiors with VWD set
begin
	forEach cell <- getDataHandlerFormList(48)
		cellEditorID = GetEditorID(cell)
		firstChars = StringSubStr(cellEditorID, 0, 2)
		if (StringCompare(firstChars, "BM", 1) == 0)
			WS = getCellWorldspace(cell)
			wsTemp = fmtNum("%08X", WS, 1)
			if (wsTemp == "00000000") ;interior cell
				forEach object <- GetCellObjects(cell)
					vwd =  GetRefVWD(object)
					if (vwd == 1)
						printC(cellEditorID//" - "//$object)
					endif
				loop
			endif
		endif
	loop
	printC("All done")
end

We had over 220 items. Fortunately I was able to flip the flag with Coda:

CODA(FixVWDInteriors)

var cell
var cellEditorID
var firstChars
var WS
var wsTemp
var object
var vwd

; list Items in interiors with VWD set
begin
	forEach cell <- getDataHandlerFormList(48)
		cellEditorID = GetEditorID(cell)
		firstChars = StringSubStr(cellEditorID, 0, 2)
		if (StringCompare(firstChars, "BM", 1) == 0)
			WS = getCellWorldspace(cell)
			wsTemp = fmtNum("%08X", WS, 1)
			if (wsTemp == "00000000") ;interior cell
				forEach object <- GetCellObjects(cell)
					vwd =  GetRefVWD(object)
					if (vwd == 1)
						printC(cellEditorID//" - "//$object)
						setRefVWD(object, 0)
						markAsModified(object, 1)
					endif
				loop
			endif
		endif
	loop
	printC("All done")
end

I have also created syntax definition files (UDL files) for Legacy (Oblivion's scripting language) and Coda for Notepad++. Please let me know if you would like a copy. I copied some of shadeMe's syntax definition from the CSE.

Link to comment
Share on other sites

Need help cluttering? This potential script could load a bookshelf. You'd need a loop that changes the coordinates so the books are placed next to one another and not in the same spot each time.

Coda(PlaceBooks)

var book
var EditorID
var bookEditorID
var bookName
var targetCell

begin
	forEach book <- GetDataHandlerFormList(21)
		EditorID = GetEditorID(book)
		bookEditorID = StringSubStr(EditorID, 0, 10)
		if StringCompare(bookEditorID, "Book1Cheap", 1) == 0
			printC("editorID ="//$EditorID)
			bookName = GetBFCFullName(book)
			printC("Name ="//bookName)
			targetCell = getFormByEditorID("DBCStrongholdLibrary")
			createRef(book, -917.0, 251.0, 12.0, -90.0, 196.0, 0.0, targetCell, targetCell)
		endif
	loop
end

The createRef command takes a worldspace form as the last parameter, but that's ignored for interior cells, so I just repeated the interior cell form to satisfy the command parameters.

Link to comment
Share on other sites

We need to fix some regions in Argonia so I just created these scripts to help. The first script lists all objects in a specific cell. Basically you give it the form ID for the cell, whether it's interior or exterior.

List Objects in Cell

coda(ListObjectsInCell)

var cell
var arObjects
var objectRef
var editorID
var baseObj
var arDistinct
var distinctStr
var found

begin
	arDistinct = arCreate (150)
	; Get objects for BlackMarshes 40,13
	cell = GetFormByFormID(0x01036964)
	arObjects = GetCellObjects(cell)
	
	if (arSize(arObjects))
		foreach objectRef <- arObjects
			baseObj = GetRefBaseform(objectRef)
			editorID = getEditorID(baseObj)
			if (arSize(arDistinct))
				found = 0
				foreach distinctStr <- arDistinct
					; 0 = equal
					if (StringCompare(editorID, distinctStr, 1) == 0)
						found = 1
						break()
					endif
				loop
				if found == 0
					arAppend(arDistinct, editorID)
				endif
			else
				arAppend(arDistinct, editorID)
			endif
		loop
		foreach distinctStr <- arDistinct
			printC("Object: "//$distinctStr)
		loop
	endif
end

The second script lists the landscape textures in an exterior cell. You need to load the cell in the render window for it to print the textures.

List Landscape Textures in Cell

coda(ListLandscapeTexturesInCell)

var cell
var editorID
var arTextures
var texture
var i

begin
	; Get landscape textures for BlackMarshes 40,13
	; Cell must be loaded into render window first
	cell = GetFormByFormID(0x01036964)
	i = 1
	
	while (i < 5)
		arTextures = GetCellLandscapeTextures(cell, i)
		printC("Quad = "//$i)
		foreach texture <- arTextures
			editorID = getEditorID(texture)
			printC("Texture: "//$editorID)
		loop
		i += 1
	loop
end

The previous scripts can be combined into one script. Here are the results:

Quote

Objects in 40,13
Object: BMrockeastcoast095
Object: BMrockeastcoast045
Object: BMrockeastcoast320
Object: BMFloraMarshmerrow03
Object: BMEmpParasol01
Object: BMLL1WildernessLAKEandDEEPWATER
Object: BMFloraMarshmerrow01
Object: BMFloraFirefern01
Object: BMEmpParasolSmall01
Object: BMOldFinger02
Object: BMrockeastcoast255
Object: BMrockeastcoast1190
Object: BMrockeastcoast220
Object: BMrockeastcoast830
Object: BMEmpParasolLog01
Object: MshrmFlyAmanita02
Object: MshrmFlyAmanita04
Object: BMTreeBamboo1b
Object: ShrubAzaleaSU
Quad = 1.000000
Texture: BMEastMudMoss
Texture: BMEastSiltMoss
Texture: BMEastMudMoss
Texture: BMEastRockMoss
Texture: BMEastSiltMossNoGrass
Quad = 2.000000
Texture: BMEastMudMoss
Texture: BMEastSiltMoss
Texture: BMEastMudMoss
Texture: BMEastRockMoss
Quad = 3.000000
Texture: BMEastMudMoss
Texture: TerrainHDRock02
Texture: BMEastSiltMoss
Texture: BMEastMudMoss
Texture: BMEastRockMoss
Texture: BMEastSiltMossNoGrass
Quad = 4.000000
Texture: BMEastMudMoss
Texture: TerrainHDRock02
Texture: BMEastSiltMoss
Texture: BMEastMudMoss
Texture: BMEastRockMoss
Texture: BMEastSiltMossNoGrass

Now I can add those to the Generated Objects list in a region.

Link to comment
Share on other sites

The MoveTrees script in the OP has been replaced. shadeMe changed how background scripts behave in a recent version of Coda so the old script doesn't work anymore.

Link to comment
Share on other sites

Here's a new script I created earlier. It will list the elements in a levelled list. It uses one of the BFC functions.

CODA(ListLLEntries)

var Form
var arItems
var Item
var EditorID

begin
	Form = getFormByEditorID("VendorAmmo")
	arItems = getBFCLeveledListEntries(Form)
	foreach Item <- arItems
		EditorID = getEditorID(Item[0])
		printC("Item: "//$EditorID//" Level: "//formatNumber("%.0f",Item[1],0)//" Count: "//formatNumber("%.0f",Item[2],0))
	loop
end

Just replace VendorAmmo with the editor ID of the levelled list you want to get the details for.

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...