diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 7f229590013..6a7ed02f7bf 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -67,6 +67,9 @@
#define COMSIG_MOVABLE_Z_CHANGED "movable_z_moved" //from atom/movable/Move and forceMove): (oldz, newz)
#define COMSIG_MOVABLE_PREMOVE "moveable_boutta_move"
+#define COMSIG_ATTEMPT_PULLING "attempt_pulling"
+ #define COMSIG_PULL_CANCEL (1<<0)
+
// /mob signals
#define COMSIG_MOB_LIFE "mob_life" //from mob/Life()
#define COMSIG_MOB_LOGIN "mob_login" //from mob/Login()
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 085a2797f75..bdea8016c83 100755
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -124,7 +124,7 @@
return 1
if(in_throw_mode)
- if(isturf(A) || isturf(A.loc))
+ if(isturf(A) || isturf(A.loc) && isturf(loc))
throw_item(A)
return 1
throw_mode_off()
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index bf0fa7a49b8..b999aee03c6 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -200,6 +200,7 @@
var/list/target_procs = (procs[target] ||= list())
var/list/lookup = (target.comp_lookup ||= list())
+
if(!override && target_procs[signal_type])
var/override_message = "[signal_type] overridden. Use override = TRUE to suppress this warning.\nTarget: [target] ([target.type]) Proc: [proctype]"
//log_signal(override_message)
diff --git a/code/datums/movement/mob.dm b/code/datums/movement/mob.dm
index 6e2ba7fa6ce..4d348bbd4f2 100755
--- a/code/datums/movement/mob.dm
+++ b/code/datums/movement/mob.dm
@@ -268,6 +268,12 @@
else
M.stop_pulling()
+ if(istype(mob.loc, /obj/item/mech_equipment/forklifting_system))
+ if(mover == mob && isliving(mob))
+ mob:resist()
+ return MOVEMENT_STOP
+
+
return MOVEMENT_PROCEED
diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm
index 85110919d66..cfe262016f2 100644
--- a/code/datums/wires/wires.dm
+++ b/code/datums/wires/wires.dm
@@ -145,7 +145,11 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown"
var/mob/living/L = usr
if(CanUse(L) && href_list["action"])
var/obj/item/I = L.get_active_hand()
- holder.add_hiddenprint(L)
+ if(!ismech(L.loc))
+ holder.add_hiddenprint(L)
+ else
+ var/mob/living/exosuit/mech = L.loc
+ I = mech.get_active_hand()
if(href_list["cut"]) // Toggles the cut/mend status
if (!istype(I))
return
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index fe7d94739c7..043ba3acf83 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -649,7 +649,7 @@ its easier to just keep the beam vertical.
/atom/movable/proc/fall_impact(turf/from, turf/dest)
//If atom stands under open space, it can prevent fall, or not
-/atom/proc/can_prevent_fall()
+/atom/proc/can_prevent_fall(above, atom/movable/thing)
return FALSE
// Show a message to all mobs and objects in sight of this atom
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 6946ff4d385..b3cd1833cc3 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -53,8 +53,8 @@
GLOB.all_doors -= src
..()
-/obj/machinery/door/can_prevent_fall()
- return density
+/obj/machinery/door/can_prevent_fall(above)
+ return above ? density : null
/obj/machinery/door/attack_generic(mob/user, var/damage)
if(damage >= resistance)
diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm
index c920cc018de..f55105c31fb 100644
--- a/code/game/objects/structures/catwalk.dm
+++ b/code/game/objects/structures/catwalk.dm
@@ -91,5 +91,5 @@
return
-/obj/structure/catwalk/can_prevent_fall()
- return FALSE
+/obj/structure/catwalk/can_prevent_fall(above)
+ return above ? FALSE : TRUE
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 5236cf9b3b7..eff2df7b10f 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -42,8 +42,8 @@
var/store_mobs = 1
var/old_chance = 0 //Chance to have rusted closet content in it, from 0 to 100. Keep in mind that chance increases in maints
-/obj/structure/closet/can_prevent_fall()
- return TRUE
+/obj/structure/closet/can_prevent_fall(above)
+ return above ? TRUE : FALSE
/obj/structure/closet/Initialize(mapload)
..()
@@ -350,6 +350,10 @@
//Empty gripper attacks will call attack_AI
return FALSE
+ /// So mechs dont open these when attacking.
+ if(istype(I, /obj/item/mech_equipment/forklifting_system))
+ return FALSE
+
var/list/usable_qualities = list(QUALITY_WELDING)
if(opened)
usable_qualities += QUALITY_SAWING
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index 11b79502719..469fdd9493b 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -81,5 +81,5 @@
return
-/obj/structure/lattice/can_prevent_fall()
- return TRUE
+/obj/structure/lattice/can_prevent_fall(above)
+ return above ? FALSE : TRUE
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 3c8f5da4ce5..10502621d96 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -24,8 +24,8 @@
atmos_canpass = CANPASS_PROC
-/obj/structure/window/can_prevent_fall()
- return !is_fulltile()
+/obj/structure/window/can_prevent_fall(above)
+ return above ? !is_fulltile() : FALSE
/obj/structure/window/get_fall_damage(var/turf/from, var/turf/dest)
var/damage = health * 0.4 * get_health_ratio()
@@ -357,7 +357,7 @@ proc/end_grab_onto(mob/living/user, mob/living/target)
usable_qualities.Add(QUALITY_SEALING)
//If you set intent to harm, you can hit the window with tools to break it. Set to any other intent to use tools on it
- if (usr.a_intent != I_HURT)
+ if (user.a_intent != I_HURT)
var/tool_type = I.get_tool_type(user, usable_qualities, src)
switch(tool_type)
if(QUALITY_SEALING)
diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm
index 397b0b21bac..6b93f1a8afa 100644
--- a/code/game/turfs/simulated/wall_attacks.dm
+++ b/code/game/turfs/simulated/wall_attacks.dm
@@ -97,7 +97,10 @@
return
//get the user's location
- if(!istype(user.loc, /turf)) return //can't do this stuff whilst inside objects and such
+ if(!istype(user.loc, /turf))
+ if(!(ismech(user.loc) && istype(I, /obj/item/tool/mech_kit)))
+ return
+
if(I)
radiate()
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
index e42111baf92..3d0b90fecc2 100644
--- a/code/modules/materials/materials.dm
+++ b/code/modules/materials/materials.dm
@@ -113,6 +113,15 @@ var/list/name_to_material
var/explosion_resistance = 5 // Only used by walls currently.
var/conductive = 1 // Objects with this var add CONDUCTS to flags on spawn.
var/list/composite_material // If set, object matter var will be a list containing these values.
+ /// Armor values for this material whenever its applied on something.
+ var/datum/armor/armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 1,
+ bomb = 1,
+ bio = 1,
+ rad = 1
+ )
// Placeholder vars for the time being, todo properly integrate windows/light tiles/rods.
var/created_window
@@ -258,6 +267,16 @@ var/list/name_to_material
hardness = 80
stack_origin_tech = list(TECH_MATERIAL = 5)
door_icon_base = "stone"
+ // it is a metal and it does conduct , but it does very poorly
+ conductive = FALSE
+ armor = list(
+ melee = 6,
+ bullet = 6,
+ energy = 10,
+ bomb = 25,
+ bio = 25,
+ rad = 0
+ )
/material/diamond
name = MATERIAL_DIAMOND
@@ -271,6 +290,14 @@ var/list/name_to_material
hardness = 100
weight = 50
stack_origin_tech = list(TECH_MATERIAL = 6)
+ armor = list(
+ melee = 15,
+ bullet = 15,
+ energy = 0,
+ bomb = 80,
+ bio = 0,
+ rad = 0
+ )
/material/gold
name = MATERIAL_GOLD
@@ -281,10 +308,28 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 4)
sheet_singular_name = "ingot"
sheet_plural_name = "ingots"
+ conductive = TRUE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 1,
+ bomb = 1,
+ bio = 45,
+ rad = 1
+ )
/material/gold/bronze //placeholder for ashtrays
name = "bronze"
icon_colour = "#EDD12F"
+ conductive = TRUE
+ armor = list(
+ melee = 2,
+ bullet = 2,
+ energy = 3,
+ bomb = 10,
+ bio = 30,
+ rad = 0
+ )
/material/silver
name = MATERIAL_SILVER
@@ -295,6 +340,15 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 3)
sheet_singular_name = "ingot"
sheet_plural_name = "ingots"
+ conductive = TRUE
+ armor = list(
+ melee = 2,
+ bullet = 2,
+ energy = 2,
+ bomb = 10,
+ bio = 80,
+ rad = 0
+ )
/material/plasma
name = MATERIAL_PLASMA
@@ -309,6 +363,15 @@ var/list/name_to_material
door_icon_base = "stone"
sheet_singular_name = "crystal"
sheet_plural_name = "crystals"
+ conductive = TRUE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 6,
+ bomb = 1,
+ bio = 80,
+ rad = 45
+ )
/*
// Commenting this out while fires are so spectacularly lethal, as I can't seem to get this balanced appropriately.
@@ -339,6 +402,15 @@ var/list/name_to_material
door_icon_base = "stone"
sheet_singular_name = "brick"
sheet_plural_name = "bricks"
+ conductive = FALSE
+ armor = list(
+ melee = 2,
+ bullet = 0,
+ energy = 1,
+ bomb = 25,
+ bio = 0,
+ rad = 0
+ )
/material/stone/marble
name = MATERIAL_MARBLE
@@ -358,12 +430,30 @@ var/list/name_to_material
icon_reinf = "reinf_over"
icon_colour = PLASTEEL_COLOUR
hitsound = 'sound/weapons/genhit.ogg'
+ conductive = TRUE
+ armor = list(
+ melee = 5,
+ bullet = 5,
+ energy = 5,
+ bomb = 35,
+ bio = 0,
+ rad = 0
+ )
/material/steel/holographic
name = "holo" + MATERIAL_STEEL
display_name = MATERIAL_STEEL
stack_type = null
shard_type = SHARD_NONE
+ // wish.com steel
+ armor = list(
+ melee = 0,
+ bullet = 0,
+ energy = 0,
+ bomb = 0,
+ bio = 0,
+ rad = 0
+ )
/material/plasteel
name = MATERIAL_PLASTEEL
@@ -377,7 +467,16 @@ var/list/name_to_material
hardness = 80
weight = 23
stack_origin_tech = list(TECH_MATERIAL = 2)
+ conductive = TRUE
hitsound = 'sound/weapons/genhit.ogg'
+ armor = list(
+ melee = 8,
+ bullet = 8,
+ energy = 4,
+ bomb = 75,
+ bio = 35,
+ rad = 25
+ )
/material/plasteel/titanium
name = "titanium"
@@ -388,6 +487,15 @@ var/list/name_to_material
door_icon_base = "metal"
icon_colour = "#D1E6E3"
icon_reinf = "reinf_metal"
+ conductive = TRUE
+ armor = list(
+ melee = 16,
+ bullet = 10,
+ energy = 6,
+ bomb = 125,
+ bio = 35,
+ rad = 0
+ )
/material/glass
name = MATERIAL_GLASS
@@ -406,7 +514,16 @@ var/list/name_to_material
created_window = /obj/structure/window/basic
created_window_full = /obj/structure/window/basic/full
rod_product = /obj/item/stack/material/glass/reinforced
+ conductive = FALSE
hitsound = 'sound/effects/Glasshit.ogg'
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 0,
+ bomb = 0,
+ bio = 0,
+ rad = 0
+ )
/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
@@ -522,8 +639,17 @@ var/list/name_to_material
window_options = list("One Direction" = 1, "Full Window" = 6, "Windoor" = 5)
created_window = /obj/structure/window/reinforced
created_window_full = /obj/structure/window/reinforced/full
+ conductive = FALSE
wire_product = null
rod_product = null
+ armor = list(
+ melee = 4,
+ bullet = 4,
+ energy = 0,
+ bomb = 35,
+ bio = 0,
+ rad = 0
+ )
/material/glass/plasma
name = MATERIAL_PLASMAGLASS
@@ -539,6 +665,15 @@ var/list/name_to_material
created_window_full = /obj/structure/window/plasmabasic/full
wire_product = null
rod_product = /obj/item/stack/material/glass/plasmarglass
+ conductive = FALSE
+ armor = list(
+ melee = 6,
+ bullet = 6,
+ energy = 0,
+ bomb = 45,
+ bio = 0,
+ rad = 0
+ )
/material/glass/plasma/reinforced
name = MATERIAL_RPLASMAGLASS
@@ -550,8 +685,17 @@ var/list/name_to_material
created_window_full = /obj/structure/window/reinforced/plasma/full
hardness = 60
weight = 50
+ conductive = FALSE
//composite_material = list() //todo
rod_product = null
+ armor = list(
+ melee = 8,
+ bullet = 8,
+ energy = 0,
+ bomb = 50,
+ bio = 0,
+ rad = 0
+ )
/material/plastic
name = MATERIAL_PLASTIC
@@ -563,13 +707,31 @@ var/list/name_to_material
hardness = 10
weight = 12
melting_point = T0C+371 //assuming heat resistant plastic
+ conductive = FALSE
stack_origin_tech = list(TECH_MATERIAL = 3)
+ armor = list(
+ melee = 3,
+ bullet = 3,
+ energy = 3,
+ bomb = 20,
+ bio = 5,
+ rad = 0
+ )
/material/plastic/holographic
name = "holoplastic"
display_name = "plastic"
stack_type = null
shard_type = SHARD_NONE
+ conductive = FALSE
+ armor = list(
+ melee = 0,
+ bullet = 0,
+ energy = 0,
+ bomb = 0,
+ bio = 0,
+ rad = 0
+ )
/material/osmium
name = MATERIAL_OSMIUM
@@ -580,6 +742,15 @@ var/list/name_to_material
hardness = 90
sheet_singular_name = "ingot"
sheet_plural_name = "ingots"
+ conductive = TRUE
+ armor = list(
+ melee = 20,
+ bullet = 14,
+ energy = 7,
+ bomb = 200,
+ bio = 0,
+ rad = 25
+ )
/material/tritium
name = MATERIAL_TRITIUM
@@ -588,6 +759,15 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 5)
sheet_singular_name = "ingot"
sheet_plural_name = "ingots"
+ conductive = FALSE
+ armor = list(
+ melee = 0,
+ bullet = 0,
+ energy = 10,
+ bomb = 0,
+ bio = 100,
+ rad = 50
+ )
/material/mhydrogen
name = MATERIAL_MHYDROGEN
@@ -596,7 +776,16 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 6, TECH_MAGNET = 5)
weight = 10
hardness = 200
+ conductive = TRUE
display_name = "metallic hydrogen"
+ armor = list(
+ melee = 35,
+ bullet = 18,
+ energy = 8,
+ bomb = 350,
+ bio = 0,
+ rad = 35
+ )
/material/platinum
name = MATERIAL_PLATINUM
@@ -607,6 +796,14 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 2)
sheet_singular_name = "ingot"
sheet_plural_name = "ingots"
+ armor = list(
+ melee = 3,
+ bullet = 3,
+ energy = 15,
+ bomb = 25,
+ bio = 55,
+ rad = 25
+ )
/material/iron
name = MATERIAL_IRON
@@ -617,6 +814,15 @@ var/list/name_to_material
sheet_singular_name = "ingot"
sheet_plural_name = "ingots"
hitsound = 'sound/weapons/smash.ogg'
+ conductive = TRUE
+ armor = list(
+ melee = 3,
+ bullet = 3,
+ energy = 3,
+ bomb = 35,
+ bio = 0,
+ rad = 0
+ )
// Adminspawn only, do not let anyone get this.
/material/voxalloy
@@ -629,6 +835,14 @@ var/list/name_to_material
explosion_resistance = 200 // Hull plating.
hardness = 500
weight = 500
+ armor = list(
+ melee = 50,
+ bullet = 35,
+ energy = 25,
+ bomb = 500,
+ bio = 0,
+ rad = 85
+ )
/material/wood
name = MATERIAL_WOOD
@@ -650,12 +864,30 @@ var/list/name_to_material
sheet_singular_name = "plank"
sheet_plural_name = "planks"
hitsound = 'sound/effects/woodhit.ogg'
+ conductive = FALSE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 5,
+ bomb = 10,
+ bio = 0,
+ rad = 0
+ )
/material/wood/holographic
name = "holowood"
display_name = "wood"
stack_type = null
shard_type = SHARD_NONE
+ conductive = FALSE
+ armor = list(
+ melee = 0,
+ bullet = 0,
+ energy = 0,
+ bomb = 0,
+ bio = 0,
+ rad = 0
+ )
/material/cardboard
name = MATERIAL_CARDBOARD
@@ -672,6 +904,15 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 1)
door_icon_base = "wood"
destruction_desc = "crumples"
+ conductive = FALSE
+ armor = list(
+ melee = 0,
+ bullet = 0,
+ energy = 0,
+ bomb = 5,
+ bio = 0,
+ rad = 0
+ )
/material/cloth //todo
name = MATERIAL_CLOTH
@@ -680,6 +921,16 @@ var/list/name_to_material
ignition_point = T0C+232
melting_point = T0C+300
flags = MATERIAL_PADDING
+ conductive = FALSE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 1,
+ bomb = 5,
+ bio = 0,
+ rad = 0
+ )
+
/material/biomatter
name = MATERIAL_BIOMATTER
@@ -688,6 +939,14 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
sheet_singular_name = "sheet"
sheet_plural_name = "sheets"
+ armor = list(
+ melee = 2,
+ bullet = 2,
+ energy = 2,
+ bomb = 15,
+ bio = 100,
+ rad = 0
+ )
/material/compressed
name = MATERIAL_COMPRESSED
@@ -695,6 +954,15 @@ var/list/name_to_material
icon_colour = "#00E1FF"
sheet_singular_name = "cartrigde"
sheet_plural_name = "cartridges"
+ conductive = TRUE
+ armor = list(
+ melee = 18,
+ bullet = 10,
+ energy = 10,
+ bomb = 150,
+ bio = 0,
+ rad = 100
+ )
//TODO PLACEHOLDERS:
/material/leather
@@ -704,6 +972,14 @@ var/list/name_to_material
flags = MATERIAL_PADDING
ignition_point = T0C+300
melting_point = T0C+300
+ armor = list(
+ melee = 4,
+ bullet = 2,
+ energy = 2,
+ bomb = 10,
+ bio = 10,
+ rad = 0
+ )
/material/carpet
name = "carpet"
@@ -715,6 +991,15 @@ var/list/name_to_material
melting_point = T0C+300
sheet_singular_name = "tile"
sheet_plural_name = "tiles"
+ conductive = FALSE
+ armor = list(
+ melee = 0,
+ bullet = 0,
+ energy = 0,
+ bomb = 5,
+ bio = 0,
+ rad = 0
+ )
/material/cotton
name = "cotton"
@@ -723,6 +1008,15 @@ var/list/name_to_material
flags = MATERIAL_PADDING
ignition_point = T0C+232
melting_point = T0C+300
+ conductive = FALSE
+ armor = list(
+ melee = 0,
+ bullet = 0,
+ energy = 0,
+ bomb = 0,
+ bio = 0,
+ rad = 0
+ )
/material/cloth_teal
name = "teal"
@@ -732,6 +1026,15 @@ var/list/name_to_material
flags = MATERIAL_PADDING
ignition_point = T0C+232
melting_point = T0C+300
+ conductive = FALSE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 1,
+ bomb = 5,
+ bio = 0,
+ rad = 0
+ )
/material/cloth_black
name = "black"
@@ -741,6 +1044,15 @@ var/list/name_to_material
flags = MATERIAL_PADDING
ignition_point = T0C+232
melting_point = T0C+300
+ conductive = FALSE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 1,
+ bomb = 5,
+ bio = 0,
+ rad = 0
+ )
/material/cloth_green
name = "green"
@@ -750,6 +1062,15 @@ var/list/name_to_material
flags = MATERIAL_PADDING
ignition_point = T0C+232
melting_point = T0C+300
+ conductive = FALSE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 1,
+ bomb = 5,
+ bio = 0,
+ rad = 0
+ )
/material/cloth_puple
name = "purple"
@@ -759,6 +1080,15 @@ var/list/name_to_material
flags = MATERIAL_PADDING
ignition_point = T0C+232
melting_point = T0C+300
+ conductive = FALSE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 1,
+ bomb = 5,
+ bio = 0,
+ rad = 0
+ )
/material/cloth_blue
name = "blue"
@@ -768,6 +1098,15 @@ var/list/name_to_material
flags = MATERIAL_PADDING
ignition_point = T0C+232
melting_point = T0C+300
+ conductive = FALSE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 1,
+ bomb = 5,
+ bio = 0,
+ rad = 0
+ )
/material/cloth_beige
name = "beige"
@@ -777,6 +1116,15 @@ var/list/name_to_material
flags = MATERIAL_PADDING
ignition_point = T0C+232
melting_point = T0C+300
+ conductive = FALSE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 1,
+ bomb = 5,
+ bio = 0,
+ rad = 0
+ )
/material/cloth_lime
name = "lime"
@@ -786,3 +1134,12 @@ var/list/name_to_material
flags = MATERIAL_PADDING
ignition_point = T0C+232
melting_point = T0C+300
+ conductive = FALSE
+ armor = list(
+ melee = 1,
+ bullet = 1,
+ energy = 1,
+ bomb = 5,
+ bio = 0,
+ rad = 0
+ )
diff --git a/code/modules/mechs/_mech_defines.dm b/code/modules/mechs/_mech_defines.dm
index 1bde101c220..d1217122fa1 100644
--- a/code/modules/mechs/_mech_defines.dm
+++ b/code/modules/mechs/_mech_defines.dm
@@ -7,6 +7,7 @@
#define MECH_HUD_ICON 'icons/mechs/mech_hud.dmi'
#define HARDPOINT_BACK "back"
+#define HARDPOINT_FRONT "front"
#define HARDPOINT_LEFT_HAND "left hand"
#define HARDPOINT_RIGHT_HAND "right hand"
#define HARDPOINT_LEFT_SHOULDER "left shoulder"
@@ -51,3 +52,12 @@ GLOBAL_LIST_INIT(mech_damage_overlay_cache, new)
GLOBAL_LIST_INIT(mech_image_cache, new)
GLOBAL_LIST_INIT(mech_icon_cache, new)
GLOBAL_LIST_INIT(mech_weapon_overlays, icon_states(MECH_WEAPON_OVERLAYS_ICON))
+
+#define MECH_POWER_OFF 0
+#define MECH_POWER_TRANSITION 1
+#define MECH_POWER_ON 2
+
+/// It will make update_icon be called on the equipment after every move
+#define EQUIPFLAG_UPDTMOVE 1
+/// It will have pretick() called on it before the mech checks wheter or not is powered
+#define EQUIPFLAG_PRETICK 2
diff --git a/code/modules/mechs/components/_components.dm b/code/modules/mechs/components/_components.dm
index efcd5483133..0f3d0d78ca0 100644
--- a/code/modules/mechs/components/_components.dm
+++ b/code/modules/mechs/components/_components.dm
@@ -17,8 +17,14 @@
var/max_damage = 60
var/damage_state = 1
var/list/has_hardpoints = list()
+ //var/material/reinforcement = null
var/decal
var/power_use = 0
+ /// how many hits do we have to get to gib once we hit max damage
+ var/gib_hits_needed = 7
+ var/gib_hits = 0
+ /// wheter or not this component can just blow up
+ var/can_gib = FALSE
/obj/item/mech_component/proc/set_colour(new_colour)
var/last_colour = color
@@ -35,13 +41,35 @@
if(.)
if(ready_to_install())
- to_chat(usr, SPAN_NOTICE("It is ready for installation."))
+ to_chat(user, SPAN_NOTICE("It is ready for installation."))
else
show_missing_parts(usr)
+ /*
+ if(reinforcement)
+ to_chat(user, SPAN_NOTICE("It is reinforced with sheets of [reinforcement.material_display_name]."))
+ else
+ to_chat(user, SPAN_NOTICE("It can be reinforced with 5 sheets of a material for additional protection."))
+ */
var/damage_string = src.get_damage_string()
to_chat(user, "The [src.name] [src.gender == PLURAL ? "are" : "is"] [damage_string].")
+/*
+
+/obj/item/mech_component/attackby(obj/item/I, mob/living/user)
+ . = ..()
+
+ if(!reinforcement && istype(I, /obj/item/stack/material))
+ var/obj/item/stack/material/mat = I
+ if(!mat.can_use(5))
+ to_chat(user, SPAN_NOTICE("You need 5 sheets of reinforcing material!"))
+ return
+ to_chat(user, SPAN_NOTICE("You start reinforcing \the src."))
+*/
+
+
+
+
//These icons have multiple directions but before they're attached we only want south.
/obj/item/mech_component/set_dir()
@@ -70,6 +98,26 @@
if(damage_state == MECH_COMPONENT_DAMAGE_DAMAGED_TOTAL)
playsound(loc, 'sound/mechs/critdestr.ogg', 50)
+ if(total_damage == max_damage)
+ if(gib_hits > gib_hits_needed && can_gib)
+ var/mob/living/exosuit/owner = loc
+ if(!istype(owner))
+ return
+ forceMove(NULLSPACE)
+ switch(type)
+ if(/obj/item/mech_component/manipulators)
+ owner.arms = null
+ if(/obj/item/mech_component/sensors)
+ owner.head = null
+ if(/obj/item/mech_component/propulsion)
+ owner.legs = null
+ if(/obj/item/mech_component/chassis)
+ owner.body = null
+ for(var/hardpoint in has_hardpoints)
+ owner.remove_system(hardpoint, null, TRUE)
+ owner.update_icon()
+ qdel(src)
+
/obj/item/mech_component/proc/ready_to_install()
return TRUE
@@ -89,6 +137,7 @@
update_health()
if(total_damage >= max_damage)
take_component_damage(amt,0)
+ gib_hits += (total_damage / 10)
return
/obj/item/mech_component/proc/take_burn_damage(amt)
@@ -96,6 +145,7 @@
update_health()
if(total_damage >= max_damage)
take_component_damage(0,amt)
+ gib_hits += (total_damage / 10)
return
/obj/item/mech_component/proc/take_component_damage(brute, burn)
diff --git a/code/modules/mechs/components/arms.dm b/code/modules/mechs/components/arms.dm
index 3f7918ffbfe..a9c80304720 100644
--- a/code/modules/mechs/components/arms.dm
+++ b/code/modules/mechs/components/arms.dm
@@ -6,9 +6,17 @@
power_use = 10
matter = list(MATERIAL_STEEL = 10)
+ can_gib = TRUE
+ gib_hits_needed = 10
var/melee_damage = WEAPON_FORCE_PAINFUL
var/action_delay = 15
+ /// if they can force open powered doors
+ var/can_force_doors = TRUE
var/obj/item/robot_parts/robot_component/actuator/motivator
+ tool_qualities = list(
+ QUALITY_HAMMERING = 30,
+ QUALITY_PRYING = 20
+ )
var/punch_sound = ('sound/mechs/mech_punch.ogg')
/obj/item/mech_component/manipulators/Destroy()
@@ -50,6 +58,7 @@
desc = "Industrial lifter arms that allow you to crudely manipulate things from the safety of your cockpit."
exosuit_desc_string = "industrial lifter arms"
icon_state = "loader_arms"
+ can_force_doors = FALSE
max_damage = 90
power_use = 30
@@ -59,6 +68,7 @@
desc = "As flexible as they are fragile, these manipulators can follow a pilot's movements in close to real time."
icon_state = "light_arms"
action_delay = 5
+ can_force_doors = FALSE
max_damage = 45
power_use = 10
matter = list(MATERIAL_STEEL = 10, MATERIAL_PLASTIC = 5)
diff --git a/code/modules/mechs/components/body.dm b/code/modules/mechs/components/body.dm
index be7214a9543..a29da3e5146 100644
--- a/code/modules/mechs/components/body.dm
+++ b/code/modules/mechs/components/body.dm
@@ -40,6 +40,10 @@
var/min_pilot_size = MOB_SMALL
var/max_pilot_size = MOB_LARGE
var/climb_time = 25
+ /// does this mech chassis have support for charging all cells inside of its storage? if its 0 it doesnt
+ var/cell_charge_rate = 200
+ /// Wheter chassis blocks sight from a outside POV (aka can see behind mech or not ?)
+ var/opaque_chassis = TRUE
/obj/item/mech_component/chassis/New()
..()
@@ -103,7 +107,7 @@
. = ..()
air_supply = new /obj/machinery/portable_atmospherics/canister/air(src)
storage_compartment = new(src)
- cockpit = new(20)
+ cockpit = new(250)
if(loc)
cockpit.equalize(loc.return_air())
@@ -281,3 +285,33 @@
power_use = 50
climb_time = 35 //Takes longer to climb into, but is beefy as HELL.
matter = list(MATERIAL_STEEL = 50, MATERIAL_URANIUM = 20, MATERIAL_PLASTEEL = 20)
+
+/obj/item/mech_component/chassis/forklift
+ name = "forklift chassis"
+ desc = "Has an integrated forklift clamp for the industrial relocation of resources. Are you ready to lift?"
+ icon_state = "seat-cockpit"
+ has_hardpoints = list(HARDPOINT_FRONT)
+ exosuit_desc_string = "a forklifting chassis"
+ pilot_coverage = 30
+ max_damage = 100
+ mech_health = 200
+ opaque_chassis = FALSE
+ matter = list(MATERIAL_STEEL = 20, MATERIAL_PLASTIC = 10)
+
+
+/obj/item/mech_component/chassis/forklift/Initialize()
+ pilot_positions = list(
+ list(
+ "[NORTH]" = list("x" = 9, "y" = 5),
+ "[SOUTH]" = list("x" = 9, "y" = 5),
+ "[EAST]" = list("x" = 6, "y" = 5),
+ "[WEST]" = list("x" = 8, "y" = 5)
+ ),
+ list(
+ "[NORTH]" = list("x" = 9, "y" = 5),
+ "[SOUTH]" = list("x" = 9, "y" = 10),
+ "[EAST]" = list("x" = 0, "y" = 5),
+ "[WEST]" = list("x" = 16, "y" = 5)
+ )
+ )
+ . = ..()
diff --git a/code/modules/mechs/components/frame.dm b/code/modules/mechs/components/frame.dm
index c972ff5f4b1..37474d2ef15 100644
--- a/code/modules/mechs/components/frame.dm
+++ b/code/modules/mechs/components/frame.dm
@@ -98,7 +98,7 @@
if(is_wired)
usable_qualities += QUALITY_WIRE_CUTTING
- if(is_wired == FRAME_WIRED_ADJUSTED && is_reinforced == FRAME_REINFORCED_WELDED && arms && legs && head && body)
+ if(is_wired == FRAME_WIRED_ADJUSTED && is_reinforced == FRAME_REINFORCED_WELDED && legs && body)
usable_qualities += QUALITY_SCREW_DRIVING
var/tool_type = I.get_tool_type(user, usable_qualities, src)
@@ -225,7 +225,7 @@
// Final construction step
if(QUALITY_SCREW_DRIVING)
// Check for basic components.
- if(!(arms && legs && head && body))
+ if(!(legs && body))
to_chat(user, SPAN_WARNING("There are still parts missing from \the [src]."))
return
@@ -251,7 +251,7 @@
if(!I.use_tool(user, src, WORKTIME_INSTANT, tool_type, FAILCHANCE_ZERO))
return
- if(is_reinforced < FRAME_REINFORCED_WELDED || is_wired < FRAME_WIRED_ADJUSTED || !(arms && legs && head && body))
+ if(is_reinforced < FRAME_REINFORCED_WELDED || is_wired < FRAME_WIRED_ADJUSTED || !(legs && body))
return
// We're all done. Finalize the exosuit and pass the frame to the new system.
@@ -318,6 +318,9 @@
// Installing basic components.
if(istype(I, /obj/item/mech_component/manipulators))
+ if(istype(body, /obj/item/mech_component/chassis/forklift))
+ to_chat(user, SPAN_WARNING("\The [src]'s chassis can not support manipulators!"))
+ return
if(arms)
to_chat(user, SPAN_WARNING("\The [src] already has manipulators installed."))
return
@@ -330,12 +333,18 @@
if(legs)
to_chat(user, SPAN_WARNING("\The [src] already has a propulsion system installed."))
return
+ if(istype(body, /obj/item/mech_component/chassis/forklift) && !istype(I, /obj/item/mech_component/propulsion/wheels))
+ to_chat(user, SPAN_WARNING("\The [src]'s chassis can not support this type of propulsation, only wheels!"))
+ return
if(install_component(I, user))
if(legs)
user.unEquip(I, loc)
return
legs = I
else if(istype(I, /obj/item/mech_component/sensors))
+ if(istype(body, /obj/item/mech_component/chassis/forklift))
+ to_chat(user, SPAN_WARNING("\The [src]'s chassis can not support sensors!"))
+ return
if(head)
to_chat(user, SPAN_WARNING("\The [src] already has a sensor array installed."))
return
@@ -369,6 +378,16 @@
if(!user.unEquip(I))
return
I.forceMove(src)
+ if(istype(MC, /obj/item/mech_component/chassis/forklift))
+ if(arms)
+ arms.forceMove(get_turf(src))
+ arms = null
+ if(head)
+ head.forceMove(get_turf(src))
+ head = null
+ if(legs && !istype(legs, /obj/item/mech_component/propulsion/wheels))
+ legs.forceMove(get_turf(src))
+ legs = null
visible_message(SPAN_NOTICE("\The [user] installs \the [I] into \the [src]."))
playsound(user.loc, 'sound/machines/click.ogg', 50, 1)
return 1
diff --git a/code/modules/mechs/components/head.dm b/code/modules/mechs/components/head.dm
index d18ebd0684c..eb1d7d55a9c 100644
--- a/code/modules/mechs/components/head.dm
+++ b/code/modules/mechs/components/head.dm
@@ -6,6 +6,8 @@
has_hardpoints = list(HARDPOINT_HEAD)
power_use = 15
matter = list(MATERIAL_STEEL = 5, MATERIAL_GLASS = 4)
+ can_gib = TRUE
+ gib_hits_needed = 5
var/vision_flags = NONE
var/see_invisible = 0
var/active_sensors = FALSE
@@ -32,18 +34,19 @@
radio = locate() in src
camera = locate() in src
-/obj/item/mech_component/sensors/proc/get_sight()
+/obj/item/mech_component/sensors/proc/get_sight(powered)
var/flags = 0
- if(total_damage >= 0.8 * max_damage)
+ var/mob/living/exosuit/mech = loc
+ if(total_damage >= 0.8 * max_damage || (!powered && mech.hatch_closed))
flags |= BLIND
else if(active_sensors)
flags |= vision_flags
return flags
-/obj/item/mech_component/sensors/proc/get_invisible()
+/obj/item/mech_component/sensors/proc/get_invisible(powered)
var/invisible = 0
- if((total_damage <= 0.8 * max_damage) && active_sensors)
+ if((total_damage <= 0.8 * max_damage) && active_sensors && powered)
invisible = see_invisible
return invisible
diff --git a/code/modules/mechs/components/legs.dm b/code/modules/mechs/components/legs.dm
index 6e987ab8c5a..980e2ee5252 100644
--- a/code/modules/mechs/components/legs.dm
+++ b/code/modules/mechs/components/legs.dm
@@ -106,3 +106,17 @@
power_use = 100
matter = list(MATERIAL_STEEL = 20, MATERIAL_URANIUM = 8)
can_climb = FALSE
+
+/obj/item/mech_component/propulsion/wheels
+ name = "wheels"
+ exosuit_desc_string = "wheels"
+ desc = "A pair of wheels for any mobile vehicle"
+ icon_state = "wheels"
+ move_delay = 1.5
+ turn_delay = 4
+ max_damage = 60
+ stomp_damage = 15
+ power_use = 10
+ can_strafe = FALSE
+ matter = list(MATERIAL_STEEL = 4, MATERIAL_PLASTIC = 16)
+ can_climb = FALSE
diff --git a/code/modules/mechs/equipment/_equipment.dm b/code/modules/mechs/equipment/_equipment.dm
index d7dc768d600..aec638bad08 100644
--- a/code/modules/mechs/equipment/_equipment.dm
+++ b/code/modules/mechs/equipment/_equipment.dm
@@ -19,6 +19,17 @@
var/active_power_use = 1 KILOWATTS // How much does it consume to perform and accomplish usage
var/passive_power_use = 0 // For gear that for some reason takes up power even if it's supposedly doing nothing (mech will idly consume power)
var/mech_layer = MECH_COCKPIT_LAYER //For the part where it's rendered as mech gear
+ var/active = FALSE
+ var/equipment_flags = 0
+
+/obj/item/mech_equipment/proc/activate()
+ active = TRUE
+
+/obj/item/mech_equipment/proc/deactivate()
+ active = FALSE
+
+/obj/item/mech_equipment/proc/pretick()
+ return FALSE
/obj/item/mech_equipment/attack() //Generally it's not desired to be able to attack with items
return 0
@@ -38,6 +49,8 @@
if(target in owner.contents)
return FALSE
var/obj/item/cell/C = owner.get_cell()
+ if(!C && active_power_use == 0)
+ return TRUE
if(!(C && C.check_charge(active_power_use * CELLRATE)))
to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src]"))
return FALSE
@@ -55,6 +68,8 @@
/obj/item/mech_equipment/attack_self(var/mob/user)
if (owner && loc == owner && ((user in owner.pilots) || user == owner))
var/obj/item/cell/C = owner.get_cell()
+ if(C && active_power_use == 0)
+ return TRUE
if(!(C && C.check_charge(active_power_use * CELLRATE)))
to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src]"))
return FALSE
@@ -130,7 +145,7 @@
/obj/item/mech_equipment/mounted_system/resolve_attackby(atom/A, mob/user, params)
// foward attackbys only when we are installed .
if(ismech(loc))
- return holding.attackby(A, user, params)
+ return A.attackby(holding, user, params)
else ..()
/obj/item/mech_equipment/mounted_system/Destroy()
diff --git a/code/modules/mechs/equipment/combat.dm b/code/modules/mechs/equipment/combat.dm
index 950bb31934e..8d5b57928c1 100644
--- a/code/modules/mechs/equipment/combat.dm
+++ b/code/modules/mechs/equipment/combat.dm
@@ -813,6 +813,8 @@
icon_state = "mech_atmoshield"
restricted_hardpoints = list(HARDPOINT_BACK)
origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 6, TECH_PLASMA = 5)
+ // so it has update icon called everytime it moves
+ equipment_flags = EQUIPFLAG_UPDTMOVE
/// Defines the amount of power drained per hit thats blocked
var/damage_to_power_drain = 30
/// Are we toggled on ?
@@ -830,8 +832,6 @@
visual_bluff.icon_state = "shield_null"
visual_bluff.vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_ID | VIS_INHERIT_PLANE
visual_bluff.layer = ABOVE_ALL_MOB_LAYER
- // the mech default offset is -8 , this neeeds 8 for some reason.
- visual_bluff.pixel_x = 8
/obj/item/mech_equipment/shield_generator/Destroy()
. = ..()
@@ -840,6 +840,14 @@
mech.vis_contents.Remove(visual_bluff)
QDEL_NULL(visual_bluff)
+/obj/item/mech_equipment/shield_generator/uninstalled()
+ owner.vis_contents.Remove(visual_bluff)
+ if(on)
+ on = FALSE
+ update_icon()
+ . = ..()
+
+
/obj/item/mech_equipment/shield_generator/attack_self(mob/user)
. = ..()
if(.)
@@ -848,13 +856,6 @@
last_toggle = world.time
update_icon()
-/obj/item/mech_equipment/shield_generator/proc/updateVisualBluff(targetDir)
- visual_bluff.dir = targetDir
- if(targetDir == NORTH)
- visual_bluff.layer = MECH_UNDER_LAYER
- else
- visual_bluff.layer = MECH_ABOVE_LAYER
-
// Used to tell how effective we are against damage,
/obj/item/mech_equipment/shield_generator/proc/getEffectiveness()
return on
@@ -870,6 +871,11 @@
return
if(!(visual_bluff in mech.vis_contents))
mech.vis_contents.Add(visual_bluff)
+ visual_bluff.dir = mech.dir
+ if(visual_bluff.dir == NORTH)
+ visual_bluff.layer = MECH_UNDER_LAYER
+ else
+ visual_bluff.layer = MECH_ABOVE_LAYER
if(last_toggle > world.time - 1 SECOND)
if(on)
flick("shield_raise", visual_bluff)
@@ -918,7 +924,7 @@
if(!(visual_bluff in _owner.vis_contents))
_owner.vis_contents.Add(visual_bluff)
visual_bluff.icon_state = "mech_shield_[hardpoint]"
- updateVisualBluff(_owner.dir)
+ update_icon()
/obj/item/mech_equipment/shield_generator/ballistic/uninstalled()
owner.vis_contents.Remove(visual_bluff)
@@ -937,50 +943,48 @@
playsound(get_turf(src), 'sound/weapons/shield/shieldblock.ogg', 50, 8)
return damages
-/obj/item/mech_equipment/shield_generator/ballistic/updateVisualBluff(targetDir)
- visual_bluff.dir = targetDir
+/obj/item/mech_equipment/shield_generator/ballistic/update_icon()
+ /// Not needed since we already have handling for visual bluffs layering
+ /// and since we dont use a shield.
+
+ ..(skip = TRUE)
+ var/mob/living/exosuit/mech = loc
+ if(!istype(mech))
+ return
+ if(!(visual_bluff in mech.vis_contents))
+ mech.vis_contents.Add(visual_bluff)
+ visual_bluff.dir = mech.dir
+ visual_bluff.icon_state = "mech_shield_[on ? "on_" : ""][get_hardpoint()]"
switch(get_hardpoint())
if(HARDPOINT_RIGHT_HAND)
// i used a switch before and it doesnt work as intended for some fucking reason FOR EAST AND WEST >:( -SPCR
- if(targetDir == NORTH)
+ if(visual_bluff.dir == NORTH)
visual_bluff.layer = MECH_UNDER_LAYER
- if(targetDir == EAST)
+ if(visual_bluff.dir == EAST)
visual_bluff.layer = MECH_ABOVE_LAYER
- if(targetDir == SOUTH)
+ if(visual_bluff.dir == SOUTH)
visual_bluff.layer = MECH_ABOVE_LAYER
- if(targetDir == WEST)
+ if(visual_bluff.dir == WEST)
visual_bluff.layer = MECH_UNDER_LAYER
return
if(HARDPOINT_LEFT_HAND)
- if(targetDir == NORTH)
+ if(visual_bluff.dir == NORTH)
visual_bluff.layer = MECH_UNDER_LAYER
- if(targetDir == EAST)
+ if(visual_bluff.dir == EAST)
visual_bluff.layer = MECH_UNDER_LAYER
- if(targetDir == SOUTH)
+ if(visual_bluff.dir == SOUTH)
visual_bluff.layer = MECH_ABOVE_LAYER
- if(targetDir == WEST)
+ if(visual_bluff.dir == WEST)
visual_bluff.layer = MECH_ABOVE_LAYER
return
-
-/obj/item/mech_equipment/shield_generator/ballistic/update_icon()
- /// Not needed since we already have handling for visual bluffs layering
- /// and since we dont use a shield.
-
- ..(skip = TRUE)
- var/mob/living/exosuit/mech = loc
- if(!istype(mech))
- return
- if(!(visual_bluff in mech.vis_contents))
- mech.vis_contents.Add(visual_bluff)
- visual_bluff.icon_state = "mech_shield_[get_hardpoint()]"
-
/obj/item/mech_equipment/shield_generator/ballistic/attack_self(mob/user)
var/mob/living/exosuit/mech = loc
if(!istype(mech))
return
to_chat(user , SPAN_NOTICE("[on ? "Retracting" : "Deploying"] \the [src]..."))
- if(do_after(user, 3 SECOND, src, FALSE))
+ var/time = on ? 0.5 SECONDS : 3 SECONDS
+ if(do_after(user, time, src, FALSE))
on = !on
to_chat(user, "You [on ? "deploy" : "retract"] \the [src].")
mech.visible_message(SPAN_DANGER("\The [mech] [on ? "deploys" : "retracts"] \the [src]!"), "", "You hear the sound of a heavy metal plate hitting the floor!", 8)
diff --git a/code/modules/mechs/equipment/medical.dm b/code/modules/mechs/equipment/medical.dm
index 7371290f795..a44242c794b 100644
--- a/code/modules/mechs/equipment/medical.dm
+++ b/code/modules/mechs/equipment/medical.dm
@@ -77,3 +77,150 @@
user.visible_message("\The [user] removes \the [beaker] from \the [src].", "You remove \the [beaker] from \the [src].")
beaker = I
user.visible_message("\The [user] adds \a [I] to \the [src].", "You add \a [I] to \the [src].")
+
+/obj/item/mech_equipment/sleeper/upgraded
+ name = "\improper MK2 mounted sleeper"
+ desc = "An exosuit-mounted sleeper designed to heal patients"
+ origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 3, TECH_BIO = 5)
+ spawn_frequency = 80
+ spawn_blacklisted = FALSE
+ spawn_tags = SPAWN_MECH_QUIPMENT
+ matter = list(MATERIAL_PLASTEEL = 10, MATERIAL_PLASTIC = 10, MATERIAL_GLASS = 5, MATERIAL_SILVER = 3, MATERIAL_PLATINUM = 1)
+
+/obj/item/mech_equipment/sleeper/upgraded/Initialize()
+ . = ..()
+ // delete old one
+ qdel(sleeper)
+ sleeper = new /obj/machinery/sleeper/mounted/upgraded(src)
+ sleeper.forceMove(src)
+
+/obj/machinery/sleeper/mounted/upgraded
+ name = "\improper MK2 mounted sleeper"
+ available_chemicals = list("inaprovaline2" = "Synth-Inaprovaline",
+ "quickclot" = "Quick-Clot",
+ "stoxin" = "Soporific",
+ "tramadol" = "Tramadol",
+ "anti_toxin" = "Dylovene",
+ "dexalin" = "Dexalin",
+ "tricordrazine" = "Tricordrazine",
+ "polystem" = "PolyStem")
+
+/obj/item/mech_equipment/auto_mender
+ name = "\improper exosuit auto-mender"
+ desc = "A mech-designed and equipped medical system for fast and automatic application of advanced trauma treatments to pacients. Makes use of medical gear found in trauma kits."
+ icon_state = "mech_mender"
+ restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND)
+ restricted_software = list(MECH_SOFTWARE_MEDICAL)
+ equipment_delay = 10 //don't spam it on people pls
+ active_power_use = 0 //Usage doesn't really require power.
+ origin_tech = list(TECH_DATA = 3, TECH_BIO = 5, TECH_ENGINEERING = 3)
+ spawn_frequency = 80
+ spawn_blacklisted = FALSE
+ spawn_tags = SPAWN_MECH_QUIPMENT
+ matter = list(MATERIAL_PLASTEEL = 10, MATERIAL_PLASTIC = 10, MATERIAL_SILVER = 8, MATERIAL_GLASS = 5)
+ passive_power_use = 1.5 KILOWATTS
+ var/mob/living/carbon/human/mending_target = null
+ var/mob/living/exosuit/mech = null
+ var/obj/item/organ/external/affecting = null
+ var/trauma_charges_stored = 0
+ var/trauma_storage_max = 30
+
+/obj/item/mech_equipment/auto_mender/afterattack(atom/target, mob/living/user, inrange, params)
+ . = ..()
+ if(. && ishuman(target))
+ if(mending_target == target)
+ mending_target = null
+ to_chat(user, SPAN_NOTICE("You cancel \the [src]'s mending on [target]."))
+ return
+ if(mending_target)
+ to_chat(user, SPAN_NOTICE("\The [src] is already mending someone,you can stop it by clicking the person again!"))
+ return
+ if(!target.Adjacent(mech))
+ to_chat(user, SPAN_NOTICE("You need to be next to \the [target] to start mending them!"))
+ mending_target = target
+ mending_loop()
+
+/obj/item/mech_equipment/auto_mender/attackby(obj/item/I, mob/living/user, params)
+ . = ..()
+ if(istype(I, /obj/item/stack/medical/advanced/bruise_pack))
+ var/obj/item/stack/medical/advanced/bruise_pack/pack = I
+ var/substract = clamp(pack.amount, 0, trauma_storage_max - trauma_charges_stored)
+ if(substract && pack.use(substract))
+ trauma_charges_stored += substract
+ to_chat(user, SPAN_NOTICE("You restock \the [src]'s internal medicine storage with \the [I], using [substract] charges."))
+
+
+/obj/item/mech_equipment/auto_mender/installed(mob/living/exosuit/_owner, hardpoint)
+ . = ..()
+ mech = _owner
+
+/obj/item/mech_equipment/auto_mender/uninstalled()
+ . = ..()
+ mech = null
+
+/obj/item/mech_equipment/auto_mender/proc/mending_loop()
+ if(!mending_target || !mech)
+ return
+ if(!mech.Adjacent(mending_target))
+ mending_target = null
+ affecting = null
+ return
+ var/obj/item/organ/external/checking
+ if(!affecting || (affecting && affecting.is_bandaged()))
+ for(var/zone in BP_ALL_LIMBS)
+ checking = mending_target.organs_by_name[zone]
+ if(checking.is_bandaged() && checking.damage < 1)
+ continue
+ if(affecting)
+ if(checking.damage > affecting.damage)
+ affecting = checking
+ else
+ affecting = checking
+
+ if(!affecting)
+ mending_target = null
+
+ return
+
+ for(var/datum/wound/W in affecting.wounds)
+ if(!mech.Adjacent(mending_target))
+ mending_target = null
+ affecting = null
+ return
+ //if(W.internal || W.bandaged)
+ // continue
+ if(W.damage < 1)
+ continue
+ if(!trauma_charges_stored)
+ break
+ if(!do_mob(mech.get_mob(), mending_target, W.damage/5))
+ to_chat(mech.get_mob(), SPAN_NOTICE("You must stand still to bandage wounds."))
+ mending_target = null
+ affecting = null
+ break
+ //if(W.internal || W.bandaged)
+ // continue
+ if (W.current_stage <= W.max_bleeding_stage)
+ mech.visible_message(
+ SPAN_NOTICE("\The [mech] cleans \a [W.desc] on [mending_target]'s [affecting.name] and seals the edges with bioglue."),
+ SPAN_NOTICE("You clean and seal \a [W.desc] on [mending_target]'s [affecting.name].")
+ )
+ else if (W.damage_type == BRUISE)
+ mech.visible_message(
+ SPAN_NOTICE("\The [mech] places a medical patch over \a [W.desc] on [mending_target]'s [affecting.name]."),
+ SPAN_NOTICE("You place a medical patch over \a [W.desc] on [mending_target]'s [affecting.name].")
+ )
+ else
+ mech.visible_message(
+ SPAN_NOTICE("\The [mech] smears some bioglue over \a [W.desc] on [mending_target]'s [affecting.name]."),
+ SPAN_NOTICE("You smear some bioglue over \a [W.desc] on [mending_target]'s [affecting.name].")
+ )
+ W.bandage()
+ W.heal_damage(10)
+ // If it doesn't cancel or run out of kits just repeat for every external organ.
+ if(affecting.is_bandaged() && affecting.damage < 1)
+ affecting = null
+ mending_loop()
+
+
+
diff --git a/code/modules/mechs/equipment/utility.dm b/code/modules/mechs/equipment/utility.dm
index a1d4ee83dd9..269457e6244 100644
--- a/code/modules/mechs/equipment/utility.dm
+++ b/code/modules/mechs/equipment/utility.dm
@@ -465,3 +465,595 @@
/obj/item/extinguisher/mech/get_hardpoint_status_value()
return reagents.total_volume/max_water
+
+/obj/item/mech_equipment/power_generator
+ name = "debug power generator"
+ desc = "If you see this tell coders to fix code!"
+ icon_state = "mech_power"
+ restricted_hardpoints = list(HARDPOINT_LEFT_SHOULDER, HARDPOINT_RIGHT_SHOULDER)
+ restricted_software = list(MECH_SOFTWARE_UTILITY)
+ equipment_flags = EQUIPFLAG_PRETICK
+ spawn_blacklisted = TRUE
+ var/obj/item/cell/internal_cell
+ /// 50 power per mech life tick , adjust for cell RATE
+ var/generation_rate = 50
+
+/obj/item/mech_equipment/power_generator/Initialize()
+ . = ..()
+ internal_cell = new /obj/item/cell/small
+ internal_cell.matter = list()
+
+/obj/item/mech_equipment/power_generator/attackby(obj/item/I, mob/living/user, params)
+ . = ..()
+ if(istype(I, /obj/item/cell) && !internal_cell)
+ user.drop_from_inventory(I)
+ I.forceMove(src)
+ internal_cell = I
+ to_chat(user, SPAN_NOTICE("You replace [src]'s cell!"))
+ return
+
+/obj/item/mech_equipment/power_generator/pretick()
+ var/ungiven_power = internal_cell?.give(generation_rate)
+ if(owner && internal_cell)
+ var/obj/item/cell/batt = owner.get_cell(TRUE)
+ if(batt && batt != internal_cell)
+ batt.give(internal_cell.use(batt.maxcharge - batt.charge))
+
+ return ungiven_power
+
+/obj/item/mech_equipment/power_generator/fueled
+ name = "fueled debug power generator"
+ // YES WE NEED VISCONTENTS FOR THE ANIMATIONS
+ equipment_flags = EQUIPFLAG_UPDTMOVE | EQUIPFLAG_PRETICK
+ var/fuel_amount = 0
+ var/fuel_max = 1000
+ var/fuel_usage_per_tick = 5
+ var/mode = 0
+ var/datum/repeating_sound/sound_loop = null
+ var/obj/visual_bluff = null
+ spawn_blacklisted = TRUE
+
+/obj/item/mech_equipment/power_generator/fueled/Initialize()
+ . = ..()
+ visual_bluff = new(src)
+ visual_bluff.forceMove(src)
+ visual_bluff.icon = MECH_WEAPON_OVERLAYS_ICON
+ visual_bluff.layer = MECH_ABOVE_LAYER
+
+/obj/item/mech_equipment/power_generator/fueled/pretick()
+ // for when we arențt on
+ if(!mode)
+ sound_loop?.stop()
+ return
+ if(fuel_amount > fuel_usage_per_tick)
+ . = ..()
+ /// if we had a extremely minimal use
+ if(. > generation_rate - generation_rate * 0.01 || . == null)
+ return
+ else
+ fuel_amount -= fuel_usage_per_tick
+ if(QDELETED(sound_loop))
+ sound_loop = new(_interval = 2 SECONDS, duration = 10 SECONDS, interval_variance = 0,
+ _source = owner, _soundin = 'sound/mechs/mech_generator.ogg' , _vol = 25 * mode, _vary = 0, _extrarange = mode * 3,
+ _falloff = 0, _is_global = FALSE, _use_pressure = TRUE)
+ else
+ // extend it artificially.
+ sound_loop.end_time = world.time + 10 SECONDS
+ sound_loop.vol = mode * 25
+ sound_loop.extrarange = mode * 3
+
+/obj/item/mech_equipment/power_generator/fueled/installed(mob/living/exosuit/_owner, hardpoint)
+ . = ..()
+ _owner.tickers.Add(src)
+ _owner.vis_contents.Add(visual_bluff)
+
+/obj/item/mech_equipment/power_generator/fueled/uninstalled()
+ . = ..()
+ owner.tickers.Remove(src)
+ owner.vis_contents.Remove(visual_bluff)
+
+/obj/item/mech_equipment/power_generator/fueled/update_icon()
+ ..()
+ icon_state = "[initial(icon_state)]"
+ visual_bluff.icon_state = "[initial(icon_state)]_[mode ? "on" : ""]_[get_hardpoint()]"
+ if(owner)
+ visual_bluff.dir = owner.dir
+
+/obj/item/mech_equipment/power_generator/fueled/attack_self(mob/user)
+ . = ..()
+ if(. && owner)
+ switch(mode)
+ /// Eco mode , very slow generation but doubled power output ( 20% of power production at cost of 10% of fuel usage)
+ if(0)
+ mode = 1
+ fuel_usage_per_tick = initial(fuel_usage_per_tick) * 0.1
+ generation_rate = initial(generation_rate) * 0.2
+ to_chat(user, SPAN_NOTICE("You switch \the [src]'s power production mode to ECO. 10% Fuel usage, 20% power output."))
+ /// Default
+ if(1)
+ mode = 2
+ fuel_usage_per_tick = initial(fuel_usage_per_tick)
+ generation_rate = initial(generation_rate)
+ to_chat(user, SPAN_NOTICE("You switch \the [src]'s power production mode to NORMAL. 100% Fuel usage, 100% power output."))
+ /// Turbo mode, 2x fuel usage at 1.6x power output
+ if(2)
+ mode = 3
+ fuel_usage_per_tick = initial(fuel_usage_per_tick) * 2
+ generation_rate = initial(generation_rate) * 1.6
+ to_chat(user, SPAN_NOTICE("You switch \the [src]'s power production mode to TURBO. 200% Fuel usage, 160% power output."))
+ /// back to eco.
+ if(3)
+ mode = 0
+ fuel_usage_per_tick = initial(fuel_usage_per_tick)
+ generation_rate = initial(generation_rate)
+ to_chat(user, SPAN_NOTICE("You switch \the [src]'s power production mode to OFF. 0% Fuel usage, 0% power output."))
+ update_icon()
+
+
+/obj/item/mech_equipment/power_generator/fueled/get_hardpoint_maptext()
+ return "[fuel_amount]/[fuel_max] - [fuel_usage_per_tick]"
+
+/obj/item/mech_equipment/power_generator/fueled/plasma
+ name = "plasma powered mech-mountable power generator"
+ desc = "a plasma-fueled mech power generator, creates 5 KW out of 1 sheet of plasma at a rate of 0.25 KW. Fully stocked it generates 35 KW in total."
+ icon_state = "mech_generator_plasma"
+ spawn_frequency = 80
+ spawn_blacklisted = FALSE
+ spawn_tags = SPAWN_MECH_QUIPMENT
+ matter = list(MATERIAL_PLASTEEL = 15, MATERIAL_GLASS = 6, MATERIAL_PLASTIC = 3, MATERIAL_SILVER = 2, MATERIAL_GOLD = 3, MATERIAL_STEEL = 4)
+ origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 5, TECH_POWER = 3)
+ generation_rate = 250
+ // each sheet is 5000 watts
+ fuel_usage_per_tick = 50
+ // 1 sheet = 1000 fuel
+ // 35000 max power out of a fully loaded generator
+ fuel_max = 7000
+
+/obj/item/mech_equipment/power_generator/fueled/plasma/attackby(obj/item/I, mob/living/user, params)
+ . = ..()
+ if(istype(I, /obj/item/stack/material/plasma))
+ var/obj/item/stack/material/plasma/stck = I
+ var/amount_to_use = round((fuel_max - fuel_amount)/1000)
+ amount_to_use = clamp(stck.amount, 0, amount_to_use)
+ if(amount_to_use && stck.use(amount_to_use))
+ fuel_amount += amount_to_use * 1000
+
+/obj/item/mech_equipment/power_generator/fueled/welding
+ name ="welding fuel powered mech-mountable power generator"
+ desc = "a mech mounted generator that runs off welding fuel, creates 1 KW out of 10 units of welding fuel, at a rate of 0.1 KW. Fully stocked it generates 20 KW in total."
+ icon_state = "mech_generator_welding"
+ spawn_frequency = 80
+ spawn_blacklisted = FALSE
+ spawn_tags = SPAWN_MECH_QUIPMENT
+ matter = list(MATERIAL_PLASTEEL = 10, MATERIAL_GLASS = 3, MATERIAL_PLASTIC = 3, MATERIAL_SILVER = 2, MATERIAL_STEEL = 4)
+ origin_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 3, TECH_POWER = 2)
+ generation_rate = 100
+ fuel_usage_per_tick = 1
+ reagent_flags = DRAINABLE | REFILLABLE
+ /// can generate 20000 power
+ fuel_max = 200
+ /// The "explosion" chamber , used for when the fuel is mixed with something else
+ var/datum/reagents/chamberReagent = null
+
+/obj/item/mech_equipment/power_generator/fueled/welding/Initialize()
+ . = ..()
+ // max volume
+ create_reagents(200)
+ chamberReagent = new(1, src)
+
+
+/obj/item/mech_equipment/power_generator/fueled/welding/attackby(obj/item/I, mob/living/user, params)
+ . = ..()
+ /// Only needed when we attack from outside
+ if(owner)
+ if(I.is_drainable() && I.reagents.total_volume)
+ to_chat(user, SPAN_NOTICE("You transfer 10 units of substance from \the [I] to \the [src]'s internal fuel storage."))
+ I.reagents.trans_to_holder(reagents, 10, 1, FALSE)
+ else if(I.reagents && I.reagent_flags & REFILLABLE && user.a_intent == I_GRAB)
+ to_chat(user, SPAN_NOTICE("You drain 10 units of substance from \the [src] to \the [I]."))
+ reagents.trans_to_holder(I.reagents, 10, 1, FALSE)
+ else
+ to_chat(user, SPAN_NOTICE("You need to be on GRAB intent to drain from \the [src]."))
+ else if(I.is_refillable() && reagents.total_volume && user.a_intent == I_GRAB)
+ return FALSE
+ else
+ to_chat(user, SPAN_NOTICE("You need to be on GRAB intent to drain from \the [src]."))
+
+
+/obj/item/mech_equipment/power_generator/fueled/welding/pretick()
+ // dont run if we aren't on
+ if(!mode)
+ sound_loop?.stop()
+ return
+ chamberReagent.clear_reagents()
+ reagents.trans_to_holder(chamberReagent, 1, 1, FALSE)
+ if(chamberReagent.has_reagent("fuel"))
+ var/fuel = chamberReagent.get_reagent_amount("fuel")
+ // for the future just add any other reagent here with + * explosion_power_multiplier
+ var/explosives = chamberReagent.get_reagent_amount("plasma") * 3
+ if(explosives > 0.5)
+ // if its full plasma if just fucking blows instantly
+ health -= maxHealth * (explosives / 3)
+ if(health < 1)
+ owner.remove_system(src, null, TRUE)
+ qdel(src)
+ return
+ // min needed for combustion
+ if(fuel > 0.25)
+ var/amountUsed = internal_cell?.give(generation_rate * fuel)
+ // refund if none of it gets turned into power for qol reasons (its never exact returnal due to float errors)
+ if(amountUsed < generation_rate * 0.1)
+ chamberReagent.trans_to_holder(reagents, 1, 1, FALSE)
+ if(fuel > fuel_usage_per_tick)
+ chamberReagent.trans_id_to(reagents, "fuel", chamberReagent.total_volume - fuel_usage_per_tick, TRUE)
+ if(internal_cell && owner)
+ var/obj/item/cell/batt = owner.get_cell(TRUE)
+ if(batt && batt != internal_cell)
+ batt.give(internal_cell.use(batt.maxcharge - batt.charge))
+ if(QDELETED(sound_loop))
+ sound_loop = new(_interval = 2 SECONDS, duration = 10 SECONDS, interval_variance = 0,
+ _source = owner, _soundin = 'sound/mechs/mech_generator.ogg' , _vol = 25 * mode, _vary = 0, _extrarange = mode * 3,
+ _falloff = 0, _is_global = FALSE, _use_pressure = TRUE)
+ else
+ // extend it artificially.
+ sound_loop.end_time = world.time + 10 SECONDS
+ sound_loop.vol = mode * 25
+ sound_loop.extrarange = mode * 3
+ fuel_amount = reagents.total_volume
+
+/obj/item/mech_equipment/towing_hook
+ name = "mounted towing hook"
+ desc = "A mech mounted towing hook, usually found in cars. Can hook to anything that isn't anchored down."
+ icon_state = "mech_tow"
+ restricted_hardpoints = list(HARDPOINT_BACK)
+ restricted_software = list(MECH_SOFTWARE_UTILITY)
+ origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 4)
+ spawn_frequency = 80
+ spawn_blacklisted = FALSE
+ spawn_tags = SPAWN_MECH_QUIPMENT
+ matter = list(MATERIAL_PLASTEEL = 10, MATERIAL_PLASTIC = 10)
+ var/atom/movable/currentlyTowing = null
+
+/obj/item/mech_equipment/towing_hook/installed(mob/living/exosuit/_owner, hardpoint)
+ . = ..()
+ RegisterSignal(_owner, COMSIG_MOVABLE_MOVED, PROC_REF(onMechMove))
+
+/obj/item/mech_equipment/towing_hook/uninstalled()
+ UnregisterSignal(owner, COMSIG_MOVABLE_MOVED)
+ if(currentlyTowing)
+ UnregisterSignal(currentlyTowing, list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING))
+ currentlyTowing = null
+ . = ..()
+
+/// Yes you can hook onto other mechs that are hooked onto you, and yes it won't break anything , SPCR-2023
+/obj/item/mech_equipment/towing_hook/proc/onTowingMove(atom/movable/mover, atom/oldLocation, atom/newLocation)
+ SIGNAL_HANDLER
+ if(newLocation.Adjacent(src))
+ return
+ UnregisterSignal(mover, list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING))
+ to_chat(owner.get_mob(), SPAN_NOTICE("You lose your hook ono \the [currentlyTowing]!"))
+ currentlyTowing = null
+
+/obj/item/mech_equipment/towing_hook/proc/onMechMove(atom/movable/mover, atom/oldLocation, atom/newLocation)
+ SIGNAL_HANDLER
+ if(!currentlyTowing)
+ return
+ if(!oldLocation.Adjacent(currentlyTowing))
+ UnregisterSignal(currentlyTowing, list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING))
+ to_chat(owner.get_mob(), SPAN_NOTICE("You lose your hook ono \the [currentlyTowing]!"))
+ currentlyTowing = null
+ return
+ // Protection against move loops caused by 2 mechs towing eachother.
+ if(COMSIG_PULL_CANCEL == SEND_SIGNAL(src, COMSIG_ATTEMPT_PULLING))
+ UnregisterSignal(currentlyTowing, list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING))
+ to_chat(owner.get_mob(), SPAN_NOTICE("You lose your hook ono \the [currentlyTowing]!"))
+ currentlyTowing = null
+ return
+ // If we move up a z-level we want to instantly pull it up with us as to prevent possible abuse.
+ // Protection against move loops caused by 2 mechs towing eachother walking diagonally
+ // this gets triggered by z-moves too ,so inbuilt check for that
+ /*
+ if(lastMove > world.time - 0.1 SECONDS)
+ UnregisterSignal(currentlyTowing, list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING))
+ currentlyTowing = null
+ return
+ */
+ if(oldLocation == newLocation)
+ return
+ if(oldLocation.z != newLocation.z)
+ currentlyTowing.forceMove(newLocation)
+ else
+ currentlyTowing.Move(oldLocation)
+
+/// We get supreme priority on pulling
+/obj/item/mech_equipment/towing_hook/proc/onTowingPullAttempt()
+ SIGNAL_HANDLER
+ return COMSIG_PULL_CANCEL
+
+/obj/item/mech_equipment/towing_hook/afterattack(atom/movable/target, mob/living/user, inrange, params)
+ . = ..()
+ if(!owner || target == owner)
+ return
+ if(!istype(target))
+ to_chat(user, SPAN_NOTICE("You cannot hook onto this!"))
+ return
+ if(!currentlyTowing)
+ if(target.Adjacent(src.owner) && !target.anchored)
+ to_chat(user, SPAN_NOTICE("You hook \the [src] onto \the [target]!"))
+ currentlyTowing = target
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(onTowingMove))
+ RegisterSignal(target, COMSIG_ATTEMPT_PULLING, PROC_REF(onTowingPullAttempt))
+ else if(currentlyTowing == target)
+ to_chat(user, SPAN_NOTICE("You unhook \the [src] from \the [target]."))
+ UnregisterSignal(currentlyTowing,list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING))
+ currentlyTowing = null
+ else
+ to_chat(user, SPAN_NOTICE("You are already towing \the [currentlyTowing]. Unhook from it first by attacking it again!"))
+
+/obj/item/mech_equipment/mounted_system/toolkit
+ name = "mounted toolkit"
+ desc = "A automatic suite of tools suited for installation on a mech."
+ icon_state = "mech_tools"
+ holding_type = /obj/item/tool/mech_kit
+ restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND)
+ restricted_software = list(MECH_SOFTWARE_UTILITY)
+ origin_tech = list(TECH_ENGINEERING = 5, TECH_MAGNET = 2, TECH_MATERIAL = 2)
+ matter = list(MATERIAL_PLASTEEL = 25, MATERIAL_PLASTIC = 10, MATERIAL_SILVER = 5)
+ spawn_frequency = 80
+ spawn_blacklisted = FALSE
+ spawn_tags = SPAWN_MECH_QUIPMENT
+
+/obj/item/tool/mech_kit
+ name = "mech toolkit"
+ desc = "A robust selection of mech-sized tools."
+ icon_state = "engimplant"
+ force = WEAPON_FORCE_DANGEROUS
+ worksound = WORKSOUND_DRIVER_TOOL
+ flags = CONDUCT
+ tool_qualities = list(
+ QUALITY_SCREW_DRIVING = 70,
+ QUALITY_BOLT_TURNING = 70,
+ QUALITY_DRILLING = 10,
+ QUALITY_WELDING = 100,
+ QUALITY_CAUTERIZING = 5,
+ QUALITY_PRYING = 100,
+ QUALITY_DIGGING = 50,
+ QUALITY_PULSING = 50,
+ QUALITY_WIRE_CUTTING = 100,
+ QUALITY_HAMMERING = 75)
+ degradation = 0
+ workspeed = 1
+ max_upgrades = 1
+ spawn_blacklisted = TRUE
+
+/// Fancy way to move someone up a z-level if you think about it..
+/obj/item/mech_equipment/forklifting_system
+ name = "forklifting bars"
+ desc = "a set of forklifts bars. Can be used to elevate crates above by a level.. or people! You can forklift a z-level up by attacking this with itself."
+ icon_state = "forklift"
+ restricted_hardpoints = list(HARDPOINT_FRONT)
+ origin_tech = list(TECH_ENGINEERING = 3, TECH_MATERIAL = 2)
+ spawn_frequency = 80
+ spawn_blacklisted = FALSE
+ spawn_tags = SPAWN_MECH_QUIPMENT
+ matter = list(MATERIAL_PLASTEEL = 15, MATERIAL_STEEL = 15, MATERIAL_PLASTIC = 10)
+ equipment_flags = EQUIPFLAG_UPDTMOVE
+ var/atom/movable/currentlyLifting = null
+ var/obj/structure/forklift_platform/platform = null
+ var/lastZ = null
+ var/lastDir = null
+ var/lifted = FALSE
+
+/obj/item/mech_equipment/forklifting_system/Initialize()
+ . = ..()
+ platform = new(NULLSPACE)
+ platform.master = src
+ platform.forceMove(src)
+
+/obj/item/mech_equipment/forklifting_system/Destroy()
+ if(currentlyLifting)
+ ejectLifting(get_turf(src))
+ if(platform)
+ QDEL_NULL(platform)
+ . = ..()
+
+
+/obj/item/mech_equipment/forklifting_system/proc/ejectLifting(atom/target)
+ currentlyLifting.forceMove(target)
+ currentlyLifting.transform = null
+ currentlyLifting.pixel_x = initial(currentlyLifting.pixel_x)
+ currentlyLifting.pixel_y = initial(currentlyLifting.pixel_y)
+ currentlyLifting.mouse_opacity = initial(currentlyLifting.mouse_opacity)
+ owner.vis_contents.Remove(currentlyLifting)
+ var/mob/targ = currentlyLifting
+ targ.update_icon()
+ targ.update_plane()
+ targ.layer = initial(targ.layer)
+ if(ismob(targ) && targ.client)
+ targ.client.perspective = MOB_PERSPECTIVE
+ targ.client.eye = src
+ currentlyLifting = null
+ update_icon()
+
+/obj/item/mech_equipment/forklifting_system/proc/startLifting(atom/movable/target)
+ currentlyLifting = target
+ // No clicking this whilst lifted
+ currentlyLifting.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ currentlyLifting.forceMove(src)
+ var/mob/targ = currentlyLifting
+ if(ismob(targ) && targ.client)
+ targ.client.perspective = EYE_PERSPECTIVE
+ targ.client.eye = src
+ to_chat(targ, SPAN_DANGER("You can resist out of the forklift to instantly get out!"))
+ update_icon()
+
+/obj/item/mech_equipment/forklifting_system/uninstalled()
+ . = ..()
+ if(currentlyLifting)
+ ejectLifting(get_turf(owner))
+
+
+/obj/structure/forklift_platform
+ layer = TURF_LAYER + 0.5
+ icon = MECH_EQUIPMENT_ICON
+ icon_state = "forklift_platform"
+ name = "forklift platform"
+ desc = "A fun way to reach new horizons. Mind the gap between.. small things fall through."
+ density = FALSE
+ anchored = TRUE
+ health = 200
+ var/obj/item/mech_equipment/forklifting_system/master = null
+
+/obj/structure/forklift_platform/Destroy()
+ if(master)
+ master.platform = null
+ master.update_icon()
+ if(master.owner)
+ master.owner.update_icon()
+ master = null
+ . = ..()
+
+/// We can prevent the fall of humans and structures , but everything else will just fall down
+/obj/structure/forklift_platform/can_prevent_fall(above, atom/movable/mover)
+ if(!above)
+ if(ishuman(mover))
+ return TRUE
+ if(isstructure(mover))
+ return TRUE
+ return FALSE
+
+
+/obj/item/mech_equipment/forklifting_system/update_icon()
+ . = ..()
+ if(owner)
+ if(!platform)
+ icon_state = "forklift_platformless"
+ return
+ if(lifted)
+ icon_state = "forklift_lifted"
+ else
+ icon_state = "forklift"
+ if(currentlyLifting)
+ if(!locate(currentlyLifting) in owner.vis_contents)
+ owner.vis_contents.Add(currentlyLifting)
+ if(owner.dir != lastDir)
+ lastDir = owner.dir
+ currentlyLifting.dir = owner.dir
+ if(lastDir == NORTH)
+ currentlyLifting.pixel_x = 8
+ currentlyLifting.pixel_y = 10
+ currentlyLifting.layer = MECH_UNDER_LAYER
+ if(lastDir == EAST)
+ currentlyLifting.pixel_x = 33
+ currentlyLifting.pixel_y = 8
+ currentlyLifting.layer = MECH_ABOVE_LAYER
+ if(lastDir == SOUTH)
+ currentlyLifting.pixel_x = 8
+ currentlyLifting.pixel_y = 0
+ currentlyLifting.layer = MECH_ABOVE_LAYER
+ if(lastDir == WEST)
+ currentlyLifting.pixel_x = -15
+ currentlyLifting.pixel_y = 8
+ currentlyLifting.layer = MECH_ABOVE_LAYER
+ if(owner.z != lastZ)
+ lastZ = owner.z
+ currentlyLifting.z = owner.z
+ currentlyLifting.update_plane()
+
+/obj/item/mech_equipment/forklifting_system/attack_self(mob/user)
+ . = ..()
+ if(!owner)
+ return
+ if(platform)
+ if(!lifted)
+ /// We are checking the turf above first
+ var/turf/aboveSpace = GetAbove(get_turf(owner))
+ if(!aboveSpace)
+ to_chat(user, SPAN_NOTICE("The universe runs out of fabric here! You cannot possibly elevate something here."))
+ return
+ if(!istype(aboveSpace, /turf/simulated/open) || locate(/obj/structure/catwalk) in aboveSpace)
+ to_chat(user, SPAN_NOTICE("Something dense prevents lifting up."))
+ return
+ /// Then the one infront + above
+ aboveSpace = get_step(owner, owner.dir)
+ aboveSpace = GetAbove(aboveSpace)
+ if(!aboveSpace)
+ to_chat(user, SPAN_NOTICE("The universe runs out of fabric here! You cannot possibly elevate something here."))
+ return
+ if(!istype(aboveSpace, /turf/simulated/open) || locate(/obj/structure/catwalk) in aboveSpace)
+ to_chat(user, SPAN_NOTICE("Something dense prevents lifting up."))
+ return
+ to_chat(user, SPAN_NOTICE("You start elevating \the [src] platform."))
+ if(do_after(user, 2 SECONDS, owner, TRUE))
+ to_chat(user, SPAN_NOTICE("You elevate \the [src]'s platform"))
+ platform.dir = owner.dir
+ platform.forceMove(aboveSpace)
+ owner.update_icon()
+ if(currentlyLifting)
+ ejectLifting(aboveSpace)
+ lifted = TRUE
+ else
+ to_chat(user, SPAN_NOTICE("You start retracting the forklift!"))
+ var/turf/targ = get_turf(platform)
+ if(do_after(user, 2 SECONDS, owner, TRUE))
+ if(!platform)
+ return
+ to_chat(user, SPAN_NOTICE("You retract the forklift!"))
+ lifted = FALSE
+ platform.forceMove(src)
+ owner.update_icon()
+ var/atom/whoWeBringingBack
+ /// Pick up the first mob , else just get the last atom returned
+ for(var/atom/movable/A in targ)
+ if(A == platform)
+ continue
+ if(A.anchored)
+ continue
+ if(ismob(A))
+ whoWeBringingBack = A
+ break
+ whoWeBringingBack = A
+ if(whoWeBringingBack)
+ startLifting(whoWeBringingBack)
+ else
+ to_chat(user, SPAN_NOTICE("You can't lift without a platform!"))
+
+/obj/item/mech_equipment/forklifting_system/afterattack(atom/movable/target, mob/living/user, inrange, params)
+ . = ..()
+ if(.)
+ if(currentlyLifting && isturf(target) && inrange)
+ for(var/atom/A in target)
+ if(A.density)
+ to_chat(user, SPAN_NOTICE("[A] is taking up space, preventing you from dropping \the [currentlyLifting] here!"))
+ return
+ ejectLifting(target)
+ return
+ if(currentlyLifting)
+ to_chat(user, SPAN_NOTICE("You are already lifting something!"))
+ return
+ if(!platform)
+ to_chat(user, SPAN_NOTICE("There is no forklift platform to lift on! You should get it replaced"))
+ return
+ if(lifted)
+ to_chat(user, SPAN_NOTICE("You can't lift someone whilst the forklift is lifted!"))
+ return
+ if(inrange && istype(target))
+ if(target.anchored)
+ to_chat(user, SPAN_NOTICE("\The [target] is anchored!"))
+ return
+ if(ismob(target))
+ var/mob/living/trg = target
+ if(trg.mob_size >= MOB_HUGE)
+ to_chat(user, SPAN_NOTICE("\The [target] is far too big to fit on the forklift clamps!"))
+ return
+ to_chat(user, SPAN_NOTICE("You start lifting \the [target] onto the hooks."))
+ if(do_after(user, 2 SECONDS, target))
+ startLifting(target)
+ update_icon()
+
+
+
+
+
+
+
diff --git a/code/modules/mechs/interface/_mech_HUD.dm b/code/modules/mechs/interface/_mech_HUD.dm
index 37f919e9b92..fbaea551813 100644
--- a/code/modules/mechs/interface/_mech_HUD.dm
+++ b/code/modules/mechs/interface/_mech_HUD.dm
@@ -55,9 +55,13 @@
/mob/living/exosuit/proc/update_mech_hud_4(var/mob/living/M)
if(M.client && M != src && HUDneed.len)
if(M in pilots)
- for(var/i in HUDneed) if(HUDneed[i]) M.client.screen |= HUDneed[i]
+ for(var/i in HUDneed)
+ if(HUDneed[i])
+ M.client.screen |= HUDneed[i]
+ var/obj/screen/movable/exosuit/thing = HUDneed[i]
+ thing.update_icon()
M.reset_view(src)
else
for(var/i in HUDneed) if(HUDneed[i]) M.client.screen -= HUDneed[i]
M.update_hud()
- M.check_HUD()
\ No newline at end of file
+ M.check_HUD()
diff --git a/code/modules/mechs/interface/datum_HUD.dm b/code/modules/mechs/interface/datum_HUD.dm
index f6a6f3c1909..c22a0096cda 100644
--- a/code/modules/mechs/interface/datum_HUD.dm
+++ b/code/modules/mechs/interface/datum_HUD.dm
@@ -9,6 +9,7 @@
"mech radio" = list("type" = /obj/screen/movable/exosuit/radio, "loc" = "WEST:4,CENTER-3:58"),
"rename mech" = list("type" = /obj/screen/movable/exosuit/rename, "loc" = "WEST:4,CENTER-3:69"),
"mech camera" = list("type" = /obj/screen/movable/exosuit/toggle/camera, "loc" = "WEST:4,CENTER-3:80"),
+ "mech power switch" = list("type" = /obj/screen/movable/exosuit/toggle/power_control, "loc" = "WEST:4,CENTER-3:-12"),
"mech health" = list("type" = /obj/screen/movable/exosuit/health, "loc" = "WEST:4,BOTTOM+3"),
"mech power" = list("type" = /obj/screen/movable/exosuit/power, "loc" = "WEST+1:4,BOTTOM+3"),
"strafe" = list("type" = /obj/screen/movable/exosuit/toggle/strafe, "loc" = "WEST:4,CENTER-3:92"),
diff --git a/code/modules/mechs/interface/screen_objects.dm b/code/modules/mechs/interface/screen_objects.dm
index 48acaff5c43..ceffb89b6e6 100644
--- a/code/modules/mechs/interface/screen_objects.dm
+++ b/code/modules/mechs/interface/screen_objects.dm
@@ -1,8 +1,11 @@
// Screen objects hereon out.
+
+#define MECH_UI_STYLE(X) "" + X + ""
+
/obj/screen/movable/exosuit
name = "hardpoint"
icon = MECH_HUD_ICON
- icon_state = "hardpoint"
+ icon_state = "base"
var/mob/living/exosuit/owner
/obj/screen/movable/exosuit/proc/on_handle_hud(var/mob/living/exosuit/E)
@@ -13,7 +16,10 @@
/obj/screen/movable/exosuit/radio
name = "radio"
- icon_state = "radio"
+ //icon_state = "radio"
+ maptext = MECH_UI_STYLE("RADIO")
+ maptext_x = 5
+ maptext_y = 12
/obj/screen/movable/exosuit/radio/Click()
if(..())
@@ -22,6 +28,7 @@
/obj/screen/movable/exosuit/hardpoint
name = "hardpoint"
+ icon_state = "hardpoint"
desc = "To activate additional hardpoint's options click on it with shift-button."
var/hardpoint_tag
var/obj/item/holding
@@ -44,6 +51,7 @@
if(holding) holding.screen_loc = screen_loc
/obj/screen/movable/exosuit/hardpoint/proc/update_system_info()
+ maptext = null
// No point drawing it if we have no item to use or nobody to see it.
if(!holding || !owner)
@@ -120,7 +128,9 @@
var/modifiers = params2list(params)
if(modifiers["ctrl"])
if(owner.hardpoints_locked) to_chat(usr, SPAN_WARNING("Hardpoint ejection system is locked."))
- else if(owner.remove_system(hardpoint_tag)) to_chat(usr, SPAN_NOTICE("You disengage and discard the system mounted to your [hardpoint_tag] hardpoint."))
+ else if(owner.remove_system(hardpoint_tag))
+ update_system_info()
+ to_chat(usr, SPAN_NOTICE("You disengage and discard the system mounted to your [hardpoint_tag] hardpoint."))
else to_chat(usr, SPAN_DANGER("You fail to remove the system mounted to your [hardpoint_tag] hardpoint."))
else if(modifiers["shift"] && holding) holding.attack_self(usr)
else if(owner.selected_hardpoint == hardpoint_tag)
@@ -128,16 +138,38 @@
owner.clear_selected_hardpoint()
else if(owner.set_hardpoint(hardpoint_tag)) icon_state = "hardpoint_selected"
+
+/obj/screen/movable/exosuit/toggle/power_control
+ name = "Power control"
+ icon_state = "small_important"
+ maptext = MECH_UI_STYLE("POWER")
+ maptext_x = 3
+ maptext_y = 13
+
+/obj/screen/movable/exosuit/toggle/power_control/toggled()
+ . = ..()
+ owner.toggle_power(usr)
+
+/obj/screen/movable/exosuit/toggle/power_control/update_icon()
+ toggled = (owner.power == MECH_POWER_ON)
+ . = ..()
+
/obj/screen/movable/exosuit/eject
name = "eject"
- icon_state = "eject"
+ //icon_state = "eject"
+ maptext = MECH_UI_STYLE("EJECT")
+ maptext_x = 5
+ maptext_y = 12
/obj/screen/movable/exosuit/eject/Click()
if(..()) owner.eject(usr)
/obj/screen/movable/exosuit/rename
name = "rename"
- icon_state = "rename"
+ //icon_state = "rename"
+ maptext = MECH_UI_STYLE("RENAME")
+ maptext_x = 1
+ maptext_y = 12
/obj/screen/movable/exosuit/power
name = "power"
@@ -146,33 +178,46 @@
maptext_width = 64
maptext_x = 2
maptext_y = 20
- maptext = "power"
+
/obj/screen/movable/exosuit/power/on_handle_hud(var/mob/living/exosuit/E)
. = ..()
if(owner)
var/obj/item/cell/C = owner.get_cell()
- if(C && istype(C)) maptext = "[round(C.charge)]/[round(C.maxcharge)]"
- else maptext = "CHECK POWER"
+ if(C && istype(C)) maptext = MECH_UI_STYLE("[round(C.charge)]/[round(C.maxcharge)]")
+ else maptext = MECH_UI_STYLE("CHECK POWER")
/obj/screen/movable/exosuit/rename/Click()
if(..()) owner.rename(usr)
/obj/screen/movable/exosuit/toggle
name = "toggle"
- var/toggled
+ var/toggled = FALSE
+
+/obj/screen/movable/exosuit/toggle/LateInitialize()
+ . = ..()
+ update_icon()
+
+/obj/screen/movable/exosuit/toggle/update_icon()
+ . = ..()
+ icon_state = "[initial(icon_state)][toggled ? "_enabled" : ""]"
+ maptext = FONT_COLORED(toggled ? COLOR_WHITE : COLOR_GRAY, initial(maptext))
/obj/screen/movable/exosuit/toggle/Click()
if(..()) toggled()
/obj/screen/movable/exosuit/toggle/proc/toggled()
toggled = !toggled
- icon_state = "[initial(icon_state)][toggled ? "_enabled" : ""]"
+ update_icon()
return toggled
/obj/screen/movable/exosuit/toggle/air
name = "air"
- icon_state = "air"
+ //icon_state = "air"
+ icon_state = "small_important"
+ maptext = MECH_UI_STYLE("AIR")
+ maptext_x = 9
+ maptext_y = 13
/obj/screen/movable/exosuit/toggle/air/toggled()
owner.use_air = ..()
@@ -180,7 +225,11 @@
/obj/screen/movable/exosuit/toggle/maint
name = "toggle maintenance protocol"
- icon_state = "maint"
+ //icon_state = "maint"
+ icon_state = "small"
+ maptext = MECH_UI_STYLE("MAINT")
+ maptext_x = 5
+ maptext_y = 13
/obj/screen/movable/exosuit/toggle/maint/toggled()
owner.maintenance_protocols = ..()
@@ -188,7 +237,10 @@
/obj/screen/movable/exosuit/toggle/hardpoint
name = "toggle hardpoint lock"
- icon_state = "hardpoint_lock"
+ //icon_state = "hardpoint_lock"
+ maptext = MECH_UI_STYLE("GEAR")
+ maptext_x = 5
+ maptext_y = 12
/obj/screen/movable/exosuit/toggle/hardpoint/toggled()
owner.hardpoints_locked = ..()
@@ -196,7 +248,10 @@
/obj/screen/movable/exosuit/toggle/hatch
name = "toggle hatch lock"
- icon_state = "hatch_lock"
+ //icon_state = "hatch_lock"
+ maptext = MECH_UI_STYLE("LOCK")
+ maptext_x = 5
+ maptext_y = 12
/obj/screen/movable/exosuit/toggle/hatch/toggled()
if(!owner.hatch_locked && !owner.hatch_closed)
@@ -205,20 +260,39 @@
if(owner.body && owner.body.total_damage >= owner.body.max_damage)
to_chat(usr, SPAN_WARNING("\The body of [owner] is far too damaged to close its hatch!"))
return
- owner.hatch_locked = ..()
+ owner.hatch_locked = owner.toggle_hatch_lock()
to_chat(usr, SPAN_NOTICE("The [owner.body.hatch_descriptor] is [owner.hatch_locked ? "now" : "no longer" ] locked."))
+ update_icon()
+
+/obj/screen/movable/exosuit/toggle/hatch/update_icon()
+ toggled = owner.hatch_locked
+ . = ..()
/obj/screen/movable/exosuit/toggle/hatch_open
name = "open or close hatch"
- icon_state = "hatch_status"
+ //icon_state = "hatch_status"
+ maptext = MECH_UI_STYLE("CLOSE")
+ maptext_x = 4
+ maptext_y = 12
/obj/screen/movable/exosuit/toggle/hatch_open/toggled()
if(owner.hatch_locked && owner.hatch_closed)
to_chat(usr, SPAN_WARNING("You cannot open the hatch while it is locked."))
return
- owner.hatch_closed = ..()
+ owner.hatch_closed = owner.toggle_hatch()
to_chat(usr, SPAN_NOTICE("The [owner.body.hatch_descriptor] is now [owner.hatch_closed ? "closed" : "open" ]."))
owner.update_icon()
+ update_icon()
+
+/obj/screen/movable/exosuit/toggle/hatch_open/update_icon()
+ toggled = owner.hatch_closed
+ . = ..()
+ if(toggled)
+ maptext = MECH_UI_STYLE("OPEN")
+ maptext_x = 5
+ else
+ maptext = MECH_UI_STYLE("CLOSE")
+ maptext_x = 4
// This is basically just a holder for the updates the exosuit does.
/obj/screen/movable/exosuit/health
@@ -268,7 +342,11 @@
//Controls if cameras set the vision flags
/obj/screen/movable/exosuit/toggle/camera
name = "toggle camera matrix"
- icon_state = "camera"
+ //icon_state = "camera"
+ icon_state = "small_important"
+ maptext = MECH_UI_STYLE("SENSOR")
+ maptext_x = 1
+ maptext_y = 13
/obj/screen/movable/exosuit/toggle/camera/toggled()
if(!owner.head)
@@ -277,8 +355,15 @@
if(!owner.head.vision_flags)
to_chat(usr, SPAN_WARNING("Alternative sensor configurations not found. Contact manufacturer for more details."))
return
- owner.head.active_sensors = ..()
+ owner.head.active_sensors = owner.toggle_sensors()
to_chat(usr, SPAN_NOTICE("[owner.head.name] advanced sensor mode is [owner.head.active_sensors ? "now" : "no longer" ] active."))
+ update_icon()
+
+/obj/screen/movable/exosuit/toggle/camera/update_icon()
+ if(owner.head)
+ toggled = owner.head.active_sensors
+ else toggled = FALSE
+ . = ..()
/obj/screen/movable/exosuit/needle
vis_flags = VIS_INHERIT_ID
diff --git a/code/modules/mechs/mech.dm b/code/modules/mechs/mech.dm
index 8fa752ca3bf..8aca6d835c4 100644
--- a/code/modules/mechs/mech.dm
+++ b/code/modules/mechs/mech.dm
@@ -50,6 +50,8 @@
var/list/hardpoints = list()
var/hardpoints_locked
var/maintenance_protocols
+ /// For equipment that has a process based on mech Life tick
+ var/list/obj/item/mech_equipment/tickers = list()
// Material
var/material/material = MATERIAL_STEEL
@@ -73,6 +75,8 @@
var/obj/screen/movable/exosuit/toggle/power_control/hud_power_control
var/obj/screen/movable/exosuit/toggle/camera/hud_camera
+ var/power = MECH_POWER_OFF
+
// Strafing - Is the mech currently strafing?
var/strafing = FALSE
@@ -80,6 +84,26 @@
for(var/mob/i in pilots)
to_chat(i, msg)
+/mob/living/exosuit/proc/toggle_power(mob/living/user)
+ if(power == MECH_POWER_TRANSITION)
+ to_chat(user, SPAN_NOTICE("Power transition in progress. Please wait."))
+ else if(power == MECH_POWER_ON) //Turning it off is instant
+ playsound(src, 'sound/mechs/mech-shutdown.ogg', 100, 0)
+ power = MECH_POWER_OFF
+ else if(get_cell(TRUE))
+ //Start power up sequence
+ power = MECH_POWER_TRANSITION
+ playsound(src, 'sound/mechs/powerup.ogg', 50, 0)
+ if(do_after(user, 1.5 SECONDS, src) && power == MECH_POWER_TRANSITION)
+ playsound(src, 'sound/mechs/nominal.ogg', 50, 0)
+ power = MECH_POWER_ON
+ else
+ to_chat(user, SPAN_WARNING("You abort the powerup sequence."))
+ power = MECH_POWER_OFF
+ //hud_power_control?.queue_icon_update()
+ else
+ to_chat(user, SPAN_WARNING("Error: No power cell was detected."))
+
/*
@@ -138,6 +162,9 @@
if(head && head.radio)
radio = new(src)
+ if(body)
+ opacity = body.opaque_chassis
+
if(LAZYLEN(component_descriptions))
desc = "[desc] It has been built with [english_list(component_descriptions)]."
@@ -197,12 +224,30 @@
to_chat(user, "It menaces with reinforcements of [material].")
to_chat(user, SPAN_NOTICE("You can remove people inside by HARM intent clicking with your hand. The hatch must be opened."))
- to_chat(user, SPAN_NOTICE("You can insert ammo into any ballistic weapon by attacking this with ammunition"))
+ to_chat(user, SPAN_NOTICE("You can eject any module from its UI by CtrlClicking the hardpoint button."))
+ if(body.storage_compartment)
+ to_chat(user, SPAN_NOTICE("You can acces its internal storage by click-dragging onto your character."))
+ if(body && body.cell_charge_rate)
+ to_chat(user, SPAN_NOTICE("This mech can recharge any cell storaged in its internal storage at a rate of [body.cell_charge_rate]."))
+ if(arms && arms.can_force_doors)
+ to_chat(user, SPAN_NOTICE("The arms on this mech can force open any unbolted door."))
+ if(locate(/obj/item/mech_equipment/mounted_system/ballistic) in contents)
+ to_chat(user, SPAN_NOTICE("You can insert ammo into any ballistic weapon by attacking this with ammunition."))
+ if(locate(/obj/item/mech_equipment/auto_mender) in contents)
+ to_chat(user, SPAN_NOTICE("You can refill its auto mender by attacking the mech with trauma kits."))
+ if(locate(/obj/item/mech_equipment/forklifting_system) in contents)
+ to_chat(user, SPAN_NOTICE("You can remove objects from this mech's forklifting system by using grab intent."))
+ if(locate(/obj/item/mech_equipment/towing_hook) in contents)
+ to_chat(user, SPAN_NOTICE("You can remove objects from this mech's towing system by using grab intent."))
+ if(locate(/obj/item/mech_equipment/power_generator/fueled) in contents)
+ to_chat(user, SPAN_NOTICE("You can refill the mounted power generators by attacking \the [src] with the fuel they use."))
+ if(locate(/obj/item/mech_equipment/power_generator/fueled/welding) in contents)
+ to_chat(user, SPAN_NOTICE("You can drain from the mounted fuel welding fuel generator by attacking with a beaker on GRAB intent"))
/mob/living/exosuit/return_air()
if(src && loc)
- if(ispath(body) || !hatch_closed)
+ if(ispath(body) || !hatch_closed || body.pilot_coverage < 100)
var/turf/current_loc = get_turf(src)
return current_loc.return_air()
if(body.pilot_coverage >= 100 && hatch_closed)
@@ -212,14 +257,6 @@
/mob/living/exosuit/GetIdCard()
return access_card
-/mob/living/exosuit/set_dir()
- . = ..()
- if(.)
- update_pilots()
- for(var/obj/item/mech_equipment/shield_generator/gen in contents)
- if(gen && gen.visual_bluff)
- gen.updateVisualBluff(dir)
-
/mob/living/exosuit/proc/return_temperature()
return bodytemperature
diff --git a/code/modules/mechs/mech_construction.dm b/code/modules/mechs/mech_construction.dm
index 900a9690d75..600780d1690 100644
--- a/code/modules/mechs/mech_construction.dm
+++ b/code/modules/mechs/mech_construction.dm
@@ -128,9 +128,10 @@
user.visible_message(SPAN_NOTICE("\The [user] begins trying to remove \the [system] from \the [src]."))
if(!do_after(user, delay, src) || hardpoints[system_hardpoint] != system) return 0
- hardpoints[system_hardpoint] = null
-
if(system_hardpoint == selected_hardpoint) clear_selected_hardpoint()
+ hardpoints[system_hardpoint] = null
+ // Remove this from screens. Would just be left on a player screen before , SPCR - 2023
+ system.screen_loc = null
var/obj/item/mech_equipment/ME = system
if(istype(ME)) ME.uninstalled()
diff --git a/code/modules/mechs/mech_damage.dm b/code/modules/mechs/mech_damage.dm
index 4ac5b950af8..dfb30a50d74 100644
--- a/code/modules/mechs/mech_damage.dm
+++ b/code/modules/mechs/mech_damage.dm
@@ -83,7 +83,12 @@
/mob/living/exosuit/adjustFireLoss(amount, obj/item/mech_component/MC = null)
if(!MC)
- MC = pick(list(arms, legs, body, head))
+ var/list/picklist = list()
+ if(arms) picklist.Add(arms)
+ if(legs) picklist.Add(legs)
+ if(head) picklist.Add(head)
+ if(body) picklist.Add(body)
+ MC = pick(picklist)
if(amount < 1)
return FALSE
MC.take_burn_damage(amount)
@@ -91,7 +96,12 @@
/mob/living/exosuit/adjustBruteLoss(amount, obj/item/mech_component/MC = null)
if(!MC)
- MC = pick(list(arms, legs, body, head))
+ var/list/picklist = list()
+ if(arms) picklist.Add(arms)
+ if(legs) picklist.Add(legs)
+ if(head) picklist.Add(head)
+ if(body) picklist.Add(body)
+ MC = pick(picklist)
if(amount < 1)
return FALSE
MC.take_brute_damage(amount)
@@ -124,6 +134,9 @@
/mob/living/exosuit/bullet_act(obj/item/projectile/P, var/def_zone)
var/hit_dir = get_dir(P.starting, src)
def_zone = zoneToComponent(def_zone)
+ /// aiming for soemthing the mech doesnt have
+ if(!def_zone)
+ return PROJECTILE_FORCE_MISS
if (P.is_hot() >= HEAT_MOBIGNITE_THRESHOLD)
IgniteMob()
diff --git a/code/modules/mechs/mech_interaction.dm b/code/modules/mechs/mech_interaction.dm
index aee217d58ed..fee206731ea 100644
--- a/code/modules/mechs/mech_interaction.dm
+++ b/code/modules/mechs/mech_interaction.dm
@@ -49,15 +49,19 @@
if(A.loc != src && !(get_dir(src, A) & dir))
return
- if(!arms)
- to_chat(user, SPAN_WARNING("\The [src] has no manipulators!"))
- setClickCooldown(3)
- return
-
- if(!arms.motivator || !arms.motivator.is_functional())
- to_chat(user, SPAN_WARNING("Your motivators are damaged! You can't use your manipulators!"))
- setClickCooldown(15)
- return
+ if(!selected_system)
+ if(arms)
+ if(!get_cell()?.checked_use(arms.power_use * CELLRATE))
+ to_chat(user, power == MECH_POWER_ON ? SPAN_WARNING("Error: Power levels insufficient.") : SPAN_WARNING("\The [src] is powered off."))
+ return
+ if(!arms.motivator || !arms.motivator.is_functional())
+ to_chat(user, SPAN_WARNING("Your motivators are damaged! You can't use your manipulators!"))
+ setClickCooldown(15)
+ return
+ else
+ to_chat(user, SPAN_WARNING("\The [src] has no manipulators!"))
+ setClickCooldown(3)
+ return
var/obj/item/cell/cell = get_cell()
if(!cell)
@@ -65,11 +69,6 @@
setClickCooldown(3)
return
- if(!cell.checked_use(arms.power_use * CELLRATE))
- to_chat(user, SPAN_WARNING("Error: Power levels insufficient."))
- setClickCooldown(3)
- return
-
if(istype(selected_system, /obj/item/mech_equipment) && !check_equipment_software(selected_system))
to_chat(user, SPAN_WARNING("Error: No control software was found for [selected_system]."))
setClickCooldown(3)
@@ -110,7 +109,7 @@
var/resolved
if(adj)
- resolved = selected_system.resolve_attackby(A, src, params)
+ resolved = selected_system.resolve_attackby(A, user, params)
if(!resolved && A && selected_system)
selected_system.afterattack(A,user,adj,params)
@@ -124,11 +123,23 @@
if(A == src)
setClickCooldown(5)
return attack_self(user)
- else if(adj)
+ else if(adj && arms)
setClickCooldown(arms_action_delay())
playsound(src.loc, arms.punch_sound, 45 + 25 * (arms.melee_damage / 50), -1)
- if(arms)
+ if(user.a_intent == I_HURT)
return A.attack_generic(src, arms.melee_damage, "attacked")
+ else if(user.a_intent == I_DISARM && arms.can_force_doors)
+ if(istype(A, /obj/machinery/door/airlock))
+ var/obj/machinery/door/airlock/door = A
+ if(!door.locked)
+ to_chat(user, SPAN_NOTICE("You start forcing \the [door] open!"))
+ visible_message(SPAN_WARNING("\The [src] starts forcing \the [door] open!"))
+ playsound(src, 'sound/machines/airlock_creaking.ogg', 100, 1, 5,5)
+ if(do_after(user, 3 SECONDS, A, FALSE))
+ door.open(TRUE)
+ return
+ else
+ return A.attackby(arms, user, params)
/// Checks the mech for places to store the ore.
/mob/living/exosuit/proc/getOreCarrier()
@@ -266,6 +277,7 @@
to_chat(user, SPAN_WARNING("\The [I] could not be installed in that hardpoint."))
return
+ /// Gun reloading handling
if(istype(I, /obj/item/ammo_magazine)|| istype(I, /obj/item/ammo_casing))
if(!maintenance_protocols)
to_chat(user, SPAN_NOTICE("\The [src] needs to be in maintenance mode to reload its guns!"))
@@ -281,21 +293,87 @@
chosen = loadable_guns[chosen]
else
chosen = loadable_guns[loadable_guns[1]]
- switch(chosen.loadMagazine(I,user))
- if(-1)
- to_chat(user, SPAN_NOTICE("\The [chosen] does not accept this type of magazine."))
- if(0)
- to_chat(user, SPAN_NOTICE("\The [chosen] has no slots left in its ammunition storage."))
- if(1)
- to_chat(user, SPAN_NOTICE("You load \the [I] into \the [chosen]."))
- if(2)
- to_chat(user, SPAN_NOTICE("You partially reload one of the existing ammo magazines inside of \the [chosen]."))
-
- else if(user.a_intent != I_HURT)
+ if(chosen)
+ switch(chosen.loadMagazine(I,user))
+ if(-1)
+ to_chat(user, SPAN_NOTICE("\The [chosen] does not accept this type of magazine."))
+ if(0)
+ to_chat(user, SPAN_NOTICE("\The [chosen] has no slots left in its ammunition storage."))
+ if(1)
+ to_chat(user, SPAN_NOTICE("You load \the [I] into \the [chosen]."))
+ if(2)
+ to_chat(user, SPAN_NOTICE("You partially reload one of the existing ammo magazines inside of \the [chosen]."))
+
+ /// Medical mender handling
+ if(istype(I, /obj/item/stack/medical/advanced/bruise_pack))
+ var/list/choices = list()
+ for(var/hardpoint in hardpoints)
+ if(istype(hardpoints[hardpoint], /obj/item/mech_equipment/auto_mender))
+ var/obj/item/mech_equipment/auto_mender/mend = hardpoints[hardpoint]
+ choices["[hardpoint] - [mend.trauma_charges_stored]/[mend.trauma_storage_max] charges"] = mend
+ var/obj/item/mech_equipment/auto_mender/choice = null
+ if(!length(choices))
+ return
+ if(length(choices) == 1)
+ choice = choices[choices[1]]
+ else
+ var/chosenMender = input("Select mech mender to refill") as null|anything in choices
+ if(chosenMender)
+ choice = choices[chosenMender]
+ if(choice)
+ choice.attackby(I, user)
+ return
+
+ /// Plasma generator handling
+ if(istype(I, /obj/item/stack/material/plasma))
+ var/list/choices = list()
+ for(var/hardpoint in hardpoints)
+ if(istype(hardpoints[hardpoint], /obj/item/mech_equipment/power_generator/fueled/plasma))
+ var/obj/item/mech_equipment/power_generator/fueled/plasma/gen = hardpoints[hardpoint]
+ choices["[hardpoint] - [gen.fuel_amount]/[gen.fuel_max]"] = gen
+ var/obj/item/mech_equipment/power_generator/fueled/plasma/chosen = null
+ if(!length(choices))
+ return
+ if(length(choices)==1)
+ chosen = choices[choices[1]]
+ else
+ var/chosenGen = input("Select generator to refill") as null|anything in choices
+ if(chosenGen)
+ chosen = choices[chosenGen]
+ if(chosen)
+ chosen.attackby(I, user)
+ return
+
+ /// Welding generator handling
+ /// Double negation to turn into 0/1 format since if its more than 1 it doesn't count as true.
+ if(I.is_drainable())
+ if(!maintenance_protocols)
+ to_chat(user, SPAN_NOTICE("\The [src] needs to be in maintenance mode for you to refill its internal generator!"))
+ return
+ var/list/choices = list()
+ for(var/hardpoint in hardpoints)
+ if(istype(hardpoints[hardpoint], /obj/item/mech_equipment/power_generator/fueled/welding))
+ var/obj/item/mech_equipment/power_generator/fueled/welding/gen = hardpoints[hardpoint]
+ choices["[hardpoint] - [gen.fuel_amount]/[gen.fuel_max]"] = gen
+ var/obj/item/mech_equipment/power_generator/fueled/welding/chosen = null
+ if(!length(choices))
+ return
+ if(length(choices)==1)
+ chosen = choices[choices[1]]
+ else
+ var/chosenGen = input("Select generator to refill") as null|anything in choices
+ if(chosenGen)
+ chosen = choices[chosenGen]
+ if(chosen)
+ chosen.attackby(I, user)
+ return
+
+
+ else if(user.a_intent != I_HELP)
if(attack_tool(I, user))
return
// we use BP_CHEST cause we dont need to convert targeted organ to mech format def zoning
- else if(user.a_intent == I_HURT && !hatch_closed && get_dir(user, src) == reverse_dir[dir] && get_mob() && !(user in pilots) && user.targeted_organ == BP_CHEST)
+ else if(user.a_intent != I_HELP && !hatch_closed && get_dir(user, src) == reverse_dir[dir] && get_mob() && !(user in pilots) && user.targeted_organ == BP_CHEST)
var/mob/living/target = get_mob()
target.attackby(I, user)
return
@@ -306,8 +384,10 @@
if(!maintenance_protocols)
to_chat(user, SPAN_WARNING("The power cell bay is locked while maintenance protocols are disabled."))
return TRUE
-
- var/obj/item/cell/cell = get_cell()
+ if(!body)
+ to_chat(user, SPAN_NOTICE("\The [src] has no slot for a battery to be installed unto!"))
+ return
+ var/obj/item/cell/cell = body.cell
if(cell)
to_chat(user, SPAN_WARNING("\The [src] already has [cell] installed!"))
return TRUE
@@ -445,13 +525,17 @@
if(QUALITY_PRYING)
- var/obj/item/cell/cell = get_cell()
+ if(!body)
+ to_chat(user, SPAN_NOTICE("\The [src] has no body to pry out a cell from!"))
+ return
+ var/obj/item/cell/cell = body.cell
if(cell)
if(!maintenance_protocols)
to_chat(user, SPAN_WARNING("The power cell bay is locked while maintenance protocols are disabled."))
return TRUE
to_chat(user, SPAN_NOTICE("You start removing [cell] from \the [src]."))
if(do_mob(user, src, 30) && cell == body.cell && body.eject_item(cell, user))
+ power = MECH_POWER_OFF
body.cell = null
return
@@ -469,9 +553,56 @@
if(ABORT_CHECK)
return
+/// Used by hatch lock UI button
+/mob/living/exosuit/proc/toggle_hatch_lock()
+ if(hatch_locked)
+ hatch_locked = FALSE
+ else
+ if(body && body.total_damage >= body.max_damage)
+ return FALSE
+ hatch_locked = TRUE
+ return hatch_locked
+
+/// Used by hatch toggle mech UI button
+/mob/living/exosuit/proc/toggle_hatch()
+ if(hatch_locked)
+ return hatch_closed
+ else
+ hatch_closed = !hatch_closed
+ return hatch_closed
+
+/// Used by camera toglge UI button
+/mob/living/exosuit/proc/toggle_sensors()
+ if(head)
+ if(!head.active_sensors)
+ if(get_cell().drain_power(0,0,head.power_use))
+ head.active_sensors = TRUE
+ return TRUE
+ return FALSE
+ else
+ head.active_sensors = FALSE
+ return FALSE
+ return FALSE
/mob/living/exosuit/attack_hand(mob/living/user)
// Drag the pilot out if possible.
+ if(user.a_intent == I_GRAB)
+ for(var/obj/item/mech_equipment/towing_hook/towing in contents)
+ if(towing.currentlyTowing)
+ to_chat(user, SPAN_NOTICE("You start removing \the [towing.currentlyTowing] from \the [src]'s towing hook."))
+ if(do_after(user, 3 SECONDS, src, TRUE))
+ to_chat(user, SPAN_NOTICE("You remove \the [towing.currentlyTowing] from \the [src]'s towing hook."))
+ towing.UnregisterSignal(towing.currentlyTowing,list(COMSIG_MOVABLE_MOVED,COMSIG_ATTEMPT_PULLING))
+ towing.currentlyTowing = null
+ return
+ for(var/obj/item/mech_equipment/forklifting_system/fork in contents)
+ if(fork.currentlyLifting)
+ to_chat(user, SPAN_NOTICE("You start removing \the [fork.currentlyLifting] from \the [src]'s forklift."))
+ if(do_after(user, 3 SECONDS ,src , TRUE))
+ to_chat(user, SPAN_NOTICE("You remove \the [fork.currentlyLifting] from \the [src]'s forklift!"))
+ fork.ejectLifting(get_turf(user))
+ return
+
if(user.a_intent == I_HURT)
if(!LAZYLEN(pilots))
to_chat(user, SPAN_WARNING("There is nobody inside \the [src]."))
diff --git a/code/modules/mechs/mech_life.dm b/code/modules/mechs/mech_life.dm
index 74cb759ce44..4354609b478 100644
--- a/code/modules/mechs/mech_life.dm
+++ b/code/modules/mechs/mech_life.dm
@@ -13,23 +13,64 @@
update_pilots()
if(radio)
- radio.on = (head && head.radio && head.radio.is_functional())
+ radio.on = (head && head.radio && head.radio.is_functional() && get_cell())
- body.update_air(hatch_closed && use_air)
+ var/powered = FALSE
+ var/obj/item/cell/mech_cell = get_cell()
+ for(var/hardpoint in hardpoints)
+ var/obj/item/mech_equipment/equip = hardpoints[hardpoint]
+ if(QDELETED(equip))
+ continue
+ if(!(equip.equipment_flags & EQUIPFLAG_PRETICK))
+ continue
+ equip.pretick()
+
+ if(mech_cell)
+ powered = mech_cell.drain_power(0, 0, calc_power_draw()) > 0
+
+ if(!powered)
+ //Shut down all systems
+ if(head)
+ head.active_sensors = FALSE
+ for(var/hardpoint in hardpoints)
+ var/obj/item/mech_equipment/M = hardpoints[hardpoint]
+ if(istype(M) && M.active && M.passive_power_use)
+ M.deactivate()
+ // for chassis charging cells
+ var/chargeUsed = 0
+ if(powered && body && body.cell_charge_rate && mech_cell.charge > 1000)
+ for(var/obj/item/cell/to_charge in body.storage_compartment)
+ if(mech_cell.charge < 1000)
+ break
+ if(chargeUsed > body.cell_charge_rate)
+ break
+ var/chargeNeeded = min(to_charge.maxcharge - to_charge.charge, body.cell_charge_rate)
+ if(!chargeNeeded)
+ continue
+ chargeUsed += to_charge.give(mech_cell.drain_power(0,0, chargeNeeded / CELLRATE))
- if((client || LAZYLEN(pilots)) && get_cell())
- var/obj/item/cell/c = get_cell()
- c.drain_power(0, 0, calc_power_draw())
+
+ body.update_air(hatch_closed && use_air)
updatehealth()
if(health <= 0 && stat != DEAD)
death()
. = ..() //Handles stuff like environment
lying = FALSE // Fuck off, carp.
- handle_vision()
+ handle_vision(powered)
+
+/mob/living/exosuit/get_cell(force)
+ RETURN_TYPE(/obj/item/cell)
+
+ if(power == MECH_POWER_ON || force) //For most intents we can assume that a powered off exosuit acts as if it lacked a cell
+ . = body ? body.cell : null
+ if(!.)
+ for(var/obj/item/mech_equipment/power_generator/gen in tickers)
+ if(!. && gen.internal_cell)
+ . = gen.internal_cell
+ return .
+ return null
-/mob/living/exosuit/get_cell()
- return body?.get_cell()
/mob/living/exosuit/proc/calc_power_draw()
//Passive power stuff here. You can also recharge cells or hardpoints if those make sense
@@ -38,7 +79,8 @@
var/obj/item/mech_equipment/I = hardpoints[hardpoint]
if(!istype(I))
continue
- total_draw += I.passive_power_use
+
+ total_draw += I.active ? I.active_power_use : I.passive_power_use
if(head && head.active_sensors)
total_draw += head.power_use
@@ -77,14 +119,18 @@
var/obj/wreck = new wreckage_path(drop_location(), src, gibbed)
wreck.name = "wreckage of \the [name]"
if(!gibbed)
- if(arms.loc != src)
- arms = null
- if(legs.loc != src)
- legs = null
- if(head.loc != src)
- head = null
- if(body.loc != src)
- body = null
+ if(arms)
+ if(arms.loc != src)
+ arms = null
+ if(legs)
+ if(legs.loc != src)
+ legs = null
+ if(head)
+ if(head.loc != src)
+ head = null
+ if(body)
+ if(body.loc != src)
+ body = null
// Handle the rest of things.
..(gibbed, (gibbed ? "explodes!" : "grinds to a halt before collapsing!"))
@@ -116,10 +162,12 @@
qdel(src)
return
-/mob/living/exosuit/handle_vision()
+/mob/living/exosuit/handle_vision(powered)
if(head)
- sight = head.get_sight()
- see_invisible = head.get_invisible()
+ sight = head.get_sight(powered)
+ see_invisible = head.get_invisible(powered)
+ else if(hatch_closed)
+ sight &= BLIND
if(body && (body.pilot_coverage < 100 || body.transparent_cabin) || !hatch_closed)
sight &= ~BLIND
diff --git a/code/modules/mechs/mech_movement.dm b/code/modules/mechs/mech_movement.dm
index dac935b20b4..40663ce6d1c 100644
--- a/code/modules/mechs/mech_movement.dm
+++ b/code/modules/mechs/mech_movement.dm
@@ -40,6 +40,25 @@
victim.forceMove(theDepths)
visible_message("The [src] pushes [victim] downwards.")
occupant_message("You can feel \the [src] step onto something.")
+ for(var/hardpoint in hardpoints)
+ if(!hardpoints[hardpoint])
+ continue
+ var/obj/item/mech_equipment/thing = hardpoints[hardpoint]
+ if(!(thing.equipment_flags & EQUIPFLAG_UPDTMOVE))
+ continue
+ thing.update_icon()
+
+/mob/living/exosuit/set_dir()
+ . = ..()
+ if(.)
+ update_pilots()
+ for(var/hardpoint in hardpoints)
+ if(!hardpoints[hardpoint])
+ continue
+ var/obj/item/mech_equipment/thing = hardpoints[hardpoint]
+ if(!(thing.equipment_flags & EQUIPFLAG_UPDTMOVE))
+ continue
+ thing.update_icon()
/mob/living/exosuit/get_jetpack()
for(var/hardpoint_thing in hardpoints)
@@ -178,11 +197,17 @@
/mob/living/exosuit/proc/moveBlocked()
for(var/hardpoint in hardpoints)
- var/obj/item/mech_equipment/shield_generator/ballistic/blocker = hardpoints[hardpoint]
- if(!istype(blocker))
- continue
- if(blocker.on)
- return "\The [blocker] is deployed! Immobilizing you. "
+ var/obj/item/mech_equipment/equip = hardpoints[hardpoint]
+ if(equip)
+ switch(equip.type)
+ if(/obj/item/mech_equipment/shield_generator/ballistic)
+ var/obj/item/mech_equipment/shield_generator/ballistic/blocker = equip
+ if(blocker.on)
+ return "\The [blocker] is deployed! Immobilizing you. "
+ if(/obj/item/mech_equipment/forklifting_system)
+ var/obj/item/mech_equipment/forklifting_system/fork = equip
+ if(fork.lifted)
+ return "\The [fork] is lifted, locking you in place!"
return ""
diff --git a/code/modules/mechs/premade/_premade.dm b/code/modules/mechs/premade/_premade.dm
index 5f36892beb3..49ddd4f4df3 100644
--- a/code/modules/mechs/premade/_premade.dm
+++ b/code/modules/mechs/premade/_premade.dm
@@ -26,10 +26,14 @@
/mob/living/exosuit/premade/Initialize()
- arms = new arms(src)
- body = new body(src)
- head = new head(src)
- legs = new legs(src)
+ if(arms)
+ arms = new arms(src)
+ if(body)
+ body = new body(src)
+ if(head)
+ head = new head(src)
+ if(legs)
+ legs = new legs(src)
for(var/obj/item/mech_component/C in list(arms, legs, head, body))
if(decal)
diff --git a/code/modules/mechs/premade/powerloader.dm b/code/modules/mechs/premade/powerloader.dm
index 4475beb9411..c94f8775d30 100644
--- a/code/modules/mechs/premade/powerloader.dm
+++ b/code/modules/mechs/premade/powerloader.dm
@@ -44,3 +44,21 @@
HARDPOINT_RIGHT_HAND = /obj/item/mech_equipment/mounted_system/extinguisher,
HARDPOINT_HEAD = /obj/item/mech_equipment/light,
)
+
+/mob/living/exosuit/premade/forklift
+ name = "Aster's Guild \"Forklift\""
+ desc = "A modernized forklift for usage on space-ships. Are you ready to lift?"
+ rarity_value = 40
+ material = MATERIAL_PLASTIC
+ installed_armor = /obj/item/robot_parts/robot_component/armour/exosuit/plain
+ exosuit_color = "#c6c37b"
+ body = /obj/item/mech_component/chassis/forklift
+ legs = /obj/item/mech_component/propulsion/wheels
+ arms = null
+ head = null
+ installed_software_boards = list(
+ /obj/item/electronics/circuitboard/exosystem/utility
+ )
+ installed_systems = list(
+ HARDPOINT_FRONT = /obj/item/mech_equipment/forklifting_system
+ )
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 9f6e69b5ade..36764b163a6 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -112,6 +112,10 @@
process_glasses(G,TRUE)
/mob/living/carbon/human/reset_layer()
+ /// The forklift handles it for us here.
+ if(istype(loc, /obj/item/mech_equipment/forklifting_system))
+ if(lying) set_plane(LYING_HUMAN_PLANE)
+ return
if(hiding)
set_plane(HIDING_MOB_PLANE)
layer = HIDING_MOB_LAYER
diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm
index d3604bcf7eb..0c0c56467d9 100644
--- a/code/modules/mob/living/carbon/resist.dm
+++ b/code/modules/mob/living/carbon/resist.dm
@@ -14,6 +14,11 @@
escape_inventory(src.loc)
return
+ if(istype(loc, /obj/item/mech_equipment/forklifting_system))
+ var/obj/item/mech_equipment/forklifting_system/fork = loc
+ fork.ejectLifting(get_turf(fork))
+ return
+
//unbuckling yourself
if(buckled)
if (buckled.resist_buckle(src))
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 68d451ddc45..30b67f081e2 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -91,8 +91,8 @@
messageturfs += turf
-
-
+
+
for(var/mob/M in getMobsInRangeChunked(get_turf(src), range, FALSE, TRUE))
if(!M.client)
continue
@@ -610,6 +610,11 @@
to_chat(src, "It won't budge!")
return
+ if(SEND_SIGNAL(AM, COMSIG_ATTEMPT_PULLING) == COMSIG_PULL_CANCEL)
+ to_chat(src, SPAN_WARNING("It won't budge!"))
+ return
+
+
var/mob/M = AM
if(ismob(AM))
diff --git a/code/modules/multiz/structures.dm b/code/modules/multiz/structures.dm
index 17377ed1302..59ad0902313 100644
--- a/code/modules/multiz/structures.dm
+++ b/code/modules/multiz/structures.dm
@@ -242,6 +242,10 @@
icon_state = "ramptop"
layer = 2.4
+/obj/structure/multiz/stairs/can_prevent_fall(above)
+ return above ? FALSE : TRUE
+
+
/obj/structure/multiz/stairs/enter
icon_state = "ramptop"
diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm
index 57f1b12bc1f..da01d672368 100755
--- a/code/modules/multiz/turf.dm
+++ b/code/modules/multiz/turf.dm
@@ -90,14 +90,14 @@ see multiz/movement.dm for some info.
if(!below)
return
- if(catwalk != (locate(/obj/structure/catwalk) in src))
- return
-
- if(locate(/obj/structure/multiz/stairs) in src)
- return
+ /// If anything on our turf stops falls downwards
+ for(var/atom/A in contents)
+ if(A.can_prevent_fall(FALSE, null))
+ return
+ /// If anything below stops falls from above
for(var/atom/A in below)
- if(A.can_prevent_fall())
+ if(A.can_prevent_fall(TRUE,null))
return
return TRUE
@@ -117,6 +117,10 @@ see multiz/movement.dm for some info.
P.height = HEIGHT_LOW // We are shooting from above, this protects windows from damage
return // We are done here
+ for(var/atom/A in contents)
+ if(A.can_prevent_fall(FALSE, mover))
+ return
+
if(!mover.can_fall())
return
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index d47f4372d37..70987683fec 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -135,7 +135,6 @@
explode()
return FALSE
- if(maxcharge < amount) return FALSE
var/amount_used = min(maxcharge-charge,amount)
charge += amount_used
update_icon()
diff --git a/code/modules/research/designs/mechs2/exosuits_components.dm b/code/modules/research/designs/mechs2/exosuits_components.dm
index c3be59c7d8b..38fe446e2c7 100644
--- a/code/modules/research/designs/mechs2/exosuits_components.dm
+++ b/code/modules/research/designs/mechs2/exosuits_components.dm
@@ -86,6 +86,9 @@
/datum/design/research/item/mechfab/exosuit/chassis/pod
build_path = /obj/item/mech_component/chassis/pod
+/datum/design/research/item/mechfab/exosuit/chassis/forklift
+ build_path = /obj/item/mech_component/chassis/forklift
+
//Manipulators
/datum/design/research/item/mechfab/exosuit/manipulators
category = "Exosuit Manipulators"
@@ -124,3 +127,6 @@
/datum/design/research/item/mechfab/exosuit/propulsion/tracks
build_path = /obj/item/mech_component/propulsion/tracks
+
+/datum/design/research/item/mechfab/exosuit/propulsion/wheels
+ build_path = /obj/item/mech_component/propulsion/wheels
diff --git a/code/modules/research/designs/mechs2/exosuits_equipment.dm b/code/modules/research/designs/mechs2/exosuits_equipment.dm
index bd0fc4305d9..ee9afd41de1 100644
--- a/code/modules/research/designs/mechs2/exosuits_equipment.dm
+++ b/code/modules/research/designs/mechs2/exosuits_equipment.dm
@@ -88,13 +88,40 @@
name = "mounted ion thrusters"
build_path = /obj/item/mech_equipment/thrusters
+/datum/design/research/item/exosuit/forklift
+ name = "forklift clamps"
+ build_path = /obj/item/mech_equipment/forklifting_system
+
+/datum/design/research/item/exosuit/fuel_generator
+ name = "welding fuel mech generator"
+ build_path = /obj/item/mech_equipment/power_generator/fueled/welding
+
+/datum/design/research/item/exosuit/plasma_generator
+ name = "plasma mech generator"
+ build_path = /obj/item/mech_equipment/power_generator/fueled/plasma
+
+/datum/design/research/item/exosuit/towing_hook
+ name = "mech towing hook"
+ build_path = /obj/item/mech_equipment/towing_hook
+
//MEDICAL
/datum/design/research/item/exosuit/sleeper
name = "mounted sleeper"
build_path = /obj/item/mech_equipment/sleeper
+/datum/design/research/item/exosuit/sleeper/upgraded
+ name = "mounted sleeper MK2"
+ build_path = /obj/item/mech_equipment/sleeper/upgraded
+
+/datum/design/research/item/exosuit/automender
+ name = "mech auto-mender"
+ build_path = /obj/item/mech_equipment/auto_mender
//ENGINEERING
/datum/design/research/item/exosuit/rcd
name = "mounted RCD"
build_path = /obj/item/mech_equipment/mounted_system/rcd
+
+/datum/design/research/item/exosuit/toolkit
+ name = "mounted toolkit"
+ build_path = /obj/item/mech_equipment/mounted_system/toolkit
diff --git a/code/modules/research/nodes/robotics.dm b/code/modules/research/nodes/robotics.dm
index d7c8377b1ce..94bd7401670 100644
--- a/code/modules/research/nodes/robotics.dm
+++ b/code/modules/research/nodes/robotics.dm
@@ -60,7 +60,9 @@
/datum/design/research/item/mechfab/exosuit/sensors/light,
/datum/design/research/item/mechfab/exosuit/chassis/light,
/datum/design/research/item/mechfab/exosuit/manipulators/light,
- /datum/design/research/item/mechfab/exosuit/propulsion/light
+ /datum/design/research/item/mechfab/exosuit/propulsion/light,
+ /datum/design/research/item/mechfab/exosuit/propulsion/wheels,
+ /datum/design/research/item/mechfab/exosuit/chassis/forklift
)
@@ -205,7 +207,9 @@
unlocks_designs = list(
/datum/design/research/circuit/exosuit/medical,
- /datum/design/research/item/exosuit/sleeper
+ /datum/design/research/item/exosuit/sleeper,
+ /datum/design/research/item/exosuit/sleeper/upgraded,
+ /datum/design/research/item/exosuit/automender
)
/datum/technology/mech_utility_modules
@@ -231,7 +235,13 @@
/datum/design/research/item/mechfab/exosuit/drillbit/steel,
/datum/design/research/item/mechfab/exosuit/drillbit/plasteel,
/datum/design/research/item/mechfab/exosuit/drillbit/diamond,
- /datum/design/research/item/exosuit/ion_thruster
+ /datum/design/research/item/exosuit/ion_thruster,
+ /datum/design/research/item/exosuit/forklift,
+ /datum/design/research/item/exosuit/fuel_generator,
+ /datum/design/research/item/exosuit/plasma_generator,
+ /datum/design/research/item/exosuit/towing_hook,
+ /datum/design/research/item/exosuit/rcd,
+ /datum/design/research/item/exosuit/toolkit
)
/datum/technology/mech_teleporter_modules
diff --git a/icons/mechs/bshield.dmi b/icons/mechs/bshield.dmi
index dda9fa60bc9..2f998c7a7f3 100644
Binary files a/icons/mechs/bshield.dmi and b/icons/mechs/bshield.dmi differ
diff --git a/icons/mechs/mech_equipment.dmi b/icons/mechs/mech_equipment.dmi
index 78cddcd85c4..0c2c6540a36 100644
Binary files a/icons/mechs/mech_equipment.dmi and b/icons/mechs/mech_equipment.dmi differ
diff --git a/icons/mechs/mech_hud.dmi b/icons/mechs/mech_hud.dmi
index 029be31e2e4..2d86a4aaef9 100644
Binary files a/icons/mechs/mech_hud.dmi and b/icons/mechs/mech_hud.dmi differ
diff --git a/icons/mechs/mech_parts.dmi b/icons/mechs/mech_parts.dmi
index 581b5456b67..218142a2e95 100644
Binary files a/icons/mechs/mech_parts.dmi and b/icons/mechs/mech_parts.dmi differ
diff --git a/icons/mechs/mech_parts_held.dmi b/icons/mechs/mech_parts_held.dmi
index 0276b3fb0aa..76494a5d865 100644
Binary files a/icons/mechs/mech_parts_held.dmi and b/icons/mechs/mech_parts_held.dmi differ
diff --git a/icons/mechs/mech_weapon_overlays.dmi b/icons/mechs/mech_weapon_overlays.dmi
index 28f0eb261bc..c5f97e07556 100644
Binary files a/icons/mechs/mech_weapon_overlays.dmi and b/icons/mechs/mech_weapon_overlays.dmi differ
diff --git a/icons/mechs/shield.dmi b/icons/mechs/shield.dmi
index a2d5131a605..c46b5a5ac62 100644
Binary files a/icons/mechs/shield.dmi and b/icons/mechs/shield.dmi differ
diff --git a/sound/mechs/mech-shutdown.ogg b/sound/mechs/mech-shutdown.ogg
new file mode 100644
index 00000000000..9733bb26df5
Binary files /dev/null and b/sound/mechs/mech-shutdown.ogg differ
diff --git a/sound/mechs/mech_generator.ogg b/sound/mechs/mech_generator.ogg
new file mode 100644
index 00000000000..16b178d05ce
Binary files /dev/null and b/sound/mechs/mech_generator.ogg differ