Jump to content

Changing Object Model Via Script


JonesenoJ

Recommended Posts

To use this function you will need to know the difference between a "Base Object" and a "Reference to a Base Object".

A Base Object does not exist in the game as a 3D object, it exists as a bunch of data that describes the object.

A Reference to a Base Object is the individual 3D objects that exist in the game that can be interacted with, they use the data stored in the base object.

See image.

 

From my testing, this function only affects "References to Base Objects". That means that whatever items you want to modify, you are going to have to set a "Reference Editor ID". See step-by-step images on how to do that.

 

After setting a "Reference Editor ID", just use the functions like this:

 

 

ThisIsMyReference.SetModelPathEx "Clutter\Junk\Conductor.NIF"
ThisIsMyReference.Update3D

 

 

 

 

 

Or you can just follow this example, although it might be a little advanced.

 

 

Int TemporaryInt
Ref TemporaryRef
Array_Var TemporaryArray

Begin GameMode
	Let TemporaryArray := GetRefs 31, -1
	Set TemporaryInt To Ar_Size TemporaryArray
	While -1 < (TemporaryInt -= 1)
		Let TemporaryRef := TemporaryArray[TemporaryInt]
		
		If TemporaryRef.GetBaseObject == FissionBattery
			SetModelPathEx "Clutter\Junk\Conductor.NIF" TemporaryRef
			TemporaryRef.Update3D
		EndIf
		
	Loop
	Ar_Null TemporaryArray
End

 

This script will look at all the MISC items around the player and if any of them are Fission Batteries it will set their item model to that of conductors.

Edited by IntenseMute
Link to comment
Share on other sites

Thank you for explaining it with such great detail.

 

This is how my script looks now.

String_Var "Furniture\Suburban\SubCouch01.NIF"

 if eval CouchREF.GetModelPath == "Furniture\Suburban\SubCouch01.NIF"
  Showmessage 01AlreadyDone
 Endif

 if eval CouchREF.GetModelPath == "Furniture\Suburban\SubCouchDirty01.NIF" && Player.GetItemCount Caps001 < 1000
  Showmessage 01NoCaps
 Endif

 if eval CouchREF.GetModelPath == "Furniture\Suburban\SubCouchDirty01.NIF" && Player.GetItemCount Caps001 >= 1000
  CouchREF.SetModelPathEx "Furniture\Suburban\SubCouch01.NIF"
  CouchREF.Update3D
  Showmessage 01AllDone
  Player.RemoveItem f 1000
 Endif

Btw i spent one hour looking for an error, turned out I used > instead of <.

Link to comment
Share on other sites

That sort of error is quite common, and a devil to find. One way to avoid it is to simplify your code wherever possible. For instance (rhetorical question), what is the difference between:

if eval CouchREF.GetModelPath == "Furniture\Suburban\SubCouchDirty01.NIF" && Player.GetItemCount Caps001 < 1000
  <action>
endif
if eval CouchREF.GetModelPath == "Furniture\Suburban\SubCouchDirty01.NIF" && Player.GetItemCount Caps001 >= 1000
 <action>
endif

Answer: just the value being tested. And the choice of <action> is essentially an "If Caps001 < 1000 then <action1> ELSE <action2> EndIf". Now there is only one "condition value check" instead of two, but still multiple courses of <action>. If you were testing for which of three or more possible values of "Caps001", then it would be a "If <value1> ElseIf <value2> Else ... (must be something else, but is it unexpected?) ... EndIf". Because "Caps001" is only going to have one value at any given time and you are just trying to determine which.

 

Remember: Every "IF" implies an "Else", even if not explicitly stated. This has bitten more than one new script writer. You can always have an "Else" spit out a "debug" message so you know it got there during development, and then strip it out later. Might have saved you an hour.

 

-Dubious-

Link to comment
Share on other sites

In principle it should not matter how many messages you have in each case. You can always set one or more variables to the correct message content to be displayed under each condition, and then use a single statement or block to display each "non-null" variable message. Simplest example:

string sMsg ; initializes to ""
Begin <block type>
  If <condition1>
    set sMsg to 01AlreadyDone
    ; other statements as appropriate
  Elseif <condition2>
    set sMsg to 01NoCaps
    ; other statements as appropriate
  Elseif <condition3>
    set sMsg to 01AllDone
    ; other statements as appropriate
  Else
    set sMsg to "No condition match"
  EndIf
  ShowMessage sMsg  ; There should not be a "null" value of sMsg in this instance.
End

Another, related point:


A simple condition test of variables is quite efficient. It's when you use a function call as part of a condition test that you are slowing things down and losing efficiency, because the processing has to "save it's place" and all the values of variables in use in the current script at the time, so it can go off and perform the function and then return that result as a temporary variable AFTER it resumes where it had left off.


One of the problems with debugging "compound conditional tests" (e.g. "If <condition1> && <condition2>") is determining which of the conditions failed. But you have no way to determine what any function used in a conditional test returned. THAT variable is not one you defined. You are better off calling the function once before the conditional test, saving the result as a defined variable, and testing that variable as many times as needed thereafter. Even if you need to call the function several times, saving the result to a variable outside of a conditional test enables you to verify it returned something valid, which you can't do as part of the condition test itself. You want to make sure each component of your "compound" condition is working correctly before you combine them.

-Dubious-

Edited by dubiousintent
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...