diff --git a/citadel.dme b/citadel.dme
index ce82918ea89..55a4ed1bb69 100644
--- a/citadel.dme
+++ b/citadel.dme
@@ -145,6 +145,7 @@
#include "code\__DEFINES\combat\attack_types.dm"
#include "code\__DEFINES\combat\damage.dm"
#include "code\__DEFINES\combat\explosions.dm"
+#include "code\__DEFINES\combat\shieldcall.dm"
#include "code\__DEFINES\controllers\_repositories.dm"
#include "code\__DEFINES\controllers\_subsystems.dm"
#include "code\__DEFINES\controllers\dbcore.dm"
@@ -187,6 +188,7 @@
#include "code\__DEFINES\dcs\signals\signals_item\signals_item_inventory.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_appearance.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_combat.dm"
+#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_defense.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_inventory.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_main.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_mobility.dm"
@@ -227,9 +229,15 @@
#include "code\__DEFINES\mapping\maps.dm"
#include "code\__DEFINES\mapping\multiz.dm"
#include "code\__DEFINES\mapping\system.dm"
-#include "code\__DEFINES\materials\balancing.dm"
+#include "code\__DEFINES\materials\attributes.dm"
+#include "code\__DEFINES\materials\dynamics.dm"
+#include "code\__DEFINES\materials\flags.dm"
+#include "code\__DEFINES\materials\helpers.dm"
#include "code\__DEFINES\materials\misc.dm"
+#include "code\__DEFINES\materials\parts.dm"
+#include "code\__DEFINES\materials\stats.dm"
#include "code\__DEFINES\mining\legacy.dm"
+#include "code\__DEFINES\misc\attack_animations.dm"
#include "code\__DEFINES\misc\message_ranges.dm"
#include "code\__DEFINES\mobs\actions.dm"
#include "code\__DEFINES\mobs\characteristics.dm"
@@ -347,6 +355,7 @@
#include "code\__HELPERS\unsorted.dm"
#include "code\__HELPERS\vector.dm"
#include "code\__HELPERS\verbs.dm"
+#include "code\__HELPERS\animations\attack.dm"
#include "code\__HELPERS\datastructs\armor.dm"
#include "code\__HELPERS\datastructs\bodytypes.dm"
#include "code\__HELPERS\datastructs\ingredients.dm"
@@ -382,6 +391,7 @@
#include "code\__HELPERS\lists\unique.dm"
#include "code\__HELPERS\math\angle.dm"
#include "code\__HELPERS\math\distance.dm"
+#include "code\__HELPERS\math\multipliers.dm"
#include "code\__HELPERS\matrices\color_matrix.dm"
#include "code\__HELPERS\matrices\transform_matrix.dm"
#include "code\__HELPERS\misc\sonar.dm"
@@ -615,9 +625,11 @@
#include "code\datums\progressbar.dm"
#include "code\datums\prototype.dm"
#include "code\datums\radiation_wave.dm"
+#include "code\datums\shieldcall.dm"
#include "code\datums\soul_link.dm"
#include "code\datums\sun.dm"
#include "code\datums\tgs_event_handler.dm"
+#include "code\datums\unarmed_attack.dm"
#include "code\datums\weakref.dm"
#include "code\datums\world_topic.dm"
#include "code\datums\announce\_legacy.dm"
@@ -651,6 +663,9 @@
#include "code\datums\armor\clothing\shoes.dm"
#include "code\datums\armor\clothing\suit.dm"
#include "code\datums\armor\clothing\uniform.dm"
+#include "code\datums\armor\objects\doors.dm"
+#include "code\datums\armor\objects\standard.dm"
+#include "code\datums\armor\objects\windows.dm"
#include "code\datums\armor\outsider\autolok.dm"
#include "code\datums\armor\outsider\imperial.dm"
#include "code\datums\armor\outsider\lavaland.dm"
@@ -932,6 +947,8 @@
#include "code\game\atoms\atom.dm"
#include "code\game\atoms\buckling.dm"
#include "code\game\atoms\defense.dm"
+#include "code\game\atoms\defense_old.dm"
+#include "code\game\atoms\materials.dm"
#include "code\game\atoms\movement.dm"
#include "code\game\atoms\say.dm"
#include "code\game\atoms\vv.dm"
@@ -940,6 +957,8 @@
#include "code\game\atoms\movable\pulling.dm"
#include "code\game\atoms\movable\throwing.dm"
#include "code\game\atoms\movable\vv.dm"
+#include "code\game\atoms\movable\special\overlay.dm"
+#include "code\game\atoms\movable\special\render.dm"
#include "code\game\click\adjacency.dm"
#include "code\game\click\adjacency_legacy.dm"
#include "code\game\click\ai.dm"
@@ -1194,7 +1213,6 @@
#include "code\game\machinery\rechargestation.dm"
#include "code\game\machinery\recipe_lookup.dm"
#include "code\game\machinery\requests_console.dm"
-#include "code\game\machinery\robot_fabricator.dm"
#include "code\game\machinery\seed_extractor.dm"
#include "code\game\machinery\Sleeper.dm"
#include "code\game\machinery\spaceheater.dm"
@@ -1253,24 +1271,25 @@
#include "code\game\machinery\computer\arcade\orion_event.dm"
#include "code\game\machinery\computer\command\card.dm"
#include "code\game\machinery\computer\misc\bioscan.dm"
-#include "code\game\machinery\doors\airlock.dm"
-#include "code\game\machinery\doors\airlock_control.dm"
-#include "code\game\machinery\doors\airlock_electronics.dm"
-#include "code\game\machinery\doors\airlock_subtypes.dm"
-#include "code\game\machinery\doors\airlock_vr.dm"
-#include "code\game\machinery\doors\alarmlock.dm"
#include "code\game\machinery\doors\blast_door.dm"
-#include "code\game\machinery\doors\brigdoors.dm"
#include "code\game\machinery\doors\checkForMultipleDoors.dm"
+#include "code\game\machinery\doors\defense.dm"
#include "code\game\machinery\doors\door.dm"
+#include "code\game\machinery\doors\door_timer.dm"
#include "code\game\machinery\doors\door_vr.dm"
#include "code\game\machinery\doors\firedoor.dm"
#include "code\game\machinery\doors\firedoor_assembly.dm"
#include "code\game\machinery\doors\multi_tile.dm"
#include "code\game\machinery\doors\multi_tile_vr.dm"
-#include "code\game\machinery\doors\phoronlocks.dm"
#include "code\game\machinery\doors\unpowered.dm"
#include "code\game\machinery\doors\windowdoor.dm"
+#include "code\game\machinery\doors\airlock\airlock.dm"
+#include "code\game\machinery\doors\airlock\airlock_control.dm"
+#include "code\game\machinery\doors\airlock\airlock_electronics.dm"
+#include "code\game\machinery\doors\airlock\airlock_subtypes.dm"
+#include "code\game\machinery\doors\airlock\airlock_vr.dm"
+#include "code\game\machinery\doors\airlock\alarmlock.dm"
+#include "code\game\machinery\doors\airlock\phoronlocks.dm"
#include "code\game\machinery\embedded_controller\airlock_controllers.dm"
#include "code\game\machinery\embedded_controller\airlock_docking_controller.dm"
#include "code\game\machinery\embedded_controller\airlock_docking_controller_multi.dm"
@@ -1288,7 +1307,6 @@
#include "code\game\machinery\pipe\construction.dm"
#include "code\game\machinery\pipe\pipe_dispenser.dm"
#include "code\game\machinery\pipe\pipe_recipes.dm"
-#include "code\game\machinery\pipe\pipelayer.dm"
#include "code\game\machinery\suit_storage\suit_cycler.dm"
#include "code\game\machinery\suit_storage\suit_storage_massive.dm"
#include "code\game\machinery\suit_storage\suit_storage_prepared.dm"
@@ -1410,10 +1428,12 @@
#include "code\game\mecha\working\working.dm"
#include "code\game\objects\attacks.dm"
#include "code\game\objects\banners.dm"
+#include "code\game\objects\defense.dm"
#include "code\game\objects\empulse.dm"
#include "code\game\objects\explosion.dm"
#include "code\game\objects\explosion_recursive.dm"
#include "code\game\objects\items.dm"
+#include "code\game\objects\materials.dm"
#include "code\game\objects\misc.dm"
#include "code\game\objects\mob_spawner.dm"
#include "code\game\objects\objs.dm"
@@ -1439,7 +1459,6 @@
#include "code\game\objects\effects\step_triggers.dm"
#include "code\game\objects\effects\traps.dm"
#include "code\game\objects\effects\zone_divider.dm"
-#include "code\game\objects\effects\alien\aliens.dm"
#include "code\game\objects\effects\chem\chemsmoke.dm"
#include "code\game\objects\effects\chem\coating.dm"
#include "code\game\objects\effects\chem\foam.dm"
@@ -1494,6 +1513,7 @@
#include "code\game\objects\items\gunbox.dm"
#include "code\game\objects\items\holosign_creator.dm"
#include "code\game\objects\items\inducer.dm"
+#include "code\game\objects\items\inflatables.dm"
#include "code\game\objects\items\latexballoon.dm"
#include "code\game\objects\items\offhand.dm"
#include "code\game\objects\items\paintkit.dm"
@@ -1525,7 +1545,6 @@
#include "code\game\objects\items\circuitboards\machinery\_machine.dm"
#include "code\game\objects\items\circuitboards\machinery\biogenerator.dm"
#include "code\game\objects\items\circuitboards\machinery\cloning.dm"
-#include "code\game\objects\items\circuitboards\machinery\engineering.dm"
#include "code\game\objects\items\circuitboards\machinery\jukebox.dm"
#include "code\game\objects\items\circuitboards\machinery\mech_recharger.dm"
#include "code\game\objects\items\circuitboards\machinery\mining_drill.dm"
@@ -1727,6 +1746,7 @@
#include "code\game\objects\items\weapons\implants\implantrestrainingbolt.dm"
#include "code\game\objects\items\weapons\implants\implantuplink.dm"
#include "code\game\objects\items\weapons\implants\neuralbasic.dm"
+#include "code\game\objects\items\weapons\material\armor.dm"
#include "code\game\objects\items\weapons\material\ashtray.dm"
#include "code\game\objects\items\weapons\material\bats.dm"
#include "code\game\objects\items\weapons\material\chainsaw.dm"
@@ -1734,8 +1754,7 @@
#include "code\game\objects\items\weapons\material\gravemarker.dm"
#include "code\game\objects\items\weapons\material\kitchen.dm"
#include "code\game\objects\items\weapons\material\knives.dm"
-#include "code\game\objects\items\weapons\material\material_armor.dm"
-#include "code\game\objects\items\weapons\material\material_weapons.dm"
+#include "code\game\objects\items\weapons\material\material.dm"
#include "code\game\objects\items\weapons\material\misc.dm"
#include "code\game\objects\items\weapons\material\shards.dm"
#include "code\game\objects\items\weapons\material\swords.dm"
@@ -1759,8 +1778,10 @@
#include "code\game\objects\random\spacesuits.dm"
#include "code\game\objects\random\underdark.dm"
#include "code\game\objects\random\unidentified\medicine.dm"
+#include "code\game\objects\structures\aliens.dm"
#include "code\game\objects\structures\ashlander.dm"
#include "code\game\objects\structures\atmos_tanks.dm"
+#include "code\game\objects\structures\barricade.dm"
#include "code\game\objects\structures\barsign.dm"
#include "code\game\objects\structures\bedsheet_bin.dm"
#include "code\game\objects\structures\bonfire.dm"
@@ -1877,6 +1898,17 @@
#include "code\game\objects\structures\stool_bed_chair_nest\chairs_vr.dm"
#include "code\game\objects\structures\stool_bed_chair_nest\stools.dm"
#include "code\game\objects\structures\stool_bed_chair_nest\wheelchair.dm"
+#include "code\game\objects\structures\tables\bench.dm"
+#include "code\game\objects\structures\tables\defense.dm"
+#include "code\game\objects\structures\tables\flipping.dm"
+#include "code\game\objects\structures\tables\interactions.dm"
+#include "code\game\objects\structures\tables\materials.dm"
+#include "code\game\objects\structures\tables\presets.dm"
+#include "code\game\objects\structures\tables\presets_vr.dm"
+#include "code\game\objects\structures\tables\rack.dm"
+#include "code\game\objects\structures\tables\rack_vr.dm"
+#include "code\game\objects\structures\tables\table.dm"
+#include "code\game\objects\structures\tables\update_triggers.dm"
#include "code\game\objects\systems\_system.dm"
#include "code\game\objects\systems\cell_slot.dm"
#include "code\game\rendering\client.dm"
@@ -1920,6 +1952,7 @@
#include "code\game\rendering\plane_masters\plane_render.dm"
#include "code\game\turfs\baseturfs.dm"
#include "code\game\turfs\change_turf.dm"
+#include "code\game\turfs\defense.dm"
#include "code\game\turfs\simulated.dm"
#include "code\game\turfs\turf.dm"
#include "code\game\turfs\turf_ao.dm"
@@ -1928,40 +1961,42 @@
#include "code\game\turfs\unsimulated.dm"
#include "code\game\turfs\initialization\init.dm"
#include "code\game\turfs\initialization\maintenance.dm"
-#include "code\game\turfs\simulated\floor.dm"
-#include "code\game\turfs\simulated\floor_acts.dm"
-#include "code\game\turfs\simulated\floor_attackby.dm"
-#include "code\game\turfs\simulated\floor_damage.dm"
-#include "code\game\turfs\simulated\floor_icon.dm"
-#include "code\game\turfs\simulated\floor_static.dm"
-#include "code\game\turfs\simulated\floor_types.dm"
-#include "code\game\turfs\simulated\floor_types_eris.dm"
-#include "code\game\turfs\simulated\floor_types_vr.dm"
#include "code\game\turfs\simulated\sky.dm"
-#include "code\game\turfs\simulated\wall.dm"
-#include "code\game\turfs\simulated\wall_attacks.dm"
-#include "code\game\turfs\simulated\wall_composition.dm"
-#include "code\game\turfs\simulated\wall_icon.dm"
-#include "code\game\turfs\simulated\wall_types.dm"
+#include "code\game\turfs\simulated\floor\floor.dm"
+#include "code\game\turfs\simulated\floor\floor_acts.dm"
+#include "code\game\turfs\simulated\floor\floor_attackby.dm"
+#include "code\game\turfs\simulated\floor\floor_damage.dm"
+#include "code\game\turfs\simulated\floor\floor_icon.dm"
+#include "code\game\turfs\simulated\floor\floor_static.dm"
+#include "code\game\turfs\simulated\floor\floor_types.dm"
+#include "code\game\turfs\simulated\floor\floor_types_eris.dm"
+#include "code\game\turfs\simulated\floor\floor_types_vr.dm"
+#include "code\game\turfs\simulated\floor_types\atmoscaves_vr.dm"
+#include "code\game\turfs\simulated\floor_types\concrete.dm"
+#include "code\game\turfs\simulated\floor_types\dirt.dm"
+#include "code\game\turfs\simulated\floor_types\dungeon.dm"
+#include "code\game\turfs\simulated\floor_types\glass.dm"
+#include "code\game\turfs\simulated\floor_types\grass.dm"
+#include "code\game\turfs\simulated\floor_types\lava.dm"
+#include "code\game\turfs\simulated\floor_types\outdoors.dm"
+#include "code\game\turfs\simulated\floor_types\outdoors_attackby.dm"
+#include "code\game\turfs\simulated\floor_types\sky.dm"
+#include "code\game\turfs\simulated\floor_types\snow.dm"
+#include "code\game\turfs\simulated\floor_types\water.dm"
#include "code\game\turfs\simulated\flooring\_flooring.dm"
#include "code\game\turfs\simulated\flooring\flooring_decals.dm"
#include "code\game\turfs\simulated\flooring\flooring_premade.dm"
#include "code\game\turfs\simulated\flooring\flooring_traps.dm"
#include "code\game\turfs\simulated\flooring\shuttle_vr.dm"
-#include "code\game\turfs\simulated\floors\atmoscaves_vr.dm"
-#include "code\game\turfs\simulated\floors\concrete.dm"
-#include "code\game\turfs\simulated\floors\dirt.dm"
-#include "code\game\turfs\simulated\floors\dungeon.dm"
-#include "code\game\turfs\simulated\floors\glass.dm"
-#include "code\game\turfs\simulated\floors\grass.dm"
-#include "code\game\turfs\simulated\floors\lava.dm"
-#include "code\game\turfs\simulated\floors\outdoors.dm"
-#include "code\game\turfs\simulated\floors\outdoors_attackby.dm"
-#include "code\game\turfs\simulated\floors\sky.dm"
-#include "code\game\turfs\simulated\floors\snow.dm"
-#include "code\game\turfs\simulated\floors\water.dm"
#include "code\game\turfs\simulated\misc\fancy_shuttles.dm"
-#include "code\game\turfs\simulated\walls\dungeon.dm"
+#include "code\game\turfs\simulated\wall\defense.dm"
+#include "code\game\turfs\simulated\wall\materials.dm"
+#include "code\game\turfs\simulated\wall\rot.dm"
+#include "code\game\turfs\simulated\wall\wall.dm"
+#include "code\game\turfs\simulated\wall\wall_attacks.dm"
+#include "code\game\turfs\simulated\wall\wall_icon.dm"
+#include "code\game\turfs\simulated\wall_types\dungeon.dm"
+#include "code\game\turfs\simulated\wall_types\wall_types.dm"
#include "code\game\turfs\space\cracked_asteroid.dm"
#include "code\game\turfs\space\space.dm"
#include "code\game\turfs\space\transit.dm"
@@ -2272,7 +2307,6 @@
#include "code\modules\awaymissions\pamphlet.dm"
#include "code\modules\awaymissions\trigger.dm"
#include "code\modules\awaymissions\zlevel.dm"
-#include "code\modules\blob\blob.dm"
#include "code\modules\blob2\_defines.dm"
#include "code\modules\blob2\announcement.dm"
#include "code\modules\blob2\blobs\base_blob.dm"
@@ -3162,16 +3196,19 @@
#include "code\modules\maps\weather\rift_lythios-43c.dm"
#include "code\modules\maps\weather\tether_virgo3b.dm"
#include "code\modules\maps\weather\virgo4.dm"
-#include "code\modules\materials\_materials.dm"
+#include "code\modules\materials\dynamics.dm"
#include "code\modules\materials\fifty_spawner_mats.dm"
+#include "code\modules\materials\material.dm"
#include "code\modules\materials\material_sheets.dm"
#include "code\modules\materials\material_synth.dm"
#include "code\modules\materials\recipes.dm"
-#include "code\modules\materials\definitions\legacy.dm"
+#include "code\modules\materials\stack.dm"
+#include "code\modules\materials\trait.dm"
#include "code\modules\materials\definitions\special.dm"
#include "code\modules\materials\definitions\admin\alienalloy.dm"
#include "code\modules\materials\definitions\crystals\diamond.dm"
#include "code\modules\materials\definitions\crystals\glass.dm"
+#include "code\modules\materials\definitions\elements\carbon.dm"
#include "code\modules\materials\definitions\metals\brass.dm"
#include "code\modules\materials\definitions\metals\bronze.dm"
#include "code\modules\materials\definitions\metals\copper.dm"
@@ -3193,6 +3230,7 @@
#include "code\modules\materials\definitions\misc\plastic.dm"
#include "code\modules\materials\definitions\misc\snow.dm"
#include "code\modules\materials\definitions\misc\wax.dm"
+#include "code\modules\materials\definitions\organic\algae.dm"
#include "code\modules\materials\definitions\organic\bone.dm"
#include "code\modules\materials\definitions\organic\chitin.dm"
#include "code\modules\materials\definitions\organic\cotton.dm"
@@ -3211,6 +3249,13 @@
#include "code\modules\materials\definitions\special\verdantium.dm"
#include "code\modules\materials\definitions\stones\marble.dm"
#include "code\modules\materials\definitions\stones\sandstone.dm"
+#include "code\modules\materials\traits\attack_nullify.dm"
+#include "code\modules\materials\traits\brittle.dm"
+#include "code\modules\materials\traits\glow.dm"
+#include "code\modules\materials\traits\radioactive.dm"
+#include "code\modules\materials\traits\reactive_teleport.dm"
+#include "code\modules\materials\traits\reflective.dm"
+#include "code\modules\materials\traits\supermatter.dm"
#include "code\modules\media\media_machinery.dm"
#include "code\modules\media\media_player_html5.dm"
#include "code\modules\media\media_player_vlc.dm"
@@ -3348,6 +3393,7 @@
#include "code\modules\mob\living\logout.dm"
#include "code\modules\mob\living\mobility.dm"
#include "code\modules\mob\living\movement.dm"
+#include "code\modules\mob\living\offense.dm"
#include "code\modules\mob\living\organs.dm"
#include "code\modules\mob\living\resist.dm"
#include "code\modules\mob\living\say.dm"
@@ -3442,7 +3488,6 @@
#include "code\modules\mob\living\carbon\human\say.dm"
#include "code\modules\mob\living\carbon\human\status_procs.dm"
#include "code\modules\mob\living\carbon\human\stripping.dm"
-#include "code\modules\mob\living\carbon\human\unarmed_attack.dm"
#include "code\modules\mob\living\carbon\human\update_icons.dm"
#include "code\modules\mob\living\carbon\human\ai_controlled\ai_controlled.dm"
#include "code\modules\mob\living\carbon\human\descriptors\_descriptors.dm"
@@ -3461,6 +3506,7 @@
#include "code\modules\mob\living\silicon\examine.dm"
#include "code\modules\mob\living\silicon\laws.dm"
#include "code\modules\mob\living\silicon\login.dm"
+#include "code\modules\mob\living\silicon\offense.dm"
#include "code\modules\mob\living\silicon\perspective.dm"
#include "code\modules\mob\living\silicon\say.dm"
#include "code\modules\mob\living\silicon\silicon.dm"
@@ -3630,11 +3676,11 @@
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\carp_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\gaslamp_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\goose.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\space\horing.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\mouse_army.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\snake_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\space.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\space_vr.dm"
-#include "code\modules\mob\living\simple_mob\subtypes\animal\space\thrumbo.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\worm.dm"
#include "code\modules\mob\living\simple_mob\subtypes\blob\blob.dm"
#include "code\modules\mob\living\simple_mob\subtypes\blob\spore.dm"
@@ -4631,15 +4677,6 @@
#include "code\modules\surgery\robotics.dm"
#include "code\modules\surgery\surgery.dm"
#include "code\modules\surgery\~defines.dm"
-#include "code\modules\tables\bench.dm"
-#include "code\modules\tables\flipping.dm"
-#include "code\modules\tables\interactions.dm"
-#include "code\modules\tables\presets.dm"
-#include "code\modules\tables\presets_vr.dm"
-#include "code\modules\tables\rack.dm"
-#include "code\modules\tables\rack_vr.dm"
-#include "code\modules\tables\tables.dm"
-#include "code\modules\tables\update_triggers.dm"
#include "code\modules\telesci\bscyrstal.dm"
#include "code\modules\telesci\construction.dm"
#include "code\modules\telesci\hyper_pad.dm"
diff --git a/code/__DEFINES/_core.dm b/code/__DEFINES/_core.dm
index d311a97e88d..041c95757dc 100644
--- a/code/__DEFINES/_core.dm
+++ b/code/__DEFINES/_core.dm
@@ -11,3 +11,6 @@
/// * call a new proc so the originating trace isn't from the original file anymore
/// * put the stack trace in stack trace storage
#define stack_trace(message) _stack_trace(message, __FILE__, __LINE__)
+
+/// byond bug https://secure.byond.com/forum/?post=2072419
+#define BLOCK_BYOND_BUG_2072419
diff --git a/code/__DEFINES/_flags/atom_flags.dm b/code/__DEFINES/_flags/atom_flags.dm
index afb4dec9521..e6bb75e57b3 100644
--- a/code/__DEFINES/_flags/atom_flags.dm
+++ b/code/__DEFINES/_flags/atom_flags.dm
@@ -1,18 +1,16 @@
-//! FLAG BITMASKS - Used in /atom/var/flags
+//? FLAG BITMASKS - Used in /atom/var/flags
/// The atom is initialized
#define ATOM_INITIALIZED (1<<0)
/// Item has priority to check when entering or leaving.
#define ATOM_BORDER (1<<1)
-/// Atom is admin spawned
-#define ATOM_ADMINSPAWNED (1<<2)
/// get_hearers_in_view() returns us, meaning we intercept usually for-players messages. Mobs, mechas, etc should all have this!
-#define ATOM_HEAR (1<<3)
+#define ATOM_HEAR (1<<2)
/// Atom queued to SSoverlay for compile_overlays
-#define ATOM_OVERLAY_QUEUED (1<<4)
+#define ATOM_OVERLAY_QUEUED (1<<3)
/// Atom is absolute-abstract - should not be interactable or movable in any way shape or form
-#define ATOM_ABSTRACT (1<<5)
-/// We are an holographic atom from a holodeck/AR system
-#define HOLOGRAM (1<<6) // TODO: should this be an atom flag?
+#define ATOM_ABSTRACT (1<<4)
+/// uses integrity, and is broken
+#define ATOM_BROKEN (1<<5)
/// Used for items if they don't want to get a blood overlay.
#define NOBLOODY (1<<7) // TODO: item flag
/// Reagents don't react inside this container.
@@ -25,6 +23,7 @@
#define PHORONGUARD (1<<11) // TODO: item flag
/// Does not leave user's fingerprints/fibers when used on things?
#define NOPRINT (1<<12) // TODO: item flag
+
///CITMAIN FLAG BITMASKS - Completely unused.
/*
/// Early returns mob.face_atom()
@@ -40,26 +39,29 @@
/// should not get harmed if this gets caught by an explosion?
#define PREVENT_CONTENTS_EXPLOSION (1<<22)
*/
-#define HTML_USE_INITIAL_ICON (1<<23)
+/// We are ticking in materials
+#define ATOM_MATERIALS_TICKING (1<<22)
+/// Use initial icon/icon state for HTML renders in things like VV
+#define ATOM_HTML_INITIAL_ICON (1<<23)
DEFINE_BITFIELD(atom_flags, list(
BITFIELD(ATOM_INITIALIZED),
BITFIELD(ATOM_BORDER),
- BITFIELD(ATOM_ADMINSPAWNED),
BITFIELD(ATOM_HEAR),
BITFIELD(ATOM_OVERLAY_QUEUED),
BITFIELD(ATOM_ABSTRACT),
- BITFIELD(HOLOGRAM),
+ BITFIELD(ATOM_BROKEN),
BITFIELD(NOBLOODY),
BITFIELD(NOREACT),
BITFIELD(NOCONDUCT),
BITFIELD(OPENCONTAINER),
BITFIELD(PHORONGUARD),
BITFIELD(NOPRINT),
- BITFIELD(HTML_USE_INITIAL_ICON),
+ BITFIELD(ATOM_MATERIALS_TICKING),
+ BITFIELD(ATOM_HTML_INITIAL_ICON),
))
-//! /atom/movable/var/movable_flags
+//? /atom/movable/var/movable_flags
/// Throwing does not scale damage at all regardless of force.
#define MOVABLE_NO_THROW_SPEED_SCALING (1<<0)
/// Throwing should ignore move force scaling entirely.
@@ -140,7 +142,34 @@ DEFINE_BITFIELD(movement_type, list(
BITFIELD(MOVEMENT_FLOATING),
))
-//! /atom/movable buckle_flags
+//? /atom integrity_flags
+/// cannot be broken, period
+#define INTEGRITY_INDESTRUCTIBLE (1<<0)
+/// completely immune to fire, can't even light
+#define INTEGRITY_FIREPROOF (1<<1)
+/// completely immune to acid, can't even have it stick
+#define INTEGRITY_ACIDPROOF (1<<2)
+/// completely immune to lava
+#define INTEGRITY_LAVAPROOF (1<<3)
+/// don't delete on atom_destruction()
+/// be very careful with this flag, as atom_destruction()
+/// will keep being called every time it gets damaged while 0 integrity!
+#define INTEGRITY_NO_DECONSTRUCT (1<<4)
+/// flammable by dynamic atom fire
+/// this is opt in as a flag so people have to think about it before throwing it onto things.
+/// <--- clueless comment author
+#define INTEGRITY_FLAMMABLE (1<<5)
+
+DEFINE_BITFIELD(integrity_flags, list(
+ BITFIELD(INTEGRITY_INDESTRUCTIBLE),
+ BITFIELD(INTEGRITY_FIREPROOF),
+ BITFIELD(INTEGRITY_ACIDPROOF),
+ BITFIELD(INTEGRITY_LAVAPROOF),
+ BITFIELD(INTEGRITY_NO_DECONSTRUCT),
+ BITFIELD(INTEGRITY_FLAMMABLE),
+))
+
+//? /atom/movable buckle_flags
/// Requires restrained() (usually handcuffs) to work.
#define BUCKLING_REQUIRES_RESTRAINTS (1<<0)
/// Buckling doesn't allow you to pull the person to try to move the object (assuming the object otherwise can be pulled). This does NOT stop them from pulling the buckled object!
diff --git a/code/__DEFINES/_flags/obj_flags.dm b/code/__DEFINES/_flags/obj_flags.dm
index e042a35136e..d002e89ea78 100644
--- a/code/__DEFINES/_flags/obj_flags.dm
+++ b/code/__DEFINES/_flags/obj_flags.dm
@@ -1,22 +1,37 @@
// Flags for the obj_flags var on /obj
/// we're emagged
-#define EMAGGED (1<<0)
-/// can this be bludgeoned by items?
-#define CAN_BE_HIT (1<<1)
-/// Are we visible on the station blueprints at roundstart?
-#define ON_BLUEPRINTS (1<<2)
+#define OBJ_EMAGGED (1<<0)
/// Prevent people from clicking under us
-#define OBJ_PREVENT_CLICK_UNDER (1<<3)
+#define OBJ_PREVENT_CLICK_UNDER (1<<1)
+/// Are we visible on the station blueprints at roundstart?
+#define OBJ_ON_BLUEPRINTS (1<<2)
+/// can be targeted in melee
+#define OBJ_MELEE_TARGETABLE (1<<3)
+/// can be targeted by projectiles
+#define OBJ_RANGE_TARGETABLE (1<<4)
+/// is a hologram
+#define OBJ_HOLOGRAM (1<<5)
/// We ignore depth system when blocking mobs
-#define OBJ_IGNORE_MOB_DEPTH (1<<4)
+#define OBJ_IGNORE_MOB_DEPTH (1<<6)
+/// Base materials have been modified
+#define OBJ_MATERIALS_MODIFIED (1<<7)
+/// Material parts have been modified
+#define OBJ_MATERIAL_PARTS_MODIFIED (1<<8)
+/// Materials have been initialized
+#define OBJ_MATERIAL_INITIALIZED (1<<9)
/// no sculpting
-#define OBJ_NO_SCULPTING (1<<5)
+#define OBJ_NO_SCULPTING (1<<10)
DEFINE_BITFIELD(obj_flags, list(
- BITFIELD(EMAGGED),
- BITFIELD(CAN_BE_HIT),
- BITFIELD(ON_BLUEPRINTS),
+ BITFIELD(OBJ_EMAGGED),
BITFIELD(OBJ_PREVENT_CLICK_UNDER),
+ BITFIELD(OBJ_ON_BLUEPRINTS),
+ BITFIELD(OBJ_MELEE_TARGETABLE),
+ BITFIELD(OBJ_RANGE_TARGETABLE),
+ BITFIELD(OBJ_HOLOGRAM),
BITFIELD(OBJ_IGNORE_MOB_DEPTH),
+ BITFIELD(OBJ_MATERIALS_MODIFIED),
+ BITFIELD(OBJ_MATERIAL_PARTS_MODIFIED),
+ BITFIELD(OBJ_MATERIAL_INITIALIZED),
BITFIELD(OBJ_NO_SCULPTING),
))
diff --git a/code/__DEFINES/combat/armor.dm b/code/__DEFINES/combat/armor.dm
index 2ec42e7e1db..f57d5e4f6f2 100644
--- a/code/__DEFINES/combat/armor.dm
+++ b/code/__DEFINES/combat/armor.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
//? --- armor defines ---
//* Want to add more?
//* Update [code/__HELPERS/datastructs/armor.dm]
@@ -6,17 +9,22 @@
//* The system will handle the rest.
//* Make sure the var names match the names in here!
+// todo: change melee/bullet to blunt/slash/pierce
+
//? Tiered - used to model attacks - stacked with tier system when layered.
#define ARMOR_MELEE "melee"
#define ARMOR_MELEE_TIER "melee_t"
#define ARMOR_MELEE_SOAK "melee_s"
+#define ARMOR_MELEE_DEFLECT "melee_d"
#define ARMOR_BULLET "bullet"
#define ARMOR_BULLET_TIER "bullet_t"
#define ARMOR_BULLET_SOAK "bullet_s"
+#define ARMOR_BULLET_DEFLECT "bullet_d"
#define ARMOR_LASER "laser"
#define ARMOR_LASER_TIER "laser_t"
#define ARMOR_LASER_SOAK "laser_s"
+#define ARMOR_LASER_DEFLECT "laser_d"
//? Flat - stacked multiplicatively when layered
//? Standalone:
@@ -27,48 +35,84 @@
#define ARMOR_BOMB "bomb"
#define ARMOR_BIO "bio"
#define ARMOR_RAD "rad"
+#define ARMOR_FIRE "fire"
+#define ARMOR_ACID "acid"
GLOBAL_REAL_LIST(armor_enums) = list(
ARMOR_MELEE,
ARMOR_MELEE_TIER,
ARMOR_MELEE_SOAK,
+ ARMOR_MELEE_DEFLECT,
ARMOR_BULLET,
ARMOR_BULLET_TIER,
ARMOR_BULLET_SOAK,
+ ARMOR_BULLET_DEFLECT,
ARMOR_LASER,
ARMOR_LASER_TIER,
ARMOR_LASER_SOAK,
+ ARMOR_LASER_DEFLECT,
ARMOR_ENERGY,
ARMOR_BOMB,
ARMOR_BIO,
ARMOR_RAD,
+ ARMOR_FIRE,
+ ARMOR_ACID,
)
//? --- armor tiers ---
+#define ARMOR_TIER_DEFAULT 0
+
#define ARMOR_TIER_LAUGHABLE -3
#define ARMOR_TIER_LOW -2
#define ARMOR_TIER_BELOW -1
-#define ARMOR_TIER_DEFAULT 0
+#define ARMOR_TIER_NORMAL 0
#define ARMOR_TIER_ABOVE 1
#define ARMOR_TIER_HIGH 2
#define ARMOR_TIER_OVERWHELMING 3
+#define ARMOR_TIER_RIDICULOUS 4
+
+#define ARMOR_BARELY_BEATS(other) (other + 0.001)
//? melee
-#define MELEE_TIER_UNARMED_FISTS -1
-#define MELEE_TIER_UNARMED_CLAW 0
#define MELEE_TIER_DEFAULT ARMOR_TIER_DEFAULT
+#define MELEE_TIER_UNARMED_DEFAULT ARMOR_TIER_LOW
+#define MELEE_TIER_UNARMED_FISTS ARMOR_TIER_LOW
+#define MELEE_TIER_UNARMED_CLAW ARMOR_TIER_BELOW
+#define MELEE_TIER_LIGHT ARMOR_TIER_DEFAULT
+#define MELEE_TIER_MEDIUM ARMOR_TIER_ABOVE
+#define MELEE_TIER_HEAVY ARMOR_TIER_HIGH
+#define MELEE_TIER_EXTREME ARMOR_TIER_OVERWHELMING
+
//? bullet
#define BULLET_TIER_DEFAULT ARMOR_TIER_DEFAULT
+#define BULLET_TIER_LAUGHABLE ARMOR_TIER_BELOW //! super improvised rounds / pistols / whatever.
+#define BULLET_TIER_LOW ARMOR_TIER_DEFAULT //! pistols
+#define BULLET_TIER_MEDIUM ARMOR_TIER_ABOVE //! smgs
+#define BULLET_TIER_HIGH ARMOR_TIER_HIGH //! rifles
+#define BULLET_TIER_EXTREME ARMOR_TIER_OVERWHELMING //! lmgs, light mech weapons
+#define BULLET_TIER_RIDICULOUS ARMOR_TIER_RIDICULOUS //! heavy mech weapons
+
//? laser
#define LASER_TIER_DEFAULT ARMOR_TIER_DEFAULT
+#define LASER_TIER_LAUGHABLE ARMOR_TIER_BELOW //! improvised laser focis / etc
+#define LASER_TIER_LOW ARMOR_TIER_DEFAULT //! low tier lasers
+#define LASER_TIER_MEDIUM ARMOR_TIER_ABOVE //! laser carbines, energy guns, etc
+#define LASER_TIER_HIGH ARMOR_TIER_HIGH //! x-ray rifles, snipers
+#define LASER_TIER_EXTREME ARMOR_TIER_OVERWHELMING //! mech weapons, usualy
+#define LASER_TIER_RIDICULOUS ARMOR_TIER_RIDICULOUS //! power transmission laser?
+
//? --- armor calculations ---
/// tierdiff is tier difference of armor against attack; positive = armor is higher tier.
-#define ARMOR_TIER_CALC(_armor, _tierdiff) ((_tierdiff) > 0? ((_armor) ** (1 / (1 + (_tierdiff)))) : ((_armor) * (1 / (1 - (_tierdiff)))))
+#define ARMOR_TIER_CALC(_armor, _tierdiff) \
+(_armor > 0? \
+ ((_tierdiff) > 0? ((_armor) ** (1 / (1 + (_tierdiff)))) : ((_armor) * (1 / (1 - (_tierdiff))))) : \
+ (_armor) \
+)
diff --git a/code/__DEFINES/combat/atom_damage.dm b/code/__DEFINES/combat/atom_damage.dm
index 5dd16daa4db..9c23b91e86d 100644
--- a/code/__DEFINES/combat/atom_damage.dm
+++ b/code/__DEFINES/combat/atom_damage.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
//! Atom destruction types, used in /deconstruct() and its derived/child/called functions.
/// Atom was neatly deconstructed
#define ATOM_DECONSTRUCT_DISASSEMBLED 0
@@ -7,5 +10,3 @@
#define ATOM_DECONSTRUCT_ACID 2
/// Atom was put out of commission by an unexpected thermal event
#define ATOM_DECONSTRUCT_FIRE 3
-
-
diff --git a/code/__DEFINES/combat/attack_types.dm b/code/__DEFINES/combat/attack_types.dm
index 44645219134..26989b0a23c 100644
--- a/code/__DEFINES/combat/attack_types.dm
+++ b/code/__DEFINES/combat/attack_types.dm
@@ -1,6 +1,11 @@
-//? attack_type bitfield
+//? attack_type bitfield - bitfield for check, but pass only one in at a time.
+#define ATTACK_TYPE_NONE (0)
+/// damage source is /obj/item
#define ATTACK_TYPE_MELEE (1<<0)
+/// damage source is /obj/projectile
#define ATTACK_TYPE_PROJECTILE (1<<1)
+/// damage source is /datum/thrownthing
#define ATTACK_TYPE_THROWN (1<<2)
+/// damage source is /mob
#define ATTACK_TYPE_UNARMED (1<<3)
diff --git a/code/__DEFINES/combat/damage.dm b/code/__DEFINES/combat/damage.dm
index fcdfc643e9c..335ea3ae37a 100644
--- a/code/__DEFINES/combat/damage.dm
+++ b/code/__DEFINES/combat/damage.dm
@@ -1,7 +1,14 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
//? damage types
// todo: refactor damage types
//? damage_mode bitfield
-// none yet
+#define DAMAGE_MODE_SHARP (1<<0) //! sharp weapons like knives, spears, etc
+#define DAMAGE_MODE_EDGE (1<<1) //! weapons with an edge, like knives, being used as such. without this, sharp = pierce
+#define DAMAGE_MODE_ABLATING (1<<2) //! pulse lasers, etc, basically blows a crater
+#define DAMAGE_MODE_PIERCE (1<<3) //! specifically highly-piercing weapons like bullets, even worse than sharp.
+#define DAMAGE_MODE_SHRED (1<<4) //! messy, shredded wounds instead of a clean cut / pierce. strong.
diff --git a/code/__DEFINES/combat/explosions.dm b/code/__DEFINES/combat/explosions.dm
index c0b2b11e061..c8709ccfd8a 100644
--- a/code/__DEFINES/combat/explosions.dm
+++ b/code/__DEFINES/combat/explosions.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
//! Global balancing numbers; everything should derive off of these so we can adjust everything at once.
/// global default multiplier for falloff factor
#define EXPLOSION_FALLOFF_FACTOR 1
@@ -19,6 +22,11 @@
#define LEGACY_EXPLOSION_SEVERE_POWER EXPLOSION_CONSTANT_SEVERE
#define LEGACY_EXPLOSION_MINOR_POWER EXPLOSION_CONSTANT_MINOR
+#define LEGACY_EXPLOSION_DEVASTATE_INTEGRITY 1000
+#define LEGACY_EXPLOSION_SEVERE_INTEGRITY 180
+#define LEGACY_EXPLOSION_MINOR_INTEGRITY 50
+#define LEGACY_EXPLOSION_INTEGRITY_MULT (0.01 * rand(50, 200))
+
// why the extra numbers? so if someone does weird math we don't out of bounds
GLOBAL_REAL(_legacy_expowers, /list) = list(
LEGACY_EXPLOSION_DEVASTATE_POWER,
@@ -29,5 +37,17 @@ GLOBAL_REAL(_legacy_expowers, /list) = list(
0
)
+// ditto
+GLOBAL_REAL(_legacy_ex_atom_damage, /list) = list(
+ LEGACY_EXPLOSION_DEVASTATE_INTEGRITY,
+ LEGACY_EXPLOSION_SEVERE_INTEGRITY,
+ LEGACY_EXPLOSION_MINOR_INTEGRITY,
+ 0,
+ 0,
+ 0
+)
+
+#define LEGACY_EXPLOSION_ATOM_DAMAGE(P) (global._legacy_ex_atom_damage[P] * LEGACY_EXPLOSION_INTEGRITY_MULT)
+
// this works out becuase epxlosions are 1-3 in legacy, so we can just use it as list indices
#define LEGACY_EX_ACT(ATOM, POWER, TARGET) ATOM.legacy_ex_act(POWER, TARGET); ATOM.ex_act(_legacy_expowers[POWER]);
diff --git a/code/__DEFINES/combat/shieldcall.dm b/code/__DEFINES/combat/shieldcall.dm
new file mode 100644
index 00000000000..889d27cad26
--- /dev/null
+++ b/code/__DEFINES/combat/shieldcall.dm
@@ -0,0 +1,44 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
+//? keys for list/additional in atom_shieldcall
+
+// None yet
+
+//? shieldcall "struct" - this *must* match up with /atom/proc/run/check_shieldcall!
+
+/// damage amount
+#define SHIELDCALL_ARG_DAMAGE 1
+/// damage type
+#define SHIELDCALL_ARG_DAMTYPE 2
+/// damage tier
+#define SHIELDCALL_ARG_TIER 3
+/// armor flag
+#define SHIELDCALL_ARG_FLAG 4
+/// damage mode
+#define SHIELDCALL_ARG_MODE 5
+/// attack type
+#define SHIELDCALL_ARG_TYPE 6
+/// attacking weapon datum - same as used in armor
+#define SHIELDCALL_ARG_WEAPON 7
+/// list for additional data
+#define SHIELDCALL_ARG_ADDITIONAL 8
+/// flags returned
+#define SHIELDCALL_ARG_RETVAL 9
+
+//? shieldcall additional data keys
+
+// none yet
+
+//? shieldcall return flags
+
+/// abort further shieldcalls - hit is totally blocked or mitigated
+#define SHIELDCALL_FULLY_MITIGATED (1<<0)
+/// hit was partially blocked or mitigated
+#define SHIELDCALL_PARTIALLY_MITIGATED (1<<1)
+/// attack was forcefully missed e.g. by reactive teleport armor
+#define SHIELDCALL_FORCED_MISS (1<<2)
+/// fake; this is a check
+#define SHIELDCALL_JUST_CHECKING (1<<3)
+/// terminate further shieldcalls
+#define SHIELDCALL_CEASE (1<<4)
diff --git a/code/__DEFINES/controllers/_repositories.dm b/code/__DEFINES/controllers/_repositories.dm
index 4a4573a2aa9..a901c80f4d1 100644
--- a/code/__DEFINES/controllers/_repositories.dm
+++ b/code/__DEFINES/controllers/_repositories.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
//* This is here in [code/__DEFINES/controllers/_repositories.dm] for compile order reasons. *//
/datum/controller/subsystem/repository/proc/__init_repositories()
diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_defense.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_defense.dm
index d9e09336065..fbe58fa32a6 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_defense.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_defense.dm
@@ -1,38 +1,4 @@
-//? shieldcall signals - these gather what to call on.
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
-/// runs shield checks - from base of /atom/proc/atom_shieldcall: (list/considering)
-#define COMSIG_ATOM_SHIELDCALL "atom_shieldcall"
-
-//? shieldcall "struct" - this *must* match up with /atom/proc/run/check_shieldcall!
-
-/// damage amount
-#define SHIELDCALL_ARG_DAMAGE 1
-/// damage tier
-#define SHIELDCALL_ARG_TIER 2
-/// armor flag
-#define SHIELDCALL_ARG_FLAG 3
-/// damage mode
-#define SHIELDCALL_ARG_MODE 4
-/// attack type
-#define SHIELDCALL_ARG_TYPE 5
-/// attacking weapon datum - same as used in armor
-#define SHIELDCALL_ARG_WEAPON 6
-/// list for additional data
-#define SHIELDCALL_ARG_ADDITIONAL 7
-/// flags returned
-#define SHIELDCALL_ARG_RETVAL 8
-
-//? shieldcall additional data keys
-
-// none yet
-
-//? shieldcall return flags
-
-/// abort further shieldcalls - hit is totally blocked or mitigated
-#define SHIELDCALL_FULLY_MITIGATED (1<<0)
-/// hit was partially blocked or mitigated
-#define SHIELDCALL_PARTIALLY_MITIGATED (1<<1)
-/// attack was forcefully missed e.g. by reactive teleport armor
-#define SHIELDCALL_FORCED_MISS (1<<2)
-/// fake; this is a check
-#define SHIELDCALL_JUST_CHECKING (1<<3)
+// todo: this file left intentionally empty since shieldcalls were moved to datums
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 e6cad3647e4..c8275ee9125 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
@@ -48,6 +48,3 @@
/// When the transform or an atom is varedited through vv topic.
////#define COMSIG_ATOM_VV_MODIFY_TRANSFORM "atom_vv_modify_transform"
-
-/// Generally called before temporary non-parallel animate()s on the atom (animation_duration)
-////#define COMSIG_ATOM_TEMPORARY_ANIMATION_START "atom_temp_animate_start"
diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_visuals.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_visuals.dm
index 3f38df72abe..8c1d29c8f2a 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_visuals.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_visuals.dm
@@ -5,4 +5,5 @@
*/
/// generally called before temporary non-parallel animate()s on the atom (animation_duration)
-#define COMSIG_ATOM_TEMPORARY_ANIMATION_START "atom_temp_animate_start"
+// todo: this is a good idea but not going to be implemented this way.
+// #define COMSIG_ATOM_TEMPORARY_ANIMATION_START "atom_temp_animate_start"
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_defense.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_defense.dm
new file mode 100644
index 00000000000..18bfbe019bc
--- /dev/null
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_defense.dm
@@ -0,0 +1,4 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
+// todo: COMSIG_MOB_SHIELDCALL: prioritizes above atom shieldcall
diff --git a/code/__DEFINES/materials/attributes.dm b/code/__DEFINES/materials/attributes.dm
new file mode 100644
index 00000000000..f7114d6b0ce
--- /dev/null
+++ b/code/__DEFINES/materials/attributes.dm
@@ -0,0 +1,74 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
+//? master file for balancing / efficiency tuning
+
+//* Efficiency
+
+/// scale a lathe's efficiency to upgrade level
+#define MATERIAL_EFFICIENCY_LATHE_SCALE(tier) max(0, 1.1 - tier * 0.1)
+
+//* Attributes - Resistance
+
+/// used to signify an interpolation, with 'HOW_MUCH' being a linear gradient of how far between it is from B1 to B2
+#define MATERIAL_RESISTANCE_BETWEEN(B1, B2, HOW_MUCH) (B1 + (B2 - B1) * HOW_MUCH)
+
+/// the level at which vulnerability is comedically high
+#define MATERIAL_RESISTANCE_CATASTROPHICALLY_VULNERABLE -800
+#define MATERIAL_RESISTANCE_ABOVE_CATASTROPHICALLY_VULNERABLE(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_CATASTROPHICALLY_VULNERABLE, MATERIAL_RESISTANCE_SUPER_VULNERABLE, HOW_MUCH)
+/// the level at which vulnerability is very high
+#define MATERIAL_RESISTANCE_SUPER_VULNERABLE -400
+#define MATERIAL_RESISTANCE_ABOVE_SUPER_VULNERABLE(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_SUPER_VULNERABLE, MATERIAL_RESISTANCE_VERY_VULNERABLE, HOW_MUCH)
+/// the level at which vulnerability is high
+#define MATERIAL_RESISTANCE_VERY_VULNERABLE -200
+#define MATERIAL_RESISTANCE_ABOVE_VERY_VULNERABLE(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_VERY_VULNERABLE, MATERIAL_RESISTANCE_VULNERABLE, HOW_MUCH)
+/// the level at which vulnerability is high
+#define MATERIAL_RESISTANCE_VULNERABLE -100
+#define MATERIAL_RESISTANCE_ABOVE_VULNERABLE(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_VULNERABLE, MATERIAL_RESISTANCE_SOMEWHAT_VULNERABLE, HOW_MUCH)
+/// the level at which vulnerability is present
+#define MATERIAL_RESISTANCE_SOMEWHAT_VULNERABLE -50
+#define MATERIAL_RESISTANCE_ABOVE_SOMEWHAT_VULNERABLE(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_SOMEWHAT_VULNERABLE, MATERIAL_RESISTANCE_NEGLIGIBLY_VULNERABLE, HOW_MUCH)
+/// the level at which vulnerability is slightly there
+#define MATERIAL_RESISTANCE_NEGLIGIBLY_VULNERABLE -25
+#define MATERIAL_RESISTANCE_ABOVE_NEGLIGIBLY_VULNERABLE(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_NEGLIGIBLY_VULNERABLE, MATERIAL_RESISTANCE_NONE, HOW_MUCH)
+/// baseline MATERIAL_RESISTANCE for nothing
+#define MATERIAL_RESISTANCE_NONE 0
+#define MATERIAL_RESISTANCE_ABOVE_NONE(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_NONE, MATERIAL_RESISTANCE_NEGLIGIBLE, HOW_MUCH)
+/// the level at which resistance is barely there
+#define MATERIAL_RESISTANCE_NEGLIGIBLE 25
+#define MATERIAL_RESISTANCE_ABOVE_NEGLIGIBLE(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_NEGLIGIBLE, MATERIAL_RESISTANCE_LOW, HOW_MUCH)
+/// the level at which resistance is workable
+#define MATERIAL_RESISTANCE_LOW 50
+#define MATERIAL_RESISTANCE_ABOVE_LOW(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_LOW, MATERIAL_RESISTANCE_MODERATE, HOW_MUCH)
+/// the level at which resistance is good
+#define MATERIAL_RESISTANCE_MODERATE 100
+#define MATERIAL_RESISTANCE_ABOVE_MODERATE(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_MODERATE, MATERIAL_RESISTANCE_HIGH, HOW_MUCH)
+/// the level at which resistance is high
+#define MATERIAL_RESISTANCE_HIGH 200
+#define MATERIAL_RESISTANCE_ABOVE_HIGH(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_HIGH, MATERIAL_RESISTANCE_EXTREME, HOW_MUCH)
+/// the level at which resistance is very high
+#define MATERIAL_RESISTANCE_EXTREME 400
+#define MATERIAL_RESISTANCE_ABOVE_EXTREME(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_EXTREME, MATERIAL_RESISTANCE_IMPERMEABLE, HOW_MUCH)
+/// the level at which resistance is nearly impermeable
+#define MATERIAL_RESISTANCE_IMPERMEABLE 800
+#define MATERIAL_RESISTANCE_ABOVE_IMPERMEABLE(HOW_MUCH) MATERIAL_RESISTANCE_BETWEEN(MATERIAL_RESISTANCE_IMPERMEABLE, 1600, HOW_MUCH)
+
+//* Conductvitiy
+/// relative_conductivity threshold considered NOCONDUCT
+#define MATERIAL_CONDUCTIVITY_NOCONDUCT 0.05
+
+//* Opacity
+
+/// threshold for block
+#define MATERIAL_OPACITY_THRESHOLD 0.6
+/// opacity to alpha; uses quadratic falloff and a constant because we don't want stuff to just be invisible
+#define MATERIAL_OPACITY_TO_ALPHA(opacity) max((255 * (1 - (1 - opacity)**2)), 25)
+
+//* Radioactivity
+
+#define MATERIAL_RADIOACTIVITY_MULTIPLIER_WALL 1.5
+#define MATERIAL_RADIOACTIVITY_MULTIPLIER_GIRDER 1
+#define MATERIAL_RADIOACTIVITY_MULTIPLIER_NORMAL 1
+#define MATERIAL_RADIOACTIVITY_MULTIPLIER_GRILLE 0.33
+#define MATERIAL_RADIOACTIVITY_MULTIPLIER_ITEM 0.25
+#define MATERIAL_RADIOACTIVITY_MULTIPLIER_SHARD 0.25
diff --git a/code/__DEFINES/materials/balancing.dm b/code/__DEFINES/materials/balancing.dm
deleted file mode 100644
index 13f0a822054..00000000000
--- a/code/__DEFINES/materials/balancing.dm
+++ /dev/null
@@ -1,6 +0,0 @@
-//? master file for balancing / efficiency tuning
-
-//* efficiency
-
-/// scale a lathe's efficiency to upgrade level
-#define MATERIAL_EFFICIENCY_LATHE_SCALE(tier) max(0, 1.1 - tier * 0.1)
diff --git a/code/__DEFINES/materials/dynamics.dm b/code/__DEFINES/materials/dynamics.dm
new file mode 100644
index 00000000000..62be496d389
--- /dev/null
+++ b/code/__DEFINES/materials/dynamics.dm
@@ -0,0 +1,77 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
+//* Significance; This is how much material is in something
+
+/// used for shards
+#define MATERIAL_SIGNIFICANCE_SHARD 3.5
+/// baseline significance of material calculations done on material-side / default computations
+#define MATERIAL_SIGNIFICANCE_BASELINE 10
+
+#define MATERIAL_SIGNIFICANCE_WEAPON_ULTRALIGHT 6
+#define MATERIAL_SIGNIFICANCE_WEAPON_LIGHT 8.5
+#define MATERIAL_SIGNIFICANCE_WEAPON_MEDIUM 10
+#define MATERIAL_SIGNIFICANCE_WEAPON_HEAVY 15
+#define MATERIAL_SIGNIFICANCE_WEAPON_SUPERHEAVY 20
+
+#define MATERIAL_SIGNIFICANCE_ARMOR_LIGHT 7.5
+#define MATERIAL_SIGNIFICANCE_ARMOR_MEDIUM 10
+#define MATERIAL_SIGNIFICANCE_ARMOR_HEAVY 15
+
+/// used for most doors
+#define MATERIAL_SIGNIFICANCE_DOOR 20
+/// significance used for normal wall layer
+#define MATERIAL_SIGNIFICANCE_WALL 20
+//? we are using a higher value because we max(), so reinf lets you basically combine another mat's armor.
+//? this should be dropped to 10 later when we get a new algorithm.
+/// significance used for reinforcing wall layer
+#define MATERIAL_SIGNIFICANCE_WALL_REINF 17.5
+/// significance used for girder wall layer
+#define MATERIAL_SIGNIFICANCE_WALL_GIRDER 5
+
+#define MATERIAL_SIGNIFICANCE_TABLE_STRUCTURE 10
+#define MATERIAL_SIGNIFICANCE_TABLE_REINFORCEMENT 7.5
+
+//* Uh Oh. *//
+//! WARNING: HERE BE DRAGONS !//
+//! Here's the core values for the current material dynamics system !//
+//! Material dynamics is in charge of assigning damage and armor values to things using materials. !//
+//! This will be documented as well as possible but understand that it's all a bit arbitrary. !//
+
+//* desmos graphs:
+//* v1 material damage https://www.desmos.com/calculator/dzyyj0vpem
+//* v2 material damage https://www.desmos.com/calculator/awyudtcm6e <-- CURRENT
+
+/// upper curve
+#define MATERIAL_DYNAMICS_DAMAGE_CEILING 30
+/// logistic constant
+#define MATERIAL_DYNAMICS_DAMAGE_LOGISTIC 0.04
+/// divisor
+#define MATERIAL_DYNAMICS_DAMAGE_DIVISOR 7
+/// multiplier to x
+#define MATERIAL_DYNAMICS_DAMAGE_INTENSIFIER 1
+/// shift to x after multiply
+#define MATERIAL_DYNAMICS_DAMAGE_SHIFT 185
+
+
+#define MATERIAL_DENSITY_TO_DAMAGE_INTENSIFIER(DENS) max(0, log(10, DENS/2 + 1))
+#define MATERIAL_SIGNIFICANCE_TO_DAMAGE_INTENSIFIER(SIG) max(0, (SIG > MATERIAL_SIGNIFICANCE_BASELINE)? ((SIG - MATERIAL_SIGNIFICANCE_BASELINE) / MATERIAL_SIGNIFICANCE_BASELINE + 1) : (SIG / MATERIAL_SIGNIFICANCE_BASELINE))
+
+/// upper curve
+#define MATERIAL_DYNAMICS_DAMTIER_CEILING 45.5
+/// logistic constant
+#define MATERIAL_DYNAMICS_DAMTIER_LOGISTIC 0.005
+/// divisor
+#define MATERIAL_DYNAMICS_DAMTIER_DIVISOR 1
+/// multiplier to x
+#define MATERIAL_DYNAMICS_DAMTIER_INTENSIFIER 1
+/// shift to x after multiply
+#define MATERIAL_DYNAMICS_DAMTIER_SHIFT 50
+/// +- shift
+#define MATERIAL_DYNAMICS_DAMTIER_ADJUST 0
+/// overall result gets multiplied by this
+#define MATERIAL_DYNAMICS_DAMTIER_SCALER 0.1
+
+#define MATERIAL_DENSITY_TO_DAMTIER_INTENSIFIER(DENS) max(0, log(10, DENS/2 + 1))
+#define MATERIAL_SIGNIFICANCE_TO_DAMTIER_INTENSIFIER(SIG) max(0, (SIG > MATERIAL_SIGNIFICANCE_BASELINE? ((SIG - MATERIAL_SIGNIFICANCE_BASELINE) / 10) : ((MATERIAL_SIGNIFICANCE_BASELINE - ((MATERIAL_SIGNIFICANCE_BASELINE - SIG) / 2)) / 10)))
+
diff --git a/code/__DEFINES/materials/flags.dm b/code/__DEFINES/materials/flags.dm
new file mode 100644
index 00000000000..4bfd28a8d66
--- /dev/null
+++ b/code/__DEFINES/materials/flags.dm
@@ -0,0 +1,52 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
+//* /datum/material material_flags
+
+/// vulnerability applies to mob armor (uh oh)
+#define MATERIAL_FLAG_VULNERABLE_MOB_ARMOR (1<<0)
+/// utterly immune to melting, thermite or otherwise
+#define MATERIAL_FLAG_UNMELTABLE (1<<1)
+
+DEFINE_BITFIELD(material_flags, list(
+ BITFIELD(MATERIAL_FLAG_VULNERABLE_MOB_ARMOR),
+ BITFIELD(MATERIAL_FLAG_UNMELTABLE),
+))
+
+//* /datum/material material_constraints
+//* /datum/design material_constraints list values
+
+// None yet
+
+DEFINE_BITFIELD(material_constraints, list(
+ // none yet
+))
+
+//* /datum/material_trait material_trait_flags
+
+/// used to attack
+#define MATERIAL_TRAIT_ATTACK (1<<0)
+/// hook shieldcalls
+#define MATERIAL_TRAIT_SHIELD (1<<1)
+/// reqiures passive ticking
+#define MATERIAL_TRAIT_TICKING (1<<2)
+/// has examine text
+#define MATERIAL_TRAIT_EXAMINE (1<<3)
+/// requires setup/teardown
+#define MATERIAL_TRAIT_REGISTRATION (1<<4)
+
+DEFINE_BITFIELD(material_trait_flags, list(
+ BITFIELD(MATERIAL_TRAIT_ATTACK),
+ BITFIELD(MATERIAL_TRAIT_SHIELD),
+ BITFIELD(MATERIAL_TRAIT_TICKING),
+ BITFIELD(MATERIAL_TRAIT_EXAMINE),
+ BITFIELD(MATERIAL_TRAIT_REGISTRATION),
+))
+
+//! WARNING: CONSIDERED LEGACY CODE !//
+// Flags returned from material defense hooks
+// eventually we want to transition all of this to the atom shieldcall system.
+
+#define MATERIAL_DEFEND_FORCE_MISS (1<<0)
+#define MATERIAL_DEFEND_FULL_BLOCK (1<<1)
+#define MATERIAL_DEFEND_REFLECT (1<<2)
diff --git a/code/__DEFINES/materials/helpers.dm b/code/__DEFINES/materials/helpers.dm
new file mode 100644
index 00000000000..36c9375a93e
--- /dev/null
+++ b/code/__DEFINES/materials/helpers.dm
@@ -0,0 +1,54 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
+//* object checks
+
+/// We are ticking materials.
+#define IS_TICKING_MATERIALS(A) (A.atom_flags & ATOM_MATERIALS_TICKING)
+#define START_TICKING_MATERIALS(A) SSmaterials.add_ticked_object(src)
+#define STOP_TICKING_MATERIALS(A) SSmaterials.remove_ticked_object(src)
+
+//* /atom level invocation of traits
+
+/// Invocation of material traits
+/// A - the atom
+/// CHECK - material_trait_flags to check
+/// INVOKE - procname on /datum/material_trait to invoke
+/// ARGS... - directly appended to the material_trait proc invocation after the params 'host' being A, and 'data' being the data the trait has on A.
+#define MATERIAL_INVOKE(A, CHECK, INVOKE, ARGS...) \
+ if(A.material_trait_flags & CHECK) { \
+ if(islist(A.material_traits)) { \
+ for(var/datum/material_trait/__trait as anything in A.material_traits){ \
+ if(!(__trait.material_trait_flags & CHECK)) { \
+ continue; \
+ } \
+ __trait.INVOKE(A, A.material_traits[__trait], ##args); \
+ } \
+ } \
+ else { \
+ var/datum/material_trait/__trait = A.material_traits; \
+ __trait.INVOKE(A, A.material_traits_data, ##args); \
+ } \
+ }
+
+/// Invocation of material traits with flag return
+/// OUT - flag returns from invocations are binary OR'd into this.
+/// A - the atom
+/// CHECK - material_trait_flags to check
+/// INVOKE - procname on /datum/material_trait to invoke
+/// ARGS... - directly appended to the material_trait proc invocation after the params 'host' being A, and 'data' being the data the trait has on A.
+#define MATERIAL_INVOKE_OUT(OUT, A, CHECK, INVOKE, ARGS...) \
+ if(A.material_trait_flags & CHECK) { \
+ if(islist(A.material_traits)) { \
+ for(var/datum/material_trait/__trait as anything in A.material_traits){ \
+ if(!(__trait.material_trait_flags & CHECK)) { \
+ continue; \
+ } \
+ OUT |= __trait.INVOKE(A, A.material_traits[__trait], ##args); \
+ } \
+ } \
+ else { \
+ var/datum/material_trait/__trait = A.material_traits; \
+ OUT |= __trait.INVOKE(A, A.material_traits_data, ##args); \
+ } \
+ }
diff --git a/code/__DEFINES/materials/misc.dm b/code/__DEFINES/materials/misc.dm
index 239163a5aec..8b5eb95e89a 100644
--- a/code/__DEFINES/materials/misc.dm
+++ b/code/__DEFINES/materials/misc.dm
@@ -1,5 +1,7 @@
// Material Defines
+// todo: stop using these please, we're reliance on them out.
+#define MAT_ALGAE "algae"
#define MAT_BANANIUM "bananium"
#define MAT_CARBON "carbon"
#define MAT_CHITIN "chitin"
@@ -43,18 +45,10 @@
#define MAT_VERDANTIUM "verdantium"
#define MAT_WOOD "wood"
-
#define SHARD_SHARD "shard"
#define SHARD_SHRAPNEL "shrapnel"
#define SHARD_STONE_PIECE "piece"
#define SHARD_SPLINTER "splinters"
#define SHARD_NONE ""
-#define MATERIAL_UNMELTABLE 0x1
-#define MATERIAL_BRITTLE 0x2
-#define MATERIAL_PADDING 0x4
-
-/// Amount table damage is multiplied by if it is made of a brittle material (e.g. glass)
-#define TABLE_BRITTLE_MATERIAL_MULTIPLIER 4
-
#define SHEET_MATERIAL_AMOUNT 2000
diff --git a/code/__DEFINES/materials/parts.dm b/code/__DEFINES/materials/parts.dm
new file mode 100644
index 00000000000..ba97d7aea54
--- /dev/null
+++ b/code/__DEFINES/materials/parts.dm
@@ -0,0 +1,13 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
+/// material part key that a single-material-part object is treated as having
+#define MATERIAL_PART_DEFAULT "structure"
+/// material_parts value for object does not use material parts system
+#define MATERIAL_DEFAULT_DISABLED "DISABLED"
+/// material_parts value for object uses hardcoded vars / overrides the abstraction API
+#define MATERIAL_DEFAULT_ABSTRACTED "ABSTRACTED"
+/// material_parts value for object has a single material but it's absent
+#define MATERIAL_DEFAULT_NONE null
+/// material ID to pass to Initialize() procs for "erase the default material of this slot"
+#define MATERIAL_ID_ERASE "___ERASE___"
diff --git a/code/__DEFINES/materials/stats.dm b/code/__DEFINES/materials/stats.dm
new file mode 100644
index 00000000000..7ad6a60a506
--- /dev/null
+++ b/code/__DEFINES/materials/stats.dm
@@ -0,0 +1,7 @@
+
+#define MATERIAL_MELEE_STATS_DAMAGE 1
+#define MATERIAL_MELEE_STATS_FLAG 2
+#define MATERIAL_MELEE_STATS_TIERMOD 3
+#define MATERIAL_MELEE_STATS_MODE 4
+
+#define MATERIAL_MELEE_STATS_LISTLEN 4
diff --git a/code/__DEFINES/math.dm b/code/__DEFINES/math.dm
index 293b52e7923..2e190ce6173 100644
--- a/code/__DEFINES/math.dm
+++ b/code/__DEFINES/math.dm
@@ -210,6 +210,7 @@
// )
+/// random but float
#define RAND_F(LOW, HIGH) (rand()*(HIGH-LOW) + LOW)
#define SQUARE(x) (x*x)
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index dfe4a49e34c..313d0d10b7a 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -360,11 +360,6 @@ GLOBAL_LIST_EMPTY(##LIST_NAME);\
/// Embed chance unset for embed_chance var on /obj/item.
#define EMBED_CHANCE_UNSET -1337
-
-/// No hitsound define
-#define HITSOUND_UNSET "UNSET"
-
-
/// Herm Gender
/// Snowflake Global that throws a fit
#define HERM "herm"
diff --git a/code/__DEFINES/misc/attack_animations.dm b/code/__DEFINES/misc/attack_animations.dm
new file mode 100644
index 00000000000..c4111e5c6fa
--- /dev/null
+++ b/code/__DEFINES/misc/attack_animations.dm
@@ -0,0 +1,6 @@
+#define ATTACK_ANIMATION_PUNCH "punch"
+#define ATTACK_ANIMATION_DISARM "disarm"
+#define ATTACK_ANIMATION_CLAW "claw"
+#define ATTACK_ANIMATION_KICK "kick"
+#define ATTACK_ANIMATION_BITE "bite"
+#define ATTACK_ANIMATION_SMASH "smash"
diff --git a/code/__DEFINES/mobs/health.dm b/code/__DEFINES/mobs/health.dm
index 4f4b76d1b0d..ab1c1e71867 100644
--- a/code/__DEFINES/mobs/health.dm
+++ b/code/__DEFINES/mobs/health.dm
@@ -5,6 +5,9 @@
* Atom damage uses this too!
*/
#define DAMAGE_PRECISION 0.01
+#define DAMAGE_TIER_PRECISION 0.01
+#define ARMOR_PRECISION 0.001
+#define ARMOR_TIER_PRECISION 0.01
//? CPR
/// how long CPR suppresses brain decay
diff --git a/code/__DEFINES/mobs/mobs.dm b/code/__DEFINES/mobs/mobs.dm
index ee73e2632f9..94e5a35c44f 100644
--- a/code/__DEFINES/mobs/mobs.dm
+++ b/code/__DEFINES/mobs/mobs.dm
@@ -307,11 +307,6 @@
#define SLIME_COMMAND_FACTION 2
/// When befriended with a slime friendship agent.
#define SLIME_COMMAND_FRIEND 3
-// Threshold for mobs being able to damage things like airlocks or reinforced glass windows.
-// If the damage is below this, nothing will happen besides a message saying that the attack was ineffective.
-// Generally, this was not a define but was commonly set to 10, however 10 may be too low now since simple_mobs now attack twice as fast,
-// at half damage compared to the old mob system, meaning mobs who could hurt structures may not be able to now, so now it is 5.
-#define STRUCTURE_MIN_DAMAGE_THRESHOLD 5
// Clothing flags, organized in roughly top-bottom
#define EXAMINE_SKIPHELMET 0x0001
diff --git a/code/__DEFINES/move_force.dm b/code/__DEFINES/move_force.dm
index a069b980c61..523eb44007f 100644
--- a/code/__DEFINES/move_force.dm
+++ b/code/__DEFINES/move_force.dm
@@ -1,11 +1,18 @@
// todo: this system needs reworked
//Defaults
-#define MOVE_FORCE_DEFAULT 1000
+
+#define MOVE_RESIST_SHURIKEN 250
#define MOVE_RESIST_DEFAULT 1000
-#define PULL_FORCE_DEFAULT 1000
+
+#define MOVE_FORCE_DEFAULT 1000
+
#define THROW_FORCE_DEFAULT 1000
+
+#define THROW_RESIST_SHURIKEN 250
#define THROW_RESIST_DEFAULT 1000
+#define PULL_FORCE_DEFAULT 1000
+
//etc
//? stuff that shouldn't have force, almost
#define MOVE_FORCE_MOUSE 100
diff --git a/code/__DEFINES/procs/clickcode.dm b/code/__DEFINES/procs/clickcode.dm
index 9e38b340ea9..6293c3498e0 100644
--- a/code/__DEFINES/procs/clickcode.dm
+++ b/code/__DEFINES/procs/clickcode.dm
@@ -2,8 +2,8 @@
/**
* flags passed around click procs including:
* ClickOn
- * melee_attack_chain
- * ranged_attack_chain
+ * melee_interaction_chain
+ * ranged_interaction_chain
* attackby
* pre_attack
* standard_melee_attack and related
@@ -32,10 +32,12 @@
#define CLICKCHAIN_FROM_HREF (1<<4)
/// did something in the proc, logically should stop using it (the user should anyways)
#define CLICKCHAIN_DID_SOMETHING (1<<5)
+/// attack missed
+#define CLICKCHAIN_ATTACK_MISSED (1<<6)
/// completely block attacking (notably, attack_mob, attack_obj) from happening by halting standard_melee_attack.
-#define CLICKCHAIN_DO_NOT_ATTACK (1<<6)
+#define CLICKCHAIN_DO_NOT_ATTACK (1<<7)
/// intercepted by component
-#define CLICKCHAIN_COMPONENT_SIGNAL_HANDLED (1<<7)
+#define CLICKCHAIN_COMPONENT_SIGNAL_HANDLED (1<<8)
//! Reachability Depths - checked from level of DirectAccess and turf adjacency.
/// default reachability depth
diff --git a/code/__DEFINES/radiation/simulation.dm b/code/__DEFINES/radiation/simulation.dm
index 9a70f2acdab..8cade0aea76 100644
--- a/code/__DEFINES/radiation/simulation.dm
+++ b/code/__DEFINES/radiation/simulation.dm
@@ -30,6 +30,8 @@
#define RAD_FALLOFF_ENGINE_SUPERMATTER 0.5
/// singulo
#define RAD_FALLOFF_ENGINE_SINGULARITY 0.5
+/// materials
+#define RAD_FALLOFF_MATERIALS 0.5
//! Pulse - Z Falloff
//* Keep in mind that these are low because things are usually really far away and the point of Z rad is to hit most things.
diff --git a/code/__DEFINES/tools/functionality.dm b/code/__DEFINES/tools/functionality.dm
index 98998953838..bdeeefc443d 100644
--- a/code/__DEFINES/tools/functionality.dm
+++ b/code/__DEFINES/tools/functionality.dm
@@ -36,7 +36,18 @@ GLOBAL_REAL_VAR(_dyntool_image_states) = list(
//? Tool usage flags
-//* None yet! Waiting on skill-system design.
+/// repairing
+#define TOOL_USAGE_REPAIR (1<<0)
+/// initial construction
+#define TOOL_USAGE_CONSTRUCT (1<<1)
+/// deconstruct
+#define TOOL_USAGE_DECONSTRUCT (1<<2)
+/// superstructure, making / breaking turfs, etc
+#define TOOL_USAGE_BUILDING_SUPERSTRUCTURE (1<<3)
+/// making railings, catwalks, wires, etc
+#define TOOL_USAGE_BUILDING_FRAMEWORK (1<<4)
+/// making tables, detailed furnishings, etc
+#define TOOL_USAGE_BUILDING_FURNISHINGS (1<<5)
//? tool_locked var
diff --git a/code/__HELPERS/animations/attack.dm b/code/__HELPERS/animations/attack.dm
new file mode 100644
index 00000000000..0e706b1b4d1
--- /dev/null
+++ b/code/__HELPERS/animations/attack.dm
@@ -0,0 +1,91 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
+/**
+ * 'bounce' towards a target
+ *
+ * @params
+ * * target - the target
+ * * time - animation duration
+ * * dist - pixels to move
+ */
+/atom/movable/proc/animate_swing_at_target(atom/target, time = 3, dist = 8)
+ var/mob_rotation = pick(10, -10)
+ var/matrix/original = matrix(transform)
+ var/matrix/rotated = matrix(transform)
+ rotated.Turn(mob_rotation)
+ if(get_turf(target) == get_turf(src))
+ // just jump up and down lmao
+ var/cpz = pixel_z
+ animate(src, pixel_z = dist * (1 / 2), time = time * (1 / 3), transform = rotated, flags = ANIMATION_PARALLEL, easing = EASE_IN | BACK_EASING)
+ animate(pixel_z = cpz, time = time * (2 / 3), transform = original, easing = SINE_EASING)
+ return
+ var/angle = get_visual_angle(src, target)
+ var/cpx = pixel_x
+ var/cpy = pixel_y
+ var/d_x = sin(angle) * dist + cpx
+ var/d_y = cos(angle) * dist + cpy
+ // fast bounce, with a bit of angular rotation
+ animate(src, pixel_x = d_x, pixel_y = d_y, time = time * (1 / 3), transform = rotated, flags = ANIMATION_PARALLEL, easing = EASE_IN | BACK_EASING)
+ animate(pixel_x = cpx, pixel_y = cpy, time = time * (2 / 3), transform = original, easing = SINE_EASING)
+
+/**
+ * animate *incoming* weapon attacks
+ *
+ * @params
+ * * attacker - (optional) what hit us
+ * * weapon - thing hitting us
+ * * time - animation duration
+ */
+/atom/proc/animate_hit_by_weapon(atom/attacker, obj/item/weapon, time = 8)
+ // make sure it exists
+ if(isnull(weapon))
+ return
+
+ // todo: overlays/vis contents?
+ var/image/rendering = image(weapon, loc = src)
+ flick_overlay(rendering, GLOB.clients, time)
+
+ // yeah we don't care about the mob's state, we're an animation
+ rendering.appearance_flags = KEEP_APART | RESET_ALPHA | RESET_TRANSFORM | RESET_COLOR
+ rendering.plane = MOB_PLANE
+
+ // size down
+ rendering.transform = matrix() * 0.4
+
+ // 'slide' the weapon across us while it fades
+ #define ATTACK_ITEM_OFFSET 12
+ if(isnull(attacker) || attacker == src)
+ rendering.pixel_z = ATTACK_ITEM_OFFSET
+ else
+ var/angle = get_visual_angle(attacker)
+ var/d_x = sin(angle) * ATTACK_ITEM_OFFSET
+ var/d_y = cos(angle) * ATTACK_ITEM_OFFSET
+ rendering.pixel_x = d_x
+ rendering.pixel_y = d_y
+ #undef ATTACK_ITEM_OFFSET
+
+ animate(rendering, alpha = 175, transform = matrix() * 0.7, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = time * (1 / 2), easing = BACK_EASING | EASE_OUT)
+ animate(alpha = 0, time = time * (1 / 2), easing = SINE_EASING | EASE_OUT)
+
+/**
+ * animate some kind of predetermined attack effect
+ *
+ * @params
+ * * animation_type - ATTACK_ANIMATION_X enum
+ * * time - how long; this is sometimes ignored due to animations having hardcoded length.
+ */
+/atom/proc/animate_hit_by_attack(animation_type = ATTACK_ANIMATION_PUNCH, time = 6)
+ #define ATTACK_ANIMATION_FILE 'icons/effects/attack_animations.dmi'
+ var/image/rendering = image(ATTACK_ANIMATION_FILE, icon_state = animation_type, loc = src)
+ flick_overlay(rendering, GLOB.clients, time)
+
+ // yeah we don't care about the mob's state, we're an animation
+ rendering.appearance_flags = KEEP_APART | RESET_ALPHA | RESET_TRANSFORM | RESET_COLOR
+ rendering.plane = MOB_PLANE
+
+ // just make it fade out
+ animate(rendering, alpha = 175, time = time * (1 / 2))
+ animate(alpha = 0, time = time * (1 / 2), easing = SINE_EASING | EASE_OUT)
+
+ #undef ATTACK_ANIMATION_FILE
diff --git a/code/__HELPERS/datastructs/armor.dm b/code/__HELPERS/datastructs/armor.dm
index e17c6adbfb6..929eb064b56 100644
--- a/code/__HELPERS/datastructs/armor.dm
+++ b/code/__HELPERS/datastructs/armor.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
/**
* armor datums for holding values
* globally cached.
@@ -9,16 +12,21 @@
var/melee = 0
var/melee_tier = ARMOR_TIER_DEFAULT
var/melee_soak = 0
+ var/melee_deflect = 0
var/bullet = 0
var/bullet_tier = ARMOR_TIER_DEFAULT
var/bullet_soak = 0
+ var/bullet_deflect = 0
var/laser = 0
var/laser_tier = ARMOR_TIER_DEFAULT
var/laser_soak = 0
+ var/laser_deflect = 0
var/energy = 0
var/bomb = 0
var/bio = 0
var/rad = 0
+ var/fire = 0
+ var/acid = 0
/datum/armor/New(list/from_values)
if(from_values)
@@ -35,16 +43,21 @@
UNPACK_OR(melee, ARMOR_MELEE, 0)
UNPACK_OR(melee_tier, ARMOR_MELEE_TIER, ARMOR_TIER_DEFAULT)
UNPACK_OR(melee_soak, ARMOR_MELEE_SOAK, 0)
+ UNPACK_OR(melee_deflect, ARMOR_MELEE_DEFLECT, 0)
UNPACK_OR(bullet, ARMOR_BULLET, 0)
UNPACK_OR(bullet_tier, ARMOR_BULLET_TIER, ARMOR_TIER_DEFAULT)
UNPACK_OR(bullet_soak, ARMOR_BULLET_SOAK, 0)
+ UNPACK_OR(bullet_deflect, ARMOR_BULLET_DEFLECT, 0)
UNPACK_OR(laser, ARMOR_LASER, 0)
UNPACK_OR(laser_tier, ARMOR_LASER_TIER, ARMOR_TIER_DEFAULT)
UNPACK_OR(laser_soak, ARMOR_LASER_SOAK, 0)
+ UNPACK_OR(laser_deflect, ARMOR_LASER_DEFLECT, 0)
UNPACK_OR(energy, ARMOR_ENERGY, 0)
UNPACK_OR(bomb, ARMOR_BOMB, 0)
UNPACK_OR(bio, ARMOR_BIO, 0)
UNPACK_OR(rad, ARMOR_RAD, 0)
+ UNPACK_OR(fire, ARMOR_FIRE, 0)
+ UNPACK_OR(acid, ARMOR_ACID, 0)
#undef UNPACK_OR
/datum/armor/proc/to_list()
@@ -52,27 +65,34 @@
ARMOR_MELEE = melee,
ARMOR_MELEE_TIER = melee_tier,
ARMOR_MELEE_SOAK = melee_soak,
+ ARMOR_MELEE_DEFLECT = melee_deflect,
ARMOR_BULLET = bullet,
ARMOR_BULLET_TIER = bullet_tier,
ARMOR_BULLET_SOAK = bullet_soak,
+ ARMOR_BULLET_DEFLECT = bullet_deflect,
ARMOR_LASER = laser,
ARMOR_LASER_TIER = laser_tier,
ARMOR_LASER_SOAK = laser_soak,
+ ARMOR_LASER_DEFLECT = laser_deflect,
ARMOR_ENERGY = energy,
ARMOR_BOMB = bomb,
ARMOR_BIO = bio,
ARMOR_RAD = rad,
+ ARMOR_FIRE = fire,
+ ARMOR_ACID = acid,
)
/datum/armor/proc/to_name()
return jointext(list(
- "[round(melee * 100, 0.1)]@[melee_tier]-[melee_soak]",
- "[round(bullet * 100, 0.1)]@[bullet_tier]-[bullet_soak]",
- "[round(laser * 100, 0.1)]@[laser_tier]-[laser_soak]",
+ "[round(melee * 100, 0.1)]@[melee_tier]-[melee_soak]^[melee_deflect]",
+ "[round(bullet * 100, 0.1)]@[bullet_tier]-[bullet_soak]^[bullet_deflect]",
+ "[round(laser * 100, 0.1)]@[laser_tier]-[laser_soak]^[laser_deflect]",
"[round(energy * 100, 0.1)]",
"[round(bomb * 100, 0.1)]",
"[round(bio * 100, 0.1)]",
"[round(rad * 100, 0.1)]",
+ "[round(fire * 100, 0.1)]",
+ "[round(acid * 100, 0.1)]",
), " | ")
/datum/armor/proc/raw(flag)
@@ -83,16 +103,24 @@
return melee_soak
if(ARMOR_MELEE_TIER)
return melee_tier
+ if(ARMOR_MELEE_DEFLECT)
+ return melee_deflect
if(ARMOR_BULLET)
return bullet
if(ARMOR_BULLET_SOAK)
return bullet_soak
if(ARMOR_BULLET_TIER)
return bullet_tier
+ if(ARMOR_BULLET_DEFLECT)
+ return bullet_deflect
if(ARMOR_LASER)
return laser
if(ARMOR_LASER_SOAK)
return laser_soak
+ if(ARMOR_LASER_TIER)
+ return laser_tier
+ if(ARMOR_LASER_DEFLECT)
+ return laser_deflect
if(ARMOR_ENERGY)
return energy
if(ARMOR_BOMB)
@@ -101,6 +129,10 @@
return bio
if(ARMOR_RAD)
return rad
+ if(ARMOR_FIRE)
+ return fire
+ if(ARMOR_ACID)
+ return acid
else
CRASH("Invalid flag: [flag]")
@@ -123,6 +155,10 @@
return bio
if(ARMOR_RAD)
return rad
+ if(ARMOR_FIRE)
+ return fire
+ if(ARMOR_ACID)
+ return acid
else
CRASH("Invalid flag: [flag]")
@@ -137,23 +173,43 @@
else
return 0
+/datum/armor/proc/deflect(flag)
+ switch(flag)
+ if(ARMOR_MELEE)
+ return melee_deflect
+ if(ARMOR_BULLET)
+ return bullet_deflect
+ if(ARMOR_LASER)
+ return laser_deflect
+ else
+ return 0
+
/datum/armor/proc/resultant_damage(damage, tier, flag)
switch(flag)
if(ARMOR_MELEE)
if(!melee)
return damage
var/tdiff = melee_tier - tier
- return max(0, (tdiff? (damage * (1 - ARMOR_TIER_CALC(melee, tdiff))) : (damage * (1 - melee))) - melee_soak)
+ damage = max(0, (tdiff? (damage * (1 - ARMOR_TIER_CALC(melee, tdiff))) : (damage * (1 - melee))) - melee_soak)
+ if(damage <= melee_deflect)
+ return 0
+ return damage
if(ARMOR_BULLET)
if(!bullet)
return damage
var/tdiff = bullet_tier - tier
- return max(0, (tdiff? (damage * (1 - ARMOR_TIER_CALC(bullet, tdiff))) : (damage * (1 - bullet))) - bullet_soak)
+ damage = max(0, (tdiff? (damage * (1 - ARMOR_TIER_CALC(bullet, tdiff))) : (damage * (1 - bullet))) - bullet_soak)
+ if(damage <= bullet_deflect)
+ return 0
+ return damage
if(ARMOR_LASER)
if(!laser)
return damage
var/tdiff = laser_tier - tier
- return max(0, (tdiff? (damage * (1 - ARMOR_TIER_CALC(laser, tdiff))) : (damage * (1 - laser))) - laser_soak)
+ damage = max(0, (tdiff? (damage * (1 - ARMOR_TIER_CALC(laser, tdiff))) : (damage * (1 - laser))) - laser_soak)
+ if(damage <= laser_deflect)
+ return 0
+ return damage
if(ARMOR_ENERGY)
return damage * (1 - energy)
if(ARMOR_BOMB)
@@ -162,6 +218,10 @@
return damage * (1 - bio)
if(ARMOR_RAD)
return damage * (1 - rad)
+ if(ARMOR_FIRE)
+ return damage * (1 - fire)
+ if(ARMOR_ACID)
+ return damage * (1 - acid)
else
CRASH("Invalid flag: [flag]")
@@ -175,6 +235,8 @@
. += "Bomb: [round(bomb * 100, 0.1)]%"
. += "Bio: [round(bio * 100, 0.1)]%"
. += "Radiation: [round(rad * 100, 0.1)]%"
+ . += "Thermal: [round(fire * 100, 0.1)]%"
+ . += "Acid: [round(acid * 100, 0.1)]%"
/datum/armor/proc/log_string()
var/list/built = list()
diff --git a/code/__HELPERS/datastructs/bodytypes.dm b/code/__HELPERS/datastructs/bodytypes.dm
index 90c97b9e4a4..f1dd2c3a926 100644
--- a/code/__HELPERS/datastructs/bodytypes.dm
+++ b/code/__HELPERS/datastructs/bodytypes.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
/**
* holds cached, invertible lists
* allows all using null values and non-inverted
diff --git a/code/__HELPERS/datastructs/ingredients.dm b/code/__HELPERS/datastructs/ingredients.dm
index c00dc9fb75e..100ab3712c1 100644
--- a/code/__HELPERS/datastructs/ingredients.dm
+++ b/code/__HELPERS/datastructs/ingredients.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
//* INGREDIENTS SYSTEM - Check [code/__DEFINES/ingredients.dm] *//
/// Ingredients are specially formatted lists.
diff --git a/code/__HELPERS/icon_smoothing.dm b/code/__HELPERS/icon_smoothing.dm
index d854c36e6a4..e234e5b03e4 100644
--- a/code/__HELPERS/icon_smoothing.dm
+++ b/code/__HELPERS/icon_smoothing.dm
@@ -181,7 +181,7 @@
*/
/atom/proc/smooth_icon()
smoothing_flags &= ~SMOOTH_QUEUED
- atom_flags |= HTML_USE_INITIAL_ICON
+ atom_flags |= ATOM_HTML_INITIAL_ICON
if (!z)
CRASH("[type] called smooth_icon() without being on a z-level")
if(smoothing_flags & SMOOTH_CORNERS)
diff --git a/code/__HELPERS/math/angle.dm b/code/__HELPERS/math/angle.dm
index 8b9d3f6807c..3ba3ce9e7cf 100644
--- a/code/__HELPERS/math/angle.dm
+++ b/code/__HELPERS/math/angle.dm
@@ -2,10 +2,11 @@
* angle clockwise from north from point A to point B
*
* this is visual angle because pixel shifts don't determine loc.
+ * this ignores step x/y as we don't generally use those, so this works on all /atom's
*
* this is also visual angle because ss13 uses weird CW of N instead of CCW of E angles (which the rest of the math world does).
*/
-/proc/get_visual_angle(atom/movable/start, atom/movable/end)
+/proc/get_visual_angle(atom/start, atom/end)
if(!start || !end)
return 0
var/dy =(32 * end.y + end.pixel_y) - (32 * start.y + start.pixel_y)
diff --git a/code/__HELPERS/math/multipliers.dm b/code/__HELPERS/math/multipliers.dm
new file mode 100644
index 00000000000..515e4c848cf
--- /dev/null
+++ b/code/__HELPERS/math/multipliers.dm
@@ -0,0 +1,11 @@
+/**
+ * multiplied effect of an effect multiplier based on '1' being default
+ */
+/proc/multiply_effect_multiplier(multiplier, multiply_by)
+ if(multiply_by < 0)
+ multiply_by = -multiply_by
+ multiplier = -multiplier
+ if(multiplier > 0)
+ return multiplier ** multiply_by
+ else
+ return -((-multiplier) ** multiply_by)
diff --git a/code/__HELPERS/typelists.dm b/code/__HELPERS/typelists.dm
index 9b4101cfc41..79f69741d61 100644
--- a/code/__HELPERS/typelists.dm
+++ b/code/__HELPERS/typelists.dm
@@ -53,3 +53,6 @@ GLOBAL_LIST_EMPTY(typelistkeys)
if(!dlist)
return
return dlist[key]
+
+/datum/proc/is_typelist(key, list/L)
+ return L == GLOB.typelists[type]?[key]
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 749a21bd200..2e3e736f72b 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1020,6 +1020,10 @@
return TRUE
if(O.edge)
return TRUE
+ if(isitem(O))
+ var/obj/item/I = O
+ if(I.damage_mode & DAMAGE_MODE_SHARP)
+ return TRUE
return FALSE
/// Whether or not the given item counts as cutting with an edge in terms of removing limbs.
@@ -1028,6 +1032,10 @@
return FALSE
if(O.edge)
return TRUE
+ if(isitem(O))
+ var/obj/item/I = O
+ if(I.damage_mode & DAMAGE_MODE_EDGE)
+ return TRUE
return FALSE
/// Returns 1 if the given item is capable of popping things like balloons, inflatable barriers, or cutting police tape.
diff --git a/code/controllers/repository/structs.dm b/code/controllers/repository/structs.dm
index f1ee6088647..6a6bd2eb004 100644
--- a/code/controllers/repository/structs.dm
+++ b/code/controllers/repository/structs.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
REPOSITORY_DEF(structs)
name = "Repository - Structs"
expected_type = /datum/prototype/struct
diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm
index 6d7bba8dae9..a4adda3d45d 100644
--- a/code/controllers/subsystem/materials.dm
+++ b/code/controllers/subsystem/materials.dm
@@ -1,10 +1,13 @@
SUBSYSTEM_DEF(materials)
name = "Materials"
- subsystem_flags = SS_NO_FIRE
+ subsystem_flags = NONE
init_order = INIT_ORDER_MATERIALS
+ wait = 2 SECONDS
/// material by id
var/list/material_lookup
+ /// material trait by path
+ var/list/material_traits
/// legacy material lookup *vomit
var/list/legacy_material_lookup
/// material recipes
@@ -14,16 +17,69 @@ SUBSYSTEM_DEF(materials)
// however, i can't be assed to write Recover() until we do procedural materials
// thus, dealing with it later :^)
+ /// ticked atoms
+ var/list/ticking = list()
+ /// currentrun
+ var/list/currentrun
+
+ /// layered armor cache
+ var/list/layered_armor_cache = list()
+ /// combined armor cache
+ var/list/combined_armor_cache = list()
+ /// wall armor cache
+ var/list/wall_armor_cache = list()
+
/datum/controller/subsystem/materials/Initialize()
+ initialize_material_traits()
initialize_materials()
initialize_material_recipes()
return ..()
/datum/controller/subsystem/materials/Recover()
+ initialize_material_traits()
initialize_materials()
initialize_material_recipes()
+ if(islist(SSmaterials.ticking))
+ // todo: better sanitization
+ src.ticking = SSmaterials.ticking
+ else
+ src.ticking = list()
return ..()
+/datum/controller/subsystem/materials/proc/add_ticked_object(atom/A)
+ if(A.atom_flags & ATOM_MATERIALS_TICKING)
+ return
+ A.atom_flags |= ATOM_MATERIALS_TICKING
+ ticking += A
+
+/datum/controller/subsystem/materials/proc/remove_ticked_object(atom/A)
+ if(!(A.atom_flags & ATOM_MATERIALS_TICKING))
+ return
+ A.atom_flags &= ~ATOM_MATERIALS_TICKING
+ ticking -= A
+
+/datum/controller/subsystem/materials/fire(resumed)
+ if(!resumed)
+ src.currentrun = ticking.Copy()
+ var/list/currentrun = src.currentrun
+ var/atom/A
+ var/dt = (subsystem_flags & SS_TICKER)? (wait * world.tick_lag) : max(world.tick_lag, wait * 0.1)
+ var/i
+ var/datum/material_trait/trait
+ for(i in length(currentrun) to 1 step -1)
+ A = currentrun[A]
+ if(length(A.material_traits))
+ for(trait as anything in A.material_traits)
+ if(!(trait.material_trait_flags & MATERIAL_TRAIT_TICKING))
+ continue
+ trait.tick(A, A.material_traits[trait], dt)
+ else
+ trait = A.material_traits
+ trait.tick(A, A.material_traits_data, dt)
+ if(MC_TICK_CHECK)
+ break
+ currentrun.len -= (length(currentrun) - i + 1)
+
/datum/controller/subsystem/materials/proc/initialize_materials()
material_lookup = list()
legacy_material_lookup = list()
@@ -42,6 +98,15 @@ SUBSYSTEM_DEF(materials)
material_lookup[initial(mat_ref.id)] = mat_ref
legacy_material_lookup[lowertext(mat_ref.name)] = mat_ref
+/datum/controller/subsystem/materials/proc/initialize_material_traits()
+ material_traits = list()
+ for(var/path in subtypesof(/datum/material_trait))
+ var/datum/material/mat_trait = path
+ if(initial(mat_trait.abstract_type) == path)
+ continue
+ mat_trait = new path
+ material_traits[path] = mat_trait
+
/datum/controller/subsystem/materials/proc/initialize_material_recipes()
material_stack_recipes = list()
for(var/path in subtypesof(/datum/stack_recipe/material))
@@ -57,21 +122,106 @@ SUBSYSTEM_DEF(materials)
* ids are acceptable on maps
*
* @params
- * id_or_path - id or typepath
+ * id_or_path - id or typepath; if this is already a material instance, it will be returned as-is.
*/
-/datum/controller/subsystem/materials/proc/get_material(datum/material/id_or_path)
+/datum/controller/subsystem/materials/proc/resolve_material(datum/material/id_or_path)
if(istext(id_or_path))
// yay it's an id
return material_lookup[id_or_path]
+ else if(istype(id_or_path))
+ return id_or_path
else if(ispath(id_or_path))
// yay it's a path
return material_lookup[initial(id_or_path.id)]
- else if(istype(id_or_path))
- return id_or_path
- else
- // what
- // yes you get a runtime if you pass null in, the subsystem shouldn't have to sanitycheck for you.
- CRASH("tried to fetch neither a text string (id) or a typepath (compiled in material type)")
+ else if(isnull(id_or_path))
+ return
+ CRASH("what?")
+
+/**
+ * ensures a list is full of material ids for keys
+ *
+ * if key is not a valid material or is null, it will be nulled.
+ */
+/datum/controller/subsystem/materials/proc/preprocess_flat_keys_to_ids(list/L)
+ // todo: optimize
+ . = list()
+ for(var/i in 1 to length(L))
+ var/datum/material/resolved = resolve_material(L[i])
+ . += resolved?.id
+
+/**
+ * ensures a list is full of material references for keys
+ *
+ * if key is not a valid material or is null, it will be nulled.
+ */
+/datum/controller/subsystem/materials/proc/preprocess_flat_keys_to_instances(list/L)
+ // todo: optimize
+ . = list()
+ for(var/i in 1 to length(L))
+ var/datum/material/resolved = resolve_material(L[i])
+ . += resolved
+
+/**
+ * ensures a list is full of material ids for keys
+ *
+ * if key is not a valid material or is null, it will be dropped.
+ * undefined behavior if there's duped ids / materials - this should never happen.
+ */
+/datum/controller/subsystem/materials/proc/preprocess_kv_keys_to_ids(list/L)
+ // todo: optimize
+ . = list()
+ for(var/i in 1 to length(L))
+ var/key = L[i]
+ var/datum/material/resolved = resolve_material(key)
+ if(isnull(resolved))
+ continue
+ var/value = L[key]
+ .[resolved.id] = value
+
+/**
+ * ensures a list is full of material references for keys
+ *
+ * if key is not a valid material or is null, it will be dropped.
+ * undefined behavior if there's duped ids / materials - this should never happen.
+ */
+/datum/controller/subsystem/materials/proc/preprocess_kv_keys_to_instances(list/L)
+ // todo: optimize
+ . = list()
+ for(var/i in 1 to length(L))
+ var/key = L[i]
+ var/datum/material/resolved = resolve_material(key)
+ if(isnull(resolved))
+ continue
+ var/value = L[key]
+ .[resolved] = value
+
+/**
+ * ensures a list is full of material ids for values
+ *
+ * if value is not a valid material or is null, it will be nulled.
+ */
+/datum/controller/subsystem/materials/proc/preprocess_kv_values_to_ids(list/L)
+ // todo: optimize
+ . = list()
+ for(var/i in 1 to length(L))
+ var/key = L[i]
+ var/value = L[key]
+ var/datum/material/resolved = resolve_material(value)
+ .[key] = resolved?.id
+
+/**
+ * ensures a list is full of material references for values
+ *
+ * if value is not a valid material or is null, it will be nulled.
+ */
+/datum/controller/subsystem/materials/proc/preprocess_kv_values_to_instances(list/L)
+ // todo: optimize
+ . = list()
+ for(var/i in 1 to length(L))
+ var/key = L[i]
+ var/value = L[key]
+ var/datum/material/resolved = resolve_material(value)
+ .[key] = resolved
/**
* returns all material datums
@@ -84,12 +234,19 @@ SUBSYSTEM_DEF(materials)
for(var/id in material_lookup)
. += material_lookup[id]
+/**
+ * drop a material sheet
+ */
+/datum/controller/subsystem/materials/proc/drop_sheets(datum/material/id_or_path, amount, atom/where)
+ var/datum/material/mat = resolve_material(id_or_path)
+ mat.place_sheet(where, amount)
+
/**
* ! DEPRECATED
* todo: REMOVE
*
* DO NOT USE THIS PROC
- * Use SSmaterials.get_material()!
+ * Use SSmaterials.resolve_material()!
*/
/proc/get_material_by_name(name)
if(istype(name, /datum/material))
diff --git a/code/controllers/subsystem/plants.dm b/code/controllers/subsystem/plants.dm
index 403eb196781..0ed5ca68eb1 100644
--- a/code/controllers/subsystem/plants.dm
+++ b/code/controllers/subsystem/plants.dm
@@ -147,7 +147,6 @@ SUBSYSTEM_DEF(plants)
/datum/controller/subsystem/plants/proc/remove_plant(var/obj/effect/plant/plant)
processing -= plant
-
///Debug Verb for testing seed genes.
/client/proc/show_plant_genes()
set category = "Debug"
diff --git a/code/controllers/subsystem/repository.dm b/code/controllers/subsystem/repository.dm
index f95a882d65b..17bd60b7c44 100644
--- a/code/controllers/subsystem/repository.dm
+++ b/code/controllers/subsystem/repository.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
SUBSYSTEM_DEF(repository)
name = "Repository System"
init_order = INIT_ORDER_REPOSITORY
diff --git a/code/controllers/subsystem/research.dm b/code/controllers/subsystem/research.dm
index 98dd7bdc9c5..f6b1b5de2d8 100644
--- a/code/controllers/subsystem/research.dm
+++ b/code/controllers/subsystem/research.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
SUBSYSTEM_DEF(research)
name = "Research"
subsystem_flags = SS_NO_FIRE
diff --git a/code/controllers/subsystem/supply.dm b/code/controllers/subsystem/supply.dm
index cbcb428d476..cddb0929e8a 100644
--- a/code/controllers/subsystem/supply.dm
+++ b/code/controllers/subsystem/supply.dm
@@ -121,10 +121,10 @@ SUBSYSTEM_DEF(supply)
continue
// Sell phoron and platinum
- if(istype(A, /obj/item/stack))
- var/obj/item/stack/P = A
- if(material_points_conversion[P.get_material_name()])
- EC.contents[EC.contents.len]["value"] = P.get_amount() * material_points_conversion[P.get_material_name()]
+ if(istype(A, /obj/item/stack/material))
+ var/obj/item/stack/material/P = A
+ if(material_points_conversion[P.material.name])
+ EC.contents[EC.contents.len]["value"] = P.get_amount() * material_points_conversion[P.material.name]
EC.contents[EC.contents.len]["quantity"] = P.get_amount()
EC.value += EC.contents[EC.contents.len]["value"]
diff --git a/code/datums/armor/misc.dm b/code/datums/armor/misc.dm
index 0fe6de3cf2c..a2364286c17 100644
--- a/code/datums/armor/misc.dm
+++ b/code/datums/armor/misc.dm
@@ -2,3 +2,8 @@
/datum/armor/misc/bucket
melee = 0.1
+
+/datum/armor/misc/weeping_angel
+ melee = 0.5
+ melee_soak = 7
+ melee_deflect = 18
diff --git a/code/datums/armor/objects/doors.dm b/code/datums/armor/objects/doors.dm
new file mode 100644
index 00000000000..a40611402b0
--- /dev/null
+++ b/code/datums/armor/objects/doors.dm
@@ -0,0 +1,36 @@
+/datum/armor/door
+ melee_deflect = 5
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_LIGHT)
+ melee_soak = 5
+ melee = 0.2
+
+/datum/armor/door/airlock
+ melee_deflect = 17
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_MEDIUM)
+ melee_soak = 5
+ melee = 0.5
+
+/datum/armor/door/airlock/vault
+ melee_deflect = 29
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_HEAVY)
+
+/datum/armor/door/airlock/light
+ melee = 0.25
+
+/datum/armor/door/blast_door
+ melee_deflect = 17
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_MEDIUM)
+ melee_soak = 5
+ melee = 0.5
+
+/datum/armor/door/windoor
+ melee_deflect = 5
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_LIGHT)
+ melee_soak = 0
+ melee = 0.8
+
+/datum/armor/door/windoor/reinforced
+ melee_deflect = 17
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_MEDIUM)
+ melee_soak = 5
+ melee = 0.5
diff --git a/code/datums/armor/objects/standard.dm b/code/datums/armor/objects/standard.dm
new file mode 100644
index 00000000000..35937b8b39f
--- /dev/null
+++ b/code/datums/armor/objects/standard.dm
@@ -0,0 +1,22 @@
+/datum/armor/object
+ abstract_type = /datum/armor/object
+
+/datum/armor/object/default
+ melee_deflect = 5
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_LIGHT)
+ melee = 0.1
+
+/datum/armor/object/light
+ melee_deflect = 5
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_LIGHT)
+ melee = 0.1
+
+/datum/armor/object/medium
+ melee_deflect = 10
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_MEDIUM)
+ melee = 0.25
+
+/datum/armor/object/heavy
+ melee_deflect = 18
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_HEAVY)
+ melee = 0.4
diff --git a/code/datums/armor/objects/windows.dm b/code/datums/armor/objects/windows.dm
new file mode 100644
index 00000000000..369d9487d8c
--- /dev/null
+++ b/code/datums/armor/objects/windows.dm
@@ -0,0 +1,10 @@
+/datum/armor/window
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_LIGHT)
+ melee = 0.1
+ bomb = -1
+
+/datum/armor/window/reinforced
+ melee_deflect = 6
+ melee_soak = 2
+ melee_tier = ARMOR_BARELY_BEATS(MELEE_TIER_MEDIUM)
+ melee = 0.2
diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm
index a5e3644f8ef..004d48b5325 100644
--- a/code/datums/components/crafting/crafting.dm
+++ b/code/datums/components/crafting/crafting.dm
@@ -120,10 +120,10 @@
if(!isturf(a.loc))
return
- for(var/atom/movable/AM in range(radius_range, a))
- if(AM.atom_flags & HOLOGRAM)
+ for(var/obj/O in range(radius_range, a))
+ if(O.obj_flags & OBJ_HOLOGRAM)
continue
- . += AM
+ . += O
/datum/component/personal_crafting/proc/get_surroundings(atom/a)
. = list()
@@ -131,7 +131,7 @@
.["other"] = list()
.["instances"] = list()
for(var/obj/item/I in get_environment(a))
- if(I.atom_flags & HOLOGRAM)
+ if(I.obj_flags & OBJ_HOLOGRAM)
continue
if(.["instances"][I.type])
.["instances"][I.type] += I
diff --git a/code/datums/design/design.dm b/code/datums/design/design.dm
index b60809bcbf3..b0d33e61afd 100644
--- a/code/datums/design/design.dm
+++ b/code/datums/design/design.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
/**
* design datums for holding what lathes can print.
*
@@ -43,12 +46,13 @@
//? Build Costs
/// list of materials needed - typepath or id to amount. null to auto-detect from the object in question. list() for no cost (DANGEROUS).
- var/list/materials
+ var/list/materials_base
/// for variable-material designs: assoc list of key to amounts
/// the key will be fed into print() during creation with the material id the user picked
/// autodetected if null.
/// this should obviously match material_parts on the /obj in question.
- var/list/material_parts
+ /// todo: add optional parts and constraints
+ var/list/material_costs
/// Items needed, as ingredients list - see [code/__HELPERS/datastructs/ingredients.dm]
var/list/ingredients
/// list of reagents needed - typepath or id to amount. null to auto-detect from the object in question. list() for no cost (DANGEROUS).
@@ -74,17 +78,14 @@
// lathe designs shouldn't be qdeleting, but incase someone puts in a random..
if(QDELETED(instance))
return
- // todo: maybe /obj/proc/detect_materials, TYPE_PROC_REF(/obj, detect_material_parts) ? this works fine for now tho.
- if(isnull(materials))
- if(!isnull(instance.materials))
- materials = instance.materials.Copy()
- if(!isnull(materials) && !isnull(instance.material_parts) && !isnull(instance.material_defaults))
- // subtract out the material defaults the instance itself added
- for(var/key in instance.material_parts)
- materials[instance.material_defaults[key]] -= instance.material_parts[key]
- if(isnull(material_parts))
- if(!isnull(instance.material_parts))
- material_parts = instance.material_parts.Copy()
+ if(isnull(materials_base))
+ var/list/fetched = instance.detect_material_base_costs()
+ if(length(fetched))
+ materials_base = fetched
+ if(isnull(material_costs))
+ var/list/fetched = instance.detect_material_part_costs()
+ if(length(fetched))
+ material_costs = fetched
if(isnull(reagents))
// if(!isnull(instance.reagents))
// reagents = instance.reagents.Copy()
@@ -118,8 +119,8 @@
"id" = id,
"work" = work,
"category" = category,
- "materials" = length(materials)? materials : null,
- "material_parts" = length(material_parts)? material_parts : null,
+ "materials" = length(materials_base)? materials_base : null,
+ "material_parts" = length(material_costs)? material_costs : null,
"reagents" = length(reagents)? reagents : null,
"ingredients" = length(ingredients)? ingredients : null,
"resultItem" = list(
@@ -133,17 +134,22 @@
* This is called even before the fabricator can touch the item.
*
* @params
- * * where - where to put the finished product
- * * fabricator - the lathe printing the product
+ * * where - where to print
+ * * amount - how many to print
+ * * material_parts - keys to ids
+ * * ingredient_parts - ingredients
+ * * reagent_parts - keys to ids
+ * * cost_multiplier - the cost multiplier used to print it
*
* @return created atom, or list of created atoms.
*/
/datum/design/proc/print(atom/where, amount, list/material_parts, list/ingredient_parts, list/reagent_parts, cost_multiplier = 1)
+ var/list/resolved_material_parts = SSmaterials.preprocess_kv_values_to_instances(material_parts)
if(is_stack)
var/stack_size = max_stack
if(stack_size >= amount)
. = new build_path(where, amount)
- on_print(., material_parts, ingredient_parts, reagent_parts, cost_multiplier)
+ on_print(., resolved_material_parts, ingredient_parts, reagent_parts, cost_multiplier)
else
. = list()
var/safety = 0
@@ -156,32 +162,30 @@
made = new build_path(where, making)
left -= making
. += made
- on_print(made, material_parts, ingredient_parts, reagent_parts, cost_multiplier)
+ on_print(made, resolved_material_parts, ingredient_parts, reagent_parts, cost_multiplier)
else
if(amount > 50)
STACK_TRACE("way too high")
if(amount == 1)
. = new build_path(where)
- on_print(., material_parts, ingredient_parts, reagent_parts, cost_multiplier)
+ on_print(., resolved_material_parts, ingredient_parts, reagent_parts, cost_multiplier)
else
. = list()
var/atom/made
for(var/i in 1 to min(amount, 50))
made = new build_path(where)
- on_print(made, material_parts, ingredient_parts, reagent_parts, cost_multiplier)
+ on_print(made, resolved_material_parts, ingredient_parts, reagent_parts, cost_multiplier)
. += made
-/datum/design/proc/on_print(atom/created, list/material_parts, list/ingredient_parts, list/reagent_parts, cost_multiplier = 1)
+/**
+ * material parts gets resolved to instances
+ */
+/datum/design/proc/on_print(atom/created, list/resolved_material_parts, list/ingredient_parts, list/reagent_parts, cost_multiplier = 1)
if(isobj(created))
var/obj/O = created
- var/list/effective_materials = materials.Copy()
- for(var/key in material_parts)
- effective_materials[material_parts[key]] += src.material_parts[key]
- if(cost_multiplier != 1)
- for(var/key in effective_materials)
- effective_materials[key] *= cost_multiplier
- O.materials = effective_materials
- O.set_material_parts(material_parts)
+ O.set_materials_base(materials_base)
+ O.set_material_parts(resolved_material_parts)
+ O.material_multiplier = cost_multiplier
/**
* called when a lathe prints a design, instead of print()
diff --git a/code/datums/design/design_holder.dm b/code/datums/design/design_holder.dm
index f0540aac04a..00e15deb771 100644
--- a/code/datums/design/design_holder.dm
+++ b/code/datums/design/design_holder.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
/datum/design_holder
/// any ids to specifically include
var/list/design_ids
diff --git a/code/datums/design/designs/machines/circuits.dm b/code/datums/design/designs/machines/circuits.dm
index d50ac0c7d88..1bfa81b070e 100644
--- a/code/datums/design/designs/machines/circuits.dm
+++ b/code/datums/design/designs/machines/circuits.dm
@@ -104,12 +104,6 @@
design_unlock = DESIGN_UNLOCK_INTRINSIC
build_path = /obj/item/circuitboard/request
-/datum/design/machine_circuit/pipelayer
- id = "CircuitPipeLayer"
- lathe_type = LATHE_TYPE_AUTOLATHE
- design_unlock = DESIGN_UNLOCK_INTRINSIC
- build_path = /obj/item/circuitboard/pipelayer
-
/datum/design/machine_circuit/timeclock
id = "CircuitTimeclock"
lathe_type = LATHE_TYPE_AUTOLATHE
diff --git a/code/datums/design/designs/medical/chemistry.dm b/code/datums/design/designs/medical/chemistry.dm
index 58ae9631b97..29b9abe6440 100644
--- a/code/datums/design/designs/medical/chemistry.dm
+++ b/code/datums/design/designs/medical/chemistry.dm
@@ -42,7 +42,7 @@
lathe_type = LATHE_TYPE_AUTOLATHE
design_unlock = DESIGN_UNLOCK_INTRINSIC
build_path = /obj/item/reagent_containers/hypospray/autoinjector/empty
- materials = list(
+ materials_base = list(
MAT_STEEL = 250,
MAT_GLASS = 250,
)
diff --git a/code/datums/design/designs/sheets.dm b/code/datums/design/designs/sheets.dm
index f7652801a16..47354831df7 100644
--- a/code/datums/design/designs/sheets.dm
+++ b/code/datums/design/designs/sheets.dm
@@ -5,7 +5,7 @@
id = "SheetReinforcedGlass"
lathe_type = LATHE_TYPE_AUTOLATHE
design_unlock = DESIGN_UNLOCK_INTRINSIC
- materials = list(
+ materials_base = list(
MAT_STEEL = 1000,
MAT_GLASS = 2000,
)
@@ -16,7 +16,7 @@
id = "SheetSteelRods"
lathe_type = LATHE_TYPE_AUTOLATHE
design_unlock = DESIGN_UNLOCK_INTRINSIC
- materials = list(
+ materials_base = list(
MAT_STEEL = 1000
)
build_path = /obj/item/stack/rods
diff --git a/code/datums/design/designs/tools/general.dm b/code/datums/design/designs/tools/general.dm
index ed687f1a45c..1b2643b8651 100644
--- a/code/datums/design/designs/tools/general.dm
+++ b/code/datums/design/designs/tools/general.dm
@@ -70,8 +70,8 @@
lathe_type = LATHE_TYPE_AUTOLATHE
design_unlock = DESIGN_UNLOCK_INTRINSIC
build_path = /obj/item/material/minihoe
- materials = list(MAT_STEEL = 50)
- material_parts = list(
+ materials_base = list(MAT_STEEL = 50)
+ material_costs = list(
"tip" = 250
)
diff --git a/code/datums/design/designs/weapons/knives.dm b/code/datums/design/designs/weapons/knives.dm
index 107ec837c2a..59d31c20844 100644
--- a/code/datums/design/designs/weapons/knives.dm
+++ b/code/datums/design/designs/weapons/knives.dm
@@ -4,9 +4,9 @@
build_path = /obj/item/material/knife/tacknife
lathe_type = LATHE_TYPE_AUTOLATHE
design_unlock = DESIGN_UNLOCK_INTRINSIC
- materials = list(
+ materials_base = list(
MAT_STEEL = 500,
)
- material_parts = list(
+ material_costs = list(
"blade" = 3000,
)
diff --git a/code/datums/design/designs/weapons/melee.dm b/code/datums/design/designs/weapons/melee.dm
index 90748774697..9b7f1da4ec6 100644
--- a/code/datums/design/designs/weapons/melee.dm
+++ b/code/datums/design/designs/weapons/melee.dm
@@ -3,7 +3,7 @@
build_path = /obj/item/clothing/gloves/knuckledusters
lathe_type = LATHE_TYPE_AUTOLATHE
design_unlock = DESIGN_UNLOCK_INTRINSIC
- materials = list(MAT_STEEL = 2000)
+ materials_base = list(MAT_STEEL = 2000)
/datum/design/weapon/flamethrower
id = "WeaponFlamethrower"
diff --git a/code/datums/design/designs/weapons/misc.dm b/code/datums/design/designs/weapons/misc.dm
index 27d14790bec..e5ec8d8f1b6 100644
--- a/code/datums/design/designs/weapons/misc.dm
+++ b/code/datums/design/designs/weapons/misc.dm
@@ -3,7 +3,7 @@
lathe_type = LATHE_TYPE_AUTOLATHE
design_unlock = DESIGN_UNLOCK_INTRINSIC
build_path = /obj/item/weaponcrafting/receiver
- materials = list(
+ materials_base = list(
MAT_STEEL = 8000,
MAT_GLASS = 2500,
)
diff --git a/code/datums/event_args/clickchain.dm b/code/datums/event_args/clickchain.dm
index ce2039376a3..4f350e9cae3 100644
--- a/code/datums/event_args/clickchain.dm
+++ b/code/datums/event_args/clickchain.dm
@@ -6,8 +6,11 @@
var/intent
/// click params
var/list/params
+ /// target atom
+ var/atom/target
-/datum/event_args/actor/clickchain/New(mob/performer, mob/initiator, intent, list/params)
+/datum/event_args/actor/clickchain/New(mob/performer, mob/initiator, atom/target, intent, list/params)
..()
+ src.target = target
src.intent = isnull(intent)? performer.a_intent : intent
src.params = isnull(params)? list() : params
diff --git a/code/datums/material_container.dm b/code/datums/material_container.dm
index 1ff12d6bbb4..5a940836055 100644
--- a/code/datums/material_container.dm
+++ b/code/datums/material_container.dm
@@ -32,7 +32,7 @@
if(isnull(stored))
return
for(var/mat_id in stored)
- var/datum/material/M = SSmaterials.get_material(mat_id)
+ var/datum/material/M = SSmaterials.resolve_material(mat_id)
if(isnull(M))
continue
var/safety = 50
@@ -67,7 +67,7 @@
if(amount < 0)
CRASH("negative amount?")
if(!istype(material))
- material = SSmaterials.get_material(material)
+ material = SSmaterials.resolve_material(material)
var/can_dump = round(stored[material.id] / SHEET_MATERIAL_AMOUNT)
var/dumping = min(amount, can_dump)
stored[material.id] -= dumping * SHEET_MATERIAL_AMOUNT
diff --git a/code/datums/position_point_vector.dm b/code/datums/position_point_vector.dm
index 869e47b743e..ed30566a0e6 100644
--- a/code/datums/position_point_vector.dm
+++ b/code/datums/position_point_vector.dm
@@ -117,6 +117,9 @@
/datum/point/proc/return_turf()
return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
+/datum/point/proc/clamped_return_turf()
+ return locate(clamp(CEILING(x / world.icon_size, 1), 1, world.maxx), clamp(CEILING(y / world.icon_size, 1), 1, world.maxy), z)
+
/datum/point/proc/return_coordinates() //[turf_x, turf_y, z]
return list(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
diff --git a/code/datums/repositories/ammomaterial.dm b/code/datums/repositories/ammomaterial.dm
index 0d9c5df3986..30eac92515c 100644
--- a/code/datums/repositories/ammomaterial.dm
+++ b/code/datums/repositories/ammomaterial.dm
@@ -12,7 +12,7 @@ var/global/datum/repository/ammomaterial/ammo_repository = new()
if(!(I in ammotypes))
ammotypes += I
var/obj/item/ammo_casing/temp = new I
- ammotypes[I] = temp.materials
+ ammotypes[I] = temp.materials_base
qdel(temp)
return ammotypes[I]
diff --git a/code/datums/shieldcall.dm b/code/datums/shieldcall.dm
new file mode 100644
index 00000000000..8f66b776107
--- /dev/null
+++ b/code/datums/shieldcall.dm
@@ -0,0 +1,22 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
+/**
+ * Shieldcall handling datums
+ */
+/datum/shieldcall
+ /// priority ; should never change once we're registered on something. lower has higher priority.
+ var/priority = 0
+ /// goes to mob when in inventory - whether equipped to slot or in hand
+ /// do not modify while applied. it will not un/register properly.
+ var/shields_in_inventory = TRUE
+
+/**
+ * sent over from the atom
+ *
+ * @params
+ * * defending - the atom in question
+ * * shieldcall_args - indexed list of shieldcall args.
+ */
+/datum/shieldcall/proc/handle_shieldcall(atom/defending, list/shieldcall_args)
+ return
diff --git a/code/modules/mob/living/carbon/human/unarmed_attack.dm b/code/datums/unarmed_attack.dm
similarity index 81%
rename from code/modules/mob/living/carbon/human/unarmed_attack.dm
rename to code/datums/unarmed_attack.dm
index 6cc17705fd9..2a7e1a9c575 100644
--- a/code/modules/mob/living/carbon/human/unarmed_attack.dm
+++ b/code/datums/unarmed_attack.dm
@@ -1,28 +1,58 @@
-var/global/list/sparring_attack_cache = list()
+GLOBAL_LIST_EMPTY(unarmed_attack_cache)
-//Species unarmed attacks
+/proc/fetch_unarmed_style(datum/unarmed_attack/path)
+ if(isnull(GLOB.unarmed_attack_cache[path]))
+ GLOB.unarmed_attack_cache[path] = new path
+ return GLOB.unarmed_attack_cache[path]
+
+/**
+ * Unarmed attacks for mobs
+ */
/datum/unarmed_attack
- var/attack_verb = list("attack") // Empty hand hurt intent verb.
- var/attack_noun = list("fist")
- var/damage = 0 // Extra empty hand attack damage.
+ //? Damage
+ /// damage amount - flat
+ var/damage = 5
+ /// add damage - low
+ var/damage_add_low = 0
+ /// add damage - high
+ var/damage_add_high = 0
+ /// damage mode flags
+ var/damage_mode = NONE
+ /// damage tier
+ var/damage_tier = MELEE_TIER_UNARMED_DEFAULT
+ /// damage type
+ var/damage_type = BRUTE
+ /// damage flag
+ var/damage_flag = ARMOR_MELEE
+
+ //? Sounds
+ /// sound when attacking
var/attack_sound = "punch"
+ /// sound when missing
var/miss_sound = 'sound/weapons/punchmiss.ogg'
- var/shredding = 0 // Calls the old attack_alien() behavior on objects/mobs when on harm intent.
- var/sharp = 0
- var/edge = 0
+
+ //? Visuals
+ /// ATTACK_ANIMATION_X enum
+ var/animation_type = ATTACK_ANIMATION_PUNCH
+
+ //? Text
+ /// past tense, aka "[person] has [past] [target] in their [zone]"
+ var/list/verb_past_participle = list("attacked")
+
+ //? legacy
+ var/attack_verb_legacy = list("attack") // Empty hand hurt intent verb.
+ var/attack_noun = list("fist")
var/infected_wound_probability = 10
- var/damage_type = BRUTE
var/sparring_variant_type = /datum/unarmed_attack/light_strike
var/eye_attack_text
var/eye_attack_text_victim
+//* Feedback
+
/datum/unarmed_attack/proc/get_sparring_variant()
- if(sparring_variant_type)
- if(!sparring_attack_cache[sparring_variant_type])
- sparring_attack_cache[sparring_variant_type] = new sparring_variant_type()
- return sparring_attack_cache[sparring_variant_type]
+ return fetch_unarmed_style(sparring_variant_type)
/datum/unarmed_attack/proc/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone)
if(user.restrained())
@@ -39,8 +69,8 @@ var/global/list/sparring_attack_cache = list()
return FALSE
-/datum/unarmed_attack/proc/get_unarmed_damage()
- return damage
+/datum/unarmed_attack/proc/get_unarmed_damage(mob/attacker, atom/defender)
+ return damage + rand(damage_add_low, damage_add_high)
/datum/unarmed_attack/proc/apply_effects(var/mob/living/carbon/human/user,var/mob/living/carbon/human/target,var/armour,var/attack_damage,var/zone)
@@ -74,7 +104,7 @@ var/global/list/sparring_attack_cache = list()
target.visible_message("[target] slams into [T]!")
if(prob(50))
target.setDir(global.reverse_dir[target.dir])
- target.apply_effect(attack_damage * 0.4, WEAKEN, armour)
+ target.apply_effect(attack_damage * 0.3, WEAKEN, armour)
if(BP_GROIN)
if(!target.isSynthetic())
target.visible_message("[target] looks like [TT.he] [TT.is] in pain!", "[(target.gender=="female") ? "Oh god that hurt!" : "Oh no, not your[pick("testicles", "crown jewels", "clockweights", "family jewels", "marbles", "bean bags", "teabags", "sweetmeats", "goolies")]!"]") // """""""I see no easy way to fix this for non-organic or neuter characters.""""""" - original coder
@@ -82,7 +112,7 @@ var/global/list/sparring_attack_cache = list()
if("l_leg", "l_foot", "r_leg", "r_foot")
if(!target.lying)
target.visible_message("[target] gives way slightly.")
- target.apply_effect(attack_damage*3, AGONY, armour)
+ target.apply_effect(attack_damage * 3, AGONY, armour)
else if(attack_damage >= 5 && !(target == user) && (stun_chance + attack_damage * 5 >= 100) && armour < 2) // Chance to get the usual throwdown as well (25% standard chance)
if(!target.lying)
target.visible_message("[target] [pick("slumps", "falls", "drops")] down to the ground!")
@@ -95,7 +125,7 @@ var/global/list/sparring_attack_cache = list()
var/obj/item/organ/external/affecting = target.get_organ(zone)
var/attack_message
var/datum/wound/W
- if(edge)
+ if(damage_mode & DAMAGE_MODE_EDGE)
W = affecting.create_specific_wound(/datum/wound/cut/small, 5)
attack_message = "leaves behind infested residue in [target]!"
else
@@ -107,7 +137,7 @@ var/global/list/sparring_attack_cache = list()
/datum/unarmed_attack/proc/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
var/obj/item/organ/external/affecting = target.get_organ(zone)
- user.visible_message("[user] [pick(attack_verb)] [target] in the [affecting.name]!")
+ user.visible_message("[user] [pick(attack_verb_legacy)] [target] in the [affecting.name]!")
playsound(user.loc, attack_sound, 25, 1, -1)
/datum/unarmed_attack/proc/handle_eye_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target)
@@ -126,14 +156,12 @@ var/global/list/sparring_attack_cache = list()
return FALSE //return true if the unarmed override prevents further attacks
/datum/unarmed_attack/bite
- attack_verb = list("bit")
+ verb_past_participle = list("bitten")
+ attack_verb_legacy = list("bit")
attack_sound = 'sound/weapons/bite.ogg'
- shredding = 0
- damage = 0
- sharp = 0
- edge = 0
-
-/datum/unarmed_attack/bite/event1
+ damage = 3
+ damage_mode = NONE
+ damage_tier = MELEE_TIER_UNARMED_FISTS
/datum/unarmed_attack/bite/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone)
@@ -144,13 +172,14 @@ var/global/list/sparring_attack_cache = list()
return TRUE
/datum/unarmed_attack/punch
- attack_verb = list("punched")
+ verb_past_participle = list("punched")
+ attack_verb_legacy = list("punched")
attack_noun = list("fist")
eye_attack_text = "fingers"
eye_attack_text_victim = "digits"
- damage = 0
-
-/datum/unarmed_attack/punch/event1
+ damage_add_low = 0
+ damage_add_high = 5
+ damage_tier = MELEE_TIER_UNARMED_FISTS
/datum/unarmed_attack/punch/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
var/obj/item/organ/external/affecting = target.get_organ(zone)
@@ -159,10 +188,10 @@ var/global/list/sparring_attack_cache = list()
var/datum/gender/TU = GLOB.gender_datums[user.get_visible_gender()]
var/datum/gender/TT = GLOB.gender_datums[target.get_visible_gender()]
- attack_damage = clamp(attack_damage, 1, 5) // We expect damage input of 1 to 5 for this proc. But we leave this check juuust in case.
+ attack_damage = clamp(attack_damage - 5, 1, 5) // We expect damage input of 1 to 5 for this proc. But we leave this check juuust in case.
if(target == user)
- user.visible_message("[user] [pick(attack_verb)] [TU.himself] in the [organ]!")
+ user.visible_message("[user] [pick(attack_verb_legacy)] [TU.himself] in the [organ]!")
return 0
if(!target.lying)
@@ -174,7 +203,7 @@ var/global/list/sparring_attack_cache = list()
user.visible_message("[user] slapped [target] across [TT.his] cheek!")
if(3 to 4)
user.visible_message(pick(
- 40; "[user] [pick(attack_verb)] [target] in the head!",
+ 40; "[user] [pick(attack_verb_legacy)] [target] in the head!",
30; "[user] struck [target] in the head[pick("", " with a closed fist")]!",
30; "[user] threw a hook against [target]'s head!"
))
@@ -188,7 +217,7 @@ var/global/list/sparring_attack_cache = list()
// ----- BODY ----- //
switch(attack_damage)
if(1 to 2) user.visible_message("[user] threw a glancing punch at [target]'s [organ]!")
- if(1 to 4) user.visible_message("[user] [pick(attack_verb)] [target] in [TT.his] [organ]!")
+ if(1 to 4) user.visible_message("[user] [pick(attack_verb_legacy)] [target] in [TT.his] [organ]!")
if(5)
user.visible_message(pick(
50; "[user] smashed [TU.his] [pick(attack_noun)] into [target]'s [organ]!",
@@ -198,12 +227,12 @@ var/global/list/sparring_attack_cache = list()
user.visible_message("[user] [pick("punched", "threw a punch against", "struck", "slammed [TU.his] [pick(attack_noun)] into")] [target]'s [organ]!") //why do we have a separate set of verbs for lying targets?
/datum/unarmed_attack/kick
- attack_verb = list("kicked", "kicked", "kicked", "kneed")
+ verb_past_participle = list("kicked")
+ attack_verb_legacy = list("kicked", "kicked", "kicked", "kneed")
attack_noun = list("kick", "kick", "kick", "knee strike")
attack_sound = "swing_hit"
- damage = 0
-
-/datum/unarmed_attack/kick/event1
+ damage_add_low = 0
+ damage_add_high = 5
/datum/unarmed_attack/kick/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone)
if (user.legcuffed)
@@ -226,27 +255,27 @@ var/global/list/sparring_attack_cache = list()
var/obj/item/clothing/shoes = user.shoes
if(!istype(shoes))
return damage
- return damage + (shoes ? shoes.damage_force : 0)
+ return damage + max(0, shoes ? shoes.damage_force - 5 : 0)
/datum/unarmed_attack/kick/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
var/obj/item/organ/external/affecting = target.get_organ(zone)
var/datum/gender/TT = GLOB.gender_datums[target.get_visible_gender()]
var/organ = affecting.name
- attack_damage = clamp(attack_damage, 1, 5)
+ attack_damage = clamp(attack_damage - 5, 1, 5)
switch(attack_damage)
if(1 to 2) user.visible_message("[user] threw [target] a glancing [pick(attack_noun)] to the [organ]!") //it's not that they're kicking lightly, it's that the kick didn't quite connect
- if(3 to 4) user.visible_message("[user] [pick(attack_verb)] [target] in [TT.his] [organ]!")
+ if(3 to 4) user.visible_message("[user] [pick(attack_verb_legacy)] [target] in [TT.his] [organ]!")
if(5) user.visible_message("[user] landed a strong [pick(attack_noun)] against [target]'s [organ]!")
/datum/unarmed_attack/stomp
- attack_verb = null
+ verb_past_participle = list("stomped")
+ attack_verb_legacy = list("stomped")
attack_noun = list("stomp")
attack_sound = "swing_hit"
- damage = 0
-
-/datum/unarmed_attack/stomp/event1
+ damage_add_low = 0
+ damage_add_high = 5
/datum/unarmed_attack/stomp/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone)
@@ -271,7 +300,7 @@ var/global/list/sparring_attack_cache = list()
/datum/unarmed_attack/stomp/get_unarmed_damage(var/mob/living/carbon/human/user)
var/obj/item/clothing/shoes = user.shoes
- return damage + (shoes ? shoes.damage_force : 0)
+ return damage + max(0, shoes ? shoes.damage_force - 5 : 0)
/datum/unarmed_attack/stomp/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
var/obj/item/organ/external/affecting = target.get_organ(zone)
@@ -279,18 +308,16 @@ var/global/list/sparring_attack_cache = list()
var/obj/item/clothing/shoes = user.shoes
var/datum/gender/TU = GLOB.gender_datums[user.get_visible_gender()]
- attack_damage = clamp(attack_damage, 1, 5)
+ attack_damage = clamp(attack_damage - 5, 1, 5)
switch(attack_damage)
if(1 to 4) user.visible_message("[pick("[user] stomped on", "[user] slammed [TU.his] [shoes ? copytext(shoes.name, 1, -1) : "foot"] down onto")] [target]'s [organ]!")
if(5) user.visible_message("[pick("[user] landed a powerful stomp on", "[user] stomped down hard on", "[user] slammed [TU.his] [shoes ? copytext(shoes.name, 1, -1) : "foot"] down hard onto")] [target]'s [organ]!") //Devastated lol. No. We want to say that the stomp was powerful or forceful, not that it /wrought devastation/
/datum/unarmed_attack/light_strike
+ verb_past_participle = list("lightly struck")
attack_noun = list("tap","light strike")
- attack_verb = list("tapped", "lightly struck")
- damage = 3
+ attack_verb_legacy = list("tapped", "lightly struck")
+ damage = 5
+ damage_mode = NONE
damage_type = AGONY
- shredding = 0
- damage = 0
- sharp = 0
- edge = 0
diff --git a/code/game/atoms/action_feedback.dm b/code/game/atoms/action_feedback.dm
index 096a003c3c1..a9876c1b19c 100644
--- a/code/game/atoms/action_feedback.dm
+++ b/code/game/atoms/action_feedback.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
//* Action feedback module
//* Handles giving chat feedback for actions performed by an atom,
//* whether to the atom, to the target, or to everyone around
diff --git a/code/game/atoms/atom.dm b/code/game/atoms/atom.dm
index 18d89a31e4c..e203d343e7a 100644
--- a/code/game/atoms/atom.dm
+++ b/code/game/atoms/atom.dm
@@ -46,6 +46,8 @@
var/list/context_menus
//? Economy
+ // todo: move all this to obj level, you aren't going to sell a fucking turf.
+ // the procs can however stay.
/// intrinsic worth without accounting containing reagents / materials - applies in static and dynamic mode.
var/worth_intrinsic = 0
/// static worth of contents - only read if getting a static worth from typepath.
@@ -68,18 +70,18 @@
*/
var/worth_dynamic = FALSE
- //? Health
- // todo: every usage of these vars need to be parsed because shitcode still exists that
- // todo: was just monkey patched over by making it not compile error for redefining this..
+ //? Integrity
/// max health
- var/max_integrity
+ var/integrity_max
/// health
var/integrity
/// what integrity we call break at.
- var/failure_integrity = 0
- /// do we use the atom damage system?
- var/use_integrity = FALSE
- // todo: use integrity & procs on turf and obj level
+ var/integrity_failure = 0
+ /// do we use the atom damage system? having this off implicitly implies non-targetability for this entity,
+ /// completely overriding any object flags at /obj levels for targeting.
+ var/integrity_enabled = FALSE
+ /// flags for resistances
+ var/integrity_flags = NONE
//? HUDs
/// This atom's HUD (med/sec, etc) images. Associative list.
@@ -136,13 +138,37 @@
/// Shows up under a UV light.
var/fluorescent
+ //? Materials
+ /// combined material trait flags
+ /// this list is at /atom level but are only used/implemented on /obj generically; anything else, e.g. walls, should implement manually for efficiency.
+ var/material_trait_flags = NONE
+ /// material traits on us, associated to metadata
+ /// this list is at /atom level but are only used/implemented on /obj generically; anything else, e.g. walls, should implement manually for efficiency.
+ var/list/datum/material_trait/material_traits
+ /// material trait metadata when [material_traits] is a single trait. null otherwise.
+ var/material_traits_data
+ /// 'stacks' of ticking
+ /// this synchronizes the system so removing one ticking material trait doesn't fully de-tick the entity
+ //! DO NOT FUCK WITH THIS UNLESS YOU KNOW WHAT YOU ARE DOING
+ var/material_ticking_counter = 0
+ /// material trait relative strength
+ /// applies to all traits globally as opposed to just one material parts,
+ /// because this is at /atom level.
+ var/material_traits_multiplier = 1
+
//? Radiation
/// radiation flags
var/rad_flags = RAD_NO_CONTAMINATE // overridden to NONe in /obj and /mob base
/// radiation insulation - does *not* affect rad_act!
var/rad_insulation = RAD_INSULATION_NONE
/// contamination insulation; null defaults to rad_insulation, this is a multiplier. *never* set higher than 1!!
- var/rad_stickiness
+ var/rad_stickiness = 1
+
+ //? Shieldcalls
+ /// sorted priority list of datums for handling shieldcalls with
+ /// we use this instead of signals so we can enforce priorities
+ /// this is horrifying.
+ var/list/datum/shieldcall/shieldcalls
//? Overlays
/// vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays.
@@ -176,6 +202,13 @@
/// The orbiter comopnent if we're being orbited.
var/datum/component/orbiter/orbiters
+ //? Sounds
+ /// Default sound played on impact when damaged by a weapon / projectile / whatnot. This is usually null for default.
+ var/hit_sound_brute
+ /// Default sound played on a burn type impact. This is usually null for default.
+ var/hit_sound_burn
+
+
/**
* Called when an atom is created in byond (built in engine proc)
*
@@ -328,19 +361,6 @@
/atom/proc/HasProximity(atom/movable/proximity_check_mob as mob|obj)
return
-/atom/proc/emp_act(var/severity)
- // todo: SHOULD_CALL_PARENT(TRUE)
- SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity)
-
-
-/atom/proc/bullet_act(obj/projectile/P, def_zone)
- P.on_hit(src, 0, def_zone)
- . = 0
-
-// Called when a blob expands onto the tile the atom occupies.
-/atom/proc/blob_act()
- return
-
///Return true if we're inside the passed in atom
/atom/proc/in_contents_of(container)//can take class or object instance as argument
if(ispath(container))
@@ -431,6 +451,8 @@
. += get_name_chaser(user)
if(desc)
. += "
[desc]"
+ if(integrity_flags & INTEGRITY_INDESTRUCTIBLE)
+ . += SPAN_NOTICE("It doesn't look like it can be damaged through common means.")
/*
if(custom_materials)
var/list/materials_list = list()
@@ -465,6 +487,8 @@
else
. += SPAN_DANGER("It's empty.")
+ MATERIAL_INVOKE(src, MATERIAL_TRAIT_EXAMINE, on_examine, ., user, dist)
+
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
/**
@@ -505,43 +529,10 @@
invisibility = new_invisibility
return TRUE
-/**
- * React to being hit by an explosion
- *
- * Should be called through the [EX_ACT] wrapper macro.
- * The wrapper takes care of the [COMSIG_ATOM_EX_ACT] signal.
- * as well as calling [/atom/proc/contents_explosion].
- */
-/atom/proc/legacy_ex_act(severity, target)
- set waitfor = FALSE
-
-/**
- * todo: implement on most atoms/generic damage system
- * todo: replace legacy_ex_act entirely with this
- *
- * React to being hit by an explosive shockwave
- *
- * ? Tip for overrides: . = ..() when you want signal to be sent, mdify power before if you need to; to ignore parent
- * ? block power, just `return power` in your proc after . = ..().
- *
- * @params
- * - power - power our turf was hit with
- * - direction - DIR_BIT bits; can bwe null if it wasn't a wave explosion!!
- * - explosion - explosion automata datum; can be null
- *
- * @return power after falloff (e.g. hit with 30 power, return 20 to apply 10 falloff)
- */
-/atom/proc/ex_act(power, dir, datum/automata/wave/explosion/E)
- SHOULD_CALL_PARENT(TRUE)
- SEND_SIGNAL(src, COMSIG_ATOM_EX_ACT, power, dir, E)
- return power
-
// todo: this really needs to be refactored
/atom/proc/emag_act(var/remaining_charges, var/mob/user, var/emag_source)
return -1
-/atom/proc/fire_act()
- return
// Returns an assoc list of RCD information.
// Example would be: list(RCD_VALUE_MODE = RCD_DECONSTRUCT, RCD_VALUE_DELAY = 50, RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 4)
@@ -1131,12 +1122,3 @@
/atom/proc/auto_pixel_offset_to_center()
set_base_pixel_y(get_centering_pixel_y_offset())
set_base_pixel_x(get_centering_pixel_x_offset())
-
-//? materials
-
-/**
- * get raw materials remaining in us as list (not reagents)
- * used from everything from economy to lathe recycling
- */
-/atom/proc/get_materials()
- return list()
diff --git a/code/game/atoms/buckling.dm b/code/game/atoms/buckling.dm
index 32f3da64bee..45e68574979 100644
--- a/code/game/atoms/buckling.dm
+++ b/code/game/atoms/buckling.dm
@@ -1,9 +1,14 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
/atom/movable/MouseDroppedOn(atom/dropping, mob/user, proximity, params)
if(drag_drop_buckle_interaction(dropping, user))
return CLICKCHAIN_DO_NOT_PROPAGATE
return ..()
/atom/movable/attack_hand(mob/user, list/params)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
. = ..()
if(.)
return
diff --git a/code/game/atoms/defense.dm b/code/game/atoms/defense.dm
index ff52deca31a..cb37faf013e 100644
--- a/code/game/atoms/defense.dm
+++ b/code/game/atoms/defense.dm
@@ -1,13 +1,374 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
//! Welcome to the atom damage module.
//! Enjoy the bitfield and #define vomit.
+//? Hooks / External
+
+/**
+ * todo: implement on most atoms/generic damage system
+ * todo: replace legacy_ex_act entirely with this
+ *
+ * React to being hit by an explosive shockwave
+ *
+ * ? Tip for overrides: . = ..() when you want signal to be sent, mdify power before if you need to; to ignore parent
+ * ? block power, just `return power` in your proc after . = ..().
+ *
+ * @params
+ * - power - power our turf was hit with
+ * - direction - DIR_BIT bits; can bwe null if it wasn't a wave explosion!!
+ * - explosion - explosion automata datum; can be null
+ *
+ * @return power after falloff (e.g. hit with 30 power, return 20 to apply 10 falloff)
+ */
+/atom/proc/ex_act(power, dir, datum/automata/wave/explosion/E)
+ SHOULD_CALL_PARENT(TRUE)
+ SEND_SIGNAL(src, COMSIG_ATOM_EX_ACT, power, dir, E)
+ return power
+
+/**
+ * called on melee hit
+ *
+ * @params
+ * * user - person attacking
+ * * weapon - weapon used
+ * * target_zone - zone targeted
+ * * mult - damage multiplier
+ *
+ * @return clickchain flags to append
+ */
+/atom/proc/melee_act(mob/user, obj/item/weapon, target_zone, mult = 1)
+ return CLICKCHAIN_DO_NOT_ATTACK
+
+/**
+ * called on unarmed melee hit
+ *
+ * @params
+ * * user - person attacking
+ * * style - unarmed attack datum
+ * * target_zone - zone targeted
+ * * mult - damage multiplier
+ *
+ * @return clickchain flags to append
+ */
+/atom/proc/unarmed_act(mob/attacker, datum/unarmed_attack/style, target_zone, mult = 1)
+ return CLICKCHAIN_DO_NOT_ATTACK
+
+//? Damage API
+
+/**
+ * takes damage from a generic attack, taking into account armor but not shields.
+ * this does not handle playing sounds / anything, this is strictly generic damage handling
+ * usable by anything.
+ *
+ * @params
+ * * damage - raw damage
+ * * tier - (optional) penetration / attack tier
+ * * flag - (optional) armor flag as seen in [code/__DEFINES/combat/armor.dm]; leave out to not run armor.
+ * * mode - (optional) damage_mode
+ * * attack_type - (optional) attack type flags from [code/__DEFINES/combat/attack_types.dm]
+ * * weapon - (optional) attacking /obj/item for melee or thrown, /obj/projectile for ranged, /mob for unarmed
+ * * gradual - loud effects like glass clanging should not happen. use for stuff like acid and fire.
+ *
+ * @return raw damage taken
+ */
+/atom/proc/inflict_atom_damage(damage, tier, flag, mode, attack_type, datum/weapon, gradual)
+ if(!integrity_enabled)
+ return 0
+ if(integrity_flags & INTEGRITY_INDESTRUCTIBLE)
+ return 0
+ if(flag)
+ var/list/returned = run_armor(arglist(args))
+ damage = returned[1]
+ mode = returned[4]
+ if(!damage)
+ return
+ . = integrity
+ damage_integrity(damage)
+ . = . - integrity
+
+//? Hitsound API
+
+// todo: stuff like metal limbs punching walls making special sounds
+
+/**
+ * gets hitsound override. return a value to be fed into playsound, or null for default.
+ *
+ * @params
+ * * damage_type - damage type like brute / burn / etc
+ * * damage_mode - damage mode for piercing / whatnot
+ * * attack_type - attack type enum like melee / projectile / thrown / unarmed / etc
+ * * weapon - attacking /obj/item for melee / thrown, /obj/projectile for ranged, /mob for unarmed
+ */
+/atom/proc/hitsound_override(damage_type, damage_mode, attack_type, datum/weapon)
+ return // default is null
+
+/atom/proc/hitsound_melee(obj/item/I)
+ . = I.attacksound_override(src, ATTACK_TYPE_MELEE)
+ if(!isnull(.))
+ return
+ . = hitsound_override(I.damtype, I.damage_mode, ATTACK_TYPE_MELEE, I)
+ if(.)
+ return
+ . = (I.damtype == BURN? hit_sound_burn : hit_sound_brute) || I.attack_sound
+ if(.)
+ return
+ switch(I.damtype)
+ if(BRUTE)
+ return "swing_hit"
+ if(BURN)
+ return "'sound/items/welder.ogg"
+ else
+ return "swing_hit"
+
+/atom/proc/hitsound_projectile(obj/projectile/P)
+ //? todo: projectile gets final say
+ . = hitsound_override(P.damtype, P.damage_mode, ATTACK_TYPE_PROJECTILE, P)
+ if(.)
+ return
+ return islist(P.impact_sounds)? pick(P.impact_sounds) : P.impact_sounds
+
+/atom/proc/hitsound_throwhit(obj/item/I)
+ . = I.attacksound_override(src, ATTACK_TYPE_THROWN)
+ if(!isnull(.))
+ return
+ . = hitsound_override(I.damtype, I.damage_mode, ATTACK_TYPE_THROWN, I)
+ if(.)
+ return
+ . = (I.damtype == BURN? hit_sound_burn : hit_sound_brute) || I.attack_sound
+ if(.)
+ return
+ switch(I.damtype)
+ if(BRUTE)
+ return "swing_hit"
+ if(BURN)
+ return 'sound/items/welder.ogg'
+ else
+ return "swing_hit"
+
+/atom/proc/hitsound_unarmed(mob/M, datum/unarmed_attack/style)
+ //? todo: style gets final say
+ . = hitsound_override(M, style.damage_mode, ATTACK_TYPE_UNARMED, style)
+ if(.)
+ return
+ // todo: way to override this from style side? we don't just want hitsound brute/burn.
+ . = (style.damage_type == BURN? hit_sound_burn : hit_sound_brute) || style.attack_sound
+
+//? Direct Integrity
+
+/**
+ * damages integrity directly, ignoring armor / shields
+ *
+ * @params
+ * * amount - how much
+ * * gradual - burst or gradual? if you want to play a sound or something, you usually want to check this.
+ * * do_not_break - skip calling atom_break
+ */
+/atom/proc/damage_integrity(amount, gradual, do_not_break)
+ SHOULD_CALL_PARENT(TRUE)
+ SHOULD_NOT_SLEEP(TRUE)
+ var/was_working = integrity > integrity_failure
+ integrity = max(0, integrity - amount)
+ if(was_working && integrity <= integrity_failure && !do_not_break)
+ atom_break()
+ if(integrity <= 0)
+ atom_destruction()
+
+/**
+ * heals integrity directly
+ *
+ * @params
+ * * amount - how much
+ * * gradual - burst or gradual? if you want to play a sound or something, you usually want to check this.
+ * * do_not_fix - skip calling atom_fix
+ *
+ * @return amount healed
+ */
+/atom/proc/heal_integrity(amount, gradual, do_not_fix)
+ SHOULD_CALL_PARENT(TRUE)
+ SHOULD_NOT_SLEEP(TRUE)
+ var/was_failing = integrity <= integrity_failure
+ . = integrity
+ integrity = min(integrity_max, integrity + amount)
+ . = integrity - .
+ if(was_failing && integrity > integrity_failure && !do_not_fix)
+ atom_fix()
+
+/**
+ * directly sets integrity - ignores armor / sihelds
+ *
+ * will not call [damage_integrity] or [heal_integrity]
+ * will call [atom_break], [atom_fix], [atom_destruction]
+ *
+ * @params
+ * * amount - how much to set to?
+ */
+/atom/proc/set_integrity(amount)
+ SHOULD_CALL_PARENT(TRUE)
+ SHOULD_NOT_SLEEP(TRUE)
+ var/was_failing = integrity <= integrity_failure
+ integrity = clamp(amount, 0, integrity_max)
+ if(!was_failing && integrity <= integrity_failure)
+ atom_break()
+ else if(was_failing && integrity > integrity_failure)
+ atom_fix()
+ if(integrity <= 0)
+ atom_destruction()
+
+/**
+ * sets max integrity - will automatically reduce integrity if it's above max.
+ *
+ * will not call [damage_integrity]
+ * will call [atom_break], [atom_fix], [atom_destruction]
+ *
+ * @params
+ * * amount - how much to set to
+ */
+/atom/proc/set_max_integrity(amount)
+ integrity_max = max(amount, 0)
+ if(integrity < integrity_max)
+ return
+ var/was_broken = integrity <= integrity_failure
+ integrity = integrity_max
+ if(!was_broken && (integrity <= integrity_failure))
+ atom_break()
+ if(integrity <= 0)
+ atom_destruction()
+
+/**
+ * sets integrity and max integrity - will automatically reduce integrity if it's above max.
+ *
+ * will not call [damage_integrity]
+ * will call [atom_break], [atom_fix], [atom_destruction]
+ *
+ * @params
+ * * integrity - how much to set integrity to
+ * * integrity_max - how much to set integrity_max to
+ */
+/atom/proc/set_full_integrity(integrity, integrity_max)
+ src.integrity_max = max(integrity_max, 0)
+ var/was_broken = src.integrity <= integrity_failure
+ src.integrity = clamp(integrity, 0, integrity_max)
+ var/now_broken = integrity <= integrity_failure
+ if(!was_broken && now_broken)
+ atom_break()
+ else if(was_broken && !now_broken)
+ atom_fix()
+ if(integrity <= 0)
+ atom_destruction()
+
+/**
+ * Set integrity to a multiple of initial.
+ *
+ * And fully restore it if specified.
+ * Otherwise, will retain the last percentage.
+ */
+/atom/proc/set_multiplied_integrity(factor, restore)
+ var/was_broken = src.integrity <= integrity_failure
+ if(restore)
+ integrity = integrity_max = initial(integrity_max) * factor
+ if(was_broken && integrity > integrity_failure)
+ atom_fix()
+ return
+ var/ratio = integrity / integrity_max
+ integrity_max = initial(integrity_max) * factor
+ integrity = integrity_max * ratio
+ var/now_broken = integrity <= integrity_failure
+ if(!was_broken && now_broken)
+ atom_break()
+ else if(was_broken && !now_broken)
+ atom_fix()
+ if(integrity <= 0)
+ atom_destruction()
+
+/**
+ * adjusts integrity - routes directly to [damage_integrity] and [heal_integrity]
+ *
+ * will call [damage_integrity]
+ * will call [atom_break], [atom_fix], [atom_destruction]
+ *
+ * @params
+ * * amount - how much
+ * * gradual - burst or gradual?
+ * * no_checks - do not call fix/break
+ */
+/atom/proc/adjust_integrity(amount, gradual, no_checks)
+ SHOULD_CALL_PARENT(TRUE)
+ SHOULD_NOT_SLEEP(TRUE)
+ if(amount > 0)
+ return heal_integrity(amount, gradual, no_checks)
+ else
+ return damage_integrity(amount, gradual, no_checks)
+
+/**
+ * adjusts max integrity - will automatically reduce integrity if it's above max.
+ *
+ * will call [damage_integrity]
+ * will call [atom_break], [atom_fix], [atom_destruction]
+ *
+ * @params
+ * * amount - how much to adjust by
+ * * gradual - burst or gradual?
+ */
+/atom/proc/adjust_max_integrity(amount, gradual)
+ // lazy route lmao
+ set_max_integrity(integrity_max + amount)
+
+/**
+ * percent integrity, rounded.
+ */
+/atom/proc/percent_integrity(round_to = 0.1)
+ return integrity_max? round(integrity / integrity_max, round_to) : 0
+
+/atom/proc/is_integrity_broken()
+ return atom_flags & ATOM_BROKEN
+
+/atom/proc/is_integrity_damaged()
+ return integrity < integrity_max
+
+//? Thresholds & Events
+
+/**
+ * called when integrity reaches 0 from a non 0 value
+ */
+/atom/proc/atom_destruction()
+ SHOULD_CALL_PARENT(TRUE)
+ SHOULD_NOT_SLEEP(TRUE)
+ if(!(integrity_flags & INTEGRITY_NO_DECONSTRUCT))
+ deconstruct(ATOM_DECONSTRUCT_DESTROYED)
+
+/**
+ * called when integrity drops below or at integrity_failure
+ *
+ * if integrity_failure is 0, this is called before destruction.
+ */
+/atom/proc/atom_break()
+ SHOULD_CALL_PARENT(TRUE)
+ SHOULD_NOT_SLEEP(TRUE)
+ if(integrity > integrity_failure)
+ damage_integrity(integrity - integrity_failure, do_not_break = TRUE)
+ atom_flags |= ATOM_BROKEN
+
+/**
+ * called when integrity rises above integrity_failure
+ *
+ * if integrity_failure is 0, this still works.
+ */
+/atom/proc/atom_fix()
+ SHOULD_CALL_PARENT(TRUE)
+ SHOULD_NOT_SLEEP(TRUE)
+ if(integrity < integrity_failure)
+ heal_integrity(integrity_failure - integrity + 1, do_not_fix = TRUE)
+ atom_flags &= ~ATOM_BROKEN
+
//? Deconstruction
/**
* called to semantically deconstruct an atom
*
* @params
- * - method - how we were deconstructed
+ * * method - how we were deconstructed
*/
/atom/proc/deconstruct(method = ATOM_DECONSTRUCT_DISASSEMBLED)
SHOULD_NOT_OVERRIDE(TRUE)
@@ -17,8 +378,14 @@
// do da funny logic
deconstructed(method)
// drop things after so things that rely on having objects don't break
- drop_products(method)
+ drop_products(method, drop_location())
// goodbye, cruel world
+ break_apart(method)
+
+/**
+ * called to actually destroy ourselves
+ */
+/atom/proc/break_apart(method)
qdel(src)
/**
@@ -37,8 +404,9 @@
*
* @params
* * method - how we were deconstructed
+ * * where - where to drop products; set in base if null to drop_location().
*/
-/atom/proc/drop_products(method)
+/atom/proc/drop_products(method, atom/where = drop_location())
return
/**
@@ -74,7 +442,13 @@
*/
/atom/proc/fetch_armor()
RETURN_TYPE(/datum/armor)
- return armor || (armor = fetch_armor_struct(armor_type))
+ return armor || (armor = generate_armor())
+
+/**
+ * get default armor datum
+ */
+/atom/proc/generate_armor()
+ return fetch_armor_struct(armor_type)
/**
* calculates the resulting damage from an attack, taking into account our armor and soak
@@ -117,23 +491,54 @@
* checks for shields
* not always accurate
*
- * todo: use pointers instead
- *
* params are modified and then returned as a list.
+ *
+ * @params
+ * * damage - raw damage
+ * * damtype - damage type
+ * * tier - penetration / attack tier
+ * * flag - armor flag as seen in [code/__DEFINES/combat/armor.dm]
+ * * mode - damage_mode
+ * * attack_type - (optional) attack type flags from [code/__DEFINES/combat/attack_types.dm]
+ * * weapon - (optional) attacking /obj/item for melee or thrown, /obj/projectile for ranged, /mob for unarmed
+ * * additional - a way to retrieve data out of the shieldcall, passed in by attacks. [code/__DEFINES/dcs/signals/atoms/signals_atom_defense.dm]
+ * * retval - shieldcall flags passed through components. [code/__DEFINES/dcs/signals/atoms/signals_atom_defense.dm]
+ *
+ * @return modified args as list
*/
-/atom/proc/atom_shieldcheck(damage, tier, flag, mode, attack_type, datum/weapon, list/additional = list(), retval = NONE)
+/atom/proc/atom_shieldcheck(damage, damtype, tier, flag, mode, attack_type, datum/weapon, list/additional = list(), retval = NONE)
retval |= SHIELDCALL_JUST_CHECKING
- SEND_SIGNAL(src, COMSIG_ATOM_SHIELDCALL, args)
+ for(var/datum/shieldcall/calling as anything in shieldcalls)
+ calling.handle_shieldcall(src, args)
return args.Copy()
/**
* runs an attack against shields
* side effects are allowed
*
- * todo: use pointers instead
- *
* params are modified and then returned as a list
+ *
+ * @params
+ * * damage - raw damage
+ * * damtype - damage type
+ * * tier - penetration / attack tier
+ * * flag - armor flag as seen in [code/__DEFINES/combat/armor.dm]
+ * * mode - damage_mode
+ * * attack_type - (optional) attack type flags from [code/__DEFINES/combat/attack_types.dm]
+ * * weapon - (optional) attacking /obj/item for melee or thrown, /obj/projectile for ranged, /mob for unarmed
+ * * additional - a way to retrieve data out of the shieldcall, passed in by attacks. [code/__DEFINES/combat/shieldcall.dm]
+ * * retval - shieldcall flags passed through components. [code/__DEFINES/combat/shieldcall.dm]
+ *
+ * @return modified args as list
*/
-/atom/proc/atom_shieldcall(damage, tier, flag, mode, attack_type, datum/weapon, list/additional = list(), retval = NONE)
- SEND_SIGNAL(src, COMSIG_ATOM_SHIELDCALL, args)
+/atom/proc/atom_shieldcall(damage, damtype, tier, flag, mode, attack_type, datum/weapon, list/additional = list(), retval = NONE)
+ for(var/datum/shieldcall/calling as anything in shieldcalls)
+ calling.handle_shieldcall(src, args)
return args.Copy()
+
+/atom/proc/register_shieldcall(datum/shieldcall/delegate)
+ LAZYINITLIST(shieldcalls)
+ BINARY_INSERT(delegate, shieldcalls, /datum/shieldcall, delegate, priority, COMPARE_KEY)
+
+/atom/proc/unregister_shieldcall(datum/shieldcall/delegate)
+ LAZYREMOVE(shieldcalls, delegate)
diff --git a/code/game/atoms/defense_old.dm b/code/game/atoms/defense_old.dm
new file mode 100644
index 00000000000..ab7d141eed0
--- /dev/null
+++ b/code/game/atoms/defense_old.dm
@@ -0,0 +1,31 @@
+/**
+ * React to being hit by an explosion
+ *
+ * Should be called through the [EX_ACT] wrapper macro.
+ * The wrapper takes care of the [COMSIG_ATOM_EX_ACT] signal.
+ * as well as calling [/atom/proc/contents_explosion].
+ */
+/atom/proc/legacy_ex_act(severity, target)
+ set waitfor = FALSE
+
+/atom/proc/emp_act(var/severity)
+ // todo: SHOULD_CALL_PARENT(TRUE)
+ SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity)
+
+/atom/proc/bullet_act(obj/projectile/P, def_zone)
+ P.on_hit(src, 0, def_zone)
+ . = 0
+
+// Called when a blob expands onto the tile the atom occupies.
+/atom/proc/blob_act()
+ return
+
+/**
+ * called when being burned in a fire
+ *
+ * this is explicitly for ZAS only
+ *
+ * todo: make params (air, temperature, dt), so this is more generic
+ */
+/atom/proc/fire_act(datum/gas_mixture/air, temperature, volume)
+ return
diff --git a/code/game/atoms/materials.dm b/code/game/atoms/materials.dm
new file mode 100644
index 00000000000..ff947557228
--- /dev/null
+++ b/code/game/atoms/materials.dm
@@ -0,0 +1,73 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
+/**
+ * get raw materials remaining in us as list (not reagents)
+ * used from everything from economy to lathe recycling
+ *
+ * for things like stacks, this is amount per sheet.
+ *
+ * @params
+ * * respect_multiplier - respect material_multiplier which is often used to modify atom materials when efficiency is higher in lathes.
+ *
+ * @return list of id to amount
+ */
+/atom/proc/get_materials(respect_multiplier)
+ return list()
+
+/// ensure this is called once and only once when a material is added to an atom
+/// alternatively, don't call this at all if you don't want to register traits.
+/// this should null-check, as null is a valid material.
+/atom/proc/register_material(datum/material/mat, primary)
+ if(!isnull(mat?.material_traits))
+ for(var/datum/material_trait/trait as anything in mat.material_traits)
+ if(islist(material_traits))
+ var/old_data = material_traits[trait]
+ material_traits[trait] = trait.on_add(src, old_data, mat.material_traits[trait])
+ material_trait_flags |= trait.material_trait_flags
+ else if(isnull(material_traits))
+ material_traits = trait
+ material_traits_data = trait.on_add(src, null, mat.material_traits[trait])
+ material_trait_flags = trait.material_trait_flags
+ else
+ var/datum/material_trait/other = material_traits
+ var/old_data = material_traits_data
+ if(other == trait)
+ material_traits_data = trait.on_add(src, old_data, mat.material_traits[trait])
+ else
+ // we wrap other, trait in ()'s so byond's list() syntax doesn't turn them into strings rather than the actual referneces.
+ material_traits = list((other) = old_data, (trait) = trait.on_add(old_data, mat.material_traits[trait]))
+ material_traits_data = null
+ material_trait_flags = other.material_trait_flags | trait.material_trait_flags
+
+/// ensure this is called once and only once when a material is deleted from an atom
+/// this is only to be used if the material was registered. if it was never registered, DO NOT call this.
+/// this should null-check, as null is a valid material.
+/atom/proc/unregister_material(datum/material/mat, primary)
+ if(!isnull(mat?.material_traits))
+ for(var/datum/material_trait/trait as anything in mat.material_traits)
+ if(islist(material_traits))
+ var/old_data = material_traits[trait]
+ var/new_data = trait.on_remove(src, old_data, mat.material_traits[trait])
+ if(isnull(new_data))
+ material_traits -= trait
+ if(length(material_traits) == 1)
+ var/datum/material_trait/other = material_traits[1]
+ material_traits_data = material_traits[other]
+ material_traits = other
+ material_trait_flags = other.material_trait_flags
+ else
+ material_trait_flags = NONE
+ for(var/datum/material_trait/other as anything in material_traits)
+ material_trait_flags |= other.material_trait_flags
+ else
+ material_traits[trait] = new_data
+ else
+ ASSERT(material_traits == trait)
+ var/new_data = trait.on_remove(src, material_traits_data, mat.material_traits[trait])
+ if(isnull(new_data))
+ material_traits = null
+ material_traits_data = null
+ material_trait_flags = NONE
+ else
+ material_traits_data = new_data
diff --git a/code/game/atoms/movable/movable.dm b/code/game/atoms/movable/movable.dm
index d7b1aea55c3..0c3844410d5 100644
--- a/code/game/atoms/movable/movable.dm
+++ b/code/game/atoms/movable/movable.dm
@@ -203,22 +203,6 @@
if(mover.loc in locs)
. = TRUE
-//Overlays
-/atom/movable/overlay
- atom_flags = ATOM_ABSTRACT
- var/atom/master = null
- anchored = TRUE
-
-/atom/movable/overlay/attackby(a, b)
- if (src.master)
- return src.master.attackby(a, b)
- return
-
-/atom/movable/overlay/attack_hand(a, b, c)
- if (src.master)
- return src.master.attack_hand(a, b, c)
- return
-
/atom/movable/proc/touch_map_edge()
if(z in (LEGACY_MAP_DATUM).sealed_levels)
return
diff --git a/code/game/atoms/movable/special/overlay.dm b/code/game/atoms/movable/special/overlay.dm
new file mode 100644
index 00000000000..56889c02b35
--- /dev/null
+++ b/code/game/atoms/movable/special/overlay.dm
@@ -0,0 +1,14 @@
+/atom/movable/overlay
+ atom_flags = ATOM_ABSTRACT
+ vis_flags = VIS_INHERIT_ID
+ anchored = TRUE
+ // todo: nuke this shit from orbit, this is awful.
+ var/atom/master = null
+
+/atom/movable/overlay/attackby(a, b)
+ if (src.master)
+ return src.master.attackby(a, b)
+
+/atom/movable/overlay/attack_hand(a, b, c)
+ if (src.master)
+ return src.master.attack_hand(a, b, c)
diff --git a/code/game/atoms/movable/special/render.dm b/code/game/atoms/movable/special/render.dm
new file mode 100644
index 00000000000..7e5cc7d9a46
--- /dev/null
+++ b/code/game/atoms/movable/special/render.dm
@@ -0,0 +1,5 @@
+/**
+ * holds render effects / otherwise just acts like it isn't there other than its visual impacts
+ */
+/atom/movable/render
+ atom_flags = ATOM_ABSTRACT
diff --git a/code/game/atoms/movable/throwing.dm b/code/game/atoms/movable/throwing.dm
index 1bc820832f4..082fa388900 100644
--- a/code/game/atoms/movable/throwing.dm
+++ b/code/game/atoms/movable/throwing.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
//! Welcome to unoptimized hell. Enjoy your comsigs.
/**
diff --git a/code/game/atoms/vv.dm b/code/game/atoms/vv.dm
index e2a71bc0c16..2373c129b6a 100644
--- a/code/game/atoms/vv.dm
+++ b/code/game/atoms/vv.dm
@@ -9,9 +9,10 @@
* Also, if GLOB.Debug2 is FALSE, it sets the ADMIN_SPAWNED_1 flag on flags_1, which signifies
* the object has been admin edited
*/
-/atom/vv_edit_var(var_name, var_value)
- if(!GLOB.Debug2)
- atom_flags |= ATOM_ADMINSPAWNED
+/atom/vv_edit_var(var_name, var_value, mass_edit, raw_edit)
+ if(raw_edit)
+ return ..()
+
switch(var_name)
if(NAMEOF(src, smoothing_junction))
set_smoothed_icon_state(var_value)
@@ -25,6 +26,22 @@
if(NAMEOF(src, base_pixel_y))
set_base_pixel_y(var_value)
. = TRUE
+ if(NAMEOF(src, integrity))
+ if(!isnum(var_value))
+ return FALSE
+ if(var_value > integrity_max)
+ integrity_max = var_value
+ var_value = max(0, var_value)
+ if(integrity_enabled)
+ set_integrity(var_value)
+ . = TRUE
+ if(NAMEOF(src, integrity_failure))
+ if(!isnum(var_value) || var_value < 0)
+ return FALSE
+ if(NAMEOF(src, integrity_max))
+ if(!isnum(var_value))
+ return FALSE
+ var_value = max(0, var_value)
if(NAMEOF(src, contents))
var/list/O = contents
var/list/N = var_value
@@ -39,10 +56,9 @@
datum_flags |= DF_VAR_EDITED
return
- if(!GLOB.Debug2)
- atom_flags |= ATOM_ADMINSPAWNED
-
. = ..()
+ if(!.)
+ return
switch(var_name)
if(NAMEOF(src, color))
@@ -51,6 +67,16 @@
set_base_layer(var_value)
if(NAMEOF(src, relative_layer))
set_relative_layer(var_value)
+ if(NAMEOF(src, integrity_max))
+ integrity = min(integrity_max, integrity)
+ if(NAMEOF(src, integrity_failure))
+ if(integrity_enabled)
+ var/was_failing = integrity_failure >= integrity
+ var/now_failing = var_value >= integrity
+ if(!was_failing && now_failing)
+ atom_break()
+ else if(was_failing && !now_failing)
+ atom_fix()
/atom/vv_get_var(var_name)
switch(var_name)
diff --git a/code/game/click/click.dm b/code/game/click/click.dm
index fdf533a4fe3..534afebd90e 100644
--- a/code/game/click/click.dm
+++ b/code/game/click/click.dm
@@ -142,18 +142,18 @@
if(Reachability(A, null, I?.reach, I))
//? attempt melee attack chain
if(I)
- I.melee_attack_chain(A, src, clickchain_flags | CLICKCHAIN_HAS_PROXIMITY, unpacked_params)
+ I.melee_interaction_chain(A, src, clickchain_flags | CLICKCHAIN_HAS_PROXIMITY, unpacked_params)
else
- melee_attack_chain(A, clickchain_flags | CLICKCHAIN_HAS_PROXIMITY, unpacked_params)
+ melee_interaction_chain(A, clickchain_flags | CLICKCHAIN_HAS_PROXIMITY, unpacked_params)
// todo: refactor aiming
trigger_aiming(TARGET_CAN_CLICK)
return
else if(ranged_generics_allowed)
//? attempt ranged attack chain
if(I)
- I.ranged_attack_chain(A, src, clickchain_flags, unpacked_params)
+ I.ranged_interaction_chain(A, src, clickchain_flags, unpacked_params)
else
- ranged_attack_chain(A, clickchain_flags, unpacked_params)
+ ranged_interaction_chain(A, clickchain_flags, unpacked_params)
// todo: refactor aiming
trigger_aiming(TARGET_CAN_CLICK)
return
diff --git a/code/game/click/cyborg.dm b/code/game/click/cyborg.dm
index e2268ea8d80..22718c69b83 100644
--- a/code/game/click/cyborg.dm
+++ b/code/game/click/cyborg.dm
@@ -85,18 +85,18 @@
if(Reachability(A, null, I?.reach, I))
//? attempt melee attack chain
if(I)
- I.melee_attack_chain(A, src, CLICKCHAIN_HAS_PROXIMITY, unpacked_params)
+ I.melee_interaction_chain(A, src, CLICKCHAIN_HAS_PROXIMITY, unpacked_params)
else
- melee_attack_chain(A, CLICKCHAIN_HAS_PROXIMITY, unpacked_params)
+ melee_interaction_chain(A, CLICKCHAIN_HAS_PROXIMITY, unpacked_params)
// todo: refactor aiming
trigger_aiming(TARGET_CAN_CLICK)
return
else if(ranged_generics_allowed)
//? attempt ranged attack chain
if(I)
- I.ranged_attack_chain(A, src, NONE, params)
+ I.ranged_interaction_chain(A, src, NONE, params)
else
- ranged_attack_chain(A, NONE, unpacked_params)
+ ranged_interaction_chain(A, NONE, unpacked_params)
// todo: refactor aiming
trigger_aiming(TARGET_CAN_CLICK)
return
diff --git a/code/game/click/items.dm b/code/game/click/items.dm
index eb53a256838..e130a0a47ca 100644
--- a/code/game/click/items.dm
+++ b/code/game/click/items.dm
@@ -5,6 +5,8 @@
//? Click-Chain system - using an item in hand to "attack", whether in melee or ranged.
+// todo: refactor attack object/mob to just melee attack or something
+
/**
* Called when trying to click something that the user can Reachability() to.
*
@@ -14,7 +16,7 @@
* - clickchain_flags - see [code/__DEFINES/procs/clickcode.dm]
* - params - params as list.
*/
-/obj/item/proc/melee_attack_chain(atom/target, mob/user, clickchain_flags, list/params)
+/obj/item/proc/melee_interaction_chain(atom/target, mob/user, clickchain_flags, list/params)
// wow we have a lot of params
// if only this was ss14 so we could have the EntityEventArgs :pleading:
@@ -42,7 +44,7 @@
* - clickchain_flags - see [code/__DEFINES/procs/clickcode.dm]
* - params - params as list.
*/
-/obj/item/proc/ranged_attack_chain(atom/target, mob/user, clickchain_flags, list/params)
+/obj/item/proc/ranged_interaction_chain(atom/target, mob/user, clickchain_flags, list/params)
// todo: signal for afterattack here
return clickchain_flags | afterattack(target, user, clickchain_flags, params)
@@ -54,7 +56,7 @@
// are we on harm intent? if so, lol no
if(user && (user.a_intent == INTENT_HARM))
return NONE
- return target.tool_interaction(src, new /datum/event_args/actor/clickchain(user, params = params), clickchain_flags | CLICKCHAIN_TOOL_ACT)
+ return target.tool_interaction(src, new /datum/event_args/actor/clickchain(user, target = target, params = params), clickchain_flags | CLICKCHAIN_TOOL_ACT)
/**
* called at the start of melee attack chains
@@ -125,6 +127,7 @@
return NONE
if(clickchain_flags & CLICKCHAIN_DO_NOT_ATTACK)
return NONE
+ var/datum/event_args/actor/clickchain/e_args = new(user, target = target, intent = intent, params = params)
// todo: not hardcoding this
if(IS_PRONE(user))
mult *= 0.66
@@ -136,10 +139,13 @@
return
return . | finalize_mob_melee(target, user, . | clickchain_flags, params, mult, target_zone, intent)
// is obj, go to that
- . = attack_object(target, user, clickchain_flags, params, mult)
+ . = attack_object(target, e_args, clickchain_flags, mult)
if(. & CLICKCHAIN_DO_NOT_PROPAGATE)
return
- return . | finalize_object_melee(target, user, . | clickchain_flags, params, mult)
+ return . | finalize_object_melee(target, e_args, . | clickchain_flags, mult)
+
+//? todo: melee_special
+//? todo: combine mob/obj procs
/**
* called when we're used to attack a mob
@@ -157,15 +163,15 @@
*/
/obj/item/proc/attack_mob(mob/target, mob/user, clickchain_flags, list/params, mult = 1, target_zone, intent)
PROTECTED_PROC(TRUE) // route via standard_melee_attack please.
+ //? legacy: for now no attacking nonliving
+ if(!isliving(target))
+ return CLICKCHAIN_ATTACK_MISSED
// too complciated to be put in proc header
if(isnull(target_zone))
target_zone = user.zone_sel?.selecting
if(isnull(intent))
intent = user.a_intent
// end
- //? legacy: for now no attacking nonliving
- if(!isliving(target))
- return
var/mob/living/L = target
// check intent
if(user == L)
@@ -176,6 +182,8 @@
if((item_flags & ITEM_CAREFUL_BLUDGEON) && user.a_intent == INTENT_HELP)
user.action_feedback(SPAN_WARNING("You refrain from hitting [target] with [src], as your intent is set to help."), src)
return NONE
+ //? legacy: decloak
+ user.break_cloak()
// todo: better tracking
user.lastattacked = L
L.lastattacker = user
@@ -183,7 +191,7 @@
// todo: clickcd rework
user.setClickCooldown(user.get_attack_speed(src))
// animation
- user.do_attack_animation(L)
+ user.animate_swing_at_target(L)
// resolve accuracy
var/hit_zone = L.resolve_item_attack(src, user, target_zone)
if(!hit_zone)
@@ -211,23 +219,13 @@
* * intent - action intent that was attempted
*/
/obj/item/proc/melee_mob_miss(mob/target, mob/user, clickchain_flags, list/params, mult = 1, target_zone, intent)
- // too complciated to be put in proc header
- if(isnull(target_zone))
- target_zone = user.zone_sel?.selecting
- if(isnull(intent))
- intent = user.a_intent
- // end
- //? legacy: decloak
- user.break_cloak()
- //? legacy: for now no attacking nonliving
- if(!isliving(target))
- return
+ SHOULD_CALL_PARENT(TRUE)
var/mob/living/L = target
// todo: proper weapon sound ranges/rework
playsound(src, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
// feedback
visible_message("\The [user] misses [L] with \the [src]!")
- return NONE
+ return CLICKCHAIN_ATTACK_MISSED
/**
* called at base of attack_mob after standard melee attack resolves
@@ -245,17 +243,6 @@
*/
/obj/item/proc/melee_mob_hit(mob/target, mob/user, clickchain_flags, list/params, mult = 1, target_zone, intent)
SHOULD_CALL_PARENT(TRUE)
- // too complciated to be put in proc header
- if(isnull(target_zone))
- target_zone = user.zone_sel?.selecting
- if(isnull(intent))
- intent = user.a_intent
- // end
- //? legacy: decloak
- user.break_cloak()
- //? legacy: for now no attacking nonliving
- if(!isliving(target))
- return
// harmless, just tap them and leave
if(!damage_force)
// todo: proper weapon sound ranges/rework
@@ -265,8 +252,8 @@
return NONE
var/mob/living/L = target
// todo: proper weapon sound ranges/rework
- if(hitsound)
- playsound(src, hitsound, 50, 1, -1)
+ if(attack_sound)
+ playsound(src, attack_sound, 50, 1, -1)
// feedback
visible_message(SPAN_DANGER("[L] has been [length(attack_verb)? pick(attack_verb) : attack_verb] with [src] by [user]!"))
@@ -283,6 +270,17 @@
L.hit_with_weapon(src, user, power, target_zone)
//? legacy code end
+ // animate
+ L.animate_hit_by_weapon(user, src)
+
+ // todo: better logging
+ // todo: entity ids?
+ var/newhp
+ if(isliving(target))
+ var/mob/living/casted = target
+ newhp = casted.health
+ log_attack(key_name(src), key_name(target), "attacked with [src] [src.damtype]-[src.damage_force]=[src.damage_tier] newhp ~[newhp || "unknown"]")
+
return NONE
/**
@@ -301,12 +299,6 @@
* @return clickchain flags to append
*/
/obj/item/proc/finalize_mob_melee(mob/target, mob/user, clickchain_flags, list/params, mult = 1, target_zone, intent)
- // too complciated to be put in proc header
- if(isnull(target_zone))
- target_zone = user.zone_sel?.selecting
- if(isnull(intent))
- intent = user.a_intent
- // end
return NONE
/**
@@ -315,21 +307,57 @@
*
* @params
* * target - atom being attacked
- * * user - person attacking
+ * * clickchain - the /datum/event_args/actor/clickchain arguments included
* * clickchain_flags - __DEFINES/procs/clickcode.dm flags
- * * params - list of click params
+ * * mult - damage multiplier
*
* @return clickchain flags to append
*/
-/obj/item/proc/attack_object(atom/target, mob/user, clickchain_flags, list/params)
+/obj/item/proc/attack_object(atom/target, datum/event_args/actor/clickchain/clickchain, clickchain_flags, mult = 1)
PROTECTED_PROC(TRUE) // route via standard_melee_attack please.
- if((item_flags & ITEM_CAREFUL_BLUDGEON) && user.a_intent == INTENT_HELP)
- user.action_feedback(SPAN_WARNING("You refrain from hitting [target] because your intent is set to help."), src)
- return
- // sorry, no atom damage
- // ... yet >:)
- visible_message(SPAN_WARNING("[user] bashes [target] with [src]."))
- return melee_object_hit(target, user, clickchain_flags, params, 1)
+ // todo: move this somewhere else
+ if(!target.integrity_enabled)
+ // no targeting
+ return NONE
+ if(isobj(target))
+ var/obj/casted = target
+ if(!(casted.obj_flags & OBJ_MELEE_TARGETABLE))
+ // no targeting
+ return NONE
+ // check intent
+ if((item_flags & ITEM_CAREFUL_BLUDGEON) && clickchain.intent == INTENT_HELP)
+ clickchain.initiator.action_feedback(SPAN_WARNING("You refrain from hitting [target] because your intent is set to help."), src)
+ return CLICKCHAIN_DO_NOT_PROPAGATE
+ //? legacy: decloak
+ clickchain.performer.break_cloak()
+ // click cooldown
+ // todo: clickcd rework
+ clickchain.performer.setClickCooldown(clickchain.performer.get_attack_speed(src))
+ // animation
+ clickchain.performer.animate_swing_at_target(target)
+ // perform the hit
+ . = melee_object_hit(target, clickchain, clickchain_flags, mult)
+
+/**
+ * called at base of attack_object after standard melee attack misses
+ *
+ * @return clickchain flags to append
+ *
+ * @params
+ * * target - atom being attacked
+ * * clickchain - the /datum/event_args/actor/clickchain arguments included
+ * * clickchain_flags - __DEFINES/procs/clickcode.dm flags
+ * * mult - damage multiplier
+ */
+/obj/item/proc/melee_object_miss(atom/target, datum/event_args/actor/clickchain/clickchain, clickchain_flags, mult = 1)
+ SHOULD_CALL_PARENT(TRUE)
+ playsound(clickchain.performer, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ clickchain.visible_feedback(
+ target = target,
+ range = MESSAGE_RANGE_COMBAT_LOUD,
+ visible = SPAN_WARNING("[clickchain.performer] swings for [target], but misses!"),
+ )
+ return CLICKCHAIN_ATTACK_MISSED
/**
* called at base of attack_object after standard melee attack resolves
@@ -338,13 +366,47 @@
*
* @params
* * target - atom being attacked
- * * user - person attacking
+ * * clickchain - the /datum/event_args/actor/clickchain arguments included
* * clickchain_flags - __DEFINES/procs/clickcode.dm flags
- * * params - list of click params
* * mult - damage multiplier
*/
-/obj/item/proc/melee_object_hit(atom/target, mob/user, clickchain_flags, list/params, mult = 1)
+/obj/item/proc/melee_object_hit(atom/target, datum/event_args/actor/clickchain/clickchain, clickchain_flags, mult = 1)
SHOULD_CALL_PARENT(TRUE)
+
+ // harmless, just tap them and leave
+ if(!damage_force)
+ // todo: proper weapon sound ranges/rework
+ playsound(clickchain.performer, 'sound/weapons/tap.ogg', 50, 1, -1)
+ // feedback
+ clickchain.visible_feedback(
+ target = target,
+ range = MESSAGE_RANGE_COMBAT_LOUD,
+ visible = SPAN_WARNING("[clickchain.performer] harmlessly taps [target] with [src]."),
+ visible_them = SPAN_WARNING("[clickchain.performer] harmlessly taps you with [src]."),
+ visible_self = SPAN_WARNING("You harmlessly tap [target] with [src].")
+ )
+ return NONE
+ // sound
+ var/resolved_sound = target.hitsound_melee(src)
+ if(!isnull(resolved_sound))
+ playsound(target, resolved_sound, 50, TRUE)
+ // feedback
+ // todo: grammar
+ clickchain.visible_feedback(
+ target = target,
+ range = MESSAGE_RANGE_COMBAT_LOUD,
+ visible = SPAN_DANGER("[target] has been [islist(attack_verb)? pick(attack_verb) : attack_verb] with [src] by [clickchain.performer]!")
+ )
+ // damage
+ target.melee_act(clickchain.performer, src, mult = mult)
+ // animate
+ target.animate_hit_by_weapon(clickchain.performer, src)
+
+ // todo: better logging
+ // todo: entity ids?
+ var/newhp = target.integrity
+ log_attack(key_name(src), "[target] ([ref(target)])", "attacked with [src] [src.damtype]-[src.damage_force]=[src.damage_tier] newhp ~[newhp || "unknown"]")
+
return NONE
/**
@@ -353,12 +415,11 @@
*
* @params
* * target - atom being attacked
- * * user - person attacking
+ * * clickchain - the /datum/event_args/actor/clickchain arguments included
* * clickchain_flags - __DEFINES/procs/clickcode.dm flags
- * * params - list of click params
* * mult - damage multiplier
*
* @return clickchain flags to append
*/
-/obj/item/proc/finalize_object_melee(atom/target, mob/user, clickchain_flags, list/params, mult = 1)
+/obj/item/proc/finalize_object_melee(atom/target, datum/event_args/actor/clickchain/clickchain, clickchain_flags, mult = 1)
return NONE
diff --git a/code/game/click/mobs.dm b/code/game/click/mobs.dm
index 422b14593c4..7ac0ad4c737 100644
--- a/code/game/click/mobs.dm
+++ b/code/game/click/mobs.dm
@@ -6,7 +6,7 @@
* - clickchain_flags - see [code/__DEFINES/procs/clickcode.dm]
* - params - parameters of click, as list
*/
-/mob/proc/melee_attack_chain(atom/target, clickchain_flags, list/params)
+/mob/proc/melee_interaction_chain(atom/target, clickchain_flags, list/params)
// todo: refactor cooldown handling
if(ismob(target))
setClickCooldown(get_attack_speed())
@@ -20,7 +20,105 @@
* - clickchain_flags - see [code/__DEFINES/procs/clickcode.dm]
* - params - parameters of click, as list
*/
-/mob/proc/ranged_attack_chain(atom/target, clickchain_flags, list/params)
- // todo: NO. MORE. LIST. PARAMS. WHY. ARE. WE. UNPACKING. THE. LIST. MULTIPLE. TIMES?
+/mob/proc/ranged_interaction_chain(atom/target, clickchain_flags, list/params)
+ // todo: NO. MORE. TEXT. PARAMS. WHY. ARE. WE. UNPACKING. THE. LIST. MULTIPLE. TIMES?
var/stupid_fucking_shim = list2params(params)
RangedAttack(target, stupid_fucking_shim)
+
+/**
+ * called to try to hit something in melee
+ */
+/mob/proc/melee_attack_chain(atom/target, datum/event_args/actor/clickchain/clickchain, datum/unarmed_attack/style = unarmed_attack_style(), clickchain_flags, target_zone, mult = 1)
+ if(isnull(style))
+ // we can't autoattack
+ return NONE
+ if(isnull(clickchain))
+ clickchain = new(src, target = target, intent = a_intent)
+ // too complciated to be put in proc header
+ if(isnull(target_zone))
+ target_zone = clickchain.performer.zone_sel?.selecting
+ // end
+ if(clickchain_flags & CLICKCHAIN_DO_NOT_ATTACK)
+ return NONE
+ // todo: not hardcoding this
+ if(IS_PRONE(clickchain.performer))
+ mult *= 0.66
+ // todo: signals
+ . = melee_attack(target, clickchain, style, clickchain_flags, target_zone, mult)
+ if(. & CLICKCHAIN_DO_NOT_PROPAGATE)
+ return
+ return . | melee_attack_finalize(target, clickchain, style, clickchain_flags, target_zone, mult)
+
+/**
+ * default current unarmed attack style
+ *
+ * todo: kinda shitycodey but w/e
+ */
+/mob/proc/unarmed_attack_style()
+ // none by default
+ return null
+
+// todo: melee_special for overrides (?)
+
+/mob/proc/melee_attack(atom/target, datum/event_args/actor/clickchain/clickchain, datum/unarmed_attack/style, clickchain_flags, target_zone, mult)
+ SHOULD_CALL_PARENT(TRUE)
+ // todo: move this somewhere else
+ if(!target.integrity_enabled)
+ // no targeting
+ return NONE
+ if(isobj(target))
+ var/obj/casted = target
+ if(!(casted.obj_flags & OBJ_MELEE_TARGETABLE))
+ // no targeting
+ return NONE
+ //? legacy: for now no attacking nonliving
+ if(ismob(target) && !isliving(target))
+ return NONE
+ //? legacy: decloak
+ clickchain.performer.break_cloak()
+
+ // todo: clickcd rework
+ clickchain.performer.setClickCooldown(clickchain.performer.get_attack_speed())
+ // todo: animation might need to depend on if it hits
+ animate_swing_at_target(target)
+
+ . = melee_attack_hit(target, clickchain, style, clickchain_flags, target_zone, mult)
+
+ // todo: better logging
+ // todo: entity ids?
+ var/newhp
+ if(isliving(target))
+ var/mob/living/casted = target
+ newhp = casted.health
+ else
+ newhp = target.integrity
+
+ . |= melee_attack_finalize(target, clickchain, style, clickchain_flags, target_zone, mult)
+
+ log_attack(key_name(src), ismob(target)? key_name(target) : "[target] ([ref(target)])", "attacked with [style.attack_name] newhp ~[newhp || "unknown"]")
+
+/mob/proc/melee_attack_hit(atom/target, datum/event_args/actor/clickchain/clickchain, datum/unarmed_attack/style, clickchain_flags, target_zone, mult)
+ . = target.unarmed_act(src, style, target_zone, mult)
+ if(. & CLICKCHAIN_ATTACK_MISSED)
+ return . | melee_attack_miss(target, clickchain, style, clickchain_flags, target_zone, mult)
+ // todo: the rest of this proc not qdel-safe
+ playsound(src, target.hitsound_unarmed(src, style), 50, TRUE, -1)
+ // todo: better feedback
+ clickchain.visible_feedback(
+ target = target,
+ range = MESSAGE_RANGE_COMBAT_LOUD,
+ visible = SPAN_DANGER("[target] has been [islist(style.verb_past_participle)? pick(style.verb_past_participle) : style.verb_past_participle] by [clickchain.performer]!")
+ )
+ target.animate_hit_by_attack(style.animation_type)
+
+/mob/proc/melee_attack_miss(atom/target, datum/event_args/actor/clickchain/clickchain, datum/unarmed_attack/style, clickchain_flags, target_zone, mult)
+ playsound(src, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ clickchain.visible_feedback(
+ target = target,
+ range = MESSAGE_RANGE_COMBAT_LOUD,
+ visible = SPAN_WARNING("[src] swings for [target], but misses!"),
+ )
+ return NONE
+
+/mob/proc/melee_attack_finalize(atom/target, datum/event_args/actor/clickchain/clickchain, datum/unarmed_attack/style, clickchain_flags, target_zone, mult)
+ return NONE
diff --git a/code/game/click/other_mobs.dm b/code/game/click/other_mobs.dm
index 0506362b231..3e68c198d3e 100644
--- a/code/game/click/other_mobs.dm
+++ b/code/game/click/other_mobs.dm
@@ -4,9 +4,6 @@
/atom/proc/attack_alien(mob/user)
-/atom/proc/take_damage(var/damage)
- return 0
-
/*
Humans:
Adds an exception for gloves, to allow special glove types like the ninja ones.
@@ -33,7 +30,10 @@
/// Return TRUE to cancel other attack hand effects that respect it.
// todo: /datum/event_args/actor/clickchain
/atom/proc/attack_hand(mob/user, list/params)
- if(on_attack_hand(new /datum/event_args/actor/clickchain(user, intent = user.a_intent, params = params)))
+ var/datum/event_args/actor/clickchain/e_args = new(user, target = src, intent = user.a_intent, params = params)
+ if(user.a_intent == INTENT_HARM)
+ return user.melee_attack_chain(src, e_args)
+ if(on_attack_hand(e_args))
return TRUE
. = _try_interact(user)
diff --git a/code/game/click/reachability.dm b/code/game/click/reachability.dm
index 9623a1cd899..2604d39f220 100644
--- a/code/game/click/reachability.dm
+++ b/code/game/click/reachability.dm
@@ -236,7 +236,7 @@
//! Clicking out of - for ranged attack chains
/**
- * called to see if we're allowed to proc ranged_attack_chain from in here at a target
+ * called to see if we're allowed to proc ranged_interaction_chain from in here at a target
*
* this proc needs refactored at some point to allow for complexity if necessary
* but for now it works so don't fuck with it
diff --git a/code/game/gamemodes/cult/construct_spells.dm b/code/game/gamemodes/cult/construct_spells.dm
index aace3300040..5c0c2ec78ae 100644
--- a/code/game/gamemodes/cult/construct_spells.dm
+++ b/code/game/gamemodes/cult/construct_spells.dm
@@ -665,7 +665,7 @@
var/turf/simulated/wall/W = hit_atom
user.visible_message("\The [user] rears its fist, preparing to hit \the [W]!")
var/windup = cooldown
- if(W.reinf_material)
+ if(W.material_reinf)
windup = cooldown * 2
if(do_after(user, windup))
W.visible_message("\The [user] [attack_message] \the [W], obliterating it!")
diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm
index ef9ea2a2578..0e293510bf6 100644
--- a/code/game/gamemodes/cult/cult_items.dm
+++ b/code/game/gamemodes/cult/cult_items.dm
@@ -6,7 +6,7 @@
w_class = ITEMSIZE_LARGE
damage_force = 30
throw_force = 10
- hitsound = 'sound/weapons/bladeslice.ogg'
+ attack_sound = 'sound/weapons/bladeslice.ogg'
drop_sound = 'sound/items/drop/sword.ogg'
pickup_sound = 'sound/items/pickup/sword.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index 3b81bae9faf..21fc3fd4d9c 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -46,8 +46,9 @@
/obj/structure/cult/pylon/attackby(obj/item/W as obj, mob/user as mob)
attackpylon(user, W.damage_force)
-/obj/structure/cult/pylon/take_damage(var/damage)
+/obj/structure/cult/pylon/inflict_atom_damage(damage, tier, flag, mode, attack_type, datum/weapon, gradual)
pylonhit(damage)
+ return damage
/obj/structure/cult/pylon/bullet_act(var/obj/projectile/Proj)
pylonhit(Proj.get_structure_damage())
@@ -127,9 +128,9 @@
desc = "You're pretty sure that abyss is staring back."
icon = 'icons/obj/cult.dmi'
icon_state = "hole"
- density = 1
- unacidable = 1
- anchored = 1.0
+ density = TRUE
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE | INTEGRITY_ACIDPROOF | INTEGRITY_FIREPROOF | INTEGRITY_LAVAPROOF
+ anchored = TRUE
var/spawnable = null
/obj/effect/gateway/active
diff --git a/code/game/gamemodes/cult/cultify/obj.dm b/code/game/gamemodes/cult/cultify/obj.dm
index 2144e327bd8..c0c8de68e1d 100644
--- a/code/game/gamemodes/cult/cultify/obj.dm
+++ b/code/game/gamemodes/cult/cultify/obj.dm
@@ -131,9 +131,8 @@
// Make it a wood-reinforced wooden table.
// There are cult materials available, but it'd make the table non-deconstructable with how holotables work.
// Could possibly use a new material var for holographic-ness?
- material = get_material_by_name("wood")
- reinforced = get_material_by_name("wood")
+ var/datum/material/resolved = SSmaterials.resolve_material(/datum/material/wood_plank)
+ set_material_parts(list("base" = resolved, "reinf" = resolved))
update_desc()
update_connections(1)
update_icon()
- update_material()
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index 7bbc8e5f4dc..204aa61a5f6 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -26,7 +26,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
icon = 'icons/obj/rune.dmi'
icon_state = "1"
var/visibility = 0
- unacidable = 1
+ integrity_flags = INTEGRITY_ACIDPROOF | INTEGRITY_FIREPROOF
layer = TURF_LAYER
diff --git a/code/game/gamemodes/events/black_hole.dm b/code/game/gamemodes/events/black_hole.dm
index 4af0d958b03..1bc471d0be1 100644
--- a/code/game/gamemodes/events/black_hole.dm
+++ b/code/game/gamemodes/events/black_hole.dm
@@ -3,10 +3,10 @@
icon = 'icons/obj/objects.dmi'
desc = "FUCK FUCK FUCK AAAHHH"
icon_state = "bhole3"
- opacity = 1
- unacidable = 1
- density = 0
- anchored = 1
+ opacity = TRUE
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE | INTEGRITY_ACIDPROOF | INTEGRITY_FIREPROOF | INTEGRITY_LAVAPROOF
+ density = FALSE
+ anchored = TRUE
var/process_step = 0
/obj/effect/bhole/Initialize(mapload)
diff --git a/code/game/gamemodes/malfunction/malf_hardware.dm b/code/game/gamemodes/malfunction/malf_hardware.dm
index 8036f45240d..93ce4c2ac7b 100644
--- a/code/game/gamemodes/malfunction/malf_hardware.dm
+++ b/code/game/gamemodes/malfunction/malf_hardware.dm
@@ -65,7 +65,8 @@
/datum/malf_hardware/strong_turrets/install()
..()
for(var/obj/machinery/porta_turret/T in GLOB.machines)
- T.maxhealth = round(initial(T.maxhealth) * 1.4)
+ T.integrity_max = T.integrity_max * 2
+ T.integrity += T.integrity_max / 2
T.shot_delay = round(initial(T.shot_delay) / 2)
T.auto_repair = 1
T.active_power_usage = round(initial(T.active_power_usage) * 5)
diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm
index 7af0fbd3a42..b33b71d1528 100644
--- a/code/game/gamemodes/meteor/meteors.dm
+++ b/code/game/gamemodes/meteor/meteors.dm
@@ -162,7 +162,7 @@
if(T)
if(istype(T, /turf/simulated/wall))
var/turf/simulated/wall/W = T
- W.take_damage(wall_power) // Stronger walls can halt asteroids.
+ W.inflict_atom_damage(wall_power, flag = ARMOR_BOMB) // Stronger walls can halt asteroids.
/obj/effect/meteor/proc/get_shield_damage()
return max(((max(hits, 2)) * (heavy + 1) * rand(6, 12)) / hitpwr , 0)
diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm
index 3c3ce515eb6..c9542d67176 100644
--- a/code/game/gamemodes/nuclear/pinpointer.dm
+++ b/code/game/gamemodes/nuclear/pinpointer.dm
@@ -7,7 +7,7 @@
item_state = "electronic"
throw_speed = 4
throw_range = 20
- materials = list(MAT_STEEL = 500)
+ materials_base = list(MAT_STEEL = 500)
preserve_item = 1
var/obj/item/disk/nuclear/the_disk = null
var/active = 0
diff --git a/code/game/gamemodes/technomancer/assistance/golem.dm b/code/game/gamemodes/technomancer/assistance/golem.dm
index df7212c2549..e9a6e932ce6 100644
--- a/code/game/gamemodes/technomancer/assistance/golem.dm
+++ b/code/game/gamemodes/technomancer/assistance/golem.dm
@@ -27,8 +27,8 @@
unsuitable_atoms_damage = 0
speed = 0
- melee_damage_lower = 30 // It has a built in esword.
- melee_damage_upper = 30
+ legacy_melee_damage_lower = 30 // It has a built in esword.
+ legacy_melee_damage_upper = 30
attack_sound = 'sound/weapons/blade1.ogg'
attacktext = list("slashed")
friendly = "hugs"
diff --git a/code/game/gamemodes/technomancer/core_obj.dm b/code/game/gamemodes/technomancer/core_obj.dm
index 96901241955..313807074cb 100644
--- a/code/game/gamemodes/technomancer/core_obj.dm
+++ b/code/game/gamemodes/technomancer/core_obj.dm
@@ -7,7 +7,7 @@
item_state = "technomancer_core"
w_class = ITEMSIZE_HUGE
slot_flags = SLOT_BACK
- unacidable = 1
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE | INTEGRITY_ACIDPROOF | INTEGRITY_FIREPROOF | INTEGRITY_LAVAPROOF
origin_tech = list(
TECH_MATERIAL = 8, TECH_ENGINEERING = 8, TECH_POWER = 8, TECH_BLUESPACE = 10,
TECH_COMBAT = 7, TECH_MAGNET = 9, TECH_DATA = 5
diff --git a/code/game/gamemodes/technomancer/spells/flame_tongue.dm b/code/game/gamemodes/technomancer/spells/flame_tongue.dm
index 4b7ea386665..98ad44291c9 100644
--- a/code/game/gamemodes/technomancer/spells/flame_tongue.dm
+++ b/code/game/gamemodes/technomancer/spells/flame_tongue.dm
@@ -54,7 +54,7 @@
var/resolved = hit_atom.attackby(welder, user)
if(!resolved && welder && hit_atom)
if(pay_energy(500))
- welder.melee_attack_chain(hit_atom, user, def_zone)
+ welder.melee_interaction_chain(hit_atom, user, def_zone)
adjust_instability(4)
if(welder && user && (welder.loc == user))
welder.loc = src
diff --git a/code/game/gamemodes/technomancer/spells/reflect.dm b/code/game/gamemodes/technomancer/spells/reflect.dm
index 9b7661e35c2..b1bd2526260 100644
--- a/code/game/gamemodes/technomancer/spells/reflect.dm
+++ b/code/game/gamemodes/technomancer/spells/reflect.dm
@@ -75,7 +75,7 @@
else if(istype(damage_source, /obj/item))
var/obj/item/W = damage_source
if(attacker)
- W.melee_attack_chain(attacker)
+ W.melee_interaction_chain(attacker)
to_chat(attacker, "Your [damage_source.name] goes through \the [src] in one location, comes out \
on the same side, and hits you!")
diff --git a/code/game/gamemodes/technomancer/spells/summon/summon_creature.dm b/code/game/gamemodes/technomancer/spells/summon/summon_creature.dm
index 22384bb8fc0..228ce0daa17 100644
--- a/code/game/gamemodes/technomancer/spells/summon/summon_creature.dm
+++ b/code/game/gamemodes/technomancer/spells/summon/summon_creature.dm
@@ -46,8 +46,8 @@
// Makes their new pal big and strong, if they have spell power.
summoned.maxHealth = calculate_spell_power(summoned.maxHealth)
summoned.health = calculate_spell_power(summoned.health)
- summoned.melee_damage_lower = calculate_spell_power(summoned.melee_damage_lower)
- summoned.melee_damage_upper = calculate_spell_power(summoned.melee_damage_upper)
+ summoned.legacy_melee_damage_lower = calculate_spell_power(summoned.legacy_melee_damage_lower)
+ summoned.legacy_melee_damage_upper = calculate_spell_power(summoned.legacy_melee_damage_upper)
// This makes the summon slower, so the crew has a chance to flee from massive monsters.
summoned.movement_cooldown = calculate_spell_power(round(summoned.movement_cooldown))
diff --git a/code/game/gamemodes/technomancer/spells/targeting_matrix.dm b/code/game/gamemodes/technomancer/spells/targeting_matrix.dm
index 3b4d73a4e15..ea600152198 100644
--- a/code/game/gamemodes/technomancer/spells/targeting_matrix.dm
+++ b/code/game/gamemodes/technomancer/spells/targeting_matrix.dm
@@ -26,7 +26,7 @@
if(I && pay_energy(200))
var/prox = user.Adjacent(chosen_target)
if(prox) // Needed or else they can attack with melee from afar.
- I.melee_attack_chain(chosen_target,owner)
+ I.melee_interaction_chain(chosen_target,owner)
I.afterattack(chosen_target,owner, prox)
adjust_instability(2)
diff --git a/code/game/gamemodes/technomancer/spells/warp_strike.dm b/code/game/gamemodes/technomancer/spells/warp_strike.dm
index 0022bdd05a4..804f1378b5f 100644
--- a/code/game/gamemodes/technomancer/spells/warp_strike.dm
+++ b/code/game/gamemodes/technomancer/spells/warp_strike.dm
@@ -69,10 +69,10 @@
if(istype(I, /obj/item))
var/obj/item/W = I
- W.melee_attack_chain(chosen_target, user)
+ W.melee_interaction_chain(chosen_target, user)
W.afterattack(chosen_target, user)
else
- I.melee_attack_chain(chosen_target, user)
+ I.melee_interaction_chain(chosen_target, user)
I.afterattack(chosen_target, user)
else
chosen_target.attack_hand(user)
diff --git a/code/game/machinery/_frame.dm b/code/game/machinery/_frame.dm
index 6ecdd1740bd..0c32c989ef4 100644
--- a/code/game/machinery/_frame.dm
+++ b/code/game/machinery/_frame.dm
@@ -543,7 +543,7 @@
state = FRAME_FASTENED
new /obj/item/stack/cable_coil(loc, 5)
- else if(istype(P, /obj/item/stack/material) && P.get_material_name() == "glass")
+ else if(P.is_material_stack_of(/datum/material/glass))
if(state == FRAME_WIRED)
if(frame_type.frame_class == FRAME_CLASS_COMPUTER)
var/obj/item/stack/G = P
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index ee82898fbde..f29cacf09dd 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -302,6 +302,8 @@
// todo: refactor
/obj/machinery/attack_hand(mob/user, list/params)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
if(IsAdminGhost(user))
return FALSE
if(!(istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon)))
@@ -497,7 +499,6 @@
if(do_after(user, 20 * S.tool_speed))
if(machine_stat & BROKEN)
to_chat(user, "The broken glass falls out.")
- new /obj/item/material/shard(src.loc)
else
to_chat(user, "You disconnect the monitor.")
. = dismantle()
@@ -521,14 +522,15 @@
new/obj/item/stack/cable_coil(get_turf(src), 5)
. = dismantle()
-/obj/machinery/proc/dismantle()
- playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1)
- drop_products(ATOM_DECONSTRUCT_DISASSEMBLED)
+/obj/machinery/deconstructed(method)
+ . = ..()
+ // todo: get rid of this, legacy.
on_deconstruction()
- // If it doesn't have a circuit board, don't create a frame, instead just break.
- if(!circuit)
- qdel(src)
- return 0
+
+/obj/machinery/drop_products(method, atom/where)
+ . = ..()
+ if(isnull(circuit))
+ return
var/obj/structure/frame/A = new /obj/structure/frame(src.loc)
var/obj/item/circuitboard/M = circuit
A.circuit = M
@@ -569,8 +571,10 @@
A.update_appearance()
M.loc = null
M.after_deconstruct(src)
- qdel(src)
- return 1
+
+// todo: kill this shit, this is legacy
+/obj/machinery/proc/dismantle()
+ deconstruct(ATOM_DECONSTRUCT_DISASSEMBLED)
//called on machinery construction (i.e from frame to machinery) but not on initialization
// /obj/machinery/proc/on_construction() //! Not used yet.
@@ -607,3 +611,13 @@
. = . % 9
dropped_atom.pixel_x = -8 + ((.%3)*8)
dropped_atom.pixel_y = -8 + (round( . / 3)*8)
+
+/obj/machinery/atom_break()
+ . = ..()
+ // todo: rework
+ machine_stat |= BROKEN
+
+/obj/machinery/atom_fix()
+ . = ..()
+ // todo: rework
+ machine_stat &= ~BROKEN
diff --git a/code/game/machinery/atm_ret_field.dm b/code/game/machinery/atm_ret_field.dm
index bdeb68ae661..296cb80b75b 100644
--- a/code/game/machinery/atm_ret_field.dm
+++ b/code/game/machinery/atm_ret_field.dm
@@ -209,6 +209,9 @@
/obj/structure/atmospheric_retention_field/Initialize(mapload)
. = ..()
update_nearby_tiles() //Force ZAS update
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/structure/atmospheric_retention_field/LateInitialize()
update_connections(1)
update_icon()
diff --git a/code/game/machinery/bomb_tester.dm b/code/game/machinery/bomb_tester.dm
index 4d042530955..ac36e0354b0 100644
--- a/code/game/machinery/bomb_tester.dm
+++ b/code/game/machinery/bomb_tester.dm
@@ -45,15 +45,13 @@
test_canister = null
..()
-/obj/machinery/bomb_tester/dismantle()
- if(tank1)
- tank1.forceMove(get_turf(src))
- tank1 = null
- if(tank2)
- tank2.forceMove(get_turf(src))
- tank2 = null
- simulation_finish(1)
- return ..()
+/obj/machinery/bomb_tester/drop_products(method, atom/where)
+ . = ..()
+ tank1?.forceMove(where)
+ tank1 = null
+ tank2?.forceMove(where)
+ tank2 = null
+ simulation_finish(TRUE)
/obj/machinery/bomb_tester/process(delta_time)
..()
diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm
index 9811c1b7318..6ac42003acc 100644
--- a/code/game/machinery/buttons.dm
+++ b/code/game/machinery/buttons.dm
@@ -9,6 +9,8 @@
use_power = USE_POWER_IDLE
idle_power_usage = 2
active_power_usage = 4
+ // todo: remove when this is constructible (and all its subtypes are)
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE
/obj/machinery/button/attack_ai(mob/user)
return attack_hand(user)
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index e87757a02b2..8e4958d14a5 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -6,6 +6,7 @@
use_power = USE_POWER_ACTIVE
idle_power_usage = 5
active_power_usage = 10
+ depth_projected = FALSE
plane = MOB_PLANE
layer = BELOW_MOB_LAYER
@@ -14,7 +15,6 @@
var/c_tag_order = 999
var/status = 1
anchored = 1.0
- var/invuln = 0
var/bugged = 0
var/obj/item/camera_assembly/assembly = null
@@ -99,32 +99,12 @@
update_coverage()
START_PROCESSING(SSobj, src)
-/obj/machinery/camera/bullet_act(var/obj/projectile/P)
- take_damage(P.get_structure_damage())
-
-/obj/machinery/camera/legacy_ex_act(severity)
- if(src.invuln)
- return
-
- //camera dies if an explosion touches it!
- if(severity <= 2 || prob(50))
- destroy()
-
- ..() //and give it the regular chance of being deleted outright
/obj/machinery/camera/blob_act()
- if((machine_stat & BROKEN) || invuln)
+ if(machine_stat & BROKEN)
return
destroy()
-/obj/machinery/camera/throw_impacted(atom/movable/AM, datum/thrownthing/TT)
- . = ..()
- if (istype(AM, /obj))
- var/obj/O = AM
- if (O.throw_force >= src.toughness)
- visible_message("[src] was hit by [O].")
- take_damage(O.throw_force)
-
/obj/machinery/camera/proc/setViewRange(var/num = 7)
src.view_range = num
GLOB.cameranet.updateVisibility(src, 0)
@@ -211,19 +191,8 @@
else to_chat(O, "[U] holds \a [itemname] up to one of your cameras ...")
O << browse("[itemname][info]", "window=[itemname]")
- else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras
- user.setClickCooldown(user.get_attack_speed(W))
- if (W.damage_force >= src.toughness)
- user.do_attack_animation(src)
- visible_message("[src] has been [W.get_attack_verb(src, user)] with [W] by [user]!")
- if (istype(W, /obj/item)) //is it even possible to get into attackby() with non-items?
- var/obj/item/I = W
- if (I.hitsound)
- playsound(loc, I.hitsound, 50, 1, -1)
- take_damage(W.damage_force)
-
else
- ..()
+ return ..()
/obj/machinery/camera/proc/deactivate(user as mob, var/choice = 1)
// The only way for AI to reactivate cameras are malf abilities, this gives them different messages.
@@ -251,7 +220,7 @@
icon_state = initial(icon_state)
add_hiddenprint(user)
-/obj/machinery/camera/take_damage(force, message)
+/obj/machinery/camera/proc/take_damage_legacy(force, message)
//prob(25) gives an average of 3-4 hits
if (force >= toughness && (force > toughness*4 || prob(25)))
destroy()
diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm
index 55550d1cf58..ba756f64f27 100644
--- a/code/game/machinery/camera/camera_assembly.dm
+++ b/code/game/machinery/camera/camera_assembly.dm
@@ -6,7 +6,7 @@
w_class = ITEMSIZE_SMALL
anchored = 0
- materials = list(MAT_STEEL = 700, MAT_GLASS = 300)
+ materials_base = list(MAT_STEEL = 700, MAT_GLASS = 300)
// Motion, EMP-Proof, X-Ray
var/list/obj/item/possible_upgrades = list(/obj/item/assembly/prox_sensor, /obj/item/stack/material/osmium, /obj/item/stock_parts/scanning_module)
diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm
index 62ed90bc749..c4a8c41842a 100644
--- a/code/game/machinery/camera/presets.dm
+++ b/code/game/machinery/camera/presets.dm
@@ -100,7 +100,7 @@ var/global/list/engineering_networks = list(
/obj/machinery/camera/network/thunder
network = list(NETWORK_THUNDER)
- invuln = 1
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE
// EMP
diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm
index 8002321d58f..b5d46e6f897 100644
--- a/code/game/machinery/cell_charger.dm
+++ b/code/game/machinery/cell_charger.dm
@@ -143,7 +143,7 @@
)
item_state = "syringe_kit"
w_class = ITEMSIZE_NORMAL
- materials = list(MAT_STEEL = 4000, MAT_GLASS = 1000)
+ materials_base = list(MAT_STEEL = 4000, MAT_GLASS = 1000)
/obj/item/cell_charger_kit/attack_self(mob/user)
. = ..()
diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm
index 334a6f5eca5..2d5e94e91bb 100644
--- a/code/game/machinery/computer/ai_core.dm
+++ b/code/game/machinery/computer/ai_core.dm
@@ -88,8 +88,8 @@
var/obj/item/stack/cable_coil/A = new /obj/item/stack/cable_coil( loc )
A.amount = 5
- if(istype(P, /obj/item/stack/material) && P.get_material_name() == "rglass")
- var/obj/item/stack/RG = P
+ if(P.is_material_stack_of(/datum/material/glass/reinforced))
+ var/obj/item/stack/material/RG = P
if (RG.get_amount() < 2)
to_chat(user, "You need two sheets of glass to put in the glass panel.")
return
diff --git a/code/game/machinery/computer/arcade/battler.dm b/code/game/machinery/computer/arcade/battler.dm
index 898b7404cb4..c090e7e2dff 100644
--- a/code/game/machinery/computer/arcade/battler.dm
+++ b/code/game/machinery/computer/arcade/battler.dm
@@ -192,9 +192,9 @@
else if (href_list["newgame"]) //Reset everything
temp = "
New Round"
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
Reset()
- obj_flags &= ~EMAGGED
+ obj_flags &= ~OBJ_EMAGGED
enemy_setup(gamerSkill)
screen_setup(usr)
@@ -240,7 +240,7 @@
attack_amount -= 5
//if emagged, cuban pete will set up a bomb acting up as a timer. when it reaches 0 the player fucking dies
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
switch(bomb_cooldown--)
if(18)
list_temp += "
[enemy_name] takes two valve tank and links them together, what's he planning?"
@@ -403,18 +403,18 @@
temp = "
[enemy_name] has fallen! Rejoice!"
playsound(loc, 'sound/arcade/win.ogg', 50, TRUE)
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
new /obj/effect/spawner/newbomb/timer/syndicate(loc)
new /obj/item/clothing/head/collectable/petehat(loc)
message_admins("[ADMIN_LOOKUPFLW(usr)] has outbombed Cuban Pete and been awarded a bomb.")
log_game("[key_name(usr)] has outbombed Cuban Pete and been awarded a bomb.")
Reset()
- obj_flags &= ~EMAGGED
+ obj_flags &= ~OBJ_EMAGGED
xp_gained += 100
else
prizevend(user)
xp_gained += 50
- //SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("win", (obj_flags & EMAGGED ? "emagged":"normal")))
+ //SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("win", (obj_flags & OBJ_EMAGGED ? "emagged":"normal")))
else if(player_hp <= 0)
if(timer_id)
@@ -424,11 +424,11 @@
temp = "
You have been crushed! GAME OVER"
playsound(loc, 'sound/arcade/lose.ogg', 50, TRUE)
xp_gained += 10//pity points
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
var/mob/living/living_user = user
if (istype(living_user))
living_user.gib()
- //SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("loss", "hp", (obj_flags & EMAGGED ? "emagged":"normal")))
+ //SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("loss", "hp", (obj_flags & OBJ_EMAGGED ? "emagged":"normal")))
// if(gameover)
// user?.mind?.adjust_experience(/datum/skill/gaming, xp_gained+1)//always gain at least 1 point of XP
@@ -465,7 +465,7 @@
return .
/obj/machinery/computer/arcade/battle/emag_act(mob/user)
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
return
to_chat(user, SPAN_WARNING("A mesmerizing Rhumba beat starts playing from the arcade machine's speakers!"))
@@ -482,7 +482,7 @@
screen_setup(user)
gameover = FALSE
- obj_flags |= EMAGGED
+ obj_flags |= OBJ_EMAGGED
enemy_name = "Cuban Pete"
name = "Outbomb Cuban Pete"
diff --git a/code/game/machinery/computer/arcade/orion.dm b/code/game/machinery/computer/arcade/orion.dm
index 49e8604be07..49fb5b74805 100644
--- a/code/game/machinery/computer/arcade/orion.dm
+++ b/code/game/machinery/computer/arcade/orion.dm
@@ -181,7 +181,7 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events())
/obj/machinery/computer/arcade/orion_trail/ui_static_data(mob/user)
var/list/static_data = list()
static_data["gamename"] = name
- static_data["emagged"] = obj_flags & EMAGGED
+ static_data["emagged"] = obj_flags & OBJ_EMAGGED
static_data["settlers"] = settlers
static_data["settlermoods"] = settlermoods
return static_data
@@ -334,7 +334,7 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events())
if(!event)
CRASH("Woah, hey! we could not find the specified event \"[path]\"! Add it to the events list, numb nuts!")
event.on_select(src, gamer_skill, gamer_skill_level, gamer_skill_rands)
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
event.emag_effect(src, gamer)
/obj/machinery/computer/arcade/orion_trail/proc/set_game_over(user, given_reason)
@@ -349,20 +349,20 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events())
else
if(food <= 0)
reason = "You ran out of food and starved."
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
gamer.set_nutrition(0) //yeah you pretty hongry
to_chat(gamer, "Your body instantly contracts to that of one who has not eaten in months. Agonizing cramps seize you as you fall to the floor.")
if(fuel <= 0)
reason = "You ran out of fuel, and drift, slowly, into a star."
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
gamer.adjust_fire_stacks(5)
gamer.IgniteMob() //flew into a star, so you're on fire
to_chat(gamer, "You feel an immense wave of heat emanate from the arcade machine. Your skin bursts into flames.")
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
to_chat(gamer, "You're never going to make it to Orion...")
gamer.death()
- obj_flags &= ~EMAGGED //removes the emagged status after you lose
+ obj_flags &= ~OBJ_EMAGGED //removes the emagged status after you lose
gameStatus = ORION_STATUS_START
name = "The Orion Trail"
desc = "Learn how our ancestors got to Orion, and have fun in the process!"
@@ -423,13 +423,13 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events())
gamer.playsound_local(get_turf(src) ,'sound/weapons/Gunshot_deagle.ogg', 50, TRUE)
if(!settlers.len || !alive)
src.audible_message("\The [src] says, 'The last crewmember [sheriff], shot themselves, GAME OVER!'")
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
gamer.death()
set_game_over(gamer, "Your last pioneer committed suicide.")
if(killed_crew >= ORION_STARTING_CREW_COUNT)
//gamer.mind?.adjust_experience(/datum/skill/gaming, -15)//no cheating by spamming game overs
report_player(gamer)
- else if(obj_flags & EMAGGED)
+ else if(obj_flags & OBJ_EMAGGED)
if(findtext(gamer.name, sheriff))
src.audible_message("\The [src] says, 'The crew of the ship chose to kill [gamer]!'")
gamer.death()
@@ -466,24 +466,24 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events())
/obj/machinery/computer/arcade/orion_trail/proc/win(mob/user)
gameStatus = ORION_STATUS_START
src.audible_message("\The [src] says, 'Congratulations, you made it to Orion!'")
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
new /obj/item/orion_ship(loc)
message_admins("[ADMIN_LOOKUPFLW(usr)] made it to Orion on an emagged machine and got an explosive toy ship.")
log_game("[key_name(usr)] made it to Orion on an emagged machine and got an explosive toy ship.")
else
prizevend(user)
- obj_flags &= ~EMAGGED
+ obj_flags &= ~OBJ_EMAGGED
name = initial(name)
desc = initial(desc)
/obj/machinery/computer/arcade/orion_trail/emag_act(mob/user)
- if(obj_flags & EMAGGED)
+ if(obj_flags & OBJ_EMAGGED)
return
to_chat(user, SPAN_NOTICE("You override the cheat code menu and skip to Cheat #[rand(1, 50)]: Realism Mode."))
name = "The Orion Trail: Realism Edition"
desc = "Learn how our ancestors got to Orion, and try not to die in the process!"
newgame()
- obj_flags |= EMAGGED
+ obj_flags |= OBJ_EMAGGED
/mob/living/simple_mob/hostile/humanoid/orion
name = "spaceport security"
diff --git a/code/game/machinery/computer/arcade/orion_event.dm b/code/game/machinery/computer/arcade/orion_event.dm
index 2c1d541f987..f7fb5895f4b 100644
--- a/code/game/machinery/computer/arcade/orion_event.dm
+++ b/code/game/machinery/computer/arcade/orion_event.dm
@@ -435,7 +435,7 @@
..()
/*
/datum/orion_event/black_hole_death/emag_effect(obj/machinery/computer/arcade/orion_trail/game, mob/living/carbon/gamer)
- if(game.obj_flags & EMAGGED)
+ if(game.obj_flags & OBJ_EMAGGED)
playsound(game.loc, 'sound/effects/supermatter.ogg', 100, TRUE)
game.say("A miniature black hole suddenly appears in front of [game], devouring [gamer] alive!")
gamer.afflict_stun(20 * 200, ignore_canstun = TRUE) //you can't run :^)
@@ -523,7 +523,7 @@
game.set_game_over(usr, "You were gunned down by space port security.")
return ..()
text = "You failed to raid the spaceport! You lost [fuel*-1] Fuel and [food*-1] Food, AND [lost_crew] in your scramble to escape! ([fuel]fuel, [food] food, -Crew)"
- if(game.obj_flags & EMAGGED)
+ if(game.obj_flags & OBJ_EMAGGED)
game.audible_message("\The [src] says, 'WEEWOO! WEEWOO! Spaceport security en route!'")
playsound(game, 'sound/items/weeoo1.ogg', 100, FALSE)
//for(var/i, i<=3, i++)
diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm
index c6876f758bc..3748b3970ce 100644
--- a/code/game/machinery/computer/camera.dm
+++ b/code/game/machinery/computer/camera.dm
@@ -64,6 +64,7 @@
network = list(NETWORK_THUNDER)
density = 0
circuit = null
+ depth_projected = FALSE
/obj/machinery/computer/security/telescreen/entertainment
name = "entertainment monitor"
diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm
index 956524447cf..a99174ac303 100644
--- a/code/game/machinery/computer/computer.dm
+++ b/code/game/machinery/computer/computer.dm
@@ -33,39 +33,10 @@
return TRUE
/obj/machinery/computer/emp_act(severity)
- if(prob(20/severity)) set_broken()
- ..()
-
-
-/obj/machinery/computer/legacy_ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- return
- if(2.0)
- if (prob(25))
- qdel(src)
- return
- if (prob(50))
- for(var/x in verbs)
- remove_obj_verb(src, x)
- set_broken()
- if(3.0)
- if (prob(25))
- for(var/x in verbs)
- remove_obj_verb(src, x)
- set_broken()
- else
- return
-
-/obj/machinery/computer/bullet_act(var/obj/projectile/Proj)
- if(prob(Proj.get_structure_damage()))
+ if(prob(20/severity))
set_broken()
..()
-/obj/machinery/computer/blob_act()
- legacy_ex_act(2)
-
/obj/machinery/computer/update_icon()
cut_overlays()
@@ -110,6 +81,16 @@
else
set_light(light_range_on, light_power_on)
+/obj/machinery/computer/drop_products(method, atom/where)
+ . = ..()
+ // todo: legacy-ish shitcode
+ if(machine_stat & BROKEN)
+ new /obj/item/material/shard(where)
+
+/obj/machinery/computer/atom_break()
+ . = ..()
+ set_broken()
+
/obj/machinery/computer/proc/set_broken()
machine_stat |= BROKEN
update_icon()
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 2f740a0166e..9e80eb1a2ba 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -18,6 +18,8 @@
climb_allowed = FALSE
depth_projected = FALSE
interaction_flags_machine = INTERACT_MACHINE_OFFLINE | INTERACT_MACHINE_ALLOW_SILICON
+ // todo: temporary, as this is unbuildable
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE
var/mode = null
//Used for logging people entering cryosleep and important items they are carrying.
@@ -224,6 +226,8 @@
density = TRUE
anchored = TRUE
dir = WEST
+ // todo: temporary, as this is unbuildable
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE
base_icon_state = "cryopod_0"
var/occupied_icon_state = "cryopod_1"
@@ -441,6 +445,10 @@
items -= announce // or the autosay radio.
for(var/obj/item/W in items)
+ // todo: fucking rework cryo
+ if(istype(W, /obj/item/holder))
+ W.forceMove(drop_location())
+ return
var/preserve = FALSE
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index c51b2f561f8..92e9e54feac 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -1,108 +1,3 @@
-/*
-CONTAINS:
-Deployable items
-Barricades
-*/
-
-//Barricades!
-/obj/structure/barricade
- name = "barricade"
- desc = "This space is blocked off by a barricade."
- icon = 'icons/obj/structures.dmi'
- icon_state = "barricade"
- pass_flags_self = ATOM_PASS_TABLE
- anchored = TRUE
- density = TRUE
- var/health = 100
- var/maxhealth = 100
- var/datum/material/material
-
-/obj/structure/barricade/Initialize(mapload, material_name)
- . = ..()
- if(!material_name)
- material_name = "wood"
- material = get_material_by_name("[material_name]")
- if(!material)
- qdel(src)
- return
- name = "[material.display_name] barricade"
- desc = "This space is blocked off by a barricade made of [material.display_name]."
- color = material.icon_colour
- maxhealth = material.integrity
- health = maxhealth
-
-/obj/structure/barricade/get_material()
- return material
-
-/obj/structure/barricade/attackby(obj/item/W as obj, mob/user as mob)
- user.setClickCooldown(user.get_attack_speed(W))
- if(istype(W, /obj/item/stack))
- var/obj/item/stack/D = W
- if(D.get_material_name() != material.name)
- return //hitting things with the wrong type of stack usually doesn't produce messages, and probably doesn't need to.
- if(health < maxhealth)
- if(D.get_amount() < 1)
- to_chat(user, SPAN_WARNING("You need one sheet of [material.display_name] to repair \the [src]."))
- return
- visible_message(SPAN_NOTICE("[user] begins to repair \the [src]."))
- if(do_after(user,20) && health < maxhealth)
- if(D.use(1))
- health = maxhealth
- visible_message(SPAN_NOTICE("[user] repairs \the [src]."))
- return
- return
- else
- switch(W.damtype)
- if("fire")
- health -= W.damage_force * 1
- if("brute")
- health -= W.damage_force * 0.75
- if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD) || get_material_by_name(MAT_HARDWOOD)))
- playsound(loc, 'sound/effects/woodcutting.ogg', 100, TRUE)
- else
- playsound(src, 'sound/weapons/smash.ogg', 50, TRUE)
- CheckHealth()
- ..()
-
-/obj/structure/barricade/proc/CheckHealth()
- if(health <= 0)
- dismantle()
- return
-
-/obj/structure/barricade/take_damage(damage)
- health -= damage
- CheckHealth()
- return
-
-/obj/structure/barricade/attack_generic(mob/user, damage, attack_verb)
- visible_message(SPAN_DANGER("[user] [attack_verb] \the [src]!"))
-
- if(material == get_material_by_name("resin"))
- playsound(loc, 'sound/effects/attackblob.ogg', 100, TRUE)
- else if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD) || get_material_by_name(MAT_HARDWOOD)))
- playsound(loc, 'sound/effects/woodcutting.ogg', 100, TRUE)
- else
- playsound(src, 'sound/weapons/smash.ogg', 50, TRUE)
- user.do_attack_animation(src)
- health -= damage
- CheckHealth()
- return
-
-/obj/structure/barricade/proc/dismantle()
- material.place_dismantled_product(get_turf(src))
- visible_message("\The [src] falls apart!")
- qdel(src)
- return
-
-/obj/structure/barricade/legacy_ex_act(severity)
- switch(severity)
- if(1.0)
- dismantle()
- if(2.0)
- health -= 25
- CheckHealth()
-
-//Actual Deployable machinery stuff
/obj/machinery/deployable
name = "deployable"
desc = "deployable"
@@ -117,8 +12,8 @@ Barricades
density = TRUE
icon_state = "barrier0"
pass_flags_self = ATOM_PASS_TABLE
- var/health = 100
- var/maxhealth = 100
+ integrity = 200
+ integrity_max = 200
var/locked = FALSE
// req_access = list(ACCESS_ENGINEERING_MAINT)
@@ -130,9 +25,11 @@ Barricades
. = ..()
icon_state = "barrier[locked]"
-/obj/machinery/deployable/barrier/attackby(obj/item/W as obj, mob/user as mob)
+/obj/machinery/deployable/barrier/attackby(obj/item/I, mob/living/user, list/params, clickchain_flags, damage_multiplier)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
- if(istype(W, /obj/item/card/id/))
+ if(istype(I, /obj/item/card/id/))
if(allowed(user))
if (emagged < 2)
locked = !locked
@@ -151,10 +48,10 @@ Barricades
visible_message(SPAN_WARNING("BZZzZZzZZzZT"))
return
return
- else if(W.is_wrench())
- if(health < maxhealth)
- health = maxhealth
- emagged = 0
+ else if(I.is_wrench())
+ if(integrity < integrity_max)
+ set_integrity(integrity_max)
+ emagged = FALSE
req_access = list(ACCESS_SECURITY_EQUIPMENT)
visible_message(SPAN_WARNING("[user] repairs \the [src]!"))
return
@@ -164,43 +61,7 @@ Barricades
visible_message(SPAN_WARNING("[user] repairs \the [src]!"))
return
return
- else
- switch(W.damtype)
- if("fire")
- health -= W.damage_force * 0.75
- if("brute")
- health -= W.damage_force * 0.5
- playsound(src, 'sound/weapons/smash.ogg', 50, TRUE)
- CheckHealth()
- ..()
-
-/obj/machinery/deployable/barrier/proc/CheckHealth()
- if(health <= 0)
- explode()
- return
-
-/obj/machinery/deployable/barrier/attack_generic(mob/user, damage, attack_verb)
- visible_message(SPAN_DANGER("[user] [attack_verb] \the [src]!"))
- playsound(src, 'sound/weapons/smash.ogg', 50, TRUE)
- user.do_attack_animation(src)
- health -= damage
- CheckHealth()
- return
-
-/obj/machinery/deployable/barrier/take_damage(damage)
- health -= damage
- CheckHealth()
- return
-
-/obj/machinery/deployable/barrier/legacy_ex_act(severity)
- switch(severity)
- if(1.0)
- explode()
- return
- if(2.0)
- health -= 25
- CheckHealth()
- return
+ return ..()
/obj/machinery/deployable/barrier/emp_act(severity)
if(machine_stat & (BROKEN|NOPOWER))
diff --git a/code/game/machinery/deployable_vr.dm b/code/game/machinery/deployable_vr.dm
index b57f97c5659..55b62ce1844 100644
--- a/code/game/machinery/deployable_vr.dm
+++ b/code/game/machinery/deployable_vr.dm
@@ -4,7 +4,10 @@
icon = 'icons/obj/cardboard_cutout.dmi'
icon_state = "cutout_basic"
- maxhealth = 15 //Weaker than normal barricade
+ integrity = 40
+ integrity_max = 40
+ integrity_failure = 20
+
anchored = FALSE
var/fake_name = "unknown"
@@ -50,11 +53,15 @@
name = fake_name
desc = fake_desc
visible_message(SPAN_WARNING("[src] is uprighted to their proper position."))
+ set_integrity(integrity_max)
-/obj/structure/barricade/cutout/CheckHealth()
- if(!toppled && (health < (maxhealth/2)))
- topple()
- ..()
+/obj/structure/barricade/cutout/atom_break()
+ . = ..()
+ topple()
+
+/obj/structure/barricade/cutout/atom_fix()
+ . = ..()
+ untopple()
/obj/structure/barricade/cutout/attack_hand(mob/user, list/params)
if((. = ..()))
@@ -65,9 +72,9 @@
/obj/structure/barricade/cutout/examine(mob/user, dist)
. = ..()
-
- if(Adjacent(user))
- . += SPAN_NOTICE("... from this distance, they seem to be made of [material.name] ...")
+ if(dist <= 1)
+ var/datum/material/primary = get_primary_material()
+ . += SPAN_NOTICE("... from this distance, they seem to be made of [isnull(primary)? "cardboard" : primary.name] ...")
/obj/structure/barricade/cutout/attackby(obj/I, mob/user)
if(is_type_in_list(I, painters))
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock/airlock.dm
similarity index 95%
rename from code/game/machinery/doors/airlock.dm
rename to code/game/machinery/doors/airlock/airlock.dm
index 49bd15f65d1..c89103137b2 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock/airlock.dm
@@ -33,6 +33,10 @@ GLOBAL_REAL_VAR(airlock_typecache) = typecacheof(list(
power_channel = ENVIRON
rad_flags = RAD_BLOCK_CONTENTS
rad_insulation = RAD_INSULATION_MEDIUM
+ armor_type = /datum/armor/door/airlock
+
+ integrity = 300
+ integrity_max = 300
explosion_resistance = 10
autoclose = 1
@@ -69,7 +73,6 @@ GLOBAL_REAL_VAR(airlock_typecache) = typecacheof(list(
var/closeOtherId = null
var/lockdownbyai = 0
var/assembly_type = /obj/structure/door_assembly
- var/mineral = null
var/justzap = 0
var/safe = 1
var/obj/item/airlock_electronics/electronics = null
@@ -197,7 +200,7 @@ GLOBAL_REAL_VAR(airlock_typecache) = typecacheof(list(
if(machine_stat & BROKEN)
damage_overlay = sparks_broken_file
- else if(health < maxhealth * 3/4)
+ else if(integrity < integrity_max * 2 / 3)
damage_overlay = sparks_damaged_file
if(welded)
@@ -222,8 +225,9 @@ GLOBAL_REAL_VAR(airlock_typecache) = typecacheof(list(
))
/obj/machinery/door/airlock/attack_generic(var/mob/living/user, var/damage)
+ // todo: refactor
if(machine_stat & (BROKEN|NOPOWER))
- if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
+ if(damage >= 5)
if(src.locked || src.welded)
visible_message("\The [user] begins breaking into \the [src] internals!")
user.set_AI_busy(TRUE) // If the mob doesn't have an AI attached, this won't do anything.
@@ -277,11 +281,6 @@ GLOBAL_REAL_VAR(airlock_typecache) = typecacheof(list(
return
..()
-/obj/machinery/door/airlock/get_material()
- if(mineral)
- return get_material_by_name(mineral)
- return get_material_by_name(MAT_STEEL)
-
/obj/machinery/door/airlock/process(delta_time)
// Deliberate no call to parent.
if(main_power_lost_until > 0 && world.time >= main_power_lost_until)
@@ -648,7 +647,7 @@ About the new airlock wires panel:
if (istype(mover, /obj/item))
var/obj/item/i = mover
if(world.time > last_spark + 2 SECONDS)
- if (i.materials && (MAT_STEEL in i.materials) && i.materials[MAT_STEEL] > 0)
+ if (i.materials_base && (MAT_STEEL in i.materials_base) && i.materials_base[MAT_STEEL] > 0)
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
s.set_up(5, 1, src)
s.start()
@@ -786,7 +785,6 @@ About the new airlock wires panel:
if(istype(C, /obj/item/barrier_tape_roll))
return
- if (attempt_vr(src,"attackby_vr",list(C, user))) return
if(istype(C, /mob/living))
..()
return
@@ -828,32 +826,8 @@ About the new airlock wires panel:
user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove electronics from the airlock assembly.")
if(do_after(user,40 * C.tool_speed))
to_chat(user, "You removed the airlock electronics!")
-
- var/obj/structure/door_assembly/da = new assembly_type(src.loc)
- if (istype(da, /obj/structure/door_assembly/multi_tile))
- da.setDir(src.dir)
-
- da.anchored = 1
- if(mineral)
- da.glass = mineral
- //else if(glass)
- else if(glass && !da.glass)
- da.glass = 1
- da.state = 1
- da.created_name = src.name
- da.update_state()
-
- if(operating == -1 || (machine_stat & BROKEN))
- new /obj/item/circuitboard/broken(src.loc)
- operating = 0
- else
- if (!electronics) create_electronics()
-
- electronics.loc = src.loc
- electronics = null
-
- qdel(src)
- return
+ deconstruct(ATOM_DECONSTRUCT_DISASSEMBLED)
+ return CLICKCHAIN_DO_NOT_PROPAGATE | CLICKCHAIN_DID_SOMETHING
else if(arePowerSystemsOn())
to_chat(user, "The airlock's motors resist your efforts to force it.")
else if(locked)
@@ -894,11 +868,11 @@ About the new airlock wires panel:
ignite(is_hot(C))
..()
-/obj/machinery/door/airlock/set_broken()
+/obj/machinery/door/airlock/atom_break()
src.p_open = 1
- machine_stat |= BROKEN
if (secured_wires)
lock()
+ . = ..()
for (var/mob/O in viewers(src, null))
if ((O.client && !( O.blinded )))
O.show_message("[src.name]'s control panel bursts open, sparks spewing out!")
@@ -907,9 +881,6 @@ About the new airlock wires panel:
s.set_up(5, 1, src)
s.start()
- update_icon()
- return
-
/obj/machinery/door/airlock/open(var/forced=0)
if(!can_open(forced))
return 0
@@ -942,7 +913,7 @@ About the new airlock wires panel:
for(var/turf/turf in locs)
for(var/atom/movable/AM in turf)
if(AM.airlock_crush(DOOR_CRUSH_DAMAGE))
- take_damage(DOOR_CRUSH_DAMAGE)
+ inflict_atom_damage(DOOR_CRUSH_DAMAGE, flag = ARMOR_MELEE)
use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people
has_beeped = 0
@@ -992,22 +963,20 @@ About the new airlock wires panel:
/mob/living/blocks_airlock()
return 1
+// todo: refactor
/atom/movable/proc/airlock_crush(var/crush_damage)
return 0
/obj/machinery/portable_atmospherics/canister/airlock_crush(var/crush_damage)
. = ..()
- health -= crush_damage
- healthcheck()
+ damage_integrity(crush_damage)
/obj/effect/energy_field/airlock_crush(var/crush_damage)
adjust_strength(crush_damage)
/obj/structure/closet/airlock_crush(var/crush_damage)
..()
- damage(crush_damage)
- for(var/atom/movable/AM in src)
- AM.airlock_crush()
+ damage_integrity(crush_damage)
return 1
/mob/living/airlock_crush(var/crush_damage)
@@ -1149,8 +1118,43 @@ About the new airlock wires panel:
//update the electronics to match the door's access
if(!src.req_access)
src.check_access()
- electronics.conf_req_access = req_access.Copy()
- electronics.conf_req_one_access = req_one_access.Copy()
+ electronics.conf_req_access = req_access?.Copy()
+ electronics.conf_req_one_access = req_one_access?.Copy()
+
+/**
+ * drop our circuitry
+ */
+/obj/machinery/door/airlock/proc/drop_airlock_electronics(atom/where = drop_location(), broken)
+ if(broken)
+ new /obj/item/circuitboard/broken(where)
+ return
+ if(isnull(electronics))
+ create_electronics()
+ electronics.forceMove(loc)
+ electronics = null
+
+/**
+ * drop our assembly
+ */
+/obj/machinery/door/airlock/proc/drop_airlock_assembly(atom/where = drop_location())
+ var/obj/structure/door_assembly/assembly = new assembly_type(where)
+ if(istype(assembly, /obj/structure/door_assembly/multi_tile))
+ assembly.setDir(dir)
+ //! LEGACY
+ assembly.set_anchored(TRUE)
+ assembly.state = 1
+ if(mineral)
+ assembly.glass = mineral
+ else if(glass && !assembly.glass)
+ assembly.glass = TRUE
+ assembly.created_name = name
+ assembly.update_state()
+ //! END
+
+/obj/machinery/door/airlock/drop_products(method, atom/where)
+ . = ..()
+ drop_airlock_assembly(where)
+ drop_airlock_electronics(where, (atom_flags & ATOM_BROKEN) || (method != ATOM_DECONSTRUCT_DISASSEMBLED))
/obj/machinery/door/airlock/emp_act(var/severity)
if(prob(40/severity))
diff --git a/code/game/machinery/doors/airlock_control.dm b/code/game/machinery/doors/airlock/airlock_control.dm
similarity index 100%
rename from code/game/machinery/doors/airlock_control.dm
rename to code/game/machinery/doors/airlock/airlock_control.dm
diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock/airlock_electronics.dm
similarity index 97%
rename from code/game/machinery/doors/airlock_electronics.dm
rename to code/game/machinery/doors/airlock/airlock_electronics.dm
index 988e37fc620..398eef26b61 100644
--- a/code/game/machinery/doors/airlock_electronics.dm
+++ b/code/game/machinery/doors/airlock/airlock_electronics.dm
@@ -4,7 +4,7 @@
icon_state = "door_electronics"
w_class = ITEMSIZE_SMALL //It should be tiny! -Agouri
- materials = list(MAT_STEEL = 50, MAT_GLASS = 50)
+ materials_base = list(MAT_STEEL = 50, MAT_GLASS = 50)
var/list/conf_req_access
var/list/conf_req_one_access
diff --git a/code/game/machinery/doors/airlock_subtypes.dm b/code/game/machinery/doors/airlock/airlock_subtypes.dm
similarity index 97%
rename from code/game/machinery/doors/airlock_subtypes.dm
rename to code/game/machinery/doors/airlock/airlock_subtypes.dm
index fea2ca8f139..fba2e5a6eb1 100644
--- a/code/game/machinery/doors/airlock_subtypes.dm
+++ b/code/game/machinery/doors/airlock/airlock_subtypes.dm
@@ -137,10 +137,9 @@
/obj/machinery/door/airlock/glass
name = "Glass Airlock"
- hitsound = 'sound/effects/Glasshit.ogg'
open_sound_powered = 'sound/machines/door/hall1o.ogg'
close_sound_powered = 'sound/machines/door/hall1c.ogg'
- maxhealth = 300
+ hit_sound_brute = 'sound/effects/Glasshit.ogg'
explosion_resistance = 5
opacity = FALSE
glass = TRUE
@@ -175,6 +174,7 @@
close_sound_powered = 'sound/machines/door/vault1c.ogg'
icon = 'icons/obj/doors/vault/door.dmi'
fill_file = 'icons/obj/doors/vault/fill_steel.dmi'
+ heat_resistance = 6000
/obj/machinery/door/airlock/vault/bolted
icon_state = "door_locked"
@@ -207,6 +207,7 @@
welded_file = 'icons/obj/doors/hatch/welded.dmi'
emag_file = 'icons/obj/doors/hatch/emag.dmi'
stripe_color = COLOR_AMBER
+ heat_resistance = 6000
/obj/machinery/door/airlock/maintenance_hatch
name = "Maintenance Hatch"
@@ -235,8 +236,6 @@
name = "Command Airlock"
opacity = FALSE
glass = TRUE
- hitsound = 'sound/effects/Glasshit.ogg'
- maxhealth = 300
explosion_resistance = 5
opacity = 0
assembly_type = /obj/structure/door_assembly/command
@@ -251,8 +250,6 @@
/obj/machinery/door/airlock/glass/engineering
name = "Engineering Airlock"
- hitsound = 'sound/effects/Glasshit.ogg'
- maxhealth = 300
explosion_resistance = 5
opacity = 0
assembly_type = /obj/structure/door_assembly/engi
@@ -266,8 +263,6 @@
/obj/machinery/door/airlock/glass/engineeringatmos
name = "Atmospherics Airlock"
- hitsound = 'sound/effects/Glasshit.ogg'
- maxhealth = 300
explosion_resistance = 5
opacity = 0
assembly_type = /obj/structure/door_assembly/engi_atmos
@@ -281,8 +276,6 @@
/obj/machinery/door/airlock/glass/security
name = "Security Airlock"
- hitsound = 'sound/effects/Glasshit.ogg'
- maxhealth = 300
explosion_resistance = 5
opacity = 0
assembly_type = /obj/structure/door_assembly/security
@@ -295,8 +288,6 @@
/obj/machinery/door/airlock/glass/medical
name = "Medical Airlock"
- hitsound = 'sound/effects/Glasshit.ogg'
- maxhealth = 300
explosion_resistance = 5
opacity = 0
assembly_type = /obj/structure/door_assembly/medical
@@ -336,8 +327,6 @@
/obj/machinery/door/airlock/glass/research
name = "Research Airlock"
- hitsound = 'sound/effects/Glasshit.ogg'
- maxhealth = 300
explosion_resistance = 5
opacity = 0
assembly_type = /obj/structure/door_assembly/research
@@ -351,8 +340,6 @@
/obj/machinery/door/airlock/glass/mining
name = "Mining Airlock"
- hitsound = 'sound/effects/Glasshit.ogg'
- maxhealth = 300
explosion_resistance = 5
opacity = 0
assembly_type = /obj/structure/door_assembly/mining
@@ -366,8 +353,6 @@
/obj/machinery/door/airlock/glass/atmos
name = "Atmospherics Airlock"
- hitsound = 'sound/effects/Glasshit.ogg'
- maxhealth = 300
explosion_resistance = 5
opacity = 0
assembly_type = /obj/structure/door_assembly/atmos
diff --git a/code/game/machinery/doors/airlock_vr.dm b/code/game/machinery/doors/airlock/airlock_vr.dm
similarity index 100%
rename from code/game/machinery/doors/airlock_vr.dm
rename to code/game/machinery/doors/airlock/airlock_vr.dm
diff --git a/code/game/machinery/doors/alarmlock.dm b/code/game/machinery/doors/airlock/alarmlock.dm
similarity index 100%
rename from code/game/machinery/doors/alarmlock.dm
rename to code/game/machinery/doors/airlock/alarmlock.dm
diff --git a/code/game/machinery/doors/phoronlocks.dm b/code/game/machinery/doors/airlock/phoronlocks.dm
similarity index 100%
rename from code/game/machinery/doors/phoronlocks.dm
rename to code/game/machinery/doors/airlock/phoronlocks.dm
diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm
index f28b7052b2e..b9041727b7d 100644
--- a/code/game/machinery/doors/blast_door.dm
+++ b/code/game/machinery/doors/blast_door.dm
@@ -15,7 +15,7 @@
desc = "That looks like it doesn't open easily."
icon = 'icons/obj/doors/rapid_pdoor.dmi'
icon_state = null
- min_force = 20 //minimum amount of force needed to damage the door with a melee weapon
+ armor_type = /datum/armor/door/blast_door
rad_flags = RAD_NO_CONTAMINATE
rad_insulation = RAD_INSULATION_SUPER
dir = NORTH
@@ -44,9 +44,6 @@
. = ..()
implicit_material = get_material_by_name("plasteel")
-/obj/machinery/door/blast/get_material()
- return implicit_material
-
// Proc: Bumped()
// Parameters: 1 (AM - Atom that tried to walk through this object)
// Description: If we are open returns zero, otherwise returns result of parent function.
@@ -132,12 +129,14 @@
// Parameters: 2 (C - Item this object was clicked with, user - Mob which clicked this object)
// Description: If we are clicked with crowbar, wielded fire axe, or armblade, try to manually open the door.
// This only works on broken doors or doors without power. Also allows repair with Plasteel.
-/obj/machinery/door/blast/attackby(obj/item/C as obj, mob/user as mob)
- src.add_fingerprint(user, 0, C)
- if(istype(C, /obj/item)) // For reasons unknown, sometimes C is actually not what it is advertised as, like a mob.
- if(C.pry == 1 && (user.a_intent != INTENT_HARM || (machine_stat & BROKEN))) // Can we pry it open with something, like a crowbar/fireaxe/lingblade?
- if(istype(C,/obj/item/material/twohanded/fireaxe)) // Fireaxes need to be in both hands to pry.
- var/obj/item/material/twohanded/fireaxe/F = C
+/obj/machinery/door/blast/attackby(obj/item/I, mob/living/user, list/params, clickchain_flags, damage_multiplier)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
+ src.add_fingerprint(user, 0, I)
+ if(istype(I, /obj/item)) // For reasons unknown, sometimes C is actually not what it is advertised as, like a mob.
+ if(I.pry == 1 && (user.a_intent != INTENT_HARM || (machine_stat & BROKEN))) // Can we pry it open with something, like a crowbar/fireaxe/lingblade?
+ if(istype(I,/obj/item/material/twohanded/fireaxe)) // Fireaxes need to be in both hands to pry.
+ var/obj/item/material/twohanded/fireaxe/F = I
if(!F.wielded)
to_chat(user, "You need to be wielding \the [F] to do that.")
return
@@ -149,27 +148,12 @@
else
to_chat(user, "[src]'s motors resist your effort.")
return
-
-
- else if(src.density && (user.a_intent == INTENT_HARM)) //If we can't pry it open and it's a weapon, let's hit it.
- var/obj/item/W = C
- user.setClickCooldown(user.get_attack_speed(W))
- if(W.damtype == BRUTE || W.damtype == BURN)
- user.do_attack_animation(src)
- if(W.damage_force < min_force)
- user.visible_message("\The [user] hits \the [src] with \the [W] with no visible effect.")
- else
- user.visible_message("\The [user] forcefully strikes \the [src] with \the [W]!")
- playsound(src.loc, hitsound, 100, 1)
- take_damage(W.damage_force*0.35) //it's a blast door, it should take a while. -Luke
- return
-
- else if(istype(C, /obj/item/stack/material) && C.get_material_name() == "plasteel") // Repairing.
- var/amt = CEILING((maxhealth - health)/150, 1)
+ else if(I.is_material_stack_of(/datum/material/plasteel)) // Repairing.
+ var/amt = CEILING((integrity_max - integrity)/150, 1)
if(!amt)
to_chat(user, "\The [src] is already fully repaired.")
return
- var/obj/item/stack/P = C
+ var/obj/item/stack/P = I
if(P.amount < amt)
to_chat(user, "You don't have enough sheets to repair this! You need at least [amt] sheets.")
return
@@ -180,19 +164,7 @@
src.repair()
else
to_chat(user, "You don't have enough sheets to repair this! You need at least [amt] sheets.")
-
- else if(src.density && (user.a_intent == INTENT_HARM)) //If we can't pry it open and it's not a weapon.... Eh, let's attack it anyway.
- var/obj/item/W = C
- user.setClickCooldown(user.get_attack_speed(W))
- if(W.damtype == BRUTE || W.damtype == BURN)
- user.do_attack_animation(src)
- if(W.damage_force < min_force) //No actual non-weapon item shouls have a force greater than the min_force, but let's include this just in case.
- user.visible_message("\The [user] hits \the [src] with \the [W] with no visible effect.")
- else
- user.visible_message("\The [user] forcefully strikes \the [src] with \the [W]!")
- playsound(src.loc, hitsound, 100, 1)
- take_damage(W.damage_force*0.15) //If the item isn't a weapon, let's make this take longer than usual to break it down.
- return
+ return ..()
// Proc: attack_alien()
// Parameters: Attacking Xeno mob.
@@ -223,7 +195,7 @@
// Description: Checks the power or integrity of the blast door, if either have failed, chekcs the damage to determine if the creature would be able to open the door by force. Otherwise, super.
/obj/machinery/door/blast/attack_generic(mob/living/user, damage)
if(machine_stat & (BROKEN|NOPOWER))
- if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
+ if(damage >= 10)
user.set_AI_busy(TRUE) // If the mob doesn't have an AI attached, this won't do anything.
if(src.density)
visible_message("\The [user] starts forcing \the [src] open!")
@@ -271,7 +243,7 @@
// Parameters: None
// Description: Fully repairs the blast door.
/obj/machinery/door/blast/proc/repair()
- health = maxhealth
+ set_integrity(integrity_max)
if(machine_stat & BROKEN)
machine_stat &= ~BROKEN
@@ -292,7 +264,9 @@
icon_state_closed = "pdoor1"
icon_state_closing = "pdoorc1"
icon_state = "pdoor1"
- maxhealth = 600
+ integrity = 600
+ integrity_max = 600
+ heat_resistance = INFINITY
/obj/machinery/door/blast/regular/open
icon_state = "pdoor0"
diff --git a/code/game/machinery/doors/defense.dm b/code/game/machinery/doors/defense.dm
new file mode 100644
index 00000000000..eb2c3b43491
--- /dev/null
+++ b/code/game/machinery/doors/defense.dm
@@ -0,0 +1,7 @@
+/obj/machinery/door/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ var/maxtemperature = heat_resistance //same as a normal steel wall
+
+ if(exposed_temperature > maxtemperature)
+ var/burndamage = log(RAND_F(0.9, 1.1) * (exposed_temperature - maxtemperature))
+ inflict_atom_damage(burndamage, flag = ARMOR_FIRE, gradual = TRUE)
+ return ..()
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index a1cb606f3be..6380048ff7a 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -1,18 +1,28 @@
///amount of health regained per stack amount used
#define DOOR_REPAIR_AMOUNT 50
+
/obj/machinery/door
name = "Door"
desc = "It opens and closes."
icon = 'icons/obj/doors/Doorint.dmi'
icon_state = "door1"
- anchored = 1
- opacity = 1
- density = 1
+ armor_type = /datum/armor/door
+ anchored = TRUE
+ opacity = TRUE
+ density = TRUE
CanAtmosPass = ATMOS_PASS_PROC
layer = DOOR_OPEN_LAYER
rad_flags = RAD_BLOCK_CONTENTS
// todo: rad_insulation_open/closed
pass_flags_self = NONE
+
+ integrity = 300
+ integrity_max = 300
+ integrity_failure = 100
+
+ hit_sound_brute = 'sound/weapons/smash.ogg'
+
+ var/mineral
var/open_layer = DOOR_OPEN_LAYER
var/closed_layer = DOOR_CLOSED_LAYER
@@ -22,13 +32,8 @@
var/autoclose = 0//[bool]should the door close automaticly
var/glass = 0
var/normalspeed = 1
- var/heat_proof = 0 // For glass airlocks/opacity firedoors
+ var/heat_resistance = 1000 // For glass airlocks/opacity firedoors
var/air_properties_vary_with_direction = 0
- var/maxhealth = 300
- var/health
- var/destroy_hits = 10 //How many strong hits it takes to destroy the door
- var/min_force = 10 //minimum amount of force needed to damage the door with a melee weapon
- var/hitsound = 'sound/weapons/smash.ogg' //sound door makes when hit with a weapon
var/repairing = 0
var/block_air_zones = 1 //If set, air zones cannot merge across the door even when it is opened.
var/close_door_at = 0 //When to automatically close the door, if possible
@@ -40,16 +45,10 @@
// turf animation
var/atom/movable/overlay/c_animation = null
-/obj/machinery/door/attack_generic(var/mob/user, var/damage)
- if(isanimal(user))
- var/mob/living/simple_mob/S = user
- if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
- visible_message("\The [user] smashes into the [src]!")
- playsound(src, S.attack_sound, 75, 1)
- take_damage(damage)
- else
- visible_message("\The [user] bonks \the [src] harmlessly.")
- user.do_attack_animation(src)
+ var/reinforcing = 0
+ var/tintable = 0
+ var/icon_tinted
+ var/id_tint
/obj/machinery/door/Initialize(mapload, newdir)
. = ..()
@@ -61,7 +60,6 @@
layer = open_layer
explosion_resistance = 0
-
if(width > 1)
if(dir in list(EAST, WEST))
bound_width = world.icon_size
@@ -70,7 +68,6 @@
bound_width = width * world.icon_size
bound_height = world.icon_size
- health = maxhealth
update_icon()
update_nearby_tiles()
@@ -166,41 +163,12 @@
else
do_animate(DOOR_ANIMATION_DENY)
-/obj/machinery/door/bullet_act(var/obj/projectile/Proj)
- ..()
-
- var/damage = Proj.get_structure_damage()
-
- // Emitter Blasts - these will eventually completely destroy the door, given enough time.
- if (damage > 90)
- destroy_hits--
- if (destroy_hits <= 0)
- visible_message("\The [src.name] disintegrates!")
- switch (Proj.damage_type)
- if(BRUTE)
- new /obj/item/stack/material/steel(src.loc, 2)
- new /obj/item/stack/rods(src.loc, 3)
- if(BURN)
- new /obj/effect/debris/cleanable/ash(src.loc) // Turn it to ashes!
- qdel(src)
-
- if(damage)
- //cap projectile damage so that there's still a minimum number of hits required to break the door
- take_damage(min(damage, 100))
-
-
-
-/obj/machinery/door/throw_impacted(atom/movable/AM, datum/thrownthing/TT)
- . = ..()
- visible_message("[src.name] was hit by [AM].")
- var/tforce = AM.throw_force * TT.get_damage_multiplier()
- playsound(src, hitsound, 100, 1)
- take_damage(tforce)
-
/obj/machinery/door/attack_ai(mob/user as mob)
return src.attack_hand(user)
/obj/machinery/door/attack_hand(mob/user, list/params)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
return src.attackby(user, user)
/obj/machinery/door/attack_tk(mob/user as mob)
@@ -208,17 +176,19 @@
return
..()
-/obj/machinery/door/attackby(obj/item/I as obj, mob/user as mob)
+/obj/machinery/door/attackby(obj/item/I, mob/living/user, list/params, clickchain_flags, damage_multiplier)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
src.add_fingerprint(user, 0, I)
if(istype(I))
if(attackby_vr(I, user))
return
- if(istype(I, /obj/item/stack/material) && I.get_material_name() == src.get_material_name())
+ if(mineral && I.is_material_stack_of(mineral))
if(machine_stat & BROKEN)
to_chat(user, "It looks like \the [src] is pretty busted. It's going to need more than just patching up now.")
return
- if(health >= maxhealth)
+ if(integrity >= integrity_max)
to_chat(user, "Nothing to fix!")
return
if(!density)
@@ -226,14 +196,14 @@
return
//figure out how much metal we need
- var/amount_needed = (maxhealth - health) / DOOR_REPAIR_AMOUNT
+ var/amount_needed = (integrity_max - integrity) / DOOR_REPAIR_AMOUNT
amount_needed = (round(amount_needed) == amount_needed)? amount_needed : round(amount_needed) + 1 //Why does BYOND not have a ceiling proc?
var/obj/item/stack/stack = I
var/amount_given = amount_needed - repairing
var/mats_given = stack.get_amount()
if(repairing && amount_given <= 0)
- to_chat(user, "You must weld or remove \the [get_material_name()] from \the [src] before you can add anything else.")
+ to_chat(user, "You must weld or remove \the [mineral? mineral : "plating"] from \the [src] before you can add anything else.")
else
if(mats_given >= amount_given)
if(stack.use(amount_given))
@@ -254,37 +224,22 @@
var/obj/item/weldingtool/welder = I
if(welder.remove_fuel(0,user))
- to_chat(user, "You start to fix dents and weld \the [get_material_name()] into place.")
+ to_chat(user, "You start to fix dents and weld \the [mineral? mineral : "plating"] into place.")
playsound(src, welder.tool_sound, 50, 1)
if(do_after(user, (5 * repairing) * welder.tool_speed) && welder && welder.isOn())
to_chat(user, "You finish repairing the damage to \the [src].")
- health = between(health, health + repairing*DOOR_REPAIR_AMOUNT, maxhealth)
+ integrity = clamp(integrity + repairing * DOOR_REPAIR_AMOUNT, 0, integrity_max)
update_icon()
repairing = 0
return
if(repairing && I.is_crowbar())
- var/datum/material/M = get_material()
+ var/datum/material/M = SSmaterials.resolve_material(mineral)
var/obj/item/stack/material/repairing_sheet = M.place_sheet(loc)
repairing_sheet.amount += repairing-1
repairing = 0
to_chat(user, "You remove \the [repairing_sheet].")
playsound(src, I.tool_sound, 100, 1)
- return
-
- //psa to whoever coded this, there are plenty of objects that need to call attack() on doors without bludgeoning them.
- if(src.density && istype(I, /obj/item) && user.a_intent == INTENT_HARM && !istype(I, /obj/item/card))
- var/obj/item/W = I
- user.setClickCooldown(user.get_attack_speed(W))
- if(W.damtype == BRUTE || W.damtype == BURN)
- user.do_attack_animation(src)
- if(W.damage_force < min_force)
- user.visible_message("\The [user] hits \the [src] with \the [W] with no visible effect.")
- else
- user.visible_message("\The [user] forcefully strikes \the [src] with \the [W]!")
- playsound(src.loc, hitsound, 100, 1)
- take_damage(W.damage_force)
- return
if(src.operating > 0 || isrobot(user))
return //borgs can't attack doors open because it conflicts with their AI-like interaction with them.
@@ -311,41 +266,35 @@
operating = -1
return 1
-/obj/machinery/door/take_damage(var/damage)
- var/initialhealth = src.health
- src.health = max(0, src.health - damage)
- if(src.health <= 0 && initialhealth > 0)
- src.set_broken()
- else if(src.health < src.maxhealth / 4 && initialhealth >= src.maxhealth / 4)
- visible_message("\The [src] looks like it's about to break!" )
- else if(src.health < src.maxhealth / 2 && initialhealth >= src.maxhealth / 2)
- visible_message("\The [src] looks seriously damaged!" )
- else if(src.health < src.maxhealth * 3/4 && initialhealth >= src.maxhealth * 3/4)
- visible_message("\The [src] shows signs of damage!" )
- update_icon()
- return
-
-
-/obj/machinery/door/examine(mob/user, dist)
+/obj/machinery/door/damage_integrity(amount, gradual, do_not_break)
+ var/initial_integrity = integrity
. = ..()
- if(src.health <= 0)
- . += "The [src] is broken!"
- if(src.health < src.maxhealth / 4)
- . += "The [src] looks like it's about to break!"
- else if(src.health < src.maxhealth / 2)
- . += "The [src] looks seriously damaged!"
- else if(src.health < src.maxhealth * 3/4)
- . += "The [src] shows signs of damage!"
+ if(gradual)
+ update_appearance(UPDATE_ICON)
+ return
+ if(integrity < integrity_max / 4 && initial_integrity >= integrity_max / 4)
+ visible_message("[src] looks like it's about to break!" )
+ update_appearance(UPDATE_ICON)
+ else if(integrity < integrity_max / 2 && initial_integrity >= integrity_max / 2)
+ visible_message("[src] looks seriously damaged!" )
+ update_appearance(UPDATE_ICON)
+ else if(integrity < integrity_max * 3/4 && initial_integrity >= integrity_max * 3/4 && integrity > 0)
+ visible_message("[src] shows signs of damage!" )
+ update_appearance(UPDATE_ICON)
-
-/obj/machinery/door/proc/set_broken()
- machine_stat |= BROKEN
- for (var/mob/O in viewers(src, null))
- if ((O.client && !( O.blinded )))
- O.show_message("[src.name] breaks!" )
+/obj/machinery/door/atom_break()
+ . = ..()
+ // todo: this is shitcode
+ if(!istype(src, /obj/machinery/door/airlock))
+ for (var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message("[src.name] breaks!" )
update_icon()
- return
+/obj/machinery/door/atom_fix()
+ . = ..()
+ machine_stat &= (~BROKEN)
+ update_icon()
/obj/machinery/door/emp_act(severity)
if(prob(20/severity) && (istype(src,/obj/machinery/door/airlock) || istype(src,/obj/machinery/door/window)) )
@@ -353,33 +302,6 @@
open()
..()
-
-/obj/machinery/door/legacy_ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- if(2.0)
- if(prob(25))
- qdel(src)
- else
- take_damage(300)
- if(3.0)
- if(prob(80))
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(2, 1, src)
- s.start()
- else
- take_damage(150)
- return
-
-/obj/machinery/door/blob_act()
- if(density) // If it's closed.
- if(machine_stat & BROKEN)
- spawn(0)
- open(1)
- else
- take_damage(100)
-
/obj/machinery/door/update_icon()
if(density)
icon_state = "door1"
@@ -479,7 +401,7 @@
/obj/machinery/door/proc/update_heat_protection(var/turf/simulated/source)
if(istype(source))
- if(src.density && (src.opacity || src.heat_proof))
+ if(src.density && (src.opacity || (heat_resistance > initial(heat_resistance))))
source.thermal_conductivity = DOOR_HEAT_TRANSFER_COEFFICIENT
else
source.thermal_conductivity = initial(source.thermal_conductivity)
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/door_timer.dm
similarity index 99%
rename from code/game/machinery/doors/brigdoors.dm
rename to code/game/machinery/doors/door_timer.dm
index cf0ee676204..6b85947e5c2 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/door_timer.dm
@@ -24,6 +24,8 @@
req_access = list(ACCESS_SECURITY_BRIG)
anchored = TRUE //Can't pick it up
density = FALSE //Can walk through it.
+ // todo: temporary, as this is unbuildable
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE
var/id = null //Id of door it controls.
var/activation_time = 0
diff --git a/code/game/machinery/doors/door_vr.dm b/code/game/machinery/doors/door_vr.dm
index 3d92964373e..e2d1eae616f 100644
--- a/code/game/machinery/doors/door_vr.dm
+++ b/code/game/machinery/doors/door_vr.dm
@@ -1,48 +1,11 @@
-/turf/simulated/floor/proc/adjacent_fire_act_vr(turf/simulated/floor/adj_turf, datum/gas_mixture/adj_air, adj_temp, adj_volume)
- for(var/obj/machinery/door/D in src) //makes doors next to fire affected by fire
- D.fire_act(adj_air, adj_temp, adj_volume)
-
-/obj/machinery/door
- var/reinforcing = 0
- var/tintable = 0
- var/icon_tinted
- var/id_tint
-
-/obj/machinery/door/firedoor
- heat_proof = 1
-
-/obj/machinery/door/airlock/vault
- heat_proof = 1
-
-/obj/machinery/door/airlock/hatch
- heat_proof = 1
-
-/obj/machinery/door/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- var/maxtemperature = 1800 //same as a normal steel wall
- var/destroytime = 20 //effectively gives an airlock 200HP between breaking and completely disintegrating
- if(heat_proof)
- maxtemperature = 6000 //same as a plasteel rwall
- destroytime = 50 //fireproof airlocks need to take 500 damage after breaking before they're destroyed
-
- if(exposed_temperature > maxtemperature)
- var/burndamage = log(RAND_F(0.9, 1.1) * (exposed_temperature - maxtemperature))
- if (burndamage && health <= 0) //once they break, start taking damage to destroy_hits
- destroy_hits -= (burndamage / destroytime)
- if (destroy_hits <= 0)
- visible_message("\The [src.name] disintegrates!")
- new /obj/effect/debris/cleanable/ash(src.loc) // Turn it to ashes!
- qdel(src)
- take_damage(burndamage)
-
- return ..()
// Returns true only if one of the actions unique to reinforcing is done, otherwise false and continuing normal attackby
-/obj/machinery/door/proc/attackby_vr(obj/item/I as obj, mob/user as mob)
- if(istype(I, /obj/item/stack/material) && I.get_material_name() == "plasteel")
- if(heat_proof)
+/obj/machinery/door/proc/attackby_vr(obj/item/I, mob/living/user, list/params, clickchain_flags, damage_multiplier)
+ if(I.is_material_stack_of(/datum/material/plasteel))
+ if(heat_resistance > initial(heat_resistance))
to_chat(user, "\The [src] is already reinforced.")
return TRUE
- if((machine_stat & BROKEN) || (health < maxhealth))
+ if(machine_stat & BROKEN)
to_chat(user, "It looks like \the [src] broken. Repair it before reinforcing it.")
return TRUE
if(!density)
@@ -84,7 +47,7 @@
playsound(src, welder.tool_sound, 50, 1)
if(do_after(user, 10 * welder.tool_speed) && welder && welder.isOn())
to_chat(user, "You finish reinforcing \the [src].")
- heat_proof = 1
+ heat_resistance = 6000
update_icon()
reinforcing = 0
return TRUE
@@ -99,12 +62,6 @@
return FALSE
-/obj/machinery/door/blast/regular/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- return // blast doors are immune to fire completely.
-
-/obj/machinery/door/blast/regular/
- heat_proof = 1 //just so repairing them doesn't try to fireproof something that never takes fire damage
-
/obj/machinery/door/proc/toggle()
if(glass)
icon = icon_tinted
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 140ddfb3b07..fff8d5df947 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -34,6 +34,7 @@ GLOBAL_LIST_INIT(firelock_align_types, typecacheof(list(
open_layer = DOOR_OPEN_LAYER - 0.01// Just below doors when open
closed_layer = MID_LANDMARK_LAYER // Need this to be above windows/grilles/low walls.
smoothing_groups = (SMOOTH_GROUP_SHUTTERS_BLASTDOORS)
+ heat_resistance = 6000
//These are frequenly used with windows, so make sure zones can pass.
//Generally if a firedoor is at a place where there should be a zone boundery then there will be a regular door underneath it.
@@ -94,9 +95,6 @@ GLOBAL_LIST_INIT(firelock_align_types, typecacheof(list(
LAZYREMOVE(A.all_doors, src)
return ..()
-/obj/machinery/door/firedoor/get_material()
- return get_material_by_name(MAT_STEEL)
-
/obj/machinery/door/firedoor/examine(mob/user, dist)
. = ..()
if(!density)
@@ -238,7 +236,7 @@ GLOBAL_LIST_INIT(firelock_align_types, typecacheof(list(
/obj/machinery/door/firedoor/attack_generic(var/mob/living/user, var/damage)
if(machine_stat & (BROKEN|NOPOWER))
- if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
+ if(damage >= 5)
var/time_to_force = (2 + (2 * blocked)) * 5
if(src.density)
visible_message("\The [user] starts forcing \the [src] open!")
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index b9e7642afa4..8ca397229d7 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -4,11 +4,11 @@
icon = 'icons/obj/doors/windoor.dmi'
icon_state = "left"
pass_flags_self = ATOM_PASS_GLASS
+ armor_type = /datum/armor/door/windoor
var/base_state = "left"
- min_force = 4
- hitsound = 'sound/effects/Glasshit.ogg'
- maxhealth = 150 //If you change this, consiter changing ../door/window/brigdoor/ health at the bottom of this .dm file
- health = 150
+ hit_sound_brute = 'sound/effects/Glasshit.ogg'
+ integrity = 140
+ integrity_max = 140
visible = 0.0
use_power = USE_POWER_OFF
atom_flags = ATOM_BORDER
@@ -142,28 +142,14 @@
operating = FALSE
return TRUE
-/obj/machinery/door/window/take_damage(var/damage)
- src.health = max(0, src.health - damage)
- if (src.health <= 0)
- shatter()
- return
-
/obj/machinery/door/window/attack_ai(mob/user as mob)
return src.attack_hand(user)
/obj/machinery/door/window/attack_hand(mob/user, list/params)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
src.add_fingerprint(user)
- if(istype(user,/mob/living/carbon/human))
- var/mob/living/carbon/human/H = user
- if(H.species.can_shred(H))
- playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
- visible_message("[user] smashes against the [src.name].", 1)
- user.do_attack_animation(src)
- user.setClickCooldown(user.get_attack_speed())
- take_damage(25)
- return
-
if (src.allowed(user))
if (src.density)
open()
@@ -183,7 +169,9 @@
open()
return 1
-/obj/machinery/door/window/attackby(obj/item/I as obj, mob/user as mob)
+/obj/machinery/door/window/attackby(obj/item/I, mob/living/user, list/params, clickchain_flags, damage_multiplier)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
//If it's in the process of opening/closing, ignore the click
if (src.operating == 1)
@@ -193,12 +181,12 @@
// Fixing.
if(istype(I, /obj/item/weldingtool) && user.a_intent == INTENT_HELP)
var/obj/item/weldingtool/WT = I
- if(health < maxhealth)
+ if(integrity < integrity_max)
if(WT.remove_fuel(1 ,user))
to_chat(user, "You begin repairing [src]...")
playsound(src, WT.tool_sound, 50, 1)
if(do_after(user, 40 * WT.tool_speed, target = src))
- health = maxhealth
+ set_integrity(integrity_max)
update_icon()
to_chat(user, "You repair [src].")
else
@@ -251,17 +239,6 @@
qdel(src)
return
- //If it's a weapon, smash windoor. Unless it's an id card, agent card, ect.. then ignore it (Cards really shouldnt damage a door anyway)
- if(src.density && istype(I, /obj/item) && !istype(I, /obj/item/card))
- user.setClickCooldown(user.get_attack_speed(I))
- var/aforce = I.damage_force
- playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
- visible_message("[src] was hit by [I].")
- if(I.damtype == BRUTE || I.damtype == BURN)
- take_damage(aforce)
- return
-
-
src.add_fingerprint(user, 0, I)
if (src.allowed(user))
@@ -281,9 +258,10 @@
icon_state = "leftsecure"
base_state = "leftsecure"
req_access = list(ACCESS_SECURITY_EQUIPMENT)
+ armor_type = /datum/armor/door/windoor/reinforced
+ integrity = 280
+ integrity_max = 280
var/id = null
- maxhealth = 300
- health = 300.0 //Stronger doors for prison (regular window door health is 150)
/obj/machinery/door/window/brigdoor/shatter()
new /obj/item/stack/rods(src.loc, 2)
diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm
index 968b162ddfe..49b686f3c81 100644
--- a/code/game/machinery/embedded_controller/embedded_controller_base.dm
+++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm
@@ -67,8 +67,8 @@
icon = 'icons/obj/airlock_machines.dmi'
icon_state = "airlock_control_standby"
power_channel = ENVIRON
- density = 0
- unacidable = 1
+ density = FALSE
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE
var/id_tag
//var/radio_power_use = 50 //power used to xmit signals
diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm
index 60f87f259ad..4e7298ec91f 100644
--- a/code/game/machinery/fire_alarm.dm
+++ b/code/game/machinery/fire_alarm.dm
@@ -298,7 +298,7 @@ Just a object used in constructing fire alarms
icon_state = "door_electronics"
desc = "A circuit. It has a label on it, it says \"Can handle heat levels up to 40 degrees celsius!\""
w_class = ITEMSIZE_SMALL
- materials = list(MAT_STEEL = 50, MAT_GLASS = 50)
+ materials_base = list(MAT_STEEL = 50, MAT_GLASS = 50)
*/
/obj/machinery/partyalarm
name = "\improper PARTY BUTTON"
diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm
index 1644ad5ddcf..347e1a84ec9 100644
--- a/code/game/machinery/flasher.dm
+++ b/code/game/machinery/flasher.dm
@@ -13,6 +13,8 @@
anchored = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 2
+ // todo: temporary, as this is unbuildable
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE
/obj/machinery/flasher/portable //Portable version of the flasher. Only flashes when anchored
name = "portable flasher"
diff --git a/code/game/machinery/floor_light.dm b/code/game/machinery/floor_light.dm
index 54145073c6c..b9c0494b8b4 100644
--- a/code/game/machinery/floor_light.dm
+++ b/code/game/machinery/floor_light.dm
@@ -11,7 +11,7 @@ var/list/floor_light_cache = list()
idle_power_usage = 2
active_power_usage = 20
power_channel = LIGHT
- materials = list(MAT_STEEL = 2500, MAT_GLASS = 2750)
+ materials_base = list(MAT_STEEL = 2500, MAT_GLASS = 2750)
var/on
var/damaged
diff --git a/code/game/machinery/lathes/autolathe.dm b/code/game/machinery/lathes/autolathe.dm
index db2b02479d6..a5326de9833 100644
--- a/code/game/machinery/lathes/autolathe.dm
+++ b/code/game/machinery/lathes/autolathe.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
/obj/item/circuitboard/machine/lathe/autolathe
name = T_BOARD("autolathe")
build_path = /obj/machinery/lathe/autolathe
diff --git a/code/game/machinery/lathes/lathe.dm b/code/game/machinery/lathes/lathe.dm
index 11d76aa7cf4..458d959da61 100644
--- a/code/game/machinery/lathes/lathe.dm
+++ b/code/game/machinery/lathes/lathe.dm
@@ -1,3 +1,6 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2023 Citadel Station developers. *//
+
/obj/item/circuitboard/machine/lathe
abstract_type = /obj/item/circuitboard/machine/lathe
name = T_BOARD("lathe")
@@ -220,7 +223,7 @@
/obj/machinery/lathe/proc/recycle_item(obj/item/I, mob/user, efficiency_multiplier = 1)
efficiency_multiplier *= recycle_efficiency
- var/list/materials = I.materials.Copy()
+ var/list/materials = I.materials_base.Copy()
if(!isnull(user) && !user.temporarily_remove_from_inventory(I))
user.action_feedback(SPAN_WARNING("[I] is stuck to your hand!"), src)
return FALSE
@@ -280,11 +283,11 @@
*/
/obj/machinery/lathe/proc/has_resources_for(datum/design/instance, list/material_parts, list/ingredient_parts)
. = INFINITY
- if(length(instance.materials))
- var/list/materials = instance.materials.Copy()
- for(var/key in instance.material_parts)
+ if(length(instance.materials_base))
+ var/list/materials = instance.materials_base.Copy()
+ for(var/key in instance.material_costs)
var/id = material_parts[key]
- materials[id] += instance.material_parts[key]
+ materials[id] += instance.material_costs[key]
. = stored_materials.has_multiple(materials, efficiency_multiplier)
if(!.)
return
@@ -343,9 +346,9 @@
/obj/machinery/lathe/proc/do_print(datum/design/instance, amount = 1, list/material_parts, list/ingredient_parts, efficiency = efficiency_multiplier)
if(!amount)
return
- var/list/materials_used = instance.materials?.Copy() || list()
+ var/list/materials_used = instance.materials_base?.Copy() || list()
for(var/key in material_parts)
- materials_used[material_parts[key]] += instance.material_parts[key]
+ materials_used[material_parts[key]] += instance.material_costs[key]
use_resources(materials_used, instance.reagents, instance.ingredients, ingredient_parts, amount * efficiency)
. = instance.lathe_print(drop_location(), amount, material_parts, ingredient_parts, null, src, efficiency_multiplier)
if(!isnull(print_icon_state))
@@ -482,8 +485,8 @@
* amount variable is reserved but unused at this given time.
*/
/obj/machinery/lathe/proc/enqueue(datum/design/instance, amount = 1, list/material_parts, list/ingredient_parts, start_immediately)
- if(instance.material_parts)
- for(var/key in instance.material_parts)
+ if(!isnull(instance.material_costs))
+ for(var/key in instance.material_costs)
if(!material_parts[key])
return FALSE
var/datum/lathe_queue_entry/last = length(queue)? queue[length(queue)] : null
diff --git a/code/game/machinery/pipe/pipelayer.dm b/code/game/machinery/pipe/pipelayer.dm
deleted file mode 100644
index c6303fa7eb3..00000000000
--- a/code/game/machinery/pipe/pipelayer.dm
+++ /dev/null
@@ -1,180 +0,0 @@
-/obj/machinery/pipelayer
- name = "automatic pipe layer"
- icon = 'icons/obj/stationobjs.dmi'
- icon_state = "pipe_d"
- density = 1
- circuit = /obj/item/circuitboard/pipelayer
- var/turf/old_turf // Last turf we were on.
- var/old_dir // Last direction we were facing.
- var/on = 0 // Pipelaying online?
- var/a_dis = 0 // Auto-dismantling - If enabled it will remove floor tiles
- var/P_type = null // Currently selected pipe type
- var/P_type_t = "" // Name of currently selected pipe type
- var/max_metal = 50 // Max capacity for internal metal storage
- var/metal = 0 // Current amount in internal metal storage
- var/pipe_cost = 0.25 // Cost in steel for each pipe.
- var/obj/item/tool/wrench/W // Internal wrench used for wrenching down the pipes
- var/list/Pipes = list(
- "regular pipes" = /obj/machinery/atmospherics/pipe/simple,
- "scrubbers pipes" = /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
- "supply pipes" = /obj/machinery/atmospherics/pipe/simple/hidden/supply,
- "heat exchange pipes" = /obj/machinery/atmospherics/pipe/simple/heat_exchanging
- )
-
-/obj/machinery/pipelayer/Initialize(mapload)
- . = ..()
- W = new(src)
- update_icon()
-
-/obj/machinery/pipelayer/Destroy()
- QDEL_NULL(W)
- . = ..()
-
-/obj/machinery/pipelayer/RefreshParts()
- var/mb_rating = 0
- for(var/obj/item/stock_parts/matter_bin/M in component_parts)
- mb_rating += M.rating
- max_metal = mb_rating * initial(max_metal)
-
-/obj/machinery/pipelayer/dismantle()
- eject_metal()
- ..()
-
-// Whenever we move, if enabled try and lay pipe
-/obj/machinery/pipelayer/Move(new_turf,M_Dir)
- ..()
-
- if(on && a_dis)
- dismantleFloor(old_turf)
- layPipe(old_turf, M_Dir, old_dir)
-
- old_turf = new_turf
- old_dir = turn(M_Dir, 180)
-
-/obj/machinery/pipelayer/attack_hand(mob/user, list/params)
- if(..())
- return
- if(panel_open)
- if(metal < 1)
- to_chat(user, "\The [src] is empty.")
- return
- var/answer = alert(user, "Do you want to eject all the metal in \the [src]?", , "Yes","No")
- if(answer == "Yes")
- var/amount_ejected = eject_metal()
- user.visible_message("[user] removes [amount_ejected] sheet\s of [MAT_STEEL] from the \the [src].",
- "You remove [amount_ejected] sheet\s of [MAT_STEEL] from \the [src].")
- return
- if(!metal && !on)
- to_chat(user, "\The [src] doesn't work without metal.")
- return
- on = !on
- old_turf = get_turf(src)
- old_dir = dir
- user.visible_message("[user] has [!on?"de":""]activated \the [src].", "You [!on?"de":""]activate \the [src].")
- return
-
-/obj/machinery/pipelayer/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if(default_deconstruction_screwdriver(user, W))
- return
- if(default_deconstruction_crowbar(user, W))
- return
- if(default_part_replacement(user, W))
- return
- if (!panel_open && W.is_wrench())
- P_type_t = input("Choose pipe type", "Pipe type") as null|anything in Pipes
- P_type = Pipes[P_type_t]
- user.visible_message("[user] has set \the [src] to manufacture [P_type_t].", "You set \the [src] to manufacture [P_type_t].")
- return
- if(!panel_open && W.is_crowbar())
- a_dis = !a_dis
- user.visible_message("[user] has [!a_dis?"de":""]activated auto-dismantling.", "You [!a_dis?"de":""]activate auto-dismantling.")
- return
- if(istype(W, /obj/item/pipe))
- // NOTE - We must check for matter, otherwise the (free) pipe dispenser can be used to get infinite steel.
- if(!W.materials || W.materials[MAT_STEEL] < pipe_cost * SHEET_MATERIAL_AMOUNT)
- to_chat(user, "\The [W] doesn't contain enough [MAT_STEEL] to recycle.")
- else if(metal + pipe_cost > max_metal)
- to_chat(user, "\The [src] is full.")
- else if(user.attempt_consume_item_for_construction(W))
- metal += pipe_cost
- to_chat(user, "You recycle \the [W].")
- return
- if(istype(W, /obj/item/stack/material) && W.get_material_name() == MAT_STEEL)
- var/result = load_metal(W)
- if(isnull(result))
- to_chat(user, "Unable to load [W] - no metal found.")
- else if(!result)
- to_chat(user, "\The [src] is full.")
- else
- user.visible_message("[user] has loaded metal into \the [src].", "You load metal into \the [src]")
- return
-
- ..()
-
-/obj/machinery/pipelayer/examine(mob/user, dist)
- . = ..()
- . += "The [src] has [metal] sheets, is set to produce [P_type_t], and auto-dismantling is [!a_dis?"de":""]activated."
-
-/obj/machinery/pipelayer/proc/reset()
- on = 0
- return
-
-/obj/machinery/pipelayer/proc/load_metal(var/obj/item/stack/MM)
- if(istype(MM) && MM.get_amount())
- var/cur_amount = metal
- var/to_load = max(max_metal - round(cur_amount),0)
- if(to_load)
- to_load = min(MM.get_amount(), to_load)
- metal += to_load
- MM.use(to_load)
- return to_load
- else
- return 0
- return
-
-/obj/machinery/pipelayer/proc/use_metal(amount)
- if(!metal || metal < amount)
- visible_message("\The [src] deactivates as its metal source depletes.")
- return
- metal -= amount
- return 1
-
-/obj/machinery/pipelayer/proc/eject_metal()
- var/amount_ejected = 0
- while (metal >= 1)
- var/datum/material/M = get_material_by_name(MAT_STEEL)
- var/obj/item/stack/material/S = new M.stack_type(get_turf(src))
- S.amount = min(metal, S.max_amount)
- metal -= S.amount
- amount_ejected += S.amount
- return amount_ejected
-
-/obj/machinery/pipelayer/proc/dismantleFloor(var/turf/new_turf)
- if(istype(new_turf, /turf/simulated/floor))
- var/turf/simulated/floor/T = new_turf
- if(!T.is_plating())
- T.make_plating(!(T.broken || T.burnt))
- return new_turf.is_plating()
-
-/obj/machinery/pipelayer/proc/layPipe(var/turf/w_turf,var/M_Dir,var/old_dir)
- if(!on || !(M_Dir in list(NORTH, SOUTH, EAST, WEST)) || M_Dir==old_dir)
- return reset()
- if(!use_metal(pipe_cost))
- return reset()
- var/fdirn = turn(M_Dir, 180)
- var/obj/machinery/atmospherics/p_type = P_type
- var/p_layer = initial(p_type.piping_layer)
- var/p_dir
- if (fdirn!=old_dir)
- p_dir=old_dir+M_Dir
- else
- p_dir=M_Dir
-
- var/pi_type = initial(p_type.construction_type)
- var/obj/item/pipe/P = new pi_type(w_turf, p_type, p_dir)
- P.setPipingLayer(p_layer)
- // We used metal to make these, so should be reclaimable!
- P.materials = list(MAT_STEEL = pipe_cost * SHEET_MATERIAL_AMOUNT)
- P.attackby(W , src)
-
- return 1
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index b4fdafc3c55..575ef55b6b3 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -50,14 +50,13 @@
power_channel = EQUIP
req_one_access = list(ACCESS_SECURITY_EQUIPMENT, ACCESS_COMMAND_BRIDGE)
+ integrity = 200
+ integrity_max = 200
+
/// If the turret cover is "open" and the turret is raised.
var/raised = FALSE
/// If the turret is currently opening or closing its cover.
var/raising= FALSE
- /// The turret's health.
- var/health = 80
- /// The turret's maximum health.
- var/maxhealth = 80
/// If the turret slowly repairs itself.
var/auto_repair = FALSE
/// If the turret's behaviour control access is locked.
@@ -167,8 +166,8 @@
desc = "This variant appears to be much more durable."
req_one_access = list(ACCESS_SPECIAL_SILICONS) // Just in case.
installation = /obj/item/gun/energy/xray // For the armor pen.
- health = 250 // Since lasers do 40 each.
- maxhealth = 250
+ integrity = 250 // Since lasers do 40 each.
+ integrity_max = 250
/datum/category_item/catalogue/anomalous/precursor_a/alien_turret
name = "Precursor Alpha Object - Turrets"
@@ -193,8 +192,8 @@
lethal = TRUE
ailock = TRUE
check_all = TRUE
- health = 250 // Similar to the AI turrets.
- maxhealth = 250
+ integrity = 250 // Similar to the AI turrets.
+ integrity_max = 250
turret_type = "alien"
/obj/machinery/porta_turret/alien/destroyed // Turrets that are already dead, to act as a warning of what the rest of the submap contains.
@@ -210,16 +209,12 @@
req_one_access = list(ACCESS_COMMAND_BRIDGE)
icon_state = "turret_cover_industrial"
installation = /obj/item/gun/energy/phasegun
- health = 200
- maxhealth = 200
+ integrity = 200
+ integrity_max = 200
turret_type = "industrial"
/obj/machinery/porta_turret/industrial/bullet_act(obj/projectile/Proj)
- var/damage = round(Proj.get_structure_damage() * 1.33)
-
- if(!damage)
- return
-
+ . = ..()
if(enabled)
if(!attacked && !emagged)
attacked = TRUE
@@ -227,8 +222,6 @@
sleep(60)
attacked = FALSE
- take_damage(damage)
-
/obj/machinery/porta_turret/industrial/attack_generic(mob/living/L, damage)
return ..(L, damage * 0.8)
@@ -237,8 +230,8 @@
desc = "This variant appears to be much more durable, with a rugged outer coating."
req_one_access = list(ACCESS_COMMAND_BRIDGE)
installation = /obj/item/gun/energy/gun/burst
- health = 250
- maxhealth = 250
+ integrity = 250
+ integrity_max = 250
/obj/machinery/porta_turret/poi //These are always angry
enabled = TRUE
@@ -603,30 +596,8 @@
else
to_chat(user, "Access denied.")
- else
- //if the turret was attacked with the intention of harming it:
- user.setClickCooldown(user.get_attack_speed(I))
- take_damage(I.damage_force * 0.5)
- if(I.damage_force * 0.5 > 1) //if the force of impact dealt at least 1 damage, the turret gets pissed off
- if(!attacked && !emagged)
- attacked = 1
- spawn()
- sleep(60)
- attacked = 0
..()
-/obj/machinery/porta_turret/attack_generic(mob/living/L, damage)
- if(isanimal(L))
- var/mob/living/simple_mob/S = L
- if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
- var/incoming_damage = round(damage - (damage / 5)) //Turrets are slightly armored, assumedly.
- visible_message("\The [S] [pick(S.attacktext)] \the [src]!")
- take_damage(incoming_damage)
- S.do_attack_animation(src)
- return 1
- visible_message("\The [L] bonks \the [src]'s casing!")
- return ..()
-
/obj/machinery/porta_turret/emag_act(remaining_charges, mob/user)
if(!emagged)
//Emagging the turret makes it go bonkers and stun everyone. It also makes
@@ -640,34 +611,19 @@
enabled = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
return 1
-/obj/machinery/porta_turret/take_damage(force)
- if(!raised && !raising)
- force = force / 8
- if(force < 5)
- return
-
- health -= force
- if(force > 5 && prob(45))
+/obj/machinery/porta_turret/damage_integrity(amount, gradual, do_not_break)
+ . = ..()
+ if(!gradual && prob(45) && amount > 5)
spark_system.start()
- if(health <= 0)
- die() //the death process :(
-/obj/machinery/porta_turret/bullet_act(obj/projectile/Proj)
- var/damage = Proj.get_structure_damage()
+/obj/machinery/porta_turret/bullet_act(obj/projectile/P, def_zone)
+ aggro_for(6 SECONDS)
+ return ..()
- if(!damage)
- return
-
- if(enabled)
- if(!attacked && !emagged)
- attacked = 1
- spawn()
- sleep(60)
- attacked = FALSE
-
- ..()
-
- take_damage(damage)
+/obj/machinery/porta_turret/melee_act(mob/user, obj/item/weapon, target_zone, mult)
+ . = ..()
+ if(. > 0)
+ aggro_for(6 SECONDS, user)
/obj/machinery/porta_turret/emp_act(severity)
if(enabled)
@@ -701,21 +657,8 @@
if(!enabled)
enabled = TRUE
-/obj/machinery/porta_turret/legacy_ex_act(severity)
- switch (severity)
- if(1)
- qdel(src)
- if(2)
- if(prob(25))
- qdel(src)
- else
- take_damage(initial(health) * 8) //should instakill most turrets
- if(3)
- take_damage(initial(health) * 8 / 3) //Level 4 is too weak to bother turrets
-
-/obj/machinery/porta_turret/proc/die() //called when the turret dies, ie, health <= 0
- health = 0
- machine_stat |= BROKEN //enables the BROKEN bit
+/obj/machinery/porta_turret/atom_break()
+ . = ..()
spark_system.start() //creates some sparks because they look cool
update_icon()
@@ -745,9 +688,9 @@
spawn()
popDown() // no valid targets, close the cover
- if(auto_repair && (health < maxhealth))
+ if(auto_repair && (integrity < integrity_max))
use_power(20000)
- health = min(health+1, maxhealth) // 1HP for 20kJ
+ heal_integrity(1)
/obj/machinery/porta_turret/proc/assess_and_assign(mob/living/L, list/targets, list/secondarytargets)
switch(assess_living(L))
@@ -937,6 +880,11 @@
// Reset the time needed to go back down, since we just tried to shoot at someone.
timeout = 10
+/obj/machinery/porta_turret/proc/aggro_for(seconds, mob/aggressor)
+ timeout = round(seconds / 2)
+ spawn(-1)
+ popUp()
+
/datum/turret_checks
var/enabled
var/lethal
@@ -1007,7 +955,7 @@
return
if(1)
- if(istype(I, /obj/item/stack/material) && I.get_material_name() == MAT_STEEL)
+ if(I.is_material_stack_of(/datum/material/steel))
var/obj/item/stack/M = I
if(M.use(2))
to_chat(user, "You add some metal armor to the interior frame.")
@@ -1087,7 +1035,7 @@
//attack_hand() removes the prox sensor
if(6)
- if(istype(I, /obj/item/stack/material) && I.get_material_name() == MAT_STEEL)
+ if(I.is_material_stack_of(/datum/material/steel))
var/obj/item/stack/M = I
if(M.use(2))
to_chat(user, "You add some metal armor to the exterior frame.")
diff --git a/code/game/machinery/robot_fabricator.dm b/code/game/machinery/robot_fabricator.dm
deleted file mode 100644
index ec663130891..00000000000
--- a/code/game/machinery/robot_fabricator.dm
+++ /dev/null
@@ -1,137 +0,0 @@
-/obj/machinery/robotic_fabricator //Does this stille even need to exist?
- name = "robotic fabricator"
- icon = 'icons/obj/machines/fabricators/robotics.dmi'
- icon_state = "mechfab"
- density = TRUE
- anchored = TRUE
- var/metal_amount = NONE
- var/operating = FALSE
- var/obj/item/robot_parts/being_built = null
- use_power = USE_POWER_IDLE
- idle_power_usage = 40
- active_power_usage = 10000
-
-/obj/machinery/robotic_fabricator/attackby(var/obj/item/O as obj, var/mob/user as mob)
- if(istype(O, /obj/item/stack/material) && O.get_material_name() == MAT_STEEL)
- var/obj/item/stack/M = O
- if(metal_amount < 150000.0)
- var/count = 0
- add_overlay("[base_icon_state]-load-metal")
- spawn(15)
- if(M)
- if(!M.get_amount())
- return
- while(metal_amount < 150000 && M.amount)
- metal_amount += O.materials[MAT_STEEL] /*O:height * O:width * O:length * 100000.0*/
- M.use(1)
- count++
-
- to_chat(user, "You insert [count] metal sheet\s into the fabricator.")
- cut_overlay("[base_icon_state]-load-metal")
- updateDialog()
- else
- to_chat(user, "The robot part maker is full. Please remove metal from the robot part maker in order to insert more.")
-
-/obj/machinery/robotic_fabricator/attack_hand(mob/user, list/params)
- var/dat
- if(..())
- return
-
- if(operating)
- dat = {"
-Building [being_built.name].
-Please wait until completion...
-
-"}
- else
- dat = {"
-Metal Amount: [min(150000, metal_amount)] cm3 (MAX: 150,000)
-
-Left Arm (25,000 cc metal.)
-Right Arm (25,000 cc metal.)
-Left Leg (25,000 cc metal.)
-Right Leg (25,000 cc metal).
-Chest (50,000 cc metal).
-Head (50,000 cc metal).
-Robot Frame (75,000 cc metal).
-"}
-
- user << browse("Robotic Fabricator Control Panel[dat]", "window=robot_fabricator")
- onclose(user, "robot_fabricator")
- return
-
-/obj/machinery/robotic_fabricator/Topic(href, href_list)
- if(..())
- return
-
- usr.set_machine(src)
-
- if(href_list["make"])
- if(!operating)
- var/part_type = text2num(href_list["make"])
-
- var/build_type = ""
- var/build_time = 200
- var/build_cost = 25000
-
- switch (part_type)
- if(1)
- build_type = "/obj/item/robot_parts/l_arm"
- build_time = 200
- build_cost = 25000
-
- if(2)
- build_type = "/obj/item/robot_parts/r_arm"
- build_time = 200
- build_cost = 25000
-
- if(3)
- build_type = "/obj/item/robot_parts/l_leg"
- build_time = 200
- build_cost = 25000
-
- if(4)
- build_type = "/obj/item/robot_parts/r_leg"
- build_time = 200
- build_cost = 25000
-
- if(5)
- build_type = "/obj/item/robot_parts/chest"
- build_time = 350
- build_cost = 50000
-
- if(6)
- build_type = "/obj/item/robot_parts/head"
- build_time = 350
- build_cost = 50000
-
- if(7)
- build_type = "/obj/item/robot_parts/robot_suit"
- build_time = 600
- build_cost = 75000
-
- var/building = text2path(build_type)
- if(!isnull(building))
- if(metal_amount >= build_cost)
- operating = 1
- update_use_power(USE_POWER_ACTIVE)
-
- metal_amount = max(0, metal_amount - build_cost)
-
- being_built = new building(src)
-
- add_overlay("[base_icon_state]-active")
- updateUsrDialog()
-
- spawn (build_time)
- if(!isnull(being_built))
- being_built.loc = get_turf(src)
- being_built = null
- update_use_power(USE_POWER_IDLE)
- operating = 0
- cut_overlay("[base_icon_state]-active")
- return
-
- for (var/mob/M in viewers(1, src))
- if(M.client && M.machine == src)
- attack_hand(M)
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 91c73bfd8ae..f69d02142a7 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -8,6 +8,8 @@
icon_state = "generic"
anchored = TRUE
density = TRUE
+ // todo: temporary, as this is unbuildable
+ integrity_flags = INTEGRITY_INDESTRUCTIBLE
//! ## Icons
/// Icon_state when vending.
diff --git a/code/game/machinery/virtual_reality/ar_console.dm b/code/game/machinery/virtual_reality/ar_console.dm
index 7f5f2ee44bc..4b709393de5 100644
--- a/code/game/machinery/virtual_reality/ar_console.dm
+++ b/code/game/machinery/virtual_reality/ar_console.dm
@@ -35,7 +35,7 @@
add_fingerprint(user)
if(occupant && (istype(I, /obj/item/healthanalyzer) || istype(I, /obj/item/robotanalyzer)))
- I.melee_attack_chain(occupant, user)
+ I.melee_interaction_chain(occupant, user)
return
/obj/machinery/vr_sleeper/alien/eject()
diff --git a/code/game/machinery/virtual_reality/vr_console.dm b/code/game/machinery/virtual_reality/vr_console.dm
index af3c6e3cd98..44341a10dd4 100644
--- a/code/game/machinery/virtual_reality/vr_console.dm
+++ b/code/game/machinery/virtual_reality/vr_console.dm
@@ -72,7 +72,7 @@
add_fingerprint(user)
if(occupant && (istype(I, /obj/item/healthanalyzer) || istype(I, /obj/item/robotanalyzer)))
- I.melee_attack_chain(occupant, user)
+ I.melee_interaction_chain(occupant, user)
return
if(default_deconstruction_screwdriver(user, I))
diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm
index 6b042ee87a7..b5605ff0033 100644
--- a/code/game/mecha/combat/combat.dm
+++ b/code/game/mecha/combat/combat.dm
@@ -57,7 +57,7 @@
*/
if(ishuman(T))
var/mob/living/carbon/human/H = T
- // if (M.health <= 0) return
+ // if (M.integrity <= 0) return
var/obj/item/organ/external/temp = H.get_organ(pick(BP_TORSO, BP_TORSO, BP_TORSO, BP_HEAD))
if(temp)
@@ -119,9 +119,9 @@
playsound(src, 'sound/weapons/heavysmash.ogg', 50, 1)
if(istype(T, /obj/structure/girder))
- T:take_damage(force * 3) //Girders have 200 health by default. Steel, non-reinforced walls take four punches, girders take (with this value-mod) two, girders took five without.
+ T:take_damage_legacy(force * 3) //Girders have 200 integrity by default. Steel, non-reinforced walls take four punches, girders take (with this value-mod) two, girders took five without.
else
- T:take_damage(force)
+ T:take_damage_legacy(force)
melee_can_hit = 0
diff --git a/code/game/mecha/combat/durand.dm b/code/game/mecha/combat/durand.dm
index bc437ca08f4..decbf331831 100644
--- a/code/game/mecha/combat/durand.dm
+++ b/code/game/mecha/combat/durand.dm
@@ -5,8 +5,8 @@
initial_icon = "durand"
step_in = 4
dir_in = 1 //Facing North.
- health = 300
- maxhealth = 300 //Don't forget to update the /old variant if you change this number.
+ integrity = 300
+ integrity_max = 300 //Don't forget to update the /old variant if you change this number.
deflect_chance = 20
damage_absorption = list("brute"=0.5,"fire"=1.1,"bullet"=0.65,"laser"=0.85,"energy"=0.9,"bomb"=0.8)
max_temperature = 30000
@@ -83,6 +83,6 @@
/obj/mecha/combat/durand/old/Initialize(mapload)
. = ..()
- health = 25
- maxhealth = 250 //Just slightly worse.
+ integrity = 25
+ integrity_max = 250 //Just slightly worse.
cell.charge = rand(0, (cell.charge/2))
diff --git a/code/game/mecha/combat/fighter.dm b/code/game/mecha/combat/fighter.dm
index 6e3b1636964..37632c88b46 100644
--- a/code/game/mecha/combat/fighter.dm
+++ b/code/game/mecha/combat/fighter.dm
@@ -17,8 +17,8 @@
step_in = 2 //Fast
- health = 400
- maxhealth = 400
+ integrity = 400
+ integrity_max = 400
infra_luminosity = 6
@@ -181,7 +181,7 @@
stop_hover()
else if(moved && gravity && !ground_capable)
occupant_message("Collision alert! Vehicle not rated for use in gravity!")
- take_damage(NOGRAV_FIGHTER_DAMAGE, "brute")
+ take_damage_legacy(NOGRAV_FIGHTER_DAMAGE, "brute")
playsound(src, 'sound/effects/grillehit.ogg', 50, 1)
/obj/mecha/combat/fighter/get_step_delay()
@@ -241,7 +241,7 @@
if(istype(obstacle, /obj) || istype(obstacle, /turf))
TIMER_COOLDOWN_START(src, "fighter_collision", 5 SECONDS)
occupant_message("Collision Alert!")
- take_damage(20, "brute")
+ take_damage_legacy(20, "brute")
playsound(src, 'sound/effects/grillehit.ogg', 50, 1)
////////////// Gunpod //////////////
@@ -387,8 +387,8 @@
step_in = 3 //slightly slower than a baron (this shit doesnt actually work atm, likely due to the whole equipment weight nonsense)
- health = 800
- maxhealth = 800 //double baron HP, only room for one defensive upgrade. No specials(cloaking, speed, ect) or universals.
+ integrity = 800
+ integrity_max = 800 //double baron HP, only room for one defensive upgrade. No specials(cloaking, speed, ect) or universals.
max_hull_equip = 1
max_weapon_equip = 4
@@ -516,8 +516,8 @@
ground_capable = FALSE
- health = 500
- maxhealth = 500
+ integrity = 500
+ integrity_max = 500
/obj/mecha/combat/fighter/allure/loaded/Initialize(mapload) //Loaded version with guns
. = ..()
@@ -604,8 +604,8 @@
icon_state = "cludge"
initial_icon = "cludge"
- health = 100
- maxhealth = 100
+ integrity = 100
+ integrity_max = 100
max_hull_equip = 0
max_weapon_equip = 0
diff --git a/code/game/mecha/combat/gorilla.dm b/code/game/mecha/combat/gorilla.dm
index cb21e192ff3..f2b3e884aff 100644
--- a/code/game/mecha/combat/gorilla.dm
+++ b/code/game/mecha/combat/gorilla.dm
@@ -7,8 +7,8 @@
initial_icon = "pzrmech"
pixel_x = -16
step_in = 10
- health = 5000
- maxhealth = 5000
+ integrity = 5000
+ integrity_max = 5000
opacity = 0 // Because there's big tall legs to look through. Also it looks fucky if this is set to 1.
deflect_chance = 50
damage_absorption = list("brute"=0.1,"fire"=0.8,"bullet"=0.1,"laser"=0.6,"energy"=0.7,"bomb"=0.7) //values show how much damage will pass through, not how much will be absorbed.
diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm
index 4ff9d1d023a..b60966bb52c 100644
--- a/code/game/mecha/combat/gygax.dm
+++ b/code/game/mecha/combat/gygax.dm
@@ -5,8 +5,8 @@
initial_icon = "gygax_adv"
step_in = 3
dir_in = 1 //Facing North.
- health = 250
- maxhealth = 250 //Don't forget to update the /old variant if you change this number.
+ integrity = 250
+ integrity_max = 250 //Don't forget to update the /old variant if you change this number.
deflect_chance = 15
damage_absorption = list("brute"=0.75,"fire"=1,"bullet"=0.8,"laser"=0.7,"energy"=0.85,"bomb"=1)
max_temperature = 25000
@@ -50,10 +50,10 @@
/obj/mecha/combat/gygax/dark
desc = "A lightweight exosuit used by paramilitary forces. A significantly upgraded Gygax security mech."
name = "Dark Gygax"
+ integrity = 400
+ integrity_max = 400
icon_state = "darkgygax_adv"
initial_icon = "darkgygax_adv"
- health = 400
- maxhealth = 400
deflect_chance = 25
damage_absorption = list("brute"=0.6,"fire"=0.8,"bullet"=0.6,"laser"=0.5,"energy"=0.65,"bomb"=0.8)
max_temperature = 45000
@@ -90,8 +90,8 @@
name = "Serenity"
icon_state = "medgax"
initial_icon = "medgax"
- health = 150
- maxhealth = 150
+ integrity = 150
+ integrity_max = 150
deflect_chance = 20
step_in = 2
damage_absorption = list("brute"=0.9,"fire"=1,"bullet"=0.9,"laser"=0.8,"energy"=0.9,"bomb"=1)
@@ -115,11 +115,11 @@
/obj/item/mecha_parts/component/electrical
)
- var/obj/item/clothing/glasses/hud/health/mech/hud
+ var/obj/item/clothing/glasses/hud/integrity/mech/hud
/obj/mecha/combat/gygax/serenity/Initialize(mapload)
. = ..()
- hud = new /obj/item/clothing/glasses/hud/health/mech(src)
+ hud = new /obj/item/clothing/glasses/hud/integrity/mech(src)
/obj/mecha/combat/gygax/serenity/moved_inside(var/mob/living/carbon/human/H as mob)
if(..())
@@ -147,6 +147,6 @@
/obj/mecha/combat/gygax/old/Initialize(mapload)
. = ..()
- health = 25
- maxhealth = 250 //Just slightly worse.
+ integrity = 25
+ integrity_max = 250 //Just slightly worse.
cell.charge = rand(0, (cell.charge/2))
diff --git a/code/game/mecha/combat/honker.dm b/code/game/mecha/combat/honker.dm
index 0002b79d2d6..b20cda16565 100644
--- a/code/game/mecha/combat/honker.dm
+++ b/code/game/mecha/combat/honker.dm
@@ -5,8 +5,8 @@
initial_icon = "honker"
step_in = 4
dir_in = 1 //Facing North.
- health = 250
- maxhealth = 250 //Don't forget to update the /old variant if you change this number.
+ integrity = 250
+ integrity_max = 250 //Don't forget to update the /old variant if you change this number.
deflect_chance = 15
damage_absorption = list("brute"=0.75,"fire"=1,"bullet"=0.8,"laser"=0.7,"energy"=0.85,"bomb"=1)
max_temperature = 25000
@@ -40,8 +40,8 @@
icon = 'icons/mecha/mecha_vr.dmi'
icon_state = "cluwne"
initial_icon = "cluwne"
- health = 400
- maxhealth = 400
+ integrity = 400
+ integrity_max = 400
deflect_chance = 25
damage_absorption = list("brute"=0.6,"fire"=0.8,"bullet"=0.6,"laser"=0.5,"energy"=0.65,"bomb"=0.8)
max_temperature = 45000
diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm
index 18d0298e367..20037644610 100644
--- a/code/game/mecha/combat/marauder.dm
+++ b/code/game/mecha/combat/marauder.dm
@@ -5,8 +5,8 @@
icon_state = "marauder"
initial_icon = "marauder"
step_in = 5
- health = 350
- maxhealth = 350 //Don't forget to update the /old variant if you change this number.
+ integrity = 350
+ integrity_max = 350 //Don't forget to update the /old variant if you change this number.
deflect_chance = 25
damage_absorption = list("brute"=0.5,"fire"=0.7,"bullet"=0.45,"laser"=0.6,"energy"=0.7,"bomb"=0.7)
max_temperature = 60000
@@ -55,7 +55,7 @@
initial_icon = "seraph"
operation_req_access = list(ACCESS_CENTCOM_ERT_LEAD)
step_in = 3
- health = 450
+ integrity = 450
wreckage = /obj/effect/decal/mecha_wreckage/seraph
internal_damage_threshold = 20
force = 55
@@ -146,6 +146,6 @@
/obj/mecha/combat/marauder/old/Initialize(mapload)
. = ..()
- health = 25
- maxhealth = 300 //Just slightly worse.
+ integrity = 25
+ integrity_max = 300 //Just slightly worse.
cell.charge = rand(0, (cell.charge/2))
diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm
index 2431e6f10db..800f035c0af 100644
--- a/code/game/mecha/combat/phazon.dm
+++ b/code/game/mecha/combat/phazon.dm
@@ -6,8 +6,8 @@
step_in = 1
dir_in = 1 //Facing North.
step_energy_drain = 3
- health = 200 //God this is low
- maxhealth = 200 //Don't forget to update the /old variant if you change this number.
+ integrity = 200 //God this is low
+ integrity_max = 200 //Don't forget to update the /old variant if you change this number.
deflect_chance = 30
damage_absorption = list("brute"=0.7,"fire"=0.7,"bullet"=0.7,"laser"=0.7,"energy"=0.7,"bomb"=0.7)
max_temperature = 25000
@@ -86,8 +86,8 @@
step_in = 1
dir_in = 1 //Facing North.
step_energy_drain = 3
- health = 350
- maxhealth = 350
+ integrity = 350
+ integrity_max = 350
deflect_chance = 30
damage_absorption = list("brute"=0.6,"fire"=0.7,"bullet"=0.7,"laser"=0.9,"energy"=0.7,"bomb"=0.5)
max_temperature = 10000
@@ -107,7 +107,7 @@
switch_dmg_type_possible = TRUE
cloak_possible = FALSE
-/obj/mecha/combat/phazon/janus/take_damage(amount, type="brute")
+/obj/mecha/combat/phazon/janus/take_damage_legacy(amount, type="brute")
..()
if(phasing)
phasing = FALSE
@@ -157,6 +157,6 @@
/obj/mecha/combat/phazon/old/Initialize(mapload)
. = ..()
- health = 25
- maxhealth = 150 //Just slightly worse.
+ integrity = 25
+ integrity_max = 150 //Just slightly worse.
cell.charge = rand(0, (cell.charge/2))
diff --git a/code/game/mecha/combat/reticent.dm b/code/game/mecha/combat/reticent.dm
index d28c26609ed..7e8aa2766b2 100644
--- a/code/game/mecha/combat/reticent.dm
+++ b/code/game/mecha/combat/reticent.dm
@@ -5,8 +5,8 @@
initial_icon = "reticent"
step_in = 3
dir_in = 1 //Facing North.
- health = 180
- maxhealth = 180 //Don't forget to update the /old variant if you change this number.
+ integrity = 180
+ integrity_max = 180 //Don't forget to update the /old variant if you change this number.
deflect_chance = 25
damage_absorption = list("brute"=1,"fire"=0.75,"bullet"=0.85,"laser"=0.8,"energy"=0.7,"bomb"=1)
max_temperature = 25000
@@ -42,8 +42,8 @@
desc = "The current flagship mecha of Le Rien. The Reticence trades some speed for durability, but remains formidable. It is not commercially available."
icon_state = "reticence"
initial_icon = "reticence"
- health = 350
- maxhealth = 350
+ integrity = 350
+ integrity_max = 350
deflect_chance = 40
damage_absorption = list("brute"=0.8,"fire"=0.6,"bullet"=0.5,"laser"=0.65,"energy"=0.6,"bomb"=0.8)
max_temperature = 45000
diff --git a/code/game/mecha/components/_component.dm b/code/game/mecha/components/_component.dm
index d8cf6367982..6421f0b779b 100644
--- a/code/game/mecha/components/_component.dm
+++ b/code/game/mecha/components/_component.dm
@@ -16,8 +16,8 @@
var/list/required_type = null // List, if it exists. Exosuits meant to use the component (Unique var changes / effects)
integrity = 100
- var/integrity_danger_mod = 0.5 // Multiplier for comparison to max_integrity before problems start.
- max_integrity = 100
+ var/integrity_danger_mod = 0.5 // Multiplier for comparison to integrity_max before problems start.
+ integrity_max = 100
var/step_delay = 0
@@ -27,7 +27,7 @@
/obj/item/mecha_parts/component/examine(mob/user, dist)
. = ..()
- var/show_integrity = round(integrity/max_integrity*100, 0.1)
+ var/show_integrity = round(integrity/integrity_max*100, 0.1)
switch(show_integrity)
if(85 to 100)
. += "It's fully intact."
@@ -44,7 +44,7 @@
/obj/item/mecha_parts/component/Initialize(mapload)
. = ..()
- integrity = max_integrity
+ integrity = integrity_max
if(start_damaged)
integrity = round(integrity * integrity_danger_mod)
@@ -61,17 +61,17 @@
severity = clamp(severity + emp_resistance, 1, 4)
- take_damage((4 - severity) * round(integrity * 0.1, 0.1))
+ damage_integrity((4 - severity) * round(integrity * 0.1, 0.1))
-/obj/item/mecha_parts/component/proc/adjust_integrity(var/amt = 0)
- integrity = clamp(integrity + amt, 0, max_integrity)
+/obj/item/mecha_parts/component/proc/adjust_integrity_mecha(var/amt = 0)
+ integrity = clamp(integrity + amt, 0, integrity_max)
return
/obj/item/mecha_parts/component/proc/damage_part(var/dam_amt = 0, var/type = BRUTE)
if(dam_amt <= 0)
return FALSE
- adjust_integrity(-1 * dam_amt)
+ adjust_integrity_mecha(-1 * dam_amt)
if(chassis && internal_damage_flag)
if(get_efficiency() < 0.5)
@@ -80,7 +80,7 @@
return TRUE
/obj/item/mecha_parts/component/proc/get_efficiency()
- var/integ_limit = round(max_integrity * integrity_danger_mod)
+ var/integ_limit = round(integrity_max * integrity_danger_mod)
if(integrity < integ_limit)
var/int_percent = round(integrity / integ_limit, 0.1)
@@ -109,7 +109,7 @@
chassis = target
if(internal_damage_flag)
- if(integrity > (max_integrity * integrity_danger_mod))
+ if(integrity > (integrity_max * integrity_danger_mod))
if(chassis.hasInternalDamage(internal_damage_flag))
chassis.clearInternalDamage(internal_damage_flag)
@@ -139,10 +139,10 @@
if(istype(W,/obj/item/stack/nanopaste))
var/obj/item/stack/nanopaste/NP = W
- if(integrity < max_integrity)
- while(integrity < max_integrity && NP)
+ if(integrity < integrity_max)
+ while(integrity < integrity_max && NP)
if(do_after(user, 1 SECOND, src) && NP.use(1))
- adjust_integrity(10)
+ adjust_integrity_mecha(10)
return
diff --git a/code/game/mecha/components/actuators.dm b/code/game/mecha/components/actuators.dm
index cbd7fa5b262..dadb8165b74 100644
--- a/code/game/mecha/components/actuators.dm
+++ b/code/game/mecha/components/actuators.dm
@@ -5,7 +5,7 @@
icon_state = "motor"
w_class = ITEMSIZE_HUGE
origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2)
- materials = list(MAT_STEEL = 2500, MAT_GLASS = 1200)
+ materials_base = list(MAT_STEEL = 2500, MAT_GLASS = 1200)
component_type = MECH_ACTUATOR
@@ -15,8 +15,8 @@
required_type = null // List, if it exists. Exosuits meant to use the component.
- integrity_danger_mod = 0.6 // Multiplier for comparison to max_integrity before problems start.
- max_integrity = 50
+ integrity_danger_mod = 0.6 // Multiplier for comparison to integrity_max before problems start.
+ integrity_max = 50
internal_damage_flag = MECHA_INT_CONTROL_LOST
@@ -33,6 +33,6 @@
emp_resistance = -1
integrity_danger_mod = 0.7
- max_integrity = 60
+ integrity_max = 60
strafing_multiplier = 1.2
diff --git a/code/game/mecha/components/armor.dm b/code/game/mecha/components/armor.dm
index cfe888c4515..3bddffb7c96 100644
--- a/code/game/mecha/components/armor.dm
+++ b/code/game/mecha/components/armor.dm
@@ -5,7 +5,7 @@
icon_state = "armor"
w_class = ITEMSIZE_HUGE
origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 2)
- materials = list(MAT_STEEL = 5000, MAT_GLASS = 1000)
+ materials_base = list(MAT_STEEL = 5000, MAT_GLASS = 1000)
component_type = MECH_ARMOR
@@ -15,8 +15,8 @@
required_type = null // List, if it exists. Exosuits meant to use the component.
- integrity_danger_mod = 0.4 // Multiplier for comparison to max_integrity before problems start.
- max_integrity = 120
+ integrity_danger_mod = 0.4 // Multiplier for comparison to integrity_max before problems start.
+ integrity_max = 120
internal_damage_flag = MECHA_INT_TEMP_CONTROL
@@ -42,7 +42,7 @@
name = "blast-resistant mecha plating"
step_delay = 2
- max_integrity = 80
+ integrity_max = 80
damage_absorption = list(
"brute"=0.8,
@@ -58,7 +58,7 @@
/obj/item/mecha_parts/component/armor/lightweight
name = "lightweight mecha plating"
- max_integrity = 50
+ integrity_max = 50
step_delay = 0
damage_absorption = list(
@@ -77,7 +77,7 @@
step_delay = 4
- max_integrity = 80
+ integrity_max = 80
minimum_penetration = 10
@@ -95,7 +95,7 @@
step_delay = 4
- max_integrity = 100
+ integrity_max = 100
emp_resistance = 2
@@ -131,7 +131,7 @@
step_delay = 3
- max_integrity = 100
+ integrity_max = 100
emp_resistance = 3
@@ -182,7 +182,7 @@
step_delay = 4
- max_integrity = 150
+ integrity_max = 150
emp_resistance = 3
diff --git a/code/game/mecha/components/electrical.dm b/code/game/mecha/components/electrical.dm
index 702ef86b4d2..7cc27d2c1b3 100644
--- a/code/game/mecha/components/electrical.dm
+++ b/code/game/mecha/components/electrical.dm
@@ -5,14 +5,14 @@
icon_state = "board"
w_class = ITEMSIZE_HUGE
origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2)
- materials = list(MAT_STEEL = 2500, MAT_GLASS = 1000)
+ materials_base = list(MAT_STEEL = 2500, MAT_GLASS = 1000)
component_type = MECH_ELECTRIC
emp_resistance = 1
integrity_danger_mod = 0.4
- max_integrity = 40
+ integrity_max = 40
step_delay = 0
@@ -26,7 +26,7 @@
name = "efficient mecha electrical harness"
emp_resistance = 0
- max_integrity = 30
+ integrity_max = 30
relative_size = 10
charge_cost_mod = 0.6
diff --git a/code/game/mecha/components/hull.dm b/code/game/mecha/components/hull.dm
index 1a936a02f23..4cddba40688 100644
--- a/code/game/mecha/components/hull.dm
+++ b/code/game/mecha/components/hull.dm
@@ -5,7 +5,7 @@
icon_state = "hull"
w_class = ITEMSIZE_HUGE
origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2)
- materials = list(MAT_STEEL = 3500, MAT_GLASS = 200)
+ materials_base = list(MAT_STEEL = 3500, MAT_GLASS = 200)
component_type = MECH_HULL
@@ -13,8 +13,8 @@
required_type = null // List, if it exists. Exosuits meant to use the component.
- integrity_danger_mod = 0.5 // Multiplier for comparison to max_integrity before problems start.
- max_integrity = 50
+ integrity_danger_mod = 0.5 // Multiplier for comparison to integrity_max before problems start.
+ integrity_max = 50
internal_damage_flag = MECHA_INT_FIRE
@@ -25,7 +25,7 @@
step_delay = 4
integrity_danger_mod = 0.3
- max_integrity = 100
+ integrity_max = 100
/obj/item/mecha_parts/component/hull/lightweight
name = "lightweight mecha hull"
diff --git a/code/game/mecha/components/lifesupport.dm b/code/game/mecha/components/lifesupport.dm
index 207647b9621..9afb3e3f542 100644
--- a/code/game/mecha/components/lifesupport.dm
+++ b/code/game/mecha/components/lifesupport.dm
@@ -5,14 +5,14 @@
icon_state = "lifesupport"
w_class = ITEMSIZE_HUGE
origin_tech = list(TECH_DATA = 2, TECH_ENGINEERING = 2)
- materials = list(MAT_STEEL = 1000, MAT_GLASS = 1500)
+ materials_base = list(MAT_STEEL = 1000, MAT_GLASS = 1500)
component_type = MECH_GAS
emp_resistance = 1
integrity_danger_mod = 0.4
- max_integrity = 40
+ integrity_max = 40
step_delay = 0
@@ -24,6 +24,6 @@
name = "reinforced mecha life-support"
emp_resistance = 2
- max_integrity = 80
+ integrity_max = 80
relative_size = 40
diff --git a/code/game/mecha/equipment/tools/armor_melee.dm b/code/game/mecha/equipment/tools/armor_melee.dm
index 95efab2c7f2..8b1fb25ef23 100644
--- a/code/game/mecha/equipment/tools/armor_melee.dm
+++ b/code/game/mecha/equipment/tools/armor_melee.dm
@@ -63,7 +63,7 @@
else
chassis.occupant_message("\The [user] hits [chassis] with [W].")
user.visible_message("\The [user] hits [chassis] with [W].", "You hit [src] with [W].")
- chassis.take_damage(round(W.damage_force*damage_coeff),W.damtype)
+ chassis.take_damage_legacy(round(W.damage_force*damage_coeff),W.damtype)
chassis.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
set_ready_state(0)
chassis.use_power(energy_drain)
diff --git a/code/game/mecha/equipment/tools/armor_ranged.dm b/code/game/mecha/equipment/tools/armor_ranged.dm
index be202e0133a..caae1a42ffc 100644
--- a/code/game/mecha/equipment/tools/armor_ranged.dm
+++ b/code/game/mecha/equipment/tools/armor_ranged.dm
@@ -80,7 +80,7 @@
chassis.visible_message("The [chassis.name] armor deflects the projectile")
chassis.log_append_to_last("Armor saved.")
else
- chassis.take_damage(round(Proj.damage*src.damage_coeff),Proj.damage_flag)
+ chassis.take_damage_legacy(round(Proj.damage*src.damage_coeff),Proj.damage_flag)
chassis.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
Proj.on_hit(chassis)
set_ready_state(0)
@@ -101,7 +101,7 @@
else if(istype(A, /obj))
var/obj/O = A
if(O.throw_force)
- chassis.take_damage(round(O.throw_force*damage_coeff))
+ chassis.take_damage_legacy(round(O.throw_force*damage_coeff))
chassis.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
set_ready_state(0)
chassis.use_power(energy_drain)
diff --git a/code/game/mecha/equipment/tools/drill.dm b/code/game/mecha/equipment/tools/drill.dm
index e7b264284cb..30439c66c15 100644
--- a/code/game/mecha/equipment/tools/drill.dm
+++ b/code/game/mecha/equipment/tools/drill.dm
@@ -9,10 +9,8 @@
required_type = list(/obj/mecha/working/ripley)
/obj/item/mecha_parts/mecha_equipment/tool/drill/action(atom/target)
- if(!action_checks(target)) return
- if(isobj(target))
- var/obj/target_obj = target
- if(!target_obj.vars.Find("unacidable") || target_obj.unacidable) return
+ if(!action_checks(target))
+ return
set_ready_state(0)
chassis.use_power(energy_drain)
chassis.visible_message("[chassis] starts to drill [target]", "You hear the drill.")
@@ -23,11 +21,11 @@
if(T == chassis.loc && src == chassis.selected)
if(istype(target, /turf/simulated/wall))
var/turf/simulated/wall/W = target
- if(W.reinf_material && !advanced)//R wall but no good drill
+ if(W.material_reinf && !advanced)//R wall but no good drill
occupant_message("[target] is too durable to drill through.")
return
- else if((W.reinf_material && advanced) || do_after_cooldown(target))//R wall with good drill
+ else if((W.material_reinf && advanced) || do_after_cooldown(target))//R wall with good drill
log_message("Drilled through [target]")
LEGACY_EX_ACT(target, 3, null)
else
@@ -96,10 +94,8 @@
required_type = list(/obj/mecha/working/ripley)
/obj/item/mecha_parts/mecha_equipment/tool/drill/bore/action(atom/target)
- if(!action_checks(target)) return
- if(isobj(target))
- var/obj/target_obj = target
- if(target_obj.unacidable) return
+ if(!action_checks(target))
+ return
set_ready_state(0)
chassis.use_power(energy_drain)
chassis.visible_message("[chassis] starts to bore into \the [target]", "You hear the bore.")
@@ -110,7 +106,7 @@
if(T == chassis.loc && src == chassis.selected)
if(istype(target, /turf/simulated/wall))
var/turf/simulated/wall/W = target
- if(W.reinf_material)
+ if(W.material_reinf)
occupant_message("[target] is too durable to bore through.")
else
log_message("Bored through [target]")
diff --git a/code/game/mecha/equipment/tools/powertool.dm b/code/game/mecha/equipment/tools/powertool.dm
index e78094e7e31..9c688b5a404 100644
--- a/code/game/mecha/equipment/tools/powertool.dm
+++ b/code/game/mecha/equipment/tools/powertool.dm
@@ -29,7 +29,7 @@
return FALSE
if(isliving(target))
- my_tool.melee_attack_chain(target, chassis.occupant, BP_TORSO)
+ my_tool.melee_interaction_chain(target, chassis.occupant, BP_TORSO)
target.attackby(my_tool,chassis.occupant)
diff --git a/code/game/mecha/equipment/tools/repair_droid.dm b/code/game/mecha/equipment/tools/repair_droid.dm
index 94373867ceb..3ad442b1bc8 100644
--- a/code/game/mecha/equipment/tools/repair_droid.dm
+++ b/code/game/mecha/equipment/tools/repair_droid.dm
@@ -86,18 +86,18 @@
var/obj/item/mecha_parts/component/AC = RD.chassis.internal_components[MECH_ARMOR]
var/obj/item/mecha_parts/component/HC = RD.chassis.internal_components[MECH_HULL]
- var/damaged_armor = AC.integrity < AC.max_integrity
+ var/damaged_armor = AC.integrity < AC.integrity_max
- var/damaged_hull = HC.integrity < HC.max_integrity
+ var/damaged_hull = HC.integrity < HC.integrity_max
- if(health_boost<0 || RD.chassis.health < initial(RD.chassis.health) || damaged_armor || damaged_hull)
- RD.chassis.health += min(health_boost, initial(RD.chassis.health)-RD.chassis.health)
+ if(health_boost<0 || RD.chassis.integrity < initial(RD.chassis.integrity) || damaged_armor || damaged_hull)
+ RD.chassis.integrity += min(health_boost, initial(RD.chassis.integrity)-RD.chassis.integrity)
if(AC)
- AC.adjust_integrity(round(health_boost * 0.5, 0.5))
+ AC.adjust_integrity_mecha(round(health_boost * 0.5, 0.5))
if(HC)
- HC.adjust_integrity(round(health_boost * 0.5, 0.5))
+ HC.adjust_integrity_mecha(round(health_boost * 0.5, 0.5))
repaired = 1
if(repaired)
diff --git a/code/game/mecha/equipment/tools/shield_omni.dm b/code/game/mecha/equipment/tools/shield_omni.dm
index 923f79cd7ac..092a627c9ac 100644
--- a/code/game/mecha/equipment/tools/shield_omni.dm
+++ b/code/game/mecha/equipment/tools/shield_omni.dm
@@ -104,4 +104,6 @@
if(!active && shield_health < shield_regen_amount)
my_mech.use_power(OMNI_SHIELD_DRAIN * 4)
+BLOCK_BYOND_BUG_2072419
+
#undef OMNI_SHIELD_DRAIN
diff --git a/code/game/mecha/equipment/tools/sleeper.dm b/code/game/mecha/equipment/tools/sleeper.dm
index c6dc5200aec..400e10c0839 100644
--- a/code/game/mecha/equipment/tools/sleeper.dm
+++ b/code/game/mecha/equipment/tools/sleeper.dm
@@ -99,7 +99,7 @@
if(output)
var/temp = ""
if(occupant)
- temp = "
\[Occupant: [occupant] (Health: [occupant.health]%)\]
View stats|Eject"
+ temp = "
\[Occupant: [occupant] (Health: [occupant.integrity]%)\]
View stats|Eject"
return "[output] [temp]"
return
@@ -156,7 +156,7 @@
t1 = "*dead*"
else
t1 = "Unknown"
- return {"Health: [occupant.health]% ([t1])
+ return {"Health: [occupant.integrity]% ([t1])
Core Temperature: [src.occupant.bodytemperature-T0C]°C ([src.occupant.bodytemperature*1.8-459.67]°F)
Brute Damage: [occupant.getBruteLoss()]%
Respiratory Damage: [occupant.getOxyLoss()]%
@@ -231,7 +231,7 @@
var/mob/living/carbon/M = S.occupant
if(!M)
return
- if(M.health > 0)
+ if(M.integrity > 0)
M.adjustOxyLoss(-1)
M.update_health()
M.adjust_stunned(20 * -4)
diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm
index 095694a6b8b..6ff2d58e7e1 100644
--- a/code/game/mecha/mech_bay.dm
+++ b/code/game/mecha/mech_bay.dm
@@ -67,9 +67,9 @@
mech.occupant_message(SPAN_NOTICE("Fully charged."))
done = TRUE
- if(repair && istype(mech) && mech.health < initial(mech.health))
- mech.health = min(mech.health + repair, initial(mech.health))
- if(mech.health == initial(mech.health))
+ if(repair && istype(mech) && mech.integrity < initial(mech.integrity))
+ mech.integrity = min(mech.integrity + repair, initial(mech.integrity))
+ if(mech.integrity == initial(mech.integrity))
mech.occupant_message(SPAN_NOTICE("Fully repaired."))
else
done = FALSE
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index bff85da4fbf..d2f0957b91c 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -121,10 +121,11 @@
if(printing)
add_overlay("[base_icon_state]-active")
-/obj/machinery/mecha_part_fabricator/dismantle()
+/obj/machinery/mecha_part_fabricator/drop_products(method, atom/where)
+ . = ..()
+ // todo: refactor
for(var/f in stored_materials)
eject_materials(f, -1)
- ..()
/obj/machinery/mecha_part_fabricator/RefreshParts()
res_max_amount = 0
@@ -149,8 +150,8 @@
*/
/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D, var/categories = FALSE)
var/cost = list()
- for(var/c in D.materials)
- cost[c] = get_resource_cost_w_coeff(D, D.materials[c])
+ for(var/c in D.materials_base)
+ cost[c] = get_resource_cost_w_coeff(D, D.materials_base[c])
var/obj/built_item = D.build_path
@@ -267,8 +268,8 @@
*/
/obj/machinery/mecha_part_fabricator/proc/get_resources_w_coeff(datum/design/D)
var/list/resources = list()
- for(var/mat_id in D.materials)
- resources[mat_id] = get_resource_cost_w_coeff(D, D.materials[mat_id])
+ for(var/mat_id in D.materials_base)
+ resources[mat_id] = get_resource_cost_w_coeff(D, D.materials_base[mat_id])
return resources
/**
diff --git a/code/game/mecha/mech_prosthetics.dm b/code/game/mecha/mech_prosthetics.dm
index 4c9619e4004..c9c2814e833 100644
--- a/code/game/mecha/mech_prosthetics.dm
+++ b/code/game/mecha/mech_prosthetics.dm
@@ -16,7 +16,7 @@
var/species_types = list(SPECIES_HUMAN)
var/species = SPECIES_HUMAN
- materials = list(
+ materials_base = list(
MAT_STEEL = 0,
MAT_GLASS = 0,
MAT_PLASTIC = 0,
@@ -75,9 +75,9 @@
/obj/machinery/mecha_part_fabricator/pros/dispense_built_part(datum/design/D)
var/obj/item/I = ..()
- if(isobj(I) && I.materials && I.materials.len > 0)
- for(var/i in I.materials)
- I.materials[i] = I.materials[i] * component_coeff
+ if(isobj(I) && I.materials_base && I.materials_base.len > 0)
+ for(var/i in I.materials_base)
+ I.materials_base[i] = I.materials_base[i] * component_coeff
/obj/machinery/mecha_part_fabricator/pros/ui_data(mob/user)
var/list/data = ..()
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 410669e0893..9b1550bda1d 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -23,13 +23,14 @@
description_info = "Alt click to strafe."
icon = 'icons/mecha/mecha.dmi'
/// Dense. To raise the heat.
- density = 1
+ density = TRUE
/// Opaque. Menacing.
- opacity = 1
+ opacity = TRUE
/// No pulling around.
- anchored = 1
- /// And no deleting hoomans inside.
- unacidable = 1
+ anchored = TRUE
+ integrity_flags = INTEGRITY_ACIDPROOF | INTEGRITY_FIREPROOF
+ integrity = 300
+ integrity_max = 300
/// Icon draw layer.
layer = MOB_LAYER
/// Byond implementation is bugged.
@@ -47,10 +48,6 @@
/// What direction will the mech face when entered/powered on? Defaults to South.
var/dir_in = 2
var/step_energy_drain = 10
- /// Health is healthdrain = 10
- var/health = 300
- /// Maxhealth is maxhealth.
- var/maxhealth = 300
/// Chance to deflect the incoming projectiles, hits, or lesser the effect of legacy_ex_act.
var/deflect_chance = 10
/// The values in this list show how much damage will pass through, not how much will be absorbed.
@@ -468,7 +465,7 @@
. += "It does not seem to have a completed hull."
- var/integrity = health/initial(health)*100
+ var/integrity = src.integrity/initial(src.integrity)*100
switch(integrity)
if(85 to 100)
. += "It's fully intact."
@@ -762,8 +759,8 @@
return 0
if(overload)//Check if you have leg overload
- health--
- if(health < initial(health) - initial(health)/3)
+ integrity--
+ if(integrity < initial(integrity) - initial(integrity)/3)
overload = 0
step_energy_drain = initial(step_energy_drain)
src.occupant_message("Leg actuators damage threshold exceded. Disabling overload.")
@@ -890,7 +887,7 @@
/obj/mecha/proc/check_for_internal_damage(var/list/possible_int_damage,var/ignore_threshold=null)
if(!islist(possible_int_damage) || !length(possible_int_damage)) return
if(prob(30))
- if(ignore_threshold || src.health*100/initial(src.health) < src.internal_damage_threshold)
+ if(ignore_threshold || src.integrity*100/initial(src.integrity) < src.internal_damage_threshold)
for(var/T in possible_int_damage)
if(internal_damage & T)
possible_int_damage -= T
@@ -900,7 +897,7 @@
return //It already hurts to get some, lets not get both.
if(prob(10))
- if(ignore_threshold || src.health*100/initial(src.health) < src.internal_damage_threshold)
+ if(ignore_threshold || src.integrity*100/initial(src.integrity) < src.internal_damage_threshold)
var/obj/item/mecha_parts/mecha_equipment/destr = SAFEPICK(equipment)
if(destr)
destr.destroy()
@@ -936,14 +933,14 @@
//////// Health related procs ////////
////////////////////////////////////////
-/obj/mecha/take_damage(amount, type="brute")
+/obj/mecha/proc/take_damage_legacy(amount, type="brute")
update_damage_alerts()
if(amount)
var/damage = absorbDamage(amount,type)
damage = components_handle_damage(damage,type)
- health -= damage
+ damage_integrity(damage)
update_health()
log_append_to_last("Took [damage] points of damage. Damage type: \"[type]\".",1)
@@ -994,13 +991,13 @@
/obj/mecha/airlock_crush(var/crush_damage)
..()
- take_damage(crush_damage)
+ take_damage_legacy(crush_damage)
if(prob(50)) //Try to avoid that.
check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
return 1
/obj/mecha/proc/update_health()
- if(src.health > 0)
+ if(src.integrity > 0)
src.spark_system.start()
else
qdel(src)
@@ -1028,7 +1025,7 @@
var/mob/living/carbon/human/H = user
if(H.species.can_shred(user))
if(!prob(temp_deflect_chance))
- src.take_damage(15) //The take_damage() proc handles armor values
+ src.take_damage_legacy(15) //The take_damage_legacy() proc handles armor values
if(prob(25)) //Why would they get free internal damage. At least make it a bit RNG.
src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
playsound(src, 'sound/weapons/slash.ogg', 50, 1, -1)
@@ -1045,7 +1042,7 @@
src.log_append_to_last("Armor saved.")
return
else if ((MUTATION_HULK in user.mutations) && !prob(temp_deflect_chance))
- src.take_damage(15) //The take_damage() proc handles armor values
+ src.take_damage_legacy(15) //The take_damage_legacy() proc handles armor values
if(prob(25)) //Hulks punch hard but lets not give them consistent internal damage.
src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
user.visible_message("[user] hits [src.name], doing some damage.", "You hit [src.name] with all your might. The metal creaks and bends.")
@@ -1117,7 +1114,7 @@
pass_damage = ME.handle_ranged_contact(A, pass_damage)
pass_damage = (pass_damage*pass_damage_reduc_mod)//Applying damage reduction
- src.take_damage(pass_damage) //The take_damage() proc handles armor values
+ src.take_damage_legacy(pass_damage) //The take_damage_legacy() proc handles armor values
if(pass_damage > internal_damage_minimum) //Only decently painful attacks trigger a chance of mech damage.
src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
return
@@ -1189,7 +1186,7 @@
pass_damage_reduc_mod = 1
pass_damage = (pass_damage_reduc_mod*pass_damage)//Apply damage reduction before usage.
- src.take_damage(pass_damage, Proj.damage_flag) //The take_damage() proc handles armor values
+ src.take_damage_legacy(pass_damage, Proj.damage_flag) //The take_damage_legacy() proc handles armor values
if(prob(25))
spark_system.start()
if(pass_damage > internal_damage_minimum) //Only decently painful attacks trigger a chance of mech damage.
@@ -1233,18 +1230,18 @@
src.log_append_to_last("Armor saved, changing severity to [severity].")
switch(severity)
if(1.0)
- src.take_damage(initial(src.health), "bomb")
+ src.take_damage_legacy(initial(src.integrity), "bomb")
if(2.0)
if (prob(30))
- src.take_damage(initial(src.health), "bomb")
+ src.take_damage_legacy(initial(src.integrity), "bomb")
else
- src.take_damage(initial(src.health)/2, "bomb")
+ src.take_damage_legacy(initial(src.integrity)/2, "bomb")
src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1)
if(3.0)
if (prob(5))
qdel(src)
else
- src.take_damage(initial(src.health)/5, "bomb")
+ src.take_damage_legacy(initial(src.integrity)/5, "bomb")
src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1)
return
@@ -1252,7 +1249,7 @@
/obj/mecha/attack_blob(mob/user as mob)
src.log_message("Attack by blob. Attacker - [user].",1)
if(!prob(src.deflect_chance))
- src.take_damage(6)
+ src.take_damage_legacy(6)
src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
playsound(src, 'sound/effects/blobattack.ogg', 50, 1, -1)
to_chat(user, "You smash at the armored suit!")
@@ -1273,7 +1270,7 @@
/obj/mecha/emp_act(severity)
if(get_charge())
use_power((cell.charge/2)/severity)
- take_damage(50 / severity,"energy")
+ take_damage_legacy(50 / severity,"energy")
src.log_message("EMP detected",1)
if(prob(80))
check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1)
@@ -1285,7 +1282,7 @@
/obj/mecha/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
if(exposed_temperature>src.max_temperature)
src.log_message("Exposed to dangerous temperature.",1)
- src.take_damage(5,"fire") //The take_damage() proc handles armor values
+ src.take_damage_legacy(5,"fire") //The take_damage_legacy() proc handles armor values
src.check_for_internal_damage(list(MECHA_INT_FIRE, MECHA_INT_TEMP_CONTROL))
return
@@ -1337,7 +1334,7 @@
pass_damage = (pass_damage*pass_damage_reduc_mod) //Apply the reduction of damage from not having enough armor penetration. This is not regular armor values at play.
for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment)
pass_damage = ME.handle_projectile_contact(W, user, pass_damage)
- src.take_damage(pass_damage,W.damtype) //The take_damage() proc handles armor values
+ src.take_damage_legacy(pass_damage,W.damtype) //The take_damage_legacy() proc handles armor values
if(pass_damage > internal_damage_minimum) //Only decently painful attacks trigger a chance of mech damage.
src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
return
@@ -1485,9 +1482,9 @@
to_chat(user, "You repair the damaged gas tank.")
else
return
- if(src.healthYou repair some damage to [src.name].")
- src.health += min(10, initial(src.health)-src.health)
+ src.integrity += min(10, initial(src.integrity)-src.integrity)
update_damage_alerts()
else
to_chat(user, "The [src.name] is at full integrity")
@@ -1508,10 +1505,10 @@
if(C)
- if(C.integrity < C.max_integrity)
- while(C.integrity < C.max_integrity && NP && do_after(user, 1 SECOND, src))
+ if(C.integrity < C.integrity_max)
+ while(C.integrity < C.integrity_max && NP && do_after(user, 1 SECOND, src))
if(NP.use(1))
- C.adjust_integrity(10)
+ C.adjust_integrity_mecha(10)
to_chat(user, "You repair damage to \the [C].")
@@ -1536,7 +1533,7 @@
else
src.occupant_message("[user] hits [src] with [W].")
user.visible_message("[user] hits [src] with [W].", "You hit [src] with [W].")
- src.take_damage(W.force,W.damtype)
+ src.take_damage_legacy(W.force,W.damtype)
src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
*/
return
@@ -2117,7 +2114,7 @@
/obj/mecha/proc/get_stats_part()
- var/integrity = health/initial(health)*100
+ var/integrity = src.integrity/initial(src.integrity)*100
var/cell_charge = get_charge()
var/tank_pressure = internal_tank ? round(internal_tank.return_pressure(),0.01) : "None"
var/tank_temperature = internal_tank ? internal_tank.return_temperature() : "Unknown"
@@ -2126,9 +2123,9 @@
var/obj/item/mecha_parts/component/hull/HC = internal_components[MECH_HULL]
var/obj/item/mecha_parts/component/armor/AC = internal_components[MECH_ARMOR]
- var/output = {"[report_internal_damage()]
- Armor Integrity: [AC?"[round(AC.integrity / AC.max_integrity * 100, 0.1)]%":"ARMOR MISSING"]
- Hull Integrity: [HC?"[round(HC.integrity / HC.max_integrity * 100, 0.1)]%":"HULL MISSING"]
+ var/output_text = {"[report_internal_damage()]
+ Armor Integrity: [AC?"[round(AC.integrity / AC.integrity_max * 100, 0.1)]%":"ARMOR MISSING"]
+ Hull Integrity: [HC?"[round(HC.integrity / HC.integrity_max * 100, 0.1)]%":"HULL MISSING"]
[integrity<30?"DAMAGE LEVEL CRITICAL
":null]
Chassis Integrity: [integrity]%
Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
@@ -2143,26 +2140,26 @@
if(defence_mode_possible)
- output += "Defence mode: [defence_mode?"on":"off"]
"
+ output_text += "Defence mode: [defence_mode?"on":"off"]
"
if(overload_possible)
- output += "Leg actuators overload: [overload?"on":"off"]
"
+ output_text += "Leg actuators overload: [overload?"on":"off"]
"
if(smoke_possible)
- output += "Smoke: [smoke_reserve]
"
+ output_text += "Smoke: [smoke_reserve]
"
if(thrusters_possible)
- output += "Thrusters: [thrusters?"on":"off"]
"
+ output_text += "Thrusters: [thrusters?"on":"off"]
"
//Cargo components. Keep this last otherwise it does weird alignment issues.
- output += "Cargo Compartment Contents:"
+ output_text += "
Cargo Compartment Contents:"
if(src.cargo.len)
for(var/obj/O in src.cargo)
- output += "
Unload : [O]
"
+ output_text += "
Unload : [O]
"
else
- output += "Nothing"
- output += "
"
- return output
+ output_text += "Nothing"
+ output_text += "
"
+ return output_text
/obj/mecha/proc/get_commands()
- var/output = {"
+ var/output_text = {"
Toggle Lights
@@ -2198,29 +2195,29 @@
[(/obj/mecha/verb/eject in src.verbs)?"
Eject":null]
"}
- return output
+ return output_text
/obj/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu
- var/output
+ var/output_text
if(equipment.len)
- output += {"
+ output_text += {"
"}
for(var/obj/item/mecha_parts/mecha_equipment/W in hull_equipment)
- output += "Hull Module: [W.name]
Detach"
+ output_text += "Hull Module: [W.name]
Detach"
for(var/obj/item/mecha_parts/mecha_equipment/W in weapon_equipment)
- output += "Weapon Module: [W.name]
Detach"
+ output_text += "Weapon Module: [W.name]
Detach"
for(var/obj/item/mecha_parts/mecha_equipment/W in utility_equipment)
- output += "Utility Module: [W.name]
Detach"
+ output_text += "Utility Module: [W.name]
Detach"
for(var/obj/item/mecha_parts/mecha_equipment/W in universal_equipment)
- output += "Universal Module: [W.name]
Detach"
+ output_text += "Universal Module: [W.name]
Detach"
for(var/obj/item/mecha_parts/mecha_equipment/W in special_equipment)
- output += "Special Module: [W.name]
Detach"
+ output_text += "Special Module: [W.name]
Detach"
for(var/obj/item/mecha_parts/mecha_equipment/W in micro_utility_equipment)
- output += "Micro Utility Module: [W.name]
Detach"
+ output_text += "Micro Utility Module: [W.name]
Detach"
for(var/obj/item/mecha_parts/mecha_equipment/W in micro_weapon_equipment)
- output += "Micro Weapon Module: [W.name]
Detach"
- output += {"
Available hull slots: [max_hull_equip-hull_equipment.len]
+ output_text += "Micro Weapon Module: [W.name]
Detach"
+ output_text += {"
Available hull slots: [max_hull_equip-hull_equipment.len]
Available weapon slots: [max_weapon_equip-weapon_equipment.len]
Available micro weapon slots: [max_micro_weapon_equip-micro_weapon_equipment.len]
Available utility slots: [max_utility_equip-utility_equipment.len]
@@ -2229,26 +2226,26 @@
Available special slots: [max_special_equip-special_equipment.len]
"}
- return output
+ return output_text
/obj/mecha/proc/get_equipment_list() //outputs mecha equipment list in html
if(!equipment.len)
return
- var/output = "
Equipment:"
+ var/output_text = "
Equipment:"
for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment)
- output += "
[MT.get_equip_info()]
"
- output += "
"
- return output
+ output_text += "
[MT.get_equip_info()]
"
+ output_text += "
"
+ return output_text
/obj/mecha/proc/get_log_html()
- var/output = "
[src.name] Log"
+ var/output_text = "
[src.name] Log"
for(var/list/entry in log)
- output += {"
[time2text(entry["time"],"DDD MMM DD hh:mm:ss")] [game_year]
+ output_text += {"
[time2text(entry["time"],"DDD MMM DD hh:mm:ss")] [game_year]
[entry["message"]]
"}
- output += ""
- return output
+ output_text += ""
+ return output_text
/obj/mecha/proc/get_log_tgui()
var/list/data = list()
@@ -2263,7 +2260,7 @@
/obj/mecha/proc/output_access_dialog(obj/item/card/id/id_card, mob/user)
if(!id_card || !user) return
- var/output = {"
+ var/output_text = {"