Manipulating Static Objects through Local Scripts

Post » Mon Nov 16, 2015 7:54 pm

Hi all,

I've published a needs mod and am trying to improve its compatibility. For water sources in this mod, I made an activator with the vanilla nord well mesh and manually deleted and replaced each static well with the activator in the CS. The results are fine, but I can't help but wonder if it would be possible to dynamically replace each well using scripting at runtime, which would be a much more elegant solution for new lands mods like Tamriel Rebuilt and make the mod more compatible with town and settlement mods that move assets around in general. However, I have no idea how to implement this idea or even if it's entirely possible.
A few old forum threads I found...

http://creationkitten.tumblr.com/post/96604189758/statics-and-activators

http://www.gamesas.com/repairing-the-cogs-morrowind-t3063-175.html

http://www.mwmythicmods.com/Archives/CS/Comprehensive%20Animation%20for%20Morrowind%20-%20The%20How-To%20Thread.htm

http://www.fliggerty.com/phpBB3/viewtopic.php?f=22&t=4636

...seem to suggest that it's possible to reference and manipulate statics using scripts on other objects, possibly using MWSE, which is already required for my mod. However, I can't seem to find any information on how to declare or interact with objects in scripts that aren't directly attached to them.
Ideally, I would need to detect the wells in a loaded cell, get their XYZ coordinates and rotations, either disable/delete or offset them underneath the landscape, then place a scripted activator well in the original position.
I suspect this isn't possible via global script, but I was wondering if it would be possible to attach a local script to an item like a bucket that the player would carry around and manipulate the wells through a local script attached to such an object.
Does anyone know if this is possible, how to script it if so, or of any other mods that do something similar I could look to for a reference?

Thanks much!
User avatar
Jeff Turner
 
Posts: 3458
Joined: Tue Sep 04, 2007 5:35 pm

Post » Mon Nov 16, 2015 10:31 am

You should be able to scan/detect references in cell using XNextRef and the like. You could try xRefType to filter statics, xStringMatch (now working in latest MWSE updates by Merzasphor) to filter wells.

a global script should be fine as long as you add timers to avoid executing slow functions (e.g. some cell/inventory scanning, AI/3d functions...) each frame

The easiest not in game approach (a simple tab-delimited list) is probably to add a http://abitoftaste.altervista.org/morrowind/index.php?option=content&Itemid=10&task=viewpost&id=84&-Necessities-of-Morrowind-compatibility-with-landmass-mods-the-easy-waylike those available for NOM to swap static references ids in a mod with activators, or (more difficult) make a tes3cmd modify batch

[EDIT]typos, link

User avatar
NeverStopThe
 
Posts: 3405
Joined: Tue Mar 27, 2007 11:25 pm

Post » Mon Nov 16, 2015 11:01 am

Thanks for the quick reply Abot, also someone on the mod comments mentioned you had helped them with tweaking and bugfixing one of my mod's scripts a while back, so thanks for that too. I'll try to implement it with the functions you mentioned, awesome that you can call references directly by strings now.
User avatar
Haley Cooper
 
Posts: 3490
Joined: Wed Jun 14, 2006 11:30 am

Post » Mon Nov 16, 2015 10:39 am

So I hit a wall pretty quickly when I started testing it. A couple of walls rather. I started by making the script and attaching it to the common bucket item in the game, and am trying to make it so that upon activating the button the script finds the coordinates of the nearest loaded well, deletes it, and replaces it with a new one. Here is the code as I have it so far...

begin BN_WellReplaceScript
short WellCheck
short WellReplace
long NordWell
long TRWell
float WellPosX
float WellPosY
float WellPosZ
float WellAngle
if (OnActivate == 1)
if (GetPCSneaking == 1)
Activate
set WellCheck to 0
else
MessageBox, "Scanning For Wells"
setX NordWell to xGetRef "ex_nord_well_01"
set WellCheck to 1
endif
endif
if (WellCheck == 1)
if (NordWell != 0)
MessageBox, "Well Located"
xSetRef NordWell
set WellPosX to GetPos X
MessageBox, "Well X Position is %g", WellPosX
xSetRef NordWell
set WellPosY to GetPos Y
MessageBox, "Well Y Position is %g", WellPosY
xSetRef NordWell
set WellPosZ to GetPos Z
MessageBox, "Well Z Position is %g", WellPosZ
xSetRef NordWell
set WellAngle to GetAngle Z
MessageBox, "Well Angle is %g", WellAngle
set WellReplace to 1
else
MessageBox, "No Well Located"
endif
set WellCheck to 0
endif
if (WellReplace == 1)
MessageBox, "Disabled Well"
xSetRef NordWell
Disable
SetDelete 1
PlaceItem "BN_Nord_Well_01", WellPosX, WellPosY, WellPosZ, WellAngle
set WellReplace to 0
endif
end BN_WellReplaceScript
my first problem is that the functions that are supposed to fire on activate seem to fire every frame the bucket is in my inventory or on screen regardless of whether I am actually interacting with it. The second is that I seem not to be able to actually interact with the well once it's loaded; the script locates the well fine and returns non-zero float values for all it's coordinates and angle, but if I try to disable it or do anything else I get the "runfunction index greater than function count" error, or the game outright crashes.
Can anyone see any obvious flaws in it thus far? Does anyone know how to prevent scripts attached to misc objects from firing every frame like this, or how to actually manipulate statics once they're identified with xSetRef?
Any help is appreciated, thanks much.
User avatar
Trevor Bostwick
 
Posts: 3393
Joined: Tue Sep 25, 2007 10:51 am

Post » Mon Nov 16, 2015 2:10 pm

First of all you can use MWSE functions only in ifx statements. And you don't need any commas.
This should work:

begin BN_WellReplaceScriptshort WellCheckshort WellReplacelong NordWelllong TRWelllong templong StaticReffloat WellPosXfloat WellPosYfloat WellPosZfloat WellAngleif ( OnActivate == 1 )   if ( GetPCSneaking == 1 )      Activate      set WellCheck to 0   else      MessageBox "Scanning For Wells"      set WellCheck to 1   endifendififx ( WellCheck )ifx ( StaticRef )  setx StaticRef to xNextRef StaticRefelse  setx StaticRef to xFirstStaticendififx ( StaticRef )  xSetRef StaticRef  setx temp to xRefID  setx temp to xStringCompare temp "ex_nord_well_01"  ifx ( temp )  else   MessageBox "Well Located"   xSetRef StaticRef   set WellPosX to GetPos X   xSetRef StaticRef   set WellPosY to GetPos Y   xSetRef StaticRef   set WellPosZ to GetPos Z   xSetRef StaticRef   set WellAngle to GetAngle Z   StaticRef->Disable   StaticRef->SetDelete 1   PlaceItem "BN_Nord_Well_01" WellPosX WellPosY WellPosZ WellAngle  endifelse  messagebox "scanning done"  set WellCheck to 0endifendifend BN_WellReplaceScript
User avatar
.X chantelle .x Smith
 
Posts: 3399
Joined: Thu Jun 15, 2006 6:25 pm

Post » Mon Nov 16, 2015 8:30 pm

Thanks qqqbbb, I tried that script as written and with a few changes for testing, but the consistent problem is coming up that the xNextStatic command seems to be returning references to activators; I tried running the script in several interior and exterior cells, and when I set it to disable every reference it finds it deletes persistent activators such as doors, with the statics remaining untouched. I've tried this with both the Merzasphor MWSE alpha and the old 0.9.4 version included with MGE, but they have the same effect; does anyone know if this function works for actual statics?

User avatar
Cody Banks
 
Posts: 3393
Joined: Thu Nov 22, 2007 9:30 am

Post » Mon Nov 16, 2015 10:44 pm

Yeah, xFirstStatic does not return only static objects. And xFirstItem does not return only items. If one of them does not return ID you need , try the other one.
User avatar
lolli
 
Posts: 3485
Joined: Mon Jan 01, 2007 10:42 am

Post » Mon Nov 16, 2015 4:33 pm

FirstStatic doesn't return statics at all. That would be too intuitive. :D

Do something like this instead:

begin BN_WellReplaceScriptlong reflong tempfloat xPosfloat yPosfloat zPosfloat zRotif ( OnActivate == 0 )    returnelseif ( GetPCSneaking )    Activate    returnendifMessageBox "Scanning..."setx ref to xFirstItemwhilex ( ref )    setx temp to ref->xRefType    set temp to ( temp - 1413567571 )    ifx ( temp ); invalid type    else; is static type        setx temp to ref->xRefID        setx temp to xStringCompare temp "ex_nord_well_01"        ifx ( temp ); invalid id        else; id is "ex_nord_well_01"            xSetRef ref            set xPos to GetPos X            xSetRef ref            set yPos to GetPos Y            xSetRef ref            set zPos to GetPos Z            xSetRef ref            set zRot to GetAngle Z            ref->Disable            ref->SetDelete 1            PlaceItem "BN_Nord_Well_01" xPos yPos zPos zRot            MessageBox "Found & Replaced!"            return        endif    endif    setx ref to xNextRef refendwhileend

In the real world you'll probably want to stagger that scan over multiple frames, this should get you started though.

User avatar
Austin England
 
Posts: 3528
Joined: Thu Oct 11, 2007 7:16 pm


Return to III - Morrowind