Difference between revisions of "Talk:Door"

From the CreationKit Wiki
Jump to navigation Jump to search
imported>Tunaisafish
 
(12 intermediate revisions by 7 users not shown)
Line 25: Line 25:
::There are also a few supplied scripts that are meant to control door access; eg. DefaultNoEnemiesFollowDoorScript.psc & DefaultNoFollowDoorScript.psc
::There are also a few supplied scripts that are meant to control door access; eg. DefaultNoEnemiesFollowDoorScript.psc & DefaultNoFollowDoorScript.psc
::Look at those and see if you can configure them to your liking using the properties, or roll your own script using those as an example. -- [[User:Tunaisafish|Tunaisafish]] 05:47, 17 April 2012 (EDT)
::Look at those and see if you can configure them to your liking using the properties, or roll your own script using those as an example. -- [[User:Tunaisafish|Tunaisafish]] 05:47, 17 April 2012 (EDT)
How do I set a patrol route, I'm new to modding, and sorry for the wait, I wasn't expecting a reply. [[User:GetTheJojDone|GetTheJojDone]] 09:25, 19 May 2012 (EDT)
== Random teleports ==
The reason the assertion failure and subsequent crash occur when saving these is because the code to save them, within <code>TESObjectDOOR::SaveForm</code>, looks like this:
<pre lang="C++">
if (this->random_destinations.size() > 0) {
  uint32_t i = 0;
  do {
      uint32_t to_write = this->random_destinations[i]->formID;
      if (bSwapEndianness) { // global bool
        to_write = _byteswap_ulong(to_write);
      }
      _WriteSubrecord('TNAM', &to_write, sizeof(to_write));
  } while (++i, this->random_destinations.size() != 0); // should've been: ++i < this->random_destinations.size()
}
</pre>
Verified by reverse-engineering the LE CK. [[User:DavidJCobb|DavidJCobb]] ([[User talk:DavidJCobb|talk]]) 21:22, 30 June 2024 (EDT)
:Additional reverse-engineering:
:
:First, let's define some terms to make this easier. When the player interacts with a door ref whose base form has random destinations, that door ref &mdash; the ''source door'' &mdash; needs to be linked to a ''destination door''. The random destinations in the base form's list are ''destination spaces'' i.e. worldspaces and interior cells, and the game must find a suitable destination door from a randomly-selected destination space. The ''source space'' is the worldspace or interior cell that contains the source door.
:When two load doors ''A'' and ''B'' are linked, we say that ''A'' is ''B''&apos;s ''opposing door'', and ''B'' is ''A''&apos;s opposing door. Lastly, every functional load door has a ''teleport marker'', which is a piece of data specifying the position and rotation that an actor should arrive at (in the same space as the opposite door) after traveling through the door. Teleport markers are not refs; they are named for the visible marker you see in the Creation Kit when fiddling with load doors.
:
:'''The process for linking a source door to a destination door is as follows:'''
:# Pick a random destination space.
:#* If we've already tried this destination space, re-roll until we've tried all spaces.
:#* If we've tried all spaces, give up on finding a destination door, and don't link the source door to anything. The algorithm has failed.
:# Search all doors inside of this destination space, stopping on the first eligible door we find. (If it's a worldspace, we search its persistent cell.) A door ref is eligible to become the destination door if it meets these requirements:
:#* Not in the same space as the source door
:#* Not deleted, disabled, or [[Destructible Objects|destroyed]]
:#* Its base form also has random destinations, and one of those is the source space
:#* The door is not already linked to any other load door
:# If we find a suitable destination door, then link it to the source door.
:
:'''Failure case:''' If the game fails to pick a random destination for a randomized teleport door, then it shows the value of game setting ''sRandomDoorTeleportFailureMessage'' as a notification. The default value of that setting seems to be, "This door leads nowhere."
:'''Success case:''' Link the source door to the destination door. By default, given two randomly-linked doors ''A'' and ''B'', door ''A'' will have its teleport marker positioned directly in front of door ''B'', at a distance of ''fRandomDoorDistance'' units (or, if the other door is an automatic door, at a distance of ''max(fAutoDoorActivateDistance + 100.0, fRandomDoorDistance)'' units instead), and vice versa. This should generally work fine, but in order to allow for positioning teleport markers more precisely, the game ''does'' support the <code>REFR/XRTM</code> subrecord. This subrecord allows a potential destination door to specify a separate marker ref; if the door is randomly linked (i.e. if it's a source door or a destination door), then the position and rotation of that marker ref will be copied to serve as the position and rotation of the opposing door's teleport marker.
:[[User:DavidJCobb|DavidJCobb]] ([[User talk:DavidJCobb|talk]]) 22:53, 30 June 2024 (EDT)
::There is a final wrinkle. The game uses <code>ExtraTeleport</code> to connect two load doors together. This data is pre-generated in the Creation Kit for normal load doors (for the purposes of this comment we'll call these "pre-linked doors"), and created at run-time (and recalled from the savegame) for doors that have been randomly linked. Notably, this means that if a potential destination door is pre-linked, it will fail the requirements listed above. However, it doesn't appear that the game checks whether a source door is pre-linked; so if you interact with a pre-linked random source door, and the game manages to find a destination door, that should end up clobbering the <code>ExtraTeleport</code> for the source door, but ''not'' the third door that it was originally pre-linked with. Potentially this could allow you to break the 1:1 mapping for doors, e.g. ''A'' and ''C'' both lead to ''B'', and ''B'' leads only to ''C''. I would not recommend doing this.
::Potential shenanigans that could lead to this include: using third-party tools; or pre-placing a door, pre-linking it, and then editing its base form to have random destinations. [[User:DavidJCobb|DavidJCobb]] ([[User talk:DavidJCobb|talk]]) 23:02, 30 June 2024 (EDT)

Latest revision as of 22:02, 30 June 2024

Controlling NPC usage[edit source]

[Moved from Talk:Papyrus]

Would anyone happen to know how to stop certain actors from opening a certain door? GetTheJojDone 16:10, 15 April 2012 (EDT)

The ways I can think of:
  1. don't given that NPC any packages that could cause it to travel through the door: give it fixed patrols to follow, make it sandbox out of range of the door, etc. This is the most obvious, simplest way, but fails in extreme situations (if you attack them, they might flee through the door still, etc).
  2. make the NPC "bound", as a more restrictive version of the above (problem; they are then unable to walk around).
  3. make the door "min use" (problem: affects all NPCs).
  4. lock the door, and don't give the NPC the key (problem: has no effect once door opens; affects other NPCs).
  5. have a separate navmesh either side of the door, with no connection between the two sides of the door (affects all NPCs; unreliable).
  6. (maybe?) set ownership of the door to everyone but that person? Not sure door ownership matters if unlocked, though.
  7. have a collision primitive around the door and make it so that this NPC is the only thing that collides with it. Not sure if that's even possible.
  8. have a collision primitive around the door with an OnTriggerEnter script that detects that NPC approaching, and changes their chosen package to be "walk away from this door". This way, everyone else can use the door freely, but the door is impassible to that one NPC even if you have made them a follower and are leading them through it (however, they may magically teleport to join you the next time you enter a new cell, if they are a follower).
If it's a teleport door, ensure that the collision primitive encloses the red navmesh triangle for the door, as well as/instead of the door itself.
Beware that this might result in them walking up to the door and back away again repeatedly, if their default package can only be fulfilled by passing through the door.
Beware also that if the player leaves and returns after a few days, that NPC may be randomly placed anywhere in that cell, ignoring primitives and navmesh constraints and sometimes even locked doors! One workaround might be to have another collision primitive to detect the player approaching/leaving, then either move the NPC to a known-valid position on the correct side of the door when the player approaches; or binds the NPC in position, while the player is away.
Hope some of those ideas were useful. --Catwheezle 23:44, 16 April 2012 (EDT)


There are also a few supplied scripts that are meant to control door access; eg. DefaultNoEnemiesFollowDoorScript.psc & DefaultNoFollowDoorScript.psc
Look at those and see if you can configure them to your liking using the properties, or roll your own script using those as an example. -- Tunaisafish 05:47, 17 April 2012 (EDT)

How do I set a patrol route, I'm new to modding, and sorry for the wait, I wasn't expecting a reply. GetTheJojDone 09:25, 19 May 2012 (EDT)

Random teleports[edit source]

The reason the assertion failure and subsequent crash occur when saving these is because the code to save them, within TESObjectDOOR::SaveForm, looks like this:

if (this->random_destinations.size() > 0) {
   uint32_t i = 0;
   do {
      uint32_t to_write = this->random_destinations[i]->formID;
      if (bSwapEndianness) { // global bool
         to_write = _byteswap_ulong(to_write);
      }
      _WriteSubrecord('TNAM', &to_write, sizeof(to_write));
   } while (++i, this->random_destinations.size() != 0); // should've been: ++i < this->random_destinations.size()
}

Verified by reverse-engineering the LE CK. DavidJCobb (talk) 21:22, 30 June 2024 (EDT)

Additional reverse-engineering:
First, let's define some terms to make this easier. When the player interacts with a door ref whose base form has random destinations, that door ref — the source door — needs to be linked to a destination door. The random destinations in the base form's list are destination spaces i.e. worldspaces and interior cells, and the game must find a suitable destination door from a randomly-selected destination space. The source space is the worldspace or interior cell that contains the source door.
When two load doors A and B are linked, we say that A is B's opposing door, and B is A's opposing door. Lastly, every functional load door has a teleport marker, which is a piece of data specifying the position and rotation that an actor should arrive at (in the same space as the opposite door) after traveling through the door. Teleport markers are not refs; they are named for the visible marker you see in the Creation Kit when fiddling with load doors.
The process for linking a source door to a destination door is as follows:
  1. Pick a random destination space.
    • If we've already tried this destination space, re-roll until we've tried all spaces.
    • If we've tried all spaces, give up on finding a destination door, and don't link the source door to anything. The algorithm has failed.
  2. Search all doors inside of this destination space, stopping on the first eligible door we find. (If it's a worldspace, we search its persistent cell.) A door ref is eligible to become the destination door if it meets these requirements:
    • Not in the same space as the source door
    • Not deleted, disabled, or destroyed
    • Its base form also has random destinations, and one of those is the source space
    • The door is not already linked to any other load door
  3. If we find a suitable destination door, then link it to the source door.
Failure case: If the game fails to pick a random destination for a randomized teleport door, then it shows the value of game setting sRandomDoorTeleportFailureMessage as a notification. The default value of that setting seems to be, "This door leads nowhere."
Success case: Link the source door to the destination door. By default, given two randomly-linked doors A and B, door A will have its teleport marker positioned directly in front of door B, at a distance of fRandomDoorDistance units (or, if the other door is an automatic door, at a distance of max(fAutoDoorActivateDistance + 100.0, fRandomDoorDistance) units instead), and vice versa. This should generally work fine, but in order to allow for positioning teleport markers more precisely, the game does support the REFR/XRTM subrecord. This subrecord allows a potential destination door to specify a separate marker ref; if the door is randomly linked (i.e. if it's a source door or a destination door), then the position and rotation of that marker ref will be copied to serve as the position and rotation of the opposing door's teleport marker.
DavidJCobb (talk) 22:53, 30 June 2024 (EDT)
There is a final wrinkle. The game uses ExtraTeleport to connect two load doors together. This data is pre-generated in the Creation Kit for normal load doors (for the purposes of this comment we'll call these "pre-linked doors"), and created at run-time (and recalled from the savegame) for doors that have been randomly linked. Notably, this means that if a potential destination door is pre-linked, it will fail the requirements listed above. However, it doesn't appear that the game checks whether a source door is pre-linked; so if you interact with a pre-linked random source door, and the game manages to find a destination door, that should end up clobbering the ExtraTeleport for the source door, but not the third door that it was originally pre-linked with. Potentially this could allow you to break the 1:1 mapping for doors, e.g. A and C both lead to B, and B leads only to C. I would not recommend doing this.
Potential shenanigans that could lead to this include: using third-party tools; or pre-placing a door, pre-linking it, and then editing its base form to have random destinations. DavidJCobb (talk) 23:02, 30 June 2024 (EDT)