carry.lua 5.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. -- The native pickup grants the cell and the receptacle owns its usability/item criteria.
  2. -- Ownership Sense distinguishes held, dropped and missing cells. Only accepted receptacle
  3. -- interaction completes delivery; proximity and the recording's timing cannot complete it.
  4. return function(api, tag, pickup, receptacle, on_pickup, on_deposit)
  5. local function key(suffix) return "ember.carry." .. tag .. "." .. suffix end
  6. local function generation(s) return s:variable(key("generation")) or 1 end
  7. local function recovery(s) return "ember.carry.recover." .. tag .. "." .. generation(s) end
  8. local region = tag == "processing" and 56 or 0
  9. local obj = {}
  10. function obj.start(c, s)
  11. if s:variable(key("started")) then return end
  12. c:set_variable(key("started"), true)
  13. c:set_variable(key("receptacle_generation"), generation(s))
  14. api.slot(c, pickup):set_interactable_object{generation = generation(s), track_owner = true}
  15. api.slot(c, receptacle):set_interactable_object{generation = generation(s)}
  16. end
  17. function obj.interaction(c, s, e)
  18. if not s:variable(key("started")) or s:variable(key("done")) then return end
  19. if api.matches(c, e, receptacle) and e.generation == s:variable(key("receptacle_generation")) then
  20. -- Require a pickup receipt as well as native accepted use of the receptacle.
  21. if not s:variable(key("notified")) then return end
  22. c:set_variable(key("done"), true)
  23. c:cancel_timer(recovery(s))
  24. c:clear_variable(key("recover_armed"))
  25. c:clear_variable(key("recover_pending"))
  26. c:set_variable(key("held"), false)
  27. c:set_variable(key("present"), false)
  28. -- Native 9F19F0 destroys the old entity on a newer generation and
  29. -- active=false prevents replacement. Includes cells attached to a player.
  30. -- Keep the pickup generation for stale-event guards; a reset advances by two.
  31. api.slot(c, pickup):set_interactable_object{
  32. generation = generation(s) + 1, active = false, track_owner = true}
  33. on_deposit(c, s)
  34. elseif api.matches(c, e, pickup) and e.generation == generation(s) and not s:variable(key("notified")) then
  35. c:set_variable(key("notified"), true)
  36. c:set_variable(key("seen"), true)
  37. c:set_variable(key("held"), true)
  38. on_pickup(c, s)
  39. end
  40. end
  41. function obj.state(c, s, e)
  42. if not s:variable(key("started")) or s:variable(key("done"))
  43. or e.generation ~= generation(s) or not api.matches(c, e, pickup) then return end
  44. -- Expired cells may retain an entity for cleanup after they stop being alive.
  45. -- That entity cannot be carried or inserted and must not suppress recovery.
  46. local usable = e.present and e.alive ~= false
  47. c:set_variable(key("present"), usable)
  48. if usable then
  49. c:set_variable(key("seen"), true)
  50. c:cancel_timer(recovery(s))
  51. c:clear_variable(key("recover_armed"))
  52. if e.owner_known then c:set_variable(key("held"), e.has_owner) end
  53. if e.has_owner and not s:variable(key("notified")) then
  54. c:set_variable(key("notified"), true); on_pickup(c, s)
  55. end
  56. else
  57. c:set_variable(key("held"), false)
  58. -- Also recover when the first acknowledged generation is already missing;
  59. -- a late subscription must not require an earlier present/held event.
  60. if not s:variable(key("recover_armed")) then
  61. c:set_variable(key("recover_armed"), true)
  62. c:start_timer(recovery(s), 2000)
  63. end
  64. end
  65. end
  66. function obj.timer(c, s, e)
  67. if e.timer_name ~= recovery(s) then return false end
  68. c:clear_variable(key("recover_armed"))
  69. if s:variable(key("done")) or s:variable(key("present")) then return true end
  70. if s:variable("ember.region") ~= region then c:set_variable(key("recover_pending"), true); return true end
  71. c:set_variable(key("generation"), generation(s) + 2)
  72. c:clear_variable(key("seen")); c:clear_variable(key("notified"))
  73. api.slot(c, pickup):set_interactable_object{generation = generation(s), track_owner = true}
  74. -- Preserve the receptacle's current generation. A cell's expiry is not a new objective.
  75. return true
  76. end
  77. function obj.resume(c, s)
  78. if s:variable(key("recover_pending")) then
  79. c:clear_variable(key("recover_pending")); c:start_timer(recovery(s), 2000)
  80. end
  81. end
  82. function obj.reset(c, s)
  83. c:cancel_timer(recovery(s))
  84. api.objects(c, {pickup, receptacle}, false)
  85. c:set_variable(key("generation"), generation(s) + 2)
  86. for _, suffix in ipairs({"started", "done", "seen", "held", "present", "notified", "recover_pending", "recover_armed"}) do c:clear_variable(key(suffix)) end
  87. end
  88. function obj.held(s) return s:variable(key("held")) == true end
  89. function obj.done(s) return s:variable(key("done")) == true end
  90. return obj
  91. end