mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-28 23:51:17 +01:00
* Fixed ship munitions occasionally failing to enter their overmap target when their original physical projectile no longer existed. * Fixed several ship munitions reconstructing as the wrong projectile after overmap travel, ensuring explosive rounds correctly detonate on impact. Also had the AI write a unit test that simulates ship combat using every munition type, so we don't have more regressions here. AI usage disclosure: The code for this was created using GPT 5.6 Sol.
215 lines
9.4 KiB
Plaintext
215 lines
9.4 KiB
Plaintext
// 513 does not allow white or no color as a filter color
|
|
/datum/unit_test/overmap_effects_shall_have_non_white_color
|
|
name = "OVERMAP: Shall have non-white color"
|
|
groups = list("map", "overmap")
|
|
|
|
/datum/unit_test/overmap_effects_shall_have_non_white_color/start_test()
|
|
var/list/invalid_overmap_types = list()
|
|
for(var/omt in subtypesof(/obj/effect/overmap))
|
|
var/obj/overmap = omt
|
|
var/color = initial(overmap.color)
|
|
if(!color || color == COLOR_WHITE)
|
|
invalid_overmap_types += omt
|
|
|
|
if(invalid_overmap_types.len)
|
|
TEST_FAIL("Following /obj/effect/overmap types types have invalid colors: [english_list(invalid_overmap_types)]")
|
|
else
|
|
TEST_PASS("All /obj/effect/overmap types have a valid color")
|
|
|
|
return TRUE
|
|
|
|
/datum/unit_test/overmap_ships_shall_have_entrypoints
|
|
name = "OVERMAP: Ships shall have at least four valid entry points"
|
|
groups = list("map", "overmap")
|
|
|
|
/datum/unit_test/overmap_ships_shall_have_entrypoints/start_test()
|
|
for(var/obj/effect/overmap/visitable/ship/S in SSshuttle.initialized_sectors)
|
|
if(length(S.entry_points) >= 4)
|
|
TEST_PASS("[S.name] ([S.type]) has at least four entry points.")
|
|
else
|
|
TEST_FAIL("[S.name] ([S.type]) does not have at least four entry points!")
|
|
return TRUE
|
|
|
|
/datum/unit_test/overmap_ships_shall_have_class
|
|
name = "OVERMAP: Ships shall have class and designation"
|
|
groups = list("map", "overmap")
|
|
|
|
/datum/unit_test/overmap_ships_shall_have_class/start_test()
|
|
var/failures = 0
|
|
for(var/obj/effect/overmap/visitable/ship/S in SSshuttle.initialized_sectors)
|
|
if(!length(S.class))
|
|
TEST_FAIL("[S.name] ([S.type]) does not have a class defined.")
|
|
failures++
|
|
if(!length(S.designation))
|
|
TEST_FAIL("[S.name] ([S.type]) does not have a designation defined.")
|
|
failures++
|
|
if(!failures)
|
|
TEST_PASS("All ships have a class and designation.")
|
|
return TRUE
|
|
|
|
// Lightweight combat doubles: they exercise the overmap collision and payload
|
|
// handoff without firing a real projectile across one of the live ship maps.
|
|
/obj/effect/overmap/visitable/unit_test_combat_target/Initialize()
|
|
SHOULD_CALL_PARENT(FALSE)
|
|
// Avoid registering this lightweight collision target as a real sector.
|
|
return INITIALIZE_HINT_NORMAL
|
|
|
|
/obj/effect/overmap/visitable/unit_test_combat_target/check_ownership(obj/object)
|
|
return FALSE
|
|
|
|
/obj/effect/overmap/projectile/unit_test_combat
|
|
/// Number of payload handoffs performed by this combat carrier.
|
|
var/entry_calls = 0
|
|
/// Whether the reconstructed projectile became the ammunition's physical owner.
|
|
var/payload_transferred = FALSE
|
|
/// Physical projectile created by the overmap entry code under test.
|
|
var/obj/projectile/ship_ammo/reconstructed_projectile
|
|
|
|
/obj/effect/overmap/projectile/unit_test_combat/Initialize()
|
|
SHOULD_CALL_PARENT(FALSE)
|
|
// Avoid starting the production movement timer before the test configures the carrier.
|
|
return INITIALIZE_HINT_NORMAL
|
|
|
|
/obj/effect/overmap/projectile/unit_test_combat/check_entry_visitable(obj/projectile/ship_ammo/widowmaker, turf/target_turf)
|
|
// Capture the handoff result without firing across a live ship map.
|
|
entry_calls++
|
|
payload_transferred = (widowmaker.ammo?.loc == widowmaker)
|
|
reconstructed_projectile = widowmaker
|
|
qdel(src)
|
|
return TRUE
|
|
|
|
/obj/effect/unit_test_ship_ammo_impact/Initialize()
|
|
return ..()
|
|
|
|
/datum/unit_test/overmap_projectile_entry_is_one_shot
|
|
name = "OVERMAP: Combat projectile entry is one-shot"
|
|
groups = list("map", "overmap")
|
|
|
|
/datum/unit_test/overmap_projectile_entry_is_one_shot/start_test()
|
|
var/test_z = SSatlas.current_map?.overmap_z ? SSatlas.current_map.overmap_z : 1
|
|
var/turf/combat_turf = locate(2, 2, test_z)
|
|
TEST_ASSERT_NOTNULL(combat_turf, "Could not locate an overmap turf for the combat simulation.")
|
|
|
|
var/obj/effect/overmap/visitable/unit_test_combat_target/combat_target = new(combat_turf)
|
|
var/obj/effect/overmap/projectile/unit_test_combat/overmap_projectile = new(combat_turf)
|
|
var/obj/item/ship_ammunition/ammunition = new(overmap_projectile)
|
|
ammunition.fired_projectile_type = /obj/projectile/ship_ammo
|
|
ammunition.overmap_behaviour = SHIP_AMMO_CAN_HIT_VISITABLES
|
|
overmap_projectile.ammunition = ammunition
|
|
overmap_projectile.target = combat_target
|
|
|
|
TEST_ASSERT(overmap_projectile.check_entry(), "The projectile did not enter its overmap combat target.")
|
|
TEST_ASSERT(overmap_projectile.entering, "The overmap projectile was not marked as entering.")
|
|
TEST_ASSERT(overmap_projectile.check_entry(), "A repeated entry check did not report the handled collision.")
|
|
TEST_ASSERT_EQUAL(overmap_projectile.entry_calls, 1, "The payload was translated more than once.")
|
|
TEST_ASSERT(overmap_projectile.payload_transferred, "The ammunition was not transferred to the reconstructed projectile.")
|
|
|
|
qdel(combat_target)
|
|
qdel(overmap_projectile.reconstructed_projectile)
|
|
qdel(overmap_projectile)
|
|
TEST_PASS("An overmap combat projectile translates its payload only once.")
|
|
return TRUE
|
|
|
|
/datum/unit_test/overmap_projectile_missing_type
|
|
name = "OVERMAP: Combat carrier rejects a missing projectile type"
|
|
groups = list("map", "overmap")
|
|
|
|
/datum/unit_test/overmap_projectile_missing_type/start_test()
|
|
var/test_z = SSatlas.current_map?.overmap_z ? SSatlas.current_map.overmap_z : 1
|
|
var/turf/combat_turf = locate(2, 2, test_z)
|
|
TEST_ASSERT_NOTNULL(combat_turf, "Could not locate an overmap turf for the combat simulation.")
|
|
|
|
var/obj/effect/overmap/visitable/unit_test_combat_target/combat_target = new(combat_turf)
|
|
var/obj/effect/overmap/projectile/unit_test_combat/overmap_projectile = new(combat_turf)
|
|
var/obj/item/ship_ammunition/ammunition = new(overmap_projectile)
|
|
ammunition.overmap_behaviour = SHIP_AMMO_CAN_HIT_VISITABLES
|
|
overmap_projectile.ammunition = ammunition
|
|
overmap_projectile.target = combat_target
|
|
|
|
TEST_ASSERT(overmap_projectile.check_entry(), "The malformed carrier collision was not handled.")
|
|
TEST_ASSERT(QDELETED(overmap_projectile), "A carrier with no projectile type was not deleted.")
|
|
TEST_ASSERT_EQUAL(overmap_projectile.entry_calls, 0, "Entry ran without a projectile type.")
|
|
|
|
qdel(combat_target)
|
|
qdel(overmap_projectile)
|
|
TEST_PASS("An invalid overmap carrier is discarded without attempting reconstruction.")
|
|
return TRUE
|
|
|
|
/datum/unit_test/overmap_all_ship_munitions
|
|
name = "OVERMAP: All ship munitions reconstruct and explosive rounds detonate"
|
|
groups = list("map", "overmap")
|
|
|
|
/datum/unit_test/overmap_all_ship_munitions/start_test()
|
|
var/test_z = SSatlas.current_map?.overmap_z ? SSatlas.current_map.overmap_z : 1
|
|
var/turf/combat_turf = locate(2, 2, test_z)
|
|
TEST_ASSERT_NOTNULL(combat_turf, "Could not locate an overmap turf for the munitions simulation.")
|
|
|
|
var/list/explosive_impacts = list(
|
|
SHIP_AMMO_IMPACT_HE,
|
|
SHIP_AMMO_IMPACT_BLASTER,
|
|
SHIP_AMMO_IMPACT_BUNKERBUSTER,
|
|
SHIP_AMMO_IMPACT_ZAT
|
|
)
|
|
var/tested_munitions = 0
|
|
var/test_status = UNIT_TEST_PASSED
|
|
|
|
// Enumerate typepaths so newly added loadable ammunition is covered automatically.
|
|
for(var/ammunition_type in subtypesof(/obj/item/ship_ammunition))
|
|
if(is_abstract(ammunition_type))
|
|
continue
|
|
|
|
var/obj/item/ship_ammunition/ammunition = new ammunition_type
|
|
if(!ammunition.can_be_loaded())
|
|
qdel(ammunition)
|
|
continue
|
|
|
|
tested_munitions++
|
|
if(!ammunition.projectile_type_override)
|
|
test_status = TEST_FAIL("[ammunition_type] has no explicit physical projectile type to reconstruct after overmap travel.")
|
|
qdel(ammunition)
|
|
continue
|
|
|
|
// Probes intentionally remain on the overmap and never impact a visitable.
|
|
if(!ammunition.overmap_behaviour)
|
|
qdel(ammunition)
|
|
continue
|
|
|
|
var/obj/effect/overmap/visitable/unit_test_combat_target/combat_target = new(combat_turf)
|
|
var/obj/effect/overmap/projectile/unit_test_combat/overmap_projectile = new(combat_turf)
|
|
ammunition.forceMove(overmap_projectile)
|
|
ammunition.fired_projectile_type = ammunition.projectile_type_override
|
|
overmap_projectile.ammunition = ammunition
|
|
overmap_projectile.target = combat_target
|
|
|
|
if(!overmap_projectile.check_entry())
|
|
test_status = TEST_FAIL("[ammunition_type] did not enter its overmap combat target.")
|
|
else if(overmap_projectile.entry_calls != 1 || !overmap_projectile.payload_transferred || !overmap_projectile.reconstructed_projectile)
|
|
test_status = TEST_FAIL("[ammunition_type] did not reconstruct and transfer its payload exactly once.")
|
|
|
|
var/obj/projectile/ship_ammo/reconstructed = overmap_projectile.reconstructed_projectile
|
|
var/should_explode = reconstructed && ((ammunition.impact_type in explosive_impacts) || max(reconstructed.explosion_strength) > 0)
|
|
if(should_explode)
|
|
// Calling the real on_hit() must enqueue an explosion. Remove that queued
|
|
// work afterward so this test cannot damage the unit-test map.
|
|
var/queued_explosions = length(SSexplosives.work_queue)
|
|
var/obj/effect/unit_test_ship_ammo_impact/impact_target = new(combat_turf)
|
|
reconstructed.forceMove(combat_turf)
|
|
reconstructed.on_hit(impact_target)
|
|
if(length(SSexplosives.work_queue) <= queued_explosions)
|
|
test_status = TEST_FAIL("[ammunition_type] ([ammunition.impact_type]) did not produce an explosion on impact.")
|
|
else
|
|
var/list/test_explosions = SSexplosives.work_queue.Copy(queued_explosions + 1)
|
|
SSexplosives.work_queue -= test_explosions
|
|
QDEL_LIST(test_explosions)
|
|
qdel(impact_target)
|
|
|
|
qdel(reconstructed)
|
|
qdel(combat_target)
|
|
qdel(overmap_projectile)
|
|
|
|
if(!tested_munitions)
|
|
return TEST_FAIL("No loadable ship munitions were discovered.")
|
|
if(test_status == UNIT_TEST_PASSED)
|
|
TEST_PASS("All [tested_munitions] loadable ship munitions reconstructed; every explosive impact queued an explosion.")
|
|
return TRUE
|