1. Please be advised of a few specific rules and guidelines for this section.

RELEASED Automatic Doors 3.9

Makes all doors open and close automatically!

  1. bk3k

    bk3k Oxygen Tank

    I believe that is intentional behavior for horizontal doors which are not in the exceptions. Although I could be wrong. The horizontal doors shouldn't scan above the doors. Thinking about it, I played with the radius and such I may have changed the scan area slightly. There is some commented out debug code I could use to determine make sure.

    If you don't mind, specifically what door where you using? If that door is one of the exceptions, we do have a problem to fix.
     
  2. Image Not Available

    Image Not Available Pangalactic Porcupine

    Encountered a glitch in the Avian story mission: after the big arena battle with the scorpion spawners the NPC is supposed to fall through a series of hatches in the ceiling. This mod prevents that, causing you to be stuck. Had to teleport out, remove the mod and replay the mission to get it working.
     
    lornlynx likes this.
  3. lornlynx

    lornlynx Cosmic Narwhal

    Haha, oh it IS intentional! But I initially implemented the functionality for a mod that added the ability to put all doors horizontal and let them function as trapdoors, this was when there were only vertical doors in the vanilla game.
    --- Post updated ---
    I will check upon this later today, thank you for the report.
     
  4. lornlynx

    lornlynx Cosmic Narwhal

  5. HoaxRumors

    HoaxRumors Phantasmal Quasar

    I've noticed a bit of weirdness with NPCs, gates, and trapdoors, though I'm not yet certain if it's this mod or just AI package shenanigans, and have admittedly not yet had a chance to test if it's been resolved in the last few updates (as I'm in the throes of experimental modding at current). Nobody seems to be able to intelligently navigate fence gates at all. This wouldn't be too much of an issue, if not for the fact that this includes gates generated by the game. As a result, almost everyone in a Floran colony on the second planet I visited now resides within about five meters of land, with most of them standing or running ineffectually in place, stopped by a wooden gate. They can manage high-tech weapons, retrofit crashed spaceships, and commandeer vehicles with an almost supernatural quickness of wit, but faced with a chest-high hinged wooden entry device of their own creation, the Florans seem to be completely nonplussed. I've more than a few times opened the gate for the (metaphorical and literal) forest of people, only to have them all stand about watching me expectantly and murmur about ssstabbyface and pretty bird--I fear the day their ineffectual gate-pushing pastimes cause hunger to overtake any semblance of civility on their behalf...

    As for trap doors, I set up a nice little three-story cabin right by the abandoned mineshaft that spawns on every starter planet, and had the friendly adventurer NPC who also spawns there move in almost immediately; while I was constructing the storage space in the attic, however, she insisted on pounding her head repeatedly on the simple wooden trapdoor I had placed as an entry point, and refused to stop until I opened it for her so she could run up to one of the campfires I was lighting the room with to warm her hands. After that, she promptly began running in circles over the hatch like a mad hen until I opened it for her again, at which point she promptly went to have a lie down in my bed; I assume the lack of oxygen from being in the recently closed attic with two lit campfires caused her to panic and forget how to operate the trap door. Since the cabin's completion, she's avoided the attic entirely, though it is now lit by a lovely portcullis window during the day, and a wall-mounted oil lamp in the evening. She'll wander around the rest of the rooms in the cabin without trouble, have a seat by the fireplace to rest her weary back (which she continues to claim is not due to the overloaded backpack she insists on wearing all the time), but I can't help but wonder if she's avoiding the attic out of fear that I might not be around to let her out next time.

    tl;dr: NPCs can't seem to operate gates at all (though they still attempt to path through them), and NPCs don't "see" trapdoors to open them, but can "see" trapdoors as an opening in the terrain, allowing their AI to attempt to path to an object on the other side of it to interact, which causes them to continually attempt to jump through the trapdoor without opening it (from below) or run in circles trying to find a way down (from above). The trapdoor in question was seven blocks up from the next floor down, with no intervening "ladder" platforms, as it was possible to flatfoot jump cleanly through the trapdoor even without manually opening it. Don't know yet if it could've either been not close enough for the AI to know to manually open the trapdoor from below (and couldn't do so during a jump) and/or wasn't detecting viable solid ground under the trapdoor when approaching it to leave the room, due either to the distance or the floor directly below being platforms.
     
  6. lornlynx

    lornlynx Cosmic Narwhal

    I can't say about the gates, I haven't tested them yet, but they should behave just like doors and those work fine with the mod.
    Trapdoors on the other hand, I have to admit that I've NEVER seen an npc use a trapdoor, like at all. I know that there is ai for platforms but it wouldn't actually surprise me if npc's are unable to operate trapdoors.
    I might test this myself in the coming days if I get the chance to.
     
  7. HoaxRumors

    HoaxRumors Phantasmal Quasar

    In setting up a clean modding environment for experimentation, I've found that all of my installation's beta data (which included a number of old, outdated, and/or unmarked mods) was being loaded into the game as well as the current 1.0 files, so I've cleared my install and allowed Steam to re-download Starbound fresh. If I can, I'll try to test the gate scenario again to see if it was a result of legacy code shenanigans and update accordingly, but in my distracted micromanagement, I deleted my save data as well, so I can't exactly test it out quickly--I encountered the Floran village a good six hours into the game during a late night binge playing session, and don't expect I'll have that kind of free time or lack of distraction in the foreseeable future.
    ETA: ...although it now occurs to me that I could probably recover the save data, as I think I sent it to the Recycle Bin instead of shift-deleting like I usually tend to do when I'm clearing a game's install to prep for reinstalling. As far as I know, Starbound doesn't have the Bethesda Effect with mods (that is, there is no true "clean uninstall" of script mods from save files in Bethesda games), so in theory, it'd be like a naturally reoccurring case of the gate scenario. I'll let you know how that turns out.
     
  8. bk3k

    bk3k Oxygen Tank

    I can at least tell you your tenants don't operate horizontal doors right. I "think" they want to go to directly to the left or right of objects position before opening the door. which... they can't do with a horizontal door. Being at a different horizontal level than the object itself won't satisfy that condition. I'm betting of course the regular NPCs work the same.

    I believe I know how to fix it, but that's a separate mod and SHOULD be a vanilla fix. Being door related as it is, it actually has nothing to do with this mod. I can see how people would assume otherwise.
     
  9. HoaxRumors

    HoaxRumors Phantasmal Quasar

    So, as it turns out, that gate issue wasn't related to this mod at all! As per the 1.0.3. patch notes:
    So we're all good in that regard!
     
  10. bk3k

    bk3k Oxygen Tank

  11. lornlynx

    lornlynx Cosmic Narwhal

  12. bk3k

    bk3k Oxygen Tank

    I believe I regressed the code I provided for 3.0 but hopefully lornlynx fixed all the problems. If not, let us know.

    How'd I manage such a thing?
    Dropbox
    multiple copies open at the same time
    The different folders containing these files(stable/nightly and the cloned copy my mod's doors point to), and needing to update all of them at each change pass
    staying up all night

    ^^pick one or more

    I need to get my act together and be more organized with this whole thing. Maybe setup symbolic links on my system for my mods. How I'm doing this isn't viable, and this latest screw up proves it.

    But again hopefully he caught everything, else yet ANOTHER version coming soon. Sorry for all the rapid fire updates!
     
    lornlynx likes this.
  13. lornlynx

    lornlynx Cosmic Narwhal

    Haha, yeah, setting up a file system that doesn't confuse the fuck outta you after some time is not as easy as it should be.

    I usually have "WIP Mods" folder in my starbound folder, and from it I copy a folder to the mods folder to work with it. When I finished a session of changes I copy it back into the wip folder. When the mod is then ready to be shipped, I have a completely different folder in another location on my harddrive in which I collect the latest paks, readmes, zips and have a folder "steam upload" I use solely for the workshop. It can be tedious at times, but the more steps there are before shipping, the harder it is to make mistakes with regression and such.
     
  14. Biofreak192

    Biofreak192 Void-Bound Voyager

    i found a bug on the outpost station where their automatic doors didn't open
     
  15. bk3k

    bk3k Oxygen Tank

    Code:
    
    -- automatic doors 3.1(tentative)
    -- basic code by Chucklefish, additional code by lornlynx (with some help from Healthire), greatly reworked and updated by bk3k
    -- the additional code  is documentated
    
    function init()
      message.setHandler("openDoor", function() openDoor() end)
      message.setHandler("lockDoor", function() lockDoor() end)
     
      storage.objectName = config.getParameter("objectName", "door")
      storage.defaultLocked = config.getParameter("defaultlocked", false)
      storage.maxInputNode = ( #(config.getParameter("inputNodes", {})) - 1 )
      storage.defaultInteractive = config.getParameter("interactive", true)
      storage.wireOpened = false
      self.Interacted = false
      self.npcClosed = false
      self.closeCooldown = 0
      self.openCooldown = 0
      storage.wireControlled = object.isInputNodeConnected(0)
      --^^this should fix the mission doors!
      self.noClearOpen = object.isOutputNodeConnected(0)
      --^^another issue fixed
      storage.openingAnimation_stateName = config.getParameter("openingAnimation", "open")  
      --if doors have an opening animation cycle and frames seperate from the "open" state
      --my doors use "opening"
      storage.lockedAnimation_stateName = config.getParameter("lockedAnimation", "closed")
      --if they have an actual locked animation and frames, use instead of "closed" when locked
      --my doors use "locked"
       
      if (storage.locked == nil) then   
      storage.locked = ( storage.defaultLocked or config.getParameter("locked", false) )
      end
     
      if (storage.isOpen == nil) then
      storage.isOpen = ((config.getParameter("defaultState", "closed") == "open") and storage.locked)
      end
       
      setDirection(storage.doorDirection or object.direction())
      initializeMaterialSpaces()
      --called only in init(), use before updateMaterialSpaces()
     
      if storage.isOpen and not storage.locked and not (storage.wireControlled and not storage.wireOpened) then
      realOpenDoor(storage.doorDirection)
      elseif storage.locked then
      lockDoor()
      else
      onInputMultiNodeChange()
      end
     
      updateInteractive()
      --updateCollisionAndWires()
      --updateLight()
      --opening/locking/closing door handles this already
     
      --automatic door specific stuff below
      storage.doorException = doorException() --check if door is part of exception list and return true or false
      noAutomatic()  --will set storage.noAuto if door should not be automatic
     
      if storage.noAuto then
      return
      end  --no need for the rest, save a few CPU cycles
     
      storage.boundVar = config.getParameter("detectBoundMode", "CollisionArea")
      setIncludedTypes()
      storage.isHorizontal = isDoorHorizontal()  
      storage.playerOpened = storage.playerClosed or false
      storage.playerClosed = storage.playerClosed or false
      setQuery()
    end
    
    
    function setIncludedTypes()
      storage.scanTargets = config.getParameter("scanTargets", {"player", "vehicle"})
      if not (#storage.scanTargets > 0) or not (type(storage.scanTargets) == "table") then
      storage.scatTargets = {"player", "vehicle"}
      end
    end
    
    
    function setQuery()  --new function of code moved from update() and called by init() so only done once
    
      --local objectName = config.getParameter("objectName", "door")
      storage.doorPosition = object.position()
      storage.queryRadius = config.getParameter("queryOpenRadius", 5) --I don't like the door opening directly in my face
     
      if (storage.objectName == "lunarbasedoor") then
      storage.queryRadius = 5.5
      storage.doorPosition[2] = storage.doorPosition[2] + 2.5
      storage.doorPosition[1] = storage.doorPosition[1]
      -- world.debugLine({storage.doorPosition[1], storage.doorPosition[2]}, {storage.doorPosition[1] + storage.queryRadius, storage.doorPosition[2] + storage.queryRadius}, "blue")
      -- changes door position slightly to make scanning position at height of half
      -- the door (or width if horizontal door)
      elseif storage.isHorizontal then
      storage.doorPosition[1] = storage.doorPosition[1] + 2.5
      storage.doorPosition[2] = storage.doorPosition[2]
      -- world.debugLine(getQueryArea(storage.doorPosition, storage.queryRadius)[1], getQueryArea(storage.doorPosition, storage.queryRadius)[2], "blue")
      else
      storage.doorPosition[2] = storage.doorPosition[2] + 2.5
      storage.doorPosition[1] = storage.doorPosition[1] + 0.5
      -- world.debugLine({storage.doorPosition[1], storage.doorPosition[2]}, {storage.doorPosition[1] + storage.queryRadius, storage.doorPosition[2] + storage.queryRadius}, "blue")
      end
     
      -- sb.loginfo("dt")
      -- world.debugPoint(storage.doorPosition, "green")
      -- world.debugPoint(object.position(), "red")
      -- world.debugText("pos: %s, %s", storage.doorPosition[1], storage.doorPosition[2], {object.position()[1], object.position()[2] + 1}, "black")
     
      -- checks for players around and saves
      -- them in array.
      self.queryArea = getQueryArea(object.position(), storage.queryRadius)
    end
    
    
    function onNodeConnectionChange(args)
      updateInteractive()
      storage.wireControlled = object.isInputNodeConnected(0)
      onInputNodeChange({ level = object.getInputNodeLevel(0) })
      updateCollisionAndWires()
      self.noClearOpen = object.isOutputNodeConnected(0)
    end
    
    
    function onInputNodeChange(args)  --modified
    -- @tab args Map of:
    --  {
    --  node = <(int) index of the node that is changing>
    --  level = <new level of the node>
    --  }
      if storage.maxInputNode > 0 then
      --delegate to another function
      onInputMultiNodeChange(args)
      return
      end
       
      if args.level then
      storage.wireOpened = true
      realOpenDoor(storage.doorDirection)
      else
      storage.wireOpened = false
      realCloseDoor()
      end
    end
    
    
    function onInputMultiNodeChange(args) --added
      if storage.defaultLocked then
      --delegate to another function
      secureControl(args)
      return
      end
     
      storage.wireOpened = false
      local n = 0
      while (n <= storage.maxInputNode) do
      if object.getInputNodeLevel(n) then
      storage.wireOpened = true
      break  --no need to continue if found any active wire
      end
      n = n + 1
      end
     
      if storage.wireOpened and not storage.isOpen then
      realOpenDoor(storage.doorDirection)
      elseif storage.isOpen then
      realCloseDoor()
      else
       
      end
     
    end
    
    
    function secureControl ()
      if object.getInputNodeLevel(0) and object.getInputNodeLevel(1) then --this requires multiple inputs to open, else lock
      unlockDoor()
      realOpenDoor(storage.doorDirection)
      else
      lockDoor()
      end
      --I may expand this later to demand wire inputs that conform to a pattern.  Such as having 8 input nodes,
      --and only opening when only the correct nodes are activated at once, perhaps in sequence!
      --For now think of this as a built-in AND switch
    end
    
    
    function onInteraction(args)
      if storage.locked then
      animator.playSound("locked")
      return
      end
     
      self.Interacted = true
      --because storage.isOpen will soon flip value
      storage.playerClosed = storage.isOpen
      storage.playerOpened = not storage.isOpen
     
      if not storage.isOpen then
      if storage.isHorizontal then
      -- give the door a cooldown before closing again
      realOpenDoor(args.source[2])
      self.closeCooldown = 2  --increased cooldown
      else
      realOpenDoor(args.source[1])
      self.closeCooldown = 0
      end
      else
      realCloseDoor()
      end
       
    end
    
    
    function updateLight()
      if not storage.isOpen then
      object.setLightColor(config.getParameter("closedLight", {0,0,0,0}))
      else
      object.setLightColor(config.getParameter("openLight", {0,0,0,0}))
      end
    end
    
    
    function updateInteractive()
      object.setInteractive(storage.defaultInteractive and not (object.isInputNodeConnected(0) or storage.defaultLocked or storage.locked))
    end
    
    
    function updateCollisionAndWires()
      updateMaterialSpaces()
      object.setMaterialSpaces(storage.isOpen and storage.openMaterialSpaces or storage.closedMaterialSpaces)
      object.setAllOutputNodes(storage.isOpen)
    end
    
    
    function updateMaterialSpaces()
      if object.isInputNodeConnected(0) then
      storage.closedMaterialSpaces = storage.materialTable[1]
      else
      storage.closedMaterialSpaces = storage.materialTable[2]
      end
     
    end
    
    
    function initializeMaterialSpaces()
      --forget the vanilla idea of reading attributes and rebuilding tables every time
      --lets just build and store 2 tables at init() time
      --and switch between them as needed with updateMaterialSpaces()
      storage.openMaterialSpaces = config.getParameter("openMaterialSpaces", {})
      storage.closedMaterialSpaces = config.getParameter("closedMaterialSpaces", {})
      storage.materialTable = { {}, {} }
      local metamaterial = {"metamaterial:door", "metamaterial:lockedDoor"}
      local j = 1
      local count = 2 --could use #metamaterial but why bother?
      local allSpaces = object.spaces()
      while j <= count do
      for i, space in ipairs(allSpaces) do
      table.insert(storage.materialTable[j], {space, metamaterial[j]})
      end
      j = j + 1
      end
      updateCollisionAndWires()
     
    end
    
    
    function setDirection(direction)
      storage.doorDirection = direction
      animator.setGlobalTag("doorDirection", direction < 0 and "Left" or "Right")
    end
    
    
    function hasCapability(capability)
      --this is called by
      --scripts/actions/movement.lua
      --scripts/pathing.lua
      --it would be more accurate to call the argument "currentState" but I'll preserve the original name anyhow
      if (capability == 'lockedDoor') then
      return storage.locked
      --elseif (object.isInputNodeConnected(0) or storage.wireOpened or storage.locked or (self.closeCooldown > 0) or (self.openCooldown > 0)) then
      elseif (object.isInputNodeConnected(0) or storage.wireOpened or storage.locked ) then
      return false
      elseif (capability == 'door') then
      return true
      elseif (capability == 'closedDoor') then
      return not storage.isOpen
      elseif (capability == 'openDoor') then
      return storage.isOpen
      else
      return false
      end
    end
    
    
    function doorOccupiesSpace(position)
      --used by objects/spawner/colonydeed/scanner.lua
      local relative = {position[1] - object.position()[1], position[2] - object.position()[2]}
      for _, space in ipairs(object.spaces()) do
      if math.floor(relative[1]) == space[1] and math.floor(relative[2]) == space[2] then
      return true
      end
      end
      return false
    end
    
    
    function lockDoor() --added because oddly because there is no locking function even while an unlocking one
      if not storage.locked and (self.closeCooldown >= 0) then
      if storage.isOpen then
      animator.setAnimationState("doorState", "locking")
      storage.isOpen = false
      animator.playSound("close")
      updateCollisionAndWires()
      updateLight()
      else --no need to close door etc, just change animation state
      animator.setAnimationState("doorState", storage.lockedAnimation_stateName)
      updateCollisionAndWires()
      updateLight()
      end
      storage.locked = true
      end
    end
    
    
    function unlockDoor()
      storage.locked = false
      updateInteractive()
      if not storage.isOpen then
      animator.setAnimationState("doorState", "closed")
      end
    end
    
    
    function realCloseDoor()
      -- only close door when cooldown is zero
      --if storage.isOpen and (self.closeCooldown <= 0) then
      if storage.isOpen then
      storage.isOpen = false
      animator.playSound("close")
      animator.setAnimationState("doorState", "closing")
      end
      updateCollisionAndWires()
      updateLight()
      -- world.debugText("Close!", object.position(), "red")
    end
    
    
    function closeDoor()
      --all internal functions will use realCloseDoor()
      --see openDoor() for why
    if storage.wireControlled then return end
      self.npcClosed = true
      self.openCooldown = 2
      realCloseDoor()
    end
    
    
    function openDoor(direction)
      --all internal functions will use realOpenDoor()
      --therefore if this is called, we know it is externally sourced and can take extra measures
      --which is why I renamed the original function
     
      --movement.lua and pathing.lua use this
      --world.callScriptedEntity(doorId, "openDoor")
      --some NPCs have the intended capacity to open locked doors and this will do just as well
      --the ones that do not will not even attempt to open a locked door
      --and if wired on node 0, hasCapability() will return false to all capacities except locked
      --so that's one area we got in trouble with before is NPCs who expect to open locked doors
     
      --I'm still unsure under what conditions message.setHandler() is used
      --go ahead and delete this block of comments after you've read them!
     
      unlockDoor()
      self.closeCooldown = 2
      if (direction == nil) then
      setDirectionNPC()
      end
      realOpenDoor(direction)
       
      --sb.logInfo("door.lua/openDoor() used on door with id" .. ( tostring( entity.id() ) ) .. "at position ".. ( tostring( entity.position() ) ) )
    end
    
    
    function realOpenDoor(direction)
      if not storage.isOpen then
      storage.isOpen = true
      setDirection((direction == nil or direction * object.direction() < 0) and -1 or 1)
      animator.playSound("open")
      animator.setAnimationState("doorState", storage.openingAnimation_stateName)
       
      if storage.isHorizontal and not self.interacted then
      self.openCooldown = 2
      end
      end
     
      updateCollisionAndWires()
      updateLight()
      -- world.debugText("Open!", object.position(), "red")
    end
    
    
    -- Checks if doors is horizontal, depending on different use of anchors.
    --
    -- @return BOOL value for confirmation
    --
    function isDoorHorizontal()
    --expanded upon to have a backup should there be no anchors, instead testing for itself in either horizontal direction.
    --going to switch to spaces() check  
    --This will only run from init()
      local theAnswer = config.getParameter("horizontal_door")
      if (theAnswer ~= nil) and (type(theAnswer) == "boolean") then
      return theAnswer
      end
      --if this is set, no need to further check
       
      local anchors = config.getParameter("anchors", {"top", "bottom"})
      for _,anchor in ipairs(anchors) do
      if anchor == "left" or anchor == "right" then
      return true
      end
      end
       
      theAnswer = false --lets assume false for now
      local toTheRight = {}
      local toTheLeft = {}
      toTheRight[1] = object.position()[1] + 3
      toTheRight[2] = object.position()[2]
      toTheLeft[1] = object.position()[1] - 3
      toTheLeft[2] = object.position()[2]
      --I suppose that would fail if verticle door was 4 thick, but I've never seen thicker than 3 (and that's a bit excessive already)
     
      local rightTable = world.objectQuery(toTheRight, 0)
      local leftTable = world.objectQuery(toTheLeft, 0)
     
      for k,v in pairs(rightTable) do
      table.insert( leftTable, v )
      end  --merged leftTable into RightTable
      local rtSize = #rightTable
     
      local i = 1
      while (i <= rtSize) do
      if (rightTable[i] == entity.id()) then
      theAnswer = true
      break
      end
      i = i + 1
      end --search all entities returned in this table, and check if the id matches this object.
       
      return theAnswer
    end
    
    
    -- Modifies query values for horizontal doors
    --
    -- If the door is horizontal, the position and radius are used as min & max
    -- positions which causes Query to use a rectangular scanning area.
    --
    -- @tab position Default door position
    -- @tab radius Wanted radius/sidelenght for scanning area
    --
    -- @return minPos Position for left bottom corner of scanning rectangle
    -- @return minPos Position for right top corner of scanning rectangle
    -- @return position Does get return unmodified if vertical door
    -- @return radius Does get return unmodified if vertical door
    --
    function getQueryArea(position, radius)
      if storage.isHorizontal then
      local minPos = {position[1] - radius, position[2] - radius}
      local maxPos = {position[1] + radius, position[2]} -- Don't query above, want players to walk on the door
      return {minPos, maxPos}
      else
      return {position, radius}
      end
    end
    
    
    function noAutomatic() --added
      --sets boolean variable to determine if automatic functionality will be disabled for this door
      storage.noAuto = (storage.doorException or storage.defaultLocked or config.getParameter("noAutomaticDoors", false))
    end
    
    
    function doorException() --added, call this before noAutomatic() in init()
      --I'd really prefer to load this from JSON, but don't know that Starbound would allow access beyond current object
      --so manual table loading it is!  This seems more managable in case more exceptions get added.
      local doorTable = {
      "castlehiddentrapdoor",
      "castlehiddendoor",
      "templehiddentrapdoor",
      "pilch_horizdoor",
      "dirttrapdoor",
       "stonedoor"}
     
      local doorCount = #doorTable
      local i = 1
      while (i <= doorCount) do
      if (doorTable[i] == storage.objectName) then
      return true
      end
      i = i + 1
      end
      return false
    end
    
    -- Main function, is running constantly with delta t time interval, functions esentially like an infinite while loop
    --
    function update(dt)
      -- lowers cooldown with each cycle
      if (self.closeCooldown > 0) then
      self.closeCooldown = self.closeCooldown - dt
      end
      if (self.openCooldown > 0) then
      self.openCooldown = self.openCooldown - dt
      end
     
      self.interacted = false
      --everything remaining is used to make doors automatic, and therefore should be skipped
      --when automatic functionality is undesirable.  No automatic when wired to input 1, opened by wire,
      --don't need automatic functionality when door opened from ANY wire input or locked
      if (((storage.wireControlled or storage.wireOpened) and not self.npcClosed) or storage.noAuto or storage.locked) then
      return
      elseif self.npcClosed and storage.wireControlled and (self.openCooldown <= 0) then
      --onInputNodeChange()
      setDirectionNPC()
      onInputMultiNodeChange()  --should open the door if still approriate per wire input at that point
      self.closeCooldown = 0.1
      self.openCooldown = 0.1
      self.npcClosed = false
      return
      end
     
      local objectIdsOpen = world.entityQuery(self.queryArea[1], self.queryArea[2], {
      withoutEntityId = entity.id(),
      includedTypes = storage.scanTargets,
      boundMode = storage.boundVar})
       
      if (#objectIdsOpen == 0) then
      -- resetting toggle once player gets out of range
      storage.playerClosed = false
       
      if not self.noClearOpen then
      --found some doors in missions with only wired outputs!
      --this will prevent doors with wired outputNode(0) from autoClosing when player opened
      storage.playerOpened = false
      end
      end
     
      autoOpen(objectIdsOpen)
      autoClose(objectIdsOpen)
     
    end
    
    
    function autoOpen(objectIdsOpen)
      if (#objectIdsOpen == 0) or storage.playerClosed or storage.isOpen or (self.openCooldown > 0) then
      return
      end
      -- query for player at door proximity
      local playerPosition = world.entityPosition(objectIdsOpen[1])
      -- sb.loginfo("Player detected!")
      -- open door in direction depending on position of the player
       
      if not storage.isHorizontal then
      realOpenDoor(playerPosition[1] - storage.doorPosition[1])
       storage.playerOpened = false
      self.closeCooldown = 0.1
      -- sb.loginfo("direction: %d", playerPosition[1] - object.position()[1])
      else
      realOpenDoor(playerPosition[2] - storage.doorPosition[2])
      storage.playerOpened = false
      self.closeCooldown = 2
      --added a small timer
      -- sb.loginfo("direction: %d", playerPosition[1] - object.position()[1])
      end
    end
    
    
    function autoClose(objectIdsOpen)
      if (self.closeCooldown > 0) or not storage.isOpen or (#objectIdsOpen > 0) or storage.playerOpened then
      return
      end
      -- check for NPCs in a smaller radius
      local npcIds = world.npcQuery(storage.doorPosition, storage.queryRadius - 3, {boundMode = storage.boundVar})
       
      -- prevents door spasming
      if (#npcIds > 0) and (not storage.isHorizontal) then
      return
      end
       
     --disable for NPC's, close when opened by player
      realCloseDoor()
      storage.playerClosed = false
    end
    
    function setDirectionNPC()
      --special case function corrects direction if NPC opened door or will be nearest when opening
      local npcIds = world.npcQuery(storage.doorPosition, storage.queryRadius - 3, {boundMode = storage.boundVar})
      if (#npcIds == 0) then
      return --in theory an NPC may move before this is called
      end
      local npcPosition = world.entityPosition(npcIds[1])
     
      if not storage.isHorizontal then
      setDirection((npcPosition[1] - storage.doorPosition[1]))
      else
      setDirection((npcPosition[2] - storage.doorPosition[2]))
      end
    end
    
    
    
    


    I say "try" because that needs tested. I "think" it works, but need to test it and can't do that until later. I've simply ran out of time. But feel free to give it a spin. Worse thing that happens is you need to revert to the current release version.
     
    Last edited: Aug 1, 2016
  16. Four Dyce

    Four Dyce Void-Bound Voyager

    Sorry if this is known, but just encountered a bug in the new undersea Hyotyl (spelling?) complexes. They use an airlock to enter/exit the place. You can activate the exterior doors to get in (via switch), but once inside you cannot activate the interior airlock doors, so you cannot get out. You also can't use the MM because the blocks that make up the place are invulnerable.
     
  17. lornlynx

    lornlynx Cosmic Narwhal

  18. lornlynx

    lornlynx Cosmic Narwhal

    lornlynx updated Automatic Doors with a new update entry:

    reverted & fixes

    Read the rest of this update entry...
    --- Post updated ---
    Ok, the rewrite brought a few issues with it that I couldn't all find yet. So far, I have reverted the version back to 2.7, which is just 2.6 (the latest stable version) but with a fix so that wired doors stay open if you leave and reenter the game. This should fix the Erchius mission and Hylotl city issues I've been reported to.
    --- Post updated ---
    And now, because I'm sick and tired of checking for a bugfix and thinking it is fixed, only to run into a different issue because I thought it would work anyways, I'm quickly writing together here a checklist for us on how to properly test all possible scenarios and functions of doors in the game, so I (and b3k3) can get a better workflow together.

    Known issues of 3.1:
    -wired doors change back to animationstate closed a while after being opened (physically you can still walk through), this is mostly viewable in the Erchius mission
    -people on the steam workshop site reported that NPC's get stuck in doors and make them unuseable that way, I haven't been able to replicate it yet, but it could very well be that it was fixed with the wired doors not staying open fix in 2.7 and 3.1

    Things that definitely have to be tested before shipping a new version:
    -doors should close after being wired
    -wired doors that got opened need to stay opened after /reload as well as after restarting the game
    -automatic doors should close as soon as a player or npc is out of range
    -automatic doors should not rapidly switch between two states if more than one player and/or npcs are in opening range
    -npcs should be able to open locked doors (see floranmission floran girl opening door for you)
    -stagehands should be able to open locked doors (see floranmission dirttrapdoor getting opened after boss died, see hylotlmission after boss)
    -locked doors should not be open by automatic functions (see hylotlmission)
    -wired doors that were opened need to stay opened after leaving the game (see hylotl cities)
    -always check horizontal door functionality
    -horizontal doors should wait a second if being opened by a stagehand (see avianmission after scorpionbattle where fat bird gets teleported while stagehand opens door)
    -outpost should function properly (speak no npcs getting stuck and stuff)
    -many NPCs on one place should not break doors (like spawning many npcs on ship)
    -should be able to still close/open door with E while standing near them with or without NPCs
    -always check logfile!


    Commands useful for testing:
    "/admin" - enables godmode & enables admincommands (so basically always use)

    "/spawnitem itemname itemcount parameters" - spawn items you need
    notable examples are:"/spawnitem dirtblock 100"," /spawnitem liquidfuel 1000", "/spawnitem flag'race'" (e.g. flagavian), "/spawnitem woodendoor 10", "/spawnitem miningverticaldoor", "/spawnitem tier1switch", "/spawnitem rareassaultrifle 1 '{"level":10}'" spawns a strong ranged weapon, "/spawnitem shipT7" spawns item that upgrades ship to Tier 7 (let's you use FTL drive)

    "/enabletech techname" - enables tech at techguy at outpost, e.g. "/enabletech doublejump" and "/enabletech sprint"

    "/warp instanceworld:dungeonname:youruniverseid" - e.g. "/warp instanceworld:floranmission1:youruniverseid", you can find youruniverseid in storage/universe/universe.dat, dungeonnames can be found in the unpacked assets in the dungeonfolders
    notable options are "floranmission1", "hylotlmission1", "avianmission1" and "outpost"

    "/warp CelestialWorld:coordinates" - coordinates can be found by "/whereami", notable example is "/warp CelestialWorld:-301442406:-834381527:-159290813:3" which are coords of a hylotlcity (walk to the left after porting down, at bottom of ocean, use http://www.starboundmap.com/ for first two coords, dunno what last two are meant for
     
    foghorn likes this.
  19. lornlynx

    lornlynx Cosmic Narwhal

  20. lornlynx

    lornlynx Cosmic Narwhal

Share This Page