mission_ember_encounter_test.lua 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package.path = "scripts/?.lua;" .. package.path
  2. local Encounter = require("mission_ember.encounter")
  3. local function fixture()
  4. local vars, calls = {}, {placed = 0, cleared = 0, retired = 0}
  5. local slots = {
  6. a = {registry_key = 5, slot_type = 1, slot_index = 0},
  7. b = {registry_key = 6, slot_type = 1, slot_index = 0},
  8. }
  9. local context = {sdk = {squad_modes = {replace = "replace"}}}
  10. local state = {variable = function(_, key) return vars[key] end}
  11. function context:set_variable(key, value) vars[key] = value end
  12. function context:clear_variable(key) vars[key] = nil end
  13. function context:slot(id) return assert(slots[id]) end
  14. function context:squad(id)
  15. assert(slots[id])
  16. return {default_counts = {1},
  17. counts = function() return {set = function(self, index, value)
  18. assert(index == 1 and value == 0); self.zero = true
  19. end} end,
  20. place = function(_, args)
  21. assert(args.mode == "replace")
  22. if args.counts then assert(args.counts.zero); calls.retired = calls.retired + 1
  23. else calls.placed = calls.placed + 1 end
  24. end}
  25. end
  26. local function make()
  27. return Encounter.new("test", {{name = "a", id = "a", sensor = "a"},
  28. {name = "b", id = "b", sensor = "b"}},
  29. function() calls.cleared = calls.cleared + 1 end)
  30. end
  31. local encounter = make()
  32. local function event(id, count, previous, removal, consumed)
  33. local slot = slots[id]
  34. encounter:on_squad_state(context, state, {
  35. registry_key = slot.registry_key, slot_type = slot.slot_type,
  36. slot_index = slot.slot_index, alive_count = count,
  37. previous_alive_count = previous, removal_flag = removal,
  38. slot_counts = consumed or {(count == 0 and previous == 1) and 1 or 0},
  39. })
  40. end
  41. return context, state, encounter, calls, event, make
  42. end
  43. do
  44. local context, state, encounter, calls, event = fixture()
  45. assert(encounter:enter(context, state))
  46. assert(not encounter:enter(context, state))
  47. assert(calls.placed == 2)
  48. event("a", 0, 0); event("b", 0, 0)
  49. assert(calls.cleared == 0)
  50. event("a", 1, 0); event("b", 1, 0)
  51. event("a", 0, 1); event("a", 0, 1)
  52. assert(calls.cleared == 0)
  53. -- Actual native death reports carry this flag; discarding them deadlocks combat.
  54. event("b", 0, 1, true)
  55. assert(calls.cleared == 1 and encounter:phase(state) == 2 and calls.retired == 2)
  56. assert(not encounter:enter(context,state) and calls.placed == 2 and calls.retired == 2)
  57. event("b", 0, 1)
  58. assert(calls.cleared == 1)
  59. encounter:reset(context)
  60. assert(encounter:enter(context, state) and calls.placed == 4)
  61. event("a", 0, 0); event("b", 0, 0)
  62. assert(calls.cleared == 1)
  63. end
  64. do
  65. local context, state, encounter, calls, event, make = fixture()
  66. encounter:enter(context, state)
  67. event("a", 1, 0)
  68. local reloaded = make()
  69. assert(not reloaded:enter(context, state) and calls.placed == 2)
  70. -- A death edge with a positive prior count proves a squad existed even if its spawn edge
  71. -- was outside the callback history. Both squads still have to be accounted for.
  72. event("a", 0, 1); event("b", 0, 1)
  73. assert(calls.cleared == 1 and calls.retired == 2)
  74. local completedReload = make()
  75. assert(not completedReload:enter(context,state) and calls.placed == 2 and calls.retired == 2)
  76. end
  77. do
  78. local context, state, encounter, calls = fixture()
  79. function context:squad() error("SDK binding is not runnable") end
  80. assert(not pcall(function() encounter:enter(context, state) end))
  81. assert(calls.placed == 0 and encounter:phase(state) == 0)
  82. end
  83. do
  84. local context, state, encounter, calls, event = fixture()
  85. encounter:enter(context, state)
  86. event("a", 1, 0); event("b", 1, 0)
  87. -- Both briefly vanish while their placement requests remain outstanding.
  88. event("a", 0, 1, false, {0}); event("b", 0, 1, false, {0})
  89. assert(calls.cleared == 0 and calls.retired == 0)
  90. -- A partial native arrival can recover without the script cancelling it.
  91. event("a", 1, 0); event("a", 0, 1, false, {1})
  92. assert(calls.cleared == 0)
  93. -- Accounting may arrive in a later delta after the zero-alive report.
  94. event("b", 0, 0, false, {1})
  95. assert(calls.cleared == 1 and calls.retired == 2)
  96. end
  97. print("encounter progression, replay, reload, flagged deaths and SDK refusal checks passed")