ending.lua 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. -- Authored post-escape cinematic states; exact native completion/skip incidents advance once.
  2. --
  3. -- An authored region is `sliceSetIndex + stateOrdinal`, so apex gameplay (region 0) and both
  4. -- ending bookends (regions 1 and 2) are sibling states of one slice set. Selecting a bookend
  5. -- instantiates no new world: the client keeps the slice set it already holds and never reports
  6. -- a new held region, so this must not wait for one. The earlier region-49 staging detour forced
  7. -- a cross-slice-set round trip to manufacture that report and stalled instead.
  8. --
  9. -- The selection intent completes only once its own roster revision publishes, and intents are
  10. -- dispatched in order, so the activation queued on a later callback always follows the seed.
  11. return function(m)
  12. local movies = {
  13. {state = m.states.STATE_80B3C09E_0000_0001_80B3C091, slot = m.Slot.PF_CINEMATIC_BOOKEND_STM_CINEMATIC},
  14. {state = m.states.STATE_80B3C09E_0000_0002_80B3C093, slot = m.Slot.PF_CINEMATIC_BOOKEND_CNN_CINEMATIC},
  15. }
  16. local E = {}
  17. local music = require("mission_ember.music")(m)
  18. local function select_movie(c, index)
  19. c:set_variable("ember.ending", index)
  20. c:set_variable("ember.ending.selected", index)
  21. c:select_state(assert(movies[index].state))
  22. end
  23. function E.start(c, s)
  24. if s:variable("ember.ending") then return end
  25. music.update(c, s)
  26. select_movie(c, 1)
  27. end
  28. function E.client(c, s, e)
  29. local index = s:variable("ember.ending")
  30. local row = index and movies[index]
  31. -- Activate on a callback after the selection, never in the one that requested it.
  32. if not row or s:variable("ember.ending.selected") ~= index
  33. or s:variable("ember.ending.playing") == index then return end
  34. c:set_variable("ember.ending.playing", index)
  35. c:slot(assert(row.slot)):set_cinematic_active{active = true}
  36. end
  37. function E.terminated(c, s, e)
  38. local index = s:variable("ember.ending")
  39. local row = index and movies[index]
  40. if not row or s:variable("ember.ending.playing") ~= index then return end
  41. local slot = c:slot(row.slot)
  42. if e.registry_key ~= slot.registry_key or e.slot_type ~= slot.slot_type or e.slot_index ~= slot.slot_index then return end
  43. slot:set_cinematic_active{active = false}
  44. if movies[index + 1] then select_movie(c, index + 1)
  45. else
  46. c:set_variable("ember.ending", index + 1)
  47. c:set_variable("ember.complete", true)
  48. -- Native lifetime 6 enters the completion/reward branch (BEA9D0/B37100).
  49. c.lifetime:set{state = c.sdk.lifetime_states:at(6)}
  50. c:set_phase(100)
  51. end
  52. end
  53. return E
  54. end