HerrBaron Posted December 19, 2010 Share Posted December 19, 2010 Hey folks, I'm the guy who built HB's Wasteland Tent, and I'm looking to upgrade it to accomodate companions beyond the vanilla ones. These were easy, since they're present in the FalloutNV.esm. The issues and questions revolve around a characteristic of the Havoc door objects; when a door is moved, its' location is not updated by the engine; believe me, I've tried several different ways. Hence, the Wasteland Tent doesn't use a door; just a couple of travel markers and the MoveTo function (for both the player and the vanilla followers subject to some checks to make sure that they're actually following, not waiting and not disabled). In other words, the Tent model itself is an activator. As stated above, I'd like to be able to support other companions, such as Fake Plastic Trees EDE and GurkMeja's Sunny Smiles Companion (and a number of others recently uploaded to Nexus). One of the things I've tried to do in preparation for this is to generalize the code which tests follower/waiting/disabled status before moving a follower into or out of the tent after the player. I did this with a formlist and NVSE to loop over and process it. It doesn't work, even for the vanilla followers, apparently because the engine has no way of knowing that an aliased reference to a reference (set rFollower to ListGetNthForm VanillaFollowerList, index). When you attempt to test variables through rFollower, the engine has no way of knowing that rFollower actually points at a follower with a script which contains variables like Waiting.I've only been able to make it work for vanilla followers by duplicating the same conditional code block for each one. So, if generalizing this code doesnt' work for vanilla followers, it seems to bode ill for others not even in FalloutNV.esm. Anyone have any ideas as to how I might: A) get a door object to actually update its world location if moved,orB) Generalize the entry/exit code in such a way as to make it possible to test both vanilla followers and any others I might add to the list in the course of play? I've been fighting this for weeks, now; if anyone has any workable ideas, I'd be most grateful. Thanks!-HB Link to comment Share on other sites More sharing options...
Interfer0 Posted December 20, 2010 Share Posted December 20, 2010 * MoveTo is an excellent way to move an object from one cell to another. * Consider using SetPos if MoveTo doesn't do the trick. * If this function is used to move the player, the function will queue up a movement request which will NOT process immediately and will NOT halt script execution. * This function works as expected for Actors. For most other object types, like containers and activators, the object's coordinates are updated but its world art is not. Additional scripting may be necessary to ensure the object moves properly: myObject.DisablemyObject.MoveTo myMarkermyObject.Enableset xPos to myObject.GetPos XmyObject.SetPos X xPos * The trick above won't work with pre-loaded furnitures : It seems neither MoveTo nor SetPos are allowed with furniture objects unless they are spawned with the PlaceAtMe function. Try using this, but create a new door. I am not sure what they mean by Pre-Loaded furnitures. Try it wil This door I know it doesn't fit, but will work for testing. Link to comment Share on other sites More sharing options...
thc1234 Posted December 20, 2010 Share Posted December 20, 2010 (edited) well, You may do some "probablistic" checks with NVSE.... You need to find out a) current companionsb) their waiting status I would assume any companions which are NOT waiting are close to tent when it's door is activated. so that's b)by iterating over actors in current cell (NVSE GetFirstRef/GetNextRef) and using GetIsTeamMate (not even sure if this is true when companion is waiting) You can build formlist in OnActivate.then You can in OnLoad of Your tent use PlaceAtMe. as I said it's "probabilistic" however something better than nothing. (and also simple to code :P)at worst it will end up teleporting companions waiting outside of tent into it... (You may also add activate choice whenever player want to enter tent alone so those pervs can do inside what they want) Edited December 20, 2010 by thc1234 Link to comment Share on other sites More sharing options...
HerrBaron Posted December 21, 2010 Author Share Posted December 21, 2010 * MoveTo is an excellent way to move an object from one cell to another. * Consider using SetPos if MoveTo doesn't do the trick. * If this function is used to move the player, the function will queue up a movement request which will NOT process immediately and will NOT halt script execution. * This function works as expected for Actors. For most other object types, like containers and activators, the object's coordinates are updated but its world art is not. Additional scripting may be necessary to ensure the object moves properly: myObject.DisablemyObject.MoveTo myMarkermyObject.Enableset xPos to myObject.GetPos XmyObject.SetPos X xPos * The trick above won't work with pre-loaded furnitures : It seems neither MoveTo nor SetPos are allowed with furniture objects unless they are spawned with the PlaceAtMe function. Try using this, but create a new door. I am not sure what they mean by Pre-Loaded furnitures. Try it wil This door I know it doesn't fit, but will work for testing. Thanks, Interfero; found something similar on the GECK wiki, but oddly, the door I'm using won't move consistently, only sometimes... pretty odd. Even tried using SetPos instead of MoveTo; no joy. -HB Link to comment Share on other sites More sharing options...
HerrBaron Posted December 21, 2010 Author Share Posted December 21, 2010 well, You may do some "probablistic" checks with NVSE.... You need to find out a) current companionsb) their waiting status I would assume any companions which are NOT waiting are close to tent when it's door is activated. so that's b)by iterating over actors in current cell (NVSE GetFirstRef/GetNextRef) and using GetIsTeamMate (not even sure if this is true when companion is waiting) You can build formlist in OnActivate.then You can in OnLoad of Your tent use PlaceAtMe. as I said it's "probabilistic" however something better than nothing. (and also simple to code :P)at worst it will end up teleporting companions waiting outside of tent into it... (You may also add activate choice whenever player want to enter tent alone so those pervs can do inside what they want) thc1234, Working on something like this as we speak; I was trying to stay away from NVSE (Not because I don't like it, NVSE is terrific; I was just hesitant to introduce it into my codebase if I could think of another way to do it...). I'll post back as soon as I get it working, and let you know how it worked out! BTW, isn't PlaceAtMe only useable with form id's, not persistent references, like, say, BooneREF or VeronicaREF? Since there's only one of these each in-game, wouldn't you be creating copies of them, and bloating the game saves? You're right; they are ALL pervs; you should SEE what they get upto in that tent when my back is turned! :P -HB Link to comment Share on other sites More sharing options...
Ez0n3 Posted December 21, 2010 Share Posted December 21, 2010 You may be able to use GetCurrentAIPackage to test if the ref is using a guard package or sandbox (for mods that change guard to sandbox for followers). Perhaps in combination with GetPlayerTeammate and/or GetInFaction (Followers Faction). Link to comment Share on other sites More sharing options...
HerrBaron Posted December 21, 2010 Author Share Posted December 21, 2010 Well, got it working very nicely; gotta test it for a while though. I've attached the Entry code as a .TES file, since the code markers make a mess of the embedded code. All I have to do now is set up the quest code to check for NVSE and warn the user, and test for a good while. I used several of the suggestions from you guys; many thanks for helping me make a better mod than I had before! :) Best!-HB P.S. it sure would be nice if the GECK could process line breaks in long lines of code; not doing so makes it tough to write complex conditional code, because it all has to go on the same line... Link to comment Share on other sites More sharing options...
Ez0n3 Posted December 22, 2010 Share Posted December 22, 2010 (edited) For an NVSE check, you can do something like: Global: MyModNVSEVersionGLOB (constant "0") Quest: MyModNVSECheckQUSTscn MyModNVSECheckQUSTSCPT Begin GameMode if (MyModNVSEVersionGLOB == 0) set MyModNVSEVersionGLOB to -1 ; No NVSE set MyModNVSEVersionGLOB to GetNVSEVersion ; NVSE Version endif End If they don't have NVSE, MyModNVSEVersionGLOB will be set to "-1" and then the next line will cause the script to stop running because of "GetNVSEVersion". If they have NVSE, MyModNVSEVersionGLOB will be the version they are using. So you can test for: Quest: MyModInitializeQUSTscn MyModInitializeQUSTSCPT int iNVSEVer Begin GameMode if (iNVSEVer != MyModNVSEVersionGLOB) if (MyModNVSEVersionGLOB == 0) Return ; give the check more time else if (MyModNVSEVersionGLOB > 0) ; They have NVSE ShowMessage MyModNVSEYesMESG else ; They do not have NVSE ShowMessage MyModNVSENoMESG endif set iNVSEVer to MyModNVSEVersionGLOB endif endif End The check will be run every time the game starts (because MyModNVSEVersionGLOB is constant, it will get reset to "0"). it sure would be nice if the GECK could process line breaks in long lines of code It sure would. If you're interested, there's a post floating around by Cipscis which talks about script performance. Where he times different logic to see which is the fastest. He noted that the more operators used, the slower the performance. It was actually faster to use separate conditional statements rather than "this && that && those && these" etc. ; Slower - checks all 5 every time if ( ( rFollower.GetCurrentAIProcedure == 11 ) && ( rFollower.GetPackageTarget == Player ) && ( rFollower.GetDisabled == 0 ) && ( rFollower.GetDead == 0 ) && ( rFollower.GetUnconscious == 0 ) ) ; Do stuff endif ; Faster - could even arrange by which are most likely to be true if ( rFollower.GetCurrentAIProcedure == 11 ) if ( rFollower.GetPackageTarget == Player ) if ( rFollower.GetDisabled == 0 ) if (rFollower.GetDead == 0 ) if ( rFollower.GetUnconscious == 0 ) ; Do stuff endif endif endif endif endif Or if you're dealing with a boolean (true/false), you can leave the operators out completely. It was faster to run an if/else with no operators than an if with. ; Slower - check if equal to 0 every time if ( rFollower.GetDisabled == 0 ) ; Do stuff endif ; Faster - not doing a logical comparison if ( rFollower.GetDisabled ) ; functions like "rFollower.GetDisabled != 0" else ; Do stuff endif So, something like this would theoretically be the fastest: if ( rFollower.GetDead ) else if ( rFollower.GetDisabled ) else if ( rFollower.GetUnconscious ) else if ( rFollower.GetCurrentAIProcedure == 11 ) if ( rFollower.GetPackageTarget == Player ) ; Do stuff endif endif endif endif endif Having it all on one line is nice and neat, but not necessarily the best choice - if you're talking performance. Edit:I think there's a max of around 10 nested if's though. Edited December 22, 2010 by Ez0n3 Link to comment Share on other sites More sharing options...
HerrBaron Posted December 22, 2010 Author Share Posted December 22, 2010 For an NVSE check, you can do something like: Global: MyModNVSEVersionGLOB (constant "0") Quest: MyModNVSECheckQUSTscn MyModNVSECheckQUSTSCPT Begin GameMode if (MyModNVSEVersionGLOB == 0) set MyModNVSEVersionGLOB to -1 ; No NVSE set MyModNVSEVersionGLOB to GetNVSEVersion ; NVSE Version endif End If they don't have NVSE, MyModNVSEVersionGLOB will be set to "-1" and then the next line will cause the script to stop running because of "GetNVSEVersion". If they have NVSE, MyModNVSEVersionGLOB will be the version they are using. So you can test for: Quest: MyModInitializeQUSTscn MyModInitializeQUSTSCPT int iNVSEVer Begin GameMode if (iNVSEVer != MyModNVSEVersionGLOB) if (MyModNVSEVersionGLOB == 0) Return ; give the check more time else if (MyModNVSEVersionGLOB > 0) ; They have NVSE ShowMessage MyModNVSEYesMESG else ; They do not have NVSE ShowMessage MyModNVSENoMESG endif set iNVSEVer to MyModNVSEVersionGLOB endif endif End The check will be run every time the game starts (because MyModNVSEVersionGLOB is constant, it will get reset to "0"). it sure would be nice if the GECK could process line breaks in long lines of code It sure would. If you're interested, there's a post floating around by Cipscis which talks about script performance. Where he times different logic to see which is the fastest. He noted that the more operators used, the slower the performance. It was actually faster to use separate conditional statements rather than "this && that && those && these" etc. ; Slower - checks all 5 every time if ( ( rFollower.GetCurrentAIProcedure == 11 ) && ( rFollower.GetPackageTarget == Player ) && ( rFollower.GetDisabled == 0 ) && ( rFollower.GetDead == 0 ) && ( rFollower.GetUnconscious == 0 ) ) ; Do stuff endif ; Faster - could even arrange by which are most likely to be true if ( rFollower.GetCurrentAIProcedure == 11 ) if ( rFollower.GetPackageTarget == Player ) if ( rFollower.GetDisabled == 0 ) if (rFollower.GetDead == 0 ) if ( rFollower.GetUnconscious == 0 ) ; Do stuff endif endif endif endif endif Or if you're dealing with a boolean (true/false), you can leave the operators out completely. It was faster to run an if/else with no operators than an if with. ; Slower - check if equal to 0 every time if ( rFollower.GetDisabled == 0 ) ; Do stuff endif ; Faster - not doing a logical comparison if ( rFollower.GetDisabled ) ; functions like "rFollower.GetDisabled != 0" else ; Do stuff endif So, something like this would theoretically be the fastest: if ( rFollower.GetDead ) else if ( rFollower.GetDisabled ) else if ( rFollower.GetUnconscious ) else if ( rFollower.GetCurrentAIProcedure == 11 ) if ( rFollower.GetPackageTarget == Player ) ; Do stuff endif endif endif endif endif Having it all on one line is nice and neat, but not necessarily the best choice - if you're talking performance. Edit:I think there's a max of around 10 nested if's though. Ez0n3, Good stuff; thanks! I did run across that thread of Cipcis', over at the Bethsoft forums, but admittedly didn't spend more than a few minutes perusing it. I did intend to go back... Anyway, when I'm not focusing on the 'day job' (30 yrs+ as a software engineer), I've been focusing on getting this mod upgrade working, then getting it to work better... :thumbsup: Great suggestions you've made; I'll be using them. I'm very partial to the "If yada" notation; I use it in real life development all the time, but it seemed to me that I had some issues with it in TES script way back, so have kinda stayed away from it. The only thing currently in the quest script for the tent is a one-time Player.AddItem to stick the manual in their inventory, then I call StopQuest on it, since it never needs to execute again, so maybe I'll work that into a global flag, as well, and remove the StopQuest call. Anyway, thanks for all this; I'll be back! Best,-HB Link to comment Share on other sites More sharing options...
Ez0n3 Posted December 22, 2010 Share Posted December 22, 2010 (edited) I hear ya :) I did run across that thread of Cipcis', over at the Bethsoft forumsAhh, that's why I couldn't find it, here it is: Script Optimisation If you StopQuest the NVSE checker and then save, the next load, it will be stopped still (one time only check). If you want it to check if they are running NVSE every time it loads (in case they started it without NVSE after they already saved), you'll have to leave it running. Edited December 22, 2010 by Ez0n3 Link to comment Share on other sites More sharing options...
Recommended Posts