From d39ca65611eba0e9ab5c54fea9eeef1c6ec3ba4f Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Wed, 30 Sep 2026 04:28:31 -0700 Subject: [PATCH 1/6] Move fork files and resources into modular directories --- .../voidcrew => voidcrew/planets}/beach.dmm | 0 .../voidcrew => voidcrew/planets}/ice.dmm | 0 .../voidcrew => voidcrew/planets}/jungle.dmm | 0 .../voidcrew => voidcrew/planets}/lava.dmm | 0 .../planets}/wasteland.dmm | 0 code/modules/unit_tests/_unit_tests.dm | 238 +++++++++--------- tgstation.dme | 8 +- tgui/packages/tgui-panel/index.tsx | 2 +- tgui/packages/tgui-panel/styles/main.scss | 2 +- .../CharacterPreferences/index.tsx | 2 +- tgui/packages/tgui/styles/main.scss | 10 +- .../chat/translation.test.ts | 2 +- .../chat/translation.ts | 4 +- .../interfaces/BlueprintImprinter.jsx | 4 +- .../interfaces/ColosseumVault.tsx | 6 +- .../interfaces/DrugLabCatalyst.tsx | 4 +- .../interfaces/DrugLabCrystallizer.tsx | 4 +- .../interfaces/DrugLabMixer.tsx | 4 +- .../interfaces/MissionBoard.tsx | 4 +- .../interfaces/ModsuitBench.jsx | 4 +- .../interfaces/OutpostElevator.tsx | 4 +- .../interfaces/OutpostManagement.tsx | 6 +- .../interfaces/OutpostManipulator.tsx | 4 +- .../interfaces/OutpostMissionBoard.tsx | 4 +- .../interfaces/OutpostShellCatalog.tsx | 4 +- .../ShipCategoriesPage.tsx | 4 +- .../interfaces/ShipCatalog.tsx | 4 +- .../interfaces/ShipJoinMenu.tsx | 4 +- .../interfaces/ShipUpgradeSelector.tsx | 6 +- .../interfaces/TraderShop.tsx | 4 +- .../interfaces/common/drugLab.ts | 0 .../layouts/Window.test.tsx | 14 +- .../src/interfaces/ShipSiphon.tsx | 6 +- .../styles/interfaces/ChromeCradle.scss | 0 .../styles/interfaces/HelmComputer.scss | 0 .../styles/interfaces/MissionBoard.scss | 0 .../styles/interfaces/OutpostManagement.scss | 0 .../styles/interfaces/ShipCombatConsole.scss | 0 .../styles/panel}/components/Translation.scss | 0 .../logging => voidcrew/_HELPERS}/worldgen.dm | 0 voidcrew/mapping/_mapping.dm | 2 +- .../modules/admin/legacy}/shuttlepanel.dm | 0 voidcrew/modules/chemistry/pouring_sounds.dm | 50 ++-- .../chemistry/sound}/transfer/ATTRIBUTION.txt | 0 .../sound}/transfer/beakerpour_0-10-1.ogg | Bin .../sound}/transfer/beakerpour_0-10-2.ogg | Bin .../sound}/transfer/beakerpour_0-10-3.ogg | Bin .../sound}/transfer/beakerpour_0-10-4.ogg | Bin .../sound}/transfer/beakerpour_0-10-5.ogg | Bin .../sound}/transfer/beakerpour_0-10-6.ogg | Bin .../transfer/beakerpour_0-10-sparkle.ogg | Bin .../sound}/transfer/beakerpour_10-25-1.ogg | Bin .../sound}/transfer/beakerpour_10-25-2.ogg | Bin .../sound}/transfer/beakerpour_10-25-3.ogg | Bin .../sound}/transfer/beakerpour_10-25-4.ogg | Bin .../sound}/transfer/beakerpour_10-25-5.ogg | Bin .../sound}/transfer/beakerpour_10-25-6.ogg | Bin .../transfer/beakerpour_10-25-sparkle.ogg | Bin .../sound}/transfer/beakerpour_25-50-1.ogg | Bin .../sound}/transfer/beakerpour_25-50-2.ogg | Bin .../sound}/transfer/beakerpour_25-50-3.ogg | Bin .../transfer/beakerpour_25-50-sparkle.ogg | Bin .../sound}/transfer/beakerpour_50-inf-1.ogg | Bin .../sound}/transfer/beakerpour_50-inf-2.ogg | Bin .../sound}/transfer/beakerpour_50-inf-3.ogg | Bin .../sound}/transfer/beakerpour_50-inf-4.ogg | Bin .../sound}/transfer/beakerpour_50-inf-5.ogg | Bin .../transfer/beakerpour_50-inf-sparkle.ogg | Bin .../chemistry/sound}/transfer/dropper1.ogg | Bin .../chemistry/sound}/transfer/dropper2.ogg | Bin .../ship_purchase/admin/economy_verbs.dm | 0 .../modules/ship_purchase/ship_catalog_ui.dm | 0 .../ship_purchase/ship_economy_database.dm | 0 .../ship_purchase/transaction_helpers.dm | 0 .../unit_tests/atmos_component_pipeline.dm | 0 .../unit_tests/gas_connector_lifecycle.dm | 0 .../unit_tests/glass_floor_baseturfs.dm | 0 .../unit_tests/late_initialization_reentry.dm | 0 .../unit_tests/map_parser_attributes.dm | 0 .../unit_tests/pipeline_reconciliation.dm | 0 .../modules/unit_tests/prisoner_photos.dm | 0 .../unit_tests/reagent_holder_teardown.dm | 0 .../unit_tests/shuttle_cling_lifecycle.dm | 0 .../unit_tests/shuttle_load_ownership.dm | 0 .../modules/unit_tests/soft_crit.dm | 0 .../modules/unit_tests/throw_cleanup.dm | 0 .../unit_tests/voidcrew_ammo_box_materials.dm | 0 .../unit_tests/voidcrew_assault_pod.dm | 0 .../unit_tests/voidcrew_autopilot_course.dm | 0 .../voidcrew_autotranslate_morph.dm | 0 .../voidcrew_autotranslate_output.dm | 0 .../unit_tests/voidcrew_bank_deposits.dm | 0 .../modules/unit_tests/voidcrew_bitrunning.dm | 0 .../unit_tests/voidcrew_blueprint_guns.dm | 0 .../unit_tests/voidcrew_camera_scope.dm | 0 .../modules/unit_tests/voidcrew_cargo_cart.dm | 0 .../unit_tests/voidcrew_cargo_docking.dm | 0 .../unit_tests/voidcrew_cargo_load_queue.dm | 0 .../modules/unit_tests/voidcrew_colosseum.dm | 0 .../voidcrew_construction_automation.dm | 0 .../voidcrew_construction_refunds.dm | 0 .../unit_tests/voidcrew_cordon_teleport.dm | 0 .../unit_tests/voidcrew_crew_antag_gc.dm | 0 .../modules/unit_tests/voidcrew_crew_hud.dm | 0 .../modules/unit_tests/voidcrew_cyberware.dm | 0 .../unit_tests/voidcrew_dissection_tiers.dm | 0 .../modules/unit_tests/voidcrew_drug_lab.dm | 0 .../unit_tests/voidcrew_drug_recipe.dm | 0 .../unit_tests/voidcrew_dynamic_events.dm | 0 .../unit_tests/voidcrew_fleet_waypoints.dm | 0 .../unit_tests/voidcrew_helm_access.dm | 0 .../modules/unit_tests/voidcrew_helpers.dm | 0 .../unit_tests/voidcrew_hull_containment.dm | 0 .../unit_tests/voidcrew_hull_survey.dm | 0 .../unit_tests/voidcrew_launch_access.dm | 0 .../unit_tests/voidcrew_launch_cargo.dm | 0 .../unit_tests/voidcrew_launch_fabrication.dm | 0 .../unit_tests/voidcrew_launch_progression.dm | 0 .../unit_tests/voidcrew_legion_cleanup.dm | 0 .../modules/unit_tests/voidcrew_lich.dm | 0 .../modules/unit_tests/voidcrew_loot.dm | 0 .../unit_tests/voidcrew_map_packing.dm | 0 .../unit_tests/voidcrew_mapload_floor_dir.dm | 0 .../voidcrew_medical_research_links.dm | 0 .../unit_tests/voidcrew_megafauna_aggro.dm | 0 .../unit_tests/voidcrew_mining_input.dm | 0 .../unit_tests/voidcrew_mission_gps.dm | 0 .../modules/unit_tests/voidcrew_missions.dm | 0 .../unit_tests/voidcrew_nanite_research.dm | 0 .../voidcrew_npc_boarding_docking.dm | 0 .../modules/unit_tests/voidcrew_npc_disarm.dm | 0 .../unit_tests/voidcrew_outpost_admin.dm | 0 .../unit_tests/voidcrew_outpost_founding.dm | 0 .../unit_tests/voidcrew_outpost_management.dm | 0 .../voidcrew_outpost_management_lifecycle.dm | 0 .../unit_tests/voidcrew_outpost_protection.dm | 0 .../voidcrew_outpost_self_defense.dm | 0 .../unit_tests/voidcrew_outpost_services.dm | 0 .../voidcrew_outpost_turret_targeting.dm | 0 .../unit_tests/voidcrew_overmap_management.dm | 0 .../unit_tests/voidcrew_pandora_links.dm | 0 .../unit_tests/voidcrew_planet_cleanup.dm | 0 .../unit_tests/voidcrew_planet_definitions.dm | 0 .../unit_tests/voidcrew_planetary_factions.dm | 0 .../unit_tests/voidcrew_player_outpost.dm | 0 .../voidcrew_plumbing_shuttle_move.dm | 0 .../unit_tests/voidcrew_repair_robotics.dm | 0 .../unit_tests/voidcrew_research_lifecycle.dm | 0 .../unit_tests/voidcrew_research_movement.dm | 0 .../unit_tests/voidcrew_respawn_timer.dm | 0 .../modules/unit_tests/voidcrew_rnd_kit.dm | 0 .../unit_tests/voidcrew_ruin_bounds.dm | 0 .../unit_tests/voidcrew_ruin_cleanup.dm | 0 .../unit_tests/voidcrew_ruin_reservation.dm | 0 .../unit_tests/voidcrew_science_program.dm | 0 .../unit_tests/voidcrew_ship_abandonment.dm | 0 .../unit_tests/voidcrew_ship_access.dm | 0 .../unit_tests/voidcrew_ship_assembly.dm | 0 .../voidcrew_ship_communications.dm | 0 .../modules/unit_tests/voidcrew_ship_hulls.dm | 0 .../unit_tests/voidcrew_ship_integrity.dm | 0 .../unit_tests/voidcrew_ship_modules.dm | 0 .../unit_tests/voidcrew_ship_silicons.dm | 0 .../voidcrew_ship_turret_targeting.dm | 0 .../unit_tests/voidcrew_shop_catalog.dm | 0 .../voidcrew_silicon_ship_systems.dm | 0 .../unit_tests/voidcrew_simple_mob_ai.dm | 0 .../unit_tests/voidcrew_smart_locker.dm | 0 .../unit_tests/voidcrew_survey_archive.dm | 0 .../voidcrew_survey_capabilities.dm | 0 .../unit_tests/voidcrew_survey_identity.dm | 0 .../voidcrew_survey_research_links.dm | 0 .../modules/unit_tests/voidcrew_vestige.dm | 0 .../unit_tests/voidcrew_vestige_abductor.dm | 0 .../unit_tests/voidcrew_vestige_ascension.dm | 0 .../voidcrew_vestige_biology_routes.dm | 0 .../unit_tests/voidcrew_vestige_changeling.dm | 0 .../voidcrew_vestige_confiscation.dm | 0 .../unit_tests/voidcrew_vestige_field.dm | 0 .../unit_tests/voidcrew_vestige_hunts.dm | 0 .../unit_tests/voidcrew_vestige_lifecycle.dm | 0 .../unit_tests/voidcrew_vestige_morph.dm | 0 .../voidcrew_vestige_morph_routes.dm | 0 .../unit_tests/voidcrew_vestige_rites.dm | 0 .../voidcrew_vestige_rites_routes.dm | 0 .../unit_tests/voidcrew_vestige_routes.dm | 0 .../unit_tests/voidcrew_vestige_status.dm | 0 .../unit_tests/voidcrew_vestige_visuals.dm | 0 .../unit_tests/voidcrew_wall_break_atmos.dm | 0 .../unit_tests/voidcrew_weather_sites.dm | 0 .../unit_tests/voidcrew_windoor_survey.dm | 0 .../unit_tests/voidcrew_zone_logging.dm | 0 .../unit_tests/weather_mob_targeting.dm | 0 193 files changed, 207 insertions(+), 207 deletions(-) rename _maps/{map_files/voidcrew => voidcrew/planets}/beach.dmm (100%) rename _maps/{map_files/voidcrew => voidcrew/planets}/ice.dmm (100%) rename _maps/{map_files/voidcrew => voidcrew/planets}/jungle.dmm (100%) rename _maps/{map_files/voidcrew => voidcrew/planets}/lava.dmm (100%) rename _maps/{map_files/voidcrew => voidcrew/planets}/wasteland.dmm (100%) rename tgui/packages/{tgui-panel => voidcrew_tgui}/chat/translation.test.ts (99%) rename tgui/packages/{tgui-panel => voidcrew_tgui}/chat/translation.ts (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/BlueprintImprinter.jsx (98%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/ColosseumVault.tsx (96%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/DrugLabCatalyst.tsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/DrugLabCrystallizer.tsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/DrugLabMixer.tsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/MissionBoard.tsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/ModsuitBench.jsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/OutpostElevator.tsx (96%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/OutpostManagement.tsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/OutpostManipulator.tsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/OutpostMissionBoard.tsx (98%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/OutpostShellCatalog.tsx (96%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/PreferencesMenu/CharacterPreferences/ShipCategoriesPage.tsx (96%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/ShipCatalog.tsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/ShipJoinMenu.tsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/ShipUpgradeSelector.tsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/TraderShop.tsx (99%) rename tgui/packages/{tgui => voidcrew_tgui}/interfaces/common/drugLab.ts (100%) rename tgui/packages/{tgui => voidcrew_tgui}/layouts/Window.test.tsx (85%) rename tgui/packages/{tgui => voidcrew_tgui}/src/interfaces/ShipSiphon.tsx (97%) rename tgui/packages/{tgui => voidcrew_tgui}/styles/interfaces/ChromeCradle.scss (100%) rename tgui/packages/{tgui => voidcrew_tgui}/styles/interfaces/HelmComputer.scss (100%) rename tgui/packages/{tgui => voidcrew_tgui}/styles/interfaces/MissionBoard.scss (100%) rename tgui/packages/{tgui => voidcrew_tgui}/styles/interfaces/OutpostManagement.scss (100%) rename tgui/packages/{tgui => voidcrew_tgui}/styles/interfaces/ShipCombatConsole.scss (100%) rename tgui/packages/{tgui-panel/styles => voidcrew_tgui/styles/panel}/components/Translation.scss (100%) rename {code/__HELPERS/logging => voidcrew/_HELPERS}/worldgen.dm (100%) rename {code/modules/admin/verbs => voidcrew/modules/admin/legacy}/shuttlepanel.dm (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/ATTRIBUTION.txt (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_0-10-1.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_0-10-2.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_0-10-3.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_0-10-4.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_0-10-5.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_0-10-6.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_0-10-sparkle.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_10-25-1.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_10-25-2.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_10-25-3.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_10-25-4.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_10-25-5.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_10-25-6.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_10-25-sparkle.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_25-50-1.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_25-50-2.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_25-50-3.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_25-50-sparkle.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_50-inf-1.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_50-inf-2.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_50-inf-3.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_50-inf-4.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_50-inf-5.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/beakerpour_50-inf-sparkle.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/dropper1.ogg (100%) rename {sound/chemistry => voidcrew/modules/chemistry/sound}/transfer/dropper2.ogg (100%) rename {code => voidcrew}/modules/ship_purchase/admin/economy_verbs.dm (100%) rename {code => voidcrew}/modules/ship_purchase/ship_catalog_ui.dm (100%) rename {code => voidcrew}/modules/ship_purchase/ship_economy_database.dm (100%) rename {code => voidcrew}/modules/ship_purchase/transaction_helpers.dm (100%) rename {code => voidcrew}/modules/unit_tests/atmos_component_pipeline.dm (100%) rename {code => voidcrew}/modules/unit_tests/gas_connector_lifecycle.dm (100%) rename {code => voidcrew}/modules/unit_tests/glass_floor_baseturfs.dm (100%) rename {code => voidcrew}/modules/unit_tests/late_initialization_reentry.dm (100%) rename {code => voidcrew}/modules/unit_tests/map_parser_attributes.dm (100%) rename {code => voidcrew}/modules/unit_tests/pipeline_reconciliation.dm (100%) rename {code => voidcrew}/modules/unit_tests/prisoner_photos.dm (100%) rename {code => voidcrew}/modules/unit_tests/reagent_holder_teardown.dm (100%) rename {code => voidcrew}/modules/unit_tests/shuttle_cling_lifecycle.dm (100%) rename {code => voidcrew}/modules/unit_tests/shuttle_load_ownership.dm (100%) rename {code => voidcrew}/modules/unit_tests/soft_crit.dm (100%) rename {code => voidcrew}/modules/unit_tests/throw_cleanup.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ammo_box_materials.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_assault_pod.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_autopilot_course.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_autotranslate_morph.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_autotranslate_output.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_bank_deposits.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_bitrunning.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_blueprint_guns.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_camera_scope.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_cargo_cart.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_cargo_docking.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_cargo_load_queue.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_colosseum.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_construction_automation.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_construction_refunds.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_cordon_teleport.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_crew_antag_gc.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_crew_hud.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_cyberware.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_dissection_tiers.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_drug_lab.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_drug_recipe.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_dynamic_events.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_fleet_waypoints.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_helm_access.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_helpers.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_hull_containment.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_hull_survey.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_launch_access.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_launch_cargo.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_launch_fabrication.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_launch_progression.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_legion_cleanup.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_lich.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_loot.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_map_packing.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_mapload_floor_dir.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_medical_research_links.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_megafauna_aggro.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_mining_input.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_mission_gps.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_missions.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_nanite_research.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_npc_boarding_docking.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_npc_disarm.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_outpost_admin.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_outpost_founding.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_outpost_management.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_outpost_management_lifecycle.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_outpost_protection.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_outpost_self_defense.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_outpost_services.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_outpost_turret_targeting.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_overmap_management.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_pandora_links.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_planet_cleanup.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_planet_definitions.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_planetary_factions.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_player_outpost.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_plumbing_shuttle_move.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_repair_robotics.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_research_lifecycle.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_research_movement.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_respawn_timer.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_rnd_kit.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ruin_bounds.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ruin_cleanup.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ruin_reservation.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_science_program.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ship_abandonment.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ship_access.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ship_assembly.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ship_communications.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ship_hulls.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ship_integrity.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ship_modules.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ship_silicons.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_ship_turret_targeting.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_shop_catalog.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_silicon_ship_systems.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_simple_mob_ai.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_smart_locker.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_survey_archive.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_survey_capabilities.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_survey_identity.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_survey_research_links.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_abductor.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_ascension.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_biology_routes.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_changeling.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_confiscation.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_field.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_hunts.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_lifecycle.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_morph.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_morph_routes.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_rites.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_rites_routes.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_routes.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_status.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_vestige_visuals.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_wall_break_atmos.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_weather_sites.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_windoor_survey.dm (100%) rename {code => voidcrew}/modules/unit_tests/voidcrew_zone_logging.dm (100%) rename {code => voidcrew}/modules/unit_tests/weather_mob_targeting.dm (100%) diff --git a/_maps/map_files/voidcrew/beach.dmm b/_maps/voidcrew/planets/beach.dmm similarity index 100% rename from _maps/map_files/voidcrew/beach.dmm rename to _maps/voidcrew/planets/beach.dmm diff --git a/_maps/map_files/voidcrew/ice.dmm b/_maps/voidcrew/planets/ice.dmm similarity index 100% rename from _maps/map_files/voidcrew/ice.dmm rename to _maps/voidcrew/planets/ice.dmm diff --git a/_maps/map_files/voidcrew/jungle.dmm b/_maps/voidcrew/planets/jungle.dmm similarity index 100% rename from _maps/map_files/voidcrew/jungle.dmm rename to _maps/voidcrew/planets/jungle.dmm diff --git a/_maps/map_files/voidcrew/lava.dmm b/_maps/voidcrew/planets/lava.dmm similarity index 100% rename from _maps/map_files/voidcrew/lava.dmm rename to _maps/voidcrew/planets/lava.dmm diff --git a/_maps/map_files/voidcrew/wasteland.dmm b/_maps/voidcrew/planets/wasteland.dmm similarity index 100% rename from _maps/map_files/voidcrew/wasteland.dmm rename to _maps/voidcrew/planets/wasteland.dmm diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 9cb0ec9a5c3..ba3013c63c3 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -97,7 +97,7 @@ #include "area_contents.dm" #include "armor_verification.dm" #include "asset_smart_cache.dm" -#include "atmos_component_pipeline.dm" +#include "../../../voidcrew/modules/unit_tests/atmos_component_pipeline.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "atmospherics_sanity.dm" #include "autowiki.dm" #include "bake_a_cake.dm" @@ -167,12 +167,12 @@ #include "font_awesome_icons.dm" #include "food_edibility_check.dm" #include "full_heal.dm" -#include "gas_connector_lifecycle.dm" +#include "../../../voidcrew/modules/unit_tests/gas_connector_lifecycle.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "gas_transfer.dm" -#include "pipeline_reconciliation.dm" +#include "../../../voidcrew/modules/unit_tests/pipeline_reconciliation.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "get_turf_pixel.dm" #include "geyser.dm" -#include "glass_floor_baseturfs.dm" +#include "../../../voidcrew/modules/unit_tests/glass_floor_baseturfs.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "gloves_and_shoes_armor.dm" #include "greyscale_config.dm" #include "hallucination_icons.dm" @@ -198,7 +198,7 @@ #include "kinetic_crusher.dm" #include "knockoff_component.dm" #include "language_transfer.dm" -#include "late_initialization_reentry.dm" +#include "../../../voidcrew/modules/unit_tests/late_initialization_reentry.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "leash.dm" #include "lesserform.dm" #include "limbsanity.dm" @@ -210,7 +210,7 @@ #include "machine_disassembly.dm" #include "mafia.dm" #include "map_landmarks.dm" -#include "map_parser_attributes.dm" +#include "../../../voidcrew/modules/unit_tests/map_parser_attributes.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "mapload_space_verification.dm" #include "mapping.dm" #include "mapping_nearstation_test.dm" @@ -252,14 +252,14 @@ #include "plantgrowth_tests.dm" #include "preference_species.dm" #include "preferences.dm" -#include "prisoner_photos.dm" +#include "../../../voidcrew/modules/unit_tests/prisoner_photos.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "projectiles.dm" #include "quirks.dm" #include "range_return.dm" #include "rcd.dm" #include "reagent_container_defaults.dm" #include "reagent_id_typos.dm" -#include "reagent_holder_teardown.dm" +#include "../../../voidcrew/modules/unit_tests/reagent_holder_teardown.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "reagent_mob_expose.dm" #include "reagent_mod_procs.dm" #include "reagent_names.dm" @@ -280,14 +280,14 @@ #include "security_levels.dm" #include "security_officer_distribution.dm" #include "serving_tray.dm" -#include "shuttle_cling_lifecycle.dm" +#include "../../../voidcrew/modules/unit_tests/shuttle_cling_lifecycle.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "../../../voidcrew/modules/unit_tests/shuttle_cling_rethrow.dm" // VOIDCREW EDIT ADDITION -#include "shuttle_load_ownership.dm" +#include "../../../voidcrew/modules/unit_tests/shuttle_load_ownership.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "simple_animal_freeze.dm" #include "siunit.dm" #include "slime_mood.dm" #include "slips.dm" -#include "soft_crit.dm" +#include "../../../voidcrew/modules/unit_tests/soft_crit.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "spawn_humans.dm" #include "spawn_mobs.dm" #include "species_change_clothing.dm" @@ -318,7 +318,7 @@ #include "syringe_gun.dm" #include "tail_wag.dm" #include "teleporters.dm" -#include "throw_cleanup.dm" +#include "../../../voidcrew/modules/unit_tests/throw_cleanup.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "../../../voidcrew/modules/unit_tests/throw_rethrow.dm" // VOIDCREW EDIT ADDITION #include "text.dm" #include "tgui_create_message.dm" @@ -332,121 +332,121 @@ #include "unit_test.dm" #include "verify_config_tags.dm" #include "verify_emoji_names.dm" -#include "voidcrew_ammo_box_materials.dm" -#include "voidcrew_assault_pod.dm" -#include "voidcrew_autopilot_course.dm" -#include "voidcrew_autotranslate_morph.dm" -#include "voidcrew_autotranslate_output.dm" -#include "voidcrew_bitrunning.dm" -#include "voidcrew_blueprint_guns.dm" -#include "voidcrew_colosseum.dm" +#include "../../../voidcrew/modules/unit_tests/voidcrew_ammo_box_materials.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_assault_pod.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_autopilot_course.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_autotranslate_morph.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_autotranslate_output.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_bitrunning.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_blueprint_guns.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_colosseum.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "../../../voidcrew/modules/unit_tests/voidcrew_combat_metrics.dm" // VOIDCREW EDIT ADDITION -#include "voidcrew_construction_refunds.dm" +#include "../../../voidcrew/modules/unit_tests/voidcrew_construction_refunds.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "../../../voidcrew/modules/unit_tests/voidcrew_combat_camera_breaches.dm" // VOIDCREW EDIT ADDITION -#include "voidcrew_construction_automation.dm" -#include "voidcrew_pandora_links.dm" -#include "voidcrew_repair_robotics.dm" -#include "voidcrew_cordon_teleport.dm" -#include "voidcrew_crew_antag_gc.dm" -#include "voidcrew_crew_hud.dm" -#include "voidcrew_cyberware.dm" -#include "voidcrew_dissection_tiers.dm" -#include "voidcrew_drug_lab.dm" -#include "voidcrew_drug_recipe.dm" -#include "voidcrew_dynamic_events.dm" +#include "../../../voidcrew/modules/unit_tests/voidcrew_construction_automation.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_pandora_links.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_repair_robotics.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_cordon_teleport.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_crew_antag_gc.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_crew_hud.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_cyberware.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_dissection_tiers.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_drug_lab.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_drug_recipe.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_dynamic_events.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "../../../voidcrew/modules/unit_tests/voidcrew_economy_metrics.dm" // VOIDCREW EDIT ADDITION -#include "voidcrew_fleet_waypoints.dm" -#include "voidcrew_helpers.dm" -#include "voidcrew_hull_containment.dm" -#include "voidcrew_hull_survey.dm" +#include "../../../voidcrew/modules/unit_tests/voidcrew_fleet_waypoints.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_helpers.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_hull_containment.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_hull_survey.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "../../../voidcrew/modules/unit_tests/voidcrew_round_metrics.dm" // VOIDCREW EDIT ADDITION -#include "voidcrew_windoor_survey.dm" -#include "voidcrew_lich.dm" -#include "voidcrew_launch_access.dm" -#include "voidcrew_launch_cargo.dm" -#include "voidcrew_bank_deposits.dm" -#include "voidcrew_cargo_cart.dm" -#include "voidcrew_cargo_docking.dm" -#include "voidcrew_cargo_load_queue.dm" -#include "voidcrew_launch_fabrication.dm" -#include "voidcrew_launch_progression.dm" -#include "voidcrew_legion_cleanup.dm" -#include "voidcrew_loot.dm" -#include "voidcrew_map_packing.dm" -#include "voidcrew_mapload_floor_dir.dm" -#include "voidcrew_planetary_factions.dm" -#include "voidcrew_overmap_management.dm" -#include "voidcrew_planet_cleanup.dm" -#include "voidcrew_planet_definitions.dm" +#include "../../../voidcrew/modules/unit_tests/voidcrew_windoor_survey.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_lich.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_launch_access.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_bank_deposits.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_cargo_docking.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_cargo_load_queue.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_launch_fabrication.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_launch_progression.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_legion_cleanup.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_loot.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_map_packing.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_mapload_floor_dir.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_planetary_factions.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_overmap_management.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_planet_cleanup.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_planet_definitions.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "../../../voidcrew/modules/unit_tests/voidcrew_planet_shared_air.dm" // VOIDCREW EDIT ADDITION -#include "voidcrew_plumbing_shuttle_move.dm" -#include "voidcrew_missions.dm" -#include "voidcrew_mining_input.dm" -#include "voidcrew_mission_gps.dm" +#include "../../../voidcrew/modules/unit_tests/voidcrew_plumbing_shuttle_move.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_missions.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_mining_input.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_mission_gps.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "../../../voidcrew/modules/unit_tests/voidcrew_mission_metrics.dm" // VOIDCREW EDIT ADDITION -#include "voidcrew_npc_boarding_docking.dm" -#include "voidcrew_npc_disarm.dm" -#include "voidcrew_player_outpost.dm" -#include "voidcrew_outpost_management.dm" -#include "voidcrew_outpost_admin.dm" -#include "voidcrew_outpost_management_lifecycle.dm" -#include "voidcrew_outpost_services.dm" -#include "voidcrew_outpost_self_defense.dm" -#include "voidcrew_outpost_protection.dm" -#include "voidcrew_outpost_founding.dm" -#include "voidcrew_outpost_turret_targeting.dm" -#include "voidcrew_medical_research_links.dm" -#include "voidcrew_megafauna_aggro.dm" -#include "voidcrew_nanite_research.dm" -#include "voidcrew_research_lifecycle.dm" -#include "voidcrew_research_movement.dm" -#include "voidcrew_respawn_timer.dm" -#include "voidcrew_rnd_kit.dm" -#include "voidcrew_science_program.dm" -#include "voidcrew_survey_research_links.dm" -#include "voidcrew_survey_archive.dm" -#include "voidcrew_survey_identity.dm" -#include "voidcrew_survey_capabilities.dm" -#include "voidcrew_camera_scope.dm" -#include "voidcrew_ruin_bounds.dm" -#include "voidcrew_ruin_cleanup.dm" -#include "voidcrew_ruin_reservation.dm" -#include "voidcrew_ship_abandonment.dm" -#include "voidcrew_ship_access.dm" -#include "voidcrew_helm_access.dm" -#include "voidcrew_ship_assembly.dm" -#include "voidcrew_ship_communications.dm" -#include "voidcrew_ship_hulls.dm" -#include "voidcrew_ship_silicons.dm" -#include "voidcrew_ship_integrity.dm" -#include "voidcrew_ship_modules.dm" -#include "voidcrew_ship_turret_targeting.dm" -#include "voidcrew_shop_catalog.dm" -#include "voidcrew_silicon_ship_systems.dm" -#include "voidcrew_simple_mob_ai.dm" +#include "../../../voidcrew/modules/unit_tests/voidcrew_npc_boarding_docking.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_npc_disarm.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_player_outpost.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_outpost_management.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_outpost_admin.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_outpost_management_lifecycle.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_outpost_services.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_outpost_self_defense.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_outpost_protection.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_outpost_founding.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_outpost_turret_targeting.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_medical_research_links.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_megafauna_aggro.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_nanite_research.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_research_lifecycle.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_research_movement.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_respawn_timer.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_rnd_kit.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_science_program.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_survey_research_links.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_survey_archive.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_survey_identity.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_survey_capabilities.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_camera_scope.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ruin_bounds.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ruin_cleanup.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ruin_reservation.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ship_abandonment.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ship_access.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_helm_access.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ship_assembly.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ship_communications.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ship_hulls.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ship_silicons.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ship_integrity.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ship_modules.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_ship_turret_targeting.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_silicon_ship_systems.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_simple_mob_ai.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "../../../voidcrew/modules/unit_tests/voidcrew_slime_extract_piles.dm" // VOIDCREW EDIT ADDITION -#include "voidcrew_smart_locker.dm" -#include "voidcrew_vestige.dm" -#include "voidcrew_vestige_abductor.dm" -#include "voidcrew_vestige_ascension.dm" -#include "voidcrew_vestige_biology_routes.dm" -#include "voidcrew_vestige_changeling.dm" -#include "voidcrew_vestige_confiscation.dm" -#include "voidcrew_vestige_field.dm" -#include "voidcrew_vestige_hunts.dm" -#include "voidcrew_vestige_lifecycle.dm" -#include "voidcrew_vestige_morph.dm" -#include "voidcrew_vestige_morph_routes.dm" -#include "voidcrew_vestige_rites.dm" -#include "voidcrew_vestige_rites_routes.dm" -#include "voidcrew_vestige_routes.dm" -#include "voidcrew_vestige_status.dm" -#include "voidcrew_vestige_visuals.dm" -#include "voidcrew_wall_break_atmos.dm" -#include "voidcrew_weather_sites.dm" -#include "voidcrew_zone_logging.dm" +#include "../../../voidcrew/modules/unit_tests/voidcrew_smart_locker.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_abductor.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_ascension.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_biology_routes.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_changeling.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_confiscation.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_field.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_hunts.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_lifecycle.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_morph.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_morph_routes.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_rites.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_rites_routes.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_routes.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_status.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_vestige_visuals.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_wall_break_atmos.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_weather_sites.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. +#include "../../../voidcrew/modules/unit_tests/voidcrew_zone_logging.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "washing.dm" -#include "weather_mob_targeting.dm" +#include "../../../voidcrew/modules/unit_tests/weather_mob_targeting.dm" // VOIDCREW EDIT: keep fork tests in the unit_tests module. #include "weird_food.dm" #include "wizard_loadout.dm" #include "worn_icons.dm" diff --git a/tgstation.dme b/tgstation.dme index 456f9466d2e..2b2a2f83a42 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -524,7 +524,7 @@ #include "code\__HELPERS\logging\transport.dm" #include "code\__HELPERS\logging\ui.dm" #include "code\__HELPERS\logging\virus.dm" -#include "code\__HELPERS\logging\worldgen.dm" +#include "voidcrew\_HELPERS\worldgen.dm" #include "code\__HELPERS\paths\jps.dm" #include "code\__HELPERS\paths\path.dm" #include "code\__HELPERS\paths\sssp.dm" @@ -6098,9 +6098,9 @@ #include "code\modules\research\xenobiology\vatgrowing\samples\viruses\_virus.dm" #include "code\modules\security_levels\keycard_authentication.dm" #include "code\modules\security_levels\security_level_datums.dm" -#include "code\modules\ship_purchase\ship_catalog_ui.dm" -#include "code\modules\ship_purchase\ship_economy_database.dm" -#include "code\modules\ship_purchase\transaction_helpers.dm" +#include "voidcrew\modules\ship_purchase\ship_catalog_ui.dm" +#include "voidcrew\modules\ship_purchase\ship_economy_database.dm" +#include "voidcrew\modules\ship_purchase\transaction_helpers.dm" #include "code\modules\shuttle\shuttle.dm" #include "code\modules\shuttle\misc\manipulator.dm" #include "code\modules\shuttle\misc\medisim.dm" diff --git a/tgui/packages/tgui-panel/index.tsx b/tgui/packages/tgui-panel/index.tsx index 8b0e3c98f91..8f4be031356 100644 --- a/tgui/packages/tgui-panel/index.tsx +++ b/tgui/packages/tgui-panel/index.tsx @@ -24,7 +24,7 @@ import { chatMiddleware, chatReducer } from './chat'; // and its watchdog at module scope, and nothing else imports it - without // this line the bundler tree-shakes the whole feature out and translations // silently never apply. -import './chat/translation'; +import '../voidcrew_tgui/chat/translation'; // VOIDCREW EDIT ADDITION END import { gameMiddleware, gameReducer } from './game'; import { Panel } from './Panel'; diff --git a/tgui/packages/tgui-panel/styles/main.scss b/tgui/packages/tgui-panel/styles/main.scss index 48f688ae512..06503d81ff5 100644 --- a/tgui/packages/tgui-panel/styles/main.scss +++ b/tgui/packages/tgui-panel/styles/main.scss @@ -25,7 +25,7 @@ @include meta.load-css('./components/Notifications.scss'); @include meta.load-css('./components/UnreadCount.scss'); // VOIDCREW EDIT ADDITION - AUTOTRANSLATE -@include meta.load-css('./components/Translation.scss'); +@include meta.load-css('../../voidcrew_tgui/styles/panel/components/Translation.scss'); // Layouts @include meta.load-css('~tgui/styles/layouts/Layout.scss'); diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/index.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/index.tsx index f5f5e91f99b..e7a75178b28 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/index.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/index.tsx @@ -8,7 +8,7 @@ import type { PreferencesMenuData } from '../types'; import { LoadoutPage } from './loadout'; import { MainPage } from './MainPage'; import { QuirksPage } from './QuirksPage'; -import { ShipCategoriesPage } from './ShipCategoriesPage'; +import { ShipCategoriesPage } from '../../../../voidcrew_tgui/interfaces/PreferencesMenu/CharacterPreferences/ShipCategoriesPage'; import { SpeciesPage } from './SpeciesPage'; enum Page { diff --git a/tgui/packages/tgui/styles/main.scss b/tgui/packages/tgui/styles/main.scss index ea3e08ffc95..d9f5a95b272 100644 --- a/tgui/packages/tgui/styles/main.scss +++ b/tgui/packages/tgui/styles/main.scss @@ -18,7 +18,7 @@ // Interfaces @include meta.load-css('./interfaces/AlertModal.scss'); @include meta.load-css('./interfaces/Changelog.scss'); -@include meta.load-css('./interfaces/ChromeCradle.scss'); +@include meta.load-css('../../voidcrew_tgui/styles/interfaces/ChromeCradle.scss'); @include meta.load-css('./interfaces/CrewManifest.scss'); @include meta.load-css('./interfaces/Emojipedia.scss'); @include meta.load-css('./interfaces/ExperimentConfigure.scss'); @@ -26,19 +26,19 @@ @include meta.load-css('./interfaces/HellishRunes.scss'); @include meta.load-css('./interfaces/HotKeysHelp.scss'); @include meta.load-css('./interfaces/Hypertorus.scss'); -@include meta.load-css('./interfaces/HelmComputer.scss'); -@include meta.load-css('./interfaces/ShipCombatConsole.scss'); +@include meta.load-css('../../voidcrew_tgui/styles/interfaces/HelmComputer.scss'); +@include meta.load-css('../../voidcrew_tgui/styles/interfaces/ShipCombatConsole.scss'); @include meta.load-css('./interfaces/IntegratedCircuit.scss'); @include meta.load-css('./interfaces/LibraryAdmin.scss'); @include meta.load-css('./interfaces/LibraryComputer.scss'); @include meta.load-css('./interfaces/ListInput.scss'); @include meta.load-css('./interfaces/Mecha.scss'); -@include meta.load-css('./interfaces/MissionBoard.scss'); +@include meta.load-css('../../voidcrew_tgui/styles/interfaces/MissionBoard.scss'); @include meta.load-css('./interfaces/NtosMessenger.scss'); @include meta.load-css('./interfaces/NtosNotepad.scss'); @include meta.load-css('./interfaces/NuclearBomb.scss'); @include meta.load-css('./interfaces/Orbit.scss'); -@include meta.load-css('./interfaces/OutpostManagement.scss'); +@include meta.load-css('../../voidcrew_tgui/styles/interfaces/OutpostManagement.scss'); @include meta.load-css('./interfaces/OreSilo.scss'); @include meta.load-css('./interfaces/Paper.scss'); @include meta.load-css('./interfaces/PreferencesMenu.scss'); diff --git a/tgui/packages/tgui-panel/chat/translation.test.ts b/tgui/packages/voidcrew_tgui/chat/translation.test.ts similarity index 99% rename from tgui/packages/tgui-panel/chat/translation.test.ts rename to tgui/packages/voidcrew_tgui/chat/translation.test.ts index 84872272d75..0202fa92b1e 100644 --- a/tgui/packages/tgui-panel/chat/translation.test.ts +++ b/tgui/packages/voidcrew_tgui/chat/translation.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it, mock, spyOn } from 'bun:test'; -mock.module('./renderer', () => ({ +mock.module('../../tgui-panel/chat/renderer', () => ({ chatRenderer: { events: { on: () => {} }, messages: [], diff --git a/tgui/packages/tgui-panel/chat/translation.ts b/tgui/packages/voidcrew_tgui/chat/translation.ts similarity index 99% rename from tgui/packages/tgui-panel/chat/translation.ts rename to tgui/packages/voidcrew_tgui/chat/translation.ts index c606aaf28e3..aa274f1c134 100644 --- a/tgui/packages/tgui-panel/chat/translation.ts +++ b/tgui/packages/voidcrew_tgui/chat/translation.ts @@ -16,8 +16,8 @@ */ import { createLogger } from 'tgui/logging'; -import { chatRenderer } from './renderer'; -import { highlightNode, linkifyNode } from './replaceInTextNode'; +import { chatRenderer } from '../../tgui-panel/chat/renderer'; +import { highlightNode, linkifyNode } from '../../tgui-panel/chat/replaceInTextNode'; const logger = createLogger('translation'); diff --git a/tgui/packages/tgui/interfaces/BlueprintImprinter.jsx b/tgui/packages/voidcrew_tgui/interfaces/BlueprintImprinter.jsx similarity index 98% rename from tgui/packages/tgui/interfaces/BlueprintImprinter.jsx rename to tgui/packages/voidcrew_tgui/interfaces/BlueprintImprinter.jsx index 8312f9c6f1a..8f39516c103 100644 --- a/tgui/packages/tgui/interfaces/BlueprintImprinter.jsx +++ b/tgui/packages/voidcrew_tgui/interfaces/BlueprintImprinter.jsx @@ -10,8 +10,8 @@ import { } from 'tgui-core/components'; import { toFixed } from 'tgui-core/math'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; const TIERS = { 1: { name: 'Green', color: 'good' }, diff --git a/tgui/packages/tgui/interfaces/ColosseumVault.tsx b/tgui/packages/voidcrew_tgui/interfaces/ColosseumVault.tsx similarity index 96% rename from tgui/packages/tgui/interfaces/ColosseumVault.tsx rename to tgui/packages/voidcrew_tgui/interfaces/ColosseumVault.tsx index 03ff88e1720..819406745bb 100644 --- a/tgui/packages/tgui/interfaces/ColosseumVault.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/ColosseumVault.tsx @@ -12,9 +12,9 @@ import { import type { BooleanLike } from 'tgui-core/react'; import { createSearch } from 'tgui-core/string'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; -import { getLayoutState, LAYOUT, LayoutToggle } from './common/LayoutToggle'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; +import { getLayoutState, LAYOUT, LayoutToggle } from '../../tgui/interfaces/common/LayoutToggle'; type VaultItem = { name: string; diff --git a/tgui/packages/tgui/interfaces/DrugLabCatalyst.tsx b/tgui/packages/voidcrew_tgui/interfaces/DrugLabCatalyst.tsx similarity index 99% rename from tgui/packages/tgui/interfaces/DrugLabCatalyst.tsx rename to tgui/packages/voidcrew_tgui/interfaces/DrugLabCatalyst.tsx index ced3c63019e..93ff1701904 100644 --- a/tgui/packages/tgui/interfaces/DrugLabCatalyst.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/DrugLabCatalyst.tsx @@ -33,8 +33,8 @@ import { KEY_UP, } from 'tgui-core/keycodes'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; import { type DrugLabCatalystData, DrugLabStage, diff --git a/tgui/packages/tgui/interfaces/DrugLabCrystallizer.tsx b/tgui/packages/voidcrew_tgui/interfaces/DrugLabCrystallizer.tsx similarity index 99% rename from tgui/packages/tgui/interfaces/DrugLabCrystallizer.tsx rename to tgui/packages/voidcrew_tgui/interfaces/DrugLabCrystallizer.tsx index ba3c8876c24..1c20258aa22 100644 --- a/tgui/packages/tgui/interfaces/DrugLabCrystallizer.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/DrugLabCrystallizer.tsx @@ -23,8 +23,8 @@ import { import type { KeyEvent } from 'tgui-core/events'; import { KEY_A, KEY_D, KEY_LEFT, KEY_RIGHT } from 'tgui-core/keycodes'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; import { type DrugLabCrystallizerData, DrugLabStage, diff --git a/tgui/packages/tgui/interfaces/DrugLabMixer.tsx b/tgui/packages/voidcrew_tgui/interfaces/DrugLabMixer.tsx similarity index 99% rename from tgui/packages/tgui/interfaces/DrugLabMixer.tsx rename to tgui/packages/voidcrew_tgui/interfaces/DrugLabMixer.tsx index 1b57009def4..7fd12a47c71 100644 --- a/tgui/packages/tgui/interfaces/DrugLabMixer.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/DrugLabMixer.tsx @@ -17,8 +17,8 @@ import { Stack, } from 'tgui-core/components'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; import { type DrugLabMixerData, DrugLabStage, diff --git a/tgui/packages/tgui/interfaces/MissionBoard.tsx b/tgui/packages/voidcrew_tgui/interfaces/MissionBoard.tsx similarity index 99% rename from tgui/packages/tgui/interfaces/MissionBoard.tsx rename to tgui/packages/voidcrew_tgui/interfaces/MissionBoard.tsx index b01444090cb..4008e9582ea 100644 --- a/tgui/packages/tgui/interfaces/MissionBoard.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/MissionBoard.tsx @@ -17,8 +17,8 @@ import { } from 'tgui-core/components'; import type { BooleanLike } from 'tgui-core/react'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; type RewardItem = { name: string; diff --git a/tgui/packages/tgui/interfaces/ModsuitBench.jsx b/tgui/packages/voidcrew_tgui/interfaces/ModsuitBench.jsx similarity index 99% rename from tgui/packages/tgui/interfaces/ModsuitBench.jsx rename to tgui/packages/voidcrew_tgui/interfaces/ModsuitBench.jsx index 7c4940b8e2d..eda7d91f7ba 100644 --- a/tgui/packages/tgui/interfaces/ModsuitBench.jsx +++ b/tgui/packages/voidcrew_tgui/interfaces/ModsuitBench.jsx @@ -13,8 +13,8 @@ import { Tooltip, } from 'tgui-core/components'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; const Wallet = (props) => { const { held_vouchers, account_credits } = props; diff --git a/tgui/packages/tgui/interfaces/OutpostElevator.tsx b/tgui/packages/voidcrew_tgui/interfaces/OutpostElevator.tsx similarity index 96% rename from tgui/packages/tgui/interfaces/OutpostElevator.tsx rename to tgui/packages/voidcrew_tgui/interfaces/OutpostElevator.tsx index 34c363db01f..ee1fdd7f56a 100644 --- a/tgui/packages/tgui/interfaces/OutpostElevator.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/OutpostElevator.tsx @@ -8,8 +8,8 @@ import { } from 'tgui-core/components'; import type { BooleanLike } from 'tgui-core/react'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; type Floor = { id: number; diff --git a/tgui/packages/tgui/interfaces/OutpostManagement.tsx b/tgui/packages/voidcrew_tgui/interfaces/OutpostManagement.tsx similarity index 99% rename from tgui/packages/tgui/interfaces/OutpostManagement.tsx rename to tgui/packages/voidcrew_tgui/interfaces/OutpostManagement.tsx index 9edcd7d486e..c7dc5f392fd 100644 --- a/tgui/packages/tgui/interfaces/OutpostManagement.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/OutpostManagement.tsx @@ -1,9 +1,9 @@ import { type ReactNode, useState } from 'react'; import { Button, Dropdown, Icon, Input, TextArea } from 'tgui-core/components'; import type { BooleanLike } from 'tgui-core/react'; -import { resolveAsset } from '../assets'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { resolveAsset } from '../../tgui/assets'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; // Matches the existing 1200 x 760 console plate, including its inset borders. const FRAME = { width: 1200, height: 760 }; diff --git a/tgui/packages/tgui/interfaces/OutpostManipulator.tsx b/tgui/packages/voidcrew_tgui/interfaces/OutpostManipulator.tsx similarity index 99% rename from tgui/packages/tgui/interfaces/OutpostManipulator.tsx rename to tgui/packages/voidcrew_tgui/interfaces/OutpostManipulator.tsx index ad1ecd4d123..d6165de0726 100644 --- a/tgui/packages/tgui/interfaces/OutpostManipulator.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/OutpostManipulator.tsx @@ -10,8 +10,8 @@ import { } from 'tgui-core/components'; import type { BooleanLike } from 'tgui-core/react'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; type OutpostSummary = { ref: string; diff --git a/tgui/packages/tgui/interfaces/OutpostMissionBoard.tsx b/tgui/packages/voidcrew_tgui/interfaces/OutpostMissionBoard.tsx similarity index 98% rename from tgui/packages/tgui/interfaces/OutpostMissionBoard.tsx rename to tgui/packages/voidcrew_tgui/interfaces/OutpostMissionBoard.tsx index 650f4110ff3..9492557274f 100644 --- a/tgui/packages/tgui/interfaces/OutpostMissionBoard.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/OutpostMissionBoard.tsx @@ -11,8 +11,8 @@ import { } from 'tgui-core/components'; import type { BooleanLike } from 'tgui-core/react'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; type RewardItem = { name: string; diff --git a/tgui/packages/tgui/interfaces/OutpostShellCatalog.tsx b/tgui/packages/voidcrew_tgui/interfaces/OutpostShellCatalog.tsx similarity index 96% rename from tgui/packages/tgui/interfaces/OutpostShellCatalog.tsx rename to tgui/packages/voidcrew_tgui/interfaces/OutpostShellCatalog.tsx index 0eec1403d67..c03d50197e7 100644 --- a/tgui/packages/tgui/interfaces/OutpostShellCatalog.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/OutpostShellCatalog.tsx @@ -10,8 +10,8 @@ import { } from 'tgui-core/components'; import type { BooleanLike } from 'tgui-core/react'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; type Shell = { id: string; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/ShipCategoriesPage.tsx b/tgui/packages/voidcrew_tgui/interfaces/PreferencesMenu/CharacterPreferences/ShipCategoriesPage.tsx similarity index 96% rename from tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/ShipCategoriesPage.tsx rename to tgui/packages/voidcrew_tgui/interfaces/PreferencesMenu/CharacterPreferences/ShipCategoriesPage.tsx index 7a2e5bf3d4b..1c3fac338a3 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/ShipCategoriesPage.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/PreferencesMenu/CharacterPreferences/ShipCategoriesPage.tsx @@ -1,8 +1,8 @@ import { useBackend } from 'tgui/backend'; import { Box, Button, Section, Stack } from 'tgui-core/components'; -import { JobPriority, type PreferencesMenuData } from '../types'; -import { useServerPrefs } from '../useServerPrefs'; +import { JobPriority, type PreferencesMenuData } from '../../../../tgui/interfaces/PreferencesMenu/types'; +import { useServerPrefs } from '../../../../tgui/interfaces/PreferencesMenu/useServerPrefs'; const PRIORITY_BUTTON_SIZE = '18px'; diff --git a/tgui/packages/tgui/interfaces/ShipCatalog.tsx b/tgui/packages/voidcrew_tgui/interfaces/ShipCatalog.tsx similarity index 99% rename from tgui/packages/tgui/interfaces/ShipCatalog.tsx rename to tgui/packages/voidcrew_tgui/interfaces/ShipCatalog.tsx index c9a7b38d35a..b79129efdbd 100644 --- a/tgui/packages/tgui/interfaces/ShipCatalog.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/ShipCatalog.tsx @@ -9,8 +9,8 @@ import { } from 'tgui-core/components'; import { classes } from 'tgui-core/react'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; type PartsInventory = { combat: number; diff --git a/tgui/packages/tgui/interfaces/ShipJoinMenu.tsx b/tgui/packages/voidcrew_tgui/interfaces/ShipJoinMenu.tsx similarity index 99% rename from tgui/packages/tgui/interfaces/ShipJoinMenu.tsx rename to tgui/packages/voidcrew_tgui/interfaces/ShipJoinMenu.tsx index 6dc1e9569b7..05aea78b63a 100644 --- a/tgui/packages/tgui/interfaces/ShipJoinMenu.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/ShipJoinMenu.tsx @@ -9,8 +9,8 @@ import { } from 'tgui-core/components'; import type { BooleanLike } from 'tgui-core/react'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; type ActiveShip = { ref: string; diff --git a/tgui/packages/tgui/interfaces/ShipUpgradeSelector.tsx b/tgui/packages/voidcrew_tgui/interfaces/ShipUpgradeSelector.tsx similarity index 99% rename from tgui/packages/tgui/interfaces/ShipUpgradeSelector.tsx rename to tgui/packages/voidcrew_tgui/interfaces/ShipUpgradeSelector.tsx index 38c2084a108..66d4f4b55a7 100644 --- a/tgui/packages/tgui/interfaces/ShipUpgradeSelector.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/ShipUpgradeSelector.tsx @@ -17,9 +17,9 @@ import { Tooltip, } from 'tgui-core/components'; -import { resolveAsset } from '../assets'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { resolveAsset } from '../../tgui/assets'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; type PartsInventory = { combat: number; diff --git a/tgui/packages/tgui/interfaces/TraderShop.tsx b/tgui/packages/voidcrew_tgui/interfaces/TraderShop.tsx similarity index 99% rename from tgui/packages/tgui/interfaces/TraderShop.tsx rename to tgui/packages/voidcrew_tgui/interfaces/TraderShop.tsx index 6129085f2c9..bd0b5e301f3 100644 --- a/tgui/packages/tgui/interfaces/TraderShop.tsx +++ b/tgui/packages/voidcrew_tgui/interfaces/TraderShop.tsx @@ -14,8 +14,8 @@ import { import { formatTime } from 'tgui-core/format'; import type { BooleanLike } from 'tgui-core/react'; -import { useBackend } from '../backend'; -import { Window } from '../layouts'; +import { useBackend } from '../../tgui/backend'; +import { Window } from '../../tgui/layouts'; type CatalogSku = { ref: string; diff --git a/tgui/packages/tgui/interfaces/common/drugLab.ts b/tgui/packages/voidcrew_tgui/interfaces/common/drugLab.ts similarity index 100% rename from tgui/packages/tgui/interfaces/common/drugLab.ts rename to tgui/packages/voidcrew_tgui/interfaces/common/drugLab.ts diff --git a/tgui/packages/tgui/layouts/Window.test.tsx b/tgui/packages/voidcrew_tgui/layouts/Window.test.tsx similarity index 85% rename from tgui/packages/tgui/layouts/Window.test.tsx rename to tgui/packages/voidcrew_tgui/layouts/Window.test.tsx index 37975e425bb..17d1b71b648 100644 --- a/tgui/packages/tgui/layouts/Window.test.tsx +++ b/tgui/packages/voidcrew_tgui/layouts/Window.test.tsx @@ -14,25 +14,25 @@ Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true, Byond: { windowId: 'tgui-window-2', winset }, }); -mock.module('../backend', () => ({ +mock.module('../../tgui/backend', () => ({ useBackend: () => backend, globalStore: { dispatch: () => {} }, backendSuspendStart: () => ({}), })); -mock.module('../debug', () => ({ useDebug: () => ({}) })); -mock.module('../logging', () => ({ createLogger: () => ({ log: () => {} }) })); -mock.module('../drag', () => ({ +mock.module('../../tgui/debug', () => ({ useDebug: () => ({}) })); +mock.module('../../tgui/logging', () => ({ createLogger: () => ({ log: () => {} }) })); +mock.module('../../tgui/drag', () => ({ dragStartHandler: () => {}, resizeStartHandler: () => {}, recallWindowGeometry: recallGeometry, setWindowKey, })); -mock.module('./Layout', () => ({ +mock.module('../../tgui/layouts/Layout', () => ({ Layout: ({ children }: PropsWithChildren) =>
{children}
, })); -mock.module('./TitleBar', () => ({ TitleBar: () => null })); +mock.module('../../tgui/layouts/TitleBar', () => ({ TitleBar: () => null })); -const { Window } = await import('./Window'); +const { Window } = await import('../../tgui/layouts/Window'); let root: Root; let container: HTMLDivElement; diff --git a/tgui/packages/tgui/src/interfaces/ShipSiphon.tsx b/tgui/packages/voidcrew_tgui/src/interfaces/ShipSiphon.tsx similarity index 97% rename from tgui/packages/tgui/src/interfaces/ShipSiphon.tsx rename to tgui/packages/voidcrew_tgui/src/interfaces/ShipSiphon.tsx index 756b7162fa8..c53d93a3fd8 100644 --- a/tgui/packages/tgui/src/interfaces/ShipSiphon.tsx +++ b/tgui/packages/voidcrew_tgui/src/interfaces/ShipSiphon.tsx @@ -1,6 +1,6 @@ -import { useBackend } from '../backend'; -import { Button, LabeledList, NoticeBox, ProgressBar, Section } from '../components'; -import { Window } from '../layouts'; +import { useBackend } from 'tgui/backend'; +import { Button, LabeledList, NoticeBox, ProgressBar, Section } from 'tgui-core/components'; +import { Window } from 'tgui/layouts'; type SiphonData = { active: boolean; diff --git a/tgui/packages/tgui/styles/interfaces/ChromeCradle.scss b/tgui/packages/voidcrew_tgui/styles/interfaces/ChromeCradle.scss similarity index 100% rename from tgui/packages/tgui/styles/interfaces/ChromeCradle.scss rename to tgui/packages/voidcrew_tgui/styles/interfaces/ChromeCradle.scss diff --git a/tgui/packages/tgui/styles/interfaces/HelmComputer.scss b/tgui/packages/voidcrew_tgui/styles/interfaces/HelmComputer.scss similarity index 100% rename from tgui/packages/tgui/styles/interfaces/HelmComputer.scss rename to tgui/packages/voidcrew_tgui/styles/interfaces/HelmComputer.scss diff --git a/tgui/packages/tgui/styles/interfaces/MissionBoard.scss b/tgui/packages/voidcrew_tgui/styles/interfaces/MissionBoard.scss similarity index 100% rename from tgui/packages/tgui/styles/interfaces/MissionBoard.scss rename to tgui/packages/voidcrew_tgui/styles/interfaces/MissionBoard.scss diff --git a/tgui/packages/tgui/styles/interfaces/OutpostManagement.scss b/tgui/packages/voidcrew_tgui/styles/interfaces/OutpostManagement.scss similarity index 100% rename from tgui/packages/tgui/styles/interfaces/OutpostManagement.scss rename to tgui/packages/voidcrew_tgui/styles/interfaces/OutpostManagement.scss diff --git a/tgui/packages/tgui/styles/interfaces/ShipCombatConsole.scss b/tgui/packages/voidcrew_tgui/styles/interfaces/ShipCombatConsole.scss similarity index 100% rename from tgui/packages/tgui/styles/interfaces/ShipCombatConsole.scss rename to tgui/packages/voidcrew_tgui/styles/interfaces/ShipCombatConsole.scss diff --git a/tgui/packages/tgui-panel/styles/components/Translation.scss b/tgui/packages/voidcrew_tgui/styles/panel/components/Translation.scss similarity index 100% rename from tgui/packages/tgui-panel/styles/components/Translation.scss rename to tgui/packages/voidcrew_tgui/styles/panel/components/Translation.scss diff --git a/code/__HELPERS/logging/worldgen.dm b/voidcrew/_HELPERS/worldgen.dm similarity index 100% rename from code/__HELPERS/logging/worldgen.dm rename to voidcrew/_HELPERS/worldgen.dm diff --git a/voidcrew/mapping/_mapping.dm b/voidcrew/mapping/_mapping.dm index f03e3789044..bdf1dd7eefe 100644 --- a/voidcrew/mapping/_mapping.dm +++ b/voidcrew/mapping/_mapping.dm @@ -331,7 +331,7 @@ if(registration.ruin_type) lower_traits[registration.ruin_type] = TRUE upper_traits[registration.ruin_type] = TRUE - LoadGroup(FailedZs, "Planet [planet_name] [i]", "map_files/voidcrew", "[planet_name].dmm", list(lower_traits, upper_traits)) + LoadGroup(FailedZs, "Planet [planet_name] [i]", "voidcrew/planets", "[planet_name].dmm", list(lower_traits, upper_traits)) z_count += 2 planets["[planet_name] [i]"] = list("type" = overmap_type, "z" = z_count, "zone_band" = next_planet_zone_band()) qdel(environment) diff --git a/code/modules/admin/verbs/shuttlepanel.dm b/voidcrew/modules/admin/legacy/shuttlepanel.dm similarity index 100% rename from code/modules/admin/verbs/shuttlepanel.dm rename to voidcrew/modules/admin/legacy/shuttlepanel.dm diff --git a/voidcrew/modules/chemistry/pouring_sounds.dm b/voidcrew/modules/chemistry/pouring_sounds.dm index 305cd11b1f8..cfe778dfbf9 100644 --- a/voidcrew/modules/chemistry/pouring_sounds.dm +++ b/voidcrew/modules/chemistry/pouring_sounds.dm @@ -12,38 +12,38 @@ /obj/item/reagent_containers/cup var/static/list/pouring_sounds_categorized = list( "0_10" = list( - 'sound/chemistry/transfer/beakerpour_0-10-1.ogg', - 'sound/chemistry/transfer/beakerpour_0-10-2.ogg', - 'sound/chemistry/transfer/beakerpour_0-10-3.ogg', - 'sound/chemistry/transfer/beakerpour_0-10-4.ogg', - 'sound/chemistry/transfer/beakerpour_0-10-5.ogg', - 'sound/chemistry/transfer/beakerpour_0-10-6.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-1.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-2.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-3.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-4.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-5.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-6.ogg', ), "10_25" = list( - 'sound/chemistry/transfer/beakerpour_10-25-1.ogg', - 'sound/chemistry/transfer/beakerpour_10-25-2.ogg', - 'sound/chemistry/transfer/beakerpour_10-25-3.ogg', - 'sound/chemistry/transfer/beakerpour_10-25-5.ogg', - 'sound/chemistry/transfer/beakerpour_10-25-6.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-1.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-2.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-3.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-5.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-6.ogg', ), "25_50" = list( - 'sound/chemistry/transfer/beakerpour_25-50-1.ogg', - 'sound/chemistry/transfer/beakerpour_25-50-2.ogg', - 'sound/chemistry/transfer/beakerpour_25-50-3.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-1.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-2.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-3.ogg', ), "50_inf" = list( - 'sound/chemistry/transfer/beakerpour_50-inf-1.ogg', - 'sound/chemistry/transfer/beakerpour_50-inf-2.ogg', - 'sound/chemistry/transfer/beakerpour_50-inf-3.ogg', - 'sound/chemistry/transfer/beakerpour_50-inf-4.ogg', - 'sound/chemistry/transfer/beakerpour_50-inf-5.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-1.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-2.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-3.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-4.ogg', + 'voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-5.ogg', ), ) var/static/list/rare_pouring_sound = list( - "0_10" = 'sound/chemistry/transfer/beakerpour_0-10-sparkle.ogg', - "10_25" = 'sound/chemistry/transfer/beakerpour_10-25-sparkle.ogg', - "25_50" = 'sound/chemistry/transfer/beakerpour_25-50-sparkle.ogg', - "50_inf" = 'sound/chemistry/transfer/beakerpour_50-inf-sparkle.ogg', + "0_10" = 'voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-sparkle.ogg', + "10_25" = 'voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-sparkle.ogg', + "25_50" = 'voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-sparkle.ogg', + "50_inf" = 'voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-sparkle.ogg', ) /// Plays a pour sound scaled to the amount transferred. Pass the source turf to @@ -64,8 +64,8 @@ /obj/item/reagent_containers/dropper var/static/list/dropper_sounds = list( - 'sound/chemistry/transfer/dropper1.ogg', - 'sound/chemistry/transfer/dropper2.ogg', + 'voidcrew/modules/chemistry/sound/transfer/dropper1.ogg', + 'voidcrew/modules/chemistry/sound/transfer/dropper2.ogg', ) /obj/item/reagent_containers/dropper/proc/after_pour(trans, atom/transed_to, mob/user) diff --git a/sound/chemistry/transfer/ATTRIBUTION.txt b/voidcrew/modules/chemistry/sound/transfer/ATTRIBUTION.txt similarity index 100% rename from sound/chemistry/transfer/ATTRIBUTION.txt rename to voidcrew/modules/chemistry/sound/transfer/ATTRIBUTION.txt diff --git a/sound/chemistry/transfer/beakerpour_0-10-1.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-1.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_0-10-1.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-1.ogg diff --git a/sound/chemistry/transfer/beakerpour_0-10-2.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-2.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_0-10-2.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-2.ogg diff --git a/sound/chemistry/transfer/beakerpour_0-10-3.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-3.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_0-10-3.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-3.ogg diff --git a/sound/chemistry/transfer/beakerpour_0-10-4.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-4.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_0-10-4.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-4.ogg diff --git a/sound/chemistry/transfer/beakerpour_0-10-5.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-5.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_0-10-5.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-5.ogg diff --git a/sound/chemistry/transfer/beakerpour_0-10-6.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-6.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_0-10-6.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-6.ogg diff --git a/sound/chemistry/transfer/beakerpour_0-10-sparkle.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-sparkle.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_0-10-sparkle.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_0-10-sparkle.ogg diff --git a/sound/chemistry/transfer/beakerpour_10-25-1.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-1.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_10-25-1.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-1.ogg diff --git a/sound/chemistry/transfer/beakerpour_10-25-2.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-2.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_10-25-2.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-2.ogg diff --git a/sound/chemistry/transfer/beakerpour_10-25-3.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-3.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_10-25-3.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-3.ogg diff --git a/sound/chemistry/transfer/beakerpour_10-25-4.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-4.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_10-25-4.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-4.ogg diff --git a/sound/chemistry/transfer/beakerpour_10-25-5.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-5.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_10-25-5.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-5.ogg diff --git a/sound/chemistry/transfer/beakerpour_10-25-6.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-6.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_10-25-6.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-6.ogg diff --git a/sound/chemistry/transfer/beakerpour_10-25-sparkle.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-sparkle.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_10-25-sparkle.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_10-25-sparkle.ogg diff --git a/sound/chemistry/transfer/beakerpour_25-50-1.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-1.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_25-50-1.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-1.ogg diff --git a/sound/chemistry/transfer/beakerpour_25-50-2.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-2.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_25-50-2.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-2.ogg diff --git a/sound/chemistry/transfer/beakerpour_25-50-3.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-3.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_25-50-3.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-3.ogg diff --git a/sound/chemistry/transfer/beakerpour_25-50-sparkle.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-sparkle.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_25-50-sparkle.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_25-50-sparkle.ogg diff --git a/sound/chemistry/transfer/beakerpour_50-inf-1.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-1.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_50-inf-1.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-1.ogg diff --git a/sound/chemistry/transfer/beakerpour_50-inf-2.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-2.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_50-inf-2.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-2.ogg diff --git a/sound/chemistry/transfer/beakerpour_50-inf-3.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-3.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_50-inf-3.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-3.ogg diff --git a/sound/chemistry/transfer/beakerpour_50-inf-4.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-4.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_50-inf-4.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-4.ogg diff --git a/sound/chemistry/transfer/beakerpour_50-inf-5.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-5.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_50-inf-5.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-5.ogg diff --git a/sound/chemistry/transfer/beakerpour_50-inf-sparkle.ogg b/voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-sparkle.ogg similarity index 100% rename from sound/chemistry/transfer/beakerpour_50-inf-sparkle.ogg rename to voidcrew/modules/chemistry/sound/transfer/beakerpour_50-inf-sparkle.ogg diff --git a/sound/chemistry/transfer/dropper1.ogg b/voidcrew/modules/chemistry/sound/transfer/dropper1.ogg similarity index 100% rename from sound/chemistry/transfer/dropper1.ogg rename to voidcrew/modules/chemistry/sound/transfer/dropper1.ogg diff --git a/sound/chemistry/transfer/dropper2.ogg b/voidcrew/modules/chemistry/sound/transfer/dropper2.ogg similarity index 100% rename from sound/chemistry/transfer/dropper2.ogg rename to voidcrew/modules/chemistry/sound/transfer/dropper2.ogg diff --git a/code/modules/ship_purchase/admin/economy_verbs.dm b/voidcrew/modules/ship_purchase/admin/economy_verbs.dm similarity index 100% rename from code/modules/ship_purchase/admin/economy_verbs.dm rename to voidcrew/modules/ship_purchase/admin/economy_verbs.dm diff --git a/code/modules/ship_purchase/ship_catalog_ui.dm b/voidcrew/modules/ship_purchase/ship_catalog_ui.dm similarity index 100% rename from code/modules/ship_purchase/ship_catalog_ui.dm rename to voidcrew/modules/ship_purchase/ship_catalog_ui.dm diff --git a/code/modules/ship_purchase/ship_economy_database.dm b/voidcrew/modules/ship_purchase/ship_economy_database.dm similarity index 100% rename from code/modules/ship_purchase/ship_economy_database.dm rename to voidcrew/modules/ship_purchase/ship_economy_database.dm diff --git a/code/modules/ship_purchase/transaction_helpers.dm b/voidcrew/modules/ship_purchase/transaction_helpers.dm similarity index 100% rename from code/modules/ship_purchase/transaction_helpers.dm rename to voidcrew/modules/ship_purchase/transaction_helpers.dm diff --git a/code/modules/unit_tests/atmos_component_pipeline.dm b/voidcrew/modules/unit_tests/atmos_component_pipeline.dm similarity index 100% rename from code/modules/unit_tests/atmos_component_pipeline.dm rename to voidcrew/modules/unit_tests/atmos_component_pipeline.dm diff --git a/code/modules/unit_tests/gas_connector_lifecycle.dm b/voidcrew/modules/unit_tests/gas_connector_lifecycle.dm similarity index 100% rename from code/modules/unit_tests/gas_connector_lifecycle.dm rename to voidcrew/modules/unit_tests/gas_connector_lifecycle.dm diff --git a/code/modules/unit_tests/glass_floor_baseturfs.dm b/voidcrew/modules/unit_tests/glass_floor_baseturfs.dm similarity index 100% rename from code/modules/unit_tests/glass_floor_baseturfs.dm rename to voidcrew/modules/unit_tests/glass_floor_baseturfs.dm diff --git a/code/modules/unit_tests/late_initialization_reentry.dm b/voidcrew/modules/unit_tests/late_initialization_reentry.dm similarity index 100% rename from code/modules/unit_tests/late_initialization_reentry.dm rename to voidcrew/modules/unit_tests/late_initialization_reentry.dm diff --git a/code/modules/unit_tests/map_parser_attributes.dm b/voidcrew/modules/unit_tests/map_parser_attributes.dm similarity index 100% rename from code/modules/unit_tests/map_parser_attributes.dm rename to voidcrew/modules/unit_tests/map_parser_attributes.dm diff --git a/code/modules/unit_tests/pipeline_reconciliation.dm b/voidcrew/modules/unit_tests/pipeline_reconciliation.dm similarity index 100% rename from code/modules/unit_tests/pipeline_reconciliation.dm rename to voidcrew/modules/unit_tests/pipeline_reconciliation.dm diff --git a/code/modules/unit_tests/prisoner_photos.dm b/voidcrew/modules/unit_tests/prisoner_photos.dm similarity index 100% rename from code/modules/unit_tests/prisoner_photos.dm rename to voidcrew/modules/unit_tests/prisoner_photos.dm diff --git a/code/modules/unit_tests/reagent_holder_teardown.dm b/voidcrew/modules/unit_tests/reagent_holder_teardown.dm similarity index 100% rename from code/modules/unit_tests/reagent_holder_teardown.dm rename to voidcrew/modules/unit_tests/reagent_holder_teardown.dm diff --git a/code/modules/unit_tests/shuttle_cling_lifecycle.dm b/voidcrew/modules/unit_tests/shuttle_cling_lifecycle.dm similarity index 100% rename from code/modules/unit_tests/shuttle_cling_lifecycle.dm rename to voidcrew/modules/unit_tests/shuttle_cling_lifecycle.dm diff --git a/code/modules/unit_tests/shuttle_load_ownership.dm b/voidcrew/modules/unit_tests/shuttle_load_ownership.dm similarity index 100% rename from code/modules/unit_tests/shuttle_load_ownership.dm rename to voidcrew/modules/unit_tests/shuttle_load_ownership.dm diff --git a/code/modules/unit_tests/soft_crit.dm b/voidcrew/modules/unit_tests/soft_crit.dm similarity index 100% rename from code/modules/unit_tests/soft_crit.dm rename to voidcrew/modules/unit_tests/soft_crit.dm diff --git a/code/modules/unit_tests/throw_cleanup.dm b/voidcrew/modules/unit_tests/throw_cleanup.dm similarity index 100% rename from code/modules/unit_tests/throw_cleanup.dm rename to voidcrew/modules/unit_tests/throw_cleanup.dm diff --git a/code/modules/unit_tests/voidcrew_ammo_box_materials.dm b/voidcrew/modules/unit_tests/voidcrew_ammo_box_materials.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ammo_box_materials.dm rename to voidcrew/modules/unit_tests/voidcrew_ammo_box_materials.dm diff --git a/code/modules/unit_tests/voidcrew_assault_pod.dm b/voidcrew/modules/unit_tests/voidcrew_assault_pod.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_assault_pod.dm rename to voidcrew/modules/unit_tests/voidcrew_assault_pod.dm diff --git a/code/modules/unit_tests/voidcrew_autopilot_course.dm b/voidcrew/modules/unit_tests/voidcrew_autopilot_course.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_autopilot_course.dm rename to voidcrew/modules/unit_tests/voidcrew_autopilot_course.dm diff --git a/code/modules/unit_tests/voidcrew_autotranslate_morph.dm b/voidcrew/modules/unit_tests/voidcrew_autotranslate_morph.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_autotranslate_morph.dm rename to voidcrew/modules/unit_tests/voidcrew_autotranslate_morph.dm diff --git a/code/modules/unit_tests/voidcrew_autotranslate_output.dm b/voidcrew/modules/unit_tests/voidcrew_autotranslate_output.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_autotranslate_output.dm rename to voidcrew/modules/unit_tests/voidcrew_autotranslate_output.dm diff --git a/code/modules/unit_tests/voidcrew_bank_deposits.dm b/voidcrew/modules/unit_tests/voidcrew_bank_deposits.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_bank_deposits.dm rename to voidcrew/modules/unit_tests/voidcrew_bank_deposits.dm diff --git a/code/modules/unit_tests/voidcrew_bitrunning.dm b/voidcrew/modules/unit_tests/voidcrew_bitrunning.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_bitrunning.dm rename to voidcrew/modules/unit_tests/voidcrew_bitrunning.dm diff --git a/code/modules/unit_tests/voidcrew_blueprint_guns.dm b/voidcrew/modules/unit_tests/voidcrew_blueprint_guns.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_blueprint_guns.dm rename to voidcrew/modules/unit_tests/voidcrew_blueprint_guns.dm diff --git a/code/modules/unit_tests/voidcrew_camera_scope.dm b/voidcrew/modules/unit_tests/voidcrew_camera_scope.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_camera_scope.dm rename to voidcrew/modules/unit_tests/voidcrew_camera_scope.dm diff --git a/code/modules/unit_tests/voidcrew_cargo_cart.dm b/voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_cargo_cart.dm rename to voidcrew/modules/unit_tests/voidcrew_cargo_cart.dm diff --git a/code/modules/unit_tests/voidcrew_cargo_docking.dm b/voidcrew/modules/unit_tests/voidcrew_cargo_docking.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_cargo_docking.dm rename to voidcrew/modules/unit_tests/voidcrew_cargo_docking.dm diff --git a/code/modules/unit_tests/voidcrew_cargo_load_queue.dm b/voidcrew/modules/unit_tests/voidcrew_cargo_load_queue.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_cargo_load_queue.dm rename to voidcrew/modules/unit_tests/voidcrew_cargo_load_queue.dm diff --git a/code/modules/unit_tests/voidcrew_colosseum.dm b/voidcrew/modules/unit_tests/voidcrew_colosseum.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_colosseum.dm rename to voidcrew/modules/unit_tests/voidcrew_colosseum.dm diff --git a/code/modules/unit_tests/voidcrew_construction_automation.dm b/voidcrew/modules/unit_tests/voidcrew_construction_automation.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_construction_automation.dm rename to voidcrew/modules/unit_tests/voidcrew_construction_automation.dm diff --git a/code/modules/unit_tests/voidcrew_construction_refunds.dm b/voidcrew/modules/unit_tests/voidcrew_construction_refunds.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_construction_refunds.dm rename to voidcrew/modules/unit_tests/voidcrew_construction_refunds.dm diff --git a/code/modules/unit_tests/voidcrew_cordon_teleport.dm b/voidcrew/modules/unit_tests/voidcrew_cordon_teleport.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_cordon_teleport.dm rename to voidcrew/modules/unit_tests/voidcrew_cordon_teleport.dm diff --git a/code/modules/unit_tests/voidcrew_crew_antag_gc.dm b/voidcrew/modules/unit_tests/voidcrew_crew_antag_gc.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_crew_antag_gc.dm rename to voidcrew/modules/unit_tests/voidcrew_crew_antag_gc.dm diff --git a/code/modules/unit_tests/voidcrew_crew_hud.dm b/voidcrew/modules/unit_tests/voidcrew_crew_hud.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_crew_hud.dm rename to voidcrew/modules/unit_tests/voidcrew_crew_hud.dm diff --git a/code/modules/unit_tests/voidcrew_cyberware.dm b/voidcrew/modules/unit_tests/voidcrew_cyberware.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_cyberware.dm rename to voidcrew/modules/unit_tests/voidcrew_cyberware.dm diff --git a/code/modules/unit_tests/voidcrew_dissection_tiers.dm b/voidcrew/modules/unit_tests/voidcrew_dissection_tiers.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_dissection_tiers.dm rename to voidcrew/modules/unit_tests/voidcrew_dissection_tiers.dm diff --git a/code/modules/unit_tests/voidcrew_drug_lab.dm b/voidcrew/modules/unit_tests/voidcrew_drug_lab.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_drug_lab.dm rename to voidcrew/modules/unit_tests/voidcrew_drug_lab.dm diff --git a/code/modules/unit_tests/voidcrew_drug_recipe.dm b/voidcrew/modules/unit_tests/voidcrew_drug_recipe.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_drug_recipe.dm rename to voidcrew/modules/unit_tests/voidcrew_drug_recipe.dm diff --git a/code/modules/unit_tests/voidcrew_dynamic_events.dm b/voidcrew/modules/unit_tests/voidcrew_dynamic_events.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_dynamic_events.dm rename to voidcrew/modules/unit_tests/voidcrew_dynamic_events.dm diff --git a/code/modules/unit_tests/voidcrew_fleet_waypoints.dm b/voidcrew/modules/unit_tests/voidcrew_fleet_waypoints.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_fleet_waypoints.dm rename to voidcrew/modules/unit_tests/voidcrew_fleet_waypoints.dm diff --git a/code/modules/unit_tests/voidcrew_helm_access.dm b/voidcrew/modules/unit_tests/voidcrew_helm_access.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_helm_access.dm rename to voidcrew/modules/unit_tests/voidcrew_helm_access.dm diff --git a/code/modules/unit_tests/voidcrew_helpers.dm b/voidcrew/modules/unit_tests/voidcrew_helpers.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_helpers.dm rename to voidcrew/modules/unit_tests/voidcrew_helpers.dm diff --git a/code/modules/unit_tests/voidcrew_hull_containment.dm b/voidcrew/modules/unit_tests/voidcrew_hull_containment.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_hull_containment.dm rename to voidcrew/modules/unit_tests/voidcrew_hull_containment.dm diff --git a/code/modules/unit_tests/voidcrew_hull_survey.dm b/voidcrew/modules/unit_tests/voidcrew_hull_survey.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_hull_survey.dm rename to voidcrew/modules/unit_tests/voidcrew_hull_survey.dm diff --git a/code/modules/unit_tests/voidcrew_launch_access.dm b/voidcrew/modules/unit_tests/voidcrew_launch_access.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_launch_access.dm rename to voidcrew/modules/unit_tests/voidcrew_launch_access.dm diff --git a/code/modules/unit_tests/voidcrew_launch_cargo.dm b/voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_launch_cargo.dm rename to voidcrew/modules/unit_tests/voidcrew_launch_cargo.dm diff --git a/code/modules/unit_tests/voidcrew_launch_fabrication.dm b/voidcrew/modules/unit_tests/voidcrew_launch_fabrication.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_launch_fabrication.dm rename to voidcrew/modules/unit_tests/voidcrew_launch_fabrication.dm diff --git a/code/modules/unit_tests/voidcrew_launch_progression.dm b/voidcrew/modules/unit_tests/voidcrew_launch_progression.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_launch_progression.dm rename to voidcrew/modules/unit_tests/voidcrew_launch_progression.dm diff --git a/code/modules/unit_tests/voidcrew_legion_cleanup.dm b/voidcrew/modules/unit_tests/voidcrew_legion_cleanup.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_legion_cleanup.dm rename to voidcrew/modules/unit_tests/voidcrew_legion_cleanup.dm diff --git a/code/modules/unit_tests/voidcrew_lich.dm b/voidcrew/modules/unit_tests/voidcrew_lich.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_lich.dm rename to voidcrew/modules/unit_tests/voidcrew_lich.dm diff --git a/code/modules/unit_tests/voidcrew_loot.dm b/voidcrew/modules/unit_tests/voidcrew_loot.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_loot.dm rename to voidcrew/modules/unit_tests/voidcrew_loot.dm diff --git a/code/modules/unit_tests/voidcrew_map_packing.dm b/voidcrew/modules/unit_tests/voidcrew_map_packing.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_map_packing.dm rename to voidcrew/modules/unit_tests/voidcrew_map_packing.dm diff --git a/code/modules/unit_tests/voidcrew_mapload_floor_dir.dm b/voidcrew/modules/unit_tests/voidcrew_mapload_floor_dir.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_mapload_floor_dir.dm rename to voidcrew/modules/unit_tests/voidcrew_mapload_floor_dir.dm diff --git a/code/modules/unit_tests/voidcrew_medical_research_links.dm b/voidcrew/modules/unit_tests/voidcrew_medical_research_links.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_medical_research_links.dm rename to voidcrew/modules/unit_tests/voidcrew_medical_research_links.dm diff --git a/code/modules/unit_tests/voidcrew_megafauna_aggro.dm b/voidcrew/modules/unit_tests/voidcrew_megafauna_aggro.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_megafauna_aggro.dm rename to voidcrew/modules/unit_tests/voidcrew_megafauna_aggro.dm diff --git a/code/modules/unit_tests/voidcrew_mining_input.dm b/voidcrew/modules/unit_tests/voidcrew_mining_input.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_mining_input.dm rename to voidcrew/modules/unit_tests/voidcrew_mining_input.dm diff --git a/code/modules/unit_tests/voidcrew_mission_gps.dm b/voidcrew/modules/unit_tests/voidcrew_mission_gps.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_mission_gps.dm rename to voidcrew/modules/unit_tests/voidcrew_mission_gps.dm diff --git a/code/modules/unit_tests/voidcrew_missions.dm b/voidcrew/modules/unit_tests/voidcrew_missions.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_missions.dm rename to voidcrew/modules/unit_tests/voidcrew_missions.dm diff --git a/code/modules/unit_tests/voidcrew_nanite_research.dm b/voidcrew/modules/unit_tests/voidcrew_nanite_research.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_nanite_research.dm rename to voidcrew/modules/unit_tests/voidcrew_nanite_research.dm diff --git a/code/modules/unit_tests/voidcrew_npc_boarding_docking.dm b/voidcrew/modules/unit_tests/voidcrew_npc_boarding_docking.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_npc_boarding_docking.dm rename to voidcrew/modules/unit_tests/voidcrew_npc_boarding_docking.dm diff --git a/code/modules/unit_tests/voidcrew_npc_disarm.dm b/voidcrew/modules/unit_tests/voidcrew_npc_disarm.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_npc_disarm.dm rename to voidcrew/modules/unit_tests/voidcrew_npc_disarm.dm diff --git a/code/modules/unit_tests/voidcrew_outpost_admin.dm b/voidcrew/modules/unit_tests/voidcrew_outpost_admin.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_outpost_admin.dm rename to voidcrew/modules/unit_tests/voidcrew_outpost_admin.dm diff --git a/code/modules/unit_tests/voidcrew_outpost_founding.dm b/voidcrew/modules/unit_tests/voidcrew_outpost_founding.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_outpost_founding.dm rename to voidcrew/modules/unit_tests/voidcrew_outpost_founding.dm diff --git a/code/modules/unit_tests/voidcrew_outpost_management.dm b/voidcrew/modules/unit_tests/voidcrew_outpost_management.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_outpost_management.dm rename to voidcrew/modules/unit_tests/voidcrew_outpost_management.dm diff --git a/code/modules/unit_tests/voidcrew_outpost_management_lifecycle.dm b/voidcrew/modules/unit_tests/voidcrew_outpost_management_lifecycle.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_outpost_management_lifecycle.dm rename to voidcrew/modules/unit_tests/voidcrew_outpost_management_lifecycle.dm diff --git a/code/modules/unit_tests/voidcrew_outpost_protection.dm b/voidcrew/modules/unit_tests/voidcrew_outpost_protection.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_outpost_protection.dm rename to voidcrew/modules/unit_tests/voidcrew_outpost_protection.dm diff --git a/code/modules/unit_tests/voidcrew_outpost_self_defense.dm b/voidcrew/modules/unit_tests/voidcrew_outpost_self_defense.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_outpost_self_defense.dm rename to voidcrew/modules/unit_tests/voidcrew_outpost_self_defense.dm diff --git a/code/modules/unit_tests/voidcrew_outpost_services.dm b/voidcrew/modules/unit_tests/voidcrew_outpost_services.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_outpost_services.dm rename to voidcrew/modules/unit_tests/voidcrew_outpost_services.dm diff --git a/code/modules/unit_tests/voidcrew_outpost_turret_targeting.dm b/voidcrew/modules/unit_tests/voidcrew_outpost_turret_targeting.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_outpost_turret_targeting.dm rename to voidcrew/modules/unit_tests/voidcrew_outpost_turret_targeting.dm diff --git a/code/modules/unit_tests/voidcrew_overmap_management.dm b/voidcrew/modules/unit_tests/voidcrew_overmap_management.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_overmap_management.dm rename to voidcrew/modules/unit_tests/voidcrew_overmap_management.dm diff --git a/code/modules/unit_tests/voidcrew_pandora_links.dm b/voidcrew/modules/unit_tests/voidcrew_pandora_links.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_pandora_links.dm rename to voidcrew/modules/unit_tests/voidcrew_pandora_links.dm diff --git a/code/modules/unit_tests/voidcrew_planet_cleanup.dm b/voidcrew/modules/unit_tests/voidcrew_planet_cleanup.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_planet_cleanup.dm rename to voidcrew/modules/unit_tests/voidcrew_planet_cleanup.dm diff --git a/code/modules/unit_tests/voidcrew_planet_definitions.dm b/voidcrew/modules/unit_tests/voidcrew_planet_definitions.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_planet_definitions.dm rename to voidcrew/modules/unit_tests/voidcrew_planet_definitions.dm diff --git a/code/modules/unit_tests/voidcrew_planetary_factions.dm b/voidcrew/modules/unit_tests/voidcrew_planetary_factions.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_planetary_factions.dm rename to voidcrew/modules/unit_tests/voidcrew_planetary_factions.dm diff --git a/code/modules/unit_tests/voidcrew_player_outpost.dm b/voidcrew/modules/unit_tests/voidcrew_player_outpost.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_player_outpost.dm rename to voidcrew/modules/unit_tests/voidcrew_player_outpost.dm diff --git a/code/modules/unit_tests/voidcrew_plumbing_shuttle_move.dm b/voidcrew/modules/unit_tests/voidcrew_plumbing_shuttle_move.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_plumbing_shuttle_move.dm rename to voidcrew/modules/unit_tests/voidcrew_plumbing_shuttle_move.dm diff --git a/code/modules/unit_tests/voidcrew_repair_robotics.dm b/voidcrew/modules/unit_tests/voidcrew_repair_robotics.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_repair_robotics.dm rename to voidcrew/modules/unit_tests/voidcrew_repair_robotics.dm diff --git a/code/modules/unit_tests/voidcrew_research_lifecycle.dm b/voidcrew/modules/unit_tests/voidcrew_research_lifecycle.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_research_lifecycle.dm rename to voidcrew/modules/unit_tests/voidcrew_research_lifecycle.dm diff --git a/code/modules/unit_tests/voidcrew_research_movement.dm b/voidcrew/modules/unit_tests/voidcrew_research_movement.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_research_movement.dm rename to voidcrew/modules/unit_tests/voidcrew_research_movement.dm diff --git a/code/modules/unit_tests/voidcrew_respawn_timer.dm b/voidcrew/modules/unit_tests/voidcrew_respawn_timer.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_respawn_timer.dm rename to voidcrew/modules/unit_tests/voidcrew_respawn_timer.dm diff --git a/code/modules/unit_tests/voidcrew_rnd_kit.dm b/voidcrew/modules/unit_tests/voidcrew_rnd_kit.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_rnd_kit.dm rename to voidcrew/modules/unit_tests/voidcrew_rnd_kit.dm diff --git a/code/modules/unit_tests/voidcrew_ruin_bounds.dm b/voidcrew/modules/unit_tests/voidcrew_ruin_bounds.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ruin_bounds.dm rename to voidcrew/modules/unit_tests/voidcrew_ruin_bounds.dm diff --git a/code/modules/unit_tests/voidcrew_ruin_cleanup.dm b/voidcrew/modules/unit_tests/voidcrew_ruin_cleanup.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ruin_cleanup.dm rename to voidcrew/modules/unit_tests/voidcrew_ruin_cleanup.dm diff --git a/code/modules/unit_tests/voidcrew_ruin_reservation.dm b/voidcrew/modules/unit_tests/voidcrew_ruin_reservation.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ruin_reservation.dm rename to voidcrew/modules/unit_tests/voidcrew_ruin_reservation.dm diff --git a/code/modules/unit_tests/voidcrew_science_program.dm b/voidcrew/modules/unit_tests/voidcrew_science_program.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_science_program.dm rename to voidcrew/modules/unit_tests/voidcrew_science_program.dm diff --git a/code/modules/unit_tests/voidcrew_ship_abandonment.dm b/voidcrew/modules/unit_tests/voidcrew_ship_abandonment.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ship_abandonment.dm rename to voidcrew/modules/unit_tests/voidcrew_ship_abandonment.dm diff --git a/code/modules/unit_tests/voidcrew_ship_access.dm b/voidcrew/modules/unit_tests/voidcrew_ship_access.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ship_access.dm rename to voidcrew/modules/unit_tests/voidcrew_ship_access.dm diff --git a/code/modules/unit_tests/voidcrew_ship_assembly.dm b/voidcrew/modules/unit_tests/voidcrew_ship_assembly.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ship_assembly.dm rename to voidcrew/modules/unit_tests/voidcrew_ship_assembly.dm diff --git a/code/modules/unit_tests/voidcrew_ship_communications.dm b/voidcrew/modules/unit_tests/voidcrew_ship_communications.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ship_communications.dm rename to voidcrew/modules/unit_tests/voidcrew_ship_communications.dm diff --git a/code/modules/unit_tests/voidcrew_ship_hulls.dm b/voidcrew/modules/unit_tests/voidcrew_ship_hulls.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ship_hulls.dm rename to voidcrew/modules/unit_tests/voidcrew_ship_hulls.dm diff --git a/code/modules/unit_tests/voidcrew_ship_integrity.dm b/voidcrew/modules/unit_tests/voidcrew_ship_integrity.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ship_integrity.dm rename to voidcrew/modules/unit_tests/voidcrew_ship_integrity.dm diff --git a/code/modules/unit_tests/voidcrew_ship_modules.dm b/voidcrew/modules/unit_tests/voidcrew_ship_modules.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ship_modules.dm rename to voidcrew/modules/unit_tests/voidcrew_ship_modules.dm diff --git a/code/modules/unit_tests/voidcrew_ship_silicons.dm b/voidcrew/modules/unit_tests/voidcrew_ship_silicons.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ship_silicons.dm rename to voidcrew/modules/unit_tests/voidcrew_ship_silicons.dm diff --git a/code/modules/unit_tests/voidcrew_ship_turret_targeting.dm b/voidcrew/modules/unit_tests/voidcrew_ship_turret_targeting.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_ship_turret_targeting.dm rename to voidcrew/modules/unit_tests/voidcrew_ship_turret_targeting.dm diff --git a/code/modules/unit_tests/voidcrew_shop_catalog.dm b/voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_shop_catalog.dm rename to voidcrew/modules/unit_tests/voidcrew_shop_catalog.dm diff --git a/code/modules/unit_tests/voidcrew_silicon_ship_systems.dm b/voidcrew/modules/unit_tests/voidcrew_silicon_ship_systems.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_silicon_ship_systems.dm rename to voidcrew/modules/unit_tests/voidcrew_silicon_ship_systems.dm diff --git a/code/modules/unit_tests/voidcrew_simple_mob_ai.dm b/voidcrew/modules/unit_tests/voidcrew_simple_mob_ai.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_simple_mob_ai.dm rename to voidcrew/modules/unit_tests/voidcrew_simple_mob_ai.dm diff --git a/code/modules/unit_tests/voidcrew_smart_locker.dm b/voidcrew/modules/unit_tests/voidcrew_smart_locker.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_smart_locker.dm rename to voidcrew/modules/unit_tests/voidcrew_smart_locker.dm diff --git a/code/modules/unit_tests/voidcrew_survey_archive.dm b/voidcrew/modules/unit_tests/voidcrew_survey_archive.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_survey_archive.dm rename to voidcrew/modules/unit_tests/voidcrew_survey_archive.dm diff --git a/code/modules/unit_tests/voidcrew_survey_capabilities.dm b/voidcrew/modules/unit_tests/voidcrew_survey_capabilities.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_survey_capabilities.dm rename to voidcrew/modules/unit_tests/voidcrew_survey_capabilities.dm diff --git a/code/modules/unit_tests/voidcrew_survey_identity.dm b/voidcrew/modules/unit_tests/voidcrew_survey_identity.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_survey_identity.dm rename to voidcrew/modules/unit_tests/voidcrew_survey_identity.dm diff --git a/code/modules/unit_tests/voidcrew_survey_research_links.dm b/voidcrew/modules/unit_tests/voidcrew_survey_research_links.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_survey_research_links.dm rename to voidcrew/modules/unit_tests/voidcrew_survey_research_links.dm diff --git a/code/modules/unit_tests/voidcrew_vestige.dm b/voidcrew/modules/unit_tests/voidcrew_vestige.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_abductor.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_abductor.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_abductor.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_abductor.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_ascension.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_ascension.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_ascension.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_ascension.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_biology_routes.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_biology_routes.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_biology_routes.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_biology_routes.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_changeling.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_changeling.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_changeling.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_changeling.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_confiscation.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_confiscation.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_confiscation.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_confiscation.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_field.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_field.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_field.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_field.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_hunts.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_hunts.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_hunts.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_hunts.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_lifecycle.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_lifecycle.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_lifecycle.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_lifecycle.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_morph.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_morph.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_morph.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_morph.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_morph_routes.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_morph_routes.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_morph_routes.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_morph_routes.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_rites.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_rites.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_rites.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_rites.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_rites_routes.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_rites_routes.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_rites_routes.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_rites_routes.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_routes.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_routes.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_routes.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_routes.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_status.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_status.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_status.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_status.dm diff --git a/code/modules/unit_tests/voidcrew_vestige_visuals.dm b/voidcrew/modules/unit_tests/voidcrew_vestige_visuals.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_vestige_visuals.dm rename to voidcrew/modules/unit_tests/voidcrew_vestige_visuals.dm diff --git a/code/modules/unit_tests/voidcrew_wall_break_atmos.dm b/voidcrew/modules/unit_tests/voidcrew_wall_break_atmos.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_wall_break_atmos.dm rename to voidcrew/modules/unit_tests/voidcrew_wall_break_atmos.dm diff --git a/code/modules/unit_tests/voidcrew_weather_sites.dm b/voidcrew/modules/unit_tests/voidcrew_weather_sites.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_weather_sites.dm rename to voidcrew/modules/unit_tests/voidcrew_weather_sites.dm diff --git a/code/modules/unit_tests/voidcrew_windoor_survey.dm b/voidcrew/modules/unit_tests/voidcrew_windoor_survey.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_windoor_survey.dm rename to voidcrew/modules/unit_tests/voidcrew_windoor_survey.dm diff --git a/code/modules/unit_tests/voidcrew_zone_logging.dm b/voidcrew/modules/unit_tests/voidcrew_zone_logging.dm similarity index 100% rename from code/modules/unit_tests/voidcrew_zone_logging.dm rename to voidcrew/modules/unit_tests/voidcrew_zone_logging.dm diff --git a/code/modules/unit_tests/weather_mob_targeting.dm b/voidcrew/modules/unit_tests/weather_mob_targeting.dm similarity index 100% rename from code/modules/unit_tests/weather_mob_targeting.dm rename to voidcrew/modules/unit_tests/weather_mob_targeting.dm From ab00cffb53f0b941018dc54a47cd79b6f3d93e34 Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Wed, 30 Sep 2026 04:28:10 -0700 Subject: [PATCH 2/6] Modularize game integration helpers and annotate fork changes --- code/game/area/areas.dm | 60 ++--------------- code/game/atom/_atom.dm | 23 +++---- code/game/atom/atom_defense.dm | 2 + code/game/machinery/computer/apc_control.dm | 2 +- code/game/machinery/computer/atmos_alert.dm | 4 +- code/game/machinery/computer/camera.dm | 8 ++- .../game/machinery/computer/communications.dm | 51 +++++++++----- code/game/machinery/computer/crew.dm | 13 ++-- code/game/machinery/doors/airlock.dm | 2 +- .../machinery/doors/airlock_electronics.dm | 2 + code/game/machinery/doors/firedoor.dm | 24 +------ code/game/machinery/doors/windowdoor.dm | 7 +- .../embedded_controller/airlock_controller.dm | 30 ++++----- code/game/machinery/status_display.dm | 6 +- code/game/movable_luminosity.dm | 16 ----- code/game/objects/effects/decals/crayon.dm | 2 +- code/game/objects/items.dm | 2 +- .../items/devices/scanners/gas_analyzer.dm | 2 +- .../items/devices/scanners/t_scanner.dm | 6 +- code/game/objects/items/rcd/RCD.dm | 63 ++++------------- code/game/objects/items/rcd/RHD.dm | 4 +- code/game/objects/items/rcd/RPD.dm | 23 +------ code/game/objects/items/stacks/medical.dm | 2 + code/game/objects/items/stacks/stack.dm | 4 +- code/game/objects/items/tanks/tanks.dm | 4 +- .../items/tools/painter/decal_painter.dm | 6 +- code/game/objects/obj_defense.dm | 2 +- .../structures/crates_lockers/closets.dm | 4 +- .../structures/crates_lockers/crates.dm | 2 - code/game/objects/structures/grille.dm | 6 +- code/game/objects/structures/lattice.dm | 2 + .../objects/structures/lavaland/ore_vent.dm | 2 + code/game/objects/structures/mystery_box.dm | 12 +++- code/game/objects/structures/shower.dm | 4 +- code/game/objects/structures/tables_racks.dm | 2 +- code/game/objects/structures/window.dm | 2 +- code/game/shuttle_engines.dm | 4 +- code/game/sound/sound.dm | 4 +- code/game/turfs/change_turf.dm | 17 +++-- code/game/turfs/closed/minerals.dm | 17 ++++- code/game/turfs/closed/wall/misc_walls.dm | 2 +- code/game/turfs/closed/wall/reinf_walls.dm | 2 +- code/game/turfs/closed/walls.dm | 10 ++- code/game/turfs/open/_open.dm | 2 +- code/game/turfs/open/floor.dm | 20 ++++-- code/game/turfs/open/floor/fancy_floor.dm | 2 +- code/game/turfs/open/grass.dm | 11 +-- code/game/turfs/open/river.dm | 4 +- code/game/turfs/open/space/space.dm | 5 +- code/game/turfs/open/space/transit.dm | 4 +- .../abductor/equipment/glands/heal.dm | 31 +++------ .../heretic/magic/rust_construction.dm | 20 +----- code/modules/clothing/clothing.dm | 2 +- .../clothing/glasses/engine_goggles.dm | 4 +- code/modules/clothing/head/hardhat.dm | 28 ++++---- code/modules/clothing/head/hat.dm | 6 +- code/modules/clothing/suits/utility.dm | 2 + .../modules/mob/dead/new_player/new_player.dm | 9 ++- code/modules/mob/dead/observer/observer.dm | 4 +- .../living/basic/lavaland/legion/legion.dm | 2 +- .../basic/lavaland/legion/spawn_legions.dm | 29 +------- code/modules/mob/living/basic/tree.dm | 2 +- .../mob/living/basic/trooper/pirate.dm | 1 + .../mob/living/basic/trooper/trooper.dm | 5 +- .../carbon/human/species_types/golems.dm | 2 +- code/modules/mob/living/carbon/inventory.dm | 17 +---- code/modules/mob/living/carbon/life.dm | 2 +- code/modules/mob/living/living.dm | 10 +-- code/modules/mob/living/login.dm | 2 +- code/modules/mob/living/silicon/ai/ai.dm | 8 +-- code/modules/mob/living/silicon/ai/ai_say.dm | 8 +-- .../mob/living/silicon/ai/robot_control.dm | 4 +- .../modules/mob/living/silicon/robot/robot.dm | 2 + .../living/simple_animal/hostile/hostile.dm | 4 +- .../hostile/megafauna/_megafauna.dm | 42 ------------ .../hostile/mining_mobs/mining_mobs.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 2 +- code/modules/mob/mob.dm | 18 +---- code/modules/mob/mob_defines.dm | 3 - code/modules/mod/mod_activation.dm | 2 +- code/modules/mod/mod_theme.dm | 34 +++++----- code/modules/mod/modules/modules_supply.dm | 11 +-- code/modules/mod/modules/modules_visor.dm | 4 +- code/modules/power/cable.dm | 4 +- .../singularity/dark_matter_singularity.dm | 2 + code/modules/power/singularity/emitter.dm | 6 +- .../modules/power/singularity/reality_tear.dm | 6 ++ code/modules/power/singularity/singularity.dm | 18 +++++ code/modules/power/smes.dm | 2 + code/modules/power/tesla/energy_ball.dm | 12 ++++ code/modules/power/turbine/turbine.dm | 33 +-------- .../modules/reagents/chemistry/equilibrium.dm | 9 +-- .../reagents/chemistry/holder/holder.dm | 5 +- .../reagents/chemistry/holder/reactions.dm | 6 +- .../chemistry/machinery/chem_heater.dm | 2 +- .../chemistry/reagents/food_reagents.dm | 2 + .../reagents/reaction_agents_reagents.dm | 4 +- code/modules/reagents/reagent_containers.dm | 2 +- .../reagents/reagent_containers/dropper.dm | 2 +- .../reagents/reagent_containers/hypospray.dm | 2 +- .../spells/spell_types/jaunt/bloodcrawl.dm | 19 +++--- .../spell_types/jaunt/ethereal_jaunt.dm | 53 +++++---------- .../spells/spell_types/tower_of_babel.dm | 5 +- voidcrew/edits/area_lifecycle.dm | 54 +++++++++++++++ voidcrew/edits/contained_lights.dm | 12 ++++ voidcrew/edits/grass_lifecycle.dm | 8 +++ voidcrew/edits/machinery/firedoor_shuttle.dm | 21 ++++++ voidcrew/edits/machinery/turbine_shuttle.dm | 31 +++++++++ voidcrew/edits/mobs/healing_gland.dm | 13 ++++ voidcrew/edits/mobs/internals_logging.dm | 10 +++ voidcrew/edits/mobs/legion_reach.dm | 24 +++++++ voidcrew/edits/mobs/megafauna_logging.dm | 41 ++++++++++++ voidcrew/edits/mobs/mind_history.dm | 4 ++ voidcrew/edits/mobs/softcrit_interaction.dm | 14 ++++ voidcrew/edits/mobs/trooper_appearance.dm | 3 + .../edits/objects/items/construction_hooks.dm | 67 +++++++++++++++++++ .../objects/items/mod_storage_lifecycle.dm | 5 ++ .../edits/objects/structures/cargo_payment.dm | 3 + voidcrew/edits/screentip_hover.dm | 8 +++ voidcrew/edits/spells/jaunt_destinations.dm | 36 ++++++++++ voidcrew/edits/spells/rust_filters.dm | 17 +++++ 121 files changed, 801 insertions(+), 596 deletions(-) create mode 100644 voidcrew/edits/area_lifecycle.dm create mode 100644 voidcrew/edits/contained_lights.dm create mode 100644 voidcrew/edits/grass_lifecycle.dm create mode 100644 voidcrew/edits/machinery/firedoor_shuttle.dm create mode 100644 voidcrew/edits/machinery/turbine_shuttle.dm create mode 100644 voidcrew/edits/mobs/healing_gland.dm create mode 100644 voidcrew/edits/mobs/internals_logging.dm create mode 100644 voidcrew/edits/mobs/legion_reach.dm create mode 100644 voidcrew/edits/mobs/megafauna_logging.dm create mode 100644 voidcrew/edits/mobs/mind_history.dm create mode 100644 voidcrew/edits/mobs/softcrit_interaction.dm create mode 100644 voidcrew/edits/mobs/trooper_appearance.dm create mode 100644 voidcrew/edits/objects/items/construction_hooks.dm create mode 100644 voidcrew/edits/objects/items/mod_storage_lifecycle.dm create mode 100644 voidcrew/edits/objects/structures/cargo_payment.dm create mode 100644 voidcrew/edits/screentip_hover.dm create mode 100644 voidcrew/edits/spells/jaunt_destinations.dm create mode 100644 voidcrew/edits/spells/rust_filters.dm diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 979166def26..17251a673e5 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -195,6 +195,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) . = ..() + // VOIDCREW EDIT REMOVAL - overmap lighting: area illumination must not multiply the ambient encounter appearance (voidcrew/edits/lighting.dm) reg_in_areas_in_z() update_base_lighting() @@ -281,6 +282,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) // Do your damndest to keep turfs out of /area/space as a stepping stone // That sucker gets HUGE and will make this take actual seconds if (zlevel_to_clean <= length(turfs_by_zlevel) && zlevel_to_clean <= length(turfs_to_uncontain_by_zlevel)) + // VOIDCREW EDIT START - overmap: keep recycled area turf bookkeeping bounded and lighting compatible with encounter areas var/list/contained_turfs = turfs_by_zlevel[zlevel_to_clean] var/list/turfs_to_cut = turfs_to_uncontain_by_zlevel[zlevel_to_clean] var/cut_count = length(turfs_to_cut) @@ -313,6 +315,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) contained_turfs += kept_turfs else turfs_by_zlevel[zlevel_to_clean] -= turfs_to_cut + // VOIDCREW EDIT END if (!_autoclean) // Removes empty lists from the end of this list turfs_to_uncontain_by_zlevel[zlevel_to_clean] = list() @@ -340,62 +343,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) // get_zlevel_turf_lists() tests exactly that length to decide whether it has to come // back here at all. Without this, every later call re-walks every z of an area with // nothing pending. See trim_trailing_empty_uncontain_lists(). - trim_trailing_empty_uncontain_lists() - -/** - * Drops the trailing all-empty z entries off turfs_to_uncontain_by_zlevel. - * - * `length(turfs_to_uncontain_by_zlevel)` is the cheap "is there anything pending" test that - * get_zlevel_turf_lists(), get_turfs_by_zlevel() and has_contained_turfs() all branch on, so - * an area whose cut lists have all been applied has to shrink back to zero or those hot - * readers keep paying to rediscover that there is nothing to do. - * - * Only trailing empties are dropped - a populated z anywhere in the list stops the walk - so - * this can never discard a pending cut. Callers that are mid-iteration over the list must - * call it AFTER the loop: it shortens the list, and DM snapshots a `1 to length()` bound. - */ -/area/proc/trim_trailing_empty_uncontain_lists() - var/current_length = length(turfs_to_uncontain_by_zlevel) - var/new_length = current_length - // Walk backwards thru the list - for (var/i in current_length to 0 step -1) - if (i && length(turfs_to_uncontain_by_zlevel[i])) - break // Stop the moment we find a useful list - new_length = i - - if (new_length < current_length) - turfs_to_uncontain_by_zlevel.len = new_length - -/** - * VOIDCREW ADDITION: TRUE when a turf really does still stand in this area. - * - * has_contained_turfs() above answers from list LENGTHS - `turfs_by_zlevel` minus the - * pending `turfs_to_uncontain_by_zlevel` - and that arithmetic only balances if every entry - * added to one list eventually gets its counterpart applied against the other. - * - * It did not. SSarea_contents used to empty an area's whole cut list in a single assignment - * once its drain loop finished, and change_area() appends to that same list during every - * MC_TICK_CHECK yield the drain takes. Anything that landed mid-drain was discarded without - * ever being applied, leaving one PHANTOM entry in `turfs_by_zlevel` per lost cut - and - * nothing that could ever remove it. An area in that state answers "still occupied" forever - * even once every real turf has been handed back, which is exactly the state a torn-down - * site's area is in, and why reap_emptied_areas() could not collect them. - * - * That discard is fixed (area_contents.dm drains one z at a time and clears only what it - * just applied), so this should now find residue only from paths that hand-roll the - * bookkeeping. It stays as the load-bearing safety for reap_emptied_areas(): reparenting - * live ground out from under a co-tenant is unrecoverable, and a length comparison is not - * worth that risk. - * - * Cheap in the case it exists for: get_zlevel_turf_lists() cannonizes first, which drops - * every properly-returned turf, so what is walked here is just the residue. - */ -/area/proc/has_resident_turfs() - for (var/list/zlevel_turfs as anything in get_zlevel_turf_lists()) - for (var/turf/resident as anything in zlevel_turfs) - if (resident?.loc == src) - return TRUE - return FALSE + trim_trailing_empty_uncontain_lists() // VOIDCREW EDIT: overmap: keep recycled area turf bookkeeping bounded and lighting compatible with encounter areas /// Returns TRUE if we have contained turfs, FALSE otherwise diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index 1fa24ab4113..eaa29ed1f7f 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -829,15 +829,6 @@ /atom/MouseEntered(location, control, params) SSmouse_entered.hovers[usr.client] = src -/atom/MouseExited(location, control, params) - var/client/hovering_client = usr?.client - if(!hovering_client) - return - // The pointer can leave before the deferred MouseEntered has been processed. - if(SSmouse_entered.hovers[hovering_client] == src) - SSmouse_entered.hovers[hovering_client] = null - hovering_client.mob?.hud_used?.screentip_text?.clear_hover(src) - /// Fired whenever this atom is the most recent to be hovered over in the tick. /// Preferred over MouseEntered if you do not need information such as the position of the mouse. /// Especially because this is deferred over a tick, do not trust that `client` is not null. @@ -855,10 +846,10 @@ if(!active_hud) return - var/hover_version = active_hud.screentip_text.begin_hover(src) + var/hover_version = active_hud.screentip_text.begin_hover(src) // VOIDCREW EDIT: screentip hover integration: clear departed hovers and reject stale deferred text (voidcrew/edits/screentip_hover.dm) var/screentips_enabled = active_hud.screentips_enabled if(screentips_enabled == SCREENTIP_PREFERENCE_DISABLED || flags_1 & NO_SCREENTIPS_1) - active_hud.screentip_text.set_hover_text("") + active_hud.screentip_text.set_hover_text("") // VOIDCREW EDIT: screentip hover integration: clear departed hovers and reject stale deferred text (voidcrew/edits/screentip_hover.dm) return var/lmb_rmb_line = "" @@ -939,27 +930,33 @@ if(extra_lines) extra_context = "
[lmb_rmb_line][ctrl_lmb_ctrl_rmb_line][alt_lmb_alt_rmb_line][shift_lmb_ctrl_shift_lmb_line]" + // VOIDCREW EDIT START - screentip hover integration: clear departed hovers and reject stale deferred text (voidcrew/edits/screentip_hover.dm) if (extra_context == "" && (screentips_enabled == SCREENTIP_PREFERENCE_CONTEXT_ONLY || !length(used_name))) active_hud.screentip_text.set_hover_text("") return //We inline a MAPTEXT() here, because there's no good way to statically add to a string like this var/new_maptext = "[used_name][extra_context]" + // VOIDCREW EDIT END if (length(used_name) * 10 > active_hud.screentip_text.maptext_width) - INVOKE_ASYNC(src, PROC_REF(set_hover_maptext), client, active_hud, new_maptext, hover_version) + INVOKE_ASYNC(src, PROC_REF(set_hover_maptext), client, active_hud, new_maptext, hover_version) // VOIDCREW EDIT: screentip hover integration: clear departed hovers and reject stale deferred text (voidcrew/edits/screentip_hover.dm) return - active_hud.screentip_text.set_hover_text(new_maptext, 10 - (extra_lines > 0 ? 11 + 9 * (extra_lines - 1): 0)) + active_hud.screentip_text.set_hover_text(new_maptext, 10 - (extra_lines > 0 ? 11 + 9 * (extra_lines - 1): 0)) // VOIDCREW EDIT: screentip hover integration: clear departed hovers and reject stale deferred text (voidcrew/edits/screentip_hover.dm) +// VOIDCREW EDIT START - screentip hover integration: clear departed hovers and reject stale deferred text (voidcrew/edits/screentip_hover.dm) /atom/proc/set_hover_maptext(client/client, datum/hud/active_hud, new_maptext, hover_version) var/atom/movable/screen/screentip/screentip = active_hud?.screentip_text if(!client || QDELETED(screentip) || screentip.hover_version != hover_version) return +// VOIDCREW EDIT END var/map_height + // VOIDCREW EDIT START - screentip hover integration: clear departed hovers and reject stale deferred text (voidcrew/edits/screentip_hover.dm) WXH_TO_HEIGHT(client.MeasureText(new_maptext, null, screentip.maptext_width), map_height) if(!client || QDELETED(screentip) || screentip.hover_version != hover_version) return screentip.set_hover_text(new_maptext, 26 - map_height) + // VOIDCREW EDIT END /** * This proc is used for telling whether something can pass by this atom in a given direction, for use by the pathfinding system. diff --git a/code/game/atom/atom_defense.dm b/code/game/atom/atom_defense.dm index 34bf17f2060..d3f19069100 100644 --- a/code/game/atom/atom_defense.dm +++ b/code/game/atom/atom_defense.dm @@ -70,8 +70,10 @@ return atom_integrity = new_value // VOIDCREW: record supported ship fixtures only when they actually lose integrity. + // VOIDCREW EDIT START - ship_repairs: distinguish damaged fixtures from deliberate dismantling if(new_value < old_value) record_ship_fixture_damage(src) + // VOIDCREW EDIT END on_update_integrity(old_value, new_value) return new_value diff --git a/code/game/machinery/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm index 7fdf566fb3f..02b718c5cb3 100644 --- a/code/game/machinery/computer/apc_control.dm +++ b/code/game/machinery/computer/apc_control.dm @@ -102,7 +102,7 @@ */ /obj/machinery/computer/apc_control/proc/check_apc(obj/machinery/power/apc/checked_apc) - // VOIDCREW EDIT ADDITION: packed-level containment, and a live is_on_station. + // VOIDCREW EDIT ADDITION START: packed-level containment, and a live is_on_station. - overmap: contain observers and effects within their packed encounter // Both branches of the upstream expression are wrong once sites share a z-level: // * is_on_station FALSE -> bare z equality lists and REMOTELY OPERATES every APC on // the packed z, i.e. all three co-tenants' sites plus any hull docked at them; diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm index df87a597f09..2017545e881 100644 --- a/code/game/machinery/computer/atmos_alert.dm +++ b/code/game/machinery/computer/atmos_alert.dm @@ -65,7 +65,7 @@ var/list/station_alert_areas = GLOB.the_station_areas + typesof(/area/mine) // Setting up a variable for checking our circuit's station_only var/obj/item/circuitboard/computer/atmos_alert/my_circuit = circuit - // VOIDCREW EDIT ADDITION: packed-level containment, resolved once per process() rather + // VOIDCREW EDIT ADDITION START: packed-level containment, resolved once per process() rather - overmap: contain observers and effects within their packed encounter // than once per alarm. The z branch below prints get_area_name() for every matching // alarm, so on a packed level a local atmos console named the neighbouring crew's rooms. var/datum/console_region = my_circuit.station_only ? null : map_region_for_turf(get_turf(src)) @@ -78,7 +78,7 @@ // Otherwise just check if alarms match the console's z-level else if (air_alarm.z != z) continue - // VOIDCREW EDIT ADDITION + // VOIDCREW EDIT ADDITION START - overmap: contain observers and effects within their packed encounter else if (map_region_excludes_turf(console_region, get_turf(air_alarm))) continue // VOIDCREW EDIT END diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index c4793514f00..d62ac6e36e0 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -111,10 +111,10 @@ if(action == "switch_camera") active_camera?.on_stop_watching(src) var/obj/machinery/camera/selected_camera = locate(params["camera"]) in GLOB.cameranet.cameras - active_camera = can_view_camera(selected_camera) ? selected_camera : null + active_camera = can_view_camera(selected_camera) ? selected_camera : null // VOIDCREW EDIT: ship camera integration: validate camera access and clear stale views (voidcrew/edits/machinery/camera.dm) if(isnull(active_camera)) - update_active_camera_screen() + update_active_camera_screen() // VOIDCREW EDIT: ship camera integration: validate camera access and clear stale views (voidcrew/edits/machinery/camera.dm) return TRUE active_camera.on_start_watching(src) @@ -124,13 +124,15 @@ /obj/machinery/computer/security/proc/update_active_camera_screen() // VOIDCREW: a stale/forged reference must not bypass the local camera network. + // VOIDCREW EDIT START - ship camera integration: validate camera access and clear stale views (voidcrew/edits/machinery/camera.dm) if(active_camera && !can_view_camera(active_camera)) active_camera.on_stop_watching(src) active_camera = null last_camera_turf = null + // VOIDCREW EDIT END // Show static if can't use the camera if(!active_camera?.can_use()) - last_camera_turf = null + last_camera_turf = null // VOIDCREW EDIT: ship camera integration: validate camera access and clear stale views (voidcrew/edits/machinery/camera.dm) cam_screen.show_camera_static() return diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 7d8e0aeb259..a9eba9aac64 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -21,7 +21,7 @@ /// Cooldown for important actions, such as messaging CentCom or other sectors COOLDOWN_DECLARE(static/important_action_cooldown) - COOLDOWN_DECLARE(emergency_access_cooldown) + COOLDOWN_DECLARE(emergency_access_cooldown) // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship /// Whether syndicate mode is enabled or not. var/syndicate = FALSE @@ -49,7 +49,7 @@ var/send_cross_comms_message_timer /// The last lines used for changing the status display - var/last_status_display + var/last_status_display // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship ///how many uses the console has done of toggling the emergency access var/toggle_uses = 0 @@ -77,6 +77,7 @@ /obj/machinery/computer/communications/syndicate/authenticated_as_silicon_or_captain(mob/user) return FALSE +// VOIDCREW EDIT REMOVAL - comms: syndicate consoles use the same local recipient scope as other ship consoles /obj/machinery/computer/communications/Initialize(mapload) . = ..() @@ -199,10 +200,10 @@ if (SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_DELTA) to_chat(user, span_warning("Central Command has placed a lock on the alert level due to a doomsday!")) return - if (get_communications_security_level().number_level == new_sec_level) + if (get_communications_security_level().number_level == new_sec_level) // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship return - set_communications_security_level(new_sec_level) + set_communications_security_level(new_sec_level) // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship to_chat(user, span_notice("Authorization confirmed. Modifying security level.")) playsound(src, 'sound/machines/terminal/terminal_prompt_confirm.ogg', 50, FALSE) @@ -275,7 +276,7 @@ bank_account.adjust_money(-shuttle.credit_cost) var/purchaser_name = (obj_flags & EMAGGED) ? scramble_message_replace_chars("AUTHENTICATION FAILURE: CVE-2018-17107", 60) : user.real_name - minor_announce("[purchaser_name] has purchased [shuttle.name] for [shuttle.credit_cost] credits.[shuttle.extra_desc ? " [shuttle.extra_desc]" : ""]" , "Shuttle Purchase", players = get_communication_players()) + minor_announce("[purchaser_name] has purchased [shuttle.name] for [shuttle.credit_cost] credits.[shuttle.extra_desc ? " [shuttle.extra_desc]" : ""]" , "Shuttle Purchase", players = get_communication_players()) // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship message_admins("[ADMIN_LOOKUPFLW(user)] purchased [shuttle.name].") log_shuttle("[key_name(user)] has purchased [shuttle.name].") @@ -286,6 +287,7 @@ if (!authenticated(user) || HAS_SILICON_ACCESS(user) || syndicate) return SSshuttle.cancelEvac(user) + // VOIDCREW EDIT REMOVAL - comms: ship consoles do not request station nuclear self-destruct codes if ("restoreBackupRoutingData") if (!authenticated_as_non_silicon_captain(user)) return @@ -355,6 +357,7 @@ var/line_one = reject_bad_text(params["upperText"] || "", MAX_STATUS_LINE_LENGTH) var/line_two = reject_bad_text(params["lowerText"] || "", MAX_STATUS_LINE_LENGTH) post_status("message", line_one, line_two) + // VOIDCREW EDIT REMOVAL - comms: keep announcements, alert state and status displays local to the communicating ship if ("setStatusPicture") if (!authenticated(user)) return @@ -365,7 +368,7 @@ post_status(picture) else if(picture == "currentalert") // You cannot set Code Blue display during Code Red and similiar - post_status("alert", get_communications_security_level().status_display_icon_state) + post_status("alert", get_communications_security_level().status_display_icon_state) // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship else post_status("alert", picture) @@ -401,13 +404,15 @@ return if (!authenticated_as_silicon_or_captain(user)) return + // VOIDCREW EDIT START - comms: keep announcements, alert state and status displays local to the communicating ship if (get_communications_emergency_access()) revoke_maint_all_access(src) + // VOIDCREW EDIT END user.log_message("disabled emergency maintenance access.", LOG_GAME) message_admins("[ADMIN_LOOKUPFLW(user)] disabled emergency maintenance access.") deadchat_broadcast(" disabled emergency maintenance access at [span_name("[get_area_name(user, TRUE)]")].", span_name("[user.real_name]"), user, message_type = DEADCHAT_ANNOUNCEMENT) else - make_maint_all_access(src) + make_maint_all_access(src) // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship user.log_message("enabled emergency maintenance access.", LOG_GAME) message_admins("[ADMIN_LOOKUPFLW(user)] enabled emergency maintenance access.") deadchat_broadcast(" enabled emergency maintenance access at [span_name("[get_area_name(user, TRUE)]")].", span_name("[user.real_name]"), user, message_type = DEADCHAT_ANNOUNCEMENT) @@ -434,7 +439,7 @@ SSjob.safe_code_request_loc = pod_location SSjob.safe_code_requested = TRUE SSjob.safe_code_timer_id = addtimer(CALLBACK(SSjob, TYPE_PROC_REF(/datum/controller/subsystem/job, send_spare_id_safe_code), pod_location), 120 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE) - minor_announce("Due to staff shortages, your crew has been approved for delivery of access codes to secure the Captain's Spare ID. Delivery via drop pod at [get_area(pod_location)]. ETA 120 seconds.", players = get_communication_players()) + minor_announce("Due to staff shortages, your crew has been approved for delivery of access codes to secure the Captain's Spare ID. Delivery via drop pod at [get_area(pod_location)]. ETA 120 seconds.", players = get_communication_players()) // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship /obj/machinery/computer/communications/proc/emergency_access_cooldown(mob/user) if(toggle_uses == toggle_max_uses) //you have used up free uses already, do it one more time and start a cooldown @@ -467,7 +472,7 @@ payload["is_filtered"] = TRUE send2otherserver(html_decode(station_name()), message, "Comms_Console", destination == "all" ? null : list(destination), additional_data = payload) - minor_announce(message, title = "Outgoing message to allied station", players = get_communication_players()) + minor_announce(message, title = "Outgoing message to allied station", players = get_communication_players()) // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship user.log_talk(message, LOG_SAY, tag = "message to the other server") message_admins("[ADMIN_LOOKUPFLW(user)] has sent a message to the other server\[s].") deadchat_broadcast(" has sent an outgoing message to the other station(s).", "[user.real_name]", user, message_type = DEADCHAT_ANNOUNCEMENT) @@ -511,6 +516,7 @@ data["canMakeAnnouncement"] = FALSE data["canMessageAssociates"] = FALSE data["canRecallShuttles"] = !HAS_SILICON_ACCESS(user) + // VOIDCREW EDIT REMOVAL - comms: keep announcements, alert state and status displays local to the communicating ship data["canSendToSectors"] = FALSE data["canSetAlertLevel"] = FALSE data["canToggleEmergencyAccess"] = FALSE @@ -518,7 +524,7 @@ data["shuttleCalled"] = FALSE data["shuttleLastCalled"] = FALSE data["aprilFools"] = check_holidays(APRIL_FOOLS) - data["alertLevel"] = get_communications_security_level().name + data["alertLevel"] = get_communications_security_level().name // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship data["authorizeName"] = authorize_name data["canLogOut"] = !HAS_SILICON_ACCESS(user) data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac() @@ -527,6 +533,7 @@ if (authenticated_as_non_silicon_captain(user)) data["canMessageAssociates"] = TRUE +// VOIDCREW EDIT REMOVAL - comms: keep announcements, alert state and status displays local to the communicating ship if (can_send_messages_to_other_sectors(user)) data["canSendToSectors"] = TRUE @@ -543,7 +550,7 @@ if (authenticated_as_silicon_or_captain(user)) data["canToggleEmergencyAccess"] = TRUE - data["emergencyAccess"] = get_communications_emergency_access() + data["emergencyAccess"] = get_communications_emergency_access() // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship data["alertLevelTick"] = alert_level_tick data["canMakeAnnouncement"] = TRUE @@ -598,9 +605,11 @@ data["budget"] = bank_account.account_balance data["shuttles"] = shuttles if (STATE_CHANGING_STATUS) + // VOIDCREW EDIT START - comms: keep announcements, alert state and status displays local to the communicating ship var/list/status_message = get_status_display_message() data["upperText"] = status_message ? status_message[1] : "" data["lowerText"] = status_message ? status_message[2] : "" + // VOIDCREW EDIT END return data @@ -642,10 +651,12 @@ /// Returns whether or not the communications console can communicate with the station /obj/machinery/computer/communications/proc/has_communication() + // VOIDCREW EDIT START - comms: keep announcements, alert state and status displays local to the communicating ship if(voidcrew_communications_ship(src)) return TRUE + // VOIDCREW EDIT END var/turf/current_turf = get_turf(src) - var/z_level = current_turf?.z + var/z_level = current_turf?.z // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship if(syndicate) return TRUE return is_station_level(z_level) || is_centcom_level(z_level) @@ -705,11 +716,13 @@ /obj/machinery/computer/communications/proc/make_announcement(mob/living/user) var/is_ai = HAS_SILICON_ACCESS(user) + // VOIDCREW EDIT START - comms: keep announcements, alert state and status displays local to the communicating ship var/datum/communciations_controller/controller = get_announcement_controller() if(!controller.can_announce(user, is_ai)) + // VOIDCREW EDIT END to_chat(user, span_alert("Intercomms recharging. Please stand by.")) return - var/input = tgui_input_text(user, "Message to announce to the local crew", "Announcement", max_length = MAX_MESSAGE_LEN) + var/input = tgui_input_text(user, "Message to announce to the local crew", "Announcement", max_length = MAX_MESSAGE_LEN) // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship if(!input || !user.can_perform_action(src, ALLOW_SILICON_REACH)) return if(user.try_speak(input)) @@ -728,12 +741,14 @@ var/list/players = get_communication_players() // Resolve again after the input prompt in case the console moved to another ship. + // VOIDCREW EDIT START - comms: keep announcements, alert state and status displays local to the communicating ship controller = get_announcement_controller() controller.make_announcement(user, is_ai, input, syndicate || (obj_flags & EMAGGED), players) + // VOIDCREW EDIT END deadchat_broadcast(" made a priority announcement from [span_name("[get_area_name(user, TRUE)]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT) /obj/machinery/computer/communications/proc/get_communication_players() - return voidcrew_announcement_players(src) + return voidcrew_announcement_players(src) // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship /obj/machinery/computer/communications/proc/post_status(command, data1, data2) @@ -742,16 +757,20 @@ if(!frequency) return + // VOIDCREW EDIT START - comms: keep announcements, alert state and status displays local to the communicating ship var/datum/signal/status_signal = new(list("command" = command, "voidcrew_net" = voidcrew_local_comms_net(src))) if(!status_signal.data["voidcrew_net"]) return + // VOIDCREW EDIT END switch(command) if("message") + // VOIDCREW EDIT START - comms: keep announcements, alert state and status displays local to the communicating ship var/obj/docking_port/mobile/ship = voidcrew_communications_ship(src) if(ship) ship.last_comms_status_display = list(data1, data2) else last_status_display = list(data1, data2) + // VOIDCREW EDIT END status_signal.data["top_text"] = data1 status_signal.data["bottom_text"] = data2 log_game("[key_name(usr)] has changed the station status display message to \"[data1] [data2]\" [loc_name(usr)]") @@ -853,7 +872,7 @@ priority_announce( "Attention crew: sector monitoring reports a jump-trace from an unidentified vessel destined for your system. Prepare for probable contact.", "[command_name()] High-Priority Update", - players = get_communication_players(), + players = get_communication_players(), // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship ) SSdynamic.force_run_midround(/datum/dynamic_ruleset/midround/from_ghosts/fugitives) @@ -861,7 +880,7 @@ priority_announce( "Attention crew, it appears that someone on your station has hijacked your telecommunications and broadcasted an unknown signal.", "[command_name()] High-Priority Update", - players = get_communication_players(), + players = get_communication_players(), // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship ) var/max_number_of_sleepers = clamp(round(length(GLOB.alive_player_list) / 40), 1, 3) if(!SSdynamic.force_run_midround(/datum/dynamic_ruleset/midround/from_living/traitor, forced_max_cap = max_number_of_sleepers)) diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index ffa6863ec0f..684f51da7b8 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -60,7 +60,7 @@ return var/list/new_table = list() - for(var/list/player_record as anything in GLOB.crewmonitor.update_data(attached_console)) + for(var/list/player_record as anything in GLOB.crewmonitor.update_data(attached_console)) // VOIDCREW EDIT: crew sensor integration: scope and cache readings by the requesting device (voidcrew/edits/machinery/crew_monitor.dm) var/list/entry = list() entry["name"] = player_record["name"] entry["job"] = player_record["assignment"] @@ -88,7 +88,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) /// List of user -> UI source var/list/ui_sources = list() /// Cache of data generated per sensor scope, used for serving the data within SENSOR_UPDATE_PERIOD of the last update - var/list/data_by_scope = list() + var/list/data_by_scope = list() // VOIDCREW EDIT: crew sensor integration: scope and cache readings by the requesting device (voidcrew/edits/machinery/crew_monitor.dm) /// Cache of last update time for each sensor scope var/list/last_update = list() /// Map of job to ID for sorting purposes @@ -176,10 +176,11 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) return host_ref?.resolve() /datum/crewmonitor/ui_data(mob/user) + // VOIDCREW EDIT REMOVAL - crew sensor integration: scope and cache readings by the requesting device (voidcrew/edits/machinery/crew_monitor.dm) // Voidcrew: the scope comes from the device that opened the UI - the console, the // handheld, the silicon - not from a bare z-level. voidcrew/edits/machinery/crew_monitor.dm . = list( - "sensors" = update_data(ui_host(user) || user), + "sensors" = update_data(ui_host(user) || user), // VOIDCREW EDIT: crew sensor integration: scope and cache readings by the requesting device (voidcrew/edits/machinery/crew_monitor.dm) "link_allowed" = HAS_AI_ACCESS(user), ) @@ -189,6 +190,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) * Voidcrew: takes the device doing the asking rather than a z-level, because a level * cannot scope this here - see voidcrew/edits/machinery/crew_monitor.dm. */ +// VOIDCREW EDIT START - crew sensor integration: scope and cache readings by the requesting device (voidcrew/edits/machinery/crew_monitor.dm) /datum/crewmonitor/proc/update_data(atom/source) var/turf/source_turf = get_turf(source) var/z = source_turf?.z @@ -197,6 +199,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) if(data_by_scope[cache_key] && last_update[cache_key] && world.time <= last_update[cache_key] + SENSORS_UPDATE_PERIOD) return data_by_scope[cache_key] +// VOIDCREW EDIT END var/list/results = list() for(var/tracked_mob in GLOB.suit_sensors_list) @@ -217,7 +220,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) // Voidcrew: the target has to be aboard our hull, or off-hull in the same place we // are - never just "on a station level", since every ship interior is one. // voidcrew/edits/machinery/crew_monitor.dm - if(!voidcrew_crew_sensor_in_scope(tracked_living_mob, pos, hull, z, source_turf)) + if(!voidcrew_crew_sensor_in_scope(tracked_living_mob, pos, hull, z, source_turf)) // VOIDCREW EDIT: crew sensor integration: scope and cache readings by the requesting device (voidcrew/edits/machinery/crew_monitor.dm) continue var/mob/living/carbon/human/tracked_human = tracked_living_mob @@ -293,8 +296,10 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) results[++results.len] = entry // Cache result + // VOIDCREW EDIT START - crew sensor integration: scope and cache readings by the requesting device (voidcrew/edits/machinery/crew_monitor.dm) data_by_scope[cache_key] = results last_update[cache_key] = world.time + // VOIDCREW EDIT END return results diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 6ddd23dd86d..30a969532b7 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1608,7 +1608,7 @@ if(!disassembled) A?.update_integrity(A.max_integrity * 0.5) // VOIDCREW: this exact wrecked frame belongs to the recorded destruction. - record_ship_repair_wreckage(src, A) + record_ship_repair_wreckage(src, A) // VOIDCREW EDIT: ship_repairs: distinguish damaged fixtures from deliberate dismantling else if(!(obj_flags & EMAGGED)) var/obj/item/electronics/airlock/ae diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm index b0f76af6ec8..5fec4fafc19 100644 --- a/code/game/machinery/doors/airlock_electronics.dm +++ b/code/game/machinery/doors/airlock_electronics.dm @@ -72,8 +72,10 @@ // this keeps any future one from costing a player their tgui window. Repairing the // var rather than just the payload also keeps do_action()'s `accesses += access` // from turning a null into a bare number. + // VOIDCREW EDIT START - ship access integration: preserve empty electronics access lists for AccessConfig (voidcrew/edits/ship_access.dm) if(isnull(accesses)) accesses = list() + // VOIDCREW EDIT END data["accesses"] = accesses data["oneAccess"] = one_access data["unres_direction"] = unres_sides diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index ec7244174d5..9742cbf1495 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -90,8 +90,10 @@ RegisterSignal(src, COMSIG_MACHINERY_POWER_RESTORED, PROC_REF(on_power_restore)) RegisterSignal(src, COMSIG_MACHINERY_POWER_LOST, PROC_REF(on_power_loss)) // Suppress atmosphere checks during shuttle moves to prevent false activations + // VOIDCREW EDIT START - shuttle: suspend firedoor atmosphere checks until the move settles (voidcrew/edits/machinery/firedoor_shuttle.dm) RegisterSignal(src, COMSIG_ATOM_BEFORE_SHUTTLE_MOVE, PROC_REF(on_shuttle_move_start)) RegisterSignal(src, COMSIG_ATOM_AFTER_SHUTTLE_MOVE, PROC_REF(on_shuttle_move_complete)) + // VOIDCREW EDIT END return INITIALIZE_HINT_LATELOAD /obj/machinery/door/firedoor/post_machine_initialize() @@ -489,28 +491,6 @@ if(is_playing_alarm) soundloop.start() -/// Called right before the shuttle physically moves - suppress atmosphere checks -/obj/machinery/door/firedoor/proc/on_shuttle_move_start(datum/source, turf/new_turf, rotation, move_mode, obj/docking_port/mobile/moving_dock) - SIGNAL_HANDLER - ignore_alarms = TRUE - -/// Called after shuttle move completes - re-enable checks and verify atmosphere -/obj/machinery/door/firedoor/proc/on_shuttle_move_complete(datum/source, turf/old_turf) - SIGNAL_HANDLER - ignore_alarms = FALSE - // Re-check atmosphere after it stabilizes to catch any real hazards - addtimer(CALLBACK(src, PROC_REF(post_shuttle_move_check)), 0.5 SECONDS) - -/// Re-evaluate atmospheric conditions after a shuttle move to catch real hazards -/obj/machinery/door/firedoor/proc/post_shuttle_move_check() - if(QDELETED(src)) - return - for(var/dir in GLOB.cardinals) - var/turf/checked_turf = get_step(get_turf(src), dir) - if(!checked_turf || !isopenturf(checked_turf)) - continue - process_results(checked_turf) - /obj/machinery/door/firedoor/attack_hand(mob/living/user, list/modifiers) . = ..() if(.) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 6a004c132a8..877ddcc4312 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -41,10 +41,13 @@ /obj/machinery/door/window/Initialize(mapload, set_dir, unres_sides) // The parent publishes atmos adjacency, which must use the edge we actually seal. + // VOIDCREW EDIT START - ship access and atmos integration: initialize the sealing edge before adjacency and preserve empty access lists (voidcrew/edits/ship_access.dm) if(set_dir) setDir(set_dir) + // VOIDCREW EDIT END . = ..() flags_1 &= ~PREVENT_CLICK_UNDER_1 + // VOIDCREW EDIT REMOVAL - ship access and atmos integration: initialize the sealing edge before adjacency and preserve empty access lists (voidcrew/edits/ship_access.dm) if(LAZYLEN(req_access)) icon_state = "[icon_state]" base_state = icon_state @@ -443,10 +446,10 @@ // no access at all has both lists null, and copying that null onto the // electronics blue-screens tgui when they are opened (AirlockElectronics.tsx // defaults `accesses` for undefined, not for null). - if(length(req_one_access)) + if(length(req_one_access)) // VOIDCREW EDIT: ship access and atmos integration: initialize the sealing edge before adjacency and preserve empty access lists (voidcrew/edits/ship_access.dm) dropped_electronics.one_access = 1 dropped_electronics.accesses = req_one_access - else if(length(req_access)) + else if(length(req_access)) // VOIDCREW EDIT: ship access and atmos integration: initialize the sealing edge before adjacency and preserve empty access lists (voidcrew/edits/ship_access.dm) dropped_electronics.accesses = req_access else dropped_electronics = electronics diff --git a/code/game/machinery/embedded_controller/airlock_controller.dm b/code/game/machinery/embedded_controller/airlock_controller.dm index ca6d0e58649..866d0545335 100644 --- a/code/game/machinery/embedded_controller/airlock_controller.dm +++ b/code/game/machinery/embedded_controller/airlock_controller.dm @@ -70,7 +70,7 @@ switch(state) if(AIRLOCK_STATE_INOPEN) if(target_state != state) - var/obj/machinery/door/airlock/interior_airlock = interior_door_ref?.resolve() + var/obj/machinery/door/airlock/interior_airlock = interior_door_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(interior_airlock)) continue @@ -80,7 +80,7 @@ else interior_airlock.secure_close() else - var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() + var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if(pump?.on) pump.on = FALSE @@ -93,7 +93,7 @@ continue if(sensor_pressure >= ONE_ATMOSPHERE*0.95) - var/obj/machinery/door/airlock/interior_airlock = interior_door_ref?.resolve() + var/obj/machinery/door/airlock/interior_airlock = interior_door_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(interior_airlock)) continue @@ -103,7 +103,7 @@ state = AIRLOCK_STATE_INOPEN process_again = TRUE else - var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() + var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(pump)) continue @@ -119,7 +119,7 @@ if(AIRLOCK_STATE_CLOSED) if(target_state == AIRLOCK_STATE_OUTOPEN) - var/obj/machinery/door/airlock/interior_airlock = interior_door_ref?.resolve() + var/obj/machinery/door/airlock/interior_airlock = interior_door_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(interior_airlock)) continue @@ -129,7 +129,7 @@ else interior_airlock?.secure_close() else if(target_state == AIRLOCK_STATE_INOPEN) - var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref?.resolve() + var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(exterior_airlock)) continue @@ -139,7 +139,7 @@ else exterior_airlock?.secure_close() else - var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() + var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(pump)) continue @@ -158,7 +158,7 @@ if(sensor_pressure <= target_pressure) if(target_state == AIRLOCK_STATE_OUTOPEN) - var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref?.resolve() + var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(exterior_airlock)) continue @@ -173,7 +173,7 @@ state = AIRLOCK_STATE_CLOSED process_again = TRUE else - var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() + var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(pump)) continue @@ -186,7 +186,7 @@ if(AIRLOCK_STATE_OUTOPEN) //state 2 if(target_state != AIRLOCK_STATE_OUTOPEN) - var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref?.resolve() + var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(exterior_airlock)) continue @@ -200,7 +200,7 @@ else exterior_airlock.secure_close() else - var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() + var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(pump)) continue @@ -221,19 +221,19 @@ var/sensor_pressure = sensor_pressure() data["sensorPressure"] = isnull(sensor_pressure) ? "----" : round(sensor_pressure, 0.1) - var/obj/machinery/door/airlock/interior_airlock = interior_door_ref?.resolve() + var/obj/machinery/door/airlock/interior_airlock = interior_door_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(interior_airlock)) data["interiorStatus"] = "----" else data["interiorStatus"] = interior_airlock.density ? "closed" : "open" - var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref?.resolve() + var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (isnull(exterior_airlock)) data["exteriorStatus"] = "----" else data["exteriorStatus"] = exterior_airlock.density ? "closed" : "open" - var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() + var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) switch (pump?.pump_direction) if (null) data["pumpStatus"] = "----" @@ -270,7 +270,7 @@ /// Returns the pressure over the pump, or null if it is deleted /obj/machinery/airlock_controller/proc/sensor_pressure() - var/obj/machinery/airlock_sensor/sensor = sensor_ref?.resolve() + var/obj/machinery/airlock_sensor/sensor = sensor_ref?.resolve() // VOIDCREW EDIT: shuttle airlock integration: tolerate missing linked devices while cycling ship airlocks (voidcrew/modules/shuttle) if (!isnull(sensor) && !sensor.on) return last_pressure diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index a24f81a001b..de50628a900 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -422,8 +422,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32) return PROCESS_KILL /obj/machinery/status_display/evac/receive_signal(datum/signal/signal) + // VOIDCREW EDIT START - comms: keep announcements, alert state and status displays local to the communicating ship if(signal.data["voidcrew_net"] && signal.data["voidcrew_net"] != voidcrew_local_comms_net(src)) return + // VOIDCREW EDIT END switch(signal.data["command"]) if("blank") current_mode = SD_BLANK @@ -466,16 +468,18 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32) /// Changes only when we are in 'alert' mode ([SD_PICTURE] and one of the alert's icon state already set) /obj/machinery/status_display/evac/proc/on_sec_level_change(datum/source, new_level) SIGNAL_HANDLER + // VOIDCREW EDIT START - comms: keep announcements, alert state and status displays local to the communicating ship var/obj/docking_port/mobile/ship = voidcrew_communications_ship(src) if(ship && source != ship) return + // VOIDCREW EDIT END if(current_mode != SD_PICTURE) return if(!(current_picture in SSsecurity_level.alert_level_icons)) return var/datum/security_level/alert_level = SSsecurity_level.available_levels[SSsecurity_level.number_level_to_text(new_level)] - last_picture = alert_level.status_display_icon_state + last_picture = alert_level.status_display_icon_state // VOIDCREW EDIT: comms: keep announcements, alert state and status displays local to the communicating ship set_picture(alert_level.status_display_icon_state) /// Supply display which shows the status of the supply shuttle. diff --git a/code/game/movable_luminosity.dm b/code/game/movable_luminosity.dm index 03455cb17de..8995ea7d7b0 100644 --- a/code/game/movable_luminosity.dm +++ b/code/game/movable_luminosity.dm @@ -10,24 +10,8 @@ luminosity -= affecting_dynamic_lumi affecting_dynamic_lumi = highest luminosity += affecting_dynamic_lumi - - ///Helper to change several lighting overlay settings. /atom/movable/proc/set_light_range_power_color(range, power, color) set_light_range(range) set_light_power(power) set_light_color(color) - - -/** - * Makes every overlay light we're carrying work out where it is again. - * - * Overlay lights only re-resolve their holder when they personally move, so gear that - * was in someone's hands or pockets while they sat inside a machine never learns that - * they climbed out of it, and stays dark until it is dropped and picked back up. - * Call this after moving a mob out of something it was inside of. - */ -/atom/movable/proc/recheck_contained_lights() - for(var/atom/movable/carried as anything in get_all_contents()) - var/datum/component/overlay_lighting/light = carried.GetComponent(/datum/component/overlay_lighting) - light?.recheck_holder() diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm index 000d3d3ddf2..b7928677600 100644 --- a/code/game/objects/effects/decals/crayon.dm +++ b/code/game/objects/effects/decals/crayon.dm @@ -20,7 +20,7 @@ name = e_name if(desc_override) desc = "[desc_override]" - else if(desc == initial(desc)) + else if(desc == initial(desc)) // VOIDCREW EDIT: ship_upgrades: preserve descriptions supplied by mapped decals // Preserve descriptions supplied by maps before initialization. desc = "A [name] vandalizing the station." if(alt_icon) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index afb9674e274..ac6cc0eb7f9 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1198,7 +1198,7 @@ remove_filter(HOVER_OUTLINE_FILTER) //get rid of the hover effect in case the mouse exit isn't called if someone drags and drops an item and somthing goes wrong /obj/item/MouseExited() - . = ..() + . = ..() // VOIDCREW EDIT: screentip hover integration: clear departed hovers and reject stale deferred text (voidcrew/edits/screentip_hover.dm) deltimer(tip_timer) //delete any in-progress timer if the mouse is moved off the item before it finishes closeToolTip(usr) remove_filter(HOVER_OUTLINE_FILTER) diff --git a/code/game/objects/items/devices/scanners/gas_analyzer.dm b/code/game/objects/items/devices/scanners/gas_analyzer.dm index 66c55d13a52..219d94dadd3 100644 --- a/code/game/objects/items/devices/scanners/gas_analyzer.dm +++ b/code/game/objects/items/devices/scanners/gas_analyzer.dm @@ -96,7 +96,7 @@ // VOIDCREW EDIT: the barometer reads the weather site standing under it, not the // z-level - several places can share a level and each hold its own storm cooldown. var/next_hit = SSweather.next_hit_timeleft_for_turf(T) - var/fixed = isnull(next_hit) ? -1 : next_hit + var/fixed = isnull(next_hit) ? -1 : next_hit // VOIDCREW EDIT: overmap weather: read the barometer cooldown for this encounter if(fixed < 0) to_chat(user, span_warning("[src]'s barometer function was unable to trace any weather patterns.")) else diff --git a/code/game/objects/items/devices/scanners/t_scanner.dm b/code/game/objects/items/devices/scanners/t_scanner.dm index fb65712af9b..e2d7ee2063d 100644 --- a/code/game/objects/items/devices/scanners/t_scanner.dm +++ b/code/game/objects/items/devices/scanners/t_scanner.dm @@ -51,13 +51,15 @@ * doing the looking, or the sweep lands around the operator sat at the console instead of * around the camera they are actually watching. */ -/proc/t_ray_scan(mob/viewer, flick_time = 8, distance = 3, atom/centre) +/proc/t_ray_scan(mob/viewer, flick_time = 8, distance = 3, atom/centre) // VOIDCREW EDIT: shuttle construction: scan around the remote drone while retaining the handheld default if(!ismob(viewer) || !viewer.client) return + // VOIDCREW EDIT START - shuttle construction: scan around the remote drone while retaining the handheld default if(isnull(centre)) centre = viewer + // VOIDCREW EDIT END var/list/t_ray_images = list() - for(var/obj/O in orange(distance, centre) ) + for(var/obj/O in orange(distance, centre) ) // VOIDCREW EDIT: shuttle construction: scan around the remote drone while retaining the handheld default if(HAS_TRAIT(O, TRAIT_T_RAY_VISIBLE)) var/image/I = new(loc = get_turf(O)) var/mutable_appearance/MA = new(O) diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index 896ba04e277..69b8c515914 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -64,10 +64,12 @@ airlock_electronics.name = "Access Control" airlock_electronics.holder = src + // VOIDCREW EDIT START - shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) var/list/designs = get_rcd_designs() root_category = designs[1] design_category = designs[root_category][1] var/list/design = designs[root_category][design_category][1] + // VOIDCREW EDIT END rcd_design_path = design["[RCD_DESIGN_PATH]"] design_title = initial(rcd_design_path.name) @@ -229,23 +231,6 @@ //checks for ui changes return ..() -/** - * Which way a directional build placed by this RCD should face. - * - * Directional windows, windoors, chairs, tables, racks and beds all take their facing from - * whoever is building them, and for a handheld RCD that is simply the user's own dir. It is - * not for an RCD driven remotely: the voidcrew ship construction console's drone is several - * rooms away from the body holding the "user" role, so every directional structure it built - * came out facing wherever the operator's body happened to be pointing at the console - * (issue #224). Overriding this lets such an RCD name the thing that is actually doing the - * building, without every rcd_act() implementation needing to know it exists. - * - * Arguments - * * [mob][user]- the mob credited with the build - */ -/obj/item/construction/rcd/proc/rcd_build_dir(mob/user) - return user?.dir - /** * actual proc to create the structure * @@ -301,7 +286,7 @@ var/obj/effect/constructing_effect/rcd_effect = new(get_turf(target), delay, rcd_results["[RCD_DESIGN_MODE]"], construction_upgrades) //resource & structure placement sanity checks before & after delay along with beam effects - if(!check_rcd_resources(rcd_results, user) || !can_place(target, rcd_results, user)) + if(!check_rcd_resources(rcd_results, user) || !can_place(target, rcd_results, user)) // VOIDCREW EDIT: shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) qdel(rcd_effect) return FALSE var/beam @@ -315,47 +300,21 @@ return FALSE if (QDELETED(rcd_effect)) return FALSE - if(!check_rcd_resources(rcd_results, user) || !can_place(target, rcd_results, user)) + if(!check_rcd_resources(rcd_results, user) || !can_place(target, rcd_results, user)) // VOIDCREW EDIT: shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) qdel(rcd_effect) return FALSE - if(!use_rcd_resources(rcd_results, user)) + if(!use_rcd_resources(rcd_results, user)) // VOIDCREW EDIT: shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) qdel(rcd_effect) return FALSE activate() - if(!apply_rcd_action(target, user, rcd_results)) + if(!apply_rcd_action(target, user, rcd_results)) // VOIDCREW EDIT: shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) qdel(rcd_effect) return FALSE playsound(loc, 'sound/machines/click.ogg', 50, TRUE) rcd_effect.end_animation() return TRUE -/** - * The design tree this RCD offers, in the GLOB.rcd_designs shape. - * - * Read instead of GLOB.rcd_designs directly so a subtype can offer blueprints the handheld - * RCD does not: the voidcrew ship construction console builds hull-grade windows that no - * engineer should be able to print out of a pocket device. - */ -/obj/item/construction/rcd/proc/get_rcd_designs() - return GLOB.rcd_designs - -/// Resource checks use the captured action, which may differ from the current UI selection after a delay. -/obj/item/construction/rcd/proc/check_rcd_resources(list/rcd_results, mob/user) - return checkResource(rcd_results["cost"], user) - -/obj/item/construction/rcd/proc/use_rcd_resources(list/rcd_results, mob/user) - return useResource(rcd_results["cost"], user) - -/// Applies a validated, paid-for action. Subtypes can handle successful resource recovery here. -/obj/item/construction/rcd/proc/apply_rcd_action(atom/target, mob/user, list/rcd_results) - var/turf/location = get_turf(target) - . = target.rcd_act(user, src, rcd_results) - // VOIDCREW: a successful deliberate removal supersedes an old repair order. - if(. && rcd_results["[RCD_DESIGN_MODE]"] == RCD_DECONSTRUCT) - var/obj/machinery/computer/camera_advanced/base_construction/ship/controller = SSship_repairs.area_controllers[get_area(location)] - controller?.forget_repair_record(controller.repair_coordinate_key(location)) - /obj/item/construction/rcd/ui_assets(mob/user) return list( get_asset_datum(/datum/asset/spritesheet_batched/rcd), @@ -377,15 +336,17 @@ for(var/key in electronics_data) data[key] = electronics_data[key] - var/list/design_tree = get_rcd_designs() + var/list/design_tree = get_rcd_designs() // VOIDCREW EDIT: shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) data["root_categories"] = list() - for(var/category in design_tree) + for(var/category in design_tree) // VOIDCREW EDIT: shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) data["root_categories"] += category data["selected_root"] = root_category data["categories"] = list() + // VOIDCREW EDIT START - shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) for(var/sub_category as anything in design_tree[root_category]) var/list/target_category = design_tree[root_category][sub_category] + // VOIDCREW EDIT END if(!length(target_category)) continue @@ -426,7 +387,7 @@ switch(action) if("root_category") var/new_root = params["root_category"] - if(get_rcd_designs()[new_root] != null) //is a valid category + if(get_rcd_designs()[new_root] != null) //is a valid category // VOIDCREW EDIT: shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) root_category = new_root update_static_data_for_all_viewers() @@ -434,7 +395,7 @@ //read and validate params from UI var/category_name = params["category"] var/index = params["index"] - var/list/root = get_rcd_designs()[root_category] + var/list/root = get_rcd_designs()[root_category] // VOIDCREW EDIT: shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) if(root == null) //not a valid root return TRUE var/list/category = root[category_name] diff --git a/code/game/objects/items/rcd/RHD.dm b/code/game/objects/items/rcd/RHD.dm index d436e52d416..88dda9c3cc8 100644 --- a/code/game/objects/items/rcd/RHD.dm +++ b/code/game/objects/items/rcd/RHD.dm @@ -69,7 +69,7 @@ ///used for examining the RCD and for its UI /obj/item/construction/proc/get_silo_iron() - if(silo_link && silo_mats.mat_container && silo_mats.check_z_level() && !silo_mats.on_hold()) + if(silo_link && silo_mats.mat_container && silo_mats.check_z_level() && !silo_mats.on_hold()) // VOIDCREW EDIT: ship material silo integration: check the linked silo scope before reading or spending resources (voidcrew/edits/machinery/materials_market.dm) return silo_mats.mat_container.get_material_amount(/datum/material/iron) / SILO_USE_AMOUNT return 0 @@ -193,8 +193,10 @@ if(!silo_mats.mat_container) if(user) balloon_alert(user, "no silo detected!") + // VOIDCREW EDIT START - ship material silo integration: check the linked silo scope before reading or spending resources (voidcrew/edits/machinery/materials_market.dm) return FALSE if(!silo_mats.can_use_resource(user_data = ID_DATA(user))) + // VOIDCREW EDIT END return FALSE if(!silo_mats.mat_container.has_enough_of_material(/datum/material/iron, amount * SILO_USE_AMOUNT)) diff --git a/code/game/objects/items/rcd/RPD.dm b/code/game/objects/items/rcd/RPD.dm index 5c3f5edf300..be477b9ba58 100644 --- a/code/game/objects/items/rcd/RPD.dm +++ b/code/game/objects/items/rcd/RPD.dm @@ -286,27 +286,6 @@ playsound(get_turf(src), 'sound/effects/pop.ogg', 50, FALSE) return TRUE -/// Installs an upgrade disk into the RPD, checking first that the upgrade isn't already present. -/// Returns TRUE if the disk was consumed. -/obj/item/pipe_dispenser/proc/install_upgrade(obj/item/rpd_upgrade/rpd_disk, mob/user) - // Check if the upgrade's already present - if(rpd_disk.upgrade_flags & upgrade_flags) - balloon_alert(user, "already installed!") - return FALSE - - // Adds the upgrade from the disk and then deletes the disk - upgrade_flags |= rpd_disk.upgrade_flags - playsound(loc, 'sound/machines/click.ogg', 50, vary = TRUE) - balloon_alert(user, "upgrade installed") - qdel(rpd_disk) - return TRUE - -/// Clicking an upgrade disk onto the RPD installs it, same as clicking the RPD onto the disk. -/obj/item/pipe_dispenser/item_interaction(mob/living/user, obj/item/tool, list/modifiers) - if(istype(tool, /obj/item/rpd_upgrade) && ISADVANCEDTOOLUSER(user)) - return install_upgrade(tool, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - return ..() - /obj/item/pipe_dispenser/interact_with_atom(atom/attack_target, mob/living/user, list/modifiers) . = NONE @@ -314,7 +293,7 @@ return if(istype(attack_target, /obj/item/rpd_upgrade)) - return install_upgrade(attack_target, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + return install_upgrade(attack_target, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING // VOIDCREW EDIT: construction tools: share disk installation between both item interaction directions (voidcrew/edits/objects/items/construction_hooks.dm) //So that changing the menu settings doesn't affect the pipes already being built. var/queued_pipe_type = recipe.id diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 120d4ac08b4..e8deb796ff4 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -182,8 +182,10 @@ if(!use(1) || !repeating || amount <= 0) var/atom/alert_loc = QDELETED(src) ? user : src alert_loc.balloon_alert(user, repeating ? "all used up!" : "treated [parse_zone(healed_zone)]") + // VOIDCREW EDIT START - Voidcrew medical integration: silent treatments must not pass a null healing sound (voidcrew/edits) if(heal_end_sound) playsound(patient, heal_end_sound, 75, TRUE, MEDIUM_RANGE_SOUND_EXTRARANGE) + // VOIDCREW EDIT END return if(heal_continuous_sound && (continuous || !silent)) playsound(patient, heal_continuous_sound, 75, TRUE, MEDIUM_RANGE_SOUND_EXTRARANGE) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 4dc77fba279..0b1c7f0d442 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -641,8 +641,10 @@ return FALSE if(SEND_SIGNAL(src, COMSIG_STACK_CAN_MERGE, check, inhand) & CANCEL_STACK_MERGE) return FALSE + // VOIDCREW EDIT START - antag_ruins: let trial loan components veto stack merges and follow splits if(SEND_SIGNAL(check, COMSIG_STACK_CAN_RECEIVE_MERGE, src, inhand) & CANCEL_STACK_MERGE) return FALSE + // VOIDCREW EDIT END return TRUE /** @@ -729,7 +731,7 @@ return null var/obj/item/stack/new_stack = new type(null, amount, FALSE, mats_per_unit) new_stack.copy_evidences(src) - SEND_SIGNAL(src, COMSIG_STACK_SPLIT, new_stack) + SEND_SIGNAL(src, COMSIG_STACK_SPLIT, new_stack) // VOIDCREW EDIT: antag_ruins: let trial loan components veto stack merges and follow splits loc.atom_storage?.refresh_views() is_zero_amount(delete_if_zero = TRUE) return new_stack diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index 10355d3a406..432e74f6270 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -78,14 +78,14 @@ return // Close open air tank if it got dropped by its current user. if (loc != breathing_mob) - breathing_mob.cutoff_internals("tank dropped by [user], now in [loc] ([loc?.type])") + breathing_mob.cutoff_internals("tank dropped by [user], now in [loc] ([loc?.type])") // VOIDCREW EDIT: shuttle internals diagnostics: identify the disconnect call site (voidcrew/edits/mobs/internals_logging.dm) /// Closes the tank if given to another mob while open. /obj/item/tank/equipped(mob/living/user, slot, initial) . = ..() // Close open air tank if it was equipped by a mob other than the current user. if (breathing_mob && (user != breathing_mob)) - breathing_mob.cutoff_internals("tank equipped to slot [slot] by [user || "NULL USER"]") + breathing_mob.cutoff_internals("tank equipped to slot [slot] by [user || "NULL USER"]") // VOIDCREW EDIT: shuttle internals diagnostics: identify the disconnect call site (voidcrew/edits/mobs/internals_logging.dm) /// Called by carbons after they connect the tank to their breathing apparatus. /obj/item/tank/proc/after_internals_opened(mob/living/carbon/carbon_target) diff --git a/code/game/objects/items/tools/painter/decal_painter.dm b/code/game/objects/items/tools/painter/decal_painter.dm index 549131501c3..7086f2233a6 100644 --- a/code/game/objects/items/tools/painter/decal_painter.dm +++ b/code/game/objects/items/tools/painter/decal_painter.dm @@ -38,7 +38,7 @@ * * target - The turf being painted to */ /obj/item/airlock_painter/decal/proc/paint_floor(turf/open/floor/target) - var/list/decal_data = get_decal_data() + var/list/decal_data = get_decal_data() // VOIDCREW EDIT: shuttle construction: route captured designs and remote building through construction hooks (voidcrew/edits/objects/items/construction_hooks.dm) target.AddElement( \ /datum/element/decal, \ @@ -50,10 +50,6 @@ _cleanable = FALSE, \ ) -/// An immutable description of the current paint selection for remote construction jobs. -/obj/item/airlock_painter/decal/proc/get_decal_data() - return current_category.get_decal_info(state = selected_decal_icon_state, color = selected_color, dir = selected_dir) - /obj/item/airlock_painter/decal/proc/set_category(datum/paintable_decal_category/category) current_category = category selected_color = category.possible_colors?[category.possible_colors[1]] diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 63566af6115..540a850448e 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -195,7 +195,7 @@ SHOULD_NOT_OVERRIDE(TRUE) // VOIDCREW: capture destruction before the fixture's configuration is discarded. - record_ship_fixture_damage(src, disassembled) + record_ship_fixture_damage(src, disassembled) // VOIDCREW EDIT: ship_repairs: distinguish damaged fixtures from deliberate dismantling //allow objects to deconstruct themselves handle_deconstruct(disassembled) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 1c436a80bfb..2bd40d4f2f5 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -618,7 +618,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) if(length(req_one_access)) electronics.one_access = TRUE electronics.accesses = req_one_access - else if(length(req_access)) + else if(length(req_access)) // VOIDCREW EDIT: ship access integration: preserve empty electronics access lists for AccessConfig (voidcrew/edits/ship_access.dm) electronics.accesses = req_access if(card_reader_installed) new /obj/item/stock_parts/card_reader(drop_location()) @@ -777,7 +777,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) if(length(req_one_access)) airlock_electronics.one_access = TRUE airlock_electronics.accesses = req_one_access - else if(length(req_access)) + else if(length(req_access)) // VOIDCREW EDIT: ship access integration: preserve empty electronics access lists for AccessConfig (voidcrew/edits/ship_access.dm) airlock_electronics.accesses = req_access req_access = list() diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 9c0881c6b19..c54605eb78c 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -27,8 +27,6 @@ var/crate_climb_time = 2 SECONDS /// The reference of the manifest paper attached to the cargo crate. var/datum/weakref/manifest - /// Actual ship order payment. Kept independently of removable paperwork for recycling caps. - var/cargo_paid_cost /// Where the Icons for lids are located. var/lid_icon = 'icons/obj/storage/crates.dmi' /// Icon state to use for lid to display when opened. Leave undefined if there isn't one. diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 572ab34eccd..8230c0abb9e 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -113,13 +113,13 @@ //checks if its a valid build direction //not user.dir: a remotely driven RCD builds where its drone is looking, not where //the body credited with the build happens to be pointing (see rcd_build_dir()) - var/build_dir = the_rcd.rcd_build_dir(user) + var/build_dir = the_rcd.rcd_build_dir(user) // VOIDCREW EDIT: shuttle construction: directional builds follow the remote drone (voidcrew/edits/objects/items/construction_hooks.dm) if(!initial(window_path.fulltile)) - if(!valid_build_direction(loc, build_dir, is_fulltile = FALSE)) + if(!valid_build_direction(loc, build_dir, is_fulltile = FALSE)) // VOIDCREW EDIT: shuttle construction: directional builds follow the remote drone (voidcrew/edits/objects/items/construction_hooks.dm) balloon_alert(user, "window already here!") return FALSE - var/obj/structure/window/WD = new window_path(T, build_dir) + var/obj/structure/window/WD = new window_path(T, build_dir) // VOIDCREW EDIT: shuttle construction: directional builds follow the remote drone (voidcrew/edits/objects/items/construction_hooks.dm) WD.set_anchored(TRUE) return TRUE return FALSE diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index cd2f0ffb561..aad983eb1d5 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -140,8 +140,10 @@ return list("mode" = RCD_DECONSTRUCT, "delay" = 1 SECONDS, "cost" = 5) return FALSE +// VOIDCREW EDIT START - shuttle construction: read the captured RCD action from the current list signature /obj/structure/lattice/catwalk/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, list/rcd_data) if(rcd_data["[RCD_DESIGN_MODE]"] == RCD_DECONSTRUCT) +// VOIDCREW EDIT END var/turf/turf = loc for(var/obj/structure/cable/cable_coil in turf) cable_coil.deconstruct() diff --git a/code/game/objects/structures/lavaland/ore_vent.dm b/code/game/objects/structures/lavaland/ore_vent.dm index 231155f0c2e..0a51fdfa612 100644 --- a/code/game/objects/structures/lavaland/ore_vent.dm +++ b/code/game/objects/structures/lavaland/ore_vent.dm @@ -410,10 +410,12 @@ // empty if SSore_generation's roundstart round-robin ran out of pool before it got to // this one (it breaks on stallbreaker), so roll a breakdown rather than produce a dud. if(!length(mineral_breakdown) && !unique_vent) + // VOIDCREW EDIT START - overmap: mid-round planet vents need a mineral breakdown before producing boulders generate_mineral_breakdown() generate_description() if(!length(mineral_breakdown)) return + // VOIDCREW EDIT END //produce the boulder var/obj/item/boulder/new_rock diff --git a/code/game/objects/structures/mystery_box.dm b/code/game/objects/structures/mystery_box.dm index 1eae8831065..28c3ebf0ad0 100644 --- a/code/game/objects/structures/mystery_box.dm +++ b/code/game/objects/structures/mystery_box.dm @@ -22,7 +22,7 @@ /// Pooled across the crew rather than handed out per person: a full ship would otherwise /// strip every use out of a chest on its own, while a two-man crew could never spend more /// than a fraction of them. -#define TREASURE_CHEST_CREW_SPINS 6 +#define TREASURE_CHEST_CREW_SPINS 6 // VOIDCREW EDIT: overmap treasure chests: pool fishing chest spins by crew rather than by individual opener GLOBAL_LIST_INIT(mystery_box_guns, list( /obj/item/gun/energy/recharge/ebow/large, @@ -292,7 +292,7 @@ GLOBAL_LIST_INIT(mystery_fishing, list( grant_extra_mag = FALSE anchored = FALSE /// Weakref of a crew - their ship, or the opener's own mind when they crew for none - to the spins that crew has already taken out of this chest. - var/list/spins_by_crew + var/list/spins_by_crew // VOIDCREW EDIT: overmap treasure chests: pool fishing chest spins by crew rather than by individual opener /obj/structure/mystery_box/handle_deconstruct(disassembled) new /obj/item/stack/sheet/mineral/wood(drop_location(), 2) @@ -301,6 +301,7 @@ GLOBAL_LIST_INIT(mystery_fishing, list( /obj/structure/mystery_box/fishing/generate_valid_types() valid_types = GLOB.mystery_fishing +// VOIDCREW EDIT START - overmap treasure chests: pool fishing chest spins by crew rather than by individual opener /obj/structure/mystery_box/fishing/Destroy() spins_by_crew = null return ..() @@ -322,16 +323,21 @@ GLOBAL_LIST_INIT(mystery_fishing, list( . += span_warning("It has nothing left for your crew.") return . += span_notice("It has [spins_left] spin[spins_left == 1 ? "" : "s"] left for your crew.") +// VOIDCREW EDIT END /obj/structure/mystery_box/fishing/activate(mob/living/user) + // VOIDCREW EDIT START - overmap treasure chests: pool fishing chest spins by crew rather than by individual opener var/datum/weakref/pool = get_spin_pool(user) if(pool && LAZYACCESS(spins_by_crew, pool) >= TREASURE_CHEST_CREW_SPINS) to_chat(user, span_warning("[src] refuses to open for your crew anymore. Perhaps you should hand it off to another one...")) + // VOIDCREW EDIT END return + // VOIDCREW EDIT START - overmap treasure chests: pool fishing chest spins by crew rather than by individual opener . = ..() if(pool) LAZYINITLIST(spins_by_crew) spins_by_crew[pool] += 1 + // VOIDCREW EDIT END /// This represents the item that comes out of the box and is constantly changing before the box finishes deciding. Can probably be just an /atom or /movable. /obj/effect/abstract/mystery_box_item @@ -416,4 +422,4 @@ GLOBAL_LIST_INIT(mystery_fishing, list( #undef MBOX_DURATION_PRESENTING #undef MBOX_DURATION_EXPIRING #undef MBOX_DURATION_STANDBY -#undef TREASURE_CHEST_CREW_SPINS +#undef TREASURE_CHEST_CREW_SPINS // VOIDCREW EDIT: overmap treasure chests: pool fishing chest spins by crew rather than by individual opener diff --git a/code/game/objects/structures/shower.dm b/code/game/objects/structures/shower.dm index 7a6fd613997..319d02d6712 100644 --- a/code/game/objects/structures/shower.dm +++ b/code/game/objects/structures/shower.dm @@ -10,7 +10,7 @@ #define SHOWER_EXPOSURE_MULTIPLIER 2 // Showers effectively double exposed reagents /// How long we run in TIMED mode #define SHOWER_TIMED_LENGTH (15 SECONDS) -// VOIDCREW EDIT: reserve a dry shower must rebuild before it auto-resumes. +// VOIDCREW EDIT START: reserve a dry shower must rebuild before it auto-resumes. - Voidcrew shower integration: refill to a working reserve before automatic restart (voidcrew/edits) // Without it, a shower left switched on re-fires the moment it recollects one // spray's worth (5u) and dumps it the same tick, so it never visibly recovers. // 50u = 10 seconds of spray. Invented/unplaytested value. @@ -326,7 +326,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/shower, (-16)) // Don't turn back on. if(mode != SHOWER_MODE_FOREVER) intended_on = FALSE - // VOIDCREW EDIT: an off-but-wanted-on shower waits for a working reserve + // VOIDCREW EDIT START: an off-but-wanted-on shower waits for a working reserve - Voidcrew shower integration: refill to a working reserve before automatic restart (voidcrew/edits) // (SHOWER_RESTART_VOLUME) instead of firing one spray per refill cycle. // Deliberate clicks (interact) still start it at one spray's worth. else if(!(intended_on && !actually_on && reagents.total_volume < SHOWER_RESTART_VOLUME)) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 776027a1416..1138c918efa 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -1020,7 +1020,7 @@ breath_mask = null /obj/structure/table/optable/make_climbable() - AddComponent(/datum/component/climb_walkable) + AddComponent(/datum/component/climb_walkable) // VOIDCREW EDIT: movable fixtures integration: make operating tables climbable (voidcrew/edits/objects/structures/movable_fixtures.dm) AddElement(/datum/element/elevation, pixel_shift = 12) ///Align the mob with the table when buckled. diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index b294a390066..282d4710fb6 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -256,7 +256,7 @@ playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) to_chat(user, span_notice("You successfully disassemble [src].")) // VOIDCREW: this tool path deletes directly, bypassing deconstruct(TRUE). - record_ship_fixture_damage(src, disassembled = TRUE) + record_ship_fixture_damage(src, disassembled = TRUE) // VOIDCREW EDIT: ship_repairs: distinguish damaged fixtures from deliberate dismantling qdel(src) return ITEM_INTERACT_SUCCESS diff --git a/code/game/shuttle_engines.dm b/code/game/shuttle_engines.dm index d5d5a6fe2a4..df3c8d5ba3e 100644 --- a/code/game/shuttle_engines.dm +++ b/code/game/shuttle_engines.dm @@ -6,7 +6,7 @@ /// Reference mass for fuel consumption scaling. Ships at this mass use base fuel amounts. /// Ships heavier than this use proportionally more fuel per burn. -#define REFERENCE_SHIP_MASS 100 +#define REFERENCE_SHIP_MASS 100 // VOIDCREW EDIT: shuttle: retain the reference ship mass used by fuel consumption scaling /obj/machinery/power/shuttle_engine name = "engine" @@ -41,7 +41,7 @@ // 30% armour = 21) needs ~24 swings per engine, where the same axe disables a laser // turret in 5. Bullet/laser stay at 10 so ship guns remain the fast way to kill engines. /datum/armor/power_shuttle_engine - melee = 30 + melee = 30 // VOIDCREW EDIT: shuttle: retain the reference ship mass used by fuel consumption scaling bullet = 10 laser = 10 fire = 50 diff --git a/code/game/sound/sound.dm b/code/game/sound/sound.dm index 167ecb828c0..60452addb21 100644 --- a/code/game/sound/sound.dm +++ b/code/game/sound/sound.dm @@ -69,7 +69,7 @@ if(get_dist(listening_ghost, turf_source) <= audible_distance) listeners += listening_ghost - // VOIDCREW EDIT ADDITION: packed-level containment. + // VOIDCREW EDIT ADDITION START: packed-level containment. - overmap: contain observers and effects within their packed encounter // ignore_walls defaults to TRUE, so the default sound path in the whole game is // get_hearers_in_range() - the one hearer helper with no opacity filter and no LOS // raycast. At vol 100 that reaches 14 tiles, and two tenants of a packed z-level are @@ -149,7 +149,7 @@ //Atmosphere affects sound var/pressure_factor = 1 var/datum/gas_mixture/hearer_env = turf_loc.return_air_readonly() // VOIDCREW EDIT: read only; must not materialize a planetary turf's air - var/datum/gas_mixture/source_env = turf_source.return_air_readonly() + var/datum/gas_mixture/source_env = turf_source.return_air_readonly() // VOIDCREW EDIT: planetary shared air: observations must not materialize planetary gas (voidcrew/edits/planetary_shared_air.dm) if(hearer_env && source_env) var/pressure = min(hearer_env.return_pressure(), source_env.return_pressure()) diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index fb9e66dbffd..4fdf8fb32de 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -56,7 +56,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( if(null) return if(/turf/baseturf_bottom) - // VOIDCREW EDIT: kept in lockstep with the copy in voidcrew/edits/turf.dm, which + // VOIDCREW EDIT START: kept in lockstep with the copy in voidcrew/edits/turf.dm, which - planetary shared air: materialize a private mixture before writes (voidcrew/edits/planetary_shared_air.dm) // is the body that actually runs (it is the outermost link of the duplicate- // definition chain and never calls ..()). The map FOOTPRINT under the turf is // asked before the z-level: a level holds up to four planets of different biomes @@ -166,7 +166,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( if(SSlighting.initialized) // Space tiles should never have lighting objects if(!space_lit) - // VOIDCREW EDIT: kept in lockstep with the copy in voidcrew/edits/turf.dm, which is + // VOIDCREW EDIT START: kept in lockstep with the copy in voidcrew/edits/turf.dm, which is - planetary shared air: materialize a private mixture before writes (voidcrew/edits/planetary_shared_air.dm) // the body that actually runs (it is the outermost link of the duplicate-definition // chain and never calls ..()). Two rules composed here: // 1. The AREA gate that SSlighting.create_all_lighting_objects() and @@ -234,7 +234,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( for(var/turf/open/space/space_tile in RANGE_TURFS(1, src)) space_tile.enable_starlight() - // VOIDCREW EDIT: ambient bleed, the same three cases the starlight branches above + // VOIDCREW EDIT START: ambient bleed, the same three cases the starlight branches above - planetary shared air: materialize a private mixture before writes (voidcrew/edits/planetary_shared_air.dm) // handle, generalised from "space turf" to "turf in an area that lights it wholesale". // Our own capability can have flipped (we became or stopped being a cordon or a space // tile), and we can have started or stopped being something for the base-lit ground @@ -279,8 +279,10 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( // VOIDCREW EDIT: a new planetary turf that came up on the very same shared mix we had // already holds this air; anything else takes a private mixture before the write. if(new_turf.air != old_air) + // VOIDCREW EDIT START - planetary shared air: materialize a private mixture before writes (voidcrew/edits/planetary_shared_air.dm) var/datum/gas_mixture/new_air = new_turf.materialize_planet_air() new_air.copy_from(stashed_air) + // VOIDCREW EDIT END new_turf.excited = stashed_state new_turf.excited_group = stashed_group #ifdef VISUALIZE_ACTIVE_TURFS @@ -315,11 +317,14 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( // survives - which is how dismantling a wall dumps a full tile of breathable air into // whatever the wall was sealing. Build the adjacency now and throw the invented gas away, // so we take a share of what our neighbours actually have instead. + // VOIDCREW EDIT START - planetary atmos integration: assimilate surrounding gas after opening a closed turf (voidcrew/edits/planetary_shared_air.dm) var/sheered_from_closed = ispath(oldType, /turf/closed) && !blocks_air && !planetary_atmos && !(flags & CHANGETURF_IGNORE_AIR) if(sheered_from_closed) flags |= CHANGETURF_RECALC_ADJACENT ..(flags, oldType) + // VOIDCREW EDIT END RemoveLattice() + // VOIDCREW EDIT START - planetary atmos integration: assimilate surrounding gas after opening a closed turf (voidcrew/edits/planetary_shared_air.dm) if(sheered_from_closed) // Temperature is deliberately left alone. An emptied turf mix still carries // HEAT_CAPACITY_VACUUM into Assimilate_Air's average, and TCMB there would @@ -328,6 +333,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( else if(flags & (CHANGETURF_IGNORE_AIR | CHANGETURF_INHERIT_AIR)) return Assimilate_Air() + // VOIDCREW EDIT END //////Assimilate Air////// /turf/open/proc/Assimilate_Air() @@ -336,9 +342,9 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( return //Stolen blatently from self_breakdown - var/list/turf_list = atmos_adjacent_turfs + src + var/list/turf_list = atmos_adjacent_turfs + src // VOIDCREW EDIT: planetary shared air: materialize a private mixture before writes (voidcrew/edits/planetary_shared_air.dm) - // VOIDCREW EDIT: turfs still on the shared planetary mix. When every turf here is on the + // VOIDCREW EDIT START: turfs still on the shared planetary mix. When every turf here is on the - planetary shared air: materialize a private mixture before writes (voidcrew/edits/planetary_shared_air.dm) // SAME shared mix the average is that mix and there is nothing to write; otherwise each // of them needs a private mixture before the copy_from() below. if(has_shared_planet_air()) @@ -355,6 +361,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( var/datum/gas_mixture/total = new//Holders to assimilate air from nearby turfs var/list/total_gases = total.gases + // VOIDCREW EDIT REMOVAL - planetary shared air: materialize a private mixture before writes (voidcrew/edits/planetary_shared_air.dm) var/turflen = turf_list.len var/energy = 0 var/heat_cap = 0 diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm index 7497fa5d0ac..402a4b917ec 100644 --- a/code/game/turfs/closed/minerals.dm +++ b/code/game/turfs/closed/minerals.dm @@ -66,6 +66,7 @@ return var/obj/item/held_item = bumping.get_active_held_item() + // VOIDCREW EDIT START - Voidcrew mining integration: use and monitor a held mining tool without changing the active hand (voidcrew/edits) var/obj/item/mining_tool = held_item // Prefer the selected tool, then a mining tool held in another hand. Do not // switch hands or send a click with the active item, which might be a weapon. @@ -74,7 +75,9 @@ if(mining_tool) attackby(mining_tool, bumping) else if(!held_item) // Preserve empty-hand bump digging for snow and mining arms. + // VOIDCREW EDIT END INVOKE_ASYNC(bumping, TYPE_PROC_REF(/mob, ClickOn), src) +// VOIDCREW EDIT REMOVAL - Voidcrew mining integration: use and monitor a held mining tool without changing the active hand (voidcrew/edits) /turf/closed/mineral/proc/Spread_Vein() var/spreadChance = initial(mineralType.spreadChance) @@ -184,10 +187,12 @@ // do_after already watches the active hand. An off-hand tool needs its own // check so dropping or stowing it also interrupts mining. + // VOIDCREW EDIT START - Voidcrew mining integration: use and monitor a held mining tool without changing the active hand (voidcrew/edits) var/datum/callback/held_tool_check if(I != user.get_active_held_item() && user.is_holding(I)) held_tool_check = CALLBACK(user, TYPE_PROC_REF(/mob, is_holding), I) if(!I.use_tool(src, user, tool_mine_speed, volume=50, extra_checks=held_tool_check)) + // VOIDCREW EDIT END TIMER_COOLDOWN_END(src, REF(user)) //if we fail we can start again immediately return if(ismineralturf(src)) @@ -441,8 +446,10 @@ // VOIDCREW EDIT: mined walls must yield the FROZEN breathable floor, the upstream icemoon // turfs are planetary ICEMOON, and every dug tile on a FROZEN planet churns atmos forever turf_type = /turf/open/misc/asteroid/snow/icemoon/breathable + // VOIDCREW EDIT START - overmap planets: mined snow walls retain the breathable frozen atmosphere baseturfs = /turf/open/misc/asteroid/snow/icemoon/breathable initial_gas_mix = FROZEN_ATMOS + // VOIDCREW EDIT END weak_turf = TRUE proximity_based = TRUE @@ -538,8 +545,10 @@ canSmoothWith = SMOOTH_GROUP_CLOSED_TURFS defer_change = TRUE turf_type = /turf/open/misc/asteroid/snow/icemoon/breathable // VOIDCREW EDIT (see random/snow) + // VOIDCREW EDIT START - overmap planets: mined snow walls retain the breathable frozen atmosphere baseturfs = /turf/open/misc/asteroid/snow/icemoon/breathable initial_gas_mix = FROZEN_ATMOS + // VOIDCREW EDIT END defer_change = TRUE /turf/closed/mineral/random/labormineral/ice/mineral_chances() @@ -727,14 +736,16 @@ /turf/closed/mineral/snowmountain/icemoon // VOIDCREW EDIT: dig into FROZEN breathable floor, not planetary-ICEMOON (churns vs FROZEN planets) turf_type = /turf/open/misc/asteroid/snow/icemoon/breathable + // VOIDCREW EDIT START - overmap planets: mined snow walls retain the breathable frozen atmosphere baseturfs = /turf/open/misc/asteroid/snow/icemoon/breathable initial_gas_mix = FROZEN_ATMOS + // VOIDCREW EDIT END /// This snowy mountain will never be scraped away for any reason what so ever. /turf/closed/mineral/snowmountain/icemoon/unscrapeable turf_flags = IS_SOLID | NO_CLEARING turf_type = /turf/open/misc/asteroid/snow/icemoon/breathable // VOIDCREW EDIT (see parent) - baseturfs = /turf/open/misc/asteroid/snow/icemoon/breathable + baseturfs = /turf/open/misc/asteroid/snow/icemoon/breathable // VOIDCREW EDIT: overmap planets: mined snow walls retain the breathable frozen atmosphere /turf/closed/mineral/snowmountain/cavern name = "ice cavern rock" @@ -748,8 +759,10 @@ /turf/closed/mineral/snowmountain/cavern/icemoon // VOIDCREW EDIT: snow/ice/icemoon is planetary ICEMOON, dig into FROZEN breathable instead baseturfs = /turf/open/misc/asteroid/snow/icemoon/breathable + // VOIDCREW EDIT START - overmap planets: mined snow walls retain the breathable frozen atmosphere turf_type = /turf/open/misc/asteroid/snow/icemoon/breathable initial_gas_mix = FROZEN_ATMOS + // VOIDCREW EDIT END //For when you want genuine, real snowy mountainside in your kitchen's cold room. /turf/closed/mineral/snowmountain/coldroom @@ -908,8 +921,10 @@ /turf/closed/mineral/gibtonite/ice/icemoon // VOIDCREW EDIT: snow/ice/icemoon is planetary ICEMOON, dig into FROZEN breathable instead turf_type = /turf/open/misc/asteroid/snow/icemoon/breathable + // VOIDCREW EDIT START - overmap planets: mined snow walls retain the breathable frozen atmosphere baseturfs = /turf/open/misc/asteroid/snow/icemoon/breathable initial_gas_mix = FROZEN_ATMOS + // VOIDCREW EDIT END /turf/closed/mineral/strong name = "Very strong rock" diff --git a/code/game/turfs/closed/wall/misc_walls.dm b/code/game/turfs/closed/wall/misc_walls.dm index ef9c04f5a49..7cf2ecf2e2e 100644 --- a/code/game/turfs/closed/wall/misc_walls.dm +++ b/code/game/turfs/closed/wall/misc_walls.dm @@ -62,7 +62,7 @@ //SDMM supports colors, this is simply for easier mapping //and should be removed on initialize color = MAP_SWITCH(null, COLOR_ORANGE_BROWN) - base_decon_state = "rusty_wall" + base_decon_state = "rusty_wall" // VOIDCREW EDIT: Voidcrew wall integration: use the rusty wall deconstruction icon state (voidcrew/edits) /turf/closed/wall/r_wall/rust/Initialize(mapload) . = ..() diff --git a/code/game/turfs/closed/wall/reinf_walls.dm b/code/game/turfs/closed/wall/reinf_walls.dm index a7092236418..a844f92deca 100644 --- a/code/game/turfs/closed/wall/reinf_walls.dm +++ b/code/game/turfs/closed/wall/reinf_walls.dm @@ -172,7 +172,7 @@ if(!istype(src, /turf/closed/wall/r_wall) || d_state != SHEATH) return TRUE to_chat(user, span_notice("You pry off the outer sheath.")) - dismantle_wall(disassembled = TRUE) + dismantle_wall(disassembled = TRUE) // VOIDCREW EDIT: ship_repairs: distinguish damaged fixtures from deliberate dismantling return TRUE if(W.tool_behaviour == TOOL_WELDER) diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index 4b1904bebb2..8a614f06cc3 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -38,7 +38,7 @@ . = ..() if(!can_engrave) ADD_TRAIT(src, TRAIT_NOT_ENGRAVABLE, INNATE_TRAIT) - // VOIDCREW EDIT CHANGE: never register ALLOCATOR-DEALT ground - original was + // VOIDCREW EDIT CHANGE START: never register ALLOCATOR-DEALT ground - original was - overmap: contain observers and effects within their packed encounter // `if(is_station_level(z))`. is_station_level() means "any z with a hull on it" in this // fork, so a ruin stamped onto a packed level while a neighbour has a ship docked put // every wall it owns into GLOB.station_turfs; the removal below is skipped because the @@ -76,7 +76,7 @@ dismantle_wall(TRUE, FALSE) /turf/closed/wall/Destroy() - // VOIDCREW EDIT CHANGE: symmetric with the guard in Initialize() - original was + // VOIDCREW EDIT CHANGE START: symmetric with the guard in Initialize() - original was - overmap: contain observers and effects within their packed encounter // `if(is_station_level(z))`, which is a DIFFERENT condition by the time a turf dies // (the level's station flag is refcounted off the hulls standing on it, and teardown // runs after the last one has left), so the entry survived its own turf. @@ -97,6 +97,7 @@ /turf/closed/wall/attack_tk() return +// VOIDCREW EDIT START - ship_repairs: deliberate remodeling supersedes pending repairs /turf/closed/wall/proc/dismantle_wall(devastated = FALSE, explode = FALSE, disassembled = FALSE) // VOIDCREW: successful hand demolition supersedes repairs, including during flight. var/obj/machinery/computer/camera_advanced/base_construction/ship/repair_controller @@ -106,6 +107,7 @@ if(repair_controller) repair_controller.forget_repair_record(repair_controller.repair_coordinate_key(src)) repair_controller.repair_applying = TRUE +// VOIDCREW EDIT END if(devastated) devastate_wall() else @@ -123,8 +125,10 @@ else ScrapeAway() QUEUE_SMOOTH_NEIGHBORS(src) + // VOIDCREW EDIT START - ship_repairs: deliberate remodeling supersedes pending repairs if(repair_controller) repair_controller.repair_applying = was_repairing + // VOIDCREW EDIT END /turf/closed/wall/proc/break_wall() new sheet_type(src, sheet_amount) @@ -271,7 +275,7 @@ if(I.use_tool(src, user, slicing_duration, volume=100)) if(iswallturf(src)) to_chat(user, span_notice("You remove the outer plating.")) - dismantle_wall(disassembled = TRUE) + dismantle_wall(disassembled = TRUE) // VOIDCREW EDIT: ship_repairs: deliberate remodeling supersedes pending repairs return TRUE return FALSE diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index f0276ccc5bd..5fa90a341a0 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -339,7 +339,7 @@ /turf/open/TakeTemperature(temp) var/datum/gas_mixture/our_air = materialize_planet_air() // VOIDCREW EDIT: shared planetary mix - our_air.temperature += temp + our_air.temperature += temp // VOIDCREW EDIT: planetary shared air: materialize a private mixture before writes (voidcrew/edits/planetary_shared_air.dm) air_update_turf(FALSE, FALSE) /turf/open/proc/freeze_turf() diff --git a/code/game/turfs/open/floor.dm b/code/game/turfs/open/floor.dm index 6ddd7ac4c06..7e21e8cbbbb 100644 --- a/code/game/turfs/open/floor.dm +++ b/code/game/turfs/open/floor.dm @@ -31,7 +31,7 @@ if(mapload && prob(33)) MakeDirty() - // VOIDCREW EDIT CHANGE: never register ALLOCATOR-DEALT ground - original was + // VOIDCREW EDIT CHANGE START: never register ALLOCATOR-DEALT ground - original was - overmap: contain observers and effects within their packed encounter // `if(is_station_level(z))`. See the matching comment on /turf/closed/wall/Initialize(). if(is_station_level(z) && !map_region_for_turf(src)) GLOB.station_turfs += src @@ -44,7 +44,7 @@ return list() /turf/open/floor/Destroy() - // VOIDCREW EDIT CHANGE: symmetric with the guard in Initialize() - original was + // VOIDCREW EDIT CHANGE START: symmetric with the guard in Initialize() - original was - overmap: contain observers and effects within their packed encounter // `if(is_station_level(z))`. See /turf/closed/wall/Destroy(). if(length(GLOB.station_turfs) && !map_region_for_turf(src)) GLOB.station_turfs -= src @@ -122,7 +122,7 @@ if(!ispath(path, /turf/open/floor)) return ..() var/old_dir = dir - // VOIDCREW EDIT ADDITION: when the map loader is the caller it has already queued the + // VOIDCREW EDIT ADDITION START: when the map loader is the caller it has already queued the - ship_upgrades: retain mapped floor directions when loading modules onto hull plating // mapped vars - dir included - for /atom/New() to apply to the turf ..() creates. // Restoring old_dir below would then stomp that with whatever floor sat here before. // Ship upgrade modules load onto hull plating, every tile of which faces SOUTH, so @@ -171,6 +171,7 @@ /turf/open/floor/proc/remove_tile(mob/user, silent = FALSE, make_tile = TRUE, force_plating) // VOIDCREW: taking up tiles with a tool is deliberate remodeling. + // VOIDCREW EDIT START - ship_repairs: deliberate remodeling supersedes pending repairs var/obj/machinery/computer/camera_advanced/base_construction/ship/repair_controller if(user) repair_controller = SSship_repairs.area_controllers[get_area(src)] @@ -178,6 +179,7 @@ if(repair_controller) repair_controller.forget_repair_record(repair_controller.repair_coordinate_key(src)) repair_controller.repair_applying = TRUE + // VOIDCREW EDIT END if(broken || burnt) broken = FALSE burnt = FALSE @@ -188,9 +190,11 @@ to_chat(user, span_notice("You remove the floor tile.")) if(make_tile) spawn_tile() + // VOIDCREW EDIT START - ship_repairs: deliberate remodeling supersedes pending repairs . = make_plating(force_plating) if(repair_controller) repair_controller.repair_applying = was_repairing + // VOIDCREW EDIT END /turf/open/floor/proc/has_tile() return floor_tile @@ -310,11 +314,13 @@ if(!initial(window_path.fulltile)) //not user.dir: a remotely driven RCD builds where its drone is looking, not //where the body credited with the build happens to be pointing + // VOIDCREW EDIT START - shuttle construction: directional builds follow the remote drone (voidcrew/edits/objects/items/construction_hooks.dm) var/build_dir = the_rcd.rcd_build_dir(user) if(!valid_build_direction(src, build_dir, is_fulltile = FALSE)) + // VOIDCREW EDIT END balloon_alert(user, "window already here!") return FALSE - var/obj/structure/window/WD = new window_path(src, build_dir) + var/obj/structure/window/WD = new window_path(src, build_dir) // VOIDCREW EDIT: shuttle construction: directional builds follow the remote drone (voidcrew/edits/objects/items/construction_hooks.dm) WD.set_anchored(TRUE) return TRUE @@ -329,8 +335,10 @@ if(ispath(airlock_type, /obj/machinery/door/window)) //see the window branch above - the drone's facing, not the operator's + // VOIDCREW EDIT START - shuttle construction: directional builds follow the remote drone (voidcrew/edits/objects/items/construction_hooks.dm) var/build_dir = the_rcd.rcd_build_dir(user) if(!valid_build_direction(src, build_dir, is_fulltile = FALSE)) + // VOIDCREW EDIT END balloon_alert(user, "there's already a windoor!") return FALSE for(var/obj/machinery/door/door in src) @@ -339,7 +347,7 @@ balloon_alert(user, "there's already a door!") return FALSE //create the assembly and let it finish itself - var/obj/structure/windoor_assembly/assembly = new (src, build_dir) + var/obj/structure/windoor_assembly/assembly = new (src, build_dir) // VOIDCREW EDIT: shuttle construction: directional builds follow the remote drone (voidcrew/edits/objects/items/construction_hooks.dm) assembly.secure = ispath(airlock_type, /obj/machinery/door/window/brigdoor) assembly.electronics = the_rcd.airlock_electronics.create_copy(assembly) assembly.finish_door() @@ -383,7 +391,7 @@ ) if(is_path_in_list(locate_type, dir_types)) //see the window branch above - the drone's facing, not the operator's - design.setDir(the_rcd.rcd_build_dir(user)) + design.setDir(the_rcd.rcd_build_dir(user)) // VOIDCREW EDIT: shuttle construction: directional builds follow the remote drone (voidcrew/edits/objects/items/construction_hooks.dm) return TRUE if(RCD_DECONSTRUCT) if(rcd_proof) diff --git a/code/game/turfs/open/floor/fancy_floor.dm b/code/game/turfs/open/floor/fancy_floor.dm index ca9f02b9cb9..d20b15187eb 100644 --- a/code/game/turfs/open/floor/fancy_floor.dm +++ b/code/game/turfs/open/floor/fancy_floor.dm @@ -512,7 +512,7 @@ // A FLOAT_LAYER decal would inherit that layer while sitting on the emissive plane, where it would draw above // every emissive blocker in the world and glow straight through mobs, items and walls. // emissive_appearance() remaps floor plane layers into the FLOOR_EMISSIVE band for this exact reason. - AddElement(/datum/element/decal, neon_icon || icon, neon_icon_state || base_icon_state, dir, EMISSIVE_PLANE, FLOOR_EMISSIVE_START_LAYER, emissive_alpha, GLOB.emissive_color, smoothing_junction) + AddElement(/datum/element/decal, neon_icon || icon, neon_icon_state || base_icon_state, dir, EMISSIVE_PLANE, FLOOR_EMISSIVE_START_LAYER, emissive_alpha, GLOB.emissive_color, smoothing_junction) // VOIDCREW EDIT: ship_upgrades lighting: floor emissives stay below blockers (voidcrew/edits/lighting.dm) /turf/open/floor/carpet/neon/simple name = "simple neon carpet" diff --git a/code/game/turfs/open/grass.dm b/code/game/turfs/open/grass.dm index 47917da17a9..cb8f73109bb 100644 --- a/code/game/turfs/open/grass.dm +++ b/code/game/turfs/open/grass.dm @@ -45,7 +45,7 @@ transform = translation icon = smooth_icon - // VOIDCREW EDIT CHANGE: never register ALLOCATOR-DEALT ground - original was + // VOIDCREW EDIT CHANGE START: never register ALLOCATOR-DEALT ground - original was - overmap: contain observers and effects within their packed encounter // `if(is_station_level(z))`. See the matching comment on /turf/closed/wall/Initialize(). // Grass is the worst offender of the three: it is planet ground, it is dealt out and // recycled on every planet build, and it had no Destroy() removal at all. @@ -53,14 +53,7 @@ GLOB.station_turfs += src // VOIDCREW EDIT END -// VOIDCREW EDIT ADDITION: /turf/open/misc/grass registers itself above but is a -// /turf/open/misc, so /turf/open/floor/Destroy()'s removal never applied to it and the -// registration was one-way even on a clean ChangeTurf. -/turf/open/misc/grass/Destroy() - if(length(GLOB.station_turfs) && !map_region_for_turf(src)) - GLOB.station_turfs -= src - return ..() -// VOIDCREW EDIT END + /turf/open/misc/grass/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) . = ..() diff --git a/code/game/turfs/open/river.dm b/code/game/turfs/open/river.dm index d50d7571342..3e4ac281ede 100644 --- a/code/game/turfs/open/river.dm +++ b/code/game/turfs/open/river.dm @@ -33,7 +33,7 @@ // /turf/proc/release_light_for_raw_swap() and voidcrew/mapping/rivers.dm, which fixed // the voidcrew copy of this generator for exactly this reason. if(SSlighting.initialized) - cur_turf.release_light_for_raw_swap() + cur_turf.release_light_for_raw_swap() // VOIDCREW EDIT: overmap river generation: release lighting before mid-round raw turf swaps (voidcrew/mapping/rivers.dm) cur_turf = new turf_type(cur_turf) var/turf/target_turf = get_turf(pick(river_nodes - waypoints)) if(!target_turf) @@ -66,7 +66,7 @@ // Workaround around ChangeTurf that's safe because of when this proc is called // VOIDCREW EDIT: see the identical guard above. if(SSlighting.initialized) - cur_turf.release_light_for_raw_swap() + cur_turf.release_light_for_raw_swap() // VOIDCREW EDIT: overmap river generation: release lighting before mid-round raw turf swaps (voidcrew/mapping/rivers.dm) var/turf/river_turf = new turf_type(cur_turf) river_turf.Spread(25, 11, whitelist_area) diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm index 95dba19dce7..40a6aabba10 100644 --- a/code/game/turfs/open/space/space.dm +++ b/code/game/turfs/open/space/space.dm @@ -22,7 +22,7 @@ GLOBAL_VAR_INIT(starlight_power, default_starlight_power()) GLOB.base_starlight_color = star_color set_starlight(star_color, range, power) -/proc/set_starlight(star_color = null, range = null, power = null, list/restrict_z = null) +/proc/set_starlight(star_color = null, range = null, power = null, list/restrict_z = null) // VOIDCREW EDIT: overmap lighting: limit per-turf starlight sweeps to selected levels (voidcrew/edits/lighting.dm) if(isnull(star_color)) star_color = GLOB.starlight_color var/old_star_color = GLOB.starlight_color @@ -33,8 +33,10 @@ GLOBAL_VAR_INIT(starlight_power, default_starlight_power()) // overlay objects and the signal below always update, so unswept z-levels // light correctly the next time anything relights them. for(var/turf/open/space/spess as anything in GLOB.starlight) + // VOIDCREW EDIT START - overmap lighting: limit per-turf starlight sweeps to selected levels (voidcrew/edits/lighting.dm) if(restrict_z && !(spess.z in restrict_z)) continue + // VOIDCREW EDIT END spess.set_light(l_range = range, l_power = power, l_color = star_color) if(star_color == old_star_color) @@ -139,6 +141,7 @@ GLOBAL_LIST_EMPTY(starlight) return attack_hand(user, modifiers) /turf/open/space/proc/CanBuildHere() + // VOIDCREW EDIT REMOVAL - shuttle construction: allow building on transition space aboard ships return TRUE /turf/open/space/handle_slip() diff --git a/code/game/turfs/open/space/transit.dm b/code/game/turfs/open/space/transit.dm index 168a45db79c..5c75e27d539 100644 --- a/code/game/turfs/open/space/transit.dm +++ b/code/game/turfs/open/space/transit.dm @@ -37,8 +37,10 @@ SIGNAL_HANDLER // The async initialization callback can outlive the move or turf replacement. + // VOIDCREW EDIT START - hyperspace integration: honor movement exemptions and reject stale asynchronous entries (voidcrew/edits/hyperspace_overboard.dm) if(QDELETED(enterer) || enterer.loc != src || !istype(src, /turf/open/space/transit)) return + // VOIDCREW EDIT END // VOIDCREW EDIT ADDITION START - the hull grace zone. Close in against a ship, hyperspace // does not take hold. The tiles are still vacuum and you still get around by pushing off @@ -69,7 +71,7 @@ var/turf/location = gone.loc // VOIDCREW: crossing into a normal-space breach respects the same exemption as the soft cordon. - if(istype(location, /turf/open/space) && !istype(location, src.type) && !HAS_TRAIT(gone, TRAIT_FREE_HYPERSPACE_SOFTCORDON_MOVEMENT)) + if(istype(location, /turf/open/space) && !istype(location, src.type) && !HAS_TRAIT(gone, TRAIT_FREE_HYPERSPACE_SOFTCORDON_MOVEMENT)) // VOIDCREW EDIT: hyperspace integration: honor movement exemptions and reject stale asynchronous entries (voidcrew/edits/hyperspace_overboard.dm) dump_in_space(gone) //launch them into game space, away from transitspace ///Get rid of all our contents, called when our reservation is released (which in our case means the shuttle arrived) diff --git a/code/modules/antagonists/abductor/equipment/glands/heal.dm b/code/modules/antagonists/abductor/equipment/glands/heal.dm index bac4f38ce28..eedbb173d38 100644 --- a/code/modules/antagonists/abductor/equipment/glands/heal.dm +++ b/code/modules/antagonists/abductor/equipment/glands/heal.dm @@ -9,18 +9,7 @@ icon_state = "health" mind_control_uses = 3 mind_control_duration = 3000 - // VOIDCREW ADD: delayed healing belongs to one continuous implantation. - var/healing_generation = 0 -// VOIDCREW ADD START -/obj/item/organ/heart/gland/heal/on_mob_remove(mob/living/carbon/gland_owner, special, movement_flags) - healing_generation++ - return ..() - -/// Removal invalidates pending work even if this gland returns to the same body. -/obj/item/organ/heart/gland/heal/proc/can_finish_healing(mob/living/carbon/recipient, generation) - return !QDELETED(src) && !QDELETED(recipient) && owner == recipient && active && generation == healing_generation && ownerCheck() -// VOIDCREW ADD END /obj/item/organ/heart/gland/heal/activate() if(!(owner.mob_biotypes & MOB_ORGANIC)) @@ -163,9 +152,9 @@ new_stomach.Insert(owner) /obj/item/organ/heart/gland/heal/proc/replace_eyes(obj/item/organ/eyes/eyes) - // VOIDCREW ADD: capture the recipient before organ-removal callbacks can change it. + // VOIDCREW EDIT ADDITION: capture the recipient before organ-removal callbacks can change it. var/mob/living/carbon/recipient = owner - var/generation = healing_generation + var/generation = healing_generation // VOIDCREW EDIT: healing gland integration: pending regrowth belongs to one continuous implantation (voidcrew/edits/mobs/healing_gland.dm) if(eyes) owner.visible_message(span_warning("[owner]'s [eyes.name] fall out of their sockets!"), span_userdanger("Your [eyes.name] fall out of their sockets!")) playsound(owner, 'sound/effects/splat.ogg', 50, TRUE) @@ -177,10 +166,10 @@ addtimer(CALLBACK(src, PROC_REF(finish_replace_eyes), recipient, generation), rand(10 SECONDS, 20 SECONDS)) // VOIDCREW EDIT /obj/item/organ/heart/gland/heal/proc/finish_replace_eyes(mob/living/carbon/recipient, generation) // VOIDCREW EDIT - // VOIDCREW ADD START + // VOIDCREW EDIT ADDITION START if(!can_finish_healing(recipient, generation)) return - // VOIDCREW ADD END + // VOIDCREW EDIT ADDITION END var/eye_type = /obj/item/organ/eyes if(recipient.dna.species && recipient.dna.species.mutanteyes) // VOIDCREW EDIT eye_type = recipient.dna.species.mutanteyes // VOIDCREW EDIT @@ -189,9 +178,9 @@ recipient.visible_message(span_warning("A pair of new eyes suddenly inflates into [recipient]'s eye sockets!"), span_userdanger("A pair of new eyes suddenly inflates into your eye sockets!")) // VOIDCREW EDIT /obj/item/organ/heart/gland/heal/proc/replace_limb(body_zone, obj/item/bodypart/limb) - // VOIDCREW ADD: limb-removal callbacks must not redirect the pending regrowth. + // VOIDCREW EDIT ADDITION: limb-removal callbacks must not redirect the pending regrowth. var/mob/living/carbon/recipient = owner - var/generation = healing_generation + var/generation = healing_generation // VOIDCREW EDIT: healing gland integration: pending regrowth belongs to one continuous implantation (voidcrew/edits/mobs/healing_gland.dm) if(limb) owner.visible_message(span_warning("[owner]'s [limb.plaintext_zone] suddenly detaches from [owner.p_their()] body!"), span_userdanger("Your [limb.plaintext_zone] suddenly detaches from your body!")) playsound(owner, SFX_DESECRATION, 50, TRUE, -1) @@ -202,10 +191,10 @@ addtimer(CALLBACK(src, PROC_REF(finish_replace_limb), body_zone, recipient, generation), rand(15 SECONDS, 30 SECONDS)) // VOIDCREW EDIT /obj/item/organ/heart/gland/heal/proc/finish_replace_limb(body_zone, mob/living/carbon/recipient, generation) // VOIDCREW EDIT - // VOIDCREW ADD START + // VOIDCREW EDIT ADDITION START if(!can_finish_healing(recipient, generation)) return - // VOIDCREW ADD END + // VOIDCREW EDIT ADDITION END recipient.visible_message(span_warning("With a loud snap, [recipient]'s [parse_zone(body_zone)] rapidly grows back from [recipient.p_their()] body!"), // VOIDCREW EDIT span_userdanger("With a loud snap, your [parse_zone(body_zone)] rapidly grows back from your body!"), span_warning("Your hear a loud snap.")) @@ -217,10 +206,10 @@ keep_replacing_blood(owner, healing_generation) // VOIDCREW EDIT /obj/item/organ/heart/gland/heal/proc/keep_replacing_blood(mob/living/carbon/recipient, generation) // VOIDCREW EDIT - // VOIDCREW ADD START + // VOIDCREW EDIT ADDITION START if(!can_finish_healing(recipient, generation)) return - // VOIDCREW ADD END + // VOIDCREW EDIT ADDITION END var/keep_going = FALSE // VOIDCREW EDIT START recipient.vomit(vomit_flags = (MOB_VOMIT_BLOOD | MOB_VOMIT_FORCE), lost_nutrition = 0, distance = 3) diff --git a/code/modules/antagonists/heretic/magic/rust_construction.dm b/code/modules/antagonists/heretic/magic/rust_construction.dm index 0a9acbd22b3..145226f4bf8 100644 --- a/code/modules/antagonists/heretic/magic/rust_construction.dm +++ b/code/modules/antagonists/heretic/magic/rust_construction.dm @@ -80,7 +80,7 @@ // but I guess a fading filter will have to do for now as walls have 0 depth (currently) // damn though with 3/4ths walls this'll look sick just imagine it new_wall.add_filter("rust_wall", 2, list("type" = "outline", "color" = "#85be299c", "size" = 2)) - // VOIDCREW EDIT: The constructed wall outlives the action. Capture this cast's + // VOIDCREW EDIT START: The constructed wall outlives the action. Capture this cast's - Voidcrew rust spell integration: expire only the filter owned by this cast (voidcrew/edits/spells) // parameter list, which survives unrelated filter rebuilds but not replacement. var/list/owned_filter = new_wall.filter_data["rust_wall"] addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fade_rust_wall_filter), new_wall, owned_filter, filter_duration * (9/20)), filter_duration * 0.5) @@ -123,20 +123,4 @@ if(!message_shown) new_wall.visible_message(span_warning("\A [new_wall] [rises_message]!")) -// VOIDCREW EDIT: Independent cosmetic expiry must not affect a later cast on this turf. -/proc/fade_rust_wall_filter(turf/closed/wall, list/owned_filter, fade_duration) - if(QDELETED(wall) || LAZYACCESS(wall.filter_data, "rust_wall") != owned_filter) - return - - var/rust_filter = wall.get_filter("rust_wall") - if(!rust_filter) - return - - animate(rust_filter, alpha = 0, time = fade_duration) - -/proc/remove_rust_wall_filter(turf/closed/wall, list/owned_filter) - if(QDELETED(wall) || LAZYACCESS(wall.filter_data, "rust_wall") != owned_filter) - return - - wall.remove_filter("rust_wall") -// END VOIDCREW EDIT +// VOIDCREW EDIT REMOVAL - rust spell: cosmetic expiry runs independently of the action (voidcrew/edits/spells/rust_filters.dm). diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 20dbe7d1124..1c8f862d2b3 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -562,7 +562,7 @@ BLIND // can't see anything if(visor_vars_to_toggle & VISOR_TINT) carbon_user.update_tint() if((visor_flags & (MASKINTERNALS|HEADINTERNALS)) && carbon_user.invalid_internals()) - carbon_user.cutoff_internals("visor adjusted on [type], up=[up]") + carbon_user.cutoff_internals("visor adjusted on [type], up=[up]") // VOIDCREW EDIT: shuttle internals diagnostics: identify the disconnect call site (voidcrew/edits/mobs/internals_logging.dm) return TRUE /obj/item/clothing/proc/visor_toggling() //handles all the actual toggling of flags diff --git a/code/modules/clothing/glasses/engine_goggles.dm b/code/modules/clothing/glasses/engine_goggles.dm index 2d9733b62a8..487537dabd8 100644 --- a/code/modules/clothing/glasses/engine_goggles.dm +++ b/code/modules/clothing/glasses/engine_goggles.dm @@ -182,12 +182,14 @@ * case. A remote operator - the ship construction console's drone pilot - has to pass the * camera, or the readout appears around them at the console rather than around the drone. */ -/proc/atmos_thermal(mob/viewer, range = 5, duration = 10, atom/centre) +/proc/atmos_thermal(mob/viewer, range = 5, duration = 10, atom/centre) // VOIDCREW EDIT: shuttle construction: scan around the remote drone while retaining the handheld default if(!ismob(viewer) || !viewer.client) return + // VOIDCREW EDIT START - shuttle construction: scan around the remote drone while retaining the handheld default if(isnull(centre)) centre = viewer for(var/turf/open in view(range, centre)) + // VOIDCREW EDIT END if(open.blocks_air) continue var/datum/gas_mixture/environment = open.return_air() diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index d39466cae77..0d04922e694 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -6,9 +6,11 @@ name = "hard hat" desc = "A piece of headgear used in dangerous working conditions to protect the head. Comes with a built-in flashlight." icon_state = "hardhat0_yellow" + // VOIDCREW EDIT START - Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing inhand_icon_state = "hardhat_yellow" lefthand_file = 'voidcrew/icons/mob/inhands/clothing/hardhat_lefthand.dmi' righthand_file = 'voidcrew/icons/mob/inhands/clothing/hardhat_righthand.dmi' + // VOIDCREW EDIT END armor_type = /datum/armor/utility_hardhat flags_inv = 0 hair_mask = /datum/hair_mask/standard_hat_middle @@ -53,11 +55,13 @@ update_appearance() /obj/item/clothing/head/utility/hardhat/update_icon_state() + // VOIDCREW EDIT START - Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing icon_state = "hardhat[on]_[hat_type]" if(hat_type == "cakehat" || hat_type == "energycake") inhand_icon_state = icon_state else inhand_icon_state = "hardhat_[hat_type]" + // VOIDCREW EDIT END return ..() /obj/item/clothing/head/utility/hardhat/proc/turn_on(mob/user) @@ -77,13 +81,13 @@ /obj/item/clothing/head/utility/hardhat/orange icon_state = "hardhat0_orange" - inhand_icon_state = "hardhat_orange" + inhand_icon_state = "hardhat_orange" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing hat_type = "orange" dog_fashion = null /obj/item/clothing/head/utility/hardhat/red icon_state = "hardhat0_red" - inhand_icon_state = "hardhat_red" + inhand_icon_state = "hardhat_red" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing hat_type = "red" dog_fashion = null name = "firefighter helmet" @@ -97,7 +101,7 @@ name = "workplace-ready firefighter helmet" desc = "By applying state of the art lighting technology to a fire helmet, and using photo-chemical hardening methods, this hardhat will protect you from robust workplace hazards." icon_state = "hardhat0_purple" - inhand_icon_state = "hardhat_purple" + inhand_icon_state = "hardhat_purple" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing light_range = 5 resistance_flags = FIRE_PROOF | ACID_PROOF custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*2, /datum/material/glass =HALF_SHEET_MATERIAL_AMOUNT, /datum/material/plastic = SHEET_MATERIAL_AMOUNT*1.5, /datum/material/silver = SMALL_MATERIAL_AMOUNT*5) @@ -105,7 +109,7 @@ /obj/item/clothing/head/utility/hardhat/white icon_state = "hardhat0_white" - inhand_icon_state = "hardhat_white" + inhand_icon_state = "hardhat_white" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing hat_type = "white" clothing_flags = STOPSPRESSUREDAMAGE | STACKABLE_HELMET_EXEMPT heat_protection = HEAD @@ -116,7 +120,7 @@ /obj/item/clothing/head/utility/hardhat/dblue icon_state = "hardhat0_dblue" - inhand_icon_state = "hardhat_dblue" + inhand_icon_state = "hardhat_dblue" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing hat_type = "dblue" dog_fashion = null @@ -174,13 +178,13 @@ /obj/item/clothing/head/utility/hardhat/welding/orange icon_state = "hardhat0_orange" - inhand_icon_state = "hardhat_orange" + inhand_icon_state = "hardhat_orange" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing hat_type = "orange" /obj/item/clothing/head/utility/hardhat/welding/white desc = "A piece of headgear used in dangerous working conditions to protect the head. Comes with a built-in flashlight AND welding shield!" //This bulb is not smaller icon_state = "hardhat0_white" - inhand_icon_state = "hardhat_white" + inhand_icon_state = "hardhat_white" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing light_range = 4 //Boss always takes the best stuff hat_type = "white" clothing_flags = STOPSPRESSUREDAMAGE | STACKABLE_HELMET_EXEMPT @@ -200,12 +204,12 @@ /obj/item/clothing/head/utility/hardhat/welding/dblue icon_state = "hardhat0_dblue" - inhand_icon_state = "hardhat_dblue" + inhand_icon_state = "hardhat_dblue" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing hat_type = "dblue" /obj/item/clothing/head/utility/hardhat/welding/atmos icon_state = "hardhat0_atmos" - inhand_icon_state = "hardhat_atmos" + inhand_icon_state = "hardhat_atmos" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing hat_type = "atmos" dog_fashion = null name = "atmospheric firefighter helmet" @@ -234,7 +238,7 @@ icon = 'icons/obj/clothing/head/costume.dmi' worn_icon = 'icons/mob/clothing/head/costume.dmi' icon_state = "hardhat0_pumpkin" - inhand_icon_state = "hardhat_pumpkin" + inhand_icon_state = "hardhat_pumpkin" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing hat_type = "pumpkin" clothing_flags = SNUG_FIT | STACKABLE_HELMET_EXEMPT flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT @@ -284,7 +288,7 @@ name = "carved blumpkin" desc = "A very blue jack o' lantern! Believed to ward off vengeful chemists." icon_state = "hardhat0_blumpkin" - inhand_icon_state = "hardhat_blumpkin" + inhand_icon_state = "hardhat_blumpkin" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing hat_type = "blumpkin" light_color = "#76ff8e" dog_fashion = /datum/dog_fashion/head/blumpkin/unlit @@ -303,7 +307,7 @@ icon = 'icons/obj/clothing/head/costume.dmi' worn_icon = 'icons/mob/clothing/head/costume.dmi' icon_state = "hardhat0_reindeer" - inhand_icon_state = "hardhat_reindeer" + inhand_icon_state = "hardhat_reindeer" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing hat_type = "reindeer" flags_inv = 0 hair_mask = "" diff --git a/code/modules/clothing/head/hat.dm b/code/modules/clothing/head/hat.dm index 9cb8c861372..1e8d1acf9b2 100644 --- a/code/modules/clothing/head/hat.dm +++ b/code/modules/clothing/head/hat.dm @@ -325,9 +325,11 @@ name = "ushanka" desc = "Perfect for winter in Siberia, da?" icon_state = "ushankadown" + // VOIDCREW EDIT START - Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing inhand_icon_state = "ushanka" lefthand_file = 'voidcrew/icons/mob/inhands/clothing/ushanka_lefthand.dmi' righthand_file = 'voidcrew/icons/mob/inhands/clothing/ushanka_righthand.dmi' + // VOIDCREW EDIT END flags_inv = HIDEEARS|HIDEHAIR cold_protection = HEAD min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT @@ -341,9 +343,11 @@ /obj/item/clothing/head/costume/ushanka/attack_self(mob/user) if(earflaps) icon_state = upsprite + // VOIDCREW EDIT REMOVAL - Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing to_chat(user, span_notice("You raise the ear flaps on the ushanka.")) else icon_state = downsprite + // VOIDCREW EDIT REMOVAL - Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing to_chat(user, span_notice("You lower the ear flaps on the ushanka.")) earflaps = !earflaps @@ -351,7 +355,7 @@ name = "bear hunter's ushanka" desc = "Handcrafted in Siberia from real polar bears." icon_state = "ushankadown_polar" - inhand_icon_state = "ushanka_polar" + inhand_icon_state = "ushanka_polar" // VOIDCREW EDIT: Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing upsprite = "ushankaup_polar" downsprite = "ushankadown_polar" diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index 943d583962d..5b31b862a35 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -175,9 +175,11 @@ /obj/item/clothing/head/utility/radiation name = "radiation hood" icon_state = "rad" + // VOIDCREW EDIT START - Voidcrew clothing sprites: use dedicated inhand states from voidcrew/icons/mob/inhands/clothing inhand_icon_state = "rad" lefthand_file = 'voidcrew/icons/mob/inhands/clothing/radiation_hood_lefthand.dmi' righthand_file = 'voidcrew/icons/mob/inhands/clothing/radiation_hood_righthand.dmi' + // VOIDCREW EDIT END desc = "A hood with radiation protective properties. The label reads, 'Made with lead. Please do not consume insulation.'" clothing_flags = THICKMATERIAL | SNUG_FIT flags_inv = HIDEMASK|HIDEEARS|HIDEFACE|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 7b56e35566c..512a64f410d 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -74,7 +74,7 @@ if(SSlag_switch.measures[DISABLE_DEAD_KEYLOOP]) less_input_message = " - Notice: Observer freelook is currently disabled." // Don't convert this to tgui please, it's way too important - var/this_is_like_playing_right = alert(usr, "Are you sure you wish to observe? [get_respawn_notice()][less_input_message]", "Observe", "Yes", "No") + var/this_is_like_playing_right = alert(usr, "Are you sure you wish to observe? [get_respawn_notice()][less_input_message]", "Observe", "Yes", "No") // VOIDCREW EDIT: ghost respawn integration: display the applicable respawn notice (voidcrew/edits/mobs/ghost_respawn.dm) if(QDELETED(src) || !src.client || this_is_like_playing_right != "Yes") ready = PLAYER_NOT_READY return FALSE @@ -245,7 +245,7 @@ if(humanc && arrivals && !arrivals.power_environ) //arrivals depowered humanc.put_in_hands(new /obj/item/crowbar/large/emergency(get_turf(humanc))) //if hands full then just drops on the floor log_manifest(character.mind.key, character.mind, character, latejoin = TRUE) - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CREWMEMBER_JOINED, character, character.mind.assigned_role.title) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CREWMEMBER_JOINED, character, character.mind.assigned_role.title) // VOIDCREW EDIT: ship crew spawning: validate arrival and announce only after equipment and manifest setup (voidcrew/edits/mobs/new_player.dm) /mob/dead/new_player/proc/AddEmploymentContract(mob/living/carbon/human/employee) //TODO: figure out a way to exclude wizards/nukeops/demons from this. @@ -255,14 +255,16 @@ employmentCabinet.addFile(employee) /// Creates, assigns and returns the new_character to spawn as. Assumes a valid mind.assigned_role exists. -/mob/dead/new_player/proc/create_character(atom/destination, datum/callback/validate_arrival) +/mob/dead/new_player/proc/create_character(atom/destination, datum/callback/validate_arrival) // VOIDCREW EDIT: ship crew spawning: validate arrival and announce only after equipment and manifest setup (voidcrew/edits/mobs/new_player.dm) spawning = TRUE mind.active = FALSE //we wish to transfer the key manually var/mob/living/spawning_mob = mind.assigned_role.get_spawn_mob(client, destination) + // VOIDCREW EDIT START - ship crew spawning: validate arrival and announce only after equipment and manifest setup (voidcrew/edits/mobs/new_player.dm) if(QDELETED(src) || !HAS_CONNECTED_PLAYER(src) || (validate_arrival && !validate_arrival.Invoke(spawning_mob))) qdel(spawning_mob) return // Disconnected or destination refused after appearance checks. + // VOIDCREW EDIT END if(!isAI(spawning_mob)) // Unfortunately there's still snowflake AI code out there. // transfer_to sets mind to null @@ -286,6 +288,7 @@ var/area/joined_area = get_area(new_character.loc) if(joined_area) joined_area.on_joining_game(new_character) + // VOIDCREW EDIT REMOVAL - ship crew spawning: validate arrival and announce only after equipment and manifest setup (voidcrew/edits/mobs/new_player.dm) // The spawn caller announces the arrival after equipment and manifest setup. new_character = null qdel(src) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 30d585250db..ecf03e5d564 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -315,7 +315,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(!HAS_TRAIT(src, TRAIT_CORPSELOCKED)) //corpse-locked have to confirm with the alert below ghostize(TRUE) return TRUE - var/response = tgui_alert(usr, "Are you sure you want to ghost? You won't be able to re-enter your body! [get_respawn_notice()]", "Confirm Ghost Observe", list("Ghost", "Stay in Body")) + var/response = tgui_alert(usr, "Are you sure you want to ghost? You won't be able to re-enter your body! [get_respawn_notice()]", "Confirm Ghost Observe", list("Ghost", "Stay in Body")) // VOIDCREW EDIT: ghost respawn and interaction integration (voidcrew/edits/mobs/ghost_respawn.dm): preserve respawn notices and validate clicked loot tiles if(response != "Ghost") return FALSE//didn't want to ghost after-all ghostize(FALSE) // FALSE parameter is so we can never re-enter our body. U ded. @@ -935,11 +935,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp // things buried under other atoms instead of only whatever is on top. // Deliberately skips COMSIG_CLICK_ALT and click_alt() - ghosts look, they don't act. if(SEND_SIGNAL(src, COMSIG_MOB_ALTCLICKON, target) & COMSIG_MOB_CANCEL_CLICKON) + // VOIDCREW EDIT START - ghost respawn and interaction integration (voidcrew/edits/mobs/ghost_respawn.dm): preserve respawn notices and validate clicked loot tiles return var/turf/tile = get_turf(target) if(isnull(tile) || isnull(client)) return client.loot_panel.open(tile) + // VOIDCREW EDIT END /mob/dead/observer/AltClickSecondaryOn(atom/target) if(client && check_rights_for(client, R_DEBUG)) diff --git a/code/modules/mob/living/basic/lavaland/legion/legion.dm b/code/modules/mob/living/basic/lavaland/legion/legion.dm index b6afb7bd56d..860595eb913 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion.dm @@ -59,7 +59,7 @@ return UnregisterSignal(stored_mob, COMSIG_LIVING_REVIVE) // Direct deletion destroys our controller before deleting the contained corpse. - ai_controller?.clear_blackboard_key(BB_LEGION_CORPSE) + ai_controller?.clear_blackboard_key(BB_LEGION_CORPSE) // VOIDCREW EDIT: Voidcrew legion lifecycle integration: tolerate the controller being deleted before its stored corpse (voidcrew/edits/mobs/legion_reach.dm) stored_mob.remove_status_effect(/datum/status_effect/grouped/stasis, STASIS_LEGION_EATEN) stored_mob.add_mood_event("legion_core", /datum/mood_event/healsbadman/long_term) // This will still probably mostly be gone before you are alive stored_mob = null diff --git a/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm b/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm index ec0540a28eb..e45b29edfe5 100644 --- a/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm +++ b/code/modules/mob/living/basic/lavaland/legion/spawn_legions.dm @@ -26,31 +26,6 @@ return FALSE return TRUE -/** - * Walks the line from the owner to `destination` and returns the last turf the skull can - * actually reach, or null if it cannot leave the owner's tile at all. - * - * Targeting is done with can_see(), which passes through anything non-opaque. A window is - * transparent and solid at the same time, so without this the launcher happily deposits - * brood on the other side of a hull - the "skulls spawned inside my ship" case. Dense mobs - * are not obstacles; a thrown skull goes over them. - */ -/datum/action/cooldown/mob_cooldown/skull_launcher/proc/clamp_to_reachable_turf(turf/destination) - var/turf/origin = get_turf(owner) - if (isnull(destination) || destination == origin) - return destination - - var/turf/furthest = null - // get_line()'s first entry is the origin itself, which is not a candidate landing spot. - var/list/path = get_line(origin, destination) - for (var/i in 2 to length(path)) - var/turf/step = path[i] - if (step.is_blocked_turf(exclude_mobs = TRUE, source_atom = owner)) - break - furthest = step - - return furthest - /datum/action/cooldown/mob_cooldown/skull_launcher/Activate(atom/target) var/turf/target_turf = get_turf(target) @@ -60,18 +35,20 @@ // The skull is thrown, so it has to be able to physically get there. Targeting only // needs line of sight, and glass is transparent but solid - without this a legion // stood outside a window drops brood on the far side of the hull. + // VOIDCREW EDIT START - Voidcrew legion reach integration: skulls must stop at solid hull obstacles (voidcrew/edits/mobs/legion_reach.dm) target_turf = clamp_to_reachable_turf(target_turf) if (isnull(target_turf)) owner.balloon_alert(owner, "no room!") StartCooldown(0.5 SECONDS) return + // VOIDCREW EDIT END // Only a dense mob can be in the way now - clamp_to_reachable_turf() already rejected // anything solid. Shuffle off it if there's a free neighbour we can also reach. if (target_turf.is_blocked_turf()) var/list/near_turfs = RANGE_TURFS(1, target_turf) - target_turf for (var/turf/check_turf as anything in near_turfs) - if (check_turf.is_blocked_turf() || clamp_to_reachable_turf(check_turf) != check_turf) + if (check_turf.is_blocked_turf() || clamp_to_reachable_turf(check_turf) != check_turf) // VOIDCREW EDIT: Voidcrew legion reach integration: skulls must stop at solid hull obstacles (voidcrew/edits/mobs/legion_reach.dm) near_turfs -= check_turf if (length(near_turfs)) target_turf = pick(near_turfs) diff --git a/code/modules/mob/living/basic/tree.dm b/code/modules/mob/living/basic/tree.dm index 6027f941dc8..7dd85e78509 100644 --- a/code/modules/mob/living/basic/tree.dm +++ b/code/modules/mob/living/basic/tree.dm @@ -74,7 +74,7 @@ if(co2 > 0 && SPT_PROB(13, seconds_per_tick)) var/amt = min(co2, 9) var/datum/gas_mixture/turf_air = our_turf.return_air() // VOIDCREW EDIT: written to; leaves the shared planetary mix - turf_air.gases[/datum/gas/carbon_dioxide][MOLES] -= amt + turf_air.gases[/datum/gas/carbon_dioxide][MOLES] -= amt // VOIDCREW EDIT: planetary shared air: materialize a private mixture before writes (voidcrew/edits/planetary_shared_air.dm) our_turf.atmos_spawn_air("[GAS_O2]=[amt]") /mob/living/basic/tree/melee_attack(atom/target, list/modifiers, ignore_cooldown = FALSE) diff --git a/code/modules/mob/living/basic/trooper/pirate.dm b/code/modules/mob/living/basic/trooper/pirate.dm index d3c180d152e..229104cc577 100644 --- a/code/modules/mob/living/basic/trooper/pirate.dm +++ b/code/modules/mob/living/basic/trooper/pirate.dm @@ -32,6 +32,7 @@ light_range = 2 light_power = 2.5 light_color = COLOR_SOFT_RED + // VOIDCREW EDIT REMOVAL - overmap ruin loot: retain the pirate corpse drop without a guaranteed duplicate energy sword mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/melee corpse = /obj/effect/mob_spawn/corpse/human/pirate/melee r_hand = /obj/item/melee/energy/sword/pirate diff --git a/code/modules/mob/living/basic/trooper/trooper.dm b/code/modules/mob/living/basic/trooper/trooper.dm index 9a3942a3bea..bf748c50a4f 100644 --- a/code/modules/mob/living/basic/trooper/trooper.dm +++ b/code/modules/mob/living/basic/trooper/trooper.dm @@ -28,13 +28,12 @@ var/r_hand /// Path of the left hand held item we give to the mob's visuals. var/l_hand - /// VOIDCREW EDIT: subtypes with bespoke static sprites (e.g. boat pirates) set this FALSE to keep their own icon. - var/use_dynamic_appearance = TRUE + /mob/living/basic/trooper/Initialize(mapload) . = ..() if(use_dynamic_appearance) // VOIDCREW EDIT - apply_dynamic_human_appearance(src, mob_spawn_path = mob_spawner, r_hand = r_hand, l_hand = l_hand) + apply_dynamic_human_appearance(src, mob_spawn_path = mob_spawner, r_hand = r_hand, l_hand = l_hand) // VOIDCREW EDIT: trooper appearance integration: respect static fork sprites (voidcrew/edits/mobs/trooper_appearance.dm) if(LAZYLEN(loot) || corpse) LAZYOR(loot, corpse) loot = string_list(loot) diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 190b73137ae..dd3ca505f60 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -16,7 +16,7 @@ TRAIT_NO_UNDERWEAR, TRAIT_PIERCEIMMUNE, TRAIT_RADIMMUNE, - // VOIDCREW EDIT ADDITION: upstream hangs the mineral-buff trait solely on + // VOIDCREW EDIT ADDITION START: upstream hangs the mineral-buff trait solely on - self_surgery: retain mineral metabolism when a golem receives another brain // /obj/item/organ/brain/golem, so a golem body carrying anyone else's brain eats // minerals (TRAIT_ROCK_EATER, from the golem stomach) and gets nothing back. This // fork ships self-surgery, so brain-swapping into a golem shell is routine, and the diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index 7f0f8bea97c..ade9ba775b1 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -252,7 +252,7 @@ // Not an else-if because we're probably equipped in another slot if(item_dropping == internal && (QDELETED(src) || QDELETED(item_dropping) || item_dropping.loc != src)) - cutoff_internals("tank unequipped from slot, newloc=[item_dropping.loc]") + cutoff_internals("tank unequipped from slot, newloc=[item_dropping.loc]") // VOIDCREW EDIT: shuttle internals diagnostics: identify the disconnect call site (voidcrew/edits/mobs/internals_logging.dm) if(!QDELETED(src)) update_mob_action_buttons(UPDATE_BUTTON_STATUS) @@ -385,24 +385,13 @@ /// Prepares emergency disconnect from open air tanks and notifies in chat. Usually called after mob suddenly unequips breathing apparatus. /// reason names the call site so intermittent cutoffs can be traced - see log_internals_cutoff(). -/mob/living/carbon/proc/cutoff_internals(reason = "unspecified") +/mob/living/carbon/proc/cutoff_internals(reason = "unspecified") // VOIDCREW EDIT: shuttle internals diagnostics: identify the disconnect call site (voidcrew/edits/mobs/internals_logging.dm) if (!external && !internal) return - log_internals_cutoff(reason) + log_internals_cutoff(reason) // VOIDCREW EDIT: shuttle internals diagnostics: identify the disconnect call site (voidcrew/edits/mobs/internals_logging.dm) to_chat(src, span_notice("Your internals disconnect from [external || internal] and the valve closes.")) close_all_airtanks() -/** - * Records why an open air tank was cut off, plus everything invalid_internals() reads. - * Cutoffs have been reported during shuttle docking with the tank still slotted and the mask - * still worn, which no call path explains - this dumps the state at the moment it happens. - * Goes to the shuttle log so it lands next to the dock entries for the same tick. - */ -/mob/living/carbon/proc/log_internals_cutoff(reason) - var/obj/item/tank/closing = external || internal - var/atom/tank_loc = closing.loc - log_shuttle("INTERNALS CUTOFF: [key_name(src)] at [AREACOORD(src)] reason=[reason] tank=[closing.type] ([external ? "external" : "internal"]) tank_loc=[tank_loc] ([tank_loc?.type]) loc_is_mob=[tank_loc == src ? "yes" : "NO"] apparatus=[can_breathe_internals() || "NONE"] mask=[wear_mask ? "[wear_mask.type] up=[wear_mask.up] flags=[wear_mask.clothing_flags]" : "NONE"] head=[head ? "[head.type] flags=[head.clothing_flags]" : "NONE"] tube=[can_breathe_tube() ? "yes" : "no"] stat=[stat]") - /** * Toggles the given internal air tank open, or close the currently open one, if a compatible breathing apparatus is found. * Returns TRUE if the tank was opened successfully. diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 02ac737582f..cd1fbe208ed 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -443,7 +443,7 @@ /mob/living/carbon/proc/get_breath_from_internal(volume_needed) if(invalid_internals()) // Unexpectely lost breathing apparatus and ability to breathe from the internal air tank. - cutoff_internals("invalid internals on breath") + cutoff_internals("invalid internals on breath") // VOIDCREW EDIT: shuttle internals diagnostics: identify the disconnect call site (voidcrew/edits/mobs/internals_logging.dm) return if (external) . = external.remove_air_volume(volume_needed) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index bb41adbab29..7869de9846d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1335,7 +1335,7 @@ if(!istype(target)) CRASH("Missing target arg for can_perform_action") - if(stat != CONSCIOUS && !(stat == SOFT_CRIT && (action_bitflags & ALLOW_SOFT_CRIT))) + if(stat != CONSCIOUS && !(stat == SOFT_CRIT && (action_bitflags & ALLOW_SOFT_CRIT))) // VOIDCREW EDIT: soft crit interaction: permit selected actions while retaining other incapacitation checks (voidcrew/edits/mobs/softcrit_interaction.dm) to_chat(src, span_warning("You are not conscious enough for this action!")) return FALSE @@ -1343,11 +1343,13 @@ var/ignore_flags = NONE if(interaction_flags_atom & INTERACT_ATOM_IGNORE_RESTRAINED) ignore_flags |= INCAPABLE_RESTRAINTS - if(!(interaction_flags_atom & INTERACT_ATOM_CHECK_GRAB) && stat != SOFT_CRIT) + if(!(interaction_flags_atom & INTERACT_ATOM_CHECK_GRAB) && stat != SOFT_CRIT) // VOIDCREW EDIT: soft crit interaction: permit selected actions while retaining other incapacitation checks (voidcrew/edits/mobs/softcrit_interaction.dm) ignore_flags |= INCAPABLE_GRAB + // VOIDCREW EDIT START - soft crit interaction: permit selected actions while retaining other incapacitation checks (voidcrew/edits/mobs/softcrit_interaction.dm) var/is_incapacitated = (action_bitflags & ALLOW_SOFT_CRIT) ? incapacitated_except_softcrit(ignore_flags) : INCAPACITATED_IGNORING(src, ignore_flags) if(is_incapacitated) + // VOIDCREW EDIT END to_chat(src, span_warning("You are incapacitated at the moment!")) return FALSE @@ -2373,7 +2375,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) if(SOFT_CRIT) if(stat >= UNCONSCIOUS) ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) //adding trait sources should come before removing to avoid unnecessary updates - ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, STAT_TRAIT) + ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, STAT_TRAIT) // VOIDCREW EDIT: soft crit interaction: permit selected actions while retaining other incapacitation checks (voidcrew/edits/mobs/softcrit_interaction.dm) if(pulledby) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, PULLED_WHILE_SOFTCRIT_TRAIT) if(UNCONSCIOUS) @@ -2398,7 +2400,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) ADD_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT) log_combat(src, src, "entered soft crit") - REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, STAT_TRAIT) + REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, STAT_TRAIT) // VOIDCREW EDIT: soft crit interaction: permit selected actions while retaining other incapacitation checks (voidcrew/edits/mobs/softcrit_interaction.dm) if(UNCONSCIOUS) if(. != HARD_CRIT) become_blind(UNCONSCIOUS_TRAIT) diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm index cccf350f4e1..bae8c944391 100644 --- a/code/modules/mob/living/login.dm +++ b/code/modules/mob/living/login.dm @@ -6,7 +6,7 @@ //Mind updates sync_mind() // VOIDCREW: retain physical boarding history across reconnects. - LoadComponent(/datum/component/ship_zone_logging) + LoadComponent(/datum/component/ship_zone_logging) // VOIDCREW EDIT: overmap logging: retain ship boarding history on reconnect update_damage_hud() update_health_hud() diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index bad4b440021..3a3f53b264f 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -23,7 +23,7 @@ create_eye() - if((target_ai.mind && target_ai.mind.active) || SSticker.current_state == GAME_STATE_SETTING_UP || target_ai.mind?.assigned_role?.ship_role == "ai") + if((target_ai.mind && target_ai.mind.active) || SSticker.current_state == GAME_STATE_SETTING_UP || target_ai.mind?.assigned_role?.ship_role == "ai") // VOIDCREW EDIT: ship silicon crew: retain the assigned crew AI relationship (voidcrew/edits/machinery/silicon_ship_systems.dm) target_ai.mind.transfer_to(src) if(is_antag()) to_chat(src, span_userdanger("You have been installed as an AI! ")) @@ -286,7 +286,7 @@ if (!is_valid_z_level(ai_turf, target_turf)) return FALSE - // VOIDCREW EDIT ADDITION: packed-level containment. can_see() in + // VOIDCREW EDIT ADDITION START: packed-level containment. can_see() in - overmap: contain observers and effects within their packed encounter // voidcrew/edits/machinery/silicon_ship_systems.dm scopes an AI that is aboard a HULL; // an AI with no hull scope (an outpost core, a ruin, an admin spawn) falls through to // cameranet.checkTurfVis(), and a co-tenant ruin with its own mapped cameras is lit for @@ -569,7 +569,7 @@ var/mob/living/silicon/ai/U = usr - // VOIDCREW EDIT ADDITION: packed-level containment, resolved once outside the loop. + // VOIDCREW EDIT ADDITION START: packed-level containment, resolved once outside the loop. - overmap: contain observers and effects within their packed encounter // Lattice encounter levels and planet levels both publish ZTRAIT_MINING, and in this // fork is_station_level() means "any z with a hull on it", so both clauses below admit a // co-tenant's cameras. The eye is already refused entry by silicon_ship_systems.dm, but @@ -583,7 +583,7 @@ var/list/tempnetwork = C.network if(!camera_turf || !(is_station_level(camera_turf.z) || is_mining_level(camera_turf.z) || (CAMERANET_NETWORK_SS13 in tempnetwork))) continue - // VOIDCREW EDIT ADDITION + // VOIDCREW EDIT ADDITION START - overmap: contain observers and effects within their packed encounter if(map_region_excludes_turf(ai_region, camera_turf)) continue // VOIDCREW EDIT END diff --git a/code/modules/mob/living/silicon/ai/ai_say.dm b/code/modules/mob/living/silicon/ai/ai_say.dm index 402002507d1..01ecbbd3a34 100644 --- a/code/modules/mob/living/silicon/ai/ai_say.dm +++ b/code/modules/mob/living/silicon/ai/ai_say.dm @@ -149,14 +149,14 @@ var/list/players = list() var/turf/ai_turf = get_turf(src) - // VOIDCREW EDIT ADDITION: is_valid_z_level() is bare z equality, and a packed z-level + // VOIDCREW EDIT ADDITION START: is_valid_z_level() is bare z equality, and a packed z-level - overmap: contain observers and effects within their packed encounter // carries up to four unrelated crews. A ship AI announcing while docked at an encounter // was heard in full, text and VOX, by every co-tenant. Resolved once, outside the loop. var/datum/ai_region = map_region_for_turf(ai_turf) // VOIDCREW EDIT END for(var/mob/player_mob as anything in GLOB.player_list) var/turf/player_turf = get_turf(player_mob) - // VOIDCREW EDIT ADDITION + // VOIDCREW EDIT ADDITION START - overmap: contain observers and effects within their packed encounter if(map_region_excludes_turf(ai_region, player_turf)) continue // VOIDCREW EDIT END @@ -178,7 +178,7 @@ // If there is no single listener, broadcast to everyone in the same z level if(!only_listener) - // VOIDCREW EDIT ADDITION: same packed-level containment as the announcement + // VOIDCREW EDIT ADDITION START: same packed-level containment as the announcement - overmap: contain observers and effects within their packed encounter // text above - see /mob/living/silicon/ai/proc/announcement(). var/datum/ai_region = map_region_for_turf(ai_turf) // VOIDCREW EDIT END @@ -191,7 +191,7 @@ var/turf/player_turf = get_turf(player_mob) if(!is_valid_z_level(ai_turf, player_turf)) continue - // VOIDCREW EDIT ADDITION + // VOIDCREW EDIT ADDITION START - overmap: contain observers and effects within their packed encounter if(map_region_excludes_turf(ai_region, player_turf)) continue // VOIDCREW EDIT END diff --git a/code/modules/mob/living/silicon/ai/robot_control.dm b/code/modules/mob/living/silicon/ai/robot_control.dm index 9b3ed32b9f3..355129c2f5e 100644 --- a/code/modules/mob/living/silicon/ai/robot_control.dm +++ b/code/modules/mob/living/silicon/ai/robot_control.dm @@ -35,14 +35,14 @@ var/turf/ai_current_turf = get_turf(owner) data["robots"] = list() - // VOIDCREW EDIT ADDITION: packed-level containment - is_valid_z_level() is bare z + // VOIDCREW EDIT ADDITION START: packed-level containment - is_valid_z_level() is bare z - overmap: contain observers and effects within their packed encounter // equality, so a co-tenant's bots were listed and remotely commandable. var/datum/ai_region = map_region_for_turf(ai_current_turf) // VOIDCREW EDIT END for(var/mob/living/our_bot as anything in GLOB.bots_list) if(!isbot(our_bot) || !is_valid_z_level(ai_current_turf, get_turf(our_bot))) continue - // VOIDCREW EDIT ADDITION + // VOIDCREW EDIT ADDITION START - overmap: contain observers and effects within their packed encounter if(map_region_excludes_turf(ai_region, get_turf(our_bot))) continue // VOIDCREW EDIT END diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index f8368ea4602..9ab4b141135 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -984,10 +984,12 @@ unbuckle_mob(unbuckle_me_now, FALSE) /mob/living/silicon/robot/proc/TryConnectToAI() + // VOIDCREW EDIT START - ship silicon crew: retain the assigned crew AI relationship (voidcrew/edits/machinery/silicon_ship_systems.dm) if(mind?.assigned_role?.ship_role == "cyborg" || istype(get_area(src), /area/shuttle/voidcrew)) set_connected_ai(crew_ai()) else set_connected_ai(select_active_ai_with_fewest_borgs(z)) + // VOIDCREW EDIT END if(connected_ai) lawsync() lawupdate = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 19ab82c2aea..3f2b819cd5b 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -620,7 +620,7 @@ /mob/living/simple_animal/hostile/proc/ListTargetsLazy(_Z)//Step 1, find out what we can see var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha)) . = list() - // VOIDCREW EDIT ADDITION: packed-level containment. vision_range is 9 by default and two + // VOIDCREW EDIT ADDITION START: packed-level containment. vision_range is 9 by default and two - overmap: contain observers and effects within their packed encounter // tenants' nearest live turfs are 6 apart, so a mob at the edge of its slot acquired a // player in the NEXT slot - one it can never reach, because /turf/cordon is never // Adjacent(), so it paths at them for the rest of its life. Resolved once per call. @@ -628,7 +628,7 @@ // VOIDCREW EDIT END for (var/I in SSmobs.clients_by_zlevel[_Z]) var/mob/M = I - // VOIDCREW EDIT ADDITION + // VOIDCREW EDIT ADDITION START - overmap: contain observers and effects within their packed encounter if(map_region_excludes_turf(own_region, get_turf(M))) continue // VOIDCREW EDIT END diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm index c5625b8429a..ace7f2d257e 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm @@ -82,48 +82,6 @@ return ..() return ..() -// VOIDCREW: record targeting decisions, including aggro before any attack lands. -/mob/living/simple_animal/hostile/megafauna/add_target(new_target) - var/atom/previous_target = target - . = ..() - if(previous_target != target) - log_aggro_change(previous_target, target) - -/mob/living/simple_animal/hostile/megafauna/handle_target_del(datum/source) - SIGNAL_HANDLER - // The parent clears target before calling LoseTarget(), so capture it now. - if(target == source) - log_aggro_change(target, null) - return ..() - -/mob/living/simple_animal/hostile/megafauna/proc/aggro_target_description(atom/subject) - if(!subject) - return "none" - var/description = "[key_name_and_tag(subject)] [REF(subject)] at [loc_name(subject)]; [overmap_zone_log_context(subject)]" - if(ismecha(subject)) - var/obj/vehicle/sealed/mecha/mech = subject - var/list/pilots = list() - for(var/mob/pilot as anything in mech.occupants) - pilots += key_name_and_tag(pilot) - description += "; occupants: [length(pilots) ? jointext(pilots, ", ") : "none"]" - return description - -/mob/living/simple_animal/hostile/megafauna/proc/log_aggro_change(atom/previous_target, atom/new_target) - var/action = new_target ? (previous_target ? "switched target" : "acquired target") : "lost target" - var/message = "\[MEGAFAUNA AGGRO\] [action]; from: [aggro_target_description(previous_target)]; to: [aggro_target_description(new_target)]" - log_message(message, LOG_ATTACK, color = "blue") - // Keep the same event in the involved players' individual logs, too. - var/list/mob/observers = list() - for(var/atom/subject as anything in list(previous_target, new_target)) - if(ismob(subject)) - observers |= subject - else if(ismecha(subject)) - var/obj/vehicle/sealed/mecha/mech = subject - for(var/mob/pilot as anything in mech.occupants) - observers |= pilot - for(var/mob/observer as anything in observers) - observer.log_message("[key_name_and_tag(src)] at [loc_name(src)]; [overmap_zone_log_context(src)]: [message]", LOG_ATTACK, color = "blue", log_globally = FALSE) - /mob/living/simple_animal/hostile/megafauna/death(gibbed, list/force_grant) if(gibbed) // in case they've been force dusted return ..() diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm index 8fbb425b703..73a41e1e469 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm @@ -3,7 +3,7 @@ vision_range = 2 atmos_requirements = null faction = list(FACTION_MINING) - // VOIDCREW EDIT: TRAIT_SNOWSTORM_IMMUNE added. /mob/living/basic/mining - the newer + // VOIDCREW EDIT START: TRAIT_SNOWSTORM_IMMUNE added. /mob/living/basic/mining - the newer - overmap planets: legacy mining wildlife shares plasma-river immunity with basic mining mobs // base every other icemoon mob already sits on - grants all THREE of these // (see its Initialize), and this one being two-thirds of that list is an oversight // upstream never felt because on icemoon the plasma rivers are mapped, not carved. diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 3c18c37662c..4b2b27d45df 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -220,7 +220,7 @@ QDEL_NULL(access_card) GLOB.simple_animals[AIStatus] -= src SSnpcpool.currentrun -= src - SSidlenpcpool.currentrun -= src // voidcrew: same deal, an in-flight idle scan would hold us past Destroy + SSidlenpcpool.currentrun -= src // voidcrew: same deal, an in-flight idle scan would hold us past Destroy // VOIDCREW EDIT: overmap NPC lifecycle: remove dying mobs from the in-flight idle scan return ..() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index f0b3b8b17a3..9e990b111ea 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -452,21 +452,6 @@ /mob/proc/build_incapacitated() return NONE -/** - * Allows item interactions in soft crit without ignoring other incapacitation sources. - * Adapted from MonkeStation: dwasint's original crit item use and action slowdown, - * https://github.com/Monkestation/Monkestation2.0/commit/232ff2ce43dafbb9a8501a618088addd4431e97f - * https://github.com/Monkestation/Monkestation2.0/commit/0254a94c43bc36c6d88252caa3dc98789649ab9d - * with SirNightKnight's source-aware checks (PR #8791) and Xander3359's hard-crit restriction (PR #8709). - * https://github.com/Monkestation/Monkestation2.0/pull/8791 - * https://github.com/Monkestation/Monkestation2.0/pull/8709 - */ -/mob/proc/incapacitated_except_softcrit(ignore_flags = NONE) - // Check sources live: adding a stun while STAT_TRAIT is present does not emit another trait-gain signal. - if(stat == SOFT_CRIT && HAS_TRAIT_FROM_ONLY(src, TRAIT_INCAPACITATED, STAT_TRAIT)) - ignore_flags |= TRADITIONAL_INCAPACITATED - return INCAPACITATED_IGNORING(src, ignore_flags) - /** * This proc is called whenever someone clicks an inventory ui slot. * @@ -771,9 +756,11 @@ if(ismecha(loc)) return + // VOIDCREW EDIT START - soft crit interaction: permit selected actions while retaining other incapacitation checks (voidcrew/edits/mobs/softcrit_interaction.dm) if(incapacitated_except_softcrit() || HAS_TRAIT(src, TRAIT_HANDS_BLOCKED)) return if(stat == SOFT_CRIT && next_move > world.time) + // VOIDCREW EDIT END return var/obj/item/I = get_active_held_item() @@ -818,6 +805,7 @@ return usr.log_message("used the respawn button.", LOG_GAME) +// VOIDCREW EDIT REMOVAL - Voidcrew mob interaction: omit the generic roleplay admonition (voidcrew/edits/mobs) if(!client) usr.log_message("respawn failed due to disconnect.", LOG_GAME) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index ef92aac59ad..fe91176128b 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -46,9 +46,6 @@ /// This is what actually gets applied to the mob, it's modified by things like glasses var/list/lighting_color_cutoffs = null var/datum/mind/mind - /// Whether this mob has ever been assigned as a mind's current body. - /// This remains TRUE after the mind leaves so formerly player-controlled bodies can still be identified. - var/ever_had_mind = FALSE var/static/next_mob_id = 0 /// List of movement speed modifiers applying to this mob diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm index b5817786b11..54fd05df50d 100644 --- a/code/modules/mod/mod_activation.dm +++ b/code/modules/mod/mod_activation.dm @@ -273,7 +273,7 @@ wearer.update_clothing(part.slot_flags | slot_flags) wearer.update_obscured_slots(part.visor_flags_inv) if((part.clothing_flags & (MASKINTERNALS|HEADINTERNALS)) && wearer.invalid_internals()) - wearer.cutoff_internals("MOD part [part.type] [is_sealed ? "sealed" : "unsealed"]") + wearer.cutoff_internals("MOD part [part.type] [is_sealed ? "sealed" : "unsealed"]") // VOIDCREW EDIT: shuttle internals diagnostics: identify the disconnect call site (voidcrew/edits/mobs/internals_logging.dm) SEND_SIGNAL(src, COMSIG_MOD_PART_SEALED, part_datum) if(is_sealed) if (!active) diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index 55455937ee7..f5115688049 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -180,22 +180,24 @@ /datum/mod_theme/civilian name = "civilian" + // VOIDCREW EDIT START - Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) desc = "A light-weight civilian suit that offers unmatched ease of movement without giving up a vacuum seal." extended_desc = "An experimental design by Nakamura Engineering, intended to be marketed towards civilian customers. \ This model sacrifices the protection from biological and chemical threats in exchange for \ vastly improved mobility, though the seals were kept intact for vacuum work. Due to the slimmed-down profile, \ it also has less capacity for modifications compared to mainline models." + // VOIDCREW EDIT END default_skin = "civilian" armor_type = /datum/armor/mod_theme_civilian max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT - min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) complexity_max = DEFAULT_MAX_COMPLEXITY - 3 slowdown_deployed = 0 variants = list( "civilian" = list( /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, SEALED_MESSAGE = HELMET_SEAL_MESSAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEEYES|HIDEHAIR|HIDESNOUT, @@ -203,21 +205,21 @@ ), /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) SEALED_INVISIBILITY = HIDEJUMPSUIT, UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) CAN_OVERSLOT = TRUE, UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) CAN_OVERSLOT = TRUE, UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, SEALED_MESSAGE = BOOT_SEAL_MESSAGE, @@ -464,7 +466,7 @@ armor_type = /datum/armor/mod_theme_mining resistance_flags = FIRE_PROOF|LAVA_PROOF max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT - min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) complexity_max = DEFAULT_MAX_COMPLEXITY - 2 charge_drain = DEFAULT_CHARGE_DRAIN * 2 inbuilt_modules = list(/obj/item/mod/module/ash_accretion, /obj/item/mod/module/sphere_transform) @@ -552,6 +554,7 @@ /datum/mod_theme/loader name = "loader" + // VOIDCREW EDIT START - Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) desc = "An experimental motorized harness manufactured by Scarborough Arms for quick and efficient munition supplies." extended_desc = "This powered suit is an experimental spinoff of standard Engineering suits. \ This fully articulated titanium exoskeleton is Scarborough Arms' suit of choice for their munition delivery men, \ @@ -562,10 +565,11 @@ suit capable of lifting 250 tons. Even the legs in the suit have been tuned to incredible capacity, \ the user being able to run at greater speeds for much longer distances and times than an unsuited equivalent. \ A lot of people would say loading cargo is a dull job. You could not disagree more." + // VOIDCREW EDIT END default_skin = "loader" armor_type = /datum/armor/mod_theme_loader max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT - min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) siemens_coefficient = 0.25 complexity_max = DEFAULT_MAX_COMPLEXITY - 5 slowdown_deployed = 0 @@ -580,7 +584,7 @@ "loader" = list( /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -589,18 +593,18 @@ ), /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), /obj/item/clothing/gloves/mod = list( - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) CAN_OVERSLOT = TRUE, UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), /obj/item/clothing/shoes/mod = list( - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) CAN_OVERSLOT = TRUE, UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, SEALED_MESSAGE = BOOT_SEAL_MESSAGE, @@ -1361,7 +1365,7 @@ "infiltrator" = list( /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT|HIDEANTENNAE, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -1371,20 +1375,20 @@ ), /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) SEALED_INVISIBILITY = HIDEJUMPSUIT|HIDEMUTWINGS, CAN_OVERSLOT = TRUE, UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), /obj/item/clothing/gloves/mod = list( - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) CAN_OVERSLOT = TRUE, UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), /obj/item/clothing/shoes/mod = list( - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, // VOIDCREW EDIT: Voidcrew MOD integration: civilian, loader and ninja suits retain vacuum seals (voidcrew/modules/clothing) CAN_OVERSLOT = TRUE, UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, SEALED_MESSAGE = BOOT_SEAL_MESSAGE, diff --git a/code/modules/mod/modules/modules_supply.dm b/code/modules/mod/modules/modules_supply.dm index 1a0e0ddb3f2..cf90dc26956 100644 --- a/code/modules/mod/modules/modules_supply.dm +++ b/code/modules/mod/modules/modules_supply.dm @@ -87,7 +87,7 @@ // inside the deactivated module (and pinned by this list if later deleted) for(var/atom/movable/crate in stored_crates) crate.forceMove(drop_location()) - stored_crates.Cut() + stored_crates.Cut() // VOIDCREW EDIT: Voidcrew MOD storage lifecycle: keep crate and ore lists coherent while contents leave (voidcrew/edits/objects/items/mod_storage_lifecycle.dm) /obj/item/mod/module/clamp/proc/check_crate_pickup(atom/movable/target) if(length(stored_crates) >= max_crates) @@ -208,20 +208,15 @@ // the dead stack pinned it in this round-long list forever - one hard delete per // pickup once the bag held a full stack of that ore (round 4: ~380 of them, 170 s). if(QDELETED(ore)) - return + return // VOIDCREW EDIT: Voidcrew MOD storage lifecycle: keep crate and ore lists coherent while contents leave (voidcrew/edits/objects/items/mod_storage_lifecycle.dm) ores += ore -// VOIDCREW EDIT: keep the bookkeeping list honest however ore leaves - dumped, -// stolen out by hand, or deleted (qdel nullspaces contents through Exited) -/obj/item/mod/module/orebag/Exited(atom/movable/gone, direction) - . = ..() - ores -= gone - /obj/item/mod/module/orebag/on_use() // VOIDCREW EDIT: iterate a copy - Exited() now prunes ores on each forceMove, // and the old explicit `ores -= ore` mid-walk skipped every other stack anyway for(var/obj/item/ore in ores.Copy()) ore.forceMove(drop_location()) + // VOIDCREW EDIT REMOVAL - Voidcrew MOD storage lifecycle: keep crate and ore lists coherent while contents leave (voidcrew/edits/objects/items/mod_storage_lifecycle.dm) drain_power(use_energy_cost) /obj/item/mod/module/hydraulic diff --git a/code/modules/mod/modules/modules_visor.dm b/code/modules/mod/modules/modules_visor.dm index 7897ac404f2..2f36d412368 100644 --- a/code/modules/mod/modules/modules_visor.dm +++ b/code/modules/mod/modules/modules_visor.dm @@ -92,9 +92,9 @@ required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /obj/item/mod/module/night/on_activation() - ADD_TRAIT(mod.wearer, TRAIT_TRUE_NIGHT_VISION, REF(src)) + ADD_TRAIT(mod.wearer, TRAIT_TRUE_NIGHT_VISION, REF(src)) // VOIDCREW EDIT: Voidcrew MOD integration: add and remove the single night-vision trait through its scalar API (voidcrew/modules/clothing) mod.wearer.update_sight() /obj/item/mod/module/night/on_deactivation(display_message = TRUE, deleting = FALSE) - REMOVE_TRAIT(mod.wearer, TRAIT_TRUE_NIGHT_VISION, REF(src)) + REMOVE_TRAIT(mod.wearer, TRAIT_TRUE_NIGHT_VISION, REF(src)) // VOIDCREW EDIT: Voidcrew MOD integration: add and remove the single night-vision trait through its scalar API (voidcrew/modules/clothing) mod.wearer.update_sight() diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 8a83f6ba2be..dfa041a5b6d 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -396,7 +396,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list( // neighbours. Only for callers about to cut EVERY cable on the net (a shuttle move): // the timers would rebuild nets over cables mid-transplant, and propagate_if_no_network() // then trusts those half-built nets after landing, leaving the grid permanently split. -/obj/structure/cable/proc/cut_cable_from_powernet(remove = TRUE, rebuild_neighbor_networks = TRUE) +/obj/structure/cable/proc/cut_cable_from_powernet(remove = TRUE, rebuild_neighbor_networks = TRUE) // VOIDCREW EDIT: shuttle power integration: defer neighbor network rebuilding until every cable has moved (voidcrew/edits/machinery/power.dm) if(!powernet) return @@ -409,11 +409,13 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list( P.disconnect_from_network() var/list/P_list = list() + // VOIDCREW EDIT START - shuttle power integration: defer neighbor network rebuilding until every cable has moved (voidcrew/edits/machinery/power.dm) if(rebuild_neighbor_networks) for(var/dir_check in GLOB.cardinals) if(linked_dirs & dir_check) T1 = get_step(loc, dir_check) P_list += locate(/obj/structure/cable) in T1 + // VOIDCREW EDIT END // remove the cut cable from its turf and powernet, so that it doesn't get count in propagate_network worklist if(remove) diff --git a/code/modules/power/singularity/dark_matter_singularity.dm b/code/modules/power/singularity/dark_matter_singularity.dm index a8a7b2de170..d70cdb74fc7 100644 --- a/code/modules/power/singularity/dark_matter_singularity.dm +++ b/code/modules/power/singularity/dark_matter_singularity.dm @@ -20,8 +20,10 @@ /obj/singularity/dark_matter/Initialize(mapload, starting_energy) . = ..() + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(. == INITIALIZE_HINT_QDEL) // VOIDCREW return + // VOIDCREW EDIT END COOLDOWN_START(src, initial_explosion_immunity, 5 SECONDS) var/datum/component/singularity/resolved_singularity = singularity_component.resolve() resolved_singularity.chance_to_move_to_target = 100 diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index ba7e2913162..b28d883c737 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -192,11 +192,11 @@ var/power_usage = active_power_usage * seconds_per_tick if(machine_stat & (BROKEN)) return - if(!welded) + if(!welded) // VOIDCREW EDIT: shuttle power integration: preserve enabled emitters while a hull powernet reconnects (voidcrew/edits/machinery/power.dm) active = FALSE update_appearance() return - if(!powernet && power_usage) + if(!powernet && power_usage) // VOIDCREW EDIT: shuttle power integration: preserve enabled emitters while a hull powernet reconnects (voidcrew/edits/machinery/power.dm) // VOIDCREW EDIT CHANGE - original: `if(!welded || (!powernet && power_usage))` above. // A ship jump severs the hull cables of any net that reaches past the hull in // cable/beforeShuttleMove() (self-contained nets now travel intact, see @@ -207,12 +207,14 @@ // merely being rebuilt: reconnect or wait. Only an actually missing cable turns the // emitter off. var/turf/here = loc + // VOIDCREW EDIT START - shuttle power integration: preserve enabled emitters while a hull powernet reconnects (voidcrew/edits/machinery/power.dm) if(!connect_to_network() && isturf(here) && here.get_cable_node(cable_layer)) return if(!powernet) active = FALSE update_appearance() return + // VOIDCREW EDIT END if(!active) return if(power_usage && surplus() < power_usage) diff --git a/code/modules/power/singularity/reality_tear.dm b/code/modules/power/singularity/reality_tear.dm index 9f744cc45da..c164a1a43bb 100644 --- a/code/modules/power/singularity/reality_tear.dm +++ b/code/modules/power/singularity/reality_tear.dm @@ -26,8 +26,10 @@ var/collapse_spawn_time = 9 SECONDS /obj/reality_tear/proc/start_disaster() + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(neutralize_trader_outpost_hazard(src)) // VOIDCREW return + // VOIDCREW EDIT END apply_wibbly_filters(src) playsound(loc, 'sound/effects/clockcult_gateway_disrupted.ogg', vary = 200, extrarange = 3, falloff_exponent = 1, frequency = 0.33, pressure_affected = FALSE, ignore_walls = TRUE, falloff_distance = 7) AddComponent( @@ -43,13 +45,17 @@ animate(time = 0.5 SECONDS, alpha = 0) /obj/reality_tear/proc/reality_collapse() + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(neutralize_trader_outpost_hazard(src)) // VOIDCREW: it may have moved since creation. return + // VOIDCREW EDIT END playsound(loc, 'sound/effects/supermatter.ogg', 200, vary = TRUE, extrarange = 3, falloff_exponent = 1, frequency = 0.5, pressure_affected = FALSE, ignore_walls = TRUE, falloff_distance = 7) var/obj/singularity/bagulo = new(loc) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(!QDELETED(bagulo)) bagulo.expand(STAGE_TWO) bagulo.energy = 400 + // VOIDCREW EDIT END qdel(src) /obj/reality_tear/attack_tk(mob/user) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index b0e3a38e9d2..88613b394dc 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -57,9 +57,11 @@ /obj/singularity/Initialize(mapload, starting_energy) . = ..() + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(is_trader_outpost_protected(src)) // VOIDCREW log_game("OUTPOST PROTECTION: Prevented [name] from forming at [AREACOORD(src)].") return INITIALIZE_HINT_QDEL + // VOIDCREW EDIT END energy = starting_energy || energy @@ -163,8 +165,10 @@ return TRUE /obj/singularity/process(seconds_per_tick) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(neutralize_trader_outpost_hazard(src)) // VOIDCREW return PROCESS_KILL + // VOIDCREW EDIT END time_since_act += seconds_per_tick if(time_since_act < 2) return @@ -187,8 +191,10 @@ time_since_last_dissipiation -= dissipate_delay /obj/singularity/proc/expand(force_size) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(QDELETED(src)) // VOIDCREW: creation may have been suppressed. return FALSE + // VOIDCREW EDIT END var/temp_allowed_size = allowed_size if(force_size) @@ -319,8 +325,10 @@ return TRUE /obj/singularity/proc/consume(atom/thing) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(QDELETED(src) || is_trader_outpost_protected(src) || is_trader_outpost_protected(thing)) // VOIDCREW return + // VOIDCREW EDIT END if(istype(thing, /obj/item/storage/backpack/holding) && !consumed_supermatter && !collapsing) consume_boh(thing) return @@ -442,8 +450,10 @@ /obj/singularity/proc/combust_mobs() for(var/mob/living/carbon/burned_mob in urange(20, src, 1)) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(is_trader_outpost_protected(burned_mob)) // VOIDCREW continue + // VOIDCREW EDIT END burned_mob.visible_message( span_warning("[burned_mob]'s skin bursts into flame!"), span_userdanger("You feel an inner fire as your skin bursts into flames!") @@ -454,8 +464,10 @@ /obj/singularity/proc/mezzer() for(var/mob/living/carbon/stunned_mob in oviewers(8, src)) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(is_trader_outpost_protected(stunned_mob)) // VOIDCREW continue + // VOIDCREW EDIT END if(stunned_mob.stat == DEAD || stunned_mob.is_blind()) continue @@ -508,8 +520,10 @@ /obj/singularity/deadchat_controlled/Initialize(mapload, starting_energy) . = ..() + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(. == INITIALIZE_HINT_QDEL) // VOIDCREW return + // VOIDCREW EDIT END deadchat_plays(mode = DEMOCRACY_MODE) /// Special singularity spawned by being sucked into a black hole during emagged orion trail. @@ -518,14 +532,18 @@ /obj/singularity/orion/Initialize(mapload) . = ..() + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(. == INITIALIZE_HINT_QDEL) // VOIDCREW return + // VOIDCREW EDIT END var/datum/component/singularity/singularity = singularity_component.resolve() singularity?.grav_pull = 1 /obj/singularity/orion/process(seconds_per_tick) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(neutralize_trader_outpost_hazard(src)) // VOIDCREW return PROCESS_KILL + // VOIDCREW EDIT END if(SPT_PROB(0.5, seconds_per_tick)) mezzer() diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index 80eaa2ba523..8d47b21d3dc 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -71,11 +71,13 @@ update_appearance(UPDATE_OVERLAYS) // Connect to powernet if there's a cable under us + // VOIDCREW EDIT START - shuttle power integration: bind mapped SMES to the cable beneath it (voidcrew/edits/machinery/power.dm) if(!powernet) var/obj/structure/cable/C = locate() in loc if(!QDELETED(C)) cable_layer = C.cable_layer connect_to_network() + // VOIDCREW EDIT END /obj/machinery/power/smes/on_construction(mob/user) var/obj/structure/cable/C = locate() in loc diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 430aa94c238..55dc9398b48 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -40,9 +40,11 @@ /obj/energy_ball/Initialize(mapload, starting_energy = 50, is_miniball = FALSE) . = ..() + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(is_trader_outpost_protected(src)) // VOIDCREW log_game("OUTPOST PROTECTION: Prevented [name] from forming at [AREACOORD(src)].") return INITIALIZE_HINT_QDEL + // VOIDCREW EDIT END energy = starting_energy miniball = is_miniball @@ -66,8 +68,10 @@ return ..() /obj/energy_ball/process() + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(neutralize_trader_outpost_hazard(src)) // VOIDCREW return PROCESS_KILL + // VOIDCREW EDIT END if(orbiting) energy = 0 // ensure we dont have miniballs of miniballs else @@ -117,8 +121,10 @@ /obj/energy_ball/proc/can_move(turf/to_move) if (!to_move) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects return FALSE if(is_trader_outpost_protected(to_move)) // VOIDCREW + // VOIDCREW EDIT END return FALSE for (var/_thing in to_move) @@ -193,8 +199,10 @@ /obj/energy_ball/proc/dust_mobs(atom/A) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(is_trader_outpost_protected(src) || is_trader_outpost_protected(A)) // VOIDCREW return + // VOIDCREW EDIT END if(isliving(A)) var/mob/living/living = A if(living.incorporeal_move || HAS_TRAIT(living, TRAIT_GODMODE)) @@ -210,8 +218,10 @@ /proc/tesla_zap(atom/source, zap_range = 3, power, cutoff = 4e5, zap_flags = ZAP_DEFAULT_FLAGS, list/shocked_targets = list()) if(QDELETED(source)) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects return if(is_trader_outpost_protected(source)) // VOIDCREW + // VOIDCREW EDIT END return if(!(zap_flags & ZAP_ALLOW_DUPLICATES)) LAZYSET(shocked_targets, source, TRUE) //I don't want no null refs in my list yeah? @@ -256,8 +266,10 @@ //Darkness fucks oview up hard. I've tried dview() but it doesn't seem to work //I hate existence for(var/atom/A as anything in typecache_filter_list(oview(zap_range+2, source), things_to_shock)) + // VOIDCREW EDIT START - trade outpost protection: stop suppressed or protected hazards before further effects if(is_trader_outpost_protected(A)) // VOIDCREW continue + // VOIDCREW EDIT END if(!(zap_flags & ZAP_ALLOW_DUPLICATES) && LAZYACCESS(shocked_targets, A)) continue // NOTE: these type checks are safe because CURRENTLY the range family of procs returns turfs in least to greatest distance order diff --git a/code/modules/power/turbine/turbine.dm b/code/modules/power/turbine/turbine.dm index 9c43941ef74..c864dd613c5 100644 --- a/code/modules/power/turbine/turbine.dm +++ b/code/modules/power/turbine/turbine.dm @@ -18,8 +18,7 @@ var/obj/item/turbine_parts/part_path ///The gas mixture this turbine part is storing var/datum/gas_mixture/machine_gasmix - ///TRUE while a shuttle move is relocating us; Moved() skips its teardown so the assembly arrives intact (VOIDCREW EDIT ADDITION) - var/shuttle_moving = FALSE + /obj/machinery/power/turbine/Initialize(mapload, gas_theoretical_volume) . = ..() @@ -239,7 +238,7 @@ /obj/machinery/power/turbine/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) . = ..() if(shuttle_moving) // VOIDCREW EDIT ADDITION - a shuttle move carries the whole assembly together; see onShuttleMove below - return + return // VOIDCREW EDIT: shuttle turbine integration: preserve the assembly throughout movement (voidcrew/edits/machinery/turbine_shuttle.dm) set_panel_open(TRUE) update_appearance(UPDATE_OVERLAYS) deactivate_parts() @@ -251,34 +250,6 @@ if(gone == installed_part) installed_part = null -// VOIDCREW EDIT ADDITION START - turbines survive shuttle moves assembled. -// Upstream tears the machine down on any Moved() because a single relocated turbine -// leaves its partners behind. A shuttle move relocates all three parts together with -// their relative positions (and any rotation) preserved, so that teardown just -// unscrewed and unlinked every ship turbine on every dock, undock and transit. -/obj/machinery/power/turbine/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock) - shuttle_moving = TRUE - . = ..() - shuttle_moving = FALSE - -/obj/machinery/power/turbine/inlet_compressor/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) - . = ..() - input_turf = null //stale ref to the old site; compress_gases() lazily reacquires from the new location - -/obj/machinery/power/turbine/turbine_outlet/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) - . = ..() - output_turf = null //stale ref to the old site; expel_gases() lazily reacquires from the new location - -/obj/machinery/power/turbine/core_rotor/lateShuttleMove(turf/oldT, list/movement_force, move_dir) - . = ..() - if(!all_parts_connected) - return - //the cable under us can end up on a rebuilt powernet after the move (rotated docks - //repropagate in /obj/structure/cable/lateShuttleMove); rebind to whatever is there now - disconnect_from_network() - connect_to_network() -// VOIDCREW EDIT ADDITION END - /obj/machinery/power/turbine/item_interaction(mob/living/user, obj/item/turbine_parts/object, list/modifiers) . = NONE if(!istype(object, part_path)) diff --git a/code/modules/reagents/chemistry/equilibrium.dm b/code/modules/reagents/chemistry/equilibrium.dm index c429f5254d6..489d5918297 100644 --- a/code/modules/reagents/chemistry/equilibrium.dm +++ b/code/modules/reagents/chemistry/equilibrium.dm @@ -105,7 +105,7 @@ return FALSE //To prevent reactions outside of the pH window from starting. - //VOIDCREW EDIT: only recipes that opt in with REACTION_USES_PURITY are gated on pH. + //VOIDCREW EDIT START: only recipes that opt in with REACTION_USES_PURITY are gated on pH. - Voidcrew chemistry: apply pH gating only to recipes opting into purity (voidcrew/modules/chemistry) if((reaction.reaction_flags & REACTION_USES_PURITY) && (holder.ph < (reaction.optimal_ph_min - reaction.determin_ph_range) || holder.ph > (reaction.optimal_ph_max + reaction.determin_ph_range))) return FALSE //VOIDCREW EDIT END @@ -269,7 +269,7 @@ //Begin checks //Calculate DeltapH (Deviation of pH from optimal) - //VOIDCREW EDIT: pH only drives purity for recipes that opt in with REACTION_USES_PURITY. + //VOIDCREW EDIT START: pH only drives purity for recipes that opt in with REACTION_USES_PURITY. - Voidcrew chemistry: apply pH gating only to recipes opting into purity (voidcrew/modules/chemistry) //Everything else reacts at full purity whatever the mixture's pH happens to be, so a //recipe's optimal band doesn't have to contain neutral for the recipe to be usable. if(!(reaction.reaction_flags & REACTION_USES_PURITY)) @@ -348,13 +348,14 @@ //Calculate how much product to make and how much reactant to remove factors.. var/required_amount + // VOIDCREW EDIT REMOVAL - Voidcrew chemistry: reset pH adjustment within each reagent loop (voidcrew/modules/chemistry) for(var/datum/reagent/requirement as anything in reaction.required_reagents) required_amount = reaction.required_reagents[requirement] if(!holder.remove_reagent(requirement, delta_chem_factor * required_amount)) to_delete = TRUE return //Apply pH changes - var/pH_adjust + var/pH_adjust // VOIDCREW EDIT: Voidcrew chemistry: reset pH adjustment within each reagent loop (voidcrew/modules/chemistry) if(reaction.reaction_flags & REACTION_PH_VOL_CONSTANT) pH_adjust = ((delta_chem_factor * required_amount) / target_vol) * (reaction.H_ion_release * h_ion_mod) else //Default adds pH independant of volume @@ -371,7 +372,7 @@ return //Apply pH changes - var/pH_adjust + var/pH_adjust // VOIDCREW EDIT: Voidcrew chemistry: reset pH adjustment within each reagent loop (voidcrew/modules/chemistry) if(reaction.reaction_flags & REACTION_PH_VOL_CONSTANT) pH_adjust = (step_add / target_vol) * (reaction.H_ion_release * h_ion_mod) else diff --git a/code/modules/reagents/chemistry/holder/holder.dm b/code/modules/reagents/chemistry/holder/holder.dm index 309bfe278f1..2839901945e 100644 --- a/code/modules/reagents/chemistry/holder/holder.dm +++ b/code/modules/reagents/chemistry/holder/holder.dm @@ -204,7 +204,7 @@ /datum/reagents/proc/add_reagent_list(list/list_reagents, list/data = null, added_purity = null, temperature = DEFAULT_REAGENT_TEMPERATURE) for(var/r_id in list_reagents) var/amt = list_reagents[r_id] - add_reagent(r_id, amt, data, reagtemp = temperature, added_purity = added_purity) + add_reagent(r_id, amt, data, reagtemp = temperature, added_purity = added_purity) // VOIDCREW EDIT: circuits chemistry integration: preserve supplied reagent temperature (voidcrew/modules/circuits) /** * Removes a specific reagent. can supress reactions if needed @@ -585,8 +585,9 @@ var/list/deleted_reagents = list() var/chem_index = 1 var/num_reagents = length(cached_reagents) - var/reagent_volume = 0 + var/reagent_volume = 0 // VOIDCREW EDIT: circuits chemistry integration: preserve supplied reagent temperature (voidcrew/modules/circuits) var/total_ph = 0 + // VOIDCREW EDIT REMOVAL - circuits chemistry integration: preserve supplied reagent temperature (voidcrew/modules/circuits) . = 0 //responsible for removing reagents and computing total ph & volume diff --git a/code/modules/reagents/chemistry/holder/reactions.dm b/code/modules/reagents/chemistry/holder/reactions.dm index ee0f9906fa4..739f71f8a84 100644 --- a/code/modules/reagents/chemistry/holder/reactions.dm +++ b/code/modules/reagents/chemistry/holder/reactions.dm @@ -72,7 +72,7 @@ if(isliving(cached_my_atom) && !reaction.mob_react) //Makes it so certain chemical reactions don't occur in mobs continue - //VOIDCREW EDIT ADDITION: keeps mob-spawning mixtures out of plant chemistry + //VOIDCREW EDIT ADDITION START: keeps mob-spawning mixtures out of plant chemistry - Voidcrew chemistry: apply pH gating only to recipes opting into purity (voidcrew/modules/chemistry) if((reaction.reaction_flags & REACTION_NOT_IN_PLANTS) && istype(cached_my_atom, /obj/item/food/grown)) continue //VOIDCREW EDIT END @@ -91,7 +91,7 @@ LAZYADD(failed_but_capable_reactions, reaction) continue - //VOIDCREW EDIT: only recipes that opt in with REACTION_USES_PURITY are gated on pH. + //VOIDCREW EDIT START: only recipes that opt in with REACTION_USES_PURITY are gated on pH. - Voidcrew chemistry: apply pH gating only to recipes opting into purity (voidcrew/modules/chemistry) if((reaction.reaction_flags & REACTION_USES_PURITY) && (ph < reaction.optimal_ph_min - reaction.determin_ph_range && ph > reaction.optimal_ph_max + reaction.determin_ph_range)) LAZYADD(failed_but_capable_reactions, reaction) continue @@ -150,7 +150,7 @@ else if(reaction.required_temp < chem_temp) return TRUE - //VOIDCREW EDIT: a reaction that doesn't opt into pH mechanics is never held back by pH, + //VOIDCREW EDIT START: a reaction that doesn't opt into pH mechanics is never held back by pH, - Voidcrew chemistry: apply pH gating only to recipes opting into purity (voidcrew/modules/chemistry) //so it's always eligible to restart once its other conditions are met. if(reaction.reaction_flags & REACTION_USES_PURITY) if(((ph >= (reaction.optimal_ph_min - reaction.determin_ph_range)) && (ph <= (reaction.optimal_ph_max + reaction.determin_ph_range)))) diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm index 04da45a7af0..32da0432859 100644 --- a/code/modules/reagents/chemistry/machinery/chem_heater.dm +++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm @@ -255,7 +255,7 @@ if(reagent.purity < equilibrium.reaction.purity_min) purity_alert = ENABLE_FLASHING//Because 0 is seen as null danger = TRUE - //VOIDCREW EDIT: only alarm on pH for recipes that actually care about it. Without + //VOIDCREW EDIT START: only alarm on pH for recipes that actually care about it. Without - Voidcrew chemistry: apply pH gating only to recipes opting into purity (voidcrew/modules/chemistry) //REACTION_USES_PURITY the mixture's pH has no effect on the reaction, so flashing the //meter at the chemist would be warning them about nothing. if(flashing != ENABLE_FLASHING && (equilibrium.reaction.reaction_flags & REACTION_USES_PURITY))//So that the pH meter flashes for ANY reactions out of optimal diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 2cfd64ad481..acc837451a2 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -413,9 +413,11 @@ var/turf/open/exposed_open_turf = exposed_turf exposed_open_turf.MakeSlippery(wet_setting=TURF_WET_ICE, min_wet_time=100, wet_time_to_add=reac_volume SECONDS) // Is less effective in high pressure/high heat capacity environments. More effective in low pressure. var/datum/gas_mixture/turf_air = exposed_open_turf.return_air() // VOIDCREW EDIT: written to below; leaves the shared planetary mix + // VOIDCREW EDIT START - planetary shared air: materialize a private mixture before writes (voidcrew/edits/planetary_shared_air.dm) var/temperature = turf_air.temperature var/heat_capacity = turf_air.heat_capacity() turf_air.temperature = max(turf_air.temperature - ((temperature - TCMB) * (heat_capacity * reac_volume * specific_heat) / (heat_capacity + reac_volume * specific_heat)) / heat_capacity, TCMB) // Exchanges environment temperature with reagent. Reagent is at 2.7K with a heat capacity of 40J per unit. + // VOIDCREW EDIT END if(reac_volume < 5) return for(var/mob/living/basic/slime/exposed_slime in exposed_turf) diff --git a/code/modules/reagents/chemistry/reagents/reaction_agents_reagents.dm b/code/modules/reagents/chemistry/reagents/reaction_agents_reagents.dm index 6480329377f..185d72041ea 100644 --- a/code/modules/reagents/chemistry/reagents/reaction_agents_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/reaction_agents_reagents.dm @@ -18,7 +18,7 @@ /datum/reagent/reaction_agent/acidic_buffer name = "Strong Acidic Buffer" - description = "An industrial acidic buffer, used to lower the pH of a solution." + description = "An industrial acidic buffer, used to lower the pH of a solution." // VOIDCREW EDIT: Voidcrew chemistry: describe industrial buffers without self-consumption instructions (voidcrew/modules/chemistry) color = "#fbc314" ph = 0 inverse_chem = null @@ -50,7 +50,7 @@ /datum/reagent/reaction_agent/basic_buffer name = "Strong Basic Buffer" - description = "An industrial alkaline buffer, used to raise the pH of a solution." + description = "An industrial alkaline buffer, used to raise the pH of a solution." // VOIDCREW EDIT: Voidcrew chemistry: describe industrial buffers without self-consumption instructions (voidcrew/modules/chemistry) color = "#3853a4" ph = 14 inverse_chem = null diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 57297f6dd8c..f88183f2ed1 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -270,7 +270,7 @@ /obj/item/reagent_containers/proc/on_reagent_change(datum/reagents/holder, ...) SIGNAL_HANDLER update_appearance() - //VOIDCREW EDIT ADDITION: lets reagents react to their own container changing (Australium) + //VOIDCREW EDIT ADDITION START: lets reagents react to their own container changing (Australium) - Voidcrew reagents: reprocess container-sensitive reagents after a container change (voidcrew/modules/chemistry) reagent_processing() //VOIDCREW EDIT END diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm index c731d076617..3c2b7bb7d34 100644 --- a/code/modules/reagents/reagent_containers/dropper.dm +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -65,7 +65,7 @@ trans = round(reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user), CHEMICAL_VOLUME_ROUNDING) to_chat(user, span_notice("You transfer [trans] unit\s of the solution.")) - if(trans) + if(trans) // VOIDCREW EDIT: Voidcrew reagent audio: run after-pour feedback only after a successful transfer (voidcrew/modules/chemistry) after_pour(trans, target, user) //VOIDCREW EDIT ADDITION: dropper sounds update_appearance() target.update_appearance() diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index b5b9350b432..62d49f69ed9 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -142,7 +142,7 @@ update_appearance() /obj/item/reagent_containers/hypospray/medipen/attack_self(mob/user) - if(user.can_perform_action(src, FORBID_TELEKINESIS_REACH|ALLOW_RESTING|ALLOW_SOFT_CRIT)) + if(user.can_perform_action(src, FORBID_TELEKINESIS_REACH|ALLOW_RESTING|ALLOW_SOFT_CRIT)) // VOIDCREW EDIT: soft crit interaction: permit selected actions while retaining other incapacitation checks (voidcrew/edits/mobs/softcrit_interaction.dm) inject(user, user) /obj/item/reagent_containers/hypospray/medipen/update_icon_state() diff --git a/code/modules/spells/spell_types/jaunt/bloodcrawl.dm b/code/modules/spells/spell_types/jaunt/bloodcrawl.dm index 2b24136b9fd..1579cb2ace9 100644 --- a/code/modules/spells/spell_types/jaunt/bloodcrawl.dm +++ b/code/modules/spells/spell_types/jaunt/bloodcrawl.dm @@ -52,19 +52,10 @@ /// Returns a nearby blood decal, or null if there aren't any /datum/action/cooldown/spell/jaunt/bloodcrawl/proc/find_nearby_blood(turf/origin) for(var/obj/effect/decal/cleanable/blood_nearby in range(blood_radius, origin)) - if(is_valid_blood_destination(origin, blood_nearby)) + if(is_valid_blood_destination(origin, blood_nearby)) // VOIDCREW EDIT: jaunt destination integration: validate teleport permission before and after the wind-up (voidcrew/edits/spells/jaunt_destinations.dm) return blood_nearby return null -/// Blood pools can be across an area boundary, beyond the holder's phased movement checks. -/datum/action/cooldown/spell/jaunt/bloodcrawl/proc/is_valid_blood_destination(atom/origin, obj/effect/decal/cleanable/blood) - if(QDELETED(blood) || !blood.can_bloodcrawl_in()) - return FALSE - var/turf/destination = get_turf(blood) - if(!destination || (destination.turf_flags & NOJAUNT) || SSmapping.level_trait(destination.z, ZTRAIT_NOPHASE)) - return FALSE - return check_teleport_valid(origin, destination, TELEPORT_CHANNEL_MAGIC) - /** * Attempts to enter or exit the passed blood pool. * Returns TRUE if we successfully entered or exited said pool, FALSE otherwise @@ -84,8 +75,10 @@ * If forced is TRUE, it will override enter_blood_time. */ /datum/action/cooldown/spell/jaunt/bloodcrawl/proc/try_enter_jaunt(obj/effect/decal/cleanable/blood, mob/living/jaunter, forced = FALSE) + // VOIDCREW EDIT START - jaunt destination integration: validate teleport permission before and after the wind-up (voidcrew/edits/spells/jaunt_destinations.dm) if(!is_valid_blood_destination(jaunter, blood)) return FALSE + // VOIDCREW EDIT END if(!forced) if(enter_blood_time > 0 SECONDS) blood.visible_message(span_warning("[jaunter] starts to sink into [blood]!")) @@ -93,8 +86,10 @@ return FALSE // The pool or its teleport permissions may have changed during the wind-up. + // VOIDCREW EDIT START - jaunt destination integration: validate teleport permission before and after the wind-up (voidcrew/edits/spells/jaunt_destinations.dm) if(!is_valid_blood_destination(jaunter, blood)) return FALSE + // VOIDCREW EDIT END // The actual turf we enter var/turf/jaunt_turf = get_turf(blood) @@ -129,8 +124,10 @@ * If forced is TRUE, it will override exit_blood_time, and if we're currently consuming someone. */ /datum/action/cooldown/spell/jaunt/bloodcrawl/proc/try_exit_jaunt(obj/effect/decal/cleanable/blood, mob/living/jaunter, forced = FALSE) + // VOIDCREW EDIT START - jaunt destination integration: validate teleport permission before and after the wind-up (voidcrew/edits/spells/jaunt_destinations.dm) if(!is_valid_blood_destination(jaunter, blood)) return FALSE + // VOIDCREW EDIT END if(!forced) if(HAS_TRAIT(jaunter, TRAIT_NO_TRANSFORM)) to_chat(jaunter, span_warning("You cannot exit yet!!")) @@ -142,8 +139,10 @@ return FALSE // Moving into a NOTELEPORT area makes eject_jaunter scatter us across the z-level. + // VOIDCREW EDIT START - jaunt destination integration: validate teleport permission before and after the wind-up (voidcrew/edits/spells/jaunt_destinations.dm) if(!is_valid_blood_destination(jaunter, blood)) return FALSE + // VOIDCREW EDIT END if(!exit_jaunt(jaunter, get_turf(blood))) return FALSE diff --git a/code/modules/spells/spell_types/jaunt/ethereal_jaunt.dm b/code/modules/spells/spell_types/jaunt/ethereal_jaunt.dm index fa23024b6db..1a9a429884a 100644 --- a/code/modules/spells/spell_types/jaunt/ethereal_jaunt.dm +++ b/code/modules/spells/spell_types/jaunt/ethereal_jaunt.dm @@ -20,25 +20,7 @@ var/obj/effect/jaunt_out_type = /obj/effect/temp_visual/wizard/out /// VOIDCREW EDIT: physical exit references travel with the deck during shuttle movement. var/list/exit_point_list - var/obj/effect/abstract/jaunt_exit/start_point_anchor -// VOIDCREW EDIT: reclaim reference effects even when the action loses its owner first. -/datum/action/cooldown/spell/jaunt/ethereal_jaunt/Destroy() - clear_exit_points() - return ..() - -/datum/action/cooldown/spell/jaunt/ethereal_jaunt/proc/clear_exit_points() - QDEL_NULL(start_point_anchor) - QDEL_LIST(exit_point_list) - exit_point_list = null - -/// An invisible location reference, carried by ordinary shuttle movement and rotation. -/obj/effect/abstract/jaunt_exit - name = "jaunt return reference" - icon = null - invisibility = INVISIBILITY_ABSTRACT - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - anchored = TRUE /datum/action/cooldown/spell/jaunt/ethereal_jaunt/enter_jaunt(mob/living/jaunter, turf/loc_override) . = ..() @@ -72,10 +54,10 @@ // VOIDCREW EDIT: keep the starting floor attached to its moving ship. clear_exit_points() - start_point_anchor = new(get_turf(holder)) + start_point_anchor = new(get_turf(holder)) // VOIDCREW EDIT: jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) LAZYINITLIST(exit_point_list) RegisterSignal(holder, COMSIG_MOVABLE_MOVED, PROC_REF(update_exit_point), target) - addtimer(CALLBACK(src, PROC_REF(stop_jaunt), cast_on, holder, start_point_anchor), jaunt_duration) + addtimer(CALLBACK(src, PROC_REF(stop_jaunt), cast_on, holder, start_point_anchor), jaunt_duration) // VOIDCREW EDIT: jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) /** * The stopping of the jaunt. @@ -86,7 +68,7 @@ * - immediately, if jaunt_in_time >= 2.5 seconds * - 2.5 seconds - jaunt_in_time seconds otherwise */ -/datum/action/cooldown/spell/jaunt/ethereal_jaunt/proc/stop_jaunt(mob/living/cast_on, obj/effect/dummy/phased_mob/spell_jaunt/holder, atom/start_point) +/datum/action/cooldown/spell/jaunt/ethereal_jaunt/proc/stop_jaunt(mob/living/cast_on, obj/effect/dummy/phased_mob/spell_jaunt/holder, atom/start_point) // VOIDCREW EDIT: jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) if(QDELETED(cast_on) || QDELETED(holder) || QDELETED(src)) return @@ -100,26 +82,30 @@ var/turf/found_exit // VOIDCREW EDIT: resolve each exit where its original deck tile is now. for(var/obj/effect/abstract/jaunt_exit/exit_anchor as anything in exit_point_list) + // VOIDCREW EDIT START - jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) var/turf/possible_exit = get_turf(exit_anchor) if(!possible_exit || possible_exit.is_blocked_turf_ignore_climbable()) + // VOIDCREW EDIT END continue found_exit = possible_exit break // No valid exit was found if(!found_exit) - var/turf/start_turf = get_turf(start_point) || get_turf(holder) + var/turf/start_turf = get_turf(start_point) || get_turf(holder) // VOIDCREW EDIT: jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) // It's possible no exit was found, because we literally didn't even move - if(get_turf(cast_on) != start_turf) + if(get_turf(cast_on) != start_turf) // VOIDCREW EDIT: jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) to_chat(cast_on, span_danger("Unable to find an unobstructed space, you find yourself ripped back to where you started.")) // Either way, default to where we started - found_exit = start_turf + found_exit = start_turf // VOIDCREW EDIT: jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) - clear_exit_points() + clear_exit_points() // VOIDCREW EDIT: jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) holder.forceMove(found_exit) // Movement callbacks may eject, transform, or remove the caster's action. + // VOIDCREW EDIT START - jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) if(QDELETED(src) || QDELETED(cast_on) || QDELETED(holder) || cast_on.loc != holder || holder.jaunter != cast_on) return + // VOIDCREW EDIT END // VOIDCREW EDIT: synchronous movement callbacks can relocate the entire deck. found_exit = get_turf(holder) do_steam_effects(found_exit) @@ -143,9 +129,11 @@ /datum/action/cooldown/spell/jaunt/ethereal_jaunt/proc/do_jaunt_in(mob/living/cast_on, obj/effect/dummy/phased_mob/spell_jaunt/holder, turf/final_point) if(QDELETED(cast_on) || QDELETED(holder) || QDELETED(src)) return + // VOIDCREW EDIT START - jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) if(cast_on.loc != holder || holder.jaunter != cast_on) qdel(holder) return + // VOIDCREW EDIT END // VOIDCREW EDIT: the return animation follows its holder through ship transit. final_point = get_turf(holder) @@ -168,9 +156,11 @@ /datum/action/cooldown/spell/jaunt/ethereal_jaunt/proc/end_jaunt(mob/living/cast_on, obj/effect/dummy/phased_mob/spell_jaunt/holder, turf/final_point) if(QDELETED(cast_on) || QDELETED(holder) || QDELETED(src)) return + // VOIDCREW EDIT START - jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) if(cast_on.loc != holder || holder.jaunter != cast_on) qdel(holder) return + // VOIDCREW EDIT END ADD_TRAIT(cast_on, TRAIT_NO_TRANSFORM, REF(src)) exit_jaunt(cast_on) @@ -180,18 +170,11 @@ // VOIDCREW EDIT: check the floor we actually emerged on, never the old deck. final_point = get_turf(cast_on) - if(final_point?.density) + if(final_point?.density) // VOIDCREW EDIT: jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) var/list/aside_turfs = get_adjacent_open_turfs(final_point) if(length(aside_turfs)) cast_on.forceMove(pick(aside_turfs)) -/// Removal, body changes and forced ejection can end the return animation early. -/datum/action/cooldown/spell/jaunt/ethereal_jaunt/on_jaunt_exited(obj/effect/dummy/phased_mob/jaunt, mob/living/unjaunter) - UnregisterSignal(jaunt, COMSIG_MOVABLE_MOVED) - clear_exit_points() - REMOVE_TRAIT(unjaunter, TRAIT_IMMOBILIZED, REF(src)) - return ..() - /** * Updates the exit point of the jaunt * @@ -208,9 +191,9 @@ return // VOIDCREW EDIT: retain the same bounded history using movable references. var/obj/effect/abstract/jaunt_exit/exit_anchor = new(location) - exit_point_list.Insert(1, exit_anchor) + exit_point_list.Insert(1, exit_anchor) // VOIDCREW EDIT: jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) if(length(exit_point_list) >= 5) - qdel(exit_point_list[5]) + qdel(exit_point_list[5]) // VOIDCREW EDIT: jaunt destination integration: carry return anchors with moving decks and stop interrupted returns (voidcrew/edits/spells/jaunt_destinations.dm) exit_point_list.Cut(5) /// Does some steam effects from the jaunt at passed loc. diff --git a/code/modules/spells/spell_types/tower_of_babel.dm b/code/modules/spells/spell_types/tower_of_babel.dm index a765dd4c2a7..0da472e71ae 100644 --- a/code/modules/spells/spell_types/tower_of_babel.dm +++ b/code/modules/spells/spell_types/tower_of_babel.dm @@ -36,7 +36,7 @@ GLOBAL_DATUM(tower_of_babel, /datum/tower_of_babel) // carbon_list, not player_list: player_list only holds mobs with a client attached, and a // dead player who ghosted leaves their cursed body clientless. Miss the body here and they // revive still babbling, with the cure already destroyed. - for(var/mob/living/carbon/target in GLOB.carbon_list) + for(var/mob/living/carbon/target in GLOB.carbon_list) // VOIDCREW EDIT: Voidcrew spell cleanup: cure clientless and mindless cursed bodies (voidcrew/edits/spells) cure_curse_of_babel(target) /datum/tower_of_babel/proc/handle_new_player(datum/source, mob/living/new_crewmember, rank) @@ -65,8 +65,9 @@ GLOBAL_DATUM(tower_of_babel, /datum/tower_of_babel) // A body whose mind left mid-curse (respawn, borging, mind swap) has no mind to carry // the babel trait but still holds the permanent status effect. Cure it unconditionally; // the minded early-out below only protects people who were never cursed by this source. - if(to_cure.mind && !HAS_TRAIT_FROM(to_cure.mind, TRAIT_TOWER_OF_BABEL, TRAUMA_TRAIT)) + if(to_cure.mind && !HAS_TRAIT_FROM(to_cure.mind, TRAIT_TOWER_OF_BABEL, TRAUMA_TRAIT)) // VOIDCREW EDIT: Voidcrew spell cleanup: cure clientless and mindless cursed bodies (voidcrew/edits/spells) return + // VOIDCREW EDIT REMOVAL - Voidcrew spell cleanup: cure clientless and mindless cursed bodies (voidcrew/edits/spells) to_cure.remove_status_effect(/datum/status_effect/tower_of_babel/magical) /client/proc/tower_of_babel() diff --git a/voidcrew/edits/area_lifecycle.dm b/voidcrew/edits/area_lifecycle.dm new file mode 100644 index 00000000000..4f2b152ea0b --- /dev/null +++ b/voidcrew/edits/area_lifecycle.dm @@ -0,0 +1,54 @@ +/** + * Drops the trailing all-empty z entries off turfs_to_uncontain_by_zlevel. + * + * `length(turfs_to_uncontain_by_zlevel)` is the cheap "is there anything pending" test that + * get_zlevel_turf_lists(), get_turfs_by_zlevel() and has_contained_turfs() all branch on, so + * an area whose cut lists have all been applied has to shrink back to zero or those hot + * readers keep paying to rediscover that there is nothing to do. + * + * Only trailing empties are dropped - a populated z anywhere in the list stops the walk - so + * this can never discard a pending cut. Callers that are mid-iteration over the list must + * call it AFTER the loop: it shortens the list, and DM snapshots a `1 to length()` bound. + */ +/area/proc/trim_trailing_empty_uncontain_lists() + var/current_length = length(turfs_to_uncontain_by_zlevel) + var/new_length = current_length + // Walk backwards thru the list + for (var/i in current_length to 0 step -1) + if (i && length(turfs_to_uncontain_by_zlevel[i])) + break // Stop the moment we find a useful list + new_length = i + + if (new_length < current_length) + turfs_to_uncontain_by_zlevel.len = new_length + +/** + * VOIDCREW ADDITION: TRUE when a turf really does still stand in this area. + * + * has_contained_turfs() above answers from list LENGTHS - `turfs_by_zlevel` minus the + * pending `turfs_to_uncontain_by_zlevel` - and that arithmetic only balances if every entry + * added to one list eventually gets its counterpart applied against the other. + * + * It did not. SSarea_contents used to empty an area's whole cut list in a single assignment + * once its drain loop finished, and change_area() appends to that same list during every + * MC_TICK_CHECK yield the drain takes. Anything that landed mid-drain was discarded without + * ever being applied, leaving one PHANTOM entry in `turfs_by_zlevel` per lost cut - and + * nothing that could ever remove it. An area in that state answers "still occupied" forever + * even once every real turf has been handed back, which is exactly the state a torn-down + * site's area is in, and why reap_emptied_areas() could not collect them. + * + * That discard is fixed (area_contents.dm drains one z at a time and clears only what it + * just applied), so this should now find residue only from paths that hand-roll the + * bookkeeping. It stays as the load-bearing safety for reap_emptied_areas(): reparenting + * live ground out from under a co-tenant is unrecoverable, and a length comparison is not + * worth that risk. + * + * Cheap in the case it exists for: get_zlevel_turf_lists() cannonizes first, which drops + * every properly-returned turf, so what is walked here is just the residue. + */ +/area/proc/has_resident_turfs() + for (var/list/zlevel_turfs as anything in get_zlevel_turf_lists()) + for (var/turf/resident as anything in zlevel_turfs) + if (resident?.loc == src) + return TRUE + return FALSE diff --git a/voidcrew/edits/contained_lights.dm b/voidcrew/edits/contained_lights.dm new file mode 100644 index 00000000000..3ddd7a758ff --- /dev/null +++ b/voidcrew/edits/contained_lights.dm @@ -0,0 +1,12 @@ +/** + * Makes every overlay light we're carrying work out where it is again. + * + * Overlay lights only re-resolve their holder when they personally move, so gear that + * was in someone's hands or pockets while they sat inside a machine never learns that + * they climbed out of it, and stays dark until it is dropped and picked back up. + * Call this after moving a mob out of something it was inside of. + */ +/atom/movable/proc/recheck_contained_lights() + for(var/atom/movable/carried as anything in get_all_contents()) + var/datum/component/overlay_lighting/light = carried.GetComponent(/datum/component/overlay_lighting) + light?.recheck_holder() diff --git a/voidcrew/edits/grass_lifecycle.dm b/voidcrew/edits/grass_lifecycle.dm new file mode 100644 index 00000000000..6b87884efdb --- /dev/null +++ b/voidcrew/edits/grass_lifecycle.dm @@ -0,0 +1,8 @@ +// VOIDCREW EDIT ADDITION START: /turf/open/misc/grass registers itself above but is a +// /turf/open/misc, so /turf/open/floor/Destroy()'s removal never applied to it and the +// registration was one-way even on a clean ChangeTurf. +/turf/open/misc/grass/Destroy() + if(length(GLOB.station_turfs) && !map_region_for_turf(src)) + GLOB.station_turfs -= src + return ..() +// VOIDCREW EDIT END diff --git a/voidcrew/edits/machinery/firedoor_shuttle.dm b/voidcrew/edits/machinery/firedoor_shuttle.dm new file mode 100644 index 00000000000..ed5cbbb3289 --- /dev/null +++ b/voidcrew/edits/machinery/firedoor_shuttle.dm @@ -0,0 +1,21 @@ +/// Called right before the shuttle physically moves - suppress atmosphere checks +/obj/machinery/door/firedoor/proc/on_shuttle_move_start(datum/source, turf/new_turf, rotation, move_mode, obj/docking_port/mobile/moving_dock) + SIGNAL_HANDLER + ignore_alarms = TRUE + +/// Called after shuttle move completes - re-enable checks and verify atmosphere +/obj/machinery/door/firedoor/proc/on_shuttle_move_complete(datum/source, turf/old_turf) + SIGNAL_HANDLER + ignore_alarms = FALSE + // Re-check atmosphere after it stabilizes to catch any real hazards + addtimer(CALLBACK(src, PROC_REF(post_shuttle_move_check)), 0.5 SECONDS) + +/// Re-evaluate atmospheric conditions after a shuttle move to catch real hazards +/obj/machinery/door/firedoor/proc/post_shuttle_move_check() + if(QDELETED(src)) + return + for(var/dir in GLOB.cardinals) + var/turf/checked_turf = get_step(get_turf(src), dir) + if(!checked_turf || !isopenturf(checked_turf)) + continue + process_results(checked_turf) diff --git a/voidcrew/edits/machinery/turbine_shuttle.dm b/voidcrew/edits/machinery/turbine_shuttle.dm new file mode 100644 index 00000000000..71cd47bbe8f --- /dev/null +++ b/voidcrew/edits/machinery/turbine_shuttle.dm @@ -0,0 +1,31 @@ +/obj/machinery/power/turbine + ///TRUE while a shuttle move is relocating us; Moved() skips its teardown so the assembly arrives intact (VOIDCREW EDIT ADDITION) + var/shuttle_moving = FALSE + +// VOIDCREW EDIT ADDITION START - turbines survive shuttle moves assembled. +// Upstream tears the machine down on any Moved() because a single relocated turbine +// leaves its partners behind. A shuttle move relocates all three parts together with +// their relative positions (and any rotation) preserved, so that teardown just +// unscrewed and unlinked every ship turbine on every dock, undock and transit. +/obj/machinery/power/turbine/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock) + shuttle_moving = TRUE + . = ..() + shuttle_moving = FALSE + +/obj/machinery/power/turbine/inlet_compressor/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) + . = ..() + input_turf = null //stale ref to the old site; compress_gases() lazily reacquires from the new location + +/obj/machinery/power/turbine/turbine_outlet/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) + . = ..() + output_turf = null //stale ref to the old site; expel_gases() lazily reacquires from the new location + +/obj/machinery/power/turbine/core_rotor/lateShuttleMove(turf/oldT, list/movement_force, move_dir) + . = ..() + if(!all_parts_connected) + return + //the cable under us can end up on a rebuilt powernet after the move (rotated docks + //repropagate in /obj/structure/cable/lateShuttleMove); rebind to whatever is there now + disconnect_from_network() + connect_to_network() +// VOIDCREW EDIT ADDITION END diff --git a/voidcrew/edits/mobs/healing_gland.dm b/voidcrew/edits/mobs/healing_gland.dm new file mode 100644 index 00000000000..cece9485c9f --- /dev/null +++ b/voidcrew/edits/mobs/healing_gland.dm @@ -0,0 +1,13 @@ +// VOIDCREW ADD START +/obj/item/organ/heart/gland/heal/on_mob_remove(mob/living/carbon/gland_owner, special, movement_flags) + healing_generation++ + return ..() + +/// Removal invalidates pending work even if this gland returns to the same body. +/obj/item/organ/heart/gland/heal/proc/can_finish_healing(mob/living/carbon/recipient, generation) + return !QDELETED(src) && !QDELETED(recipient) && owner == recipient && active && generation == healing_generation && ownerCheck() +// VOIDCREW ADD END + +/obj/item/organ/heart/gland/heal + // VOIDCREW ADD: delayed healing belongs to one continuous implantation. + var/healing_generation = 0 diff --git a/voidcrew/edits/mobs/internals_logging.dm b/voidcrew/edits/mobs/internals_logging.dm new file mode 100644 index 00000000000..e049cebc224 --- /dev/null +++ b/voidcrew/edits/mobs/internals_logging.dm @@ -0,0 +1,10 @@ +/** + * Records why an open air tank was cut off, plus everything invalid_internals() reads. + * Cutoffs have been reported during shuttle docking with the tank still slotted and the mask + * still worn, which no call path explains - this dumps the state at the moment it happens. + * Goes to the shuttle log so it lands next to the dock entries for the same tick. + */ +/mob/living/carbon/proc/log_internals_cutoff(reason) + var/obj/item/tank/closing = external || internal + var/atom/tank_loc = closing.loc + log_shuttle("INTERNALS CUTOFF: [key_name(src)] at [AREACOORD(src)] reason=[reason] tank=[closing.type] ([external ? "external" : "internal"]) tank_loc=[tank_loc] ([tank_loc?.type]) loc_is_mob=[tank_loc == src ? "yes" : "NO"] apparatus=[can_breathe_internals() || "NONE"] mask=[wear_mask ? "[wear_mask.type] up=[wear_mask.up] flags=[wear_mask.clothing_flags]" : "NONE"] head=[head ? "[head.type] flags=[head.clothing_flags]" : "NONE"] tube=[can_breathe_tube() ? "yes" : "no"] stat=[stat]") diff --git a/voidcrew/edits/mobs/legion_reach.dm b/voidcrew/edits/mobs/legion_reach.dm new file mode 100644 index 00000000000..16e359d0aa9 --- /dev/null +++ b/voidcrew/edits/mobs/legion_reach.dm @@ -0,0 +1,24 @@ +/** + * Walks the line from the owner to `destination` and returns the last turf the skull can + * actually reach, or null if it cannot leave the owner's tile at all. + * + * Targeting is done with can_see(), which passes through anything non-opaque. A window is + * transparent and solid at the same time, so without this the launcher happily deposits + * brood on the other side of a hull - the "skulls spawned inside my ship" case. Dense mobs + * are not obstacles; a thrown skull goes over them. + */ +/datum/action/cooldown/mob_cooldown/skull_launcher/proc/clamp_to_reachable_turf(turf/destination) + var/turf/origin = get_turf(owner) + if (isnull(destination) || destination == origin) + return destination + + var/turf/furthest = null + // get_line()'s first entry is the origin itself, which is not a candidate landing spot. + var/list/path = get_line(origin, destination) + for (var/i in 2 to length(path)) + var/turf/step = path[i] + if (step.is_blocked_turf(exclude_mobs = TRUE, source_atom = owner)) + break + furthest = step + + return furthest diff --git a/voidcrew/edits/mobs/megafauna_logging.dm b/voidcrew/edits/mobs/megafauna_logging.dm new file mode 100644 index 00000000000..fde200d88dc --- /dev/null +++ b/voidcrew/edits/mobs/megafauna_logging.dm @@ -0,0 +1,41 @@ +// VOIDCREW: record targeting decisions, including aggro before any attack lands. +/mob/living/simple_animal/hostile/megafauna/add_target(new_target) + var/atom/previous_target = target + . = ..() + if(previous_target != target) + log_aggro_change(previous_target, target) + +/mob/living/simple_animal/hostile/megafauna/handle_target_del(datum/source) + SIGNAL_HANDLER + // The parent clears target before calling LoseTarget(), so capture it now. + if(target == source) + log_aggro_change(target, null) + return ..() + +/mob/living/simple_animal/hostile/megafauna/proc/aggro_target_description(atom/subject) + if(!subject) + return "none" + var/description = "[key_name_and_tag(subject)] [REF(subject)] at [loc_name(subject)]; [overmap_zone_log_context(subject)]" + if(ismecha(subject)) + var/obj/vehicle/sealed/mecha/mech = subject + var/list/pilots = list() + for(var/mob/pilot as anything in mech.occupants) + pilots += key_name_and_tag(pilot) + description += "; occupants: [length(pilots) ? jointext(pilots, ", ") : "none"]" + return description + +/mob/living/simple_animal/hostile/megafauna/proc/log_aggro_change(atom/previous_target, atom/new_target) + var/action = new_target ? (previous_target ? "switched target" : "acquired target") : "lost target" + var/message = "\[MEGAFAUNA AGGRO\] [action]; from: [aggro_target_description(previous_target)]; to: [aggro_target_description(new_target)]" + log_message(message, LOG_ATTACK, color = "blue") + // Keep the same event in the involved players' individual logs, too. + var/list/mob/observers = list() + for(var/atom/subject as anything in list(previous_target, new_target)) + if(ismob(subject)) + observers |= subject + else if(ismecha(subject)) + var/obj/vehicle/sealed/mecha/mech = subject + for(var/mob/pilot as anything in mech.occupants) + observers |= pilot + for(var/mob/observer as anything in observers) + observer.log_message("[key_name_and_tag(src)] at [loc_name(src)]; [overmap_zone_log_context(src)]: [message]", LOG_ATTACK, color = "blue", log_globally = FALSE) diff --git a/voidcrew/edits/mobs/mind_history.dm b/voidcrew/edits/mobs/mind_history.dm new file mode 100644 index 00000000000..996caa65cfa --- /dev/null +++ b/voidcrew/edits/mobs/mind_history.dm @@ -0,0 +1,4 @@ +/mob + /// Whether this mob has ever been assigned as a mind's current body. + /// This remains TRUE after the mind leaves so formerly player-controlled bodies can still be identified. + var/ever_had_mind = FALSE diff --git a/voidcrew/edits/mobs/softcrit_interaction.dm b/voidcrew/edits/mobs/softcrit_interaction.dm new file mode 100644 index 00000000000..368be1be197 --- /dev/null +++ b/voidcrew/edits/mobs/softcrit_interaction.dm @@ -0,0 +1,14 @@ +/** + * Allows item interactions in soft crit without ignoring other incapacitation sources. + * Adapted from MonkeStation: dwasint's original crit item use and action slowdown, + * https://github.com/Monkestation/Monkestation2.0/commit/232ff2ce43dafbb9a8501a618088addd4431e97f + * https://github.com/Monkestation/Monkestation2.0/commit/0254a94c43bc36c6d88252caa3dc98789649ab9d + * with SirNightKnight's source-aware checks (PR #8791) and Xander3359's hard-crit restriction (PR #8709). + * https://github.com/Monkestation/Monkestation2.0/pull/8791 + * https://github.com/Monkestation/Monkestation2.0/pull/8709 + */ +/mob/proc/incapacitated_except_softcrit(ignore_flags = NONE) + // Check sources live: adding a stun while STAT_TRAIT is present does not emit another trait-gain signal. + if(stat == SOFT_CRIT && HAS_TRAIT_FROM_ONLY(src, TRAIT_INCAPACITATED, STAT_TRAIT)) + ignore_flags |= TRADITIONAL_INCAPACITATED + return INCAPACITATED_IGNORING(src, ignore_flags) diff --git a/voidcrew/edits/mobs/trooper_appearance.dm b/voidcrew/edits/mobs/trooper_appearance.dm new file mode 100644 index 00000000000..0c0f56ab9dc --- /dev/null +++ b/voidcrew/edits/mobs/trooper_appearance.dm @@ -0,0 +1,3 @@ +/mob/living/basic/trooper + /// VOIDCREW EDIT: subtypes with bespoke static sprites (e.g. boat pirates) set this FALSE to keep their own icon. + var/use_dynamic_appearance = TRUE diff --git a/voidcrew/edits/objects/items/construction_hooks.dm b/voidcrew/edits/objects/items/construction_hooks.dm new file mode 100644 index 00000000000..af8a7461de0 --- /dev/null +++ b/voidcrew/edits/objects/items/construction_hooks.dm @@ -0,0 +1,67 @@ +/** + * Which way a directional build placed by this RCD should face. + * + * Directional windows, windoors, chairs, tables, racks and beds all take their facing from + * whoever is building them, and for a handheld RCD that is simply the user's own dir. It is + * not for an RCD driven remotely: the voidcrew ship construction console's drone is several + * rooms away from the body holding the "user" role, so every directional structure it built + * came out facing wherever the operator's body happened to be pointing at the console + * (issue #224). Overriding this lets such an RCD name the thing that is actually doing the + * building, without every rcd_act() implementation needing to know it exists. + * + * Arguments + * * [mob][user]- the mob credited with the build + */ +/obj/item/construction/rcd/proc/rcd_build_dir(mob/user) + return user?.dir + +/** + * The design tree this RCD offers, in the GLOB.rcd_designs shape. + * + * Read instead of GLOB.rcd_designs directly so a subtype can offer blueprints the handheld + * RCD does not: the voidcrew ship construction console builds hull-grade windows that no + * engineer should be able to print out of a pocket device. + */ +/obj/item/construction/rcd/proc/get_rcd_designs() + return GLOB.rcd_designs + +/// Resource checks use the captured action, which may differ from the current UI selection after a delay. +/obj/item/construction/rcd/proc/check_rcd_resources(list/rcd_results, mob/user) + return checkResource(rcd_results["cost"], user) + +/obj/item/construction/rcd/proc/use_rcd_resources(list/rcd_results, mob/user) + return useResource(rcd_results["cost"], user) + +/// Applies a validated, paid-for action. Subtypes can handle successful resource recovery here. +/obj/item/construction/rcd/proc/apply_rcd_action(atom/target, mob/user, list/rcd_results) + var/turf/location = get_turf(target) + . = target.rcd_act(user, src, rcd_results) + // VOIDCREW: a successful deliberate removal supersedes an old repair order. + if(. && rcd_results["[RCD_DESIGN_MODE]"] == RCD_DECONSTRUCT) + var/obj/machinery/computer/camera_advanced/base_construction/ship/controller = SSship_repairs.area_controllers[get_area(location)] + controller?.forget_repair_record(controller.repair_coordinate_key(location)) + +/// Installs an upgrade disk into the RPD, checking first that the upgrade isn't already present. +/// Returns TRUE if the disk was consumed. +/obj/item/pipe_dispenser/proc/install_upgrade(obj/item/rpd_upgrade/rpd_disk, mob/user) + // Check if the upgrade's already present + if(rpd_disk.upgrade_flags & upgrade_flags) + balloon_alert(user, "already installed!") + return FALSE + + // Adds the upgrade from the disk and then deletes the disk + upgrade_flags |= rpd_disk.upgrade_flags + playsound(loc, 'sound/machines/click.ogg', 50, vary = TRUE) + balloon_alert(user, "upgrade installed") + qdel(rpd_disk) + return TRUE + +/// Clicking an upgrade disk onto the RPD installs it, same as clicking the RPD onto the disk. +/obj/item/pipe_dispenser/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(istype(tool, /obj/item/rpd_upgrade) && ISADVANCEDTOOLUSER(user)) + return install_upgrade(tool, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + return ..() + +/// An immutable description of the current paint selection for remote construction jobs. +/obj/item/airlock_painter/decal/proc/get_decal_data() + return current_category.get_decal_info(state = selected_decal_icon_state, color = selected_color, dir = selected_dir) diff --git a/voidcrew/edits/objects/items/mod_storage_lifecycle.dm b/voidcrew/edits/objects/items/mod_storage_lifecycle.dm new file mode 100644 index 00000000000..bfa81a0a266 --- /dev/null +++ b/voidcrew/edits/objects/items/mod_storage_lifecycle.dm @@ -0,0 +1,5 @@ +// VOIDCREW EDIT: keep the bookkeeping list honest however ore leaves - dumped, +// stolen out by hand, or deleted (qdel nullspaces contents through Exited) +/obj/item/mod/module/orebag/Exited(atom/movable/gone, direction) + . = ..() + ores -= gone diff --git a/voidcrew/edits/objects/structures/cargo_payment.dm b/voidcrew/edits/objects/structures/cargo_payment.dm new file mode 100644 index 00000000000..a9ee2486492 --- /dev/null +++ b/voidcrew/edits/objects/structures/cargo_payment.dm @@ -0,0 +1,3 @@ +/obj/structure/closet/crate + /// Actual ship order payment. Kept independently of removable paperwork for recycling caps. + var/cargo_paid_cost diff --git a/voidcrew/edits/screentip_hover.dm b/voidcrew/edits/screentip_hover.dm new file mode 100644 index 00000000000..6f199071bf1 --- /dev/null +++ b/voidcrew/edits/screentip_hover.dm @@ -0,0 +1,8 @@ +/atom/MouseExited(location, control, params) + var/client/hovering_client = usr?.client + if(!hovering_client) + return + // The pointer can leave before the deferred MouseEntered has been processed. + if(SSmouse_entered.hovers[hovering_client] == src) + SSmouse_entered.hovers[hovering_client] = null + hovering_client.mob?.hud_used?.screentip_text?.clear_hover(src) diff --git a/voidcrew/edits/spells/jaunt_destinations.dm b/voidcrew/edits/spells/jaunt_destinations.dm new file mode 100644 index 00000000000..91234221aa3 --- /dev/null +++ b/voidcrew/edits/spells/jaunt_destinations.dm @@ -0,0 +1,36 @@ +/// Blood pools can be across an area boundary, beyond the holder's phased movement checks. +/datum/action/cooldown/spell/jaunt/bloodcrawl/proc/is_valid_blood_destination(atom/origin, obj/effect/decal/cleanable/blood) + if(QDELETED(blood) || !blood.can_bloodcrawl_in()) + return FALSE + var/turf/destination = get_turf(blood) + if(!destination || (destination.turf_flags & NOJAUNT) || SSmapping.level_trait(destination.z, ZTRAIT_NOPHASE)) + return FALSE + return check_teleport_valid(origin, destination, TELEPORT_CHANNEL_MAGIC) + +// VOIDCREW EDIT: reclaim reference effects even when the action loses its owner first. +/datum/action/cooldown/spell/jaunt/ethereal_jaunt/Destroy() + clear_exit_points() + return ..() + +/datum/action/cooldown/spell/jaunt/ethereal_jaunt/proc/clear_exit_points() + QDEL_NULL(start_point_anchor) + QDEL_LIST(exit_point_list) + exit_point_list = null + +/// An invisible location reference, carried by ordinary shuttle movement and rotation. +/obj/effect/abstract/jaunt_exit + name = "jaunt return reference" + icon = null + invisibility = INVISIBILITY_ABSTRACT + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + anchored = TRUE + +/datum/action/cooldown/spell/jaunt/ethereal_jaunt + var/obj/effect/abstract/jaunt_exit/start_point_anchor + +/// Removal, body changes and forced ejection can end the return animation early. +/datum/action/cooldown/spell/jaunt/ethereal_jaunt/on_jaunt_exited(obj/effect/dummy/phased_mob/jaunt, mob/living/unjaunter) + UnregisterSignal(jaunt, COMSIG_MOVABLE_MOVED) + clear_exit_points() + REMOVE_TRAIT(unjaunter, TRAIT_IMMOBILIZED, REF(src)) + return ..() diff --git a/voidcrew/edits/spells/rust_filters.dm b/voidcrew/edits/spells/rust_filters.dm new file mode 100644 index 00000000000..f13009d026a --- /dev/null +++ b/voidcrew/edits/spells/rust_filters.dm @@ -0,0 +1,17 @@ +// VOIDCREW EDIT START: Independent cosmetic expiry must not affect a later cast on this turf. - Voidcrew rust spell integration: expire only the filter owned by this cast (voidcrew/edits/spells) +/proc/fade_rust_wall_filter(turf/closed/wall, list/owned_filter, fade_duration) + if(QDELETED(wall) || LAZYACCESS(wall.filter_data, "rust_wall") != owned_filter) + return + + var/rust_filter = wall.get_filter("rust_wall") + if(!rust_filter) + return + + animate(rust_filter, alpha = 0, time = fade_duration) + +/proc/remove_rust_wall_filter(turf/closed/wall, list/owned_filter) + if(QDELETED(wall) || LAZYACCESS(wall.filter_data, "rust_wall") != owned_filter) + return + + wall.remove_filter("rust_wall") +// END VOIDCREW EDIT From ccaaaca694b9fb5ee4cfef16535b6e403b4b278b Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Wed, 30 Sep 2026 04:32:16 -0700 Subject: [PATCH 3/6] Modularize core fork additions and mark necessary upstream hooks --- code/__DEFINES/admin.dm | 2 +- code/__DEFINES/bitrunning.dm | 5 - .../signals/signals_atom/signals_atom_main.dm | 2 - .../signals_atom/signals_atom_movement.dm | 2 - .../signals/signals_mob/signals_mob_living.dm | 3 - code/__DEFINES/dcs/signals/signals_object.dm | 4 - code/__DEFINES/explosions.dm | 2 + code/__DEFINES/hud.dm | 1 - code/__DEFINES/mobs.dm | 2 - code/__DEFINES/reagents.dm | 9 - code/__DEFINES/tgs.dm | 3 + code/__DEFINES/wiremod.dm | 6 - code/__HELPERS/_lists.dm | 22 +- code/__HELPERS/areas.dm | 2 + code/__HELPERS/logging/attack.dm | 2 + code/__HELPERS/logging/mob.dm | 2 + code/__HELPERS/paths/jps.dm | 4 + code/__HELPERS/priority_announce.dm | 4 + code/__HELPERS/radiation.dm | 3 + code/__HELPERS/shuttle.dm | 5 +- code/_onclick/click.dm | 3 + code/_onclick/hud/alert.dm | 1 + code/_onclick/hud/blob_overmind.dm | 1 + code/_onclick/hud/hud.dm | 52 +--- code/_onclick/hud/human.dm | 3 +- code/_onclick/hud/new_player.dm | 6 + code/_onclick/hud/parallax/parallax.dm | 1 + .../hud/rendering/plane_master_group.dm | 3 + .../rendering/plane_masters/_plane_master.dm | 2 + code/_onclick/hud/rendering/render_plate.dm | 8 + code/_onclick/hud/screen_objects.dm | 19 +- code/_onclick/hud/screentip.dm | 66 +---- code/_onclick/observer.dm | 2 + code/_onclick/other_mobs.dm | 4 + .../configuration/entries/game_options.dm | 2 - code/controllers/subsystem/air.dm | 106 +------ code/controllers/subsystem/area_contents.dm | 4 + code/controllers/subsystem/atoms.dm | 3 + code/controllers/subsystem/explosions.dm | 11 +- code/controllers/subsystem/job.dm | 3 + code/controllers/subsystem/lighting.dm | 5 +- code/controllers/subsystem/mapping.dm | 117 +------- code/controllers/subsystem/minor_mapping.dm | 2 +- .../subsystem/networks/bitrunning.dm | 78 ------ .../subsystem/networks/research.dm | 2 + code/controllers/subsystem/pathfinder.dm | 2 + code/controllers/subsystem/radiation.dm | 1 + code/controllers/subsystem/shuttle.dm | 126 ++------- code/controllers/subsystem/statpanel.dm | 1 + code/controllers/subsystem/ticker.dm | 4 + code/controllers/subsystem/tts.dm | 1 + code/controllers/subsystem/weather.dm | 258 +----------------- code/datums/actions/mobs/charge.dm | 63 ++--- code/datums/alarm.dm | 6 +- code/datums/components/chasm.dm | 2 + code/datums/components/crafting/crafting.dm | 2 + code/datums/components/gps.dm | 2 + code/datums/components/irradiated.dm | 2 + code/datums/components/orbiter.dm | 4 + code/datums/components/overlay_lighting.dm | 12 +- code/datums/components/shuttle_cling.dm | 23 +- code/datums/components/singularity.dm | 10 + code/datums/components/spawner.dm | 24 +- code/datums/components/tether.dm | 6 +- code/datums/elements/decals/_decal.dm | 8 +- code/datums/elements/turf_transparency.dm | 4 +- code/datums/elements/weather_listener.dm | 1 + code/datums/helper_datums/teleport.dm | 8 +- code/datums/mapgen/CaveGenerator.dm | 28 +- code/datums/mapgen/biomes/_biome.dm | 5 + code/datums/materials/basemats.dm | 3 +- code/datums/mind/_mind.dm | 1 + code/datums/records/record.dm | 3 + code/datums/screentips/atom_context.dm | 1 + code/datums/shuttles/_shuttle.dm | 3 + code/datums/station_alert.dm | 2 +- code/datums/storage/storage.dm | 1 + .../storage/subtypes/others/bag_of_holding.dm | 11 +- code/datums/weather/weather.dm | 54 +--- .../datums/weather/weather_types/ash_storm.dm | 1 + .../weather/weather_types/floor_is_lava.dm | 1 + .../weather/weather_types/rain_storm.dm | 15 + .../weather/weather_types/sand_storm.dm | 13 +- .../weather/weather_types/snow_storm.dm | 5 + .../atmospherics/environmental/LINDA_fire.dm | 2 +- .../environmental/LINDA_system.dm | 6 + .../environmental/LINDA_turf_tile.dm | 13 + .../atmospherics/machinery/atmosmachinery.dm | 4 + .../machinery/components/components_base.dm | 5 + .../unary_devices/machine_connector.dm | 2 + .../atmospherics/machinery/datum_pipeline.dm | 28 +- .../atmospherics/machinery/pipes/pipes.dm | 1 + .../machinery/portable/scrubber.dm | 1 + code/modules/error_handler/error_handler.dm | 41 ++- code/modules/error_handler/error_viewer.dm | 15 +- code/modules/lighting/lighting_object.dm | 4 +- code/modules/lighting/lighting_turf.dm | 13 +- code/modules/mapping/map_template.dm | 6 +- code/modules/mapping/mapping_helpers.dm | 3 +- code/modules/mapping/reader.dm | 4 + code/modules/mapping/ruins.dm | 30 +- .../space_management/space_reservation.dm | 38 +-- voidcrew/_DEFINES/core_integration.dm | 42 +++ voidcrew/_HELPERS/ruin_placement.dm | 22 ++ voidcrew/_HELPERS/typecache.dm | 16 ++ .../configuration/new_round_alert.dm | 2 + .../edits/_onclick/hud/screen_extensions.dm | 120 ++++++++ voidcrew/edits/actions/charge_lifecycle.dm | 41 +++ .../edits/atmospherics/pipeline_cleanup.dm | 17 ++ voidcrew/edits/components/alarm_region.dm | 5 + .../components/overlay_lighting_holder.dm | 10 + .../components/shuttle_cling_lifecycle.dm | 20 ++ .../edits/components/spawner_lifecycle.dm | 21 ++ voidcrew/edits/components/tether_pulling.dm | 3 + voidcrew/edits/elements/decal_collection.dm | 4 + .../edits/error_handler/cache_retention.dm | 5 + voidcrew/edits/error_handler/runtime_state.dm | 22 ++ .../edits/mapgen/cave_generation_report.dm | 16 ++ voidcrew/edits/mapping/reservation_bounds.dm | 17 ++ voidcrew/edits/subsystem/air_cleanup.dm | 98 +++++++ .../edits/subsystem/bitrunning_domains.dm | 80 ++++++ voidcrew/edits/subsystem/mapping_cleanup.dm | 111 ++++++++ voidcrew/edits/subsystem/weather_sites.dm | 247 +++++++++++++++++ voidcrew/edits/weather/packed_sites.dm | 45 +++ voidcrew/edits/weather/sand_storm_sound.dm | 4 + .../ship_upgrades/shuttle_manipulator.dm | 102 +++++++ voidcrew/modules/trade/bag_rift_protection.dm | 8 + 127 files changed, 1512 insertions(+), 1088 deletions(-) create mode 100644 voidcrew/_DEFINES/core_integration.dm create mode 100644 voidcrew/_HELPERS/ruin_placement.dm create mode 100644 voidcrew/_HELPERS/typecache.dm create mode 100644 voidcrew/controllers/configuration/new_round_alert.dm create mode 100644 voidcrew/edits/_onclick/hud/screen_extensions.dm create mode 100644 voidcrew/edits/actions/charge_lifecycle.dm create mode 100644 voidcrew/edits/atmospherics/pipeline_cleanup.dm create mode 100644 voidcrew/edits/components/alarm_region.dm create mode 100644 voidcrew/edits/components/overlay_lighting_holder.dm create mode 100644 voidcrew/edits/components/shuttle_cling_lifecycle.dm create mode 100644 voidcrew/edits/components/spawner_lifecycle.dm create mode 100644 voidcrew/edits/components/tether_pulling.dm create mode 100644 voidcrew/edits/elements/decal_collection.dm create mode 100644 voidcrew/edits/error_handler/cache_retention.dm create mode 100644 voidcrew/edits/error_handler/runtime_state.dm create mode 100644 voidcrew/edits/mapgen/cave_generation_report.dm create mode 100644 voidcrew/edits/mapping/reservation_bounds.dm create mode 100644 voidcrew/edits/subsystem/air_cleanup.dm create mode 100644 voidcrew/edits/subsystem/bitrunning_domains.dm create mode 100644 voidcrew/edits/subsystem/mapping_cleanup.dm create mode 100644 voidcrew/edits/subsystem/weather_sites.dm create mode 100644 voidcrew/edits/weather/packed_sites.dm create mode 100644 voidcrew/edits/weather/sand_storm_sound.dm create mode 100644 voidcrew/modules/ship_upgrades/shuttle_manipulator.dm create mode 100644 voidcrew/modules/trade/bag_rift_protection.dm diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 5b17e819430..894a0a86eae 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -40,10 +40,10 @@ #define R_SPAWN (1<<12) #define R_AUTOADMIN (1<<13) #define R_DBRANKS (1<<14) -#define R_ECONOMY (1<<15) #define R_DEFAULT R_AUTOADMIN +// VOIDCREW EDIT: Include the Economy permission in the complete admin permission mask (voidcrew/modules/admin). #define R_EVERYTHING (1<<16)-1 //the sum of all other rank permissions, used for +EVERYTHING #define ADMIN_QUE(user) "(?)" diff --git a/code/__DEFINES/bitrunning.dm b/code/__DEFINES/bitrunning.dm index 83e97809274..639ae26c3fc 100644 --- a/code/__DEFINES/bitrunning.dm +++ b/code/__DEFINES/bitrunning.dm @@ -2,11 +2,6 @@ #define BITRUNNER_COST_LOW 1 #define BITRUNNER_COST_MEDIUM 2 #define BITRUNNER_COST_HIGH 3 -/// Megafauna arenas. Priced above what they pay back so a boss dive is funded by -/// running the rest of the roster, instead of paying for itself forever. -#define BITRUNNER_COST_BOSS 5 -/// The four hardest megafauna arenas. Same idea, steeper. -#define BITRUNNER_COST_APEX_BOSS 8 #define BITRUNNER_COST_EXTREME 20 /// Yay you did it diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm index a58e15db7fb..1f261db129a 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm @@ -57,8 +57,6 @@ #define COMSIG_ATOM_SMOOTHED_ICON "atom_smoothed_icon" ///from [/datum/controller/subsystem/processing/dcs/proc/rotate_decals]: (list/datum/element/decal/rotating) #define COMSIG_ATOM_DECALS_ROTATING "atom_decals_rotating" -/// Collect attached decal elements: (list/decals) -#define COMSIG_ATOM_GET_DECALS "atom_get_decals" ///from base of atom/Entered(): (atom/movable/arrived, atom/old_loc, list/atom/old_locs) #define COMSIG_ATOM_ENTERED "atom_entered" ///from base of atom/movable/Moved(): (atom/movable/arrived, atom/old_loc, list/atom/old_locs) diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm index 2474b261646..d468be8bf80 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm @@ -21,8 +21,6 @@ #define COMPONENT_MOVE_CONTENTS MOVE_CONTENTS /// From base of /atom/movable/afterShuttleMove (turf/oldT) #define COMSIG_ATOM_AFTER_SHUTTLE_MOVE "movable_after_shuttle_move" -/// VOIDCREW ADDITION. From base of /atom/movable/lateShuttleMove, once every moved atom has landed and rotated: (turf/oldT, list/movement_force, move_dir) -#define COMSIG_ATOM_LATE_SHUTTLE_MOVE "movable_late_shuttle_move" ///called on a movable (NOT living) when it starts pulling (atom/movable/pulled, state, force) #define COMSIG_ATOM_START_PULL "movable_start_pull" /// called on /atom when something attempts to pass through it (atom/movable/source, atom/movable/passing, dir) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 661325e5a5f..1f5f19ba610 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -157,9 +157,6 @@ #define COMSIG_LIVING_EARLY_UNARMED_ATTACK "human_pre_attack_hand" /// from mob/living/*/UnarmedAttack(): (mob/living/source, atom/target, proximity, modifiers) #define COMSIG_LIVING_UNARMED_ATTACK "living_unarmed_attack" -/// After normal /mob/living/UnarmedAttack resolution: (atom/target, list/modifiers, health_damage, stamina_damage). -/// Damage is the synchronous change during this attack; target may have been deleted by a lethal hit. -#define COMSIG_LIVING_AFTER_UNARMED_ATTACK "living_after_unarmed_attack" ///From base of mob/living/MobBump(): (mob/bumped, mob/living/bumper) #define COMSIG_LIVING_PRE_MOB_BUMP "movable_pre_bump" #define COMPONENT_LIVING_BLOCK_PRE_MOB_BUMP (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index e096a971f24..844d72bc62f 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -214,10 +214,6 @@ /// from [/obj/item/stack/proc/can_merge]: (obj/item/stack/merge_with, in_hand) #define COMSIG_STACK_CAN_MERGE "stack_can_merge" #define CANCEL_STACK_MERGE (1<<0) -/// Sent to the destination of a proposed stack merge: (obj/item/stack/source_stack, inhand) -#define COMSIG_STACK_CAN_RECEIVE_MERGE "stack_can_receive_merge" -/// Sent before a split source can be deleted: (obj/item/stack/new_stack) -#define COMSIG_STACK_SPLIT "stack_split" ///from /obj/item/book/bible/interact_with_atom(): (mob/user) #define COMSIG_BIBLE_SMACKED "bible_smacked" diff --git a/code/__DEFINES/explosions.dm b/code/__DEFINES/explosions.dm index 402fefbde8a..7940cf20709 100644 --- a/code/__DEFINES/explosions.dm +++ b/code/__DEFINES/explosions.dm @@ -20,6 +20,7 @@ /// A wrapper for [/atom/proc/ex_act] to ensure that the explosion propagation and attendant signal are always handled. /// VOIDCREW: recheck outpost protection when queued or direct damage is applied. +// VOIDCREW EDIT START: Block explosions on protected trader outposts before contents and signals fire (voidcrew/modules/trade/outpost_security.dm). #define EX_ACT(target, args...)\ if(!is_trader_outpost_protected(target)) { \ if(!(target.flags_1 & PREVENT_CONTENTS_EXPLOSION_1)) { \ @@ -30,6 +31,7 @@ target.ex_act(##args);\ } \ } +// VOIDCREW EDIT END // Internal explosion argument list keys. // Must match the arguments to [/datum/controller/subsystem/explosions/proc/propagate_blastwave] diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm index db92c9eca09..c8f0a9b66b5 100644 --- a/code/__DEFINES/hud.dm +++ b/code/__DEFINES/hud.dm @@ -110,7 +110,6 @@ //Humans #define ui_human_floor_changer "EAST-4:22,SOUTH:5" -#define ui_human_skills "EAST-4:22,SOUTH+1:7" #define ui_human_crafting "EAST-3:24,SOUTH+1:7" #define ui_human_navigate "EAST-3:7,SOUTH+1:7" #define ui_human_language "EAST-3:7,SOUTH+1:24" diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 5d3b72613d9..0e966709a14 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -893,8 +893,6 @@ GLOBAL_LIST_INIT(layers_to_offset, list( #define SILENT_ADJACENCY (1<<11) /// Allows pAIs to perform an action #define ALLOW_PAI (1<<12) -/// Allows an item action in soft crit, while still checking other incapacitation sources. -#define ALLOW_SOFT_CRIT (1<<13) /// The default mob sprite size (used for shrinking or enlarging the mob sprite to regular size) #define RESIZE_DEFAULT_SIZE 1 diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index 7d8c78a743c..d2f5528bc49 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -143,15 +143,6 @@ #define REACTION_PH_VOL_CONSTANT (1<<6) ///If a reaction will generate its impure/inverse reagents in the middle of a reaction, as apposed to being determined on ingestion/on reaction completion #define REACTION_REAL_TIME_SPLIT (1<<7) -//VOIDCREW EDIT ADDITION: reaction refuses to run inside a grown food item, so plant -//chemistry can't be used to mass-produce the mob-spawning mixtures. -#define REACTION_NOT_IN_PLANTS (1<<8) -///The reaction opts into pH-driven purity. Unset (the fork-wide default) means pH is a live, -///drifting number that no reaction is blocked or purity-penalised by, so a recipe's optimal -///pH band never has to contain 7 to be usable. Set it to bring tg's pH mechanics back for -///that one recipe. -#define REACTION_USES_PURITY (1<<9) -//VOIDCREW EDIT END ///Used for overheat_temp - This sets the overheat so high it effectively has no overheat temperature. #define NO_OVERHEAT 99999 diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm index 9e04917b240..0660f78dc57 100644 --- a/code/__DEFINES/tgs.dm +++ b/code/__DEFINES/tgs.dm @@ -1,6 +1,7 @@ // tgstation-server DMAPI // The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in IETF RFC 2119. +// VOIDCREW EDIT: Match the vendored TGS DMAPI 7.4.0 version and deployment entry point in code/modules/tgs. #define TGS_DMAPI_VERSION "7.4.0" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -587,9 +588,11 @@ /// Trigger a TGS deployment for the current instance. The current state of the repository will not be changed. +// VOIDCREW EDIT START: Match the vendored TGS DMAPI 7.4.0 version and deployment entry point in code/modules/tgs. /world/proc/TgsTriggerDeployment() CAN_BE_REDEFINED(TRUE) return +// VOIDCREW EDIT END /* The MIT License diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm index cd4c9608374..b606f938869 100644 --- a/code/__DEFINES/wiremod.dm +++ b/code/__DEFINES/wiremod.dm @@ -40,12 +40,6 @@ /// Associative List datatype. Derivative of list. #define PORT_TYPE_ASSOC_LIST(key_datatype, datatype) SSwiremod_composite.composite_datatype(PORT_COMPOSITE_TYPE_ASSOC_LIST, key_datatype, datatype) -//VOIDCREW EDIT ADDITION: chemistry circuits -#define PORT_COMPOSITE_TYPE_CHEMICAL "chemical list" -/// Reagent-type -> volume mapping, the currency the chemistry circuits pass around. -#define PORT_TYPE_CHEMICAL_LIST SSwiremod_composite.composite_datatype(PORT_COMPOSITE_TYPE_CHEMICAL, PORT_TYPE_DATUM, PORT_TYPE_NUMBER) -//VOIDCREW EDIT END - // Other datatypes /// Atom datatype #define PORT_TYPE_ATOM "entity" diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 00ae0bb86d6..35264c2acd9 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -308,22 +308,6 @@ ///Checks for specific types in specifically structured (Assoc "type" = TRUE|FALSE) lists ('typecaches') #define is_type_in_typecache(A, L) (A && length(L) && L[(ispath(A) ? A : A:type)]) -/** - * VOIDCREW ADDITION: complains once per cooldown about a typecache filter called with - * something that isn't a list. - * - * The filters below run per-turf inside /turf/proc/empty(), so a reservation the size of a - * ruin interior calls them seventeen thousand times in a row. An unguarded throw there is - * not one runtime, it is a runtime per turf - which is how round-7 (2026-08-16) put a - * quarter of a million reservation runtimes into dd.log. Rate-limited so the diagnosis - * itself can never become the flood. - */ -/proc/warn_bad_typecache_filter(filter_name, list/atoms, list/typecache) - var/static/next_complaint = 0 - if(world.time < next_complaint) - return - next_complaint = world.time + 10 SECONDS - stack_trace("[filter_name]() called with [islist(atoms) ? "a list" : "a non-list"] of atoms and [islist(typecache) ? "a list" : "a non-list"] typecache - filtering nothing and returning empty") ///returns a new list with only atoms that are in the typecache list /proc/typecache_filter_list(list/atoms, list/typecache) @@ -332,8 +316,10 @@ // VOIDCREW EDIT: degrade to an empty result rather than throwing. Every caller reads // the result as "the atoms this operation applies to", so an empty list is the no-op. if(!islist(atoms) || !islist(typecache)) + // VOIDCREW EDIT START: Reject malformed typecache inputs without unsafe mass deletion; diagnostics live in voidcrew/_HELPERS/typecache.dm. warn_bad_typecache_filter("typecache_filter_list", atoms, typecache) return + // VOIDCREW EDIT END for(var/atom/atom_checked as anything in atoms) if (typecache[atom_checked.type]) . += atom_checked @@ -346,8 +332,10 @@ // everything this returns, so a missing typecache must never be read as "nothing is // excluded". Empty means nothing gets deleted, which is the recoverable direction. if(!islist(atoms) || !islist(typecache)) + // VOIDCREW EDIT START: Reject malformed typecache inputs without unsafe mass deletion; diagnostics live in voidcrew/_HELPERS/typecache.dm. warn_bad_typecache_filter("typecache_filter_list_reverse", atoms, typecache) return + // VOIDCREW EDIT END for(var/atom/atom_checked as anything in atoms) if(!typecache[atom_checked.type]) . += atom_checked @@ -357,8 +345,10 @@ . = list() // VOIDCREW EDIT: as above. if(!islist(atoms) || !islist(typecache_include) || !islist(typecache_exclude)) + // VOIDCREW EDIT START: Reject malformed typecache inputs without unsafe mass deletion; diagnostics live in voidcrew/_HELPERS/typecache.dm. warn_bad_typecache_filter("typecache_filter_multi_list_exclusion", atoms, typecache_include) return + // VOIDCREW EDIT END for(var/atom/atom_checked as anything in atoms) if(typecache_include[atom_checked.type] && !typecache_exclude[atom_checked.type]) . += atom_checked diff --git a/code/__HELPERS/areas.dm b/code/__HELPERS/areas.dm index 616ad0f10b9..f333291786d 100644 --- a/code/__HELPERS/areas.dm +++ b/code/__HELPERS/areas.dm @@ -131,11 +131,13 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(list( var/turf_count = length(turfs) if(!turf_count) // Check if we're in or adjacent to a shuttle area to give a more helpful error + // VOIDCREW EDIT START: Explain why hull areas need a ship expansion permit (voidcrew/modules/shuttle). var/area/current_area = get_area(creator) if(istype(current_area, /area/shuttle)) error = "You cannot use regular blueprints in a shuttle area. Use a shuttle expansion permit instead." else error = "The new area must be completely airtight and not a part of a shuttle." + // VOIDCREW EDIT END else if(turf_count > BP_MAX_ROOM_SIZE) error = "The room you're in is too big. It is [turf_count >= BP_MAX_ROOM_SIZE *2 ? "more than 100" : ((turf_count / BP_MAX_ROOM_SIZE)-1)*100]% larger than allowed." if(error) diff --git a/code/__HELPERS/logging/attack.dm b/code/__HELPERS/logging/attack.dm index b777b46ffc4..18c2500e79e 100644 --- a/code/__HELPERS/logging/attack.dm +++ b/code/__HELPERS/logging/attack.dm @@ -28,8 +28,10 @@ var/postfix = "[sobject][saddition][hp]" // VOIDCREW: ranged attacks can cross hulls; preserve the target's location too. + // VOIDCREW EDIT START: Record the target ship and overmap zone for cross-hull attacks (voidcrew/modules/admin). if(target && target != user) postfix += " \[Target location: [overmap_zone_log_context(target)]\]" + // VOIDCREW EDIT END var/message = "[what_done] [starget][postfix]" user.log_message(message, LOG_ATTACK, color="red") diff --git a/code/__HELPERS/logging/mob.dm b/code/__HELPERS/logging/mob.dm index 7461260a464..0191fedae16 100644 --- a/code/__HELPERS/logging/mob.dm +++ b/code/__HELPERS/logging/mob.dm @@ -17,8 +17,10 @@ return // VOIDCREW: keep the actual ship/zone visible in both individual and disk logs. + // VOIDCREW EDIT START: Record the attacker ship and overmap zone in combat logs (voidcrew/modules/admin). if(message_type == LOG_ATTACK || message_type == LOG_VICTIM) message += " \[Location: [overmap_zone_log_context(src)]\]" + // VOIDCREW EDIT END // Cannot use the list as a map if the key is a number, so we stringify it (thank you BYOND) var/smessage_type = num2text(message_type, MAX_BITFLAG_DIGITS) diff --git a/code/__HELPERS/paths/jps.dm b/code/__HELPERS/paths/jps.dm index 44ca193b5e2..717b5e14f3c 100644 --- a/code/__HELPERS/paths/jps.dm +++ b/code/__HELPERS/paths/jps.dm @@ -124,8 +124,10 @@ // These were inline list() literals, which meant two list allocations for every single node // popped off the open heap. Statics: same contents, allocated once for the whole round. + // VOIDCREW EDIT START: Reuse direction lists in fleet-scale pathfinding instead of allocating lists per node. var/static/list/cardinal_scans = list(EAST, WEST, NORTH, SOUTH) var/static/list/diagonal_scans = list(NORTHEAST, SOUTHEAST, NORTHWEST, SOUTHWEST) + // VOIDCREW EDIT END while(!open.is_empty() && !path) var/datum/jps_node/current_processed_node = open.pop() //get the lower f_value turf in the open list @@ -133,9 +135,11 @@ continue var/turf/current_turf = current_processed_node.tile + // VOIDCREW EDIT: Reuse direction lists in fleet-scale pathfinding instead of allocating lists per node. for(var/scan_direction as anything in cardinal_scans) lateral_scan_spec(current_turf, scan_direction, current_processed_node) + // VOIDCREW EDIT: Reuse direction lists in fleet-scale pathfinding instead of allocating lists per node. for(var/scan_direction as anything in diagonal_scans) diag_scan_spec(current_turf, scan_direction, current_processed_node) diff --git a/code/__HELPERS/priority_announce.dm b/code/__HELPERS/priority_announce.dm index 52e79d4a3bd..665608ade77 100644 --- a/code/__HELPERS/priority_announce.dm +++ b/code/__HELPERS/priority_announce.dm @@ -63,8 +63,10 @@ header += SUBHEADER_ANNOUNCEMENT_TITLE(title) if(ANNOUNCEMENT_TYPE_CAPTAIN) header = MAJOR_ANNOUNCEMENT_TITLE("Captain's Announcement") + // VOIDCREW EDIT START: Keep ship security announcements scoped to their recipient crew (voidcrew/modules/comms/communications_console.dm). if(players == GLOB.player_list) GLOB.news_network.submit_article(text, "Captain's Announcement", NEWSCASTER_STATION_ANNOUNCEMENTS, null) + // VOIDCREW EDIT END if(ANNOUNCEMENT_TYPE_SYNDICATE) header = MAJOR_ANNOUNCEMENT_TITLE("Syndicate Captain's Announcement") else @@ -147,6 +149,7 @@ dispatch_announcement_to_players(finalized_announcement, players, custom_sound, should_play_sound) /// Sends an announcement about the level changing to players. Uses the passed in datum and the subsystem's previous security level to generate the message. +// VOIDCREW EDIT: Keep ship security announcements scoped to their recipient crew (voidcrew/modules/comms/communications_console.dm). /proc/level_announce(datum/security_level/selected_level, previous_level_number, list/players = GLOB.player_list) var/current_level_number = selected_level.number_level var/current_level_name = selected_level.name @@ -169,6 +172,7 @@ var/finalized_announcement = CHAT_ALERT_COLORED_SPAN(current_level_color, jointext(level_announcement_strings, "")) + // VOIDCREW EDIT: Keep ship security announcements scoped to their recipient crew (voidcrew/modules/comms/communications_console.dm). dispatch_announcement_to_players(finalized_announcement, players, current_level_sound) /// Proc that just generates a custom header based on variables fed into `priority_announce()` diff --git a/code/__HELPERS/radiation.dm b/code/__HELPERS/radiation.dm index 8b360d7b260..f447e1b59bc 100644 --- a/code/__HELPERS/radiation.dm +++ b/code/__HELPERS/radiation.dm @@ -32,11 +32,14 @@ if(!SSradiation.can_fire) return + // VOIDCREW EDIT START: Skip radiation sources that cannot resolve a weak reference during deletion. var/datum/weakref/source_ref = WEAKREF(source) if(isnull(source_ref)) // null or mid-qdel source: WEAKREF() returns null and the pulse could never resolve return + // VOIDCREW EDIT END var/datum/radiation_pulse_information/pulse_information = new + // VOIDCREW EDIT: Skip radiation sources that cannot resolve a weak reference during deletion. pulse_information.source_ref = source_ref pulse_information.max_range = max_range pulse_information.threshold = threshold diff --git a/code/__HELPERS/shuttle.dm b/code/__HELPERS/shuttle.dm index 5f2119b1b57..01d8b851afc 100644 --- a/code/__HELPERS/shuttle.dm +++ b/code/__HELPERS/shuttle.dm @@ -346,7 +346,7 @@ GLOBAL_LIST_EMPTY(shuttle_frames_by_turf) var/list/area_turfs = checked_area.get_turfs_by_zlevel(z) if(!checked_area.allow_shuttle_docking) . |= INTERSECTS_NON_WHITELISTED_AREA - // VOIDCREW EDIT ADDITION: a virtual domain's reservation floor is plain + // VOIDCREW EDIT ADDITION START: a virtual domain's reservation floor is plain // /area/space, which whitelists docking. Without this a bitrunner frames up a // shuttle inside VR and flies it - and everything they looted - back to the ship. else if(SSbitrunning.is_domain_turf(checked_turf)) @@ -502,10 +502,12 @@ GLOBAL_LIST_EMPTY(shuttle_frames_by_turf) shuttle.underlying_areas_by_turf += underlying_areas SEND_SIGNAL(shuttle, COMSIG_SHUTTLE_EXPANDED, turfs) if(bounds_need_recalculation) + // VOIDCREW EDIT: Release the transit reservation before recalculating changed hull bounds (voidcrew/modules/shuttle). release_assigned_transit(shuttle) //VOID EDIT - was QDEL_NULL, which leaks the reservation shuttle.calculate_docking_port_information() shuttle.initiate_docking(shuttle.get_docked(), force = TRUE) + // VOIDCREW EDIT REMOVAL: Keep routine player hull expansions in the shuttle log without per-expansion admin announcements (voidcrew/modules/shuttle). log_shuttle("[key_name(user)] expanded [shuttle] at [get_area(user)].") /proc/clear_empty_shuttle_turfs(obj/docking_port/mobile/shuttle) @@ -561,5 +563,6 @@ GLOBAL_LIST_EMPTY(shuttle_frames_by_turf) if(docking_port_needs_relocated) shuttle.forceMove(pick(shuttle.underlying_areas_by_turf)) if(bounds_need_recalculation) + // VOIDCREW EDIT: Release the transit reservation before recalculating changed hull bounds (voidcrew/modules/shuttle). release_assigned_transit(shuttle) //VOID EDIT - was QDEL_NULL, which leaks the reservation shuttle.calculate_docking_port_information() diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 75c1875bdd3..3afab4621fc 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -24,8 +24,10 @@ var/mod = next_move_modifier var/adj = next_move_adjust // MonkeStation's crit item usage: actions in soft crit take four times as long. + // VOIDCREW EDIT START: Allow slow item actions in soft crit through incapacitated_except_softcrit(). if(stat == SOFT_CRIT) mod *= 4 + // VOIDCREW EDIT END for(var/datum/status_effect/effect as anything in status_effects) mod *= effect.nextmove_modifier() adj += effect.nextmove_adjust() @@ -107,6 +109,7 @@ CtrlClickOn(A) return + // VOIDCREW EDIT: Allow slow item actions in soft crit through incapacitated_except_softcrit(). if(incapacitated_except_softcrit(INCAPABLE_RESTRAINTS|INCAPABLE_STASIS)) return diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 28b2a90962e..3df4d448587 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -131,6 +131,7 @@ /atom/movable/screen/alert/MouseExited() + // VOIDCREW EDIT: Run parent screen initialization for Voidcrew HUD extensions in voidcrew/edits/_onclick/hud. . = ..() closeToolTip(usr) diff --git a/code/_onclick/hud/blob_overmind.dm b/code/_onclick/hud/blob_overmind.dm index e2c4f57c573..10e85b488e3 100644 --- a/code/_onclick/hud/blob_overmind.dm +++ b/code/_onclick/hud/blob_overmind.dm @@ -8,6 +8,7 @@ openToolTip(usr,src,params,title = name,content = desc, theme = "blob") /atom/movable/screen/blob/MouseExited() + // VOIDCREW EDIT: Run parent screen initialization for Voidcrew HUD extensions in voidcrew/edits/_onclick/hud. . = ..() closeToolTip(usr) diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 2cd1d98c8be..c3857f13ed8 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -191,6 +191,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list( // A hud can outlive its mob (and plane groups can be rebuilt while detached), and this // runs at the very top of build_planes_offset() - runtiming here skips the whole // offset rebuild, which is how clients end up rendering to planes that have no master. + // VOIDCREW EDIT: Tolerate a HUD that outlives its mob during plane offset rebuilding. return should_sight_scale(mymob?.sight) /datum/hud/proc/should_sight_scale(sight_flags) @@ -215,50 +216,6 @@ GLOBAL_LIST_INIT(available_ui_styles, list( var/datum/plane_master_group/group = master_groups[group_key] group.build_planes_offset(src, new_offset) -// VOIDCREW EDIT ADDITION BEGIN - the health doll has to be re-sent on a z change (issue #126) -/** - * Takes the health doll off the client's screen and puts it straight back, so the client - * re-establishes the doll's visual contents. - * - * The doll draws each limb as a separate screen object in its own vis_contents - * (/atom/movable/screen/healthdoll/human/update_body_zones in screen_objects.dm), because - * upstream wants per-limb outline filters it can animate. On a z change - which here is - * every single dock and undock - the BYOND client drops those children and never gets - * them back. This is a known client-side bug class, not a DM one: BYOND id:2303806 - * ("Visual contents were not taken into account by the client-side garbage collector... - * The objects still exist, just aren't visible unless you change an appearance var to - * bring them back into the view") and id:2359025 ("visual contents no longer showed up - * after changing Z levels"). Server side the limbs stay alive with correct icon_states - * throughout - there are no runtimes for them in any round log, and nothing in DM touches - * the doll on a z change. - * - * vis_contents is not part of an atom's appearance, and the doll has no icon_state and no - * overlays of its own, so its appearance never changes for its entire life and the client - * is never told about it a second time. That leaves a limb's own icon_state as the only - * thing that can bring it back, which is exactly what players reported ("get damage on - * that limb and heal it to fix it") and why the limbs surviving a dock were always the - * ones that had taken or healed damage since. - * - * Re-adding the doll to client.screen re-sends it and its children. This is the same - * treatment the parallax backdrop already gets by accident: it is the only other screen - * object built on vis_contents, and update_parallax_pref() above tears its holder off the - * screen and adds it back (remove_parallax/create_parallax in parallax.dm) on every z - * change, which is why parallax does not rot the way the doll did. - * - * Do not "simplify" this into update_appearance() or update_body_zones(). The first - * changes nothing about the doll's appearance so nothing is sent; the second rebuilds six - * screen objects to repair a link that was never broken server side. - */ -/datum/hud/proc/resend_healthdoll() - var/client/our_client = mymob?.client - if(isnull(our_client) || isnull(healthdoll)) - return - // Hud hidden with F12? The doll is deliberately off the screen, leave it off. - if(!(healthdoll in our_client.screen)) - return - our_client.screen -= healthdoll - our_client.screen += healthdoll -// VOIDCREW EDIT ADDITION END /datum/hud/Destroy() if(mymob.hud_used == src) @@ -322,6 +279,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list( /datum/hud/proc/build_plane_groups(starting_offset, ending_offset) for(var/group_key in master_groups) var/datum/plane_master_group/group = master_groups[group_key] + // VOIDCREW EDIT START: Refresh newly built HUD planes after live z-level growth (voidcrew/edits/_onclick/hud). var/list/atom/movable/screen/plane_master/new_planes = group.build_plane_masters(starting_offset, ending_offset) if(!length(new_planes)) continue @@ -330,6 +288,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list( // Match what group creation does after show_hud(), so the planes we just added get the same multiz // scaling and in/out of bounds treatment a client who connected after the load would have gotten group.build_planes_offset(src, current_plane_offset) + // VOIDCREW EDIT END /// Returns the plane master that matches the input plane from the passed in group /datum/hud/proc/get_plane_master(plane, group_key = PLANE_GROUP_MAIN) @@ -855,21 +814,25 @@ GLOBAL_LIST_INIT(available_ui_styles, list( if(!length(actions)) palette.set_expanded(FALSE) +// VOIDCREW EDIT REMOVAL: Disable the upstream palette layout replaced by voidcrew/edits/_onclick/hud, preserving the existing override chain. ///Commenting out due to this being replaced in 'voidcrew\edits\_onclick\hud' and the return ..() requirement // /datum/action_group/palette/refresh_actions() // var/atom/movable/screen/button_palette/palette = owner.toggle_palette // var/atom/movable/screen/palette_scroll/scroll_down = owner.palette_down // var/atom/movable/screen/palette_scroll/scroll_up = owner.palette_up +// VOIDCREW EDIT REMOVAL: Disable the upstream palette layout replaced by voidcrew/edits/_onclick/hud, preserving the existing override chain. // var/actions_above = round((owner.listed_actions.size() - 1) / owner.listed_actions.column_max) // north_offset = initial(north_offset) + actions_above +// VOIDCREW EDIT REMOVAL: Disable the upstream palette layout replaced by voidcrew/edits/_onclick/hud, preserving the existing override chain. // palette.screen_loc = ui_action_palette_offset(actions_above) // var/action_count = length(owner?.mymob?.actions) // var/our_row_count = round((length(actions) - 1) / column_max) // if(!action_count) // palette.screen_loc = null +// VOIDCREW EDIT REMOVAL: Disable the upstream palette layout replaced by voidcrew/edits/_onclick/hud, preserving the existing override chain. // if(palette.expanded && action_count && our_row_count >= max_rows) // scroll_down.screen_loc = ui_palette_scroll_offset(actions_above) // scroll_up.screen_loc = ui_palette_scroll_offset(actions_above) @@ -877,6 +840,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list( // scroll_down.screen_loc = null // scroll_up.screen_loc = null +// VOIDCREW EDIT REMOVAL: Disable the upstream palette layout replaced by voidcrew/edits/_onclick/hud, preserving the existing override chain. // return ..() /datum/action_group/palette/ButtonNumberToScreenCoords(number, landing) diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 53d823816d0..f029164904e 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -64,11 +64,13 @@ using = new /atom/movable/screen/navigate(null, src) using.icon = ui_style using.screen_loc = ui_human_navigate + // VOIDCREW EDIT START: Install the skill-report HUD shortcut defined in voidcrew/edits/_onclick/hud/screen_extensions.dm. static_inventory += using using = new /atom/movable/screen/skills(null, src) using.icon = ui_style using.screen_loc = ui_human_skills + // VOIDCREW EDIT END static_inventory += using using = new /atom/movable/screen/area_creator(null, src) @@ -390,7 +392,6 @@ screenmob.client.screen -= H.head - /datum/hud/human/persistent_inventory_update(mob/viewer) if(!mymob) return diff --git a/code/_onclick/hud/new_player.dm b/code/_onclick/hud/new_player.dm index d46ea65ec0f..800ad360318 100644 --- a/code/_onclick/hud/new_player.dm +++ b/code/_onclick/hud/new_player.dm @@ -224,9 +224,11 @@ // transfer ran straight into "Cannot read null.prefs" here. The prefs datum is also // per-client, and /datum/preferences/ui_status() closes the menu unless // user.client == parent, so reading it off any other client's mob is wrong anyway. + // VOIDCREW EDIT START: Resolve preferences from the clicking client safely across logout and mob transfer. var/datum/preferences/preferences = usr.client?.prefs if(!preferences) return + // VOIDCREW EDIT END preferences.current_window = PREFERENCE_TAB_CHARACTER_PREFERENCES preferences.update_static_data(usr) preferences.ui_interact(usr) @@ -419,9 +421,11 @@ return // Same as the Character Setup button above: the clicking client's own prefs. + // VOIDCREW EDIT START: Resolve preferences from the clicking client safely across logout and mob transfer. var/datum/preferences/preferences = usr.client?.prefs if(!preferences) return + // VOIDCREW EDIT END preferences.current_window = PREFERENCE_TAB_GAME_PREFERENCES preferences.update_static_data(usr) preferences.ui_interact(usr) @@ -759,8 +763,10 @@ var/new_maptext var/round_started = SSticker.HasRoundStarted() if(round_started) + // VOIDCREW EDIT START: Show fleet player count without a station map name in the lobby HUD. new_maptext = "[LAZYLEN(GLOB.clients)] player\s online
\ [ROUND_TIME()] in
" + // VOIDCREW EDIT END var/datum/station_trait/overflow_job_bureaucracy/overflow = locate() in SSstation.station_traits if(overflow) new_maptext += "[overflow.chosen_job_name] overflow" diff --git a/code/_onclick/hud/parallax/parallax.dm b/code/_onclick/hud/parallax/parallax.dm index 202e6a29910..2f2aa42fe75 100644 --- a/code/_onclick/hud/parallax/parallax.dm +++ b/code/_onclick/hud/parallax/parallax.dm @@ -177,6 +177,7 @@ return C.parallax_animate_timers -= layer if(!layer.scroll_loops) // VOIDCREW EDIT ADDITION - see set_parallax_movedir() + // VOIDCREW EDIT: Do not reschedule parallax animation after its scroll loop has been disabled (voidcrew/edits/_onclick/hud). return // If we are moving in a direction, we used the QUAD_EASING function with EASE_IN diff --git a/code/_onclick/hud/rendering/plane_master_group.dm b/code/_onclick/hud/rendering/plane_master_group.dm index 8ce665c7bff..7ae727cfd09 100644 --- a/code/_onclick/hud/rendering/plane_master_group.dm +++ b/code/_onclick/hud/rendering/plane_master_group.dm @@ -95,6 +95,7 @@ /// Actually generate our plane masters, in some offset range (where offset is the z layers to render to, because each "layer" in a multiz stack gets its own plane master cube) /// Returns the list of plane masters we just built, so callers that run after we already have a hud can show them /datum/plane_master_group/proc/build_plane_masters(starting_offset, ending_offset) + // VOIDCREW EDIT: Return new plane masters so the HUD can show and offset planes after a live map load. var/list/atom/movable/screen/plane_master/built = list() for(var/atom/movable/screen/plane_master/mytype as anything in get_plane_types()) for(var/plane_offset in starting_offset to ending_offset) @@ -103,8 +104,10 @@ var/atom/movable/screen/plane_master/instance = new mytype(null, null, src, plane_offset) plane_masters["[instance.plane]"] = instance prep_plane_instance(instance) + // VOIDCREW EDIT START: Return new plane masters so the HUD can show and offset planes after a live map load. built += instance return built + // VOIDCREW EDIT END /// Similarly, exists so subtypes can do unique behavior to planes on creation /datum/plane_master_group/proc/prep_plane_instance(atom/movable/screen/plane_master/instance) diff --git a/code/_onclick/hud/rendering/plane_masters/_plane_master.dm b/code/_onclick/hud/rendering/plane_masters/_plane_master.dm index 84a0412639e..c6e266b53e8 100644 --- a/code/_onclick/hud/rendering/plane_masters/_plane_master.dm +++ b/code/_onclick/hud/rendering/plane_masters/_plane_master.dm @@ -214,6 +214,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) // all pass `our_hud?.mymob`). hide_from() below tolerates that, so this must too - // a runtime here aborts whatever loop is walking the plane masters and leaves the // client with planes nothing is managing. + // VOIDCREW EDIT: Tolerate detached HUD mobs while hiding and restoring plane masters. var/client/our_client = relevant?.client if(our_client) for(var/atom/movable/render_plane_relay/relay as anything in relays) @@ -231,6 +232,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) if(!(critical & PLANE_CRITICAL_NO_RELAY)) return + // VOIDCREW EDIT: Tolerate detached HUD mobs while hiding and restoring plane masters. var/client/our_client = relevant?.client if(our_client) for(var/atom/movable/render_plane_relay/relay as anything in relays) diff --git a/code/_onclick/hud/rendering/render_plate.dm b/code/_onclick/hud/rendering/render_plate.dm index ed3ca8682be..a3e05c43f2a 100644 --- a/code/_onclick/hud/rendering/render_plate.dm +++ b/code/_onclick/hud/rendering/render_plate.dm @@ -205,8 +205,10 @@ // unhide_plane() callsite passes `our_hud?.mymob`, so null gets here for real. Runtiming // would abort whichever loop is walking the plane masters (show_hud(), build_planes_offset(), // the COMSIG_PLANE_OFFSET_INCREASE fanout) and leave planes with no master managing them. + // VOIDCREW EDIT START: Guard detached HUD mobs during lighting plate and sight-signal cleanup. if(!istype(mymob)) return + // VOIDCREW EDIT END // This applies a backdrop to our lighting plane // Why do plane masters need a backdrop sometimes? Read https://secure.byond.com/forum/?post=2141928 // Basically, we need something to brighten @@ -230,9 +232,11 @@ /atom/movable/screen/plane_master/rendering_plate/lighting/hide_from(mob/oldmob) . = ..() + // VOIDCREW EDIT START: Guard detached HUD mobs during lighting plate and sight-signal cleanup. if(istype(oldmob)) oldmob.clear_fullscreen("lighting_backdrop_lit_[home.key]#[offset]") oldmob.clear_fullscreen("lighting_backdrop_unlit_[home.key]#[offset]") + // VOIDCREW EDIT END var/datum/hud/hud = home.our_hud if(hud) UnregisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(on_offset_change)) @@ -288,8 +292,10 @@ if(!.) return // See the lighting plate above - a null/clientless mob is a supported caller here. + // VOIDCREW EDIT START: Guard detached HUD mobs during lighting plate and sight-signal cleanup. if(!istype(mymob)) return + // VOIDCREW EDIT END RegisterSignal(mymob, COMSIG_MOB_SIGHT_CHANGE, PROC_REF(handle_sight), override = TRUE) handle_sight(mymob, mymob.sight, NONE) @@ -299,8 +305,10 @@ var/atom/movable/screen/plane_master/emissive = home.get_plane(GET_NEW_PLANE(RENDER_PLANE_EMISSIVE, offset)) emissive.remove_filter("lighting_mask") remove_relay_from(GET_NEW_PLANE(RENDER_PLANE_GAME, offset)) + // VOIDCREW EDIT START: Guard detached HUD mobs during lighting plate and sight-signal cleanup. if(istype(oldmob)) UnregisterSignal(oldmob, COMSIG_MOB_SIGHT_CHANGE) + // VOIDCREW EDIT END /atom/movable/screen/plane_master/rendering_plate/light_mask/proc/handle_sight(datum/source, new_sight, old_sight) // If we can see something that shows "through" blackness, and we can't see turfs, disable our draw to the game plane diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 6740be49574..62db39a16cb 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -132,16 +132,6 @@ var/mob/living/navigator = usr navigator.navigate() -/// Shortcut to the same personal skill report provided by the View Skills verb. -/atom/movable/screen/skills - name = "view skills and experience" - icon = 'icons/hud/screen_midnight.dmi' - icon_state = "skills" - mouse_over_pointer = MOUSE_HAND_POINTER - -/atom/movable/screen/skills/Click() - usr.view_skills() - return TRUE /atom/movable/screen/craft name = "crafting menu" @@ -196,6 +186,7 @@ if(world.time <= usr.next_move) return TRUE + // VOIDCREW EDIT: Allow inventory interaction in soft crit via incapacitated_except_softcrit(). if(usr.incapacitated_except_softcrit(INCAPABLE_STASIS)) return TRUE if(ismecha(usr.loc)) // stops inventory actions in a mech @@ -286,6 +277,7 @@ return TRUE if(world.time <= user.next_move) return TRUE + // VOIDCREW EDIT: Allow inventory interaction in soft crit via incapacitated_except_softcrit(). if(user.incapacitated_except_softcrit()) return TRUE if (ismecha(user.loc)) // stops inventory actions in a mech @@ -530,6 +522,7 @@ if(world.time <= usr.next_move) return TRUE + // VOIDCREW EDIT: Allow inventory interaction in soft crit via incapacitated_except_softcrit(). if(usr.incapacitated_except_softcrit()) return TRUE if(ismecha(usr.loc)) // stops inventory actions in a mech @@ -647,6 +640,7 @@ plane = ABOVE_HUD_PLANE /atom/movable/screen/zone_sel/MouseExited(location, control, params) + // VOIDCREW EDIT: Allow inventory interaction in soft crit via incapacitated_except_softcrit(). . = ..() if(!isobserver(usr) && hovering) vis_contents -= hover_overlays_cache[hovering] @@ -804,9 +798,12 @@ update_appearance() /atom/movable/screen/healthdoll/human/update_body_zones() + // VOIDCREW EDIT REMOVAL: Allow inventory interaction in soft crit via incapacitated_except_softcrit(). vis_contents.Cut() + // VOIDCREW EDIT START: Allow inventory interaction in soft crit via incapacitated_except_softcrit(). QDEL_LIST_ASSOC_VAL(limbs) limbs ||= list() + // VOIDCREW EDIT END var/mob/living/carbon/human/owner = hud.mymob for(var/body_zone in owner.get_all_limbs()) var/atom/movable/screen/healthdoll_limb/limb = new(src, null) @@ -837,8 +834,10 @@ var/icon_key = 0 var/part_zone = body_part.body_zone // I hate that we "allow" support for more than 2 hands in the codebase + // VOIDCREW EDIT START: Allow inventory interaction in soft crit via incapacitated_except_softcrit(). if(!limbs[part_zone]) continue + // VOIDCREW EDIT END var/list/overridable_key = list(icon_key) if(body_part.bodypart_disabled) diff --git a/code/_onclick/hud/screentip.dm b/code/_onclick/hud/screentip.dm index 5aae8dc4809..dac8a1a536c 100644 --- a/code/_onclick/hud/screentip.dm +++ b/code/_onclick/hud/screentip.dm @@ -7,79 +7,17 @@ maptext_width = 480 maptext = "" layer = SCREENTIP_LAYER //Added to make screentips appear above action buttons (and other /atom/movable/screen objects) - /// Weak reference so hovering cannot keep a deleted target alive. - var/datum/weakref/hovered_atom_ref - /// Invalidates text measurements that finish after the pointer has moved on. - var/hover_version = 0 - var/showing_hover = FALSE - /// Refreshed separately from mouse events, including while our ship is moving. - var/fallback_maptext = "" /atom/movable/screen/screentip/Initialize(mapload, datum/hud/hud_owner) . = ..() update_view() + // VOIDCREW EDIT START: Initialize the persistent hover and overmap fallback lifecycle in voidcrew/edits/_onclick/hud/screen_extensions.dm. update_fallback() START_PROCESSING(SSprocessing, src) if(hud?.mymob) RegisterSignal(hud.mymob, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT), PROC_REF(on_connection_changed)) + // VOIDCREW EDIT END -/atom/movable/screen/screentip/Destroy() - STOP_PROCESSING(SSprocessing, src) - hovered_atom_ref = null - return ..() - -/atom/movable/screen/screentip/process(seconds_per_tick) - if(!hud?.mymob?.client) - return - if(hovered_atom_ref && !hovered_atom_ref.resolve()) - clear_hover() - update_fallback() - -/// Starts a hover and returns the version to use for asynchronous text measurement. -/atom/movable/screen/screentip/proc/begin_hover(atom/target) - hovered_atom_ref = WEAKREF(target) - return ++hover_version - -/// An exit from an older target must not clear a more recent hover. -/atom/movable/screen/screentip/proc/clear_hover(atom/target) - if(target && !IS_WEAKREF_OF(target, hovered_atom_ref)) - return - hovered_atom_ref = null - hover_version++ - set_hover_text("") - -/// Empty or suppressed hover text gives the fallback its turn. -/atom/movable/screen/screentip/proc/set_hover_text(new_maptext, text_y = 10) - showing_hover = length(new_maptext) > 0 - if(showing_hover) - maptext = new_maptext - maptext_y = text_y - else - show_fallback() - -/atom/movable/screen/screentip/proc/show_fallback() - maptext = hud?.screentips_enabled == SCREENTIP_PREFERENCE_DISABLED ? "" : fallback_maptext - maptext_y = 10 - -/atom/movable/screen/screentip/proc/update_fallback() - fallback_maptext = hud?.screentips_enabled == SCREENTIP_PREFERENCE_DISABLED ? "" : get_fallback_maptext() - if(!showing_hover) - show_fallback() - -/// Reused HUDs must not retain a hover from the previous connection. -/atom/movable/screen/screentip/proc/on_connection_changed(datum/source) - SIGNAL_HANDLER - update_fallback() - clear_hover() - -/// Reapply a changed preference even when the pointer stays still. -/atom/movable/screen/screentip/proc/refresh_hover() - update_fallback() - var/atom/target = hovered_atom_ref?.resolve() - if(target && hud?.mymob?.client) - target.on_mouse_enter(hud.mymob.client) - else - clear_hover() /atom/movable/screen/screentip/proc/update_view(datum/source) SIGNAL_HANDLER diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index f46b6f2d80b..80bc0e6dd5c 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -39,9 +39,11 @@ // base_click_alt() is a dead end for ghosts: can_perform_action() is always false for them, // so alt clicking as a ghost did nothing at all. if(LAZYACCESS(modifiers, RIGHT_CLICK)) + // VOIDCREW EDIT START: Dispatch observer alt clicks to the loot and admin tagging handlers in voidcrew/edits/_onclick. AltClickSecondaryOn(A) else AltClickOn(A) + // VOIDCREW EDIT END return if(LAZYACCESS(modifiers, CTRL_CLICK)) CtrlClickOn(A) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 18865f5094c..874d43c84b1 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -52,14 +52,18 @@ return FALSE if(!right_click_attack_chain(attack_target, modifiers)) + // VOIDCREW EDIT START: Report actual resolved unarmed damage to Voidcrew combat listeners after the attack. var/mob/living/living_target = isliving(attack_target) ? attack_target : null var/health_before = living_target?.health var/stamina_before = living_target?.getStaminaLoss() + // VOIDCREW EDIT END resolve_unarmed_attack(attack_target, modifiers) // Report real damage after pacifism, blocking, and attack-type checks have run. // Keep the local reference through the call so lethal DEL_ON_DEATH hits still report their result. + // VOIDCREW EDIT START: Report actual resolved unarmed damage to Voidcrew combat listeners after the attack. if(living_target) SEND_SIGNAL(src, COMSIG_LIVING_AFTER_UNARMED_ATTACK, attack_target, modifiers, max(0, health_before - living_target.health), max(0, living_target.getStaminaLoss() - stamina_before)) + // VOIDCREW EDIT END return TRUE /mob/living/carbon/human/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index 7157b0aa1b3..6a7fd36072f 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -461,8 +461,6 @@ /datum/config_entry/string/new_player_alert_role_id -/// Discord role ID pinged in the new-round announcement sent to CHANNEL_ANNOUNCE_NEW_GAME channels -/datum/config_entry/string/new_round_alert_role_id /datum/config_entry/keyed_list/positive_station_traits default = list("0" = 8, "1" = 4, "2" = 2, "3" = 1) diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index f0f0149f7a6..3312c10968f 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -29,31 +29,6 @@ SUBSYSTEM_DEF(air) var/list/rebuild_queue = list() //Subservient to rebuild queue var/list/expansion_queue = list() - /// VOIDCREW ADDITION: pipelines that lost their last member to a pipe steal in - /// expand_pipeline() while they were still flagged `building`. That call site cannot - /// qdel one on the spot - /datum/pipeline/Destroy() edits expansion_queue, which is the - /// list that drain is walking - so the husk is parked here and reaped on a later fire, - /// once `building` has cleared and it is provably still empty. Without this a - /// stacked-pipe map (every voidcrew hull has some) leaks one member-less pipeline into - /// SSair.networks per site build, processed every tick for the rest of the round. - var/list/datum/pipeline/pipeline_husks = list() - /// VOIDCREW ADDITION: how many consecutive orphan sweeps a pipeline has to be found - /// empty on before it is reaped. build_pipeline() legitimately leaves a pipeline with - /// no members for the window between `new /datum/pipeline` and its queued expansion, - /// so one strike is not proof of a leak - two separate sweeps is. - var/orphan_pipeline_strikes = 2 - /// VOIDCREW ADDITION: world.time the next orphan-pipeline sweep may run. The sweep is - /// O(networks * members) and nothing it catches is urgent, so it is rate limited. - var/next_orphan_sweep = 0 - /// VOIDCREW ADDITION: how long between orphan-pipeline sweeps. Short on purpose: two - /// strikes at this interval is how long an orphan can survive, and the churn soak - /// samples 20 seconds after a teardown. At 5 seconds an orphan made during teardown is - /// always gone before the sample, so `pipelines_orphan` reads a real state rather than - /// whatever happened to be in flight. Sweeping ~70 networks costs nothing. - var/orphan_sweep_interval = 5 SECONDS - /// VOIDCREW ADDITION: running total of pipelines the orphan sweep has reaped, for the - /// churn-soak harness and for `SSair` debug output. - var/orphan_pipelines_reaped = 0 /// List of turfs to recalculate adjacent turfs on before processing var/list/adjacent_rebuild = list() /// A list of machines that will be processed when currentpart == SSAIR_ATMOSMACHINERY. Use SSair.begin_processing_machine and SSair.stop_processing_machine to add and remove machines. @@ -150,6 +125,7 @@ SUBSYSTEM_DEF(air) // outside process_rebuilds() - that block only runs when a queue is non-empty, and an // orphan by definition is not in any queue. Runs before the drain so it can never be // editing networks/expansion_queue while expand_pipeline() is walking them. + // VOIDCREW EDIT: Keep atmos rebuild cleanup safe across repeated site loads (voidcrew/edits/subsystem/air_cleanup.dm). reap_orphan_pipelines() // Every time we fire, we want to make sure pipenets are rebuilt. The game state could have changed between each fire() proc call @@ -325,6 +301,7 @@ SUBSYSTEM_DEF(air) // constantly: pipe/nullify_node() queues the neighbour it just disconnected from, and // during a mass deletion that neighbour is very often already in the qdel queue. if(QDELETED(atmos_machine)) + // VOIDCREW EDIT: Keep atmos rebuild cleanup safe across repeated site loads (voidcrew/edits/subsystem/air_cleanup.dm). return if(istype(atmos_machine, /obj/machinery/atmospherics) && !atmos_machine.rebuilding) rebuild_queue += atmos_machine @@ -342,6 +319,7 @@ SUBSYSTEM_DEF(air) for(var/list/packet in expansion_queue.Copy()) if(packet[SSAIR_REBUILD_PIPELINE] == line) expansion_queue -= packet +// VOIDCREW EDIT REMOVAL: Remove every queued expansion packet for a deleted pipeline instead of stopping after the first match. /datum/controller/subsystem/air/proc/process_atoms(resumed = FALSE) if(!resumed) @@ -442,79 +420,9 @@ SUBSYSTEM_DEF(air) if (MC_TICK_CHECK) return -/** - * VOIDCREW ADDITION: deletes the member-less pipelines expand_pipeline() had to park. - * - * Runs before the drain rather than inside it: /datum/pipeline/Destroy() calls - * remove_from_expansion(), which edits the very list expand_pipeline() walks. By the time - * we get here that drain has finished (or has not started), so the edit is safe. - * - * A husk is only deleted once `building` has cleared - while it is set the pipeline is - * still queued for expansion and may legitimately pick members back up. - */ -/datum/controller/subsystem/air/proc/reap_pipeline_husks() - if(!length(pipeline_husks)) - return - for(var/datum/pipeline/husk as anything in pipeline_husks.Copy()) - if(QDELETED(husk)) - pipeline_husks -= husk - continue - if(husk.building) - continue - pipeline_husks -= husk - // VOIDCREW EDIT: has_live_members() rather than length(). A husk that was holding - // a machine which then hard deleted reads as length 1 with a null inside, and the - // old length test let it walk away as if it were still in use. - if(husk.has_live_members()) - continue - qdel(husk) - -/** - * VOIDCREW ADDITION: reaps member-less pipelines that never went through the husk list. - * - * `reap_pipeline_husks()` only ever sees pipelines parked by the pipe-steal branch of - * `expand_pipeline()`. The other way a pipeline ends up empty in `SSair.networks` is a - * machine that was already dying when something queued it for a rebuild: `rebuild_pipes()` - * mints a fresh `/datum/pipeline` for it, the machine's `Destroy()` has already run its - * `QDEL_NULL(parent)`, and so nothing is ever going to delete that pipeline again. It sits - * in `networks` being processed every fire for the rest of the round, and it holds a hard - * ref to the dead machine while it is at it. The source guards below stop new ones being - * made; this sweep clears any that still get through. - * - * Two details this has to get right: - * * `length(members)` is not the test. A hard-deleted machine leaves a null entry in the - * list rather than shortening it, so a leaked pipeline reads as `members = list(null)` - - * length 1, live members 0. `has_live_members()` counts what is actually there. - * * `/datum/pipeline/Destroy()` edits `networks`, `expansion_queue` and `pipeline_husks`. - * So: walk a copy, collect, and qdel only after the walk is over - and run outside the - * expansion drain, the same placement `reap_pipeline_husks()` already uses. - */ -/datum/controller/subsystem/air/proc/reap_orphan_pipelines() - if(world.time < next_orphan_sweep) - return - next_orphan_sweep = world.time + orphan_sweep_interval - var/list/datum/pipeline/doomed = list() - for(var/datum/pipeline/net as anything in networks.Copy()) - if(isnull(net) || QDELETED(net)) - continue - // Still queued for expansion - it is allowed to be empty and may pick members up. - if(net.building) - net.orphan_strikes = 0 - continue - if(net.has_live_members()) - net.orphan_strikes = 0 - continue - net.orphan_strikes++ - if(net.orphan_strikes < orphan_pipeline_strikes) - continue - doomed += net - if(!length(doomed)) - return - orphan_pipelines_reaped += length(doomed) - for(var/datum/pipeline/net as anything in doomed) - qdel(net) /datum/controller/subsystem/air/proc/process_rebuilds() + // VOIDCREW EDIT: Keep atmos rebuild cleanup safe across repeated site loads (voidcrew/edits/subsystem/air_cleanup.dm). reap_pipeline_husks() //Yes this does mean rebuilding pipenets can freeze up the subsystem forever, but if we're in that situation something else is very wrong var/list/currentrun = rebuild_queue @@ -593,11 +501,13 @@ SUBSYSTEM_DEF(air) // expansion_queue, which is the list this very drain is walking. Park it and // let reap_pipeline_husks() take it on a later fire - leaving it was a // permanent member-less pipeline in SSair.networks, one per site build. + // VOIDCREW EDIT START: Keep atmos rebuild cleanup safe across repeated site loads (voidcrew/edits/subsystem/air_cleanup.dm). if(stolen_from && stolen_from != net && !QDELETED(stolen_from) && !length(stolen_from.members) && !length(stolen_from.other_atmos_machines)) if(stolen_from.building) pipeline_husks |= stolen_from else qdel(stolen_from) + // VOIDCREW EDIT END if(item.air_temporary) net.air.merge(item.air_temporary) @@ -857,6 +767,7 @@ SUBSYSTEM_DEF(air) // pipeline into SSair.networks, and a machine that deleted itself during its own // Initialize() will never delete that pipeline again. if(QDELETED(AM)) + // VOIDCREW EDIT: Keep atmos rebuild cleanup safe across repeated site loads (voidcrew/edits/subsystem/air_cleanup.dm). continue var/list/targets = AM.get_rebuild_targets() for(var/datum/pipeline/build_off as anything in targets) @@ -891,6 +802,7 @@ GLOBAL_LIST_EMPTY(colored_images) // (stacked pipes on one turf, which every voidcrew hull has some of). Minting a // pipeline for it leaks one per template load, and this soak loads constantly. if(QDELETED(AM)) + // VOIDCREW EDIT: Keep atmos rebuild cleanup safe across repeated site loads (voidcrew/edits/subsystem/air_cleanup.dm). continue var/list/targets = AM.get_rebuild_targets() for(var/datum/pipeline/build_off as anything in targets) @@ -950,8 +862,10 @@ GLOBAL_LIST_EMPTY(colored_images) // ADD_GAS below then indexes a null list once per turf that uses the string. // Warn once for the mix instead and leave that component out. if(!ispath(path)) + // VOIDCREW EDIT START: Keep atmos rebuild cleanup safe across repeated site loads (voidcrew/edits/subsystem/air_cleanup.dm). stack_trace("parse_gas_string(): unknown gas id \"[id]\" in gas string \"[gas_string]\" - ignoring it.") continue + // VOIDCREW EDIT END ADD_GAS(path, gases) gases[path][MOLES] = text2num(gas[id]) diff --git a/code/controllers/subsystem/area_contents.dm b/code/controllers/subsystem/area_contents.dm index 67306dc1662..e7b27d50039 100644 --- a/code/controllers/subsystem/area_contents.dm +++ b/code/controllers/subsystem/area_contents.dm @@ -34,11 +34,13 @@ SUBSYSTEM_DEF(area_contents) var/area/test = currentrun[length(currentrun)] // A destroyed area has both bookkeeping lists nulled, so there is nothing to mark and // marking it would only pin the corpse until the next drain. + // VOIDCREW EDIT START: Discard destroyed areas from deferred turf bookkeeping during site teardown. if(!QDELETED(test)) for (var/area_zlevel in 1 to length(test.turfs_to_uncontain_by_zlevel)) if(length(test.turfs_to_uncontain_by_zlevel[area_zlevel]) > ALLOWED_LOOSE_TURFS) marked_for_clearing |= test break + // VOIDCREW EDIT END currentrun.len-- if(MC_TICK_CHECK) return @@ -49,11 +51,13 @@ SUBSYSTEM_DEF(area_contents) // Marked during the scan, died before the drain reached it. /area/Destroy() nulls // turfs_to_uncontain_by_zlevel, so every length() below would read 0 anyway - drop it // rather than leaving a dead area sitting at the end of the list. + // VOIDCREW EDIT START: Discard destroyed areas from deferred turf bookkeeping during site teardown. if(QDELETED(clear) || isnull(clear.turfs_to_uncontain_by_zlevel)) marked_for_clearing.len-- if(MC_TICK_CHECK) return continue + // VOIDCREW EDIT END for (var/area_zlevel in 1 to length(clear.turfs_to_uncontain_by_zlevel)) if (!length(clear.turfs_to_uncontain_by_zlevel[area_zlevel])) diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index d5075fbffff..3cab2e1ccc6 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -56,16 +56,19 @@ SUBSYSTEM_DEF(atoms) clear_tracked_initalize(source) SSicon_smooth.free_deferred(source) + // VOIDCREW EDIT START: Give nested live template loads separate late-initialization queues. while(length(late_loaders)) // Late callbacks can load another map. Give that load its own queue so it // cannot repeat or clear the callbacks this invocation is still processing. var/list/current_late_loaders = late_loaders late_loaders = list() for(var/atom/A as anything in current_late_loaders) + // VOIDCREW EDIT END //I hate that we need this if(QDELETED(A)) continue A.LateInitialize() + // VOIDCREW EDIT: Give nested live template loads separate late-initialization queues. testing("Late initialized [length(current_late_loaders)] atoms") if (created_atoms) diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm index 0e86ab70806..c1f1321cc67 100644 --- a/code/controllers/subsystem/explosions.dm +++ b/code/controllers/subsystem/explosions.dm @@ -189,7 +189,6 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec explosion(epicenter, devastation_range = round(range * 0.25), heavy_impact_range = round(range * 0.5), light_impact_range = round(range), flame_range = flame_range*range, flash_range = flash_range*range, adminlog = adminlog, ignorecap = ignorecap, silent = silent, smoke = smoke, explosion_cause = explosion_cause) - /** * Makes a given atom explode. * @@ -301,9 +300,11 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec if(!epicenter) return // VOIDCREW: suppress the blast before smoke, flashes, fire, or chain reactions. + // VOIDCREW EDIT START: Stop protected outpost blasts before smoke, flash, ignition and damage (voidcrew/modules/trade/outpost_security.dm). if(is_trader_outpost_protected(epicenter)) log_game("OUTPOST PROTECTION: Suppressed explosion ([devastation_range], [heavy_impact_range], [light_impact_range]) at [AREACOORD(epicenter)]. Cause: [explosion_cause]. Last fingerprints: [key_name(explosion_cause?.fingerprintslast)].") return + // VOIDCREW EDIT END if(isnull(flame_range)) flame_range = light_impact_range @@ -397,8 +398,10 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec //flash mobs if(flash_range) for(var/mob/living/L in viewers(flash_range, epicenter)) + // VOIDCREW EDIT START: Stop protected outpost blasts before smoke, flash, ignition and damage (voidcrew/modules/trade/outpost_security.dm). if(is_trader_outpost_protected(L)) // VOIDCREW continue + // VOIDCREW EDIT END L.flash_act() var/list/affected_turfs = prepare_explosion_turfs(max_range, epicenter, protect_epicenter, explosion_direction, explosion_arc) @@ -414,9 +417,11 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec //we presuppose that we'll be iterating away from the epicenter for(var/turf/explode as anything in affected_turfs) // VOIDCREW: outside blasts cannot damage, ignite, or throw outpost contents. + // VOIDCREW EDIT START: Stop protected outpost blasts before smoke, flash, ignition and damage (voidcrew/modules/trade/outpost_security.dm). if(is_trader_outpost_protected(explode)) cached_exp_block[explode] = INFINITY continue + // VOIDCREW EDIT END var/our_x = explode.x var/our_y = explode.y var/dist = CHEAP_HYPOTENUSE(our_x, our_y, x0, y0) @@ -541,7 +546,7 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec else creaking = FALSE - // VOIDCREW EDIT ADDITION: packed-level containment. Resolved once, outside the loop. + // VOIDCREW EDIT ADDITION START: packed-level containment. Resolved once, outside the loop. // The walk below is GLOB.player_list filtered on bare z, and its reach is // heavy_impact_range * 15 + devastation_range * 20 - well over 100 tiles for a large // blast, against the 6 tiles that separate two tenants of a packed level. playsound_local() @@ -554,7 +559,7 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec var/turf/listener_turf = get_turf(listener) if(!listener_turf || listener_turf.z != blast_z) continue - // VOIDCREW EDIT ADDITION + // VOIDCREW EDIT ADDITION START if(map_region_excludes_turf(blast_region, listener_turf)) continue // VOIDCREW EDIT END diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 3c39d84cfc2..f68dc28959f 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -942,10 +942,12 @@ SUBSYSTEM_DEF(job) job_debug("[debug_prefix]: Player has no mind, Player: [player][add_job_to_log ? ", Job: [possible_job]" : ""]") return JOB_UNAVAILABLE_GENERIC + // VOIDCREW EDIT START: Use canonical role eligibility and configuration for mapper-selected silicon crew (voidcrew/modules/ship_upgrades). var/eligibility_title = possible_job.ship_role == "crew" ? possible_job.title : initial(possible_job.title) if(possible_job.ship_role != "crew" && !possible_job.config_check()) return JOB_UNAVAILABLE_GENERIC if(eligibility_title in LAZYACCESS(prevented_occupations, player.mind)) + // VOIDCREW EDIT END job_debug("[debug_prefix] Error: [get_job_unavailable_error_message(JOB_UNAVAILABLE_ANTAG_INCOMPAT, possible_job.title)], Player: [player][add_job_to_log ? ", Job: [possible_job]" : ""]") return JOB_UNAVAILABLE_ANTAG_INCOMPAT @@ -959,6 +961,7 @@ SUBSYSTEM_DEF(job) return JOB_UNAVAILABLE_PLAYTIME // Run the banned check last since it should be the rarest check to fail and can access the database. + // VOIDCREW EDIT: Use canonical role eligibility and configuration for mapper-selected silicon crew (voidcrew/modules/ship_upgrades). if(is_banned_from(player.ckey, eligibility_title)) job_debug("[debug_prefix] Error: [get_job_unavailable_error_message(JOB_UNAVAILABLE_BANNED, possible_job.title)], Player: [player][add_job_to_log ? ", Job: [possible_job]" : ""]") return JOB_UNAVAILABLE_BANNED diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm index 68803f4e2ce..39d8aa0f1e9 100644 --- a/code/controllers/subsystem/lighting.dm +++ b/code/controllers/subsystem/lighting.dm @@ -32,7 +32,7 @@ SUBSYSTEM_DEF(lighting) /datum/controller/subsystem/lighting/proc/create_all_lighting_objects() for(var/area/area as anything in GLOB.areas) - // VOIDCREW EDIT: ambient-lit ground (a planet surface, static_lighting FALSE) carries + // VOIDCREW EDIT START: ambient-lit ground (a planet surface, static_lighting FALSE) carries // no lighting objects at all - that is where the memory saving comes from - EXCEPT // turfs that light themselves, like the fallout zone's hazard green. Those need an // object apiece or their own light has nothing to render on, and roundstart planets @@ -47,7 +47,7 @@ SUBSYSTEM_DEF(lighting) for(var/turf/area_turf as anything in zlevel_turfs) if(area_turf.space_lit) continue - // VOIDCREW EDIT: see above + // VOIDCREW EDIT START: see above if(ambient_lit_area && area_turf.skips_lighting_object()) continue // END VOIDCREW EDIT @@ -67,6 +67,7 @@ SUBSYSTEM_DEF(lighting) // with needs_update set but in no queue, so EFFECT_UPDATE refuses to requeue // them and they stay dark forever. Salvage the remainder instead of leaking it. if(length(current_sources)) + // VOIDCREW EDIT: Handle planetary ambient lighting and interrupted source drains (voidcrew/edits/lighting.dm). sources_queue = current_sources + sources_queue current_sources = sources_queue sources_queue = list() diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 37dfcef412d..e10ca410f64 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -61,16 +61,6 @@ SUBSYSTEM_DEF(mapping) var/list/used_turfs = list() //list of turf = datum/turf_reservation /// List of lists of turfs to reserve var/list/lists_to_reserve = list() - // VOIDCREW EDIT ADDITION: one-shot latch for the dead-area recovery in fire() below. - /// Whether we have already reported a reservation turf found sitting in a destroyed area. - var/warned_about_dead_reservation_area = FALSE - // VOIDCREW EDIT ADDITION: released reservation turfs whose starlight has been switched - /// off and which still have to be taken out of GLOB.starlight. Assoc turf -> TRUE so the - /// compaction below is a membership test rather than a search. See release_reservation_starlight(). - var/list/starlight_release_queue - // VOIDCREW EDIT ADDITION: world.time the next used_turfs orphan sweep may run at. - /// Rate limit for reconcile_used_turfs(), which walks all of used_turfs. - var/next_used_turf_reconcile = 0 var/list/reservation_ready = list() var/clearing_reserved_turfs = FALSE @@ -204,6 +194,7 @@ SUBSYSTEM_DEF(mapping) var/turf/reserving_turf = packet[packetlen] reserving_turf.empty(RESERVED_TURF_TYPE, RESERVED_TURF_TYPE, null, TRUE) LAZYINITLIST(unused_turfs["[reserving_turf.z]"]) + // VOIDCREW EDIT: Use turf-keyed reservation membership so handing back large sites avoids quadratic list scans. unused_turfs["[reserving_turf.z]"][reserving_turf] = TRUE var/area/old_area = reserving_turf.loc // VOIDCREW EDIT ADDITION START - never wedge the reservation queue on a dead area. @@ -226,7 +217,7 @@ SUBSYSTEM_DEF(mapping) reserving_turf.turf_flags = UNUSED_RESERVATION_TURF // reservation turfs are not allowed to interact with atmos at all reserving_turf.blocks_air = TRUE - // VOIDCREW EDIT ADDITION - darken a released reservation turf. + // VOIDCREW EDIT ADDITION START - darken a released reservation turf. // // A reservation is filled with space, content is stamped or carved into it, and the // space turfs bordering that content light themselves through enable_starlight(). @@ -266,48 +257,6 @@ SUBSYSTEM_DEF(mapping) // VOIDCREW EDIT ADDITION: only once the drain is idle, and rate limited inside. reconcile_used_turfs() -/** - * VOIDCREW ADDITION: takes the turfs darkened by the reservation drain out of - * GLOB.starlight, in one linear pass over the list rather than one linear scan per turf. - * - * `GLOB.starlight -= turf` inside the drain loop is the obvious spelling and it is - * quadratic: the loop runs once per released turf and the list can hold as many entries - * again, which on a large release is a multi-second world freeze. Rebuilding the list once - * against an assoc membership set is O(len(GLOB.starlight)) no matter how many turfs were - * released, and the drain only pays it once per REBUILD_STARLIGHT_AFTER turfs plus once at - * the end of each fire. - * - * Leaving the entries in place instead is not an option: enable_starlight() only appends - * when `!light_on`, so a member whose light we switched off would be appended a SECOND - * time the next time that ground is lit, and BYOND's Remove() only ever drops one of them. - * That trades a bounded datum leak for an unbounded list leak. - * - * A turf that was re-lit between being queued and being flushed is kept: the queue is a - * request to drop the entry, `light_on` is the ground truth about whether it still belongs. - */ -/// Turfs the reservation drain may darken before the GLOB.starlight compaction is worth a pass. -#define REBUILD_STARLIGHT_AFTER 1000 - -/datum/controller/subsystem/mapping/proc/release_reservation_starlight(force = FALSE) - var/list/released = starlight_release_queue - if(!length(released)) - return - if(!force && length(released) < REBUILD_STARLIGHT_AFTER) - return - starlight_release_queue = null - - var/list/kept = list() - for(var/turf/open/space/lit as anything in GLOB.starlight) - // `as anything`, so this also drops the nulls a hard delete leaves in place and - // anything a raw turf swap retargeted into something that is no longer space. - if(isnull(lit)) - continue - if(released[lit] && !lit.light_on) - continue - kept += lit - GLOB.starlight = kept - -#undef REBUILD_STARLIGHT_AFTER /datum/controller/subsystem/mapping/proc/calculate_default_z_level_gravities() for(var/z_level in 1 to length(z_list)) @@ -686,8 +635,10 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away // nothing. An away mission is a deliberate admin act, so this asks rather than refuses - // but the cost is permanent, BYOND never frees a z-level. See effective_z_ceiling(). if(!SSmapping.z_headroom(1)) + // VOIDCREW EDIT START: Enforce and log the permanent z-level capacity budget for live mapping (voidcrew/mapping/_mapping.dm). if(tgui_alert(user, "world.maxz is [world.maxz], at the effective ceiling of [SSmapping.effective_z_ceiling()] (configured [CONFIG_GET(number/max_z_levels)], scaled for [length(GLOB.clients)] clients). An away mission mints another z-level and BYOND never frees one - that is roughly 120 MB of address space gone for the rest of the round, on top of a server that is already at its budget. Load anyway?", "Z ceiling", list("Load anyway", "Cancel")) != "Load anyway") return + // VOIDCREW EDIT END var/list/possible_options = GLOB.potentialRandomZlevels + "Custom" var/away_name @@ -725,6 +676,7 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away /// VOIDCREW EDIT: `mint_reason` is passed through to add_new_zlevel() for the per-mint log line. /datum/controller/subsystem/mapping/proc/add_reservation_zlevel(for_shuttles, mint_reason = null) num_of_res_levels++ + // VOIDCREW EDIT: Enforce and log the permanent z-level capacity budget for live mapping (voidcrew/mapping/_mapping.dm). return add_new_zlevel("Transit/Reserved #[num_of_res_levels]", list(ZTRAIT_RESERVED = TRUE), mint_reason = mint_reason) /// Requests a /datum/turf_reservation based on the given width, height, and z_size. You can specify a z_reservation to use a specific z level, or leave it null to use any z level. @@ -814,11 +766,13 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away ) // Assoc keyed by turf, so reservations can hand turfs back with a keyed update // instead of a linear scan (see the unused_turfs declaration) + // VOIDCREW EDIT: Use turf-keyed reservation membership so handing back large sites avoids quadratic list scans. var/list/reservable_turfs = list() for(var/turf/T as anything in reserved_block) // No need to empty() these, because they just got created and are already /turf/open/space/basic. T.turf_flags = UNUSED_RESERVATION_TURF T.blocks_air = TRUE + // VOIDCREW EDIT: Use turf-keyed reservation membership so handing back large sites avoids quadratic list scans. reservable_turfs[T] = TRUE CHECK_TICK @@ -826,6 +780,7 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away if(SSatoms.initialized) SSatoms.InitializeAtoms(Z_TURFS(z)) + // VOIDCREW EDIT: Use turf-keyed reservation membership so handing back large sites avoids quadratic list scans. unused_turfs["[z]"] = reservable_turfs reservation_ready["[z]"] = TRUE clearing_reserved_turfs = FALSE @@ -837,62 +792,6 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away if(await) UNTIL(!length(turfs)) -// VOIDCREW ADDITION: how often the used_turfs orphan sweep below may run. -#define USED_TURF_RECONCILE_INTERVAL (2 MINUTES) -// VOIDCREW ADDITION: how many orphans one sweep may hand back, so a pathological -// backlog is drained over several passes instead of in one unbounded release. -#define USED_TURF_RECONCILE_MAX_RECLAIM 5000 - -/** - * VOIDCREW ADDITION: self-healing sweep for SSmapping.used_turfs. - * - * used_turfs maps turf -> the /datum/turf_reservation that claimed it, and the only thing - * that ever removes an entry is that reservation's Release(). An entry whose reservation - * is gone is therefore ground that is claimed forever: it keeps RESERVATION_TURF, never - * goes back into unused_turfs, and _reserve_area() will never hand it out again. Enough of - * those and request_turf_block_reservation() cannot fit a block on any existing reservation - * z-level and mints a permanent new 255x255 one (~65k turfs, ~48 MB) per shortfall. - * - * Release() is the fix for the known way that happened (see the note there); this is the - * net for any path that is still missed, and it also cleans up entries stranded before this - * code existed. It is deliberately narrow: an entry is only dropped when nothing live owns - * it - a null value (the reservation hard deleted, which nulls the ref in place) or a - * QDELETED one. A reservation that still exists is never touched, so this cannot race a - * live claim, and turfs claimed but not yet published are impossible because _reserve_area() - * writes used_turfs[T] and the datum ref in the same unyielding pass. - * - * O(length(used_turfs)) with no sleeps, capped and rate limited. - */ -/datum/controller/subsystem/mapping/proc/reconcile_used_turfs() - if(!initialized || clearing_reserved_turfs) - return - if(world.time < next_used_turf_reconcile) - return - next_used_turf_reconcile = world.time + USED_TURF_RECONCILE_INTERVAL - - var/list/orphans = list() - // `as anything` - a hard delete can null a key in place, and those are skipped rather - // than reclaimed: there is no turf left to hand back. - for(var/turf/claimed as anything in used_turfs) - if(isnull(claimed)) - continue - var/datum/turf_reservation/holder = used_turfs[claimed] - if(!QDELETED(holder)) - continue - orphans += claimed - if(length(orphans) >= USED_TURF_RECONCILE_MAX_RECLAIM) - break - - if(!length(orphans)) - return - - used_turfs -= orphans - log_mapping("SSmapping: reconciled [length(orphans)] used_turfs entr[length(orphans) == 1 ? "y" : "ies"] whose \ - reservation no longer exists - the ground was claimed with nothing left to release it. Handing it back.") - reserve_turfs(orphans) - -#undef USED_TURF_RECONCILE_INTERVAL -#undef USED_TURF_RECONCILE_MAX_RECLAIM //DO NOT CALL THIS PROC DIRECTLY, CALL wipe_reservations(). /datum/controller/subsystem/mapping/proc/do_wipe_turf_reservations() diff --git a/code/controllers/subsystem/minor_mapping.dm b/code/controllers/subsystem/minor_mapping.dm index 5b63d1876b8..3ca4bbe9597 100644 --- a/code/controllers/subsystem/minor_mapping.dm +++ b/code/controllers/subsystem/minor_mapping.dm @@ -78,7 +78,7 @@ SUBSYSTEM_DEF(minor_mapping) for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) all_turfs += Z_TURFS(z) for(var/turf/open/floor/plating/T in all_turfs) - // VOIDCREW EDIT ADDITION: is_station_level() means "any z with a hull on it", so + // VOIDCREW EDIT ADDITION START: is_station_level() means "any z with a hull on it", so // this sweep reaches every co-tenant of every occupied encounter level - mice would // spawn inside a site whose crew has not arrived, on top of the fauna budget. Also a // CHECK_TICK: the loop accumulates every station level's turfs and walks the lot in diff --git a/code/controllers/subsystem/networks/bitrunning.dm b/code/controllers/subsystem/networks/bitrunning.dm index 67d5a6bfbe2..2d485456a75 100644 --- a/code/controllers/subsystem/networks/bitrunning.dm +++ b/code/controllers/subsystem/networks/bitrunning.dm @@ -5,10 +5,6 @@ SUBSYSTEM_DEF(bitrunning) flags = SS_NO_FIRE var/list/all_domains = list() - /// Domain key -> weakref of the quantum server currently running it. Domain - /// datums are fleet-wide singletons and a fleet can have a server on every - /// ship, so only one holder at a time is allowed per key. - var/list/domains_in_use = list() /datum/controller/subsystem/bitrunning/Initialize() InitializeDomains() @@ -42,80 +38,6 @@ SUBSYSTEM_DEF(bitrunning) return levels -/// The quantum server currently running the given domain key, if any. Clears the -/// entry if its holder has since been destroyed. -/datum/controller/subsystem/bitrunning/proc/get_domain_holder(key) - var/datum/weakref/holder_ref = domains_in_use[key] - if(isnull(holder_ref)) - return null - - var/obj/machinery/quantum_server/holder = holder_ref.resolve() - if(isnull(holder)) - domains_in_use -= key - return null - - return holder - -/// Marks a domain key as running on the given server. FALSE if another server holds it. -/datum/controller/subsystem/bitrunning/proc/claim_domain(key, obj/machinery/quantum_server/server) - if(isnull(key) || isnull(server)) - return FALSE - - var/obj/machinery/quantum_server/holder = get_domain_holder(key) - if(holder && holder != server) - return FALSE - - domains_in_use[key] = WEAKREF(server) - return TRUE - -/** - * TRUE if the given turf sits inside a virtual domain that is currently loaded. - * - * Upstream contains a domain purely through area flags - LOCAL_TELEPORT to stop - * teleports crossing out, allow_shuttle_docking to stop shuttles landing. That only - * holds for tiles the template actually painted an area onto. A reservation's floor - * is whatever the z-level was created as, which is world.area: the global - * /area/space instance, which has no LOCAL_TELEPORT and DOES whitelist docking. Every - * /area/template_noop tile in a domain map, and every tile of the reservation the - * template doesn't cover, is one of those. Build a quantum pad or a shuttle frame on - * one and the area checks wave it straight through, loot and all. - * - * So anything asking "may this cross the VR boundary" has to ask about the - * reservation, not the area. - */ -/datum/controller/subsystem/bitrunning/proc/is_domain_turf(turf/checked) - if(isnull(checked) || !length(domains_in_use)) - return FALSE - - // Domains only ever live in a turf reservation (see /datum/lazy_template/lazy_load). - if(!is_reserved_level(checked.z)) - return FALSE - - // Deliberately not get_domain_holder(): that prunes dead keys as it goes, and - // callers include check_teleport_valid(), which is SHOULD_BE_PURE. - for(var/key in domains_in_use) - var/datum/weakref/holder_ref = domains_in_use[key] - var/obj/machinery/quantum_server/holder = holder_ref?.resolve() - var/datum/lazy_template/virtual_domain/domain = holder?.generated_domain - if(isnull(domain)) - continue - - for(var/datum/turf_reservation/reservation as anything in domain.reservations) - if(reservation.contains_turf(checked)) - return TRUE - - return FALSE - -/// Frees a domain key, provided the given server is the one holding it. -/datum/controller/subsystem/bitrunning/proc/release_domain(key, obj/machinery/quantum_server/server) - if(isnull(key)) - return - - var/obj/machinery/quantum_server/holder = get_domain_holder(key) - if(holder && holder != server) - return - - domains_in_use -= key /datum/controller/subsystem/bitrunning/proc/pick_secondary_loot(completed_domain) var/datum/lazy_template/virtual_domain/domain = completed_domain diff --git a/code/controllers/subsystem/networks/research.dm b/code/controllers/subsystem/networks/research.dm index 0e030dec18a..54cd9b0e2f0 100644 --- a/code/controllers/subsystem/networks/research.dm +++ b/code/controllers/subsystem/networks/research.dm @@ -94,6 +94,7 @@ SUBSYSTEM_DEF(research) // console's enqueue buttons were live but the nodes were silently never researched. // Income generation stays gated exactly as before; the queue now runs for every web. if(techweb_list.should_generate_points) + // VOIDCREW EDIT START: Process ship techweb research queues even when passive point generation is disabled (voidcrew/modules/research). var/list/bitcoins = list() for(var/obj/machinery/rnd/server/miner as anything in techweb_list.techweb_servers) if(miner.working) @@ -108,6 +109,7 @@ SUBSYSTEM_DEF(research) techweb_list.add_point_list(bitcoins) techweb_list.last_income = world.time + // VOIDCREW EDIT END if(length(techweb_list.research_queue_nodes)) techweb_list.research_node_id(techweb_list.research_queue_nodes[1]) // Attempt to research the first node in queue if possible diff --git a/code/controllers/subsystem/pathfinder.dm b/code/controllers/subsystem/pathfinder.dm index d429b702619..0d066707280 100644 --- a/code/controllers/subsystem/pathfinder.dm +++ b/code/controllers/subsystem/pathfinder.dm @@ -29,8 +29,10 @@ SUBSYSTEM_DEF(pathfinder) // round whether or not anything asked it for a path. With both queues empty every line // below this is a no-op, but the two list copies (one of them a deep_copy_list) still // get paid ~78k times a round. Bail before allocating anything. + // VOIDCREW EDIT START: Avoid copying empty pathfinding queues on every fleet tick. if(!length(active_pathing) && !length(source_to_maps)) return + // VOIDCREW EDIT END src.currentrun = active_pathing.Copy() src.currentmaps = deep_copy_list(source_to_maps) diff --git a/code/controllers/subsystem/radiation.dm b/code/controllers/subsystem/radiation.dm index 84bc524970a..46ea1b7c051 100644 --- a/code/controllers/subsystem/radiation.dm +++ b/code/controllers/subsystem/radiation.dm @@ -15,6 +15,7 @@ SUBSYSTEM_DEF(radiation) // A null source_ref must be dropped, not runtimed on: a runtime aborts fire() // before the Cut(), so the same entry would wedge the whole queue forever. var/datum/weakref/source_ref = pulse_information.source_ref + // VOIDCREW EDIT: Tolerate a radiation source deleted before the pulse resolves its weak reference. var/atom/source = source_ref?.resolve() if (isnull(source)) processing.Cut(1, 2) diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 36d6f26a9fe..f6ed1ab3398 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -9,6 +9,7 @@ /// at which point generate_transit_dock() is not even attempted and any ship that needs a /// NEW reservation (one that expanded its hull, or relocated its docking port) can never /// enter transit again - it can neither dock nor undock for the rest of the round. +// VOIDCREW EDIT: Size transit capacity for a fleet while recycling empty docked-ship reservations (voidcrew/modules/shuttle). #define MAX_TRANSIT_TILE_COUNT (400 ** 2) /// How many turfs to allow before we start freeing up existing "soft reserved" transit docks /// If we're under load we want to allow for cycling, but if not we want to preserve already generated docks for use @@ -17,6 +18,7 @@ /// berthed, and blocks that linger fragment the reserved levels until the allocator mints a /// fresh z (~120 MB, never freed). 40k keeps roughly a dozen hulls' blocks warm; past that, /// docked ships hand their ground back and re-request on undock, which is the normal path. +// VOIDCREW EDIT: Size transit capacity for a fleet while recycling empty docked-ship reservations (voidcrew/modules/shuttle). #define SOFT_TRANSIT_RESERVATION_THRESHOLD (200 ** 2) //END VOID EDIT @@ -161,13 +163,6 @@ SUBSYSTEM_DEF(shuttle) /// Did the supermatter start a cascade event? var/supermatter_cascade = FALSE - //VOID EDIT - Modular ship configuration for shuttle manipulator - /// Pending upgrade module selections (slot_key -> module_id) for shuttle manipulator - var/list/pending_upgrade_selections = list() - /// Pending theme selection (theme_id) for shuttle manipulator - var/pending_theme_id - //END VOID EDIT - /// List of express consoles that are waiting for pack initialization var/list/obj/machinery/computer/cargo/express/express_consoles = list() @@ -887,12 +882,14 @@ SUBSYSTEM_DEF(shuttle) * * destination_port - The station docking port to send the shuttle to once loaded * * replace - Whether to replace the shuttle or create a new one */ +// VOIDCREW EDIT START: Serialize preview loads under their owning template transaction (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). /datum/controller/subsystem/shuttle/proc/action_load(datum/map_template/shuttle/loading_template, obj/docking_port/stationary/destination_port, replace = FALSE, datum/shuttle_template_load/load_owner) return run_template_load(CALLBACK(src, PROC_REF(action_load_impl), loading_template, destination_port, replace), load_owner) /datum/controller/subsystem/shuttle/proc/action_load_impl(datum/map_template/shuttle/loading_template, obj/docking_port/stationary/destination_port, replace, datum/shuttle_template_load/load_owner) if(destination_port && QDELETED(destination_port)) return FALSE +// VOIDCREW EDIT END // Check for an existing preview if(preview_shuttle && (loading_template != preview_template)) preview_shuttle.jumpToNullSpace() @@ -901,12 +898,14 @@ SUBSYSTEM_DEF(shuttle) QDEL_NULL(preview_reservation) if(!preview_shuttle) + // VOIDCREW EDIT START: Serialize preview loads under their owning template transaction (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). load_template(loading_template, load_owner) // VOIDCREW EDIT: load_template() can now refuse gracefully (no transit // reservation free - see the capacity note in it). Without this bail the null // preview fell through to generate_transit_dock(null) and a CRASH of its own. if(!preview_shuttle) return + // VOIDCREW EDIT END preview_template = loading_template // get the existing shuttle information, if any @@ -968,11 +967,13 @@ SUBSYSTEM_DEF(shuttle) * Arguments: * * loading_template - The shuttle template to load */ +// VOIDCREW EDIT START: Serialize preview loads under their owning template transaction (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). /datum/controller/subsystem/shuttle/proc/load_template(datum/map_template/shuttle/loading_template, datum/shuttle_template_load/load_owner) return run_template_load(CALLBACK(src, PROC_REF(load_template_impl), loading_template), load_owner) /datum/controller/subsystem/shuttle/proc/load_template_impl(datum/map_template/shuttle/loading_template, datum/shuttle_template_load/load_owner) unload_preview(load_owner) +// VOIDCREW EDIT END . = FALSE // Load shuttle template to a fresh block reservation. preview_reservation = SSmapping.request_turf_block_reservation( @@ -990,6 +991,7 @@ SUBSYSTEM_DEF(shuttle) // "there was an error, contact admins" for every buyer who clicked at the wrong // moment. Refuse gracefully instead; callers already handle a missing preview. log_mapping("SSshuttle: load_template refused - no transit reservation for [loading_template.width]x[loading_template.height] '[loading_template.name]'[SSmapping.at_z_level_ceiling() ? " (world.maxz at its ceiling)" : ""]") + // VOIDCREW EDIT: Serialize preview loads under their owning template transaction (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). return FALSE var/turf/bottom_left = preview_reservation.bottom_left_turfs[1] loading_template.load(bottom_left, centered = FALSE, register = FALSE) @@ -1029,13 +1031,16 @@ SUBSYSTEM_DEF(shuttle) /** * Removes the preview_shuttle from the transit Z-level */ +// VOIDCREW EDIT START: Serialize preview loads under their owning template transaction (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). /datum/controller/subsystem/shuttle/proc/unload_preview(datum/shuttle_template_load/load_owner) return run_template_load(CALLBACK(src, PROC_REF(unload_preview_impl)), load_owner) /datum/controller/subsystem/shuttle/proc/unload_preview_impl(datum/shuttle_template_load/load_owner) +// VOIDCREW EDIT END if(preview_shuttle) preview_shuttle.jumpToNullSpace() preview_shuttle = null + // VOIDCREW EDIT: Serialize preview loads under their owning template transaction (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). preview_template = null if(preview_reservation) QDEL_NULL(preview_reservation) @@ -1075,11 +1080,13 @@ SUBSYSTEM_DEF(shuttle) L["description"] = S.description L["admin_notes"] = S.admin_notes //VOID EDIT - Check if this is a modular voidcrew ship + // VOIDCREW EDIT START: Integrate serialized live template loads and modular ship selections (voidcrew/modules/ship_upgrades/shuttle_manipulator.dm). L["is_modular"] = FALSE if(istype(S, /datum/map_template/shuttle/voidcrew)) var/datum/map_template/shuttle/voidcrew/VC = S if(VC.has_upgrade_slots) L["is_modular"] = TRUE + // VOIDCREW EDIT END //END VOID EDIT if(selected == S) @@ -1118,11 +1125,13 @@ SUBSYSTEM_DEF(shuttle) data["shuttles"] += list(L) //VOID EDIT - Add modular ship data if selected template is modular + // VOIDCREW EDIT START: Integrate serialized live template loads and modular ship selections (voidcrew/modules/ship_upgrades/shuttle_manipulator.dm). data["modular_data"] = null if(selected && istype(selected, /datum/map_template/shuttle/voidcrew)) var/datum/map_template/shuttle/voidcrew/VC = selected if(VC.has_upgrade_slots) data["modular_data"] = build_modular_ui_data(VC) + // VOIDCREW EDIT END //END VOID EDIT return data @@ -1144,12 +1153,15 @@ SUBSYSTEM_DEF(shuttle) existing_shuttle = getShuttle(S.port_id) selected = S //VOID EDIT - Clear pending modular selections when switching templates + // VOIDCREW EDIT START: Integrate serialized live template loads and modular ship selections (voidcrew/modules/ship_upgrades/shuttle_manipulator.dm). pending_upgrade_selections = list() pending_theme_id = null + // VOIDCREW EDIT END //END VOID EDIT . = TRUE //VOID EDIT - Handlers for modular ship configuration + // VOIDCREW EDIT START: Integrate serialized live template loads and modular ship selections (voidcrew/modules/ship_upgrades/shuttle_manipulator.dm). if("select_ship_theme") pending_theme_id = params["theme_id"] // Clear upgrade selections when theme changes (modules may differ per theme) @@ -1167,6 +1179,7 @@ SUBSYSTEM_DEF(shuttle) pending_upgrade_selections = list() pending_theme_id = null . = TRUE + // VOIDCREW EDIT END //END VOID EDIT if("jump_to") @@ -1197,6 +1210,7 @@ SUBSYSTEM_DEF(shuttle) SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[M.name]") break + // VOIDCREW EDIT START: The serialized template-load owner now holds the load lock (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). if("load") //VOID EDIT [ if(istype(S, /datum/map_template/shuttle/voidcrew)) var/datum/map_template/shuttle/voidcrew/VC = S @@ -1246,17 +1260,20 @@ SUBSYSTEM_DEF(shuttle) message_admins("[key_name_admin(usr)] loaded [mdp] with the shuttle manipulator.") log_admin("[key_name(usr)] loaded [mdp] with the shuttle manipulator.
") SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[mdp.name]") + // VOIDCREW EDIT END //] if("preview") //if(preview_shuttle && (loading_template != preview_template)) if(S && !shuttle_loading) . = TRUE + // VOIDCREW EDIT REMOVAL: The serialized template-load owner now holds the load lock (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). unload_preview() load_template(S) if(preview_shuttle) preview_template = S user.forceMove(get_turf(preview_shuttle)) +// VOIDCREW EDIT REMOVAL: The serialized template-load owner now holds the load lock (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). if("replace") if(existing_shuttle == backup_shuttle) @@ -1266,6 +1283,7 @@ SUBSYSTEM_DEF(shuttle) intact for round sanity.") else if(S && !shuttle_loading) . = TRUE + // VOIDCREW EDIT REMOVAL: The serialized template-load owner now holds the load lock (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). // If successful, returns the mobile docking port var/obj/docking_port/mobile/mdp = action_load(S, replace = TRUE) if(mdp) @@ -1273,6 +1291,7 @@ SUBSYSTEM_DEF(shuttle) message_admins("[key_name_admin(usr)] load/replaced [mdp] with the shuttle manipulator.") log_admin("[key_name(usr)] load/replaced [mdp] with the shuttle manipulator.
") SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[mdp.name]") + // VOIDCREW EDIT REMOVAL: The serialized template-load owner now holds the load lock (voidcrew/modules/overmap/code/controllers/subsystem/shuttle.dm). if(emergency == mdp) //you just changed the emergency shuttle, there are events in game + captains that can change your snowflake choice. var/set_purchase = tgui_alert(usr, "Do you want to also disable shuttle purchases/random events that would change the shuttle?", "Butthurt Admin Prevention", list("Yes, disable purchases/events", "No, I want to possibly get owned")) if(set_purchase == "Yes, disable purchases/events") @@ -1289,99 +1308,6 @@ SUBSYSTEM_DEF(shuttle) return has_purchase_shuttle_access //VOID EDIT - Helper proc for building modular ship UI data -/** - * Build UI data for modular ship configuration in shuttle manipulator - * - * Returns a list with: - * - themes: list of available themes with id, name, desc, is_default, jobs - * - has_themes: boolean if there are themes to choose from - * - slots: list of upgrade slots with their available modules - * - selected_theme: currently selected theme id (from pending_theme_id) - * - selected_upgrades: currently selected modules (from pending_upgrade_selections) - */ -/datum/controller/subsystem/shuttle/proc/build_modular_ui_data(datum/map_template/shuttle/voidcrew/template) - ensure_ship_upgrades_initialized() - - var/list/data = list() - - // Get themes for this ship - var/list/ship_themes = get_themes_for_ship(template.type) - var/list/themes_data = list() - - for(var/theme_id in ship_themes) - var/datum/ship_theme/theme = ship_themes[theme_id] - var/list/theme_info = list() - theme_info["id"] = theme.id - theme_info["name"] = theme.name - theme_info["desc"] = theme.desc - theme_info["is_default"] = theme.is_default - - // Include job slots for preview - if(theme.job_slots) - var/list/jobs = list() - for(var/list/job_data in theme.job_slots) - jobs += list(list( - "name" = job_data["name"], - "slots" = job_data["slots"], - "officer" = job_data["officer"] - )) - theme_info["jobs"] = jobs - - themes_data += list(theme_info) - - data["themes"] = themes_data - data["has_themes"] = length(themes_data) > 0 - - // Determine selected theme - use pending selection or find default - var/effective_theme_id = pending_theme_id - if(!effective_theme_id && length(themes_data)) - var/datum/ship_theme/default_theme = get_default_theme_for_ship(template.type) - if(default_theme) - effective_theme_id = default_theme.id - - data["selected_theme"] = effective_theme_id - - // Get upgrade slots - from theme if selected, otherwise from template - var/list/upgrade_slot_ids = template.upgrade_slot_ids - if(effective_theme_id) - var/datum/ship_theme/selected_theme = ship_themes[effective_theme_id] - if(selected_theme?.upgrade_slot_ids) - upgrade_slot_ids = selected_theme.upgrade_slot_ids - - // Get modules filtered by theme - var/list/all_modules = get_modules_for_ship_theme(template.type, effective_theme_id) - - // Organize modules by slot - var/list/slots_data = list() - for(var/slot_key in upgrade_slot_ids) - var/list/slot_info = list() - slot_info["key"] = slot_key - // Generate display name from slot key (capitalize, replace underscores) - slot_info["display_name"] = capitalize(replacetext(slot_key, "_", " ")) - - var/list/slot_modules = list() - for(var/module_id in all_modules) - var/datum/ship_upgrade_module/module = all_modules[module_id] - if(module.slot != slot_key) - continue - - var/list/module_info = list() - module_info["id"] = module.id - module_info["name"] = module.name - module_info["desc"] = module.desc - module_info["is_default"] = module.is_default - - slot_modules += list(module_info) - - slot_info["modules"] = slot_modules - slots_data += list(slot_info) - - data["slots"] = slots_data - - // Include current pending selections - data["selected_upgrades"] = pending_upgrade_selections.Copy() - - return data //END VOID EDIT #undef MAX_TRANSIT_REQUEST_RETRIES diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index dab04a667c1..fbbc9267134 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -41,6 +41,7 @@ SUBSYSTEM_DEF(statpanels) "Round Time: [ROUND_TIME()]", "Station Time: [station_time_timestamp()]", "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)", + // VOIDCREW EDIT: Show connected fleet population in the stat panel. "Connected Players: [length(GLOB.clients)]", ) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index f5a6c704c72..27a5cf0fc56 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -161,10 +161,12 @@ SUBSYSTEM_DEF(ticker) for(var/client/C in GLOB.clients) window_flash(C, ignorepref = TRUE) //let them know lobby has opened up. to_chat(world, span_notice("Welcome to [station_name()]!")) + // VOIDCREW EDIT START: Include the configured Discord round-alert role (voidcrew/controllers/configuration/new_round_alert.dm). var/new_round_alert_role = CONFIG_GET(string/new_round_alert_role_id) var/new_round_message = "[new_round_alert_role ? "<@&[new_round_alert_role]> " : ""]New round starting on [SSmapping.current_map.map_name]!" for(var/channel_tag in CONFIG_GET(str_list/channel_announce_new_game)) send2chat(new /datum/tgs_message_content(new_round_message), channel_tag) + // VOIDCREW EDIT END current_state = GAME_STATE_PREGAME SEND_SIGNAL(src, COMSIG_TICKER_ENTER_PREGAME) @@ -585,9 +587,11 @@ SUBSYSTEM_DEF(ticker) /datum/controller/subsystem/ticker/proc/transfer_characters() var/list/livings = list() for(var/mob/dead/new_player/player as anything in GLOB.new_player_list) + // VOIDCREW EDIT START: Notify Voidcrew crew integrations after a player character transfers into its living body. var/mob/living/living = player.transfer_character() if(living) SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CREWMEMBER_JOINED, living, living.mind.assigned_role.title) + // VOIDCREW EDIT END qdel(player) ADD_TRAIT(living, TRAIT_NO_TRANSFORM, SS_TICKER_TRAIT) if(living.client) diff --git a/code/controllers/subsystem/tts.dm b/code/controllers/subsystem/tts.dm index e78c08f24e3..d7bcff51b8c 100644 --- a/code/controllers/subsystem/tts.dm +++ b/code/controllers/subsystem/tts.dm @@ -83,6 +83,7 @@ SUBSYSTEM_DEF(tts) var/datum/http_response/response_pitch = request_pitch.into_response() if(response_pitch.errored || response_pitch.status_code != 200) if(response_pitch.errored) + // VOIDCREW EDIT: Report the pitch request failure from its own response, rather than the completed TTS response. stack_trace(response_pitch.error) pitch_enabled = FALSE rustg_file_write(json_encode(available_speakers), "data/cached_tts_voices.json") diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm index 007310441a4..de76a9caef7 100644 --- a/code/controllers/subsystem/weather.dm +++ b/code/controllers/subsystem/weather.dm @@ -8,28 +8,11 @@ SUBSYSTEM_DEF(weather) wait = 10 runlevels = RUNLEVEL_GAME var/list/processing = list() - /// Snapshot of active weather being processed in the current fire. The event at - /// the end remains there until all of its tasks finish, including across resumes. - var/list/currentrun = list() - // VOIDCREW EDIT REMOVAL START - the four "[z]"-keyed scheduler maps (eligible_zlevels, - // weather_types_by_zlevel, next_hit_by_zlevel, random_weather_by_zlevel) are replaced by - // the /datum/weather_site registry below, so several places can share a z-level and each - // keep its own climate, storm and cooldown. See voidcrew/datums/weather_site.dm. - /// Every registered weather site, in registration order. - var/list/datum/weather_site/weather_sites = list() - /// "[z]" -> list of /datum/weather_site on that level, for turf and level lookups. - var/list/weather_sites_by_zlevel = list() - /// Sites allowed to roll a new random storm on the next fire. - var/list/datum/weather_site/eligible_sites = list() - // VOIDCREW EDIT REMOVAL END - /// z ("[z]") -> list of living mobs, rebuilt at most once per fire cycle so several - /// concurrent storms share one scan of the global mob list instead of one scan each - var/list/mobs_by_z_cache - /// The times_fired value mobs_by_z_cache was built on - var/mobs_by_z_cache_fire = -1 + // VOIDCREW EDIT REMOVAL: Per-z scheduler maps are replaced by the site registry in voidcrew/edits/subsystem/weather_sites.dm. /datum/controller/subsystem/weather/fire(resumed = FALSE) // process active weather + // VOIDCREW EDIT START: Schedule storms per site and resume bounded weather work across ticks (voidcrew/edits/subsystem/weather_sites.dm). if(!resumed) currentrun = processing.Copy() var/list/currentrun_cache = currentrun @@ -38,12 +21,14 @@ SUBSYSTEM_DEF(weather) if(QDELETED(weather_event) || !(weather_event in processing) || !length(weather_event.subsystem_tasks) || weather_event.stage != MAIN_STAGE) currentrun_cache.len-- resumed = FALSE + // VOIDCREW EDIT END continue if(weather_event.subsystem_tasks[weather_event.task_index] == SSWEATHER_MOBS) if(!resumed) // Only collect mobs on the impacted z-levels, the whole world's mob list gets very large with populated planets. // The z index is built once per fire cycle and shared by every storm processing this fire. + // VOIDCREW EDIT START: Schedule storms per site and resume bounded weather work across ticks (voidcrew/edits/subsystem/weather_sites.dm). if(mobs_by_z_cache_fire != times_fired) mobs_by_z_cache = list() mobs_by_z_cache_fire = times_fired @@ -70,6 +55,7 @@ SUBSYSTEM_DEF(weather) if(z_mobs) eligible_mobs += z_mobs weather_event.current_mobs = eligible_mobs + // VOIDCREW EDIT END var/list/current_mobs_cache = weather_event.current_mobs // cache for performance while(current_mobs_cache.len) var/mob/living/target = current_mobs_cache[current_mobs_cache.len] @@ -111,8 +97,10 @@ SUBSYSTEM_DEF(weather) // Do not remove an event before all of its tasks complete. If MC_TICK_CHECK // returns above, this remains the last entry and the next fire resumes it. + // VOIDCREW EDIT START: Schedule storms per site and resume bounded weather work across ticks (voidcrew/edits/subsystem/weather_sites.dm). currentrun_cache.len-- resumed = FALSE + // VOIDCREW EDIT END // VOIDCREW EDIT REPLACEMENT START - random weather is scheduled per site, not per z-level. // One storm per SITE replaces the old one-storm-per-z rule, so two sites sharing a @@ -166,169 +154,6 @@ SUBSYSTEM_DEF(weather) // VOIDCREW EDIT REPLACEMENT END return SS_INIT_SUCCESS -// VOIDCREW EDIT ADDITION START - weather site registry. -/** - * Builds the random-weather weight table (weather typepath -> probability) implied by a set - * of z-level traits. - * - * This is the calculation Initialize() and update_z_level() used to each write out inline. - * Registration paths that do not want to route a climate through the level's trait dict at - * all (planets, which need to describe their own weather without fighting a co-tenant over - * the level) call this with a trait list they assembled themselves. - * - * `level_traits` is an assoc list, trait -> value, i.e. the same shape as /datum/space_level.traits. - */ -/datum/controller/subsystem/weather/proc/weather_weights_for_traits(list/level_traits) - var/list/possible_weather = list() - if(!length(level_traits)) - return possible_weather - for(var/datum/weather/weather as anything in subtypesof(/datum/weather)) - var/probability = initial(weather.probability) - if(!probability) - continue - var/target_trait = initial(weather.target_trait) - if(target_trait && level_traits[target_trait]) - possible_weather[weather] = probability - return possible_weather - -/// Every z-level trait that some weather type can be rolled from. -/datum/controller/subsystem/weather/proc/random_weather_traits() - var/list/traits = list() - for(var/datum/weather/weather as anything in subtypesof(/datum/weather)) - if(!initial(weather.probability)) - continue - var/target_trait = initial(weather.target_trait) - if(target_trait) - traits |= list(target_trait) - return traits - -/// Adds a site to the scheduler. A site with weather in its table is eligible immediately. -/datum/controller/subsystem/weather/proc/register_weather_site(datum/weather_site/site) - if(!istype(site) || (site in weather_sites)) - return site - weather_sites += site - var/z_key = "[site.z_value]" - var/list/z_sites = weather_sites_by_zlevel[z_key] - if(!z_sites) - z_sites = list() - weather_sites_by_zlevel[z_key] = z_sites - z_sites |= site - if(length(site.weather_types)) - eligible_sites |= site - return site - -/** - * Removes one site from the scheduler, ending its storm and cancelling its cooldown. - * - * This is the per-site form of the old unregister_z_level(); nothing else on the site's - * z-level is disturbed. - */ -/datum/controller/subsystem/weather/proc/unregister_weather_site(datum/weather_site/site) - if(!istype(site)) - return - weather_sites -= site - eligible_sites -= site - var/z_key = "[site.z_value]" - var/list/z_sites = weather_sites_by_zlevel[z_key] - if(z_sites) - z_sites -= site - if(!length(z_sites)) - weather_sites_by_zlevel -= z_key - site.clear_next_hit() - site.end_active_weather() - -/// The site covering a whole z-level, i.e. the one the z-keyed entry points address. Null if none. -/datum/controller/subsystem/weather/proc/get_level_weather_site(z) - for(var/datum/weather_site/site as anything in weather_sites_by_zlevel["[z]"]) - if(!site.has_footprint()) - return site - return null - -/// Every site registered on a z-level, footprinted or not. -/datum/controller/subsystem/weather/proc/get_weather_sites_on_z(z) - return weather_sites_by_zlevel["[z]"] || list() - -/** - * The site that owns a set of coordinates. - * - * A footprinted site wins over the level-wide one, so a packed planet's own climate beats - * whatever covers the rest of the level. - */ -/datum/controller/subsystem/weather/proc/get_weather_site_for_coords(x, y, z) - var/list/z_sites = weather_sites_by_zlevel["[z]"] - if(!length(z_sites)) - return null - var/datum/weather_site/level_fallback - for(var/datum/weather_site/site as anything in z_sites) - if(!site.has_footprint()) - if(isnull(level_fallback)) - level_fallback = site - continue - if(site.contains_coords(x, y, z)) - return site - return level_fallback - -/// The site that owns a turf, or null. -/datum/controller/subsystem/weather/proc/get_weather_site_for_turf(turf/checked) - if(isnull(checked)) - return null - return get_weather_site_for_coords(checked.x, checked.y, checked.z) - -/// Time until the next scheduled storm where this turf is standing, or null if nothing is armed. -/datum/controller/subsystem/weather/proc/next_hit_timeleft_for_turf(turf/checked) - var/datum/weather_site/site = get_weather_site_for_turf(checked) - if(!site?.next_hit_timer) - return null - return timeleft(site.next_hit_timer) - -/// Time until the soonest scheduled storm anywhere on a z-level, or null if nothing is armed. -/datum/controller/subsystem/weather/proc/next_hit_timeleft_for_z(z) - var/shortest = null - for(var/datum/weather_site/site as anything in weather_sites_by_zlevel["[z]"]) - if(!site.next_hit_timer) - continue - var/remaining = timeleft(site.next_hit_timer) - if(isnull(remaining)) - continue - if(isnull(shortest) || remaining < shortest) - shortest = remaining - return shortest - -/** - * Registers (or refreshes) the site covering a whole z-level. - * - * Refreshing keeps a running storm and its cooldown intact and only swaps the weight - * table, which is what update_z_level() has always done. - */ -/datum/controller/subsystem/weather/proc/register_level_weather_site(z, list/possible_weather, zone_band, site_id) - var/datum/weather_site/site = get_level_weather_site(z) - if(site) - site.set_weather_types(possible_weather) - // Only an explicit value overwrites; a bare refresh must not throw away the zone band - // the site was registered with. - if(!isnull(zone_band)) - site.zone_band = zone_band - if(!(site in eligible_sites) && !site.next_hit_timer && !site.has_active_weather() && length(possible_weather)) - eligible_sites |= site - return site - site = new /datum/weather_site(site_id || "level-[z]", z, possible_weather, zone_band) - return register_weather_site(site) - -/** - * Registers a whole-level site whose climate comes from an explicit trait set rather than - * from the level's trait dict. - * - * Planets use this: their weather has to be describable without the level's trait dict - * being the single source of truth, since a level may eventually hold more than one of them. - */ -/datum/controller/subsystem/weather/proc/register_weather_site_for_level(datum/space_level/level, list/weather_traits, zone_band, site_id) - if(isnull(level)) - return null - var/list/possible_weather = weather_weights_for_traits(weather_traits) - if(!length(possible_weather)) - return null - return register_level_weather_site(level.z_value, possible_weather, zone_band, site_id) -// VOIDCREW EDIT ADDITION END /datum/controller/subsystem/weather/proc/update_z_level(datum/space_level/level) // VOIDCREW EDIT REPLACEMENT START - drives the level-wide site instead of the "[z]" maps. @@ -344,44 +169,6 @@ SUBSYSTEM_DEF(weather) register_level_weather_site(z, possible_weather) // VOIDCREW EDIT REPLACEMENT END -/// Stops random weather scheduling for a z-level and ends every storm scheduled on it. -/datum/controller/subsystem/weather/proc/unregister_z_level(z) - // VOIDCREW EDIT REPLACEMENT START - the level is being torn down or recycled, so every - // site on it goes, not just the level-wide one. Copy(): unregister mutates the index list. - var/list/z_sites = weather_sites_by_zlevel["[z]"] - if(!length(z_sites)) - return - for(var/datum/weather_site/site as anything in z_sites.Copy()) - unregister_weather_site(site) - // VOIDCREW EDIT REPLACEMENT END - -/** - * Replaces the random-weather trait on a recycled dynamic z-level. - * - * VOIDCREW EDIT: kept as a thin wrapper over the site registry for callers that still think - * in "one climate per level" terms (map zone teardown, flat overmap encounters, mapping - * helpers). Anything that wants more than one climate on a level registers sites directly. - */ -/datum/controller/subsystem/weather/proc/set_z_level_weather_trait(datum/space_level/level, new_weather_trait) - var/z = level.z_value - unregister_z_level(z) - - for(var/weather_trait in random_weather_traits()) - level.traits -= weather_trait - var/list/trait_levels = SSmapping.z_trait_levels[weather_trait] - if(trait_levels) - trait_levels -= z - - if(!new_weather_trait) - return - - level.traits[new_weather_trait] = TRUE - var/list/new_trait_levels = SSmapping.z_trait_levels[new_weather_trait] - if(!new_trait_levels) - new_trait_levels = list() - SSmapping.z_trait_levels[new_weather_trait] = new_trait_levels - new_trait_levels |= list(z) - update_z_level(level) /datum/controller/subsystem/weather/proc/run_weather(datum/weather/weather_datum_type, z_levels, list/weather_data, datum/weather_site/site) // VOIDCREW EDIT - trailing `site` arg lets a site hand its own area instances to the storm if (istext(weather_datum_type)) @@ -403,41 +190,16 @@ SUBSYSTEM_DEF(weather) var/datum/weather/W = new weather_datum_type(z_levels, weather_data, site) // VOIDCREW EDIT - pass the scheduling site through W.telegraph() + // VOIDCREW EDIT: Schedule storms per site and resume bounded weather work across ticks (voidcrew/edits/subsystem/weather_sites.dm). return W -// VOIDCREW EDIT ADDITION START - the cooldown callback is per site now. -/// Cooldown expiry: the site may roll another storm on the next fire. -/datum/controller/subsystem/weather/proc/make_site_eligible(datum/weather_site/site) - if(QDELETED(site) || !(site in weather_sites)) - return - site.next_hit_timer = null - site.next_hit_time = 0 - // Only let go of a storm that has actually finished. Blanking this while the storm was - // still running orphaned it - it kept processing and kept holding every area instance in - // its impacted_areas with nothing left pointing at it - and let the site roll a second, - // concurrent storm on top of it. A storm that ends normally clears this itself in end(), - // so by the time the cooldown lands it is usually already null; fire() re-queues a site - // whose storm is still winding down rather than starting another. - if(!site.has_active_weather()) - if(site.active_weather?.weather_site == site) - site.active_weather.weather_site = null - site.active_weather = null - if(length(site.weather_types)) - eligible_sites |= site -// VOIDCREW EDIT ADDITION END +// VOIDCREW EDIT REMOVAL: Schedule storms per site and resume bounded weather work across ticks (voidcrew/edits/subsystem/weather_sites.dm). /// VOIDCREW EDIT: kept for z-level-minded callers; addresses the level's own site. /datum/controller/subsystem/weather/proc/make_eligible(z) + // VOIDCREW EDIT: Schedule storms per site and resume bounded weather work across ticks (voidcrew/edits/subsystem/weather_sites.dm). make_site_eligible(get_level_weather_site(z)) -/// Returns TRUE while any weather stage still occupies a z-level. -/// VOIDCREW EDIT: no longer gates random scheduling - fire() asks the site whether ITS storm -/// is still running, so two sites on one level can storm at once. Kept for outside callers. -/datum/controller/subsystem/weather/proc/is_weather_active_on_z(z) - for(var/datum/weather/weather_event as anything in processing) - if(weather_event.stage != END_STAGE && islist(weather_event.impacted_z_levels) && (z in weather_event.impacted_z_levels)) - return TRUE - return FALSE // VOIDCREW EDIT REMOVAL: get_weather(z, active_area) deleted. It matched a storm by // z-level plus area TYPE, which on a packed level answers with a co-tenant's storm - every diff --git a/code/datums/actions/mobs/charge.dm b/code/datums/actions/mobs/charge.dm index 5d2d0f7975a..e9e5210ac2c 100644 --- a/code/datums/actions/mobs/charge.dm +++ b/code/datums/actions/mobs/charge.dm @@ -29,30 +29,6 @@ var/list/charge_disabled_actions = list() // VOIDCREW EDIT END -// VOIDCREW EDIT BEGIN - removal can happen before a moving body's packet is deleted. -/datum/action/cooldown/mob_cooldown/charge/Destroy() - stop_charges() - restore_charge_actions() - return ..() - -/datum/action/cooldown/mob_cooldown/charge/Remove(mob/removed_from) - stop_charges() - restore_charge_actions() - return ..() - -/datum/action/cooldown/mob_cooldown/charge/proc/stop_charges() - for(var/atom/movable/charger as anything in charging.Copy()) - finish_charge(charger, notify_owner = FALSE) - -/datum/action/cooldown/mob_cooldown/charge/proc/restore_charge_actions() - charge_activator = null - for(var/datum/action/cooldown/ability as anything in charge_disabled_actions) - if(!QDELETED(ability)) - ability.enable() - charge_disabled_actions.Cut() - // A cancelled wind-up must not leave the inherited melee lock on its new owner. - next_melee_use_time = min(next_melee_use_time, world.time) -// VOIDCREW EDIT END /datum/action/cooldown/mob_cooldown/charge/Activate(atom/target_atom) // VOIDCREW EDIT BEGIN - remember exactly which actions this invocation disabled. @@ -74,12 +50,14 @@ restore_charge_actions() // VOIDCREW EDIT END StartCooldown() + // VOIDCREW EDIT REMOVAL: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). return TRUE /datum/action/cooldown/mob_cooldown/charge/proc/charge_sequence(atom/movable/charger, atom/target_atom, delay, past) do_charge(charger, target_atom, delay, past) // VOIDCREW EDIT - retain the caller's charge snapshot. /datum/action/cooldown/mob_cooldown/charge/proc/do_charge(atom/movable/charger, atom/target_atom, delay, past) + // VOIDCREW EDIT: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). if(QDELETED(src) || QDELETED(owner) || QDELETED(charger) || QDELETED(target_atom) || target_atom == charger) return var/chargeturf = get_turf(target_atom) @@ -95,6 +73,7 @@ finish_charge(charger, notify_owner = FALSE) // VOIDCREW EDIT - only cancel our own loop. var/charge_id = ++charge_serial // VOIDCREW EDIT - invalidate sleeping replaced invocations. + // VOIDCREW EDIT: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). charging[charger] = charge_id actively_moving = FALSE // VOIDCREW EDIT BEGIN - a start listener may synchronously remove or transfer us. @@ -112,6 +91,7 @@ RegisterSignal(charger, COMSIG_LIVING_DEATH, PROC_REF(charge_end), override = TRUE) // VOIDCREW EDIT - the owner's existing clear_ref handler invokes Remove; preserve it. if(charger != owner) + // VOIDCREW EDIT: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). RegisterSignal(charger, COMSIG_QDELETING, PROC_REF(charge_end), override = TRUE) charger.setDir(dir) do_charge_indicator(charger, target) @@ -168,26 +148,9 @@ if(istype(source, /datum/move_loop)) var/datum/move_loop/move_loop_source = source charger = move_loop_source.moving + // VOIDCREW EDIT: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). finish_charge(charger) -// VOIDCREW EDIT BEGIN - cleanup is idempotent, including loop deletion during body removal. -/datum/action/cooldown/mob_cooldown/charge/proc/finish_charge(atom/movable/charger, notify_owner = TRUE) - if(!charger || !(charger in charging)) - return - charging -= charger - UnregisterSignal(charger, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DEATH)) - if(charger != owner) - UnregisterSignal(charger, COMSIG_QDELETING) - var/datum/move_loop/charge_loop = charge_loops[charger] - charge_loops -= charger - if(charge_loop) - UnregisterSignal(charge_loop, list(COMSIG_MOVELOOP_PREPROCESS_CHECK, COMSIG_MOVELOOP_POSTPROCESS, COMSIG_QDELETING)) - if(!QDELETED(charge_loop)) - qdel(charge_loop) - actively_moving = FALSE - if(notify_owner && !QDELETED(owner)) - SEND_SIGNAL(owner, COMSIG_FINISHED_CHARGE) -// VOIDCREW EDIT END /datum/action/cooldown/mob_cooldown/charge/update_status_on_signal(mob/source, new_stat, old_stat) . = ..() @@ -345,8 +308,10 @@ /datum/action/cooldown/mob_cooldown/charge/triple_charge/charge_sequence(atom/movable/charger, atom/target_atom, delay, past) for(var/i in 0 to 2) if(QDELETED(src) || owner != charger) // VOIDCREW EDIT - cancellation ends the whole sequence. + // VOIDCREW EDIT START: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). return do_charge(charger, target_atom, charge_delay - 2 * i, charge_past) + // VOIDCREW EDIT END /datum/action/cooldown/mob_cooldown/charge/hallucination_charge name = "Hallucination Charge" @@ -368,50 +333,62 @@ return for(var/i in 0 to 2) if(QDELETED(src) || owner != charger) // VOIDCREW EDIT + // VOIDCREW EDIT: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). return hallucination_charge(target_atom, 4, 9 - 2 * i, 0, 4, TRUE) for(var/i in 0 to 2) if(QDELETED(src) || owner != charger) // VOIDCREW EDIT + // VOIDCREW EDIT START: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). return do_charge(charger, target_atom, charge_delay - 2 * i, charge_past) + // VOIDCREW EDIT END /datum/action/cooldown/mob_cooldown/charge/hallucination_charge/do_charge(atom/movable/charger, atom/target_atom, delay, past) var/disposable_clone = charger != owner // VOIDCREW EDIT - owner may change while the parent sleeps. . = ..() + // VOIDCREW EDIT: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). if(disposable_clone) qdel(charger) /datum/action/cooldown/mob_cooldown/charge/hallucination_charge/proc/hallucination_charge(atom/target_atom, clone_amount, delay, past, radius, use_self) var/mob/caster = owner // VOIDCREW EDIT - a synchronous movement/start callback can change owner. var/starting_angle = rand(1, 360) + // VOIDCREW EDIT: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). if(!radius || QDELETED(caster) || QDELETED(target_atom)) return var/angle_difference = 360 / clone_amount var/self_placed = FALSE for(var/i = 1 to clone_amount) if(QDELETED(src) || QDELETED(caster) || owner != caster || QDELETED(target_atom)) // VOIDCREW EDIT + // VOIDCREW EDIT: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). return var/angle = (starting_angle + angle_difference * i) var/turf/place = locate(target_atom.x + cos(angle) * radius, target_atom.y + sin(angle) * radius, target_atom.z) if(!place) continue if(use_self && !self_placed) + // VOIDCREW EDIT START: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). caster.forceMove(place) if(QDELETED(src) || QDELETED(caster) || owner != caster) // VOIDCREW EDIT return + // VOIDCREW EDIT END self_placed = TRUE continue var/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/our_clone = new /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination(place) + // VOIDCREW EDIT START: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). our_clone.appearance = caster.appearance our_clone.name = "[caster]'s hallucination" our_clone.alpha = 127.5 our_clone.move_through_mob = caster + // VOIDCREW EDIT END our_clone.spawn_blood = spawn_blood INVOKE_ASYNC(src, PROC_REF(do_charge), our_clone, target_atom, delay, past) if(QDELETED(src) || QDELETED(caster) || owner != caster) // VOIDCREW EDIT + // VOIDCREW EDIT START: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). return if(use_self) do_charge(caster, target_atom, delay, past) + // VOIDCREW EDIT END /datum/action/cooldown/mob_cooldown/charge/hallucination_charge/hit_target(atom/movable/source, atom/A, damage_dealt) var/applied_damage = charge_damage @@ -430,6 +407,8 @@ /datum/action/cooldown/mob_cooldown/charge/hallucination_charge/hallucination_surround/charge_sequence(atom/movable/charger, atom/target_atom, delay, past) for(var/i in 0 to 4) if(QDELETED(src) || owner != charger) // VOIDCREW EDIT + // VOIDCREW EDIT START: Keep charge ownership and cleanup valid across cancellation and yields (voidcrew/edits/actions/charge_lifecycle.dm). return hallucination_charge(target_atom, 2, 8, 2, 2, FALSE) do_charge(charger, target_atom, charge_delay, charge_past) + // VOIDCREW EDIT END diff --git a/code/datums/alarm.dm b/code/datums/alarm.dm index 4c37e564e43..7bf555fecc0 100644 --- a/code/datums/alarm.dm +++ b/code/datums/alarm.dm @@ -100,10 +100,6 @@ var/list/allowed_z_levels ///List of allowed areas. if this is null it's ignored var/list/allowed_areas - /// VOIDCREW EDIT ADDITION: weakref to the atom whose map region scopes a z-scoped - /// listener, or null for "z granularity only" (the upstream behaviour). Set by - /// /datum/station_alert/New(); see the comment there. - var/datum/weakref/region_anchor_ref ///List of alarm type -> list of area name -> list(area, ref to area's cameras, list(sources)) var/list/alarms = list() @@ -131,7 +127,7 @@ if(allowed_z_levels && !(source_z in allowed_z_levels)) return - // VOIDCREW EDIT ADDITION: packed-level containment. Resolved live rather than + // VOIDCREW EDIT ADDITION START: packed-level containment. Resolved live rather than // snapshotted - a ship-mounted console changes z constantly, and its site with it. var/atom/region_anchor = region_anchor_ref?.resolve() if(region_anchor) diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm index 6b9379f909c..556a7a1e8ff 100644 --- a/code/datums/components/chasm.dm +++ b/code/datums/components/chasm.dm @@ -303,8 +303,10 @@ GLOBAL_LIST_EMPTY(chasm_fallen_mobs) // Keyed by REF rather than by the region datum: GLOB.chasm_fallen_mobs holds these // forever, and a datum key would be a hard-delete blocker on every torn-down site. var/datum/region = map_region_for_turf(turf) + // VOIDCREW EDIT START: Keep chasm victims grouped by site when several encounters share a z-level (voidcrew/datums/map_footprint.dm). if(region) return "site-[REF(region)]-[z_level]" + // VOIDCREW EDIT END if(is_away_level(z_level)) return ZTRAIT_AWAY diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index 168678d3434..912c6a602f1 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -420,8 +420,10 @@ if (recipe.category == CAT_CULT && !IS_CULTIST(user)) // Skip blood cult recipes if not cultist return FALSE //VOID EDIT - blueprint schematics: only visible while carrying the physical blueprint or holding a round-long neural imprint (voidcrew/modules/weapons_bench/blueprint.dm) + // VOIDCREW EDIT START: Gate schematic crafting on a carried blueprint or imprint (voidcrew/modules/weapons_bench/blueprint.dm). if(istype(recipe, /datum/crafting_recipe/blueprint) && !is_blueprint_recipe_available(recipe, user)) return FALSE + // VOIDCREW EDIT END //VOID EDIT END return TRUE diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm index 6014bcd802f..a525ac35eeb 100644 --- a/code/datums/components/gps.dm +++ b/code/datums/components/gps.dm @@ -162,9 +162,11 @@ GLOBAL_LIST_EMPTY(GPS_list) // signals by overmap locality (voidcrew/edits/gps.dm). Default: upstream behavior. /// Whether a signal at pos should be listed for a unit located at curr. /datum/component/gps/item/proc/is_signal_visible(turf/curr, turf/pos) + // VOIDCREW EDIT START: Expose GPS visibility for overmap-local filtering in voidcrew/edits/gps.dm. if(global_mode) return TRUE return pos.z == curr.z + // VOIDCREW EDIT END /datum/component/gps/item/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() diff --git a/code/datums/components/irradiated.dm b/code/datums/components/irradiated.dm index 8b4c88833d7..d9b67449f28 100644 --- a/code/datums/components/irradiated.dm +++ b/code/datums/components/irradiated.dm @@ -175,11 +175,13 @@ // damage but deals 2 tox per 25 seconds, so an irradiated crewmember outruns // their own liver and the state is effectively permanent without heavy chemical // treatment. Showering is the intended way to come home off a contaminated planet. + // VOIDCREW EDIT START: Let washing remove planetary irradiation from crew as well as items. if (ishuman(parent)) to_chat(parent, span_nicegreen("The water sluices the contamination off your skin.")) qdel(src) return COMPONENT_CLEANED|COMPONENT_CLEANED_GAIN_XP + // VOIDCREW EDIT END /datum/component/irradiated/proc/on_geiger_counter_scan(datum/source, mob/user, obj/item/geiger_counter/geiger_counter) SIGNAL_HANDLER diff --git a/code/datums/components/orbiter.dm b/code/datums/components/orbiter.dm index a302d62a189..5011386fbab 100644 --- a/code/datums/components/orbiter.dm +++ b/code/datums/components/orbiter.dm @@ -26,6 +26,7 @@ RegisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, PROC_REF(orbiter_glide_size_update)) // Transfer temporarily clears parent; moving an orbiter before reattachment fires its stop signal at null. + // VOIDCREW EDIT: Reattach orbiters before movement signals and tolerate a deleted orbit master. move_react(target) /datum/component/orbiter/UnregisterFromParent() @@ -36,6 +37,7 @@ /datum/component/orbiter/Destroy() var/atom/master = parent + // VOIDCREW EDIT: Reattach orbiters before movement signals and tolerate a deleted orbit master. if(master?.orbiters == src) master.orbiters = null for(var/i in orbiter_list) @@ -58,11 +60,13 @@ orbiter_list += newcomp.orbiter_list newcomp.orbiter_list = null // A transfer into an existing orbit merges here instead of registering a new component. + // VOIDCREW EDIT: Reattach orbiters before movement signals and tolerate a deleted orbit master. move_react(parent) /datum/component/orbiter/PostTransfer(datum/new_parent) if(!isatom(new_parent) || isarea(new_parent) || !get_turf(new_parent)) return COMPONENT_INCOMPATIBLE +// VOIDCREW EDIT REMOVAL: Reattach orbiters before movement signals and tolerate a deleted orbit master. /datum/component/orbiter/proc/begin_orbit(atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation) if(orbiter.orbiting) diff --git a/code/datums/components/overlay_lighting.dm b/code/datums/components/overlay_lighting.dm index cf8641b61b0..cb22169b4aa 100644 --- a/code/datums/components/overlay_lighting.dm +++ b/code/datums/components/overlay_lighting.dm @@ -287,17 +287,6 @@ return set_holder(null) -/** - * Re-runs the holder check from outside the component. - * - * We only re-check the holder when our own parent moves, so a light sitting in someone's - * pocket keeps whatever holder it resolved to when it was last moved. If that mob then - * leaves a container the light was never told about it, and stays dark. Anything that - * dumps a mob out of itself should poke this - see [/atom/movable/proc/recheck_contained_lights]. - */ -/datum/component/overlay_lighting/proc/recheck_holder() - check_holder() - ///Called when the current_holder is qdeleted, to remove the light effect. /datum/component/overlay_lighting/proc/on_holder_qdel(atom/movable/source, force) @@ -472,6 +461,7 @@ // Our holder can be stale: whatever the parent is inside can move without the parent // itself moving, and only the parent moving re-runs this. Must happen before we set // LIGHTING_ON, or set_holder() applies the light and we then apply it a second time. + // VOIDCREW EDIT: Refresh contained light holders before enabling the overlay (voidcrew/edits/components/overlay_lighting_holder.dm). check_holder() overlay_lighting_flags |= LIGHTING_ON if(current_holder) diff --git a/code/datums/components/shuttle_cling.dm b/code/datums/components/shuttle_cling.dm index 5e5cd3f077d..62e729f6eb2 100644 --- a/code/datums/components/shuttle_cling.dm +++ b/code/datums/components/shuttle_cling.dm @@ -34,31 +34,14 @@ return COMPONENT_INCOMPATIBLE // A deferred transit callback may arrive after the movable has left hyperspace. + // VOIDCREW EDIT START: Ignore delayed shuttle-cling callbacks after transit or component deletion (voidcrew/edits/components/shuttle_cling_lifecycle.dm). if(!is_on_hyperspace(parent)) return COMPONENT_REDUNDANT + // VOIDCREW EDIT END src.direction = direction -/datum/component/shuttle_cling/RegisterWithParent() - . = ..() - // Drift may immediately move the parent off transit and delete this component. - // Start it only after _JoinParent(), so removal can safely unregister us. - ADD_TRAIT(parent, TRAIT_HYPERSPACED, REF(src)) - - RegisterSignals(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_UNBUCKLE, COMSIG_ATOM_NO_LONGER_PULLED), PROC_REF(update_state)) - RegisterSignal(parent, SIGNAL_REMOVETRAIT(TRAIT_FREE_HYPERSPACE_MOVEMENT), PROC_REF(initialize_loop)) - RegisterSignal(parent, SIGNAL_ADDTRAIT(TRAIT_FREE_HYPERSPACE_MOVEMENT), PROC_REF(clear_loop)) - - //Items have this cool thing where they're first put on the floor if you grab them from storage, and then into your hand, which isn't caught by movement signals that well - if(isitem(parent)) - RegisterSignal(parent, COMSIG_ITEM_PICKUP, PROC_REF(do_remove)) - - if(!HAS_TRAIT(parent, TRAIT_FREE_HYPERSPACE_MOVEMENT)) - initialize_loop() - if(QDELETED(src)) - return - - update_state(parent) //otherwise we'll get moved 1 tile before we can correct ourselves, which isnt super bad but just looks jank +// VOIDCREW EDIT REMOVAL: Ignore delayed shuttle-cling callbacks after transit or component deletion (voidcrew/edits/components/shuttle_cling_lifecycle.dm). /datum/component/shuttle_cling/proc/initialize_loop() hyperloop = GLOB.move_manager.move(moving = parent, direction = direction, delay = not_clinging_move_delay, subsystem = SShyperspace_drift, priority = MOVEMENT_ABOVE_SPACE_PRIORITY, flags = MOVEMENT_LOOP_NO_DIR_UPDATE|MOVEMENT_LOOP_OUTSIDE_CONTROL) diff --git a/code/datums/components/singularity.dm b/code/datums/components/singularity.dm index 7b0007a6dbe..ab73db797b7 100644 --- a/code/datums/components/singularity.dm +++ b/code/datums/components/singularity.dm @@ -134,8 +134,10 @@ )) /datum/component/singularity/process(seconds_per_tick) + // VOIDCREW EDIT START: Stop singularity hazards at protected trader outpost boundaries (voidcrew/modules/trade/outpost_security.dm). if(neutralize_trader_outpost_hazard(parent)) // VOIDCREW return PROCESS_KILL + // VOIDCREW EDIT END // We want to move and eat once a second, but want to process our turf consume queue the rest of the time time_since_last_eat += seconds_per_tick digest() @@ -160,8 +162,10 @@ /datum/component/singularity/proc/consume(datum/source, atom/thing) SIGNAL_HANDLER + // VOIDCREW EDIT START: Stop singularity hazards at protected trader outpost boundaries (voidcrew/modules/trade/outpost_security.dm). if(is_trader_outpost_protected(parent) || is_trader_outpost_protected(thing)) // VOIDCREW return + // VOIDCREW EDIT END if (thing == parent) stack_trace("Singularity tried to consume itself.") return @@ -209,8 +213,10 @@ for (cached_index in 1 to length(turfs_to_consume)) var/turf/tile = turfs_to_consume[cached_index] + // VOIDCREW EDIT START: Stop singularity hazards at protected trader outpost boundaries (voidcrew/modules/trade/outpost_security.dm). if(is_trader_outpost_protected(tile)) // VOIDCREW: also stop pulling across the boundary. continue + // VOIDCREW EDIT END var/dist_to_tile = get_dist(tile, parent) if(grav_pull < dist_to_tile) //If we've exited the singulo's range already, just skip us @@ -248,8 +254,10 @@ /datum/component/singularity/proc/moved(datum/source, atom/new_location) SIGNAL_HANDLER + // VOIDCREW EDIT START: Stop singularity hazards at protected trader outpost boundaries (voidcrew/modules/trade/outpost_security.dm). if(is_trader_outpost_protected(new_location)) // VOIDCREW: even stage five must respect the boundary. return COMPONENT_MOVABLE_BLOCK_PRE_MOVE + // VOIDCREW EDIT END var/atom/atom_parent = parent var/current_direction = atom_parent.dir @@ -273,8 +281,10 @@ /datum/component/singularity/proc/can_move(turf/to_move) if (!to_move) + // VOIDCREW EDIT START: Stop singularity hazards at protected trader outpost boundaries (voidcrew/modules/trade/outpost_security.dm). return FALSE if(is_trader_outpost_protected(to_move)) // VOIDCREW + // VOIDCREW EDIT END return FALSE for (var/_thing in to_move) diff --git a/code/datums/components/spawner.dm b/code/datums/components/spawner.dm index 2a7aa510b59..00ba48f2d91 100644 --- a/code/datums/components/spawner.dm +++ b/code/datums/components/spawner.dm @@ -19,15 +19,6 @@ var/spawn_distance /// Distance from the spawner to exclude mobs from spawning var/spawn_distance_exclude - // VOIDCREW EDIT ADDITION: cached map-tenant footprint for the presence gate in - // try_spawn_mob(). Resolved lazily on the first tick that has anyone on our z-level and - // re-resolved if the parent ever moves (structures do not, but components ride mobs and - // items too). Null means "this level is not shared", which is the common case and the - // one that keeps the plain z-level gate. - var/datum/map_footprint/cached_footprint - /// The turf cached_footprint was resolved from, so a moved parent invalidates it. - var/turf/cached_footprint_turf - // VOIDCREW EDIT ADDITION END COOLDOWN_DECLARE(spawn_delay) /datum/component/spawner/Initialize(spawn_types = list(), spawn_time = 30 SECONDS, max_spawned = 5, max_spawn_per_attempt = 1 , faction = list(FACTION_MINING), spawn_text = null, datum/callback/spawn_callback = null, spawn_distance = 1, spawn_distance_exclude = 0, initial_spawn_delay = 0 SECONDS) @@ -50,17 +41,6 @@ RegisterSignal(parent, COMSIG_VENT_WAVE_CONCLUDED, PROC_REF(stop_spawning)) START_PROCESSING((spawn_time < 2 SECONDS ? SSfastprocess : SSprocessing), src) -// VOIDCREW EDIT: break the parent <-> spawn_callback reference cycle. -// /obj/structure/spawner passes spawn_callback = CALLBACK(src, PROC_REF(on_mob_spawn)), -// and the callback datum's obj var keeps the parent alive: parent -> components -> -// this component -> spawn_callback -> parent never soft-GCs, so every component-based -// spawner hard-deletes - a multi-minute reference search each under REFERENCE_TRACKING. -/datum/component/spawner/Destroy() - spawn_callback = null - spawned_things = null - cached_footprint = null - cached_footprint_turf = null - return ..() /datum/component/spawner/process() try_spawn_mob() @@ -79,7 +59,7 @@ if(!COOLDOWN_FINISHED(src, spawn_delay)) return - // VOIDCREW EDIT: don't spawn where nobody is standing. + // VOIDCREW EDIT START: don't spawn where nobody is standing. // Spawned mobs die unattended out there (vacuum, weather, each other) and // validate_references() frees the slot the instant one is DEAD, so a bone pit or // monster den on a loaded-but-unvisited level emits a fresh corpse every spawn_time @@ -153,6 +133,7 @@ created_mob.faction = src.faction // The assignment above deliberately replaces the mob's initialized faction list, // so restore any native-planet token it received during Initialize(). + // VOIDCREW EDIT: Spawn only near players in the same footprint and preserve native planetary factions (voidcrew/edits/components/spawner_lifecycle.dm). inherit_planetary_faction(created_mob) RegisterSignal(created, COMSIG_MOB_STATCHANGE, PROC_REF(mob_stat_changed)) @@ -165,7 +146,6 @@ spawner.visible_message(span_danger("A creature [spawn_text] [spawner].")) - /// Remove weakrefs to atoms which have been killed or deleted without us picking it up somehow /datum/component/spawner/proc/validate_references() for (var/datum/weakref/weak_thing as anything in spawned_things) diff --git a/code/datums/components/tether.dm b/code/datums/components/tether.dm index def01fd5f5d..9c52edc2592 100644 --- a/code/datums/components/tether.dm +++ b/code/datums/components/tether.dm @@ -19,8 +19,6 @@ var/tether_trait_source /// If TRUE, only add TRAIT_TETHER_ATTACHED to our parent var/no_target_trait - /// Prevents infinite recursion when pulling the anchor - var/currently_pulling = FALSE /datum/component/tether/Initialize(atom/tether_target, max_dist = 7, tether_name, atom/embed_target = null, start_distance = null, \ parent_module = null, tether_trait_source = null, no_target_trait = FALSE) @@ -86,8 +84,10 @@ SIGNAL_HANDLER // Prevent infinite recursion when pulling the anchor causes their tether check to pull us back + // VOIDCREW EDIT START: Guard mutual tether pulls against recursive movement (voidcrew/edits/components/tether_pulling.dm). if (currently_pulling) return + // VOIDCREW EDIT END if (check_snap()) return @@ -100,10 +100,12 @@ var/atom/movable/movable_source = source var/atom/movable/anchor = (source == tether_target ? parent : tether_target) if (get_dist(anchor, new_loc) > cur_dist) + // VOIDCREW EDIT START: Guard mutual tether pulls against recursive movement (voidcrew/edits/components/tether_pulling.dm). currently_pulling = TRUE var/pull_success = istype(anchor) && !anchor.anchored && anchor.move_resist <= movable_source.move_force && anchor.Move(get_step_towards(anchor, new_loc)) currently_pulling = FALSE if (!pull_success) + // VOIDCREW EDIT END to_chat(source, span_warning("[tether_name] runs out of slack and prevents you from moving!")) return COMPONENT_MOVABLE_BLOCK_PRE_MOVE diff --git a/code/datums/elements/decals/_decal.dm b/code/datums/elements/decals/_decal.dm index d1bc4e501fe..42627636571 100644 --- a/code/datums/elements/decals/_decal.dm +++ b/code/datums/elements/decals/_decal.dm @@ -59,7 +59,6 @@ ) - /datum/element/decal/Attach(atom/target, _icon, _icon_state, _dir, _plane=FLOAT_PLANE, _layer=FLOAT_LAYER, _alpha=255, _color, _smoothing, _cleanable=FALSE, _description, mutable_appearance/_pic) . = ..() if(!isatom(target)) @@ -75,6 +74,7 @@ smoothing = _smoothing RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(apply_overlay), TRUE) + // VOIDCREW EDIT: Expose attached decals while preserving remaining decal rotation listeners (voidcrew/edits/elements/decal_collection.dm). RegisterSignal(target, COMSIG_ATOM_GET_DECALS, PROC_REF(collect_decals), TRUE) if(target.flags_1 & INITIALIZED_1) target.update_appearance(UPDATE_OVERLAYS) //could use some queuing here now maybe. @@ -115,10 +115,12 @@ /datum/element/decal/Detach(atom/source) UnregisterSignal(source, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_ATOM_EXAMINE, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_TURF_ON_SHUTTLE_MOVE, COMSIG_ATOM_SMOOTHED_ICON, COMSIG_ATOM_DECALS_ROTATING)) + // VOIDCREW EDIT START: Expose attached decals while preserving remaining decal rotation listeners (voidcrew/edits/elements/decal_collection.dm). UnregisterSignal(source, COMSIG_ATOM_GET_DECALS) // Removing one decal must not stop the remaining decals from rotating with their host. if(!source._listen_lookup?[COMSIG_ATOM_DECALS_ROTATING]) SSdcs.UnregisterSignal(source, COMSIG_ATOM_DIR_CHANGE) + // VOIDCREW EDIT END source.update_appearance(UPDATE_OVERLAYS) if(isitem(source)) INVOKE_ASYNC(source, TYPE_PROC_REF(/obj/item/, update_slot_icon)) @@ -138,10 +140,6 @@ overlay_list += pic -/datum/element/decal/proc/collect_decals(atom/source, list/decals) - SIGNAL_HANDLER - - decals += src /datum/element/decal/proc/clean_react(datum/source, clean_types) SIGNAL_HANDLER diff --git a/code/datums/elements/turf_transparency.dm b/code/datums/elements/turf_transparency.dm index 6ff5c9f971f..e3c144cb991 100644 --- a/code/datums/elements/turf_transparency.dm +++ b/code/datums/elements/turf_transparency.dm @@ -262,7 +262,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) ///Called when there is no real turf below this turf /datum/element/turf_z_transparency/proc/get_baseturf_underlay(turf/our_turf) - // VOIDCREW EDIT: the map FOOTPRINT under the turf answers before the z-level, the same + // VOIDCREW EDIT START: the map FOOTPRINT under the turf answers before the z-level, the same // order /turf/ChangeTurf uses (voidcrew/edits/turf.dm). A level holds up to four planets // of different biomes and ZTRAIT_BASETURF is one value per level; without this the // open-space underlay drawn under a hole on one packed planet is painted with the @@ -278,6 +278,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) // VOIDCREW EDIT: PLANE_SPACE is multiplied by parallax. Planetary ground must // render with the floors, below glass and plating, or the sky shows through it. var/is_space = ispath(path, /turf/open/space) + // VOIDCREW EDIT START: Use the tenant baseturf and render planetary underlays on the floor plane (voidcrew/datums/map_footprint.dm). var/mutable_appearance/underlay_appearance = mutable_appearance( initial(path.icon), initial(path.icon_state), @@ -285,6 +286,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) offset_spokesman = our_turf, plane = is_space ? PLANE_SPACE : FLOOR_PLANE, ) + // VOIDCREW EDIT END underlay_appearance.appearance_flags = RESET_ALPHA | RESET_COLOR return underlay_appearance diff --git a/code/datums/elements/weather_listener.dm b/code/datums/elements/weather_listener.dm index d8af355e0b8..b7bbbcb8e82 100644 --- a/code/datums/elements/weather_listener.dm +++ b/code/datums/elements/weather_listener.dm @@ -15,6 +15,7 @@ . = ..() if(!weather_type) weather_type = w_type + // VOIDCREW EDIT: Give each weather listener its own signal list for concurrent site storms. sound_change_signals = list() for(var/type in typesof(weather_type)) sound_change_signals += list( diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index c0ba59f252a..5c54b01be7a 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -200,7 +200,7 @@ for(var/turf/T as anything in RANGE_TURFS(precision,center)) if(T.is_transition_turf()) continue // Avoid picking these. - // VOIDCREW EDIT ADDITION: never offer the world border as a landing spot. Upstream + // VOIDCREW EDIT ADDITION START: never offer the world border as a landing spot. Upstream // only ever reaches cordon through /area/misc/cordon, which the NOTELEPORT test // below catches; packed lattice levels paint their band with a raw turf swap that // leaves the AREA alone (place_cordon_turf() in voidcrew/datums/map_zones.dm), so @@ -236,7 +236,7 @@ if(HAS_TRAIT(teleported_atom, TRAIT_NO_TELEPORT)) return FALSE - // VOIDCREW EDIT ADDITION: never land anybody inside the world border. + // VOIDCREW EDIT ADDITION START: never land anybody inside the world border. // // /turf/cordon is dense, opaque, airless and indestructible - ScrapeAway() returns // itself, Melt() no-ops, explosions and acid do nothing - so a mob that arrives inside @@ -272,7 +272,7 @@ && SSmapping.get_reservation_from_turf(destination_turf) != SSmapping.get_reservation_from_turf(get_turf(original_destination))) return FALSE - // VOIDCREW EDIT ADDITION: the same containment, on the slot lattice. + // VOIDCREW EDIT ADDITION START: the same containment, on the slot lattice. // The reserved-level test above was the ONLY thing keeping an imprecise teleport inside // the site it aimed at, and it only ever worked because ruins and asteroid fields lived // on ZTRAIT_RESERVED levels. Packed sites do not - lattice levels are minted @@ -303,7 +303,7 @@ if(((origin_area.area_flags & LOCAL_TELEPORT) || (destination_area.area_flags & LOCAL_TELEPORT)) && destination_area != origin_area) return FALSE - // VOIDCREW EDIT ADDITION: bitrunning containment. The LOCAL_TELEPORT check above + // VOIDCREW EDIT ADDITION START: bitrunning containment. The LOCAL_TELEPORT check above // only covers tiles a domain template painted an area onto - the untouched floor of // the reservation is plain /area/space, which has no such flag. A quantum pad built // on one of those tiles teleports real loot out of VR and past the byteforge, which diff --git a/code/datums/mapgen/CaveGenerator.dm b/code/datums/mapgen/CaveGenerator.dm index e07c63a25ab..ee6bcb862b3 100644 --- a/code/datums/mapgen/CaveGenerator.dm +++ b/code/datums/mapgen/CaveGenerator.dm @@ -102,23 +102,6 @@ closed_turf_types = expand_weights(weighted_closed_turf_types) -/** - * VOIDCREW EDIT: reports how long a generation pass took. - * - * Upstream only ever runs these generators at mapload, so shouting the timings at - * `world` reached nobody but the lobby. Here they also run MID-ROUND (asteroid - * fields, planet builds, mapgen-bearing encounters), so every player on every ship - * got a bold "Asteroid Field Generator terrain generation finished in 4.2s!" each - * time somebody, anybody, docked a rock field. Keep the lobby behaviour as-is; - * once the round is running it is admin-only. The log line is unconditional. - */ -/datum/map_generator/cave_generator/proc/announce_generation_time(message) - if(SSticker?.HasRoundStarted()) - to_chat(GLOB.admins, span_boldannounce("[message]"), MESSAGE_TYPE_DEBUG) - else - to_chat(world, span_boldannounce("[message]"), MESSAGE_TYPE_DEBUG) - log_world(message) - /datum/map_generator/cave_generator/generate_terrain(list/turfs, area/generate_in) . = ..() if(!(generate_in.area_flags & CAVES_ALLOWED)) @@ -153,6 +136,7 @@ // thousands of tiles of lit space, so this grows per churn cycle. Same guard // place_cordon_turf() carries (voidcrew/datums/map_zones.dm). if(isspaceturf(gen_turf) && gen_turf.light_on) + // VOIDCREW EDIT START: Support safe mid-round terrain swaps and budgeted generation (voidcrew/edits/turf.dm; voidcrew/modules/overmap). GLOB.starlight -= gen_turf // VOIDCREW EDIT: and its third. ChangeTurf carries the old turf's four // /datum/lighting_corner refs across its qdel()/new() pair; a raw swap gets the @@ -175,6 +159,7 @@ new_turf = new new_turf(gen_turf) if(SSlighting.initialized) new_turf.adopt_lighting_from_raw_swap(corner_ne, corner_se, corner_sw, corner_nw, old_dynamic_lumcount) + // VOIDCREW EDIT END if(gen_turf.turf_flags & NO_RUINS) new_turf.turf_flags |= NO_RUINS @@ -187,6 +172,7 @@ // every cycle, forever. Open turfs need this too: requires_activation defaults to // false, so Initialize() does not queue them and their atmos graph stays empty. if(SSair.initialized) + // VOIDCREW EDIT START: Support safe mid-round terrain swaps and budgeted generation (voidcrew/edits/turf.dm; voidcrew/modules/overmap). CALCULATE_ADJACENT_TURFS(new_turf, NORMAL_TURF) // VOIDCREW EDIT: same mid-round reality as above - thousands of turfs with no @@ -195,6 +181,7 @@ SSovermap.worldgen_yield() announce_generation_time("[name] terrain generation finished in [(REALTIMEOFDAY - start_time)/10]s!") + // VOIDCREW EDIT END /** @@ -267,6 +254,7 @@ // thousands of tiles of lit space, so this grows per churn cycle. Same guard // place_cordon_turf() carries (voidcrew/datums/map_zones.dm). if(isspaceturf(gen_turf) && gen_turf.light_on) + // VOIDCREW EDIT START: Support safe mid-round terrain swaps and budgeted generation (voidcrew/edits/turf.dm; voidcrew/modules/overmap). GLOB.starlight -= gen_turf // VOIDCREW EDIT: same corner carry as generate_terrain() above - see // /turf/proc/adopt_lighting_from_raw_swap() in voidcrew/edits/turf.dm. @@ -285,12 +273,14 @@ var/turf/new_turf = new new_turf_type(gen_turf) if(SSlighting.initialized) new_turf.adopt_lighting_from_raw_swap(corner_ne, corner_se, corner_sw, corner_nw, old_dynamic_lumcount) + // VOIDCREW EDIT END if(gen_turf.turf_flags & NO_RUINS) new_turf.turf_flags |= NO_RUINS // VOIDCREW EDIT: same mid-round adjacency scrub as generate_terrain() above if(SSair.initialized && isclosedturf(new_turf)) + // VOIDCREW EDIT: Support safe mid-round terrain swaps and budgeted generation (voidcrew/edits/turf.dm; voidcrew/modules/overmap). CALCULATE_ADJACENT_TURFS(new_turf, NORMAL_TURF) CHECK_TICK @@ -302,6 +292,7 @@ generated_turfs_per_biome[biome] = generated_turfs + // VOIDCREW EDIT: Support safe mid-round terrain swaps and budgeted generation (voidcrew/edits/turf.dm; voidcrew/modules/overmap). announce_generation_time("[name] terrain generation finished in [(REALTIMEOFDAY - start_time)/10]s!") @@ -395,6 +386,7 @@ // builds run this under the worldgen queue and must share its budget SSovermap.worldgen_yield() + // VOIDCREW EDIT: Support safe mid-round terrain swaps and budgeted generation (voidcrew/edits/turf.dm; voidcrew/modules/overmap). announce_generation_time("[name] terrain population finished in [(REALTIMEOFDAY - start_time)/10]s!") @@ -416,6 +408,7 @@ // No sense in doing anything here if nothing is allowed anyway. if(!flora_allowed && !features_allowed && !fauna_allowed) + // VOIDCREW EDIT: Support safe mid-round terrain swaps and budgeted generation (voidcrew/edits/turf.dm; voidcrew/modules/overmap). announce_generation_time("[name] terrain population finished in [(REALTIMEOFDAY - start_time)/10]s!") return @@ -425,6 +418,7 @@ CHECK_TICK + // VOIDCREW EDIT: Support safe mid-round terrain swaps and budgeted generation (voidcrew/edits/turf.dm; voidcrew/modules/overmap). announce_generation_time("[name] terrain population finished in [(REALTIMEOFDAY - start_time)/10]s!") diff --git a/code/datums/mapgen/biomes/_biome.dm b/code/datums/mapgen/biomes/_biome.dm index 8f43b7fcc9c..258e5172527 100644 --- a/code/datums/mapgen/biomes/_biome.dm +++ b/code/datums/mapgen/biomes/_biome.dm @@ -59,6 +59,7 @@ // vertices that already have them and steals them from every neighbour it shares them // with. See /turf/proc/adopt_lighting_from_raw_swap() in voidcrew/edits/turf.dm. if(!SSlighting.initialized) + // VOIDCREW EDIT START: Carry lighting corners and rebuild adjacency for live planetary terrain swaps (voidcrew/edits/turf.dm). return new turf_type(gen_turf) gen_turf.release_light_for_raw_swap() var/datum/lighting_corner/corner_ne = gen_turf.lighting_corner_NE @@ -68,6 +69,7 @@ var/old_dynamic_lumcount = gen_turf.dynamic_lumcount var/turf/new_turf = new turf_type(gen_turf) new_turf.adopt_lighting_from_raw_swap(corner_ne, corner_se, corner_sw, corner_nw, old_dynamic_lumcount) + // VOIDCREW EDIT END return new_turf @@ -103,6 +105,7 @@ // can idle a corner out from under us. See // /turf/proc/adopt_lighting_from_raw_swap() in voidcrew/edits/turf.dm. var/datum/lighting_corner/corner_ne + // VOIDCREW EDIT START: Carry lighting corners and rebuild adjacency for live planetary terrain swaps (voidcrew/edits/turf.dm). var/datum/lighting_corner/corner_se var/datum/lighting_corner/corner_sw var/datum/lighting_corner/corner_nw @@ -117,6 +120,7 @@ var/turf/new_turf = new turf_type(gen_turf) if(lighting_live) new_turf.adopt_lighting_from_raw_swap(corner_ne, corner_se, corner_sw, corner_nw, old_dynamic_lumcount) + // VOIDCREW EDIT END new_turfs += new_turf if(gen_turf.turf_flags & NO_RUINS) @@ -126,6 +130,7 @@ // raw `new` never scrubs itself out of its neighbours' atmos_adjacent_turfs. // See the matching edit in CaveGenerator.dm. if(SSair.initialized && isclosedturf(new_turf)) + // VOIDCREW EDIT: Carry lighting corners and rebuild adjacency for live planetary terrain swaps (voidcrew/edits/turf.dm). CALCULATE_ADJACENT_TURFS(new_turf, NORMAL_TURF) CHECK_TICK diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm index d6389157930..2c74ecdd108 100644 --- a/code/datums/materials/basemats.dm +++ b/code/datums/materials/basemats.dm @@ -254,8 +254,9 @@ Unless you know what you're doing, only use the first three numbers. They're in ) sheet_type = /obj/item/stack/sheet/mineral/plasma ore_type = /obj/item/stack/ore/plasma + // VOIDCREW EDIT: Price plasma as ship fuel and enable galactic market trading (voidcrew/modules/trade). value_per_unit = 20 / SHEET_MATERIAL_AMOUNT - // VOIDCREW EDIT: plasma trades on the galactic materials market. Upstream keeps + // VOIDCREW EDIT START: plasma trades on the galactic materials market. Upstream keeps // it off because plasma is the station's dedicated export; here it's ship fuel // and the market refusing exactly plasma read as a bug to crews (rounds 14/15). tradable = TRUE diff --git a/code/datums/mind/_mind.dm b/code/datums/mind/_mind.dm index b201531ed97..6171370378d 100644 --- a/code/datums/mind/_mind.dm +++ b/code/datums/mind/_mind.dm @@ -155,6 +155,7 @@ UnregisterSignal(src, COMSIG_QDELETING) current = new_current if(current) + // VOIDCREW EDIT: Remember former player bodies so site weather keeps affecting abandoned crew. current.ever_had_mind = TRUE RegisterSignal(src, COMSIG_QDELETING, PROC_REF(clear_current)) diff --git a/code/datums/records/record.dm b/code/datums/records/record.dm index e522aa2e8df..9c231f5118b 100644 --- a/code/datums/records/record.dm +++ b/code/datums/records/record.dm @@ -123,8 +123,10 @@ /datum/record/crew/Destroy() GLOB.manifest.general -= src + // VOIDCREW EDIT START: Delete associative record photos correctly and copy their appearance before posing it. QDEL_LIST_ASSOC_VAL(record_photos) record_photos = null + // VOIDCREW EDIT END return ..() /** @@ -227,6 +229,7 @@ var/icon/picture_image if(!isicon(character_appearance)) // Direction and the height chart belong to this photo, not the saved appearance. + // VOIDCREW EDIT: Delete associative record photos correctly and copy their appearance before posing it. var/mutable_appearance/appearance = new(character_appearance) appearance.setDir(orientation) if(add_height_chart) diff --git a/code/datums/screentips/atom_context.dm b/code/datums/screentips/atom_context.dm index 6843cd5c320..a81f2c26918 100644 --- a/code/datums/screentips/atom_context.dm +++ b/code/datums/screentips/atom_context.dm @@ -10,6 +10,7 @@ // re-registers over its own leftover entry. It is add_context either way, so the // duplicate warning says nothing and the stack_trace it raises is not free: inside // a try block (map loaders use them) it unwinds the whole load. + // VOIDCREW EDIT: Replace retained turf context signals during repeated live template loads. RegisterSignal(src, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(add_context), override = TRUE) /// Creates a "Type-B" contextual screentip interaction. diff --git a/code/datums/shuttles/_shuttle.dm b/code/datums/shuttles/_shuttle.dm index ee5c65ce05e..e226be739a6 100644 --- a/code/datums/shuttles/_shuttle.dm +++ b/code/datums/shuttles/_shuttle.dm @@ -82,6 +82,7 @@ // its dimensions and shuttle_areas stay empty - linkup() then walks no areas at // all and every machine that binds through connect_to_shuttle() (cryopod spawn // points, airlock ids, cameras) is silently left unbound. + // VOIDCREW EDIT START: Initialize mapped hull ports before baseturf filtering so all ship machines can bind. for(var/obj/docking_port/mobile/port in place) port.calculate_docking_port_information(src) // initTemplateBounds explicitly ignores the shuttle's docking port, to ensure that it calculates the bounds of the shuttle correctly @@ -89,6 +90,7 @@ SSatoms.InitializeAtoms(list(port)) if(register) port.register() + // VOIDCREW EDIT END if(isspaceturf(place)) // This assumes all shuttles are loaded in a single spot then moved to their real destination. continue @@ -98,6 +100,7 @@ place.insert_baseturf(3, /turf/baseturf_skipover/shuttle) +// VOIDCREW EDIT REMOVAL: Docking-port initialization now runs before the baseturf skip above so shallow hull tiles still bind. //Whatever special stuff you want /datum/map_template/shuttle/post_load(obj/docking_port/mobile/M) if(movement_force) diff --git a/code/datums/station_alert.dm b/code/datums/station_alert.dm index f382f8fc9c9..bcbc8a9c252 100644 --- a/code/datums/station_alert.dm +++ b/code/datums/station_alert.dm @@ -19,7 +19,7 @@ src.title = title src.camera_view = camera_view listener = new(alarm_types, listener_z_level, listener_areas) - // VOIDCREW EDIT ADDITION: packed-level containment for the Z-SCOPED listeners only. + // VOIDCREW EDIT ADDITION START: packed-level containment for the Z-SCOPED listeners only. // "Same z-level" is up to four unrelated crews' sites once encounters pack onto the // slot lattice, and every alarm carries its area NAME plus that area's camera refs - // so a local alert console listed the neighbouring crew's rooms and handed an AI or diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index 8e8163915bc..3dec61a02b1 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -931,6 +931,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) show_contents(to_show) return FALSE + // VOIDCREW EDIT: Allow storage access during soft crit via incapacitated_except_softcrit(). if(!isliving(to_show) || !to_show.can_perform_action(parent, ALLOW_RESTING | FORBID_TELEKINESIS_REACH | ALLOW_SOFT_CRIT)) return FALSE diff --git a/code/datums/storage/subtypes/others/bag_of_holding.dm b/code/datums/storage/subtypes/others/bag_of_holding.dm index 6cd3019979a..461ea559b9a 100644 --- a/code/datums/storage/subtypes/others/bag_of_holding.dm +++ b/code/datums/storage/subtypes/others/bag_of_holding.dm @@ -17,6 +17,7 @@ /datum/storage/bag_of_holding/proc/recursive_insertion(obj/item/to_insert, mob/living/user) // VOIDCREW: Check the bag's current location, including after the dialog. + // VOIDCREW EDIT START: Check the receiving bag location before and after the nesting dialog (voidcrew/modules/trade/bag_rift_protection.dm). if(!can_create_rift(user)) return var/safety = tgui_alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [to_insert.name]?", list("Proceed", "Abort")) @@ -29,6 +30,7 @@ || !can_insert(to_insert, user) \ || !can_create_rift(user) \ ) + // VOIDCREW EDIT END return var/turf/rift_loc = get_turf(parent) @@ -46,12 +48,3 @@ tear.start_disaster() qdel(to_insert) qdel(parent) - -/// The receiving bag can be on the other side of an area boundary from its user. -/datum/storage/bag_of_holding/proc/can_create_rift(mob/user) - var/area/bag_area = get_area(parent) - if(!bag_area || (bag_area.area_flags & NO_BOH) || is_trader_outpost_protected(parent)) - if(user) - to_chat(user, span_warning("Bluespace interference prevents the bags from nesting here.")) - return FALSE - return TRUE diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm index 1e40edda4ab..a96d0b4eed9 100644 --- a/code/datums/weather/weather.dm +++ b/code/datums/weather/weather.dm @@ -61,8 +61,6 @@ var/area_type = /area/space /// Areas to be affected by the weather, calculated when the weather begins var/list/impacted_areas = list() - /// Assoc mirror of impacted_areas (area = TRUE), for cheap membership checks in the per-mob hot path - var/list/impacted_areas_lookup = list() /// A weighted list of areas impacted by weather, where weights reflect the total turf count in each area. var/list/impacted_areas_weighted = list() /// The total number of turfs impacted by weather across all z-levels and areas. @@ -73,12 +71,6 @@ var/list/protected_areas = list() /// The list of z-levels that this weather is actively affecting var/impacted_z_levels - // VOIDCREW EDIT ADDITION START - site scoping. See voidcrew/datums/weather_site.dm - /// The /datum/weather_site that scheduled this storm, if it came from one. - var/datum/weather_site/weather_site - /// Area INSTANCES this storm is confined to. Null means the z-wide get_areas(area_type) sweep. - var/list/scoped_areas - // VOIDCREW EDIT ADDITION END /// A weighted list of z-levels impacted by weather, where weights reflect the total turf count on each level var/list/impacted_z_levels_weighted = list() @@ -106,10 +98,6 @@ /// The chance, per tick, a turf will have weather effects applied to it. This is a decimal value, 1.00 = 100%, 0.50 = 50%, etc. /// Recommend setting this low near 0.01 (results in 1 in 100 affected turfs having weather reagents applied per tick) var/turf_weather_chance = 0.01 - /// If TRUE, weather_act_turf() only tops up open reagent containers (and waters hydroponics trays when - /// the reagent is water) instead of running full reagent exposure + washing on every struck turf. - /// Planet-scale weathers pick hundreds of turfs per second. Full exposure at that rate eats whole ticks. - var/turf_act_containers_only = FALSE /// The chance, per tick, a turf will have a thunder strike applied to it. This is a decimal value, 1.00 = 100%, 0.50 = 50%, etc. /// Recommend setting this really low near 0.001 (results in 1 in 1000 affected turfs having thunder strikes applied per tick) var/turf_thunder_chance = THUNDER_CHANCE_AVERAGE // does nothing without the WEATHER_THUNDER weather_flag @@ -263,6 +251,7 @@ candidate_areas = get_areas(area_type) log_packed_level_area_sweep() // VOIDCREW EDIT ADDITION END + // VOIDCREW EDIT: Scope storm effects to their site and bound planetary weather work (voidcrew/edits/weather/packed_sites.dm). for(var/area/selected_area as anything in candidate_areas) affectareas += selected_area for(var/area/protected_area as anything in protected_areas) @@ -277,6 +266,7 @@ continue impacted_areas |= affected_area + // VOIDCREW EDIT: Use an area membership lookup for site-scoped storm eligibility (voidcrew/edits/weather/packed_sites.dm). impacted_areas_lookup[affected_area] = TRUE if(!(weather_flags & (WEATHER_THUNDER|WEATHER_TURFS))) @@ -292,34 +282,6 @@ impacted_areas_weighted[z_string][affected_area] = total_turfs total_impacted_turfs += total_turfs -/** - * VOIDCREW EDIT ADDITION - diagnostic for issue #196 (a lava planet's ash storm painting - * an ocean planet). Changes nothing about the storm. - * - * get_areas() matches by area TYPE, and every packed planet's surface and caves share - * area_type = /area/overmap_encounter/planetoid - so on a z-level carrying more than one - * map tenant this sweep can only over-reach, and a storm that takes it paints, telegraphs - * and burns on all four planets rather than on the one it belongs to. In a live round - * every planet is packed, so that is the whole of the reported symptom. - * - * Nothing in the tree is supposed to reach here on a shared level: scheduled planet storms - * carry an area-scoped site, and a site-scoped storm with no areas yet is held out of the - * scheduler entirely (SSweather.fire -> awaiting_owned_areas). An audit of every - * run_weather() caller, the site registry lifecycle, and three days of prod admin.log - * found no route that does. So rather than guess at a cause, name the offender in the - * runtime log the next time it happens - the stack trace is the caller. - */ -/datum/weather/proc/log_packed_level_area_sweep() - if(!islist(impacted_z_levels)) - return - for(var/z in impacted_z_levels) - if(!isnum(z) || z < 1 || z > length(SSmapping.z_list)) - continue - var/datum/space_level/level = SSmapping.z_list[z] - if(length(level?.footprints) <= 1) - continue - stack_trace("weather [type] fell back to the z-wide get_areas([area_type]) sweep on packed z[z] ([length(level.footprints)] tenants) - it will impact every tenant on that level. Site: [weather_site?.id || "none"]") - return /// Selects a turf impacted by weather, if available, otherwise returns null /datum/weather/proc/pick_turf() @@ -342,6 +304,7 @@ if(weather_flags & (WEATHER_TURFS)) weather_turfs_per_tick = total_impacted_turfs * turf_weather_chance + // VOIDCREW EDIT: Scope storm effects to their site and bound planetary weather work (voidcrew/edits/weather/packed_sites.dm). weather_turfs_per_tick = min(weather_turfs_per_tick, turf_act_containers_only ? MAX_CONTAINER_ONLY_TURFS_PER_TICK : MAX_TURFS_PER_TICK) if(weather_flags & (WEATHER_THUNDER)) thunder_turfs_per_tick = total_impacted_turfs * turf_thunder_chance @@ -431,6 +394,7 @@ // the checks for if a mob should receive alerts, returns TRUE if can /datum/weather/proc/can_get_alert(mob/player) var/turf/mob_turf = get_turf(player) + // VOIDCREW EDIT START: Use an area membership lookup for site-scoped storm eligibility (voidcrew/edits/weather/packed_sites.dm). if(isnull(mob_turf)) return FALSE // VOIDCREW EDIT ADDITION START - alerts follow the impacted AREAS, not the whole z-level. @@ -452,14 +416,17 @@ return FALSE // VOIDCREW EDIT ADDITION END return TRUE + // VOIDCREW EDIT END /** * Returns TRUE if the living mob can be affected by the weather */ /datum/weather/proc/can_weather_act_mob(mob/living/mob_to_check) // Preserve effects on abandoned player bodies while excluding ordinary fauna. + // VOIDCREW EDIT START: Restrict planetary storm damage to current or former player bodies. if(!mob_to_check.mind && !mob_to_check.ever_had_mind) return + // VOIDCREW EDIT END var/turf/mob_turf = get_turf(mob_to_check) @@ -469,6 +436,7 @@ if(!(mob_turf.z in impacted_z_levels)) return + // VOIDCREW EDIT: Use an area membership lookup for site-scoped storm eligibility (voidcrew/edits/weather/packed_sites.dm). if(!impacted_areas_lookup[mob_turf.loc]) return @@ -533,6 +501,7 @@ if(!weather_reagent || !weather_reagent_holder) return + // VOIDCREW EDIT START: Scope storm effects to their site and bound planetary weather work (voidcrew/edits/weather/packed_sites.dm). if(turf_act_containers_only) for(var/atom/movable/thing as anything in weather_turf) if(is_reagent_container(thing)) @@ -545,6 +514,7 @@ if(!tray.IsObscured()) tray.adjust_waterlevel(rand(5, 10)) return + // VOIDCREW EDIT END weather_reagent_holder.reagents.expose(weather_turf, TOUCH, TURF_REAGENT_VOLUME_MULTIPLIER) for(var/atom/thing as anything in weather_turf) @@ -577,8 +547,10 @@ thunder.color = thunder_color for(var/mob/living/hit_mob in weather_turf) + // VOIDCREW EDIT START: Restrict planetary storm damage to current or former player bodies. if(!can_weather_act_mob(hit_mob)) continue + // VOIDCREW EDIT END to_chat(hit_mob, span_userdanger("You've been struck by lightning!")) hit_mob.electrocute_act(50, "thunder", flags = SHOCK_TESLA|SHOCK_NOGLOVES) @@ -594,6 +566,7 @@ hit_thing.take_damage(20, BURN, ENERGY, FALSE) playsound(weather_turf, 'sound/effects/magic/lightningbolt.ogg', 100, extrarange = 10, falloff_distance = 10) weather_turf.visible_message(span_danger("A thunderbolt strikes [weather_turf]!")) + // VOIDCREW EDIT REMOVAL: Apply the existing direct lightning strike without a generic explosion that bypasses mob weather eligibility. // A generic explosion cannot honor can_weather_act_mob() and would queue damage // against ordinary fauna on this and adjacent turfs. The direct strike above and // object burn retain the intended lightning effects without bypassing eligibility. @@ -607,6 +580,7 @@ // VOIDCREW EDIT ADDITION - a hard-deleted area is nulled IN PLACE in this list rather // than removed from it, and `as anything` skips the istype filter that would catch it. if(isnull(impacted)) + // VOIDCREW EDIT: Scope storm effects to their site and bound planetary weather work (voidcrew/edits/weather/packed_sites.dm). continue if(length(overlay_cache)) impacted.overlays -= overlay_cache diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm index 672a8deeca7..cf843f29f69 100644 --- a/code/datums/weather/weather_types/ash_storm.dm +++ b/code/datums/weather/weather_types/ash_storm.dm @@ -66,6 +66,7 @@ /datum/weather/ash_storm/end() GLOB.ash_storm_sounds -= weak_sounds + // VOIDCREW EDIT: Remove only this storm sounds when concurrent sites have ash storms. GLOB.ash_storm_sounds -= strong_sounds for(var/turf/open/misc/asteroid/basalt/basalt as anything in GLOB.dug_up_basalt) if(!(basalt.loc in impacted_areas) || !(basalt.z in impacted_z_levels)) diff --git a/code/datums/weather/weather_types/floor_is_lava.dm b/code/datums/weather/weather_types/floor_is_lava.dm index c1e1103b33a..d58597ea3d1 100644 --- a/code/datums/weather/weather_types/floor_is_lava.dm +++ b/code/datums/weather/weather_types/floor_is_lava.dm @@ -29,6 +29,7 @@ /datum/weather/floor_is_lava/can_weather_act_mob(mob/living/mob_to_check) + // VOIDCREW EDIT REMOVAL: Use common weather eligibility so abandoned player bodies remain affected by lava weather. . = ..() if(!. || issilicon(mob_to_check) || istype(mob_to_check.buckled, /obj/structure/bed)) return FALSE diff --git a/code/datums/weather/weather_types/rain_storm.dm b/code/datums/weather/weather_types/rain_storm.dm index f41ed085fbc..bb47ab57f91 100644 --- a/code/datums/weather/weather_types/rain_storm.dm +++ b/code/datums/weather/weather_types/rain_storm.dm @@ -25,36 +25,49 @@ probability = 90 weather_flags = (WEATHER_TURFS | WEATHER_MOBS | WEATHER_THUNDER | WEATHER_BAROMETER) + // VOIDCREW EDIT START: Limit planetary rain work and preserve independent storm sounds across sites. turf_act_containers_only = TRUE // planet-scale storms strike hundreds of turfs/second, full reagent exposure at that rate eats whole ticks turf_thunder_chance = THUNDER_CHANCE_VERY_RARE // planet-wide areas are tens of thousands of turfs, anything above this is a constant barrage of strikes + // VOIDCREW EDIT END whitelist_weather_reagents = list(/datum/reagent/water) + // VOIDCREW EDIT START: Limit planetary rain work and preserve independent storm sounds across sites. var/list/start_sounds = list() var/list/middle_sounds = list() var/list/ending_sounds = list() + // VOIDCREW EDIT END /datum/weather/rain_storm/telegraph() + // VOIDCREW EDIT REMOVAL: Limit planetary rain work and preserve independent storm sounds across sites. for(var/area/impacted_area as anything in impacted_areas) + // VOIDCREW EDIT START: Limit planetary rain work and preserve independent storm sounds across sites. start_sounds[impacted_area] = /datum/looping_sound/rain/start middle_sounds[impacted_area] = /datum/looping_sound/rain/middle ending_sounds[impacted_area] = /datum/looping_sound/rain/end GLOB.rain_storm_sounds += start_sounds + // VOIDCREW EDIT END return ..() /datum/weather/rain_storm/start() + // VOIDCREW EDIT START: Limit planetary rain work and preserve independent storm sounds across sites. GLOB.rain_storm_sounds -= start_sounds GLOB.rain_storm_sounds += middle_sounds + // VOIDCREW EDIT END return ..() /datum/weather/rain_storm/wind_down() + // VOIDCREW EDIT START: Limit planetary rain work and preserve independent storm sounds across sites. GLOB.rain_storm_sounds -= middle_sounds GLOB.rain_storm_sounds += ending_sounds + // VOIDCREW EDIT END return ..() /datum/weather/rain_storm/end() + // VOIDCREW EDIT START: Limit planetary rain work and preserve independent storm sounds across sites. GLOB.rain_storm_sounds -= start_sounds GLOB.rain_storm_sounds -= middle_sounds GLOB.rain_storm_sounds -= ending_sounds + // VOIDCREW EDIT END return ..() /datum/weather/rain_storm/blood @@ -71,6 +84,7 @@ weather_temperature = 455 // just hot enough to apply the fried effect whitelist_weather_reagents = list(/datum/reagent/consumable/nutriment/fat/oil) weather_flags = (WEATHER_TURFS | WEATHER_INDOORS) + // VOIDCREW EDIT: Limit planetary rain work and preserve independent storm sounds across sites. turf_act_containers_only = FALSE // admeme event on station z-levels, wants the full frying splash probability = 0 // admeme event @@ -121,6 +135,7 @@ whitelist_weather_reagents = list() probability = 0 // shouldn't spawn normally weather_flags = (WEATHER_TURFS | WEATHER_MOBS | WEATHER_INDOORS | WEATHER_BAROMETER) + // VOIDCREW EDIT: Limit planetary rain work and preserve independent storm sounds across sites. turf_act_containers_only = FALSE // wizard event on the station z, the chaotic reagent splashing is the whole point /datum/weather/rain_storm/wizard/New(z_levels, list/weather_data) diff --git a/code/datums/weather/weather_types/sand_storm.dm b/code/datums/weather/weather_types/sand_storm.dm index 8277413b30b..0b76ae92d11 100644 --- a/code/datums/weather/weather_types/sand_storm.dm +++ b/code/datums/weather/weather_types/sand_storm.dm @@ -24,30 +24,35 @@ weather_flags = (WEATHER_MOBS | WEATHER_BAROMETER) + // VOIDCREW EDIT START: Preserve independent sand storm sounds across sites (voidcrew/edits/weather/sand_storm_sound.dm). var/list/weak_sounds = list() var/list/strong_sounds = list() + // VOIDCREW EDIT END /datum/weather/sand_storm/telegraph() + // VOIDCREW EDIT REMOVAL: Preserve independent sand storm sounds across sites (voidcrew/edits/weather/sand_storm_sound.dm). for(var/area/impacted_area as anything in impacted_areas) + // VOIDCREW EDIT START: Preserve independent sand storm sounds across sites (voidcrew/edits/weather/sand_storm_sound.dm). weak_sounds[impacted_area] = /datum/looping_sound/weak_outside_ashstorm strong_sounds[impacted_area] = /datum/looping_sound/active_outside_ashstorm GLOB.sand_storm_sounds += weak_sounds + // VOIDCREW EDIT END return ..() /datum/weather/sand_storm/start() + // VOIDCREW EDIT START: Preserve independent sand storm sounds across sites (voidcrew/edits/weather/sand_storm_sound.dm). GLOB.sand_storm_sounds -= weak_sounds GLOB.sand_storm_sounds += strong_sounds + // VOIDCREW EDIT END return ..() /datum/weather/sand_storm/wind_down() + // VOIDCREW EDIT START: Preserve independent sand storm sounds across sites (voidcrew/edits/weather/sand_storm_sound.dm). GLOB.sand_storm_sounds -= strong_sounds GLOB.sand_storm_sounds += weak_sounds + // VOIDCREW EDIT END return ..() -/datum/weather/sand_storm/end() - GLOB.sand_storm_sounds -= weak_sounds - GLOB.sand_storm_sounds -= strong_sounds - return ..() /datum/weather/sand_storm/weather_act_mob(mob/living/victim) victim.adjustBruteLoss(5, required_bodytype = BODYTYPE_ORGANIC) diff --git a/code/datums/weather/weather_types/snow_storm.dm b/code/datums/weather/weather_types/snow_storm.dm index c002fa67907..1d79e57d49e 100644 --- a/code/datums/weather/weather_types/snow_storm.dm +++ b/code/datums/weather/weather_types/snow_storm.dm @@ -30,15 +30,20 @@ // snowstorms temperature ignores any clothing insulation weather_flags = (WEATHER_MOBS | WEATHER_BAROMETER | WEATHER_TEMPERATURE_BYPASS_CLOTHING) + // VOIDCREW EDIT: Preserve independent snow storm sounds across sites. var/list/active_sounds = list() /datum/weather/snow_storm/start() + // VOIDCREW EDIT REMOVAL: Preserve independent snow storm sounds across sites. for(var/area/impacted_area as anything in impacted_areas) + // VOIDCREW EDIT START: Preserve independent snow storm sounds across sites. active_sounds[impacted_area] = /datum/looping_sound/snowstorm GLOB.snowstorm_sounds += active_sounds + // VOIDCREW EDIT END return ..() /datum/weather/snow_storm/end() + // VOIDCREW EDIT: Preserve independent snow storm sounds across sites. GLOB.snowstorm_sounds -= active_sounds return ..() diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm index ddb6d1b8e65..60e9ae81c2a 100644 --- a/code/modules/atmospherics/environmental/LINDA_fire.dm +++ b/code/modules/atmospherics/environmental/LINDA_fire.dm @@ -11,7 +11,6 @@ return null - /turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) return @@ -191,6 +190,7 @@ // VOIDCREW EDIT: return_air() so a turf still on the shared planetary mix takes a // private one; what we remove here has to be missing when assume_air() puts it back. var/datum/gas_mixture/location_air = location.return_air() + // VOIDCREW EDIT: Materialize private planetary air before fire removes gas (voidcrew/edits/planetary_shared_air.dm). var/datum/gas_mixture/affected = location_air.remove_ratio(volume/location_air.volume) if(affected) //in case volume is 0 reference = affected // Our color and volume will depend on this small sparked gasmix diff --git a/code/modules/atmospherics/environmental/LINDA_system.dm b/code/modules/atmospherics/environmental/LINDA_system.dm index fae9fd985b8..ebe4d39f5bd 100644 --- a/code/modules/atmospherics/environmental/LINDA_system.dm +++ b/code/modules/atmospherics/environmental/LINDA_system.dm @@ -76,6 +76,7 @@ // through to the else below is what REMOVES a pairing an earlier raw turf swap left standing, // and a continue would leave exactly the stale entry we are here to clear. var/turf/open/open_src = src + // VOIDCREW EDIT: Avoid null-air adjacency and materialize shared planetary air before writes (voidcrew/edits/planetary_shared_air.dm). var/we_hold_air = !isopenturf(src) || open_src.air // I am essentially inlineing two get_dir_multizs here, because they're way too slow on their own. I'm sorry brother var/list/z_traits = SSmapping.multiz_levels[z] @@ -105,6 +106,7 @@ // (direction & (UP | DOWN)) is just "is this vertical" by the by // VOIDCREW EDIT: `we_hold_air`/`open_neighbour.air` - see the note above the loop. var/turf/open/open_neighbour = current_turf + // VOIDCREW EDIT: Avoid null-air adjacency and materialize shared planetary air before writes (voidcrew/edits/planetary_shared_air.dm). if(canpass && we_hold_air && open_neighbour.air && CANATMOSPASS(current_turf, src, (direction & (UP|DOWN))) && !(blocks_air || current_turf.blocks_air)) LAZYINITLIST(current_turf.atmos_adjacent_turfs) atmos_adjacent_turfs[current_turf] = TRUE @@ -132,6 +134,7 @@ // pairing (the else below strips it from BOTH sides), so a `continue` here would be a no-op // against the entry that is actually causing the runtime. var/turf/open/open_src = src + // VOIDCREW EDIT: Avoid null-air adjacency and materialize shared planetary air before writes (voidcrew/edits/planetary_shared_air.dm). var/we_hold_air = !isopenturf(src) || open_src.air for(var/direction in GLOB.cardinals_multiz) var/turf/current_turf = get_step_multiz(src, direction) @@ -140,8 +143,10 @@ //Can you and me form a deeper relationship, or is this just a passing wind // (direction & (UP | DOWN)) is just "is this vertical" by the by + // VOIDCREW EDIT START: Avoid null-air adjacency and materialize shared planetary air before writes (voidcrew/edits/planetary_shared_air.dm). var/turf/open/open_neighbour = current_turf if(canpass && we_hold_air && open_neighbour.air && CANATMOSPASS(current_turf, src, (direction & (UP|DOWN))) && !(blocks_air || current_turf.blocks_air)) + // VOIDCREW EDIT END LAZYINITLIST(current_turf.atmos_adjacent_turfs) atmos_adjacent_turfs[current_turf] = TRUE current_turf.atmos_adjacent_turfs[src] = TRUE @@ -238,6 +243,7 @@ var/datum/gas_mixture/turf_mixture = SSair.parse_gas_string(text, /datum/gas_mixture/turf) var/datum/gas_mixture/our_air = materialize_planet_air() // VOIDCREW EDIT: shared planetary mix + // VOIDCREW EDIT: Avoid null-air adjacency and materialize shared planetary air before writes (voidcrew/edits/planetary_shared_air.dm). our_air.merge(turf_mixture) archive() SSair.add_to_active(src) diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index 1a55a14ff03..0cd4380d81d 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -57,14 +57,17 @@ #endif /turf/open/Initialize(mapload) + // VOIDCREW EDIT: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). prepare_planet_atmosphere() // VOIDCREW: authored atmosphere precedes air creation. if(!blocks_air) // VOIDCREW EDIT: a planetary turf starts on the shared mix for its gas string and only // takes a private mixture on its first write. See voidcrew/edits/planetary_shared_air.dm. if(planetary_atmos) + // VOIDCREW EDIT START: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). air = planetary_shared_air() if(!air) air = create_gas_mixture() + // VOIDCREW EDIT END if(planetary_atmos) if(!SSair.planetary[initial_gas_mix]) var/datum/gas_mixture/immutable/planetary/mix = new @@ -98,6 +101,7 @@ if(!giver) return FALSE var/datum/gas_mixture/our_air = materialize_planet_air() // VOIDCREW EDIT: shared planetary mix + // VOIDCREW EDIT: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). our_air.merge(giver) update_visuals() air_update_turf(FALSE, FALSE) @@ -113,11 +117,13 @@ /turf/open/proc/copy_air_with_tile(turf/open/target_turf) if(istype(target_turf)) var/datum/gas_mixture/our_air = materialize_planet_air() // VOIDCREW EDIT: shared planetary mix + // VOIDCREW EDIT: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). our_air.copy_from(target_turf.air) /turf/open/proc/copy_air(datum/gas_mixture/copy) if(copy) var/datum/gas_mixture/our_air = materialize_planet_air() // VOIDCREW EDIT: shared planetary mix + // VOIDCREW EDIT: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). our_air.copy_from(copy) /turf/return_air() @@ -131,6 +137,7 @@ // so a turf still on the shared planetary mix takes its private copy now. Readers that // must not trigger that use return_air_readonly(). if(planetary_atmos) + // VOIDCREW EDIT: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). return materialize_planet_air() return air @@ -335,9 +342,11 @@ // VOIDCREW EDIT: share() writes both mixes. Either turf may still be on the shared // planetary mix; give it a private one first (no-op otherwise). if(planetary_atmos) + // VOIDCREW EDIT START: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). our_air = materialize_planet_air() if(enemy_tile.planetary_atmos) enemy_air = enemy_tile.materialize_planet_air() + // VOIDCREW EDIT END var/difference = our_air.share(enemy_air, our_share_coeff, 1 / (LAZYLEN(enemy_tile.atmos_adjacent_turfs) + 1)) if(difference) if(difference > 0) @@ -369,6 +378,7 @@ // VOIDCREW EDIT: a 100% share into space writes us; leave the shared planetary mix first. if(planetary_atmos && share_end) + // VOIDCREW EDIT: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). our_air = materialize_planet_air() for(var/turf/open/enemy_tile as anything in share_end) var/datum/gas_mixture/enemy_mix = enemy_tile.air @@ -636,6 +646,7 @@ Then we space some of our heat, and think about if we should stop conducting. var/turf/open/open_other = other // VOIDCREW EDIT: temperature_share() writes both mixes; neither may stay on the shared planetary mix. var/datum/gas_mixture/other_air = open_other.materialize_planet_air() + // VOIDCREW EDIT: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). other_air.temperature_share(materialize_planet_air(), WINDOW_HEAT_TRANSFER_COEFFICIENT) else //Open but neighbor is solid temperature_share_open_to_solid(other) @@ -675,6 +686,7 @@ Then we space some of our heat, and think about if we should stop conducting. //Conduct with air on my tile if I have it if(..((blocks_air ? temperature : air.temperature)) != FALSE && !blocks_air) var/datum/gas_mixture/our_air = materialize_planet_air() // VOIDCREW EDIT: shared planetary mix + // VOIDCREW EDIT: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). temperature = our_air.temperature_share(null, thermal_conductivity, temperature, heat_capacity) ///Should we attempt to superconduct? @@ -712,6 +724,7 @@ Then we space some of our heat, and think about if we should stop conducting. /turf/open/proc/temperature_share_open_to_solid(turf/sharer) var/datum/gas_mixture/our_air = materialize_planet_air() // VOIDCREW EDIT: shared planetary mix + // VOIDCREW EDIT: Prepare planetary atmospheres and materialize private gas before every mutation (voidcrew/edits/planetary_shared_air.dm). sharer.temperature = our_air.temperature_share(null, sharer.thermal_conductivity, sharer.temperature, sharer.heat_capacity) /turf/proc/share_temperature_mutual_solid(turf/sharer, conduction_coefficient) //This is all just heat sharing, don't get freaked out diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index 41b21bf8980..07bb3d1e734 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -200,8 +200,10 @@ // braces with the guards in SSair.add_to_rebuild_queue()/process_rebuilds(): this one // also covers any caller that reaches rebuild_pipes() without going through the queue. if(QDELETED(src)) + // VOIDCREW EDIT START: Avoid new pipelines for dying atmos machines and tolerate asymmetric node teardown. rebuilding = FALSE return + // VOIDCREW EDIT END var/list/targets = get_rebuild_targets() rebuilding = FALSE for(var/datum/pipeline/build_off as anything in targets) @@ -419,8 +421,10 @@ // VOIDCREW EDIT: Find() returns 0 on an asymmetric link, and nodes[0] runtimes - // aborting the caller's Destroy() chain before any of its cleanup runs var/node_index = nodes.Find(reference) + // VOIDCREW EDIT START: Avoid new pipelines for dying atmos machines and tolerate asymmetric node teardown. if(node_index) nodes[node_index] = null + // VOIDCREW EDIT END update_appearance() /obj/machinery/atmospherics/attackby(obj/item/W, mob/user, list/modifiers, list/attack_modifiers) diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm index 94cf5a5ebce..d9c4e1ac2e4 100644 --- a/code/modules/atmospherics/machinery/components/components_base.dm +++ b/code/modules/atmospherics/machinery/components/components_base.dm @@ -179,6 +179,7 @@ // expected teardown path, not an error - the old CRASH here fired once per // pipeline with components on every hull/zone teardown if(QDESTROYING(reference)) + // VOIDCREW EDIT: Maintain both sides of component pipeline links during live rebuilds and merges. return qdel(reference) @@ -196,6 +197,7 @@ return ..() /obj/machinery/atmospherics/components/set_pipenet(datum/pipeline/reference, obj/machinery/atmospherics/target_component) + // VOIDCREW EDIT START: Maintain both sides of component pipeline links during live rebuilds and merges. var/port_index = nodes.Find(target_component) var/datum/pipeline/previous_parent = parents[port_index] if(previous_parent == reference) @@ -211,11 +213,13 @@ previous_parent.other_atmos_machines -= src if(custom_reconcilation) previous_parent.require_custom_reconcilation -= src + // VOIDCREW EDIT END /obj/machinery/atmospherics/components/return_pipenet(obj/machinery/atmospherics/target_component = nodes[1]) //returns parents[1] if called without argument return parents[nodes.Find(target_component)] /obj/machinery/atmospherics/components/replace_pipenet(datum/pipeline/Old, datum/pipeline/New) + // VOIDCREW EDIT START: Maintain both sides of component pipeline links during live rebuilds and merges. var/first_port = parents.Find(Old) if(!first_port) CRASH("[type] at [COORD(src)] was asked to replace a pipeline it does not belong to.") @@ -223,6 +227,7 @@ for(var/port_index in first_port to length(parents)) if(parents[port_index] == Old) parents[port_index] = New + // VOIDCREW EDIT END // Helpers diff --git a/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm b/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm index cdc6e6713b0..3b62309ffab 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm @@ -97,8 +97,10 @@ // The internal connector can be deleted first during map cleanup. Its own // destruction disconnects the pipes, and connector_deleted has cleared this reference. + // VOIDCREW EDIT START: Tolerate an internal connector already removed during site teardown. if(gas_connector) disconnect_connector() + // VOIDCREW EDIT END SSair.stop_processing_machine(connected_machine) unregister_from_machine() qdel(src) diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm index 39dbb486574..0ea192d37ab 100644 --- a/code/modules/atmospherics/machinery/datum_pipeline.dm +++ b/code/modules/atmospherics/machinery/datum_pipeline.dm @@ -21,25 +21,9 @@ var/building = FALSE /// VOIDCREW ADDITION: consecutive orphan sweeps this pipeline has been found with no /// live members on. Reset the moment it has any. See SSair.reap_orphan_pipelines(). + // VOIDCREW EDIT: Detach pipeline ownership safely and remove stale members during site churn (voidcrew/edits/atmospherics/pipeline_cleanup.dm). var/orphan_strikes = 0 -/** - * VOIDCREW ADDITION: TRUE if anything real is still attached to this pipeline. - * - * Not the same question as `length(members)`. When a machine is hard deleted its entries - * in these lists are nulled in place rather than removed, so a pipeline that has lost - * everything still reads as length 1 with a null inside. `as anything` is deliberate for - * exactly that reason - a typed loop would silently filter the nulls out and hide the - * distinction we are trying to measure. - */ -/datum/pipeline/proc/has_live_members() - for(var/obj/machinery/atmospherics/member as anything in members) - if(!isnull(member) && !QDELETED(member)) - return TRUE - for(var/obj/machinery/atmospherics/machine as anything in other_atmos_machines) - if(!isnull(machine) && !QDELETED(machine)) - return TRUE - return FALSE /datum/pipeline/New() other_airs = list() @@ -62,6 +46,7 @@ // removes the component from other_atmos_machines) - a for-in over the live list // skips every other entry when the current one is removed. Detach the lists first. var/list/dying_members = members + // VOIDCREW EDIT START: Detach pipeline ownership safely and remove stale members during site churn (voidcrew/edits/atmospherics/pipeline_cleanup.dm). members = list() for(var/obj/machinery/atmospherics/pipe/considered_pipe in dying_members) // Only sever pipes that are still ours: a pipe already rebuilt into a LIVE @@ -70,9 +55,11 @@ // leaving the live pipeline holding a pipe that no longer pointed back. if(considered_pipe.parent == src) considered_pipe.replace_pipenet(src, null) + // VOIDCREW EDIT END if(QDELETED(considered_pipe)) continue SSair.add_to_rebuild_queue(considered_pipe) + // VOIDCREW EDIT START: Detach pipeline ownership safely and remove stale members during site churn (voidcrew/edits/atmospherics/pipeline_cleanup.dm). var/list/dying_machines = other_atmos_machines other_atmos_machines = list() for(var/obj/machinery/atmospherics/components/considered_component in dying_machines) @@ -83,6 +70,7 @@ // animate() color filter; qdel'ing them also detaches them from any pipe // vis_contents still showing them QDEL_LIST_ASSOC_VAL(gas_visuals) + // VOIDCREW EDIT END return ..() /datum/pipeline/process() @@ -152,8 +140,10 @@ if(item.parent) var/static/pipenetwarnings = 10 if(pipenetwarnings > 0) + // VOIDCREW EDIT START: Include the area type when diagnosing stacked hull pipes during live site loading. var/area/our_area = get_area(borderline) log_mapping("build_pipeline(): [item.type] added to a pipenet while still having one. (pipes leading to the same spot stacking in one turf) around [AREACOORD(item)] in [our_area.type].") + // VOIDCREW EDIT END pipenetwarnings-- if(pipenetwarnings == 0) log_mapping("build_pipeline(): further messages about pipenets will be suppressed") @@ -220,9 +210,11 @@ // in both pipelines at once, and concatenating duplicated the shared pipes into // the survivor's members (each duplicate = one permanent GC-blocking ref). var/list/merged_members = parent_pipeline.members + // VOIDCREW EDIT START: Detach pipeline ownership safely and remove stale members during site churn (voidcrew/edits/atmospherics/pipeline_cleanup.dm). parent_pipeline.members = list() members |= merged_members for(var/obj/machinery/atmospherics/pipe/reference_pipe in merged_members) + // VOIDCREW EDIT END reference_pipe.replace_pipenet(reference_pipe.parent, src) air.merge(parent_pipeline.air) for(var/obj/machinery/atmospherics/components/reference_component in parent_pipeline.other_atmos_machines) @@ -231,6 +223,7 @@ require_custom_reconcilation |= reference_component other_atmos_machines |= parent_pipeline.other_atmos_machines other_airs |= parent_pipeline.other_airs + // VOIDCREW EDIT REMOVAL: Detach pipeline ownership safely and remove stale members during site churn (voidcrew/edits/atmospherics/pipeline_cleanup.dm). parent_pipeline.other_atmos_machines.Cut() parent_pipeline.require_custom_reconcilation.Cut() update = TRUE @@ -302,6 +295,7 @@ // A network or port being rebuilt can have no mixture yet. As in return_air(), // leave absent volumes out while still reconciling the surviving connections. + // VOIDCREW EDIT: Ignore not-yet-created gas mixtures while reconciling rebuilt pipeline ports. list_clear_nulls(gas_mixture_list) var/total_thermal_energy = 0 diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm index c0f103f817a..3a552bc2272 100644 --- a/code/modules/atmospherics/machinery/pipes/pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/pipes.dm @@ -113,6 +113,7 @@ // but SSair.networks points at them), so each stale entry was a permanent // GC-blocking ref: round 4 spent ~275 s hard-deleting pipes pinned this way. if(old_pipenet && old_pipenet != new_pipenet) + // VOIDCREW EDIT: Remove pipes from their previous network when rebuilding live site pipelines. old_pipenet.members -= src parent = new_pipenet diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm index 7e12ad0322f..2ab7bacfd01 100644 --- a/code/modules/atmospherics/machinery/portable/scrubber.dm +++ b/code/modules/atmospherics/machinery/portable/scrubber.dm @@ -197,6 +197,7 @@ name = "huge air scrubber" icon_state = "hugescrubber" anchored = TRUE + // VOIDCREW EDIT: Return portable scrubbers to idle power use after scrubbing stops. use_power = IDLE_POWER_USE active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.5 diff --git a/code/modules/error_handler/error_handler.dm b/code/modules/error_handler/error_handler.dm index af104abc216..da1baf0b539 100644 --- a/code/modules/error_handler/error_handler.dm +++ b/code/modules/error_handler/error_handler.dm @@ -1,33 +1,11 @@ GLOBAL_VAR_INIT(total_runtimes, GLOB.total_runtimes || 0) GLOBAL_VAR_INIT(total_runtimes_skipped, 0) -/* - * VOIDCREW ADDITION - runtime flood breaker state. - * - * Plain numbers on purpose. The failure these guard against (round-7, 2026-08-16) is one - * where EVERY list operation in the world starts throwing "bad list" - a boot-time, - * never-mutated list like the config subsystem's entries_by_type failed a plain read, - * as did client keybinding caches, SSgarbage's queues and this handler's own static - * error_last_seen. Anything here that touched a list or a config entry would throw on the - * way to the breaker and hand control back to BYOND's built-in handler, which is what - * actually wrote 337 MB of dd.log in 46 seconds. GLOB var reads are a global slot lookup - * and kept working throughout (GLOB.total_runtimes counted the whole flood), so the - * breaker is built out of those and nothing else. - */ -/// world.time-derived index of the flood window we are currently counting in. -GLOBAL_VAR_INIT(error_flood_window, 0) -/// Runtimes handled so far in this window. -GLOBAL_VAR_INIT(error_flood_count, 0) -/// Runtimes dropped by the breaker in this window. -GLOBAL_VAR_INIT(error_flood_suppressed, 0) -/// While world.time is below this, world/Error emits one flat line per runtime and does -/// nothing else - set when the handler itself threw. See the catch in world/Error. -GLOBAL_VAR_INIT(error_handler_degraded_until, 0) - #ifdef USE_CUSTOM_ERROR_HANDLER #define ERROR_USEFUL_LEN 2 /// Length of a flood-breaker window, in deciseconds. +// VOIDCREW EDIT START: Bound runtime flood handling and keep flat logging available if the rich handler fails. #define ERROR_FLOOD_WINDOW 10 /// Runtimes fully handled per ERROR_FLOOD_WINDOW before the breaker starts dropping them. /// Normal play sits under one runtime a second; round-7's flood ran at 81,000 log lines a @@ -39,6 +17,7 @@ GLOBAL_VAR_INIT(error_handler_degraded_until, 0) /// How long world/Error stays on its flat one-line path after throwing while handling a /// runtime. Short, because a single unlucky exception should not blind the log for long. #define ERROR_HANDLER_DEGRADE_TIME 50 +// VOIDCREW EDIT END /world/Error(exception/E, datum/e_src) GLOB.total_runtimes++ @@ -101,6 +80,7 @@ GLOBAL_VAR_INIT(error_handler_degraded_until, 0) // // Off under UNIT_TESTS: a dropped runtime never reaches GLOB.current_test.Fail(), and // a test suite that silently stops failing is worse than a slow one. +// VOIDCREW EDIT START: Bound runtime flood handling and keep flat logging available if the rich handler fails. #ifndef UNIT_TESTS var/flood_window = round(world.time / ERROR_FLOOD_WINDOW) if(flood_window != GLOB.error_flood_window) @@ -115,6 +95,7 @@ GLOBAL_VAR_INIT(error_handler_degraded_until, 0) GLOB.error_flood_suppressed++ return #endif +// VOIDCREW EDIT END var/static/regex/stack_workaround if(isnull(stack_workaround)) @@ -128,11 +109,13 @@ GLOBAL_VAR_INIT(error_handler_degraded_until, 0) // VOIDCREW ADDITION: the handler threw recently, so don't try the rich path again yet - // just get the runtime on the record in one line. See the catch below. +// VOIDCREW EDIT START: Bound runtime flood handling and keep flat logging available if the rich handler fails. #ifndef UNIT_TESTS if(world.time < GLOB.error_handler_degraded_until) SEND_TEXT(world.log, "\[[time2text(world.timeofday, "hh:mm:ss")]\] Runtime in [E.file],[E.line]: [E] (handler degraded)") return #endif +// VOIDCREW EDIT END // VOIDCREW ADDITION: everything from here down touches lists, the config subsystem, the // error cache and the structured logger, and every one of those threw in round-7. A @@ -140,6 +123,7 @@ GLOBAL_VAR_INIT(error_handler_degraded_until, 0) // handler, which prints the full call stack of the ORIGINAL error once per unwound // frame - roughly a twenty-line block per runtime with no rate limit of any kind // attached to it. Catch it here and fall back to a flat line instead. + // VOIDCREW EDIT START: Bound runtime flood handling and keep flat logging available if the rich handler fails. try if(stack_workaround.Find(E.name)) if(length(stack_workaround.group) > 0) @@ -179,9 +163,11 @@ GLOBAL_VAR_INIT(error_handler_degraded_until, 0) configured_error_limit = initial(CE.default) CE = /datum/config_entry/number/error_silence_time configured_error_silence_time = initial(CE.default) + // VOIDCREW EDIT END //Each occurence of a unique error adds to its cooldown time... + // VOIDCREW EDIT START: Bound runtime flood handling and keep flat logging available if the rich handler fails. cooldown = max(0, cooldown - (world.time - last_seen)) + configured_error_cooldown // ... which is used to silence an error if it occurs too often, too fast if(cooldown > configured_error_cooldown * configured_error_limit) @@ -245,17 +231,23 @@ GLOBAL_VAR_INIT(error_handler_degraded_until, 0) SEND_TEXT(world.log, main_line) for(var/line in desclines) SEND_TEXT(world.log, line) + // VOIDCREW EDIT END #ifdef UNIT_TESTS + // VOIDCREW EDIT START: Bound runtime flood handling and keep flat logging available if the rich handler fails. if(GLOB.current_test) //good day, sir GLOB.current_test.Fail("[main_line]\n[desclines.Join("\n")]", file = E.file, line = E.line) + // VOIDCREW EDIT END #endif + // VOIDCREW EDIT START: Bound runtime flood handling and keep flat logging available if the rich handler fails. if(Debugger?.enabled) to_chat(world, span_alertwarning("[main_line]"), type = MESSAGE_TYPE_DEBUG) + // VOIDCREW EDIT END // This writes the regular format (unwrapping newlines and inserting timestamps as needed). + // VOIDCREW EDIT START: Bound runtime flood handling and keep flat logging available if the rich handler fails. log_runtime("runtime error: [E.name]\n[E.desc]") catch(var/exception/handler_failure) // Two flat lines and a short degrade window. Nothing in here indexes a list, calls @@ -265,12 +257,15 @@ GLOBAL_VAR_INIT(error_handler_degraded_until, 0) GLOB.error_handler_degraded_until = world.time + ERROR_HANDLER_DEGRADE_TIME SEND_TEXT(world.log, "\[[time2text(world.timeofday, "hh:mm:ss")]\] Runtime in [E.file],[E.line]: [E]") SEND_TEXT(world.log, " RUNTIME HANDLER FAILED reporting the above ([handler_failure]) - flat logging for [ERROR_HANDLER_DEGRADE_TIME / 10] seconds.") + // VOIDCREW EDIT END #endif #undef ERROR_USEFUL_LEN +// VOIDCREW EDIT START: Bound runtime flood handling and keep flat logging available if the rich handler fails. #undef ERROR_FLOOD_WINDOW #undef ERROR_FLOOD_LIMIT #undef ERROR_HANDLER_DEGRADE_TIME +// VOIDCREW EDIT END /// Exists to trigger infinite recursion runtimes in testing /proc/recurse(times) diff --git a/code/modules/error_handler/error_viewer.dm b/code/modules/error_handler/error_viewer.dm index ad1629a3cb4..e5f8cb9f281 100644 --- a/code/modules/error_handler/error_viewer.dm +++ b/code/modules/error_handler/error_viewer.dm @@ -33,9 +33,11 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) * and both numbers are shown in the viewer. */ /// Full copies retained per error signature (file + line). +// VOIDCREW EDIT START: Bound retained runtime entries while keeping source totals (voidcrew/edits/error_handler/cache_retention.dm). #define ERROR_CACHE_MAX_PER_SOURCE 50 /// Ceiling on the flat all-errors list, across every source. #define ERROR_CACHE_MAX_ENTRIES 5000 +// VOIDCREW EDIT END // Common vars and procs are kept at the error_viewer level /datum/error_viewer @@ -121,6 +123,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) if (!error_source) error_source = new(e) error_sources[erroruid] = error_source + // VOIDCREW EDIT: Bound retained runtime entries while keeping source totals (voidcrew/edits/error_handler/cache_retention.dm). error_source.total_errors++ // VOIDCREW EDIT: retain a bounded number of full copies per signature. Skip-count @@ -128,6 +131,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) // window, they are what tells you how big a flood actually was, and dropping them // would leave the viewer claiming a source went quiet when it did the opposite. if(length(error_source.errors) >= ERROR_CACHE_MAX_PER_SOURCE && !skip_count) + // VOIDCREW EDIT START: Bound retained runtime entries while keeping source totals (voidcrew/edits/error_handler/cache_retention.dm). error_source.dropped_errors++ else var/datum/error_viewer/error_entry/error_entry = new(e, desclines, skip_count) @@ -135,6 +139,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) errors += error_entry error_source.errors += error_entry trim_to_cap() + // VOIDCREW EDIT END if (skip_count) return // Skip notifying admins about skipped errors. @@ -159,6 +164,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) * keeps the entry - and the /exception and description text hanging off it - alive, which * is the entire thing this is here to stop. */ +// VOIDCREW EDIT START: Bound retained runtime entries while keeping source totals (voidcrew/edits/error_handler/cache_retention.dm). /datum/error_viewer/error_cache/proc/trim_to_cap() var/overflow = length(errors) - ERROR_CACHE_MAX_ENTRIES if(overflow <= 0) @@ -169,14 +175,11 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) if(source) source.errors -= oldest errors.Cut(1, overflow + 1) +// VOIDCREW EDIT END /datum/error_viewer/error_source var/list/errors = list() var/next_message_at = 0 - /// VOIDCREW ADDITION: every runtime this source has produced, retained or not. - var/total_errors = 0 - /// VOIDCREW ADDITION: how many of those were counted but not kept as a full entry. - var/dropped_errors = 0 /datum/error_viewer/error_source/New(exception/e) if (!istype(e)) @@ -191,8 +194,10 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) var/html = build_header(back_to) // VOIDCREW ADDITION: say so when the list below is a sample rather than the whole story. + // VOIDCREW EDIT START: Bound retained runtime entries while keeping source totals (voidcrew/edits/error_handler/cache_retention.dm). if(dropped_errors) html += "[total_errors] runtimes from this source; [dropped_errors] were counted but not retained (cap is [ERROR_CACHE_MAX_PER_SOURCE] per source).

" + // VOIDCREW EDIT END for (var/datum/error_viewer/error_entry/error_entry in errors) html += "[error_entry.make_link(null, src)]
" @@ -246,5 +251,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) /datum/error_viewer/error_entry/make_link(linktext, datum/error_viewer/back_to, linear) return is_skip_count ? name : ..() +// VOIDCREW EDIT START: Bound retained runtime entries while keeping source totals (voidcrew/edits/error_handler/cache_retention.dm). #undef ERROR_CACHE_MAX_PER_SOURCE #undef ERROR_CACHE_MAX_ENTRIES +// VOIDCREW EDIT END diff --git a/code/modules/lighting/lighting_object.dm b/code/modules/lighting/lighting_object.dm index 64ec6bb43e0..fefce819478 100644 --- a/code/modules/lighting/lighting_object.dm +++ b/code/modules/lighting/lighting_object.dm @@ -35,7 +35,7 @@ GLOBAL_LIST_EMPTY(default_lighting_underlays_by_z) for(var/turf/open/space/space_tile in RANGE_TURFS(1, affected_turf)) space_tile.enable_starlight() - // VOIDCREW EDIT: ambient bleed, the same wake-up the loop above does for starlight, + // VOIDCREW EDIT START: ambient bleed, the same wake-up the loop above does for starlight, // generalised to any area that paints its light on the area instead of on its turfs // (ambient_lighting - planet surfaces). Those turfs carry no lighting objects and emit // nothing, so this brand new statically lit tile would render as a hard black edge @@ -125,7 +125,7 @@ GLOBAL_LIST_EMPTY(default_lighting_underlays_by_z) // Of note. Most of the cost in this proc is here, I think because color matrix'd underlays DO NOT cache well, which is what adding to underlays does // We use underlays because objects on each tile would fuck with maptick. if that ever changes, use an object for this instead affected_turf.underlays += current_underlay - // VOIDCREW EDIT: an area with active base lighting is lit by a BLEND_ADD overlay on + // VOIDCREW EDIT START: an area with active base lighting is lit by a BLEND_ADD overlay on // the area, not by light sources on its turfs, so every corner here reads dark and // set_luminosity comes out 0. BYOND culls the contents of a luminosity 0 tile out of // clients' view, which on a base-lit planet surface would leave the ground looking diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index cd96ae0a449..375b400c513 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -97,28 +97,30 @@ ///Transfer the lighting of one area to another /turf/proc/transfer_area_lighting(area/old_area, area/new_area) if(SSlighting.initialized && !space_lit) + // VOIDCREW EDIT START: Update ambient bleed on area transfers and tolerate live z-level growth (voidcrew/edits/lighting.dm). var/static_lighting_changed = (new_area.static_lighting != old_area.static_lighting) - // VOIDCREW EDIT: remembered so the ambient bleed block below can tell whether this + // VOIDCREW EDIT START: remembered so the ambient bleed block below can tell whether this // transfer actually took our lighting object away. See voidcrew/edits/lighting.dm. var/had_lighting_object = !!lighting_object // END VOIDCREW EDIT if (static_lighting_changed) + // VOIDCREW EDIT END if (new_area.static_lighting) lighting_build_overlay() - // VOIDCREW EDIT: a turf that lights itself inside an ambient-lit area - fallout + // VOIDCREW EDIT START: a turf that lights itself inside an ambient-lit area - fallout // ground, a lava river - keeps its object, or its own light has nothing to render // on. Everything else on the dynamic side loses it exactly as upstream. else if(!new_area.ambient_lighting || skips_lighting_object()) lighting_clear_overlay() // END VOIDCREW EDIT (was: else lighting_clear_overlay()) - // VOIDCREW EDIT: moving into ambient-lit ground from another DYNAMIC area does not + // VOIDCREW EDIT START: moving into ambient-lit ground from another DYNAMIC area does not // trip static_lighting_changed, but the object still has to go - that ground carries // none at all. else if(lighting_object && skips_lighting_object()) lighting_clear_overlay() // END VOIDCREW EDIT - // VOIDCREW EDIT: ambient bleed. Changing area without changing type - a ship + // VOIDCREW EDIT START: ambient bleed. Changing area without changing type - a ship // landing or taking off, a room being repainted, cave generation claiming a tile - // changes both whether we bleed light ourselves and whether we are something worth // bleeding onto, and nothing else on this path notices. See @@ -134,12 +136,15 @@ // We will only run this logic on turfs off the prime z layer // Since on the prime z layer, we use an overlay on the area instead, to save time + // VOIDCREW EDIT: Update ambient bleed on area transfers and tolerate live z-level growth (voidcrew/edits/lighting.dm). if(z <= length(SSmapping.z_level_to_plane_offset) && SSmapping.z_level_to_plane_offset[z]) var/index = SSmapping.z_level_to_plane_offset[z] + 1 //Inherit overlay of new area + // VOIDCREW EDIT START: Update ambient bleed on area transfers and tolerate live z-level growth (voidcrew/edits/lighting.dm). if(old_area.lighting_effects && index <= length(old_area.lighting_effects)) cut_overlay(old_area.lighting_effects[index]) if(new_area.lighting_effects && index <= length(new_area.lighting_effects)) + // VOIDCREW EDIT END add_overlay(new_area.lighting_effects[index]) // Manage removing/adding starlight overlays, we'll inherit from the area so we can drop it if the area has it already diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm index f36806b3d56..2f4d164fb52 100644 --- a/code/modules/mapping/map_template.dm +++ b/code/modules/mapping/map_template.dm @@ -96,7 +96,7 @@ continue var/area/loc_area = unlit.loc if(!loc_area.static_lighting) - // VOIDCREW EDIT: ambient-lit ground (a planet surface) carries no lighting objects + // VOIDCREW EDIT START: ambient-lit ground (a planet surface) carries no lighting objects // at all, with one exception - a turf that lights itself, e.g. a ruin dropping a // /lit tile straight onto surface ground rather than into its own area. Its light // needs somewhere to render. See /turf/proc/skips_lighting_object(). @@ -157,6 +157,7 @@ if((T.y+height) - 1 > world.maxy) return + // VOIDCREW EDIT: Retain self-lit planetary tiles and instrument live template loading (voidcrew/_HELPERS/worldgen.dm). var/datum/worldgen_probe/probe = worldgen_begin("template", "[name] [width]x[height] @ [T.x],[T.y],[T.z]") // Cache for sonic speed @@ -187,11 +188,13 @@ no_changeturf = (SSatoms.initialized == INITIALIZATION_INSSATOMS), place_on_top = should_place_on_top, )) + // VOIDCREW EDIT: Retain self-lit planetary tiles and instrument live template loading (voidcrew/_HELPERS/worldgen.dm). worldgen_end(probe, "parse-failed") return var/list/bounds = parsed.bounds if(!bounds) + // VOIDCREW EDIT: Retain self-lit planetary tiles and instrument live template loading (voidcrew/_HELPERS/worldgen.dm). worldgen_end(probe, "no-bounds") return @@ -205,6 +208,7 @@ generate_ceiling(affected_turfs) log_game("[name] loaded at [T.x],[T.y],[T.z]") + // VOIDCREW EDIT: Retain self-lit planetary tiles and instrument live template loading (voidcrew/_HELPERS/worldgen.dm). worldgen_end(probe) return bounds diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index c00b323e556..b068c64ea80 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -1,7 +1,6 @@ //Landmarks and other helpers which speed up the mapping process and reduce the number of unique instances/subtypes of items/turf/ect - /obj/effect/baseturf_helper //Set the baseturfs of every turf in the /area/ it is placed. name = "baseturf editor" icon = 'icons/effects/mapping_helpers.dmi' @@ -1147,7 +1146,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_atoms_ontop) var/datum/space_level/level = SSmapping.z_list[z] if(!level || !length(traits_to_add)) return - // VOIDCREW EDIT ADDITION: a template loaded onto the slot lattice must not rewrite the + // VOIDCREW EDIT ADDITION START: a template loaded onto the slot lattice must not rewrite the // LEVEL's traits - all four tenants inherit them, and one of them is ZTRAIT_BASETURF, // the fallback every flat tenant resolves a scraped floor through. The level's own // weather site would be rebuilt rect-less for everybody too. diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm index 7cee4d04f94..d7b13795450 100644 --- a/code/modules/mapping/reader.dm +++ b/code/modules/mapping/reader.dm @@ -777,9 +777,11 @@ GLOBAL_LIST_EMPTY(map_model_default) if(!ispath(atom_def, /atom)) // Skip the item if the path does not exist. Fix your crap, mappers! // Attributes were appended before resolving this path. Remove their slot too, // or every later atom receives the preceding atom's mapped variables. + // VOIDCREW EDIT START: Keep map attribute slots aligned and instantiate repeated planetary ruin areas separately (voidcrew/modules/overmap). members_attributes.len-- if(bad_paths) LAZYOR(bad_paths[path_to_init], model_key) + // VOIDCREW EDIT END continue // Index is already incremented either way, just gotta set the path and all members += atom_def @@ -933,9 +935,11 @@ GLOBAL_LIST_EMPTY(map_model_default) if(instance_ruin_area) area_instance = new_planet_ruin_area(area_type) // VOIDCREW EDIT ADDITION END + // VOIDCREW EDIT START: Keep map attribute slots aligned and instantiate repeated planetary ruin areas separately (voidcrew/modules/overmap). else // If this parsed map doesn't have that area already, we check the global cache area_instance = GLOB.areas_by_type[area_type] + // VOIDCREW EDIT END // If the global list DOESN'T have this area it's either not a unique area, or it just hasn't been created yet if (!area_instance) area_instance = new area_type(null) diff --git a/code/modules/mapping/ruins.dm b/code/modules/mapping/ruins.dm index 5ecbb8f9968..a888c42da17 100644 --- a/code/modules/mapping/ruins.dm +++ b/code/modules/mapping/ruins.dm @@ -1,25 +1,3 @@ -/** - * VOIDCREW EDIT: the rectangle a ruin's CENTRE turf may be sampled from, so that the - * template AND the margin it always keeps against a map edge land wholly inside `bounds`. - * - * `bounds` is an inclusive list(low_x, low_y, high_x, high_y). Returns a rect in the same - * shape, or NULL when the ruin cannot fit in it however lucky the sampling gets. - * - * get_affected_turfs(centre, centered = TRUE) spans - * [x - round(w/2), x - round(w/2) + w - 1], so a margin of round(w/2) on each side covers - * the wider (low) half with room to spare on the other; TRANSITIONEDGE + - * SPACERUIN_MAP_EDGE_PAD on top is the same clearance the unbounded sampler keeps against - * the world edge, kept here so a ruin never sits flush against the cordon. - */ -/proc/ruin_placement_sample_rect(width, height, list/bounds) - if(length(bounds) < 4) - return null - var/edge_x = TRANSITIONEDGE + SPACERUIN_MAP_EDGE_PAD + round(width / 2) - var/edge_y = TRANSITIONEDGE + SPACERUIN_MAP_EDGE_PAD + round(height / 2) - var/list/sample_rect = list(bounds[1] + edge_x, bounds[2] + edge_y, bounds[3] - edge_x, bounds[4] - edge_y) - if(sample_rect[1] > sample_rect[3] || sample_rect[2] > sample_rect[4]) - return null - return sample_rect /** * Tries to drop this ruin somewhere on z. @@ -63,12 +41,14 @@ var/height_border = TRANSITIONEDGE + SPACERUIN_MAP_EDGE_PAD + round(height / 2) // VOIDCREW EDIT: sample from the placement rect when one was given, from the whole z otherwise var/turf/central_turf + // VOIDCREW EDIT START: Sample ruins inside the tenant bounds and whitelist owned area instances (voidcrew/_HELPERS/ruin_placement.dm). if(forced_turf) central_turf = forced_turf else if(sample_bounds) central_turf = locate(rand(sample_bounds[1], sample_bounds[3]), rand(sample_bounds[2], sample_bounds[4]), z) else central_turf = locate(rand(width_border, world.maxx - width_border), rand(height_border, world.maxy - height_border), z) + // VOIDCREW EDIT END var/valid = TRUE var/list/affected_turfs = get_affected_turfs(central_turf,1) var/list/affected_areas = list() @@ -83,6 +63,7 @@ // This is faster yes. Only BARELY but it is faster if(length(allowed_area_instances)) // VOIDCREW EDIT: instance whitelist wins over the type one + // VOIDCREW EDIT START: Sample ruins inside the tenant bounds and whitelist owned area instances (voidcrew/_HELPERS/ruin_placement.dm). for(var/area/affct_area as anything in affected_areas) if(!allowed_area_instances[affct_area]) valid = FALSE @@ -92,6 +73,7 @@ if(!allowed_areas_typecache[affct_area.type]) valid = FALSE break + // VOIDCREW EDIT END if(!valid) continue @@ -156,10 +138,12 @@ var/list/whitelist_typecache = typecacheof(whitelist) // VOIDCREW EDIT: built once here rather than per placement sample var/list/whitelist_instances + // VOIDCREW EDIT START: Sample ruins inside the tenant bounds and whitelist owned area instances (voidcrew/_HELPERS/ruin_placement.dm). if(length(area_whitelist_instances)) whitelist_instances = list() for(var/area/whitelisted_area as anything in area_whitelist_instances) whitelist_instances[whitelisted_area] = TRUE + // VOIDCREW EDIT END for(var/zl in z_levels) var/turf/T = locate(1, 1, zl) @@ -215,7 +199,7 @@ break else //Otherwise just pick random one current_pick = pick_weight(ruins_available) - // VOIDCREW EDIT: pick_weight() returns null when every remaining candidate has + // VOIDCREW EDIT START: pick_weight() returns null when every remaining candidate has // weight 0, and ruins_available is only ever pruned by placement or by going // over budget - a zero-weight entry sits in it forever and keeps the `.len` // test in the while() above true. Unguarded, the next line reads diff --git a/code/modules/mapping/space_management/space_reservation.dm b/code/modules/mapping/space_management/space_reservation.dm index 873a61a901b..a5a4ae24a57 100644 --- a/code/modules/mapping/space_management/space_reservation.dm +++ b/code/modules/mapping/space_management/space_reservation.dm @@ -4,6 +4,7 @@ /// Above this many turfs, reservation teardown in Release() spreads itself over /// multiple ticks instead of running atomically. Small reservations keep the /// historical no-sleep behavior, so qdel() from tick-sensitive contexts stays safe. +// VOIDCREW EDIT: Bound long site releases while preserving atomic teardown for small reservations. #define RESERVATION_RELEASE_YIELD_THRESHOLD 2500 /datum/turf_reservation @@ -44,23 +45,6 @@ turf_type = /turf/open/space/transit pre_cordon_distance = 7 -/// Returns TRUE if the given turf falls inside this reservation's bounds. -/// Cheap bounds check against the per-z corners rather than a search of -/// reserved_turfs, which can run to thousands of entries. -/datum/turf_reservation/proc/contains_turf(turf/checked) - if(isnull(checked)) - return FALSE - - for(var/z_idx in 1 to length(bottom_left_turfs)) - var/turf/bottom_left = bottom_left_turfs[z_idx] - var/turf/top_right = top_right_turfs[z_idx] - if(checked.z != bottom_left.z) - continue - - return (checked.x >= bottom_left.x && checked.x <= top_right.x) \ - && (checked.y >= bottom_left.y && checked.y <= top_right.y) - - return FALSE /datum/turf_reservation/proc/Release() // VOIDCREW EDIT: the release set is rebuilt from the corners we recorded at claim time @@ -87,6 +71,7 @@ // alone and cannot be reached by anyone else, so block() over them stays the // authoritative answer to "what did we take" no matter who mutates our lists. var/list/released = list() + // VOIDCREW EDIT START: Keep reservation claims atomic and release large site footprints across ticks (voidcrew/edits/mapping/reservation_bounds.dm). for(var/z_idx in 1 to min(length(bottom_left_turfs), length(top_right_turfs))) var/turf/bottom_left = bottom_left_turfs[z_idx] var/turf/top_right = top_right_turfs[z_idx] @@ -102,12 +87,16 @@ for(var/turf/cordon_turf as anything in cordon_turfs) if(!isnull(cordon_turf)) released[cordon_turf] = TRUE + // VOIDCREW EDIT END bottom_left_turfs.Cut() top_right_turfs.Cut() + // VOIDCREW EDIT REMOVAL: Keep reservation claims atomic and release large site footprints across ticks (voidcrew/edits/mapping/reservation_bounds.dm). reserved_turfs = list() + // VOIDCREW EDIT REMOVAL: Keep reservation claims atomic and release large site footprints across ticks (voidcrew/edits/mapping/reservation_bounds.dm). cordon_turfs = list() + // VOIDCREW EDIT START: Bound long site releases while preserving atomic teardown for small reservations. if(!length(released)) return @@ -128,6 +117,7 @@ // from qdel(): our turf lists were already emptied above, so a reentrant Release() // during a yield has nothing left to double-process. var/can_yield = length(release_turfs) > RESERVATION_RELEASE_YIELD_THRESHOLD + // VOIDCREW EDIT END for(var/turf/reserved_turf as anything in release_turfs) SEND_SIGNAL(reserved_turf, COMSIG_TURF_RESERVATION_RELEASED, src) @@ -135,8 +125,10 @@ // immediately disconnect from atmos reserved_turf.blocks_air = TRUE CALCULATE_ADJACENT_TURFS(reserved_turf, KILL_EXCITED) + // VOIDCREW EDIT START: Keep reservation claims atomic and release large site footprints across ticks (voidcrew/edits/mapping/reservation_bounds.dm). if(can_yield) CHECK_TICK + // VOIDCREW EDIT END // Makes the linter happy, even tho we don't await this INVOKE_ASYNC(SSmapping, TYPE_PROC_REF(/datum/controller/subsystem/mapping, reserve_turfs), release_turfs) @@ -179,8 +171,10 @@ // per-turf removal is not; see _reserve_area()) cordon_turf.turf_flags &= ~UNUSED_RESERVATION_TURF cordon_turf.empty(/turf/cordon, /turf/cordon) + // VOIDCREW EDIT REMOVAL: Keep reservation claims atomic and release large site footprints across ticks (voidcrew/edits/mapping/reservation_bounds.dm). // still gets linked to us though SSmapping.used_turfs[cordon_turf] = src + // VOIDCREW EDIT: Keep reservation claims atomic and release large site footprints across ticks (voidcrew/edits/mapping/reservation_bounds.dm). CHECK_TICK //swap the area with the pre-cordoning area @@ -253,6 +247,7 @@ // the first origin that can ever pass calculate_cordon_turfs() is one in from the // band edge - anchoring there keeps the outermost usable column/row on the grid. if((BL.x - SHUTTLE_TRANSIT_BORDER - 1) % RESERVATION_ORIGIN_STRIDE || (BL.y - SHUTTLE_TRANSIT_BORDER - 1) % RESERVATION_ORIGIN_STRIDE) + // VOIDCREW EDIT: Align reservation origins so fleet transit holes can be reused without fragmentation. continue if(BL.x + width > world.maxx || BL.y + height > world.maxy) continue @@ -285,13 +280,17 @@ // of hard freeze for big reservations). The reserve scan above already skips // anything without UNUSED_RESERVATION_TURF, and the unused_turfs lists are assoc // keyed by turf, so handing a turf back later just updates its existing key. + // VOIDCREW EDIT START: Keep reservation claims atomic and release large site footprints across ticks (voidcrew/edits/mapping/reservation_bounds.dm). reserved_turfs += final for(var/turf/T as anything in final) + // VOIDCREW EDIT END SSmapping.used_turfs[T] = src T.turf_flags = (T.turf_flags | RESERVATION_TURF) & ~UNUSED_RESERVATION_TURF + // VOIDCREW EDIT START: Keep reservation claims atomic and release large site footprints across ticks (voidcrew/edits/mapping/reservation_bounds.dm). for(var/turf/cordon_turf as anything in cordon_turfs) cordon_turf.turf_flags &= ~UNUSED_RESERVATION_TURF SSmapping.used_turfs[cordon_turf] = src + // VOIDCREW EDIT END // Record the corners as part of claiming, not after the conversion below. The // turfs are already flagged RESERVATION_TURF and pointed at us in used_turfs, so @@ -303,9 +302,11 @@ // The actual turf conversion is by far the expensive part (a full ChangeTurf per // turf) - now that everything is claimed it can safely spread over multiple ticks + // VOIDCREW EDIT START: Keep reservation claims atomic and release large site footprints across ticks (voidcrew/edits/mapping/reservation_bounds.dm). for(var/turf/T as anything in final) T.empty(turf_type, turf_type_is_baseturf ? turf_type : null) CHECK_TICK + // VOIDCREW EDIT END return TRUE @@ -328,6 +329,7 @@ /datum/turf_reservation/proc/calculate_turf_bounds_information(turf/target) // Bounded by the corner lists rather than z_size, same as contains_turf(): a // half-built or already-released reservation still has its z_size set. + // VOIDCREW EDIT: Bound corner walks by the actual reservation state, including partial builds and released datums. for(var/z_idx in 1 to length(bottom_left_turfs)) var/turf/bottom_left = bottom_left_turfs[z_idx] var/turf/top_right = top_right_turfs[z_idx] @@ -363,6 +365,7 @@ var/z_idx = bounds_info["z_idx"] // check what z level, if its the max, then there is no turf below + // VOIDCREW EDIT: Bound corner walks by the actual reservation state, including partial builds and released datums. if(z_idx >= length(bottom_left_turfs)) return null @@ -387,6 +390,7 @@ var/turf/bottom_left = bottom_left_turfs[z_idx - 1] return locate(bottom_left.x + offset_x, bottom_left.y + offset_y, bottom_left.z) +// VOIDCREW EDIT: Bound long site releases while preserving atomic teardown for small reservations. #undef RESERVATION_RELEASE_YIELD_THRESHOLD /datum/turf_reservation/New() diff --git a/voidcrew/_DEFINES/core_integration.dm b/voidcrew/_DEFINES/core_integration.dm new file mode 100644 index 00000000000..d4de1ccb565 --- /dev/null +++ b/voidcrew/_DEFINES/core_integration.dm @@ -0,0 +1,42 @@ +#define R_ECONOMY (1<<15) + +/// Megafauna arenas. Priced above what they pay back so a boss dive is funded by +/// running the rest of the roster, instead of paying for itself forever. +#define BITRUNNER_COST_BOSS 5 +/// The four hardest megafauna arenas. Same idea, steeper. +#define BITRUNNER_COST_APEX_BOSS 8 + +/// Collect attached decal elements: (list/decals) +#define COMSIG_ATOM_GET_DECALS "atom_get_decals" + +/// Voidcrew. From base of /atom/movable/lateShuttleMove, once every moved atom has landed and rotated: (turf/oldT, list/movement_force, move_dir) +#define COMSIG_ATOM_LATE_SHUTTLE_MOVE "movable_late_shuttle_move" + +/// After normal /mob/living/UnarmedAttack resolution: (atom/target, list/modifiers, health_damage, stamina_damage). +/// Damage is the synchronous change during this attack; target may have been deleted by a lethal hit. +#define COMSIG_LIVING_AFTER_UNARMED_ATTACK "living_after_unarmed_attack" + +/// Sent to the destination of a proposed stack merge: (obj/item/stack/source_stack, inhand) +#define COMSIG_STACK_CAN_RECEIVE_MERGE "stack_can_receive_merge" +/// Sent before a split source can be deleted: (obj/item/stack/new_stack) +#define COMSIG_STACK_SPLIT "stack_split" + +#define ui_human_skills "EAST-4:22,SOUTH+1:7" + +/// Allows an item action in soft crit, while still checking other incapacitation sources. +#define ALLOW_SOFT_CRIT (1<<13) + +//Voidcrew: reaction refuses to run inside a grown food item, so plant +//chemistry can't be used to mass-produce the mob-spawning mixtures. +#define REACTION_NOT_IN_PLANTS (1<<8) +///The reaction opts into pH-driven purity. Unset (the fork-wide default) means pH is a live, +///drifting number that no reaction is blocked or purity-penalised by, so a recipe's optimal +///pH band never has to contain 7 to be usable. Set it to bring tg's pH mechanics back for +///that one recipe. +#define REACTION_USES_PURITY (1<<9) + + +//Voidcrew: chemistry circuits +#define PORT_COMPOSITE_TYPE_CHEMICAL "chemical list" +/// Reagent-type -> volume mapping, the currency the chemistry circuits pass around. +#define PORT_TYPE_CHEMICAL_LIST SSwiremod_composite.composite_datatype(PORT_COMPOSITE_TYPE_CHEMICAL, PORT_TYPE_DATUM, PORT_TYPE_NUMBER) diff --git a/voidcrew/_HELPERS/ruin_placement.dm b/voidcrew/_HELPERS/ruin_placement.dm new file mode 100644 index 00000000000..bbc966ccd3b --- /dev/null +++ b/voidcrew/_HELPERS/ruin_placement.dm @@ -0,0 +1,22 @@ +/** + * Voidcrew: the rectangle a ruin's CENTRE turf may be sampled from, so that the + * template AND the margin it always keeps against a map edge land wholly inside `bounds`. + * + * `bounds` is an inclusive list(low_x, low_y, high_x, high_y). Returns a rect in the same + * shape, or NULL when the ruin cannot fit in it however lucky the sampling gets. + * + * get_affected_turfs(centre, centered = TRUE) spans + * [x - round(w/2), x - round(w/2) + w - 1], so a margin of round(w/2) on each side covers + * the wider (low) half with room to spare on the other; TRANSITIONEDGE + + * SPACERUIN_MAP_EDGE_PAD on top is the same clearance the unbounded sampler keeps against + * the world edge, kept here so a ruin never sits flush against the cordon. + */ +/proc/ruin_placement_sample_rect(width, height, list/bounds) + if(length(bounds) < 4) + return null + var/edge_x = TRANSITIONEDGE + SPACERUIN_MAP_EDGE_PAD + round(width / 2) + var/edge_y = TRANSITIONEDGE + SPACERUIN_MAP_EDGE_PAD + round(height / 2) + var/list/sample_rect = list(bounds[1] + edge_x, bounds[2] + edge_y, bounds[3] - edge_x, bounds[4] - edge_y) + if(sample_rect[1] > sample_rect[3] || sample_rect[2] > sample_rect[4]) + return null + return sample_rect diff --git a/voidcrew/_HELPERS/typecache.dm b/voidcrew/_HELPERS/typecache.dm new file mode 100644 index 00000000000..3e2ba8feb6a --- /dev/null +++ b/voidcrew/_HELPERS/typecache.dm @@ -0,0 +1,16 @@ +/** + * Voidcrew: complains once per cooldown about a typecache filter called with + * something that isn't a list. + * + * The filters below run per-turf inside /turf/proc/empty(), so a reservation the size of a + * ruin interior calls them seventeen thousand times in a row. An unguarded throw there is + * not one runtime, it is a runtime per turf - which is how round-7 (2026-08-16) put a + * quarter of a million reservation runtimes into dd.log. Rate-limited so the diagnosis + * itself can never become the flood. + */ +/proc/warn_bad_typecache_filter(filter_name, list/atoms, list/typecache) + var/static/next_complaint = 0 + if(world.time < next_complaint) + return + next_complaint = world.time + 10 SECONDS + stack_trace("[filter_name]() called with [islist(atoms) ? "a list" : "a non-list"] of atoms and [islist(typecache) ? "a list" : "a non-list"] typecache - filtering nothing and returning empty") diff --git a/voidcrew/controllers/configuration/new_round_alert.dm b/voidcrew/controllers/configuration/new_round_alert.dm new file mode 100644 index 00000000000..80748b58b01 --- /dev/null +++ b/voidcrew/controllers/configuration/new_round_alert.dm @@ -0,0 +1,2 @@ +/// Discord role ID pinged in the new-round announcement sent to CHANNEL_ANNOUNCE_NEW_GAME channels +/datum/config_entry/string/new_round_alert_role_id diff --git a/voidcrew/edits/_onclick/hud/screen_extensions.dm b/voidcrew/edits/_onclick/hud/screen_extensions.dm new file mode 100644 index 00000000000..afa359a5769 --- /dev/null +++ b/voidcrew/edits/_onclick/hud/screen_extensions.dm @@ -0,0 +1,120 @@ +/atom/movable/screen/screentip + /// Weak reference so hovering cannot keep a deleted target alive. + var/datum/weakref/hovered_atom_ref + /// Invalidates text measurements that finish after the pointer has moved on. + var/hover_version = 0 + var/showing_hover = FALSE + /// Refreshed separately from mouse events, including while our ship is moving. + var/fallback_maptext = "" + +/** + * Takes the health doll off the client's screen and puts it straight back, so the client + * re-establishes the doll's visual contents. + * + * The doll draws each limb as a separate screen object in its own vis_contents + * (/atom/movable/screen/healthdoll/human/update_body_zones in screen_objects.dm), because + * upstream wants per-limb outline filters it can animate. On a z change - which here is + * every single dock and undock - the BYOND client drops those children and never gets + * them back. This is a known client-side bug class, not a DM one: BYOND id:2303806 + * ("Visual contents were not taken into account by the client-side garbage collector... + * The objects still exist, just aren't visible unless you change an appearance var to + * bring them back into the view") and id:2359025 ("visual contents no longer showed up + * after changing Z levels"). Server side the limbs stay alive with correct icon_states + * throughout - there are no runtimes for them in any round log, and nothing in DM touches + * the doll on a z change. + * + * vis_contents is not part of an atom's appearance, and the doll has no icon_state and no + * overlays of its own, so its appearance never changes for its entire life and the client + * is never told about it a second time. That leaves a limb's own icon_state as the only + * thing that can bring it back, which is exactly what players reported ("get damage on + * that limb and heal it to fix it") and why the limbs surviving a dock were always the + * ones that had taken or healed damage since. + * + * Re-adding the doll to client.screen re-sends it and its children. This is the same + * treatment the parallax backdrop already gets by accident: it is the only other screen + * object built on vis_contents, and update_parallax_pref() above tears its holder off the + * screen and adds it back (remove_parallax/create_parallax in parallax.dm) on every z + * change, which is why parallax does not rot the way the doll did. + * + * Do not "simplify" this into update_appearance() or update_body_zones(). The first + * changes nothing about the doll's appearance so nothing is sent; the second rebuilds six + * screen objects to repair a link that was never broken server side. + */ +/datum/hud/proc/resend_healthdoll() + var/client/our_client = mymob?.client + if(isnull(our_client) || isnull(healthdoll)) + return + // Hud hidden with F12? The doll is deliberately off the screen, leave it off. + if(!(healthdoll in our_client.screen)) + return + our_client.screen -= healthdoll + our_client.screen += healthdoll + +/atom/movable/screen/skills/Click() + usr.view_skills() + return TRUE + +/// Shortcut to the same personal skill report provided by the View Skills verb. +/atom/movable/screen/skills + name = "view skills and experience" + icon = 'icons/hud/screen_midnight.dmi' + icon_state = "skills" + mouse_over_pointer = MOUSE_HAND_POINTER + +/// Reapply a changed preference even when the pointer stays still. +/atom/movable/screen/screentip/proc/refresh_hover() + update_fallback() + var/atom/target = hovered_atom_ref?.resolve() + if(target && hud?.mymob?.client) + target.on_mouse_enter(hud.mymob.client) + else + clear_hover() + +/// Reused HUDs must not retain a hover from the previous connection. +/atom/movable/screen/screentip/proc/on_connection_changed(datum/source) + SIGNAL_HANDLER + update_fallback() + clear_hover() + +/atom/movable/screen/screentip/proc/update_fallback() + fallback_maptext = hud?.screentips_enabled == SCREENTIP_PREFERENCE_DISABLED ? "" : get_fallback_maptext() + if(!showing_hover) + show_fallback() + +/atom/movable/screen/screentip/proc/show_fallback() + maptext = hud?.screentips_enabled == SCREENTIP_PREFERENCE_DISABLED ? "" : fallback_maptext + maptext_y = 10 + +/// Empty or suppressed hover text gives the fallback its turn. +/atom/movable/screen/screentip/proc/set_hover_text(new_maptext, text_y = 10) + showing_hover = length(new_maptext) > 0 + if(showing_hover) + maptext = new_maptext + maptext_y = text_y + else + show_fallback() + +/// An exit from an older target must not clear a more recent hover. +/atom/movable/screen/screentip/proc/clear_hover(atom/target) + if(target && !IS_WEAKREF_OF(target, hovered_atom_ref)) + return + hovered_atom_ref = null + hover_version++ + set_hover_text("") + +/// Starts a hover and returns the version to use for asynchronous text measurement. +/atom/movable/screen/screentip/proc/begin_hover(atom/target) + hovered_atom_ref = WEAKREF(target) + return ++hover_version + +/atom/movable/screen/screentip/process(seconds_per_tick) + if(!hud?.mymob?.client) + return + if(hovered_atom_ref && !hovered_atom_ref.resolve()) + clear_hover() + update_fallback() + +/atom/movable/screen/screentip/Destroy() + STOP_PROCESSING(SSprocessing, src) + hovered_atom_ref = null + return ..() diff --git a/voidcrew/edits/actions/charge_lifecycle.dm b/voidcrew/edits/actions/charge_lifecycle.dm new file mode 100644 index 00000000000..d0ddc2e8b1c --- /dev/null +++ b/voidcrew/edits/actions/charge_lifecycle.dm @@ -0,0 +1,41 @@ +// Voidcrew - cleanup is idempotent, including loop deletion during body removal. +/datum/action/cooldown/mob_cooldown/charge/proc/finish_charge(atom/movable/charger, notify_owner = TRUE) + if(!charger || !(charger in charging)) + return + charging -= charger + UnregisterSignal(charger, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DEATH)) + if(charger != owner) + UnregisterSignal(charger, COMSIG_QDELETING) + var/datum/move_loop/charge_loop = charge_loops[charger] + charge_loops -= charger + if(charge_loop) + UnregisterSignal(charge_loop, list(COMSIG_MOVELOOP_PREPROCESS_CHECK, COMSIG_MOVELOOP_POSTPROCESS, COMSIG_QDELETING)) + if(!QDELETED(charge_loop)) + qdel(charge_loop) + actively_moving = FALSE + if(notify_owner && !QDELETED(owner)) + SEND_SIGNAL(owner, COMSIG_FINISHED_CHARGE) + +/datum/action/cooldown/mob_cooldown/charge/proc/restore_charge_actions() + charge_activator = null + for(var/datum/action/cooldown/ability as anything in charge_disabled_actions) + if(!QDELETED(ability)) + ability.enable() + charge_disabled_actions.Cut() + // A cancelled wind-up must not leave the inherited melee lock on its new owner. + next_melee_use_time = min(next_melee_use_time, world.time) + +/datum/action/cooldown/mob_cooldown/charge/proc/stop_charges() + for(var/atom/movable/charger as anything in charging.Copy()) + finish_charge(charger, notify_owner = FALSE) + +/datum/action/cooldown/mob_cooldown/charge/Remove(mob/removed_from) + stop_charges() + restore_charge_actions() + return ..() + +// Voidcrew - removal can happen before a moving body's packet is deleted. +/datum/action/cooldown/mob_cooldown/charge/Destroy() + stop_charges() + restore_charge_actions() + return ..() diff --git a/voidcrew/edits/atmospherics/pipeline_cleanup.dm b/voidcrew/edits/atmospherics/pipeline_cleanup.dm new file mode 100644 index 00000000000..dcc30feb7c8 --- /dev/null +++ b/voidcrew/edits/atmospherics/pipeline_cleanup.dm @@ -0,0 +1,17 @@ +/** + * Voidcrew: TRUE if anything real is still attached to this pipeline. + * + * Not the same question as `length(members)`. When a machine is hard deleted its entries + * in these lists are nulled in place rather than removed, so a pipeline that has lost + * everything still reads as length 1 with a null inside. `as anything` is deliberate for + * exactly that reason - a typed loop would silently filter the nulls out and hide the + * distinction we are trying to measure. + */ +/datum/pipeline/proc/has_live_members() + for(var/obj/machinery/atmospherics/member as anything in members) + if(!isnull(member) && !QDELETED(member)) + return TRUE + for(var/obj/machinery/atmospherics/machine as anything in other_atmos_machines) + if(!isnull(machine) && !QDELETED(machine)) + return TRUE + return FALSE diff --git a/voidcrew/edits/components/alarm_region.dm b/voidcrew/edits/components/alarm_region.dm new file mode 100644 index 00000000000..b54c4a00bd2 --- /dev/null +++ b/voidcrew/edits/components/alarm_region.dm @@ -0,0 +1,5 @@ +/datum/alarm_listener + /// Voidcrew: weakref to the atom whose map region scopes a z-scoped + /// listener, or null for "z granularity only" (the upstream behaviour). Set by + /// /datum/station_alert/New(); see the comment there. + var/datum/weakref/region_anchor_ref diff --git a/voidcrew/edits/components/overlay_lighting_holder.dm b/voidcrew/edits/components/overlay_lighting_holder.dm new file mode 100644 index 00000000000..0059a7d4cd2 --- /dev/null +++ b/voidcrew/edits/components/overlay_lighting_holder.dm @@ -0,0 +1,10 @@ +/** + * Re-runs the holder check from outside the component. + * + * We only re-check the holder when our own parent moves, so a light sitting in someone's + * pocket keeps whatever holder it resolved to when it was last moved. If that mob then + * leaves a container the light was never told about it, and stays dark. Anything that + * dumps a mob out of itself should poke this - see [/atom/movable/proc/recheck_contained_lights]. + */ +/datum/component/overlay_lighting/proc/recheck_holder() + check_holder() diff --git a/voidcrew/edits/components/shuttle_cling_lifecycle.dm b/voidcrew/edits/components/shuttle_cling_lifecycle.dm new file mode 100644 index 00000000000..823327f170a --- /dev/null +++ b/voidcrew/edits/components/shuttle_cling_lifecycle.dm @@ -0,0 +1,20 @@ +/datum/component/shuttle_cling/RegisterWithParent() + . = ..() + // Drift may immediately move the parent off transit and delete this component. + // Start it only after _JoinParent(), so removal can safely unregister us. + ADD_TRAIT(parent, TRAIT_HYPERSPACED, REF(src)) + + RegisterSignals(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_UNBUCKLE, COMSIG_ATOM_NO_LONGER_PULLED), PROC_REF(update_state)) + RegisterSignal(parent, SIGNAL_REMOVETRAIT(TRAIT_FREE_HYPERSPACE_MOVEMENT), PROC_REF(initialize_loop)) + RegisterSignal(parent, SIGNAL_ADDTRAIT(TRAIT_FREE_HYPERSPACE_MOVEMENT), PROC_REF(clear_loop)) + + //Items have this cool thing where they're first put on the floor if you grab them from storage, and then into your hand, which isn't caught by movement signals that well + if(isitem(parent)) + RegisterSignal(parent, COMSIG_ITEM_PICKUP, PROC_REF(do_remove)) + + if(!HAS_TRAIT(parent, TRAIT_FREE_HYPERSPACE_MOVEMENT)) + initialize_loop() + if(QDELETED(src)) + return + + update_state(parent) //otherwise we'll get moved 1 tile before we can correct ourselves, which isnt super bad but just looks jank diff --git a/voidcrew/edits/components/spawner_lifecycle.dm b/voidcrew/edits/components/spawner_lifecycle.dm new file mode 100644 index 00000000000..0cce434ce16 --- /dev/null +++ b/voidcrew/edits/components/spawner_lifecycle.dm @@ -0,0 +1,21 @@ +/datum/component/spawner + // Voidcrew: cached map-tenant footprint for the presence gate in + // try_spawn_mob(). Resolved lazily on the first tick that has anyone on our z-level and + // re-resolved if the parent ever moves (structures do not, but components ride mobs and + // items too). Null means "this level is not shared", which is the common case and the + // one that keeps the plain z-level gate. + var/datum/map_footprint/cached_footprint + /// The turf cached_footprint was resolved from, so a moved parent invalidates it. + var/turf/cached_footprint_turf + +// Voidcrew: break the parent <-> spawn_callback reference cycle. +// /obj/structure/spawner passes spawn_callback = CALLBACK(src, PROC_REF(on_mob_spawn)), +// and the callback datum's obj var keeps the parent alive: parent -> components -> +// this component -> spawn_callback -> parent never soft-GCs, so every component-based +// spawner hard-deletes - a multi-minute reference search each under REFERENCE_TRACKING. +/datum/component/spawner/Destroy() + spawn_callback = null + spawned_things = null + cached_footprint = null + cached_footprint_turf = null + return ..() diff --git a/voidcrew/edits/components/tether_pulling.dm b/voidcrew/edits/components/tether_pulling.dm new file mode 100644 index 00000000000..d216ee15d3b --- /dev/null +++ b/voidcrew/edits/components/tether_pulling.dm @@ -0,0 +1,3 @@ +/datum/component/tether + /// Prevents infinite recursion when pulling the anchor + var/currently_pulling = FALSE diff --git a/voidcrew/edits/elements/decal_collection.dm b/voidcrew/edits/elements/decal_collection.dm new file mode 100644 index 00000000000..9c634adc40f --- /dev/null +++ b/voidcrew/edits/elements/decal_collection.dm @@ -0,0 +1,4 @@ +/datum/element/decal/proc/collect_decals(atom/source, list/decals) + SIGNAL_HANDLER + + decals += src diff --git a/voidcrew/edits/error_handler/cache_retention.dm b/voidcrew/edits/error_handler/cache_retention.dm new file mode 100644 index 00000000000..b6d62351dfc --- /dev/null +++ b/voidcrew/edits/error_handler/cache_retention.dm @@ -0,0 +1,5 @@ +/datum/error_viewer/error_source + /// Voidcrew: every runtime this source has produced, retained or not. + var/total_errors = 0 + /// Voidcrew: how many of those were counted but not kept as a full entry. + var/dropped_errors = 0 diff --git a/voidcrew/edits/error_handler/runtime_state.dm b/voidcrew/edits/error_handler/runtime_state.dm new file mode 100644 index 00000000000..fcd8946ced2 --- /dev/null +++ b/voidcrew/edits/error_handler/runtime_state.dm @@ -0,0 +1,22 @@ +/* + * Voidcrew - runtime flood breaker state. + * + * Plain numbers on purpose. The failure these guard against (round-7, 2026-08-16) is one + * where EVERY list operation in the world starts throwing "bad list" - a boot-time, + * never-mutated list like the config subsystem's entries_by_type failed a plain read, + * as did client keybinding caches, SSgarbage's queues and this handler's own static + * error_last_seen. Anything here that touched a list or a config entry would throw on the + * way to the breaker and hand control back to BYOND's built-in handler, which is what + * actually wrote 337 MB of dd.log in 46 seconds. GLOB var reads are a global slot lookup + * and kept working throughout (GLOB.total_runtimes counted the whole flood), so the + * breaker is built out of those and nothing else. + */ +/// world.time-derived index of the flood window we are currently counting in. +GLOBAL_VAR_INIT(error_flood_window, 0) +/// Runtimes handled so far in this window. +GLOBAL_VAR_INIT(error_flood_count, 0) +/// Runtimes dropped by the breaker in this window. +GLOBAL_VAR_INIT(error_flood_suppressed, 0) +/// While world.time is below this, world/Error emits one flat line per runtime and does +/// nothing else - set when the handler itself threw. See the catch in world/Error. +GLOBAL_VAR_INIT(error_handler_degraded_until, 0) diff --git a/voidcrew/edits/mapgen/cave_generation_report.dm b/voidcrew/edits/mapgen/cave_generation_report.dm new file mode 100644 index 00000000000..c9505b07349 --- /dev/null +++ b/voidcrew/edits/mapgen/cave_generation_report.dm @@ -0,0 +1,16 @@ +/** + * Voidcrew: reports how long a generation pass took. + * + * Upstream only ever runs these generators at mapload, so shouting the timings at + * `world` reached nobody but the lobby. Here they also run MID-ROUND (asteroid + * fields, planet builds, mapgen-bearing encounters), so every player on every ship + * got a bold "Asteroid Field Generator terrain generation finished in 4.2s!" each + * time somebody, anybody, docked a rock field. Keep the lobby behaviour as-is; + * once the round is running it is admin-only. The log line is unconditional. + */ +/datum/map_generator/cave_generator/proc/announce_generation_time(message) + if(SSticker?.HasRoundStarted()) + to_chat(GLOB.admins, span_boldannounce("[message]"), MESSAGE_TYPE_DEBUG) + else + to_chat(world, span_boldannounce("[message]"), MESSAGE_TYPE_DEBUG) + log_world(message) diff --git a/voidcrew/edits/mapping/reservation_bounds.dm b/voidcrew/edits/mapping/reservation_bounds.dm new file mode 100644 index 00000000000..0c472269ec7 --- /dev/null +++ b/voidcrew/edits/mapping/reservation_bounds.dm @@ -0,0 +1,17 @@ +/// Returns TRUE if the given turf falls inside this reservation's bounds. +/// Cheap bounds check against the per-z corners rather than a search of +/// reserved_turfs, which can run to thousands of entries. +/datum/turf_reservation/proc/contains_turf(turf/checked) + if(isnull(checked)) + return FALSE + + for(var/z_idx in 1 to length(bottom_left_turfs)) + var/turf/bottom_left = bottom_left_turfs[z_idx] + var/turf/top_right = top_right_turfs[z_idx] + if(checked.z != bottom_left.z) + continue + + return (checked.x >= bottom_left.x && checked.x <= top_right.x) \ + && (checked.y >= bottom_left.y && checked.y <= top_right.y) + + return FALSE diff --git a/voidcrew/edits/subsystem/air_cleanup.dm b/voidcrew/edits/subsystem/air_cleanup.dm new file mode 100644 index 00000000000..196898b0c78 --- /dev/null +++ b/voidcrew/edits/subsystem/air_cleanup.dm @@ -0,0 +1,98 @@ +/datum/controller/subsystem/air + /// Voidcrew: pipelines that lost their last member to a pipe steal in + /// expand_pipeline() while they were still flagged `building`. That call site cannot + /// qdel one on the spot - /datum/pipeline/Destroy() edits expansion_queue, which is the + /// list that drain is walking - so the husk is parked here and reaped on a later fire, + /// once `building` has cleared and it is provably still empty. Without this a + /// stacked-pipe map (every voidcrew hull has some) leaks one member-less pipeline into + /// SSair.networks per site build, processed every tick for the rest of the round. + var/list/datum/pipeline/pipeline_husks = list() + /// Voidcrew: how many consecutive orphan sweeps a pipeline has to be found + /// empty on before it is reaped. build_pipeline() legitimately leaves a pipeline with + /// no members for the window between `new /datum/pipeline` and its queued expansion, + /// so one strike is not proof of a leak - two separate sweeps is. + var/orphan_pipeline_strikes = 2 + /// Voidcrew: world.time the next orphan-pipeline sweep may run. The sweep is + /// O(networks * members) and nothing it catches is urgent, so it is rate limited. + var/next_orphan_sweep = 0 + /// Voidcrew: how long between orphan-pipeline sweeps. Short on purpose: two + /// strikes at this interval is how long an orphan can survive, and the churn soak + /// samples 20 seconds after a teardown. At 5 seconds an orphan made during teardown is + /// always gone before the sample, so `pipelines_orphan` reads a real state rather than + /// whatever happened to be in flight. Sweeping ~70 networks costs nothing. + var/orphan_sweep_interval = 5 SECONDS + /// Voidcrew: running total of pipelines the orphan sweep has reaped, for the + /// churn-soak harness and for `SSair` debug output. + var/orphan_pipelines_reaped = 0 + +/** + * Voidcrew: reaps member-less pipelines that never went through the husk list. + * + * `reap_pipeline_husks()` only ever sees pipelines parked by the pipe-steal branch of + * `expand_pipeline()`. The other way a pipeline ends up empty in `SSair.networks` is a + * machine that was already dying when something queued it for a rebuild: `rebuild_pipes()` + * mints a fresh `/datum/pipeline` for it, the machine's `Destroy()` has already run its + * `QDEL_NULL(parent)`, and so nothing is ever going to delete that pipeline again. It sits + * in `networks` being processed every fire for the rest of the round, and it holds a hard + * ref to the dead machine while it is at it. The source guards below stop new ones being + * made; this sweep clears any that still get through. + * + * Two details this has to get right: + * * `length(members)` is not the test. A hard-deleted machine leaves a null entry in the + * list rather than shortening it, so a leaked pipeline reads as `members = list(null)` - + * length 1, live members 0. `has_live_members()` counts what is actually there. + * * `/datum/pipeline/Destroy()` edits `networks`, `expansion_queue` and `pipeline_husks`. + * So: walk a copy, collect, and qdel only after the walk is over - and run outside the + * expansion drain, the same placement `reap_pipeline_husks()` already uses. + */ +/datum/controller/subsystem/air/proc/reap_orphan_pipelines() + if(world.time < next_orphan_sweep) + return + next_orphan_sweep = world.time + orphan_sweep_interval + var/list/datum/pipeline/doomed = list() + for(var/datum/pipeline/net as anything in networks.Copy()) + if(isnull(net) || QDELETED(net)) + continue + // Still queued for expansion - it is allowed to be empty and may pick members up. + if(net.building) + net.orphan_strikes = 0 + continue + if(net.has_live_members()) + net.orphan_strikes = 0 + continue + net.orphan_strikes++ + if(net.orphan_strikes < orphan_pipeline_strikes) + continue + doomed += net + if(!length(doomed)) + return + orphan_pipelines_reaped += length(doomed) + for(var/datum/pipeline/net as anything in doomed) + qdel(net) + +/** + * Voidcrew: deletes the member-less pipelines expand_pipeline() had to park. + * + * Runs before the drain rather than inside it: /datum/pipeline/Destroy() calls + * remove_from_expansion(), which edits the very list expand_pipeline() walks. By the time + * we get here that drain has finished (or has not started), so the edit is safe. + * + * A husk is only deleted once `building` has cleared - while it is set the pipeline is + * still queued for expansion and may legitimately pick members back up. + */ +/datum/controller/subsystem/air/proc/reap_pipeline_husks() + if(!length(pipeline_husks)) + return + for(var/datum/pipeline/husk as anything in pipeline_husks.Copy()) + if(QDELETED(husk)) + pipeline_husks -= husk + continue + if(husk.building) + continue + pipeline_husks -= husk + // Voidcrew: has_live_members() rather than length(). A husk that was holding + // a machine which then hard deleted reads as length 1 with a null inside, and the + // old length test let it walk away as if it were still in use. + if(husk.has_live_members()) + continue + qdel(husk) diff --git a/voidcrew/edits/subsystem/bitrunning_domains.dm b/voidcrew/edits/subsystem/bitrunning_domains.dm new file mode 100644 index 00000000000..36ad2c6d6cc --- /dev/null +++ b/voidcrew/edits/subsystem/bitrunning_domains.dm @@ -0,0 +1,80 @@ +/datum/controller/subsystem/bitrunning + /// Domain key -> weakref of the quantum server currently running it. Domain + /// datums are fleet-wide singletons and a fleet can have a server on every + /// ship, so only one holder at a time is allowed per key. + var/list/domains_in_use = list() + +/// Frees a domain key, provided the given server is the one holding it. +/datum/controller/subsystem/bitrunning/proc/release_domain(key, obj/machinery/quantum_server/server) + if(isnull(key)) + return + + var/obj/machinery/quantum_server/holder = get_domain_holder(key) + if(holder && holder != server) + return + + domains_in_use -= key + +/** + * TRUE if the given turf sits inside a virtual domain that is currently loaded. + * + * Upstream contains a domain purely through area flags - LOCAL_TELEPORT to stop + * teleports crossing out, allow_shuttle_docking to stop shuttles landing. That only + * holds for tiles the template actually painted an area onto. A reservation's floor + * is whatever the z-level was created as, which is world.area: the global + * /area/space instance, which has no LOCAL_TELEPORT and DOES whitelist docking. Every + * /area/template_noop tile in a domain map, and every tile of the reservation the + * template doesn't cover, is one of those. Build a quantum pad or a shuttle frame on + * one and the area checks wave it straight through, loot and all. + * + * So anything asking "may this cross the VR boundary" has to ask about the + * reservation, not the area. + */ +/datum/controller/subsystem/bitrunning/proc/is_domain_turf(turf/checked) + if(isnull(checked) || !length(domains_in_use)) + return FALSE + + // Domains only ever live in a turf reservation (see /datum/lazy_template/lazy_load). + if(!is_reserved_level(checked.z)) + return FALSE + + // Deliberately not get_domain_holder(): that prunes dead keys as it goes, and + // callers include check_teleport_valid(), which is SHOULD_BE_PURE. + for(var/key in domains_in_use) + var/datum/weakref/holder_ref = domains_in_use[key] + var/obj/machinery/quantum_server/holder = holder_ref?.resolve() + var/datum/lazy_template/virtual_domain/domain = holder?.generated_domain + if(isnull(domain)) + continue + + for(var/datum/turf_reservation/reservation as anything in domain.reservations) + if(reservation.contains_turf(checked)) + return TRUE + + return FALSE + +/// Marks a domain key as running on the given server. FALSE if another server holds it. +/datum/controller/subsystem/bitrunning/proc/claim_domain(key, obj/machinery/quantum_server/server) + if(isnull(key) || isnull(server)) + return FALSE + + var/obj/machinery/quantum_server/holder = get_domain_holder(key) + if(holder && holder != server) + return FALSE + + domains_in_use[key] = WEAKREF(server) + return TRUE + +/// The quantum server currently running the given domain key, if any. Clears the +/// entry if its holder has since been destroyed. +/datum/controller/subsystem/bitrunning/proc/get_domain_holder(key) + var/datum/weakref/holder_ref = domains_in_use[key] + if(isnull(holder_ref)) + return null + + var/obj/machinery/quantum_server/holder = holder_ref.resolve() + if(isnull(holder)) + domains_in_use -= key + return null + + return holder diff --git a/voidcrew/edits/subsystem/mapping_cleanup.dm b/voidcrew/edits/subsystem/mapping_cleanup.dm new file mode 100644 index 00000000000..198eae429e6 --- /dev/null +++ b/voidcrew/edits/subsystem/mapping_cleanup.dm @@ -0,0 +1,111 @@ +/datum/controller/subsystem/mapping + // Voidcrew: one-shot latch for the dead-area recovery in fire() below. + /// Whether we have already reported a reservation turf found sitting in a destroyed area. + var/warned_about_dead_reservation_area = FALSE + // Voidcrew: released reservation turfs whose starlight has been switched + /// off and which still have to be taken out of GLOB.starlight. Assoc turf -> TRUE so the + /// compaction below is a membership test rather than a search. See release_reservation_starlight(). + var/list/starlight_release_queue + // Voidcrew: world.time the next used_turfs orphan sweep may run at. + /// Rate limit for reconcile_used_turfs(), which walks all of used_turfs. + var/next_used_turf_reconcile = 0 + +/** + * Voidcrew: takes the turfs darkened by the reservation drain out of + * GLOB.starlight, in one linear pass over the list rather than one linear scan per turf. + * + * `GLOB.starlight -= turf` inside the drain loop is the obvious spelling and it is + * quadratic: the loop runs once per released turf and the list can hold as many entries + * again, which on a large release is a multi-second world freeze. Rebuilding the list once + * against an assoc membership set is O(len(GLOB.starlight)) no matter how many turfs were + * released, and the drain only pays it once per REBUILD_STARLIGHT_AFTER turfs plus once at + * the end of each fire. + * + * Leaving the entries in place instead is not an option: enable_starlight() only appends + * when `!light_on`, so a member whose light we switched off would be appended a SECOND + * time the next time that ground is lit, and BYOND's Remove() only ever drops one of them. + * That trades a bounded datum leak for an unbounded list leak. + * + * A turf that was re-lit between being queued and being flushed is kept: the queue is a + * request to drop the entry, `light_on` is the ground truth about whether it still belongs. + */ +/// Turfs the reservation drain may darken before the GLOB.starlight compaction is worth a pass. +#define REBUILD_STARLIGHT_AFTER 1000 + +/datum/controller/subsystem/mapping/proc/release_reservation_starlight(force = FALSE) + var/list/released = starlight_release_queue + if(!length(released)) + return + if(!force && length(released) < REBUILD_STARLIGHT_AFTER) + return + starlight_release_queue = null + + var/list/kept = list() + for(var/turf/open/space/lit as anything in GLOB.starlight) + // `as anything`, so this also drops the nulls a hard delete leaves in place and + // anything a raw turf swap retargeted into something that is no longer space. + if(isnull(lit)) + continue + if(released[lit] && !lit.light_on) + continue + kept += lit + GLOB.starlight = kept + +#undef REBUILD_STARLIGHT_AFTER + +// Voidcrew: how often the used_turfs orphan sweep below may run. +#define USED_TURF_RECONCILE_INTERVAL (2 MINUTES) +// Voidcrew: how many orphans one sweep may hand back, so a pathological +// backlog is drained over several passes instead of in one unbounded release. +#define USED_TURF_RECONCILE_MAX_RECLAIM 5000 + +/** + * Voidcrew: self-healing sweep for SSmapping.used_turfs. + * + * used_turfs maps turf -> the /datum/turf_reservation that claimed it, and the only thing + * that ever removes an entry is that reservation's Release(). An entry whose reservation + * is gone is therefore ground that is claimed forever: it keeps RESERVATION_TURF, never + * goes back into unused_turfs, and _reserve_area() will never hand it out again. Enough of + * those and request_turf_block_reservation() cannot fit a block on any existing reservation + * z-level and mints a permanent new 255x255 one (~65k turfs, ~48 MB) per shortfall. + * + * Release() is the fix for the known way that happened (see the note there); this is the + * net for any path that is still missed, and it also cleans up entries stranded before this + * code existed. It is deliberately narrow: an entry is only dropped when nothing live owns + * it - a null value (the reservation hard deleted, which nulls the ref in place) or a + * QDELETED one. A reservation that still exists is never touched, so this cannot race a + * live claim, and turfs claimed but not yet published are impossible because _reserve_area() + * writes used_turfs[T] and the datum ref in the same unyielding pass. + * + * O(length(used_turfs)) with no sleeps, capped and rate limited. + */ +/datum/controller/subsystem/mapping/proc/reconcile_used_turfs() + if(!initialized || clearing_reserved_turfs) + return + if(world.time < next_used_turf_reconcile) + return + next_used_turf_reconcile = world.time + USED_TURF_RECONCILE_INTERVAL + + var/list/orphans = list() + // `as anything` - a hard delete can null a key in place, and those are skipped rather + // than reclaimed: there is no turf left to hand back. + for(var/turf/claimed as anything in used_turfs) + if(isnull(claimed)) + continue + var/datum/turf_reservation/holder = used_turfs[claimed] + if(!QDELETED(holder)) + continue + orphans += claimed + if(length(orphans) >= USED_TURF_RECONCILE_MAX_RECLAIM) + break + + if(!length(orphans)) + return + + used_turfs -= orphans + log_mapping("SSmapping: reconciled [length(orphans)] used_turfs entr[length(orphans) == 1 ? "y" : "ies"] whose \ + reservation no longer exists - the ground was claimed with nothing left to release it. Handing it back.") + reserve_turfs(orphans) + +#undef USED_TURF_RECONCILE_INTERVAL +#undef USED_TURF_RECONCILE_MAX_RECLAIM diff --git a/voidcrew/edits/subsystem/weather_sites.dm b/voidcrew/edits/subsystem/weather_sites.dm new file mode 100644 index 00000000000..d393e17791d --- /dev/null +++ b/voidcrew/edits/subsystem/weather_sites.dm @@ -0,0 +1,247 @@ +/datum/controller/subsystem/weather + /// Snapshot of active weather being processed in the current fire. The event at + /// the end remains there until all of its tasks finish, including across resumes. + var/list/currentrun = list() + // The upstream per-z scheduler maps are replaced by + // the /datum/weather_site registry below, so several places can share a z-level and each + // keep its own climate, storm and cooldown. See voidcrew/datums/weather_site.dm. + /// Every registered weather site, in registration order. + var/list/datum/weather_site/weather_sites = list() + /// "[z]" -> list of /datum/weather_site on that level, for turf and level lookups. + var/list/weather_sites_by_zlevel = list() + /// Sites allowed to roll a new random storm on the next fire. + var/list/datum/weather_site/eligible_sites = list() + /// z ("[z]") -> list of living mobs, rebuilt at most once per fire cycle so several + /// concurrent storms share one scan of the global mob list instead of one scan each + var/list/mobs_by_z_cache + /// The times_fired value mobs_by_z_cache was built on + var/mobs_by_z_cache_fire = -1 + + +/// Returns TRUE while any weather stage still occupies a z-level. +/// Voidcrew: no longer gates random scheduling - fire() asks the site whether ITS storm +/// is still running, so two sites on one level can storm at once. Kept for outside callers. +/datum/controller/subsystem/weather/proc/is_weather_active_on_z(z) + for(var/datum/weather/weather_event as anything in processing) + if(weather_event.stage != END_STAGE && islist(weather_event.impacted_z_levels) && (z in weather_event.impacted_z_levels)) + return TRUE + return FALSE + +/// Cooldown expiry: the site may roll another storm on the next fire. +/datum/controller/subsystem/weather/proc/make_site_eligible(datum/weather_site/site) + if(QDELETED(site) || !(site in weather_sites)) + return + site.next_hit_timer = null + site.next_hit_time = 0 + // Only let go of a storm that has actually finished. Blanking this while the storm was + // still running orphaned it - it kept processing and kept holding every area instance in + // its impacted_areas with nothing left pointing at it - and let the site roll a second, + // concurrent storm on top of it. A storm that ends normally clears this itself in end(), + // so by the time the cooldown lands it is usually already null; fire() re-queues a site + // whose storm is still winding down rather than starting another. + if(!site.has_active_weather()) + if(site.active_weather?.weather_site == site) + site.active_weather.weather_site = null + site.active_weather = null + if(length(site.weather_types)) + eligible_sites |= site + +/** + * Replaces the random-weather trait on a recycled dynamic z-level. + * + * Voidcrew: kept as a thin wrapper over the site registry for callers that still think + * in "one climate per level" terms (map zone teardown, flat overmap encounters, mapping + * helpers). Anything that wants more than one climate on a level registers sites directly. + */ +/datum/controller/subsystem/weather/proc/set_z_level_weather_trait(datum/space_level/level, new_weather_trait) + var/z = level.z_value + unregister_z_level(z) + + for(var/weather_trait in random_weather_traits()) + level.traits -= weather_trait + var/list/trait_levels = SSmapping.z_trait_levels[weather_trait] + if(trait_levels) + trait_levels -= z + + if(!new_weather_trait) + return + + level.traits[new_weather_trait] = TRUE + var/list/new_trait_levels = SSmapping.z_trait_levels[new_weather_trait] + if(!new_trait_levels) + new_trait_levels = list() + SSmapping.z_trait_levels[new_weather_trait] = new_trait_levels + new_trait_levels |= list(z) + update_z_level(level) + +/// Stops random weather scheduling for a z-level and ends every storm scheduled on it. +/datum/controller/subsystem/weather/proc/unregister_z_level(z) + // Voidcrew - the level is being torn down or recycled, so every + // site on it goes, not just the level-wide one. Copy(): unregister mutates the index list. + var/list/z_sites = weather_sites_by_zlevel["[z]"] + if(!length(z_sites)) + return + for(var/datum/weather_site/site as anything in z_sites.Copy()) + unregister_weather_site(site) + +/** + * Registers a whole-level site whose climate comes from an explicit trait set rather than + * from the level's trait dict. + * + * Planets use this: their weather has to be describable without the level's trait dict + * being the single source of truth, since a level may eventually hold more than one of them. + */ +/datum/controller/subsystem/weather/proc/register_weather_site_for_level(datum/space_level/level, list/weather_traits, zone_band, site_id) + if(isnull(level)) + return null + var/list/possible_weather = weather_weights_for_traits(weather_traits) + if(!length(possible_weather)) + return null + return register_level_weather_site(level.z_value, possible_weather, zone_band, site_id) + +/** + * Registers (or refreshes) the site covering a whole z-level. + * + * Refreshing keeps a running storm and its cooldown intact and only swaps the weight + * table, which is what update_z_level() has always done. + */ +/datum/controller/subsystem/weather/proc/register_level_weather_site(z, list/possible_weather, zone_band, site_id) + var/datum/weather_site/site = get_level_weather_site(z) + if(site) + site.set_weather_types(possible_weather) + // Only an explicit value overwrites; a bare refresh must not throw away the zone band + // the site was registered with. + if(!isnull(zone_band)) + site.zone_band = zone_band + if(!(site in eligible_sites) && !site.next_hit_timer && !site.has_active_weather() && length(possible_weather)) + eligible_sites |= site + return site + site = new /datum/weather_site(site_id || "level-[z]", z, possible_weather, zone_band) + return register_weather_site(site) + +/// Time until the soonest scheduled storm anywhere on a z-level, or null if nothing is armed. +/datum/controller/subsystem/weather/proc/next_hit_timeleft_for_z(z) + var/shortest = null + for(var/datum/weather_site/site as anything in weather_sites_by_zlevel["[z]"]) + if(!site.next_hit_timer) + continue + var/remaining = timeleft(site.next_hit_timer) + if(isnull(remaining)) + continue + if(isnull(shortest) || remaining < shortest) + shortest = remaining + return shortest + +/// Time until the next scheduled storm where this turf is standing, or null if nothing is armed. +/datum/controller/subsystem/weather/proc/next_hit_timeleft_for_turf(turf/checked) + var/datum/weather_site/site = get_weather_site_for_turf(checked) + if(!site?.next_hit_timer) + return null + return timeleft(site.next_hit_timer) + +/// The site that owns a turf, or null. +/datum/controller/subsystem/weather/proc/get_weather_site_for_turf(turf/checked) + if(isnull(checked)) + return null + return get_weather_site_for_coords(checked.x, checked.y, checked.z) + +/** + * The site that owns a set of coordinates. + * + * A footprinted site wins over the level-wide one, so a packed planet's own climate beats + * whatever covers the rest of the level. + */ +/datum/controller/subsystem/weather/proc/get_weather_site_for_coords(x, y, z) + var/list/z_sites = weather_sites_by_zlevel["[z]"] + if(!length(z_sites)) + return null + var/datum/weather_site/level_fallback + for(var/datum/weather_site/site as anything in z_sites) + if(!site.has_footprint()) + if(isnull(level_fallback)) + level_fallback = site + continue + if(site.contains_coords(x, y, z)) + return site + return level_fallback + +/// Every site registered on a z-level, footprinted or not. +/datum/controller/subsystem/weather/proc/get_weather_sites_on_z(z) + return weather_sites_by_zlevel["[z]"] || list() + +/// The site covering a whole z-level, i.e. the one the z-keyed entry points address. Null if none. +/datum/controller/subsystem/weather/proc/get_level_weather_site(z) + for(var/datum/weather_site/site as anything in weather_sites_by_zlevel["[z]"]) + if(!site.has_footprint()) + return site + return null + +/** + * Removes one site from the scheduler, ending its storm and cancelling its cooldown. + * + * This is the per-site form of the old unregister_z_level(); nothing else on the site's + * z-level is disturbed. + */ +/datum/controller/subsystem/weather/proc/unregister_weather_site(datum/weather_site/site) + if(!istype(site)) + return + weather_sites -= site + eligible_sites -= site + var/z_key = "[site.z_value]" + var/list/z_sites = weather_sites_by_zlevel[z_key] + if(z_sites) + z_sites -= site + if(!length(z_sites)) + weather_sites_by_zlevel -= z_key + site.clear_next_hit() + site.end_active_weather() + +/// Adds a site to the scheduler. A site with weather in its table is eligible immediately. +/datum/controller/subsystem/weather/proc/register_weather_site(datum/weather_site/site) + if(!istype(site) || (site in weather_sites)) + return site + weather_sites += site + var/z_key = "[site.z_value]" + var/list/z_sites = weather_sites_by_zlevel[z_key] + if(!z_sites) + z_sites = list() + weather_sites_by_zlevel[z_key] = z_sites + z_sites |= site + if(length(site.weather_types)) + eligible_sites |= site + return site + +/// Every z-level trait that some weather type can be rolled from. +/datum/controller/subsystem/weather/proc/random_weather_traits() + var/list/traits = list() + for(var/datum/weather/weather as anything in subtypesof(/datum/weather)) + if(!initial(weather.probability)) + continue + var/target_trait = initial(weather.target_trait) + if(target_trait) + traits |= list(target_trait) + return traits + +/** + * Builds the random-weather weight table (weather typepath -> probability) implied by a set + * of z-level traits. + * + * This is the calculation Initialize() and update_z_level() used to each write out inline. + * Registration paths that do not want to route a climate through the level's trait dict at + * all (planets, which need to describe their own weather without fighting a co-tenant over + * the level) call this with a trait list they assembled themselves. + * + * `level_traits` is an assoc list, trait -> value, i.e. the same shape as /datum/space_level.traits. + */ +/datum/controller/subsystem/weather/proc/weather_weights_for_traits(list/level_traits) + var/list/possible_weather = list() + if(!length(level_traits)) + return possible_weather + for(var/datum/weather/weather as anything in subtypesof(/datum/weather)) + var/probability = initial(weather.probability) + if(!probability) + continue + var/target_trait = initial(weather.target_trait) + if(target_trait && level_traits[target_trait]) + possible_weather[weather] = probability + return possible_weather diff --git a/voidcrew/edits/weather/packed_sites.dm b/voidcrew/edits/weather/packed_sites.dm new file mode 100644 index 00000000000..58a3042d37e --- /dev/null +++ b/voidcrew/edits/weather/packed_sites.dm @@ -0,0 +1,45 @@ +/datum/weather + /// If TRUE, weather_act_turf() only tops up open reagent containers (and waters hydroponics trays when + /// the reagent is water) instead of running full reagent exposure + washing on every struck turf. + /// Planet-scale weathers pick hundreds of turfs per second. Full exposure at that rate eats whole ticks. + var/turf_act_containers_only = FALSE + +/datum/weather + // Voidcrew - site scoping. See voidcrew/datums/weather_site.dm + /// The /datum/weather_site that scheduled this storm, if it came from one. + var/datum/weather_site/weather_site + /// Area INSTANCES this storm is confined to. Null means the z-wide get_areas(area_type) sweep. + var/list/scoped_areas + +/datum/weather + /// Assoc mirror of impacted_areas (area = TRUE), for cheap membership checks in the per-mob hot path + var/list/impacted_areas_lookup = list() + +/** + * Voidcrew - diagnostic for issue #196 (a lava planet's ash storm painting + * an ocean planet). Changes nothing about the storm. + * + * get_areas() matches by area TYPE, and every packed planet's surface and caves share + * area_type = /area/overmap_encounter/planetoid - so on a z-level carrying more than one + * map tenant this sweep can only over-reach, and a storm that takes it paints, telegraphs + * and burns on all four planets rather than on the one it belongs to. In a live round + * every planet is packed, so that is the whole of the reported symptom. + * + * Nothing in the tree is supposed to reach here on a shared level: scheduled planet storms + * carry an area-scoped site, and a site-scoped storm with no areas yet is held out of the + * scheduler entirely (SSweather.fire -> awaiting_owned_areas). An audit of every + * run_weather() caller, the site registry lifecycle, and three days of prod admin.log + * found no route that does. So rather than guess at a cause, name the offender in the + * runtime log the next time it happens - the stack trace is the caller. + */ +/datum/weather/proc/log_packed_level_area_sweep() + if(!islist(impacted_z_levels)) + return + for(var/z in impacted_z_levels) + if(!isnum(z) || z < 1 || z > length(SSmapping.z_list)) + continue + var/datum/space_level/level = SSmapping.z_list[z] + if(length(level?.footprints) <= 1) + continue + stack_trace("weather [type] fell back to the z-wide get_areas([area_type]) sweep on packed z[z] ([length(level.footprints)] tenants) - it will impact every tenant on that level. Site: [weather_site?.id || "none"]") + return diff --git a/voidcrew/edits/weather/sand_storm_sound.dm b/voidcrew/edits/weather/sand_storm_sound.dm new file mode 100644 index 00000000000..63f90d2db3e --- /dev/null +++ b/voidcrew/edits/weather/sand_storm_sound.dm @@ -0,0 +1,4 @@ +/datum/weather/sand_storm/end() + GLOB.sand_storm_sounds -= weak_sounds + GLOB.sand_storm_sounds -= strong_sounds + return ..() diff --git a/voidcrew/modules/ship_upgrades/shuttle_manipulator.dm b/voidcrew/modules/ship_upgrades/shuttle_manipulator.dm new file mode 100644 index 00000000000..814a2cb6c21 --- /dev/null +++ b/voidcrew/modules/ship_upgrades/shuttle_manipulator.dm @@ -0,0 +1,102 @@ +/datum/controller/subsystem/shuttle + + //VOID EDIT - Modular ship configuration for shuttle manipulator + /// Pending upgrade module selections (slot_key -> module_id) for shuttle manipulator + var/list/pending_upgrade_selections = list() + /// Pending theme selection (theme_id) for shuttle manipulator + var/pending_theme_id + //END VOID EDIT + +/** + * Build UI data for modular ship configuration in shuttle manipulator + * + * Returns a list with: + * - themes: list of available themes with id, name, desc, is_default, jobs + * - has_themes: boolean if there are themes to choose from + * - slots: list of upgrade slots with their available modules + * - selected_theme: currently selected theme id (from pending_theme_id) + * - selected_upgrades: currently selected modules (from pending_upgrade_selections) + */ +/datum/controller/subsystem/shuttle/proc/build_modular_ui_data(datum/map_template/shuttle/voidcrew/template) + ensure_ship_upgrades_initialized() + + var/list/data = list() + + // Get themes for this ship + var/list/ship_themes = get_themes_for_ship(template.type) + var/list/themes_data = list() + + for(var/theme_id in ship_themes) + var/datum/ship_theme/theme = ship_themes[theme_id] + var/list/theme_info = list() + theme_info["id"] = theme.id + theme_info["name"] = theme.name + theme_info["desc"] = theme.desc + theme_info["is_default"] = theme.is_default + + // Include job slots for preview + if(theme.job_slots) + var/list/jobs = list() + for(var/list/job_data in theme.job_slots) + jobs += list(list( + "name" = job_data["name"], + "slots" = job_data["slots"], + "officer" = job_data["officer"] + )) + theme_info["jobs"] = jobs + + themes_data += list(theme_info) + + data["themes"] = themes_data + data["has_themes"] = length(themes_data) > 0 + + // Determine selected theme - use pending selection or find default + var/effective_theme_id = pending_theme_id + if(!effective_theme_id && length(themes_data)) + var/datum/ship_theme/default_theme = get_default_theme_for_ship(template.type) + if(default_theme) + effective_theme_id = default_theme.id + + data["selected_theme"] = effective_theme_id + + // Get upgrade slots - from theme if selected, otherwise from template + var/list/upgrade_slot_ids = template.upgrade_slot_ids + if(effective_theme_id) + var/datum/ship_theme/selected_theme = ship_themes[effective_theme_id] + if(selected_theme?.upgrade_slot_ids) + upgrade_slot_ids = selected_theme.upgrade_slot_ids + + // Get modules filtered by theme + var/list/all_modules = get_modules_for_ship_theme(template.type, effective_theme_id) + + // Organize modules by slot + var/list/slots_data = list() + for(var/slot_key in upgrade_slot_ids) + var/list/slot_info = list() + slot_info["key"] = slot_key + // Generate display name from slot key (capitalize, replace underscores) + slot_info["display_name"] = capitalize(replacetext(slot_key, "_", " ")) + + var/list/slot_modules = list() + for(var/module_id in all_modules) + var/datum/ship_upgrade_module/module = all_modules[module_id] + if(module.slot != slot_key) + continue + + var/list/module_info = list() + module_info["id"] = module.id + module_info["name"] = module.name + module_info["desc"] = module.desc + module_info["is_default"] = module.is_default + + slot_modules += list(module_info) + + slot_info["modules"] = slot_modules + slots_data += list(slot_info) + + data["slots"] = slots_data + + // Include current pending selections + data["selected_upgrades"] = pending_upgrade_selections.Copy() + + return data diff --git a/voidcrew/modules/trade/bag_rift_protection.dm b/voidcrew/modules/trade/bag_rift_protection.dm new file mode 100644 index 00000000000..7e8c98647c3 --- /dev/null +++ b/voidcrew/modules/trade/bag_rift_protection.dm @@ -0,0 +1,8 @@ +/// The receiving bag can be on the other side of an area boundary from its user. +/datum/storage/bag_of_holding/proc/can_create_rift(mob/user) + var/area/bag_area = get_area(parent) + if(!bag_area || (bag_area.area_flags & NO_BOH) || is_trader_outpost_protected(parent)) + if(user) + to_chat(user, span_warning("Bluespace interference prevents the bags from nesting here.")) + return FALSE + return TRUE From d379a1c90ab41c1f2b6ed257f342bfa3ac7ddc3e Mon Sep 17 00:00:00 2001 From: Jackriip <97582790+Jackriip@users.noreply.github.com> Date: Wed, 30 Sep 2026 04:40:07 -0700 Subject: [PATCH 4/6] Modularize fork helpers and annotate upstream module hooks --- code/_globalvars/logging.dm | 2 +- code/modules/admin/admin_fax_panel.dm | 2 +- code/modules/admin/verbs/adminpm.dm | 2 + code/modules/asset_cache/assets/rcd.dm | 52 +--- code/modules/awaymissions/signpost.dm | 38 +-- code/modules/bitrunning/areas.dm | 14 +- .../modules/bitrunning/server/map_handling.dm | 19 +- .../bitrunning/server/obj_generation.dm | 4 +- .../bitrunning/server/signal_handlers.dm | 2 + code/modules/bitrunning/server/util.dm | 2 + .../bitrunning/util/virtual_megafauna.dm | 2 + .../virtual_domain/domains/ash_drake.dm | 4 +- .../domains/blood_drunk_miner.dm | 4 +- .../virtual_domain/domains/bubblegum.dm | 4 +- .../virtual_domain/domains/colossus.dm | 4 +- .../virtual_domain/domains/hierophant.dm | 4 +- .../virtual_domain/domains/psyker_zombies.dm | 2 +- .../virtual_domain/domains/wendigo.dm | 4 +- code/modules/cargo/exports/large_objects.dm | 15 +- code/modules/cargo/exports/manifest.dm | 6 +- code/modules/cargo/exports/materials.dm | 11 +- code/modules/cargo/exports/sheets.dm | 2 +- code/modules/cargo/materials_market.dm | 58 ++-- code/modules/cargo/order.dm | 31 +- code/modules/cargo/packs/_packs.dm | 36 +-- code/modules/client/preferences.dm | 24 +- code/modules/client/preferences/screentips.dm | 2 +- code/modules/client/preferences_savefile.dm | 4 +- code/modules/client/verbs/ooc.dm | 14 +- code/modules/events/wormholes.dm | 4 +- .../experiment/handlers/experiment_handler.dm | 2 +- .../experiment/physical_experiments.dm | 2 + .../experisci/experiment/types/scanning.dm | 12 +- .../experiment/types/scanning_fish.dm | 8 +- code/modules/fishing/sources/_fish_source.dm | 12 +- .../food_and_drinks/machinery/smartfridge.dm | 6 +- code/modules/jobs/job_types/_job.dm | 2 +- code/modules/jobs/job_types/ai.dm | 2 +- code/modules/jobs/job_types/prisoner.dm | 5 + code/modules/library/bibles.dm | 4 +- code/modules/loadout/loadout_menu.dm | 4 +- code/modules/logging/log_holder.dm | 34 +-- code/modules/lootpanel/_lootpanel.dm | 2 +- code/modules/lootpanel/contents.dm | 3 +- code/modules/mining/aux_base.dm | 2 +- code/modules/mining/fulton.dm | 2 +- .../lavaland/mining_loot/megafauna/legion.dm | 4 +- code/modules/mining/machine_redemption.dm | 2 + code/modules/mining/machine_silo.dm | 6 +- code/modules/mining/ores_coins.dm | 4 +- .../file_system/programs/budgetordering.dm | 30 +- .../file_system/programs/radar.dm | 2 +- .../file_system/programs/secureye.dm | 12 +- .../file_system/programs/sm_monitor.dm | 4 +- code/modules/projectiles/gun.dm | 2 + code/modules/research/designs.dm | 15 +- .../designs/autolathe/security_designs.dm | 6 +- .../research/designs/comp_board_designs.dm | 10 +- .../research/designs/machine_designs.dm | 10 +- code/modules/research/destructive_analyzer.dm | 4 +- .../modules/research/machinery/_production.dm | 2 +- code/modules/research/part_replacer.dm | 1 + .../modules/research/techweb/_techweb_node.dm | 2 + .../research/techweb/nodes/medbay_nodes.dm | 2 +- .../research/techweb/nodes/mining_nodes.dm | 2 +- .../research/techweb/nodes/service_nodes.dm | 2 +- .../security_levels/keycard_authentication.dm | 4 + .../shuttle/mobile_port/mobile_port.dm | 12 +- .../shuttle/mobile_port/shuttle_move.dm | 249 +--------------- .../mobile_port/shuttle_move_callbacks.dm | 34 +-- .../variants/custom/custom_consoles.dm | 1 + code/modules/shuttle/shuttle.dm | 20 +- .../shuttle_consoles/navigation_computer.dm | 74 ++--- .../shuttle/stationary_port/port_types.dm | 3 +- .../stationary_port/stationary_port.dm | 2 +- .../surgery/experimental_dissection.dm | 16 +- code/modules/surgery/healing.dm | 1 + .../organs/internal/heart/heart_anomalock.dm | 2 +- code/modules/surgery/surgery.dm | 2 +- code/modules/surgery/surgery_step.dm | 2 +- code/modules/unit_tests/designs.dm | 2 + code/modules/unit_tests/missing_icons.dm | 4 +- code/modules/unit_tests/modsuit.dm | 16 +- code/modules/unit_tests/operating_table.dm | 40 +-- .../unit_tests/simple_animal_freeze.dm | 4 + code/modules/unit_tests/spell_jaunt.dm | 66 +---- code/modules/unit_tests/spell_shapeshift.dm | 4 + .../modules/vehicles/mecha/mech_fabricator.dm | 46 +-- .../wiremod/components/ntnet/ntnet_receive.dm | 4 + .../wiremod/components/ntnet/ntnet_send.dm | 2 +- .../components/ntnet/ntnet_send_literal.dm | 2 +- .../wiremod/components/utility/nfc_receive.dm | 2 + .../components/utility/nfc_send_literal.dm | 3 +- code/modules/wiremod/core/component.dm | 16 +- .../wiremod/core/integrated_circuit.dm | 12 +- code/modules/wiremod/core/port.dm | 6 +- .../dcs_components/component_add_port.dm | 2 +- tgui/packages/tgui/drag.ts | 8 + tgui/packages/tgui/interfaces/BankMachine.tsx | 15 + .../tgui/interfaces/CameraConsole.tsx | 1 + tgui/packages/tgui/interfaces/ChemHeater.tsx | 1 + .../interfaces/CommunicationsConsole/Main.tsx | 7 + .../interfaces/CommunicationsConsole/types.ts | 1 + .../tgui/interfaces/NtosSkillTracker.jsx | 2 + tgui/packages/tgui/interfaces/OreSilo.tsx | 7 + .../CharacterPreferences/MainPage.tsx | 1 + .../CharacterPreferences/index.tsx | 8 + .../loadout/ItemDisplay.tsx | 2 + .../preferences/features/index.ts | 2 + .../tgui/interfaces/PreferencesMenu/types.ts | 3 + .../tgui/interfaces/ShuttleManipulator.jsx | 244 +-------------- tgui/packages/tgui/interfaces/StripMenu.tsx | 1 + .../interfaces/Techweb/nodes/TechNode.tsx | 2 + tgui/packages/tgui/layouts/Window.tsx | 3 + tgui/packages/tgui/styles/main.scss | 5 + .../components/ModularShipConfig.jsx | 234 +++++++++++++++ voidcrew/edits/machinery/materials_market.dm | 30 +- .../modules/cargo/budget_order_program.dm | 21 ++ voidcrew/modules/cargo/export_values.dm | 19 ++ .../modules/cargo/ship_order_settlement.dm | 58 ++++ voidcrew/modules/circuits/component_hooks.dm | 22 ++ .../metrics/structured_logging_fallback.dm | 22 ++ .../modules/mining/signpost_destinations.dm | 34 +++ .../preferences/character_preview_recovery.dm | 11 + .../modules/research/bitrunning_designs.dm | 19 ++ .../research/experimental_technology_deck.dm | 8 + .../modules/research/fabrication_materials.dm | 36 +++ .../research/fish_experiment_progress.dm | 7 + .../shuttle/construction/rcd_spritesheet.dm | 48 +++ .../modules/shuttle/shuttle_move_helpers.dm | 278 ++++++++++++++++++ .../shuttle/survey/eye_boundary_hook.dm | 13 + .../unit_tests/blood_jaunt_destinations.dm | 65 ++++ .../unit_tests/mod_night_vision_traits.dm | 15 + .../unit_tests/operating_table_movement.dm | 39 +++ 134 files changed, 1404 insertions(+), 1137 deletions(-) create mode 100644 tgui/packages/voidcrew_tgui/components/ModularShipConfig.jsx create mode 100644 voidcrew/modules/cargo/budget_order_program.dm create mode 100644 voidcrew/modules/cargo/export_values.dm create mode 100644 voidcrew/modules/cargo/ship_order_settlement.dm create mode 100644 voidcrew/modules/circuits/component_hooks.dm create mode 100644 voidcrew/modules/metrics/structured_logging_fallback.dm create mode 100644 voidcrew/modules/mining/signpost_destinations.dm create mode 100644 voidcrew/modules/preferences/character_preview_recovery.dm create mode 100644 voidcrew/modules/research/bitrunning_designs.dm create mode 100644 voidcrew/modules/research/experimental_technology_deck.dm create mode 100644 voidcrew/modules/research/fabrication_materials.dm create mode 100644 voidcrew/modules/research/fish_experiment_progress.dm create mode 100644 voidcrew/modules/shuttle/construction/rcd_spritesheet.dm create mode 100644 voidcrew/modules/shuttle/shuttle_move_helpers.dm create mode 100644 voidcrew/modules/shuttle/survey/eye_boundary_hook.dm create mode 100644 voidcrew/modules/unit_tests/blood_jaunt_destinations.dm create mode 100644 voidcrew/modules/unit_tests/mod_night_vision_traits.dm create mode 100644 voidcrew/modules/unit_tests/operating_table_movement.dm diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index 83f144a7860..d0de2a2f51a 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -32,7 +32,7 @@ GLOBAL_PROTECT(##log_var_name);\ // These should be used where the log category cannot easily be a json log file. DECLARE_LOG(config_error_log, DONT_START_LOG) DECLARE_LOG(perf_log, DONT_START_LOG) // Declared here but name is set in time_track subsystem -DECLARE_LOG(worldgen_log, START_LOG) // Planet/ruin/asteroid/ship generation timing, correlated with time dilation - see code/__HELPERS/logging/worldgen.dm +DECLARE_LOG(worldgen_log, START_LOG) // Planet/ruin/asteroid/ship generation timing, correlated with time dilation - see code/__HELPERS/logging/worldgen.dm // VOIDCREW EDIT: metrics records world-generation timing. #ifdef REFERENCE_TRACKING_LOG_APART DECLARE_LOG_NAMED(harddel_log, "harddels", START_LOG) diff --git a/code/modules/admin/admin_fax_panel.dm b/code/modules/admin/admin_fax_panel.dm index d9715606109..11e3a6043df 100644 --- a/code/modules/admin/admin_fax_panel.dm +++ b/code/modules/admin/admin_fax_panel.dm @@ -116,7 +116,7 @@ ADMIN_VERB(fax_panel, R_ADMIN, "Fax Panel", "View and respond to faxes sent to C stamp_class = needed_stamp[3] break - fax_paper.name = "paper, [default_paper_name]" + fax_paper.name = "paper, [default_paper_name]" // VOIDCREW EDIT: paperwork keeps fax titles compatible with the client font. fax_paper.add_raw_text(params["rawText"], advanced_html = TRUE) if(stamp) diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index ec940fcdeac..55a64d0f5d1 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -791,9 +791,11 @@ ADMIN_VERB(cmd_admin_pm_panel, R_NONE, "Admin PM", "Show a list of clients to PM type = MESSAGE_TYPE_ADMINPM, html = fieldset_block( span_adminhelp("Administrator private message"), + // VOIDCREW EDIT START: autotranslate displays the translated administrator message. "Admin PM from-[reply_to]\n\n\ [display_message]\n\n\ Click on the administrator's name to reply.", + // VOIDCREW EDIT END "boxed_message red_box"), confidential = TRUE ) diff --git a/code/modules/asset_cache/assets/rcd.dm b/code/modules/asset_cache/assets/rcd.dm index d8c7fbd8bf2..9b2c94eb1d6 100644 --- a/code/modules/asset_cache/assets/rcd.dm +++ b/code/modules/asset_cache/assets/rcd.dm @@ -4,54 +4,10 @@ /datum/asset/spritesheet_batched/rcd/create_spritesheets() //the ship construction console's hull windows are not in GLOB.rcd_designs (they are not //offered by the handheld RCD) but they share this spritesheet, so draw both trees + // VOIDCREW EDIT START: shuttle draws hull-window construction icons. for(var/list/design_tree as anything in list(GLOB.rcd_designs, GLOB.ship_rcd_hull_designs)) draw_design_tree(design_tree) + // VOIDCREW EDIT END -/// Inserts an icon for every design in one GLOB.rcd_designs-shaped tree. -/datum/asset/spritesheet_batched/rcd/proc/draw_design_tree(list/design_tree) - for(var/root_category in design_tree) - - var/list/category_designs = design_tree[root_category] - if(!length(category_designs)) - continue - - for(var/category in category_designs) - var/list/designs = category_designs[category] - - var/sprite_name - - for(var/list/design as anything in designs) - var/atom/movable/path = design[RCD_DESIGN_PATH] - if(!ispath(path)) - continue - sprite_name = initial(path.name) - var/datum/universal_icon/sprite_icon - - //icon for windows are blended with grills if required and loaded from radial menu - if(ispath(path, /obj/structure/window)) - var/obj/structure/window/window_path = path - if(path == /obj/structure/window) - sprite_icon = uni_icon('icons/hud/radial.dmi', "windowsize") - else if(path == /obj/structure/window/reinforced) - sprite_icon = uni_icon('icons/hud/radial.dmi', "windowtype") - else - sprite_icon = uni_icon(initial(window_path.icon), initial(window_path.icon_state)) - //every other full tile window sits on a grille the same way the two - //stock ones do, including the hull windows added above - if(initial(window_path.fulltile)) - sprite_icon.blend_icon(uni_icon('icons/obj/structures.dmi', "grille"), ICON_UNDERLAY) - - //icons for solid airlocks have an added solid overlay on top of their glass icons - else if(ispath(path, /obj/machinery/door/airlock)) - var/obj/machinery/door/airlock/airlock_path = path - var/airlock_icon = initial(airlock_path.icon) - - sprite_icon = uni_icon(airlock_icon, "closed") - if(!initial(airlock_path.glass) && initial(airlock_path.can_be_glass)) - sprite_icon.blend_icon(uni_icon(airlock_icon, "fill_closed"), ICON_OVERLAY) - - //for all other icons we load the paths default icon & icon state - else - sprite_icon = uni_icon(initial(path.icon), initial(path.icon_state)) - - insert_icon(sanitize_css_class_name(sprite_name), sprite_icon) +// VOIDCREW EDIT: shuttle draws icons for construction design trees; implementation in voidcrew/modules/shuttle/construction/rcd_spritesheet.dm. +// VOIDCREW EDIT REMOVAL: shuttle draws the original design loop in voidcrew/modules/shuttle/construction/rcd_spritesheet.dm. diff --git a/code/modules/awaymissions/signpost.dm b/code/modules/awaymissions/signpost.dm index d5ea59142e8..c2e72bdc5ac 100644 --- a/code/modules/awaymissions/signpost.dm +++ b/code/modules/awaymissions/signpost.dm @@ -10,13 +10,14 @@ /obj/structure/signpost/Initialize(mapload) . = ..() set_light(2) +// VOIDCREW EDIT REMOVAL: mining resolves signpost destinations through the crew ship. /obj/structure/signpost/interact(mob/user) . = ..() if(.) return if(tgui_alert(usr,question,name,list("Yes","No")) == "Yes" && Adjacent(user)) - var/turf/T = get_destination_turf(user) + var/turf/T = get_destination_turf(user) // VOIDCREW EDIT: mining resolves signpost destinations through the crew ship. if(T) var/atom/movable/AM = user.pulling @@ -29,36 +30,7 @@ else to_chat(user, "Nothing happens. You feel that this is a bad sign.") -/** - * Where this signpost drops [user]. Voidcrew: aboard the ship they crew, and nowhere else. - * - * Upstream rolled a random safe turf on any ZTRAIT_STATION z-level, which on /tg/ means the - * station. This fork stamps that trait onto every z-level that currently holds a ship - - * link_to_z_level(), voidcrew/mapping/docking_port/_docking_port.dm - NPC hulls included, and - * a ship interior is the only pressurised thing on such a level, so the old roll reliably - * deposited whoever used it inside a random ship. Pirates counted. Resolve the user's own hull - * through the same mind-to-ship mapping the shop and the outposts use; crewing nothing means - * there is nowhere to go back to. - */ -/obj/structure/signpost/proc/get_destination_turf(mob/user) - var/obj/structure/overmap/ship/home = get_crew_ship(user) - if(!home?.shuttle?.shuttle_areas) - return null - - var/list/habitable = list() - var/list/breached = list() //A hull venting to space is still a better landing than none at all. - for(var/area/ship_area in home.shuttle.shuttle_areas) - for(var/turf/deck in ship_area) - if(!isopenturf(deck) || deck.density || isspaceturf(deck)) - continue - if(is_safe_turf(deck)) - habitable += deck - else - breached += deck - - if(length(habitable)) - return pick(habitable) - return length(breached) ? pick(breached) : null +// VOIDCREW EDIT: mining returns explorers to their own crew ship; implementation in voidcrew/modules/mining/signpost_destinations.dm. /obj/structure/signpost/attackby(obj/item/W, mob/user, list/modifiers, list/attack_modifiers) return interact(user) @@ -99,6 +71,4 @@ // also, could you think of the horror if they ended up in a holodeck // template or something -/// The meme signpost keeps its anywhere-at-all roll; it is not promising anyone a way home. -/obj/structure/signpost/exit/get_destination_turf(mob/user) - return find_safe_turf(zlevels = zlevels) +// VOIDCREW EDIT: mining preserves the exit signpost random destination; implementation in voidcrew/modules/mining/signpost_destinations.dm. diff --git a/code/modules/bitrunning/areas.dm b/code/modules/bitrunning/areas.dm index 078407a6859..f4144a6ca69 100644 --- a/code/modules/bitrunning/areas.dm +++ b/code/modules/bitrunning/areas.dm @@ -24,7 +24,7 @@ area_flags = UNIQUE_AREA | LOCAL_TELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING default_gravity = STANDARD_GRAVITY requires_power = FALSE - allow_shuttle_docking = FALSE + allow_shuttle_docking = FALSE // VOIDCREW EDIT: research forbids shuttle entry into virtual domains. /area/virtual_domain/fullbright static_lighting = FALSE @@ -38,7 +38,7 @@ icon_state = "bit_safe" requires_power = FALSE sound_environment = SOUND_ENVIRONMENT_ROOM - allow_shuttle_docking = FALSE + allow_shuttle_docking = FALSE // VOIDCREW EDIT: research forbids shuttle entry into virtual domains. /// Custom subtypes @@ -46,27 +46,27 @@ name = "Virtual Domain Lava Ruins" icon_state = "bit_ruin" area_flags = UNIQUE_AREA | LOCAL_TELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING - allow_shuttle_docking = FALSE + allow_shuttle_docking = FALSE // VOIDCREW EDIT: research forbids shuttle entry into virtual domains. /area/icemoon/underground/explored/virtual_domain name = "Virtual Domain Ice Ruins" icon_state = "bit_ice" area_flags = UNIQUE_AREA | LOCAL_TELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING - allow_shuttle_docking = FALSE + allow_shuttle_docking = FALSE // VOIDCREW EDIT: research forbids shuttle entry into virtual domains. /area/ruin/space/virtual_domain name = "Virtual Domain Unexplored Location" icon = 'icons/area/areas_station.dmi' icon_state = "bit_ruin" area_flags = UNIQUE_AREA | LOCAL_TELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING - allow_shuttle_docking = FALSE + allow_shuttle_docking = FALSE // VOIDCREW EDIT: research forbids shuttle entry into virtual domains. /area/space/virtual_domain name = "Virtual Domain Space" icon = 'icons/area/areas_station.dmi' icon_state = "bit_space" area_flags = UNIQUE_AREA | LOCAL_TELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING - allow_shuttle_docking = FALSE + allow_shuttle_docking = FALSE // VOIDCREW EDIT: research forbids shuttle entry into virtual domains. ///Areas that virtual entities should not be in @@ -74,7 +74,7 @@ name = "Virtual Domain Safe Zone" area_flags = UNIQUE_AREA | LOCAL_TELEPORT | EVENT_PROTECTED | VIRTUAL_SAFE_AREA | UNLIMITED_FISHING icon_state = "bit_safe" - allow_shuttle_docking = FALSE + allow_shuttle_docking = FALSE // VOIDCREW EDIT: research forbids shuttle entry into virtual domains. /area/virtual_domain/protected_space/fullbright static_lighting = FALSE diff --git a/code/modules/bitrunning/server/map_handling.dm b/code/modules/bitrunning/server/map_handling.dm index bbaba13f081..a31919fdd61 100644 --- a/code/modules/bitrunning/server/map_handling.dm +++ b/code/modules/bitrunning/server/map_handling.dm @@ -83,19 +83,20 @@ /// Initializes a new domain if the given key is valid and the user has enough points /obj/machinery/quantum_server/proc/load_domain(map_key) - var/datum/lazy_template/virtual_domain/target_domain + var/datum/lazy_template/virtual_domain/target_domain // VOIDCREW EDIT: research locks each virtual domain to one server. for(var/datum/lazy_template/virtual_domain/available in SSbitrunning.all_domains) if(map_key == available.key && points >= available.cost) - target_domain = available + target_domain = available // VOIDCREW EDIT: research locks each virtual domain to one server. break - if(!target_domain) + if(!target_domain) // VOIDCREW EDIT: research locks each virtual domain to one server. return FALSE // Domain datums are one instance for the whole fleet, and their reservation // list and loot counters go with them. A second server booting the same key // would read the first one's reservation, match no landmarks at all and take // itself offline for the round, so one holder per domain at a time. + // VOIDCREW EDIT START: research locks each virtual domain to one server. if(!SSbitrunning.claim_domain(map_key, src)) balloon_alert_to_viewers("domain in use!") say("[target_domain.name] is already running on another server. Pick a different domain.") @@ -103,6 +104,7 @@ return FALSE generated_domain = target_domain + // VOIDCREW EDIT END if(generated_domain.mission_min_candidates && (!COOLDOWN_FINISHED(src, polling_cooldown))) say("Advanced NPC algorithms resetting, please wait [DisplayTimeText(polling_cooldown)] or load a different domain.") @@ -143,11 +145,13 @@ // GLOB.landmarks_list is global, but a fleet can have a server on every // ship. Two of them cold booting at once would consume each other's // landmarks, so only claim the ones inside our own reservation. - var/datum/turf_reservation/our_reservation = LAZYACCESS(generated_domain.reservations, 1) + var/datum/turf_reservation/our_reservation = LAZYACCESS(generated_domain.reservations, 1) // VOIDCREW EDIT: research claims landmarks from the server reservation and tolerates missing exits. for(var/obj/effect/landmark/bitrunning/thing in GLOB.landmarks_list) + // VOIDCREW EDIT START: research claims landmarks from the server reservation and tolerates missing exits. if(our_reservation && !our_reservation.contains_turf(get_turf(thing))) continue + // VOIDCREW EDIT END if(istype(thing, /obj/effect/landmark/bitrunning/hololadder_spawn)) exit_turfs += get_turf(thing) @@ -192,11 +196,15 @@ // Logged rather than thrown: an unwound cold_boot_map never restores is_ready, // which leaves the server dark for the rest of the round. if(!length(exit_turfs)) + // VOIDCREW EDIT START: research claims landmarks from the server reservation and tolerates missing exits. stack_trace("Failed to find exit turfs on generated domain.") return FALSE + // VOIDCREW EDIT END if(!length(goal_turfs)) + // VOIDCREW EDIT START: research claims landmarks from the server reservation and tolerates missing exits. stack_trace("Failed to find send turfs on generated domain.") return FALSE + // VOIDCREW EDIT END if(!attempt_spawn_cache(cache_turfs)) return FALSE @@ -239,6 +247,7 @@ // A boot that failed before a domain was picked still lands here, so nothing // below may assume there is one. + // VOIDCREW EDIT START: research clears spent reservations before releasing virtual-domain ownership. if(generated_domain) // Drop the reservation from the domain before releasing it. lazy_load() appends to // this list and nothing else ever removes from it, so leaving spent entries behind @@ -253,6 +262,7 @@ generated_domain.secondary_loot_generated = 0 SSbitrunning.release_domain(generated_domain.key, src) + // VOIDCREW EDIT END var/list/creatures = spawned_threat_refs + mutation_candidate_refs for(var/datum/weakref/creature_ref as anything in creatures) @@ -262,6 +272,7 @@ qdel(creature) + // VOIDCREW EDIT REMOVAL: research clears spent reservations before releasing virtual-domain ownership. avatar_connection_refs.Cut() exit_turfs = list() generated_domain = null diff --git a/code/modules/bitrunning/server/obj_generation.dm b/code/modules/bitrunning/server/obj_generation.dm index 9735010508b..eacbe843eb2 100644 --- a/code/modules/bitrunning/server/obj_generation.dm +++ b/code/modules/bitrunning/server/obj_generation.dm @@ -106,11 +106,13 @@ // Same reason load_map_items() scopes its sweep: GLOB.landmarks_list is global // and a fleet can have a server on every ship, so only claim the landmarks // standing inside our own reservation. - var/datum/turf_reservation/our_reservation = LAZYACCESS(generated_domain.reservations, 1) + var/datum/turf_reservation/our_reservation = LAZYACCESS(generated_domain.reservations, 1) // VOIDCREW EDIT: research claims mob landmarks only from the server reservation. for(var/obj/effect/landmark/bitrunning/mob_segment/landmark in GLOB.landmarks_list) + // VOIDCREW EDIT START: research claims mob landmarks only from the server reservation. if(our_reservation && !our_reservation.contains_turf(get_turf(landmark))) continue + // VOIDCREW EDIT END if(current_index > length(generated_domain.mob_modules)) stack_trace("vdom: mobs segments are set to unique, but there are more landmarks than available segments") diff --git a/code/modules/bitrunning/server/signal_handlers.dm b/code/modules/bitrunning/server/signal_handlers.dm index d05cc2ab947..dbd3834f6e9 100644 --- a/code/modules/bitrunning/server/signal_handlers.dm +++ b/code/modules/bitrunning/server/signal_handlers.dm @@ -74,11 +74,13 @@ // ismegafauna() also covers /mob/living/basic/boss, which has no // make_virtual_megafauna() - calling it on one is a runtime. if(ismegafauna(creature)) + // VOIDCREW EDIT START: research limits virtual megafauna conversion to supported mobs. if(istype(creature, /mob/living/simple_animal/hostile/megafauna)) var/mob/living/simple_animal/hostile/megafauna/boss = creature boss.make_virtual_megafauna() else stack_trace("bitrunning: [creature.type] has no virtual megafauna nerf, it keeps full loot inside the domain") + // VOIDCREW EDIT END continue mutation_candidate_refs.Add(WEAKREF(creature)) diff --git a/code/modules/bitrunning/server/util.dm b/code/modules/bitrunning/server/util.dm index e41d62b0ffa..1299e2625d2 100644 --- a/code/modules/bitrunning/server/util.dm +++ b/code/modules/bitrunning/server/util.dm @@ -85,8 +85,10 @@ // A ship can map or build a server without a forge in range. Callers already // handle a null forge; pick() on an empty list would runtime before they got it. + // VOIDCREW EDIT START: research tolerates ship servers without a nearby forge. if(!length(nearby_forges)) return null + // VOIDCREW EDIT END return pick(nearby_forges) diff --git a/code/modules/bitrunning/util/virtual_megafauna.dm b/code/modules/bitrunning/util/virtual_megafauna.dm index aeaad1765fe..77a02db5b29 100644 --- a/code/modules/bitrunning/util/virtual_megafauna.dm +++ b/code/modules/bitrunning/util/virtual_megafauna.dm @@ -10,9 +10,11 @@ // well after it, so the component is already attached by the time we get here. Left // alone, every megafauna domain broadcasts a lavaland signal out of the turf // reservation to anyone holding a GPS. + // VOIDCREW EDIT START: research removes real-world GPS signals from virtual bosses. var/datum/component/gps/beacon = GetComponent(/datum/component/gps) if(beacon) qdel(beacon) + // VOIDCREW EDIT END loot.Cut() loot += /obj/structure/closet/crate/secure/bitrunning/encrypted diff --git a/code/modules/bitrunning/virtual_domain/domains/ash_drake.dm b/code/modules/bitrunning/virtual_domain/domains/ash_drake.dm index 034cd984987..bc59b698cc5 100644 --- a/code/modules/bitrunning/virtual_domain/domains/ash_drake.dm +++ b/code/modules/bitrunning/virtual_domain/domains/ash_drake.dm @@ -1,14 +1,16 @@ /datum/lazy_template/virtual_domain/ash_drake name = "Ashen Inferno" - cost = BITRUNNER_COST_BOSS + cost = BITRUNNER_COST_BOSS // VOIDCREW EDIT: research prices virtual boss domains and supplies their domain briefing. desc = "Home of the ash drake, a powerful dragon that scours the surface of Lavaland." difficulty = BITRUNNER_DIFFICULTY_MEDIUM forced_outfit = /datum/outfit/job/miner + // VOIDCREW EDIT START: research prices virtual boss domains and supplies their domain briefing. help_text = "There is no crate waiting for you out there. The drake is carrying it. \ Kill it, take the cache off the body, and haul it back to the safehouse goal tile. \ It breathes fire in a cone, calls down meteors, throws out rings of fireballs, and swoops \ into the air to land somewhere else. Below half health it walls the fight into a ring of \ lava, and leaving that ring only makes it angrier. Take the armoury with you." + // VOIDCREW EDIT END key = "ash_drake" map_name = "ash_drake" reward_points = BITRUNNER_REWARD_MEDIUM diff --git a/code/modules/bitrunning/virtual_domain/domains/blood_drunk_miner.dm b/code/modules/bitrunning/virtual_domain/domains/blood_drunk_miner.dm index 540c4000baa..cbd3d17de5a 100644 --- a/code/modules/bitrunning/virtual_domain/domains/blood_drunk_miner.dm +++ b/code/modules/bitrunning/virtual_domain/domains/blood_drunk_miner.dm @@ -1,14 +1,16 @@ /datum/lazy_template/virtual_domain/blood_drunk_miner name = "Sanguine Excavation" - cost = BITRUNNER_COST_BOSS + cost = BITRUNNER_COST_BOSS // VOIDCREW EDIT: research prices virtual boss domains and supplies their domain briefing. desc = "Few escape the surface of Lavaland without a few scars. Some remain, maddened by the hunt." difficulty = BITRUNNER_DIFFICULTY_MEDIUM forced_outfit = /datum/outfit/job/miner + // VOIDCREW EDIT START: research prices virtual boss domains and supplies their domain briefing. help_text = "The miner is carrying the cache. Kill it, pick the cache up off the body, and \ bring it back to the safehouse goal tile. It dashes to close distance and hits hard with \ its saw, so it will not let you kite it for long. It also eats the dead to heal, which \ means a downed teammate left on the floor hands it most of its health back. \ Everything in the safehouse armoury is yours." + // VOIDCREW EDIT END key = "blood_drunk_miner" map_name = "blood_drunk_miner" reward_points = BITRUNNER_REWARD_MEDIUM diff --git a/code/modules/bitrunning/virtual_domain/domains/bubblegum.dm b/code/modules/bitrunning/virtual_domain/domains/bubblegum.dm index 6fb610f9b59..e572fdfa94b 100644 --- a/code/modules/bitrunning/virtual_domain/domains/bubblegum.dm +++ b/code/modules/bitrunning/virtual_domain/domains/bubblegum.dm @@ -1,14 +1,16 @@ /datum/lazy_template/virtual_domain/bubblegum name = "Blood-Soaked Lair" - cost = BITRUNNER_COST_APEX_BOSS + cost = BITRUNNER_COST_APEX_BOSS // VOIDCREW EDIT: research prices virtual boss domains and supplies their domain briefing. desc = "King of the slaughter demons. Bubblegum is a massive, hulking beast with a penchant for violence." difficulty = BITRUNNER_DIFFICULTY_HIGH completion_loot = list(/obj/item/toy/plush/bubbleplush = 1) forced_outfit = /datum/outfit/job/miner + // VOIDCREW EDIT START: research prices virtual boss domains and supplies their domain briefing. help_text = "Bubblegum is carrying the cache. Kill it, take the cache off the body, and haul \ it to the safehouse goal tile. It moves through blood, so every pool on the floor is \ somewhere it can appear from, including the blood you are leaving behind. It charges in a \ straight line and calls in copies of itself. Fighting it on clean ground is much easier." + // VOIDCREW EDIT END key = "bubblegum" map_name = "bubblegum" reward_points = BITRUNNER_REWARD_HIGH diff --git a/code/modules/bitrunning/virtual_domain/domains/colossus.dm b/code/modules/bitrunning/virtual_domain/domains/colossus.dm index 27db788f4b3..1478e0cbb30 100644 --- a/code/modules/bitrunning/virtual_domain/domains/colossus.dm +++ b/code/modules/bitrunning/virtual_domain/domains/colossus.dm @@ -1,13 +1,15 @@ /datum/lazy_template/virtual_domain/colossus name = "Celestial Trial" - cost = BITRUNNER_COST_APEX_BOSS + cost = BITRUNNER_COST_APEX_BOSS // VOIDCREW EDIT: research prices virtual boss domains and supplies their domain briefing. desc = "A massive, ancient beast named the Colossus. Judgment comes." difficulty = BITRUNNER_DIFFICULTY_HIGH forced_outfit = /datum/outfit/job/miner + // VOIDCREW EDIT START: research prices virtual boss domains and supplies their domain briefing. help_text = "The Colossus is holding the cache. Kill it, take the cache, and carry it back to \ the safehouse goal tile. It barely moves. Everything it does is projectiles, and every \ pattern has a gap in it, so the fight is about reading the spread and standing in the gap. \ It gets faster as its health drops. Take the whole armoury with you." + // VOIDCREW EDIT END key = "colossus" map_name = "colossus" reward_points = BITRUNNER_REWARD_HIGH diff --git a/code/modules/bitrunning/virtual_domain/domains/hierophant.dm b/code/modules/bitrunning/virtual_domain/domains/hierophant.dm index d03867cd20a..9cb2b07e7e3 100644 --- a/code/modules/bitrunning/virtual_domain/domains/hierophant.dm +++ b/code/modules/bitrunning/virtual_domain/domains/hierophant.dm @@ -1,14 +1,16 @@ /datum/lazy_template/virtual_domain/hierophant name = "Zealot Arena" - cost = BITRUNNER_COST_APEX_BOSS + cost = BITRUNNER_COST_APEX_BOSS // VOIDCREW EDIT: research prices virtual boss domains and supplies their domain briefing. desc = "Dance, puppets, dance!" difficulty = BITRUNNER_DIFFICULTY_HIGH forced_outfit = /datum/outfit/job/miner + // VOIDCREW EDIT START: research prices virtual boss domains and supplies their domain briefing. help_text = "The hierophant is carrying the cache. Kill it, take the cache, and get it to the \ safehouse goal tile. It teleports directly onto whoever it is chasing and leaves damaging \ squares on the floor, so putting a wall between you and it buys less time than you think. \ Watch the ground: everything it does is telegraphed a moment before it lands. \ Everything in the safehouse armoury is yours." + // VOIDCREW EDIT END key = "hierophant" map_name = "hierophant" reward_points = BITRUNNER_REWARD_HIGH diff --git a/code/modules/bitrunning/virtual_domain/domains/psyker_zombies.dm b/code/modules/bitrunning/virtual_domain/domains/psyker_zombies.dm index 96fb62a6dc8..0f9a7c4d6aa 100644 --- a/code/modules/bitrunning/virtual_domain/domains/psyker_zombies.dm +++ b/code/modules/bitrunning/virtual_domain/domains/psyker_zombies.dm @@ -3,7 +3,7 @@ // Was COST_MEDIUM, which made this the only domain in the roster paying net +3 // while also being BEPIS-eligible - strictly better than the megafauna arenas it // is supposed to fund. Priced back onto the flat +2 ladder everything else uses. - cost = BITRUNNER_COST_HIGH + cost = BITRUNNER_COST_HIGH // VOIDCREW EDIT: research keeps the psyker domain on the shared bitrunning reward ladder. desc = "Another neglected corner of the virtual world. This one had to be abandoned due to zombie virus. \ Warning -- Virtual domain does not support visual display. This mission must be completed using echolocation." difficulty = BITRUNNER_DIFFICULTY_MEDIUM diff --git a/code/modules/bitrunning/virtual_domain/domains/wendigo.dm b/code/modules/bitrunning/virtual_domain/domains/wendigo.dm index 86d5f45b4b1..e834d02bcf1 100644 --- a/code/modules/bitrunning/virtual_domain/domains/wendigo.dm +++ b/code/modules/bitrunning/virtual_domain/domains/wendigo.dm @@ -1,14 +1,16 @@ /datum/lazy_template/virtual_domain/wendigo name = "Glacial Devourer" - cost = BITRUNNER_COST_APEX_BOSS + cost = BITRUNNER_COST_APEX_BOSS // VOIDCREW EDIT: research prices virtual boss domains and supplies their domain briefing. desc = "Legends speak of the ravenous Wendigo hidden deep within the caves of Icemoon." difficulty = BITRUNNER_DIFFICULTY_HIGH forced_outfit = /datum/outfit/job/miner + // VOIDCREW EDIT START: research prices virtual boss domains and supplies their domain briefing. help_text = "The wendigo has the cache. Kill it, take the cache, and bring it back to the \ safehouse goal tile. It slams the ground to throw you across the arena and fires shockwaves \ in spirals and expanding walls, so distance on its own will not keep you safe. Below half \ health it teleports back to where the fight started and opens up with heavier shockwave \ patterns. The bodies out there are the last crew that tried this." + // VOIDCREW EDIT END key = "wendigo" map_name = "wendigo" reward_points = BITRUNNER_REWARD_HIGH diff --git a/code/modules/cargo/exports/large_objects.dm b/code/modules/cargo/exports/large_objects.dm index 91c0cc1dfa5..d8f2c074687 100644 --- a/code/modules/cargo/exports/large_objects.dm +++ b/code/modules/cargo/exports/large_objects.dm @@ -1,5 +1,5 @@ /datum/export/large/crate - cost = CARGO_CRATE_VALUE * 0.25 + cost = CARGO_CRATE_VALUE * 0.25 // VOIDCREW EDIT: cargo tunes salvage refunds to ship shipment prices. k_elasticity = 0 unit_name = "crate" export_types = list(/obj/structure/closet/crate) @@ -15,14 +15,7 @@ if(. && notes) . += " Thanks for participating in Nanotrasen Crates Recycling Program." -/datum/export/large/crate/get_cost(obj/exported_obj, apply_elastic = TRUE) - . = ..() - // Preserve each crate type's salvage value, but discounted shipping packaging - // must not refund the shipment. Its removable manifest is not the authority. - if(istype(exported_obj, /obj/structure/closet/crate)) - var/obj/structure/closet/crate/crate = exported_obj - if(!isnull(crate.cargo_paid_cost)) - return max(0, min(., FLOOR(crate.cargo_paid_cost * 0.1, 1))) +// VOIDCREW EDIT: cargo caps crate resale against the settled shipment; implementation in voidcrew/modules/cargo/export_values.dm. /datum/export/large/crate/wooden cost = CARGO_CRATE_VALUE/5 @@ -57,12 +50,12 @@ /datum/export/large/reagent_dispenser/water unit_name = "watertank" export_types = list(/obj/structure/reagent_dispensers/watertank) - contents_cost = CARGO_CRATE_VALUE * 0.25 + contents_cost = CARGO_CRATE_VALUE * 0.25 // VOIDCREW EDIT: cargo tunes salvage refunds to ship shipment prices. /datum/export/large/reagent_dispenser/fuel unit_name = "fueltank" export_types = list(/obj/structure/reagent_dispensers/fueltank) - contents_cost = CARGO_CRATE_VALUE * 0.55 + contents_cost = CARGO_CRATE_VALUE * 0.55 // VOIDCREW EDIT: cargo tunes salvage refunds to ship shipment prices. /datum/export/large/reagent_dispenser/beer unit_name = "beer keg" diff --git a/code/modules/cargo/exports/manifest.dm b/code/modules/cargo/exports/manifest.dm index 21c2c0f282c..a84cd442a5d 100644 --- a/code/modules/cargo/exports/manifest.dm +++ b/code/modules/cargo/exports/manifest.dm @@ -3,15 +3,13 @@ // Approved manifest. // At most20 credits or10% of payment: cheap goodies and flash coupons cannot subsidize themselves. /datum/export/manifest_correct - cost = CARGO_CRATE_VALUE * 0.1 + cost = CARGO_CRATE_VALUE * 0.1 // VOIDCREW EDIT: cargo caps manifest resale against shipment payment. k_elasticity = 0 unit_name = "approved manifest" export_types = list(/obj/item/paper/fluff/jobs/cargo/manifest) scannable = FALSE -/datum/export/manifest_correct/get_cost(obj/O, apply_elastic = TRUE) - var/obj/item/paper/fluff/jobs/cargo/manifest/manifest = O - return max(0, min(..(), FLOOR(manifest.order_cost * 0.1, 1))) +// VOIDCREW EDIT: cargo caps manifest refunds against the paid order; implementation in voidcrew/modules/cargo/export_values.dm. /datum/export/manifest_correct/applies_to(obj/O) if(!..()) diff --git a/code/modules/cargo/exports/materials.dm b/code/modules/cargo/exports/materials.dm index 0dcc5f1fef5..e1f3a98534e 100644 --- a/code/modules/cargo/exports/materials.dm +++ b/code/modules/cargo/exports/materials.dm @@ -33,18 +33,15 @@ // Materials. Static materials exist as parent types, while materials subject to the stock market have a fluid cost as determined by material/market types // If you're adding a new material to the stock market, make sure its export type is added here. -/// Fuel has one resale ceiling, whether shipped loose or through a stock block. -/proc/plasma_export_bid() - return max(0, min(SSstock_market.materials_prices[/datum/material/plasma], 10)) +// VOIDCREW EDIT: cargo shares the plasma resale ceiling with stock blocks; implementation in voidcrew/modules/cargo/export_values.dm. /datum/export/material/plasma - cost = 10 + cost = 10 // VOIDCREW EDIT: cargo caps plasma resale across loose and market exports. k_elasticity = 0 material_id = /datum/material/plasma message = "cm3 of plasma" -/datum/export/material/plasma/get_cost(obj/exported_obj, apply_elastic = TRUE) - return round(plasma_export_bid() * get_amount(exported_obj)) +// VOIDCREW EDIT: cargo applies the plasma resale ceiling to loose material; implementation in voidcrew/modules/cargo/export_values.dm. /datum/export/material/bananium cost = CARGO_CRATE_VALUE * 2 @@ -177,7 +174,7 @@ /obj/item/stock_block, ) //For whatever reason, bluespace crystals are not a mineral -// VOIDCREW EDIT: plasma trades on the materials market here (see basemats.dm). +// VOIDCREW EDIT START: cargo - plasma trades on the materials market here (see basemats.dm). // Direct plasma is matched by the earlier datum. Blocks must obey its same // ceiling, including a fixed quote captured before prices or balance changed. /datum/export/material/market/plasma diff --git a/code/modules/cargo/exports/sheets.dm b/code/modules/cargo/exports/sheets.dm index 72382a3865b..bb28367113a 100644 --- a/code/modules/cargo/exports/sheets.dm +++ b/code/modules/cargo/exports/sheets.dm @@ -65,7 +65,7 @@ // For base materials, see materials.dm /datum/export/stack/plasteel - cost = CARGO_CRATE_VALUE * 0.1 + cost = CARGO_CRATE_VALUE * 0.1 // VOIDCREW EDIT: cargo keeps plasteel salvage below its shipment price. message = "of plasteel" export_types = list(/obj/item/stack/sheet/plasteel) diff --git a/code/modules/cargo/materials_market.dm b/code/modules/cargo/materials_market.dm index f50b7e924e0..d341c53f7de 100644 --- a/code/modules/cargo/materials_market.dm +++ b/code/modules/cargo/materials_market.dm @@ -100,33 +100,7 @@ else set_light(initial(light_range), initial(light_power)) -/** - * VOIDCREW EDIT ADDITION: four seams so a market that is not bolted to a station's cargo - * department can still work. Nothing in this fork ever ships SSshuttle.shopping_list - - * deliveries run off the per-ship cargo console's own cart (voidcrew/modules/cargo/shipping) - * - and there is no ACCOUNT_CAR budget and no crew member holding ACCESS_CARGO, so an order - * placed here used to be quoted against the wrong account and then filed into a list nothing - * reads. Overridden in voidcrew/edits/materials_market.dm. - */ - -/// The order list this market files into. Null means it has nowhere to file an order. -/// `announce_refusal` is TRUE only on the path that is actually placing one, so the override -/// can say why it is refusing without spamming that message from every ui_data() tick. -/obj/machinery/materials_market/proc/get_order_list(announce_refusal = FALSE) - return SSshuttle.shopping_list - -/// Whether `id_card` may spend a budget here instead of their own money. -/obj/machinery/materials_market/proc/can_order_on_budget(obj/item/card/id/id_card) - return (ACCESS_CARGO in id_card?.GetAccess()) - -/// Whether an order placed with `id_card` comes out of the buyer's own pocket, which means a -/// 1.1x surcharge and a crate only their ID can open. -/obj/machinery/materials_market/proc/ordering_privately(obj/item/card/id/id_card) - return ordering_private || !can_order_on_budget(id_card) - -/// The account an order placed here is quoted against, and billed to when it is not private. -/obj/machinery/materials_market/proc/market_account(obj/item/card/id/id_card, is_ordering_private) - return is_ordering_private ? id_card?.registered_account : SSeconomy.get_dep_account(ACCOUNT_CAR) +// VOIDCREW EDIT: cargo supplies market account and cart hooks; implementation in voidcrew/edits/machinery/materials_market.dm. /** * Find the order purchased either privately or by cargo budget @@ -135,7 +109,7 @@ * * is_ordering_private - is the player ordering privatly. If FALSE it means they are using cargo budget */ /obj/machinery/materials_market/proc/find_order(mob/user, is_ordering_private) - for(var/datum/supply_order/order in get_order_list()) + for(var/datum/supply_order/order in get_order_list()) // VOIDCREW EDIT: cargo routes material orders through ship accounts and validates the pooled cart. // Must be a Galactic Materials Market order and payed by the null account(if ordered via cargo budget) or by correct user for private purchase if(order.orderer_rank == GALATIC_MATERIAL_ORDER && ( \ (!is_ordering_private && isnull(order.paying_account)) || \ @@ -160,14 +134,15 @@ . = list() //can this player use cargo budget + // VOIDCREW EDIT REMOVAL: cargo routes material orders through ship accounts and validates the pooled cart. var/obj/item/card/id/used_id_card if(isliving(user)) var/mob/living/living_user = user used_id_card = living_user.get_idcard(TRUE) - var/can_buy_via_budget = can_order_on_budget(used_id_card) + var/can_buy_via_budget = can_order_on_budget(used_id_card) // VOIDCREW EDIT: cargo routes material orders through ship accounts and validates the pooled cart. //if no cargo access then force private purchase - var/is_ordering_private = ordering_privately(used_id_card) + var/is_ordering_private = ordering_privately(used_id_card) // VOIDCREW EDIT: cargo routes material orders through ship accounts and validates the pooled cart. //find current order based on ordering mode & player var/datum/supply_order/current_order = find_order(user, is_ordering_private) @@ -238,7 +213,7 @@ // this proc uses `is_ordering_private`, so a buyer with no cargo access was quoted against // the budget's balance and then charged their own. Ask the seam that ui_act() bills. var/datum/bank_account/quoted_account = market_account(used_id_card, is_ordering_private) - var/balance = quoted_account?.account_balance || 0 + var/balance = quoted_account?.account_balance || 0 // VOIDCREW EDIT: cargo routes material orders through ship accounts and validates the pooled cart. //is market crashing var/market_crashing = FALSE @@ -270,18 +245,20 @@ if(isnull(used_id_card)) say("No ID Found") return - var/can_buy_via_budget = can_order_on_budget(used_id_card) + var/can_buy_via_budget = can_order_on_budget(used_id_card) // VOIDCREW EDIT: cargo routes material orders through ship accounts and validates the pooled cart. //if multiple users open the UI some of them may not have the required access so we recheck - var/is_ordering_private = ordering_privately(used_id_card) + var/is_ordering_private = ordering_privately(used_id_card) // VOIDCREW EDIT: cargo routes material orders through ship accounts and validates the pooled cart. switch(action) if("buy") var/material_str = params["material"] + // VOIDCREW EDIT START: cargo routes material orders through ship accounts and validates the pooled cart. var/quantity = isnum(params["quantity"]) ? params["quantity"] : text2num(params["quantity"]) if(!valid_cargo_order_quantity(quantity, MAX_STACK_SIZE * MAX_STACK_LIMIT)) say("Order a whole number of sheets, from 1 to [MAX_STACK_SIZE * MAX_STACK_LIMIT].") return FALSE + // VOIDCREW EDIT END //find material from its name var/datum/material/material_bought @@ -291,13 +268,13 @@ material_bought = mat break if(!material_bought) - return FALSE + return FALSE // VOIDCREW EDIT: cargo routes material orders through ship accounts and validates the pooled cart. sheet_to_buy = initial(material_bought.sheet_type) if(!sheet_to_buy) CRASH("Material with no sheet type being sold on materials market!") //get available bank account for purchasing - var/datum/bank_account/account_payable = market_account(used_id_card, is_ordering_private) + var/datum/bank_account/account_payable = market_account(used_id_card, is_ordering_private) // VOIDCREW EDIT: cargo routes material orders through ship accounts and validates the pooled cart. if(!account_payable) say("No bank account detected!") return @@ -316,16 +293,19 @@ // We want to count how many stacks of all sheets we're ordering to make sure they don't exceed the limit of 10 // If we already have a custom order on SSshuttle, we should add the things to order to that order var/datum/supply_order/current_order = find_order(living_user, is_ordering_private) + // VOIDCREW EDIT START: cargo routes material orders through ship accounts and validates the pooled cart. var/list/proposed_contents = current_order ? current_order.pack.contains.Copy() : list() proposed_contents[sheet_to_buy] += quantity if(!valid_material_order_contents(proposed_contents)) say("One material order can contain at most [MAX_STACK_LIMIT] stacks across all materials.") return FALSE + // VOIDCREW EDIT END if(!isnull(current_order)) // Check if this order exceeded the market limit var/prior_sheets = current_order.pack.contains[sheet_to_buy] if(prior_sheets + quantity > SSstock_market.materials_quantity[material_bought] ) say("There aren't enough sheets on the market! Please wait for more sheets to be traded before adding more.") + // VOIDCREW EDIT REMOVAL: cargo routes material orders through ship accounts and validates the pooled cart. playsound(usr, 'sound/machines/synth/synth_no.ogg', 35, FALSE) return @@ -366,11 +346,13 @@ // VOIDCREW EDIT CHANGE - original: `SSshuttle.shopping_list += new_order`. The seam // says no by returning null, and has already told the buyer why. var/list/order_list = get_order_list(announce_refusal = TRUE) + // VOIDCREW EDIT START: cargo routes material orders through ship accounts and validates the pooled cart. if(isnull(order_list)) qdel(new_order) return + // VOIDCREW EDIT END say("Thank you for your purchase! It will arrive on the next cargo shuttle!") - order_list += new_order + order_list += new_order // VOIDCREW EDIT: cargo routes material orders through ship accounts and validates the pooled cart. return TRUE if("toggle_budget") @@ -383,9 +365,11 @@ var/datum/supply_order/current_order = find_order(living_user, is_ordering_private) if(!isnull(current_order)) var/list/order_list = get_order_list() // VOIDCREW EDIT CHANGE - original: `SSshuttle.shopping_list` + // VOIDCREW EDIT START: cargo routes material orders through ship accounts and validates the pooled cart. if(isnull(order_list)) return order_list -= current_order + // VOIDCREW EDIT END qdel(current_order) return TRUE @@ -424,7 +408,7 @@ /obj/item/stock_block/proc/update_value() if(!SSstock_market.materials_prices[export_mat]) return - export_value = quantity * (export_mat == /datum/material/plasma ? plasma_export_bid() : SSstock_market.materials_prices[export_mat]) + export_value = quantity * (export_mat == /datum/material/plasma ? plasma_export_bid() : SSstock_market.materials_prices[export_mat]) // VOIDCREW EDIT: cargo routes material orders through ship accounts and validates the pooled cart. icon_state = "stock_block_liquid" update_appearance(UPDATE_ICON_STATE) visible_message(span_warning("\The [src] becomes liquid!")) diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm index 296a2bf5861..69d0b880967 100644 --- a/code/modules/cargo/order.dm +++ b/code/modules/cargo/order.dm @@ -61,9 +61,11 @@ ///Boolean on whether the manifest can be cancelled through cargo consoles. var/can_be_cancelled = TRUE /// Actual ship-account payment, also used by its manifest. Null until settled. + // VOIDCREW EDIT START: cargo tracks the settled ship payment on crates and manifests. var/ship_paid_cost /// Last refusal from ship settlement, for delivery feedback. var/ship_settlement_error + // VOIDCREW EDIT END /datum/supply_order/New( datum/supply_pack/pack, @@ -106,28 +108,7 @@ cost *= 1.1 return round(cost) -/// Settle a ship order atomically before generating any goods or changing market stock. -/datum/supply_order/proc/settle_ship_order(datum/bank_account/account) - ship_settlement_error = null - if(!account || !isnull(ship_paid_cost)) - ship_settlement_error = "No paying account, or order already paid." - return FALSE - var/datum/supply_pack/custom/minerals/material_order = astype(pack) - if(material_order) - ship_settlement_error = material_order.ship_order_error() - if(ship_settlement_error) - return FALSE - var/price = get_final_cost() - if(!isnum(price) || price < 0) - ship_settlement_error = "Invalid order price." - return FALSE - // adjust_money(0) reports failure, although a fully discounted order is valid. - if(price > 0 && !account.adjust_money(-price)) - ship_settlement_error = "Insufficient credits; order remains in the cart." - return FALSE - ship_paid_cost = price - material_order?.commit_ship_order() - return TRUE +// VOIDCREW EDIT: cargo settles ship orders before goods are generated; implementation in voidcrew/modules/cargo/ship_order_settlement.dm. /datum/supply_order/proc/generateRequisition(turf/T) var/obj/item/paper/requisition/requisition_paper = new(T) @@ -167,7 +148,7 @@ manifest_text += "Item: [packname]
" manifest_text += "Contents:
" manifest_text += "