Bläddra i källkod

Enable the weapon beam device in every region that places its object

The Almighty's weapon beam is an object AND the type-23 device that drives it,
but only apex ever enabled the device. Powerhouse, Processing and Cinder each
place their beam object and never touch its device, so the beam sat there as an
unpowered prop:

  region 64  POWERHOUSE_CORE_WEAPON_LASER_BEAM_DEVICE   never referenced
  region 56  CORE_WEAPON_LASER_BEAM_DEVICE              object placed only
  region 40  CINDER_CORE_WEAPON_LASER_BEAM_DEVICE       object placed only
  region 0   SPECOPS_APEX_RING_*_DEVICE                 unlocked and powered

Each region now unlocks and powers its beam device beside the object, which is
the treatment apex already gave the ring. Position is only one of a type-23's
three lanes; a device that is never unlocked and powered stays inert however its
position is driven, which is consistent with the apex ring devices animating
their position lane while the beam itself never responded.

Adds route_support.lane/enable_device for the power and lock lanes, which were
previously reachable only through apex's own local helper.

The controller suite now asserts the powerhouse device is enabled rather than
merely placed; its mock transition vocabulary was position-only.

22 portable tests and five Lua suites pass.
Millie 4 dagar sedan
förälder
incheckning
d575355ff1

+ 1 - 0
scripts/mission_ember/cinder.lua

@@ -52,6 +52,7 @@ return function(m, a)
         if phase(s) > 0 then return end
         set(c, 1)
         a.objects(c, {"CORE_WEAPON_LASER_BEAM_OBJECT_80B3C22D"}, true)
+        a.enable_device(c, "CINDER_CORE_WEAPON_LASER_BEAM_DEVICE")
         -- This is the entrance to Ready Room 1; its defenders are beyond the hatch.
         a.device(c, "TUMBLER_HATCH_DOOR_DEVICE", true)
         a.slot(c, "TUMBLER_HATCH_DOOR_KLAXON_AUDIO_SEQUENCE"):play_sequence{}

+ 7 - 0
scripts/mission_ember/landing.lua

@@ -184,6 +184,13 @@ return function(mission)
         context:slot(door):transition{transition = context.sdk.device_transitions.close, snap = true}
         context:slot(lever_device):transition{transition = context.sdk.device_transitions.close, snap = true}
         context:slot(lever):set_interactable_object{generation = 1}
+        -- The Almighty's weapon is firing at the sun for the whole mission, and every region
+        -- that shows the beam owns the device that drives it. Placing the beam without
+        -- unlocking and powering its device leaves a dead prop.
+        local beam = required(mission.Slot.POWERHOUSE_CORE_WEAPON_LASER_BEAM_DEVICE,
+                              "powerhouse core weapon laser beam device")
+        context:slot(beam):transition{transition = context.sdk.device_transitions.unlock}
+        context:slot(beam):transition{transition = context.sdk.device_transitions.power_on}
     end
 
     return {

+ 1 - 0
scripts/mission_ember/processing.lua

@@ -41,6 +41,7 @@ return function(m, a)
         a.objects(c, {"MERCURY_HOLOGRAM_OBJECT", "DEVICE_DOOR_HATCH_ONE_OBJECT", "DEVICE_DOOR_HATCH_TWO_OBJECT",
             "DEVICE_DOOR_HATCH_THREE_OBJECT", "DEVICE_DOOR_HATCH_FOUR_OBJECT",
             "CORE_WEAPON_LASER_BEAM_OBJECT_80B3C8F7"}, true)
+        a.enable_device(c, "CORE_WEAPON_LASER_BEAM_DEVICE")
         a.device(c, "LINK_ENTRY_DOOR_DEVICE", true)
         a.device(c, "TUMBLER_DOOR_DEVICE", true, true)
         a.device(c, "CONTROL_CONSOLE_SCREEN_DEVICE", false, true)

+ 10 - 0
scripts/mission_ember/route_support.lua

@@ -69,6 +69,16 @@ return function(mission, on_clear)
         api.slot(c, name):transition{transition = open and c.sdk.device_transitions.open or c.sdk.device_transitions.close,
             snap = snap or false}
     end
+    -- Position is only one of a type-23's three lanes; power and lock are the others, and a
+    -- device that is never unlocked and powered stays inert however its position is driven.
+    function api.lane(c, name, transition, snap)
+        api.slot(c, name):transition{transition = c.sdk.device_transitions[transition], snap = snap or false}
+    end
+    -- The Almighty's weapon beam is an object AND the device that drives it. Placing the object
+    -- alone leaves a dead prop, so every region that shows the beam enables its device too.
+    function api.enable_device(c, name)
+        api.lane(c, name, "unlock"); api.lane(c, name, "power_on")
+    end
     function api.objects(c, names, active)
         -- Each is an exact type-4 entry at its package transform, including native components.
         for _, name in ipairs(names) do api.slot(c, name):set_object_active{active = active} end

+ 16 - 1
tests/mission_ember_controller_test.lua

@@ -45,7 +45,11 @@ local navpoints = {}
 local flights, deliveries, retiredShips = {}, {}, 0
 local exitActions = {}
 local darkness = {}
+local beamLanes = {}
 mission.Slot.HARD_WIPE_GLOBALS = "darkness"
+-- The Almighty's weapon beam is placed in every region that shows it, and its type-23 device
+-- must be unlocked and powered or the beam is left a dead prop.
+mission.Slot.POWERHOUSE_CORE_WEAPON_LASER_BEAM_DEVICE = "powerhouse_beam"
 local timers, timerStarts, now = {}, 0, 0
 for index, letter in ipairs({"A", "B", "C", "D"}) do
     local prefix = "BRIDGE_CROSSING_DROPSHIP_" .. letter
@@ -109,7 +113,7 @@ local state = {variable = function(_, key) return vars[key] end}
 local closed, resets, movies, cues = {}, 0, {}, {}
 local ghost, door, extended = {}, {}, 0
 local leverAnimation = {}
-local context = {sdk = {squad_modes = {replace = "replace", reserve = "reserve"}, device_transitions = {close = "close", open = "open"}}}
+local context = {sdk = {squad_modes = {replace = "replace", reserve = "reserve"}, device_transitions = {close = "close", open = "open", unlock = "unlock", lock = "lock", power_on = "power_on", power_off = "power_off"}}}
 function context:start_timer(name, delay)
     assert(delay == (name:find("depart", 1, true) and 4000 or 6000),
            "unload adds three seconds to the prior three-second settle; departure holds four seconds")
@@ -195,6 +199,9 @@ function context:slot(name)
         return {registry_key = 12, slot_type = 65, slot_index = 60,
             set_ghost_link = function(_, args) ghost[#ghost + 1] = args end}
     end
+    if name == "powerhouse_beam" then
+        return {transition = function(_, args) beamLanes[#beamLanes + 1] = args.transition end}
+    end
     if name == "lever_device" then
         return {transition = function(_, args) leverAnimation[#leverAnimation+1] = args end}
     end
@@ -422,6 +429,14 @@ assert(placements == 42 and #flights == 8 and #deliveries == 2,
        "duplicate path and scan receipts cannot respawn ships or passengers")
 region(64); cleared()
 assert(#ghost == 2 and extended == 6)
+do
+    local unlocked, powered = false, false
+    for _, lane in ipairs(beamLanes) do
+        unlocked = unlocked or lane == "unlock"
+        powered = powered or lane == "power_on"
+    end
+    assert(unlocked and powered, "the powerhouse weapon beam device must be enabled, not just placed")
+end
 print("cinematic handoff, 42-squad route, skipped volumes, exact triggers, dialogue and reload checks passed")
 
 for _, group in ipairs({"catwalk_entry", "catwalk_mid", "pipe", "mercury", "mercury_bonus", "bridge", "passengers", "sun", "helipad"}) do