diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index 8904c0295abf..c0ccd5164b0b 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -83,10 +83,15 @@
#define ABOVE_SPECIAL_RESIN_STRUCTURE_LAYER 3.01
+/// A layer above objects (like structures) but below items
+#define BETWEEN_OBJECT_ITEM_LAYER 3.01
+
+/// The layer on which items lay
+#define ITEM_LAYER 3.02
/// for items that should be at the top of the pile of items
-#define UPPER_ITEM_LAYER 3.01
+#define UPPER_ITEM_LAYER 3.03
/// just above all items
-#define ABOVE_OBJ_LAYER 3.02
+#define ABOVE_OBJ_LAYER 3.04
#define BUSH_LAYER 3.05
diff --git a/code/game/machinery/fax_machine.dm b/code/game/machinery/fax_machine.dm
index 783d24c00f2e..ff26ce802b08 100644
--- a/code/game/machinery/fax_machine.dm
+++ b/code/game/machinery/fax_machine.dm
@@ -396,7 +396,7 @@ var/list/alldepartments = list()
P.stamps += "
This paper has been stamped by the USCM High Command Quantum Relay."
if("NC4 UA Federal Secure Network - CMB Relay")
var/image/stampoverlay = image('icons/obj/items/paper.dmi')
- stampoverlay.icon_state = "paper_stamp-uscm" // placeholder icon
+ stampoverlay.icon_state = "paper_stamp-cmb"
if(!P.stamped)
P.stamped = new
P.stamped += /obj/item/tool/stamp
@@ -404,7 +404,7 @@ var/list/alldepartments = list()
P.stamps += "
This paper has been stamped by The Office of Colonial Marshals."
if("Weyland-Yutani Quantum Relay")
var/image/stampoverlay = image('icons/obj/items/paper.dmi')
- stampoverlay.icon_state = "paper_stamp-cent"
+ stampoverlay.icon_state = "paper_stamp-weyyu"
if(!P.stamped)
P.stamped = new
P.stamped += /obj/item/tool/stamp
diff --git a/code/game/objects/effects/landmarks/corpsespawner.dm b/code/game/objects/effects/landmarks/corpsespawner.dm
index bcedcb85f47e..fe338bceabfe 100644
--- a/code/game/objects/effects/landmarks/corpsespawner.dm
+++ b/code/game/objects/effects/landmarks/corpsespawner.dm
@@ -48,10 +48,6 @@
name = "Engineer"
equip_path = /datum/equipment_preset/corpse/engineer
-/obj/effect/landmark/corpsespawner/clown
- name = "Clown"
- equip_path = /datum/equipment_preset/corpse/clown
-
/obj/effect/landmark/corpsespawner/scientist
name = "Scientist"
equip_path = /datum/equipment_preset/corpse/scientist
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index f497bc20ba83..2ad355d98bbb 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -2,8 +2,8 @@
name = "item"
icon = 'icons/obj/items/items.dmi'
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
+ layer = ITEM_LAYER
light_system = MOVABLE_LIGHT
-
/// this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite
var/image/blood_overlay = null
var/randpixel = 6
diff --git a/code/game/objects/items/tools/misc_tools.dm b/code/game/objects/items/tools/misc_tools.dm
index 505006285881..b5be55eed540 100644
--- a/code/game/objects/items/tools/misc_tools.dm
+++ b/code/game/objects/items/tools/misc_tools.dm
@@ -420,12 +420,20 @@
name = "internal affairs rubber stamp"
icon_state = "stamp-intaff"
-/obj/item/tool/stamp/centcomm
- name = "centcomm rubber stamp"
- icon_state = "stamp-cent"
+/obj/item/tool/stamp/weyyu
+ name = "WY rubber stamp"
+ icon_state = "stamp-weyyu"
+
+/obj/item/tool/stamp/uscm
+ name = "USCM rubber stamp"
+ icon_state = "stamp-uscm"
+
+/obj/item/tool/stamp/cmb
+ name = "CMB rubber stamp"
+ icon_state = "stamp-cmb"
/obj/item/tool/stamp/ro
- name = "requisitions officer's rubber stamp"
+ name = "quartermaster's rubber stamp"
icon_state = "stamp-ro"
/obj/item/tool/carpenters_hammer //doesn't do anything, yet
diff --git a/code/game/objects/structures/crates_lockers/closets/coffin.dm b/code/game/objects/structures/crates_lockers/closets/coffin.dm
index a0c1aade6d73..41c27ae47519 100644
--- a/code/game/objects/structures/crates_lockers/closets/coffin.dm
+++ b/code/game/objects/structures/crates_lockers/closets/coffin.dm
@@ -6,6 +6,7 @@
icon_opened = "coffin_open"
material = MATERIAL_WOOD
anchored = FALSE
+ layer = BETWEEN_OBJECT_ITEM_LAYER
/obj/structure/closet/coffin/update_icon()
if(!opened)
diff --git a/code/modules/admin/topic/topic.dm b/code/modules/admin/topic/topic.dm
index a76be10e9c26..d7f6d7159675 100644
--- a/code/modules/admin/topic/topic.dm
+++ b/code/modules/admin/topic/topic.dm
@@ -1502,7 +1502,7 @@
// Stamps
var/image/stampoverlay = image('icons/obj/items/paper.dmi')
- stampoverlay.icon_state = "paper_stamp-cent"
+ stampoverlay.icon_state = "paper_stamp-weyyu"
if(!P.stamped)
P.stamped = new
P.stamped += /obj/item/tool/stamp
@@ -1584,7 +1584,7 @@
// Stamps
var/image/stampoverlay = image('icons/obj/items/paper.dmi')
- stampoverlay.icon_state = "paper_stamp-cent"
+ stampoverlay.icon_state = "paper_stamp-cmb"
if(!P.stamped)
P.stamped = new
P.stamped += /obj/item/tool/stamp
diff --git a/code/modules/cm_aliens/weeds.dm b/code/modules/cm_aliens/weeds.dm
index 01140beae304..eb4fc3cd6f09 100644
--- a/code/modules/cm_aliens/weeds.dm
+++ b/code/modules/cm_aliens/weeds.dm
@@ -193,13 +193,16 @@
// If you're still confused, scroll aaaall the way down to the bottom of the file.
// that's /obj/effect/alien/weeds/node/Destroy().
/obj/effect/alien/weeds/proc/avoid_orphanage()
- for(var/obj/effect/alien/weeds/node/N in orange(node_range, get_turf(src)))
- // WE FOUND A NEW MOMMY
- N.add_child(src)
- break
+ var/parent_type = /obj/effect/alien/weeds/node
+ if(weed_strength >= WEED_LEVEL_HIVE)
+ parent_type = /obj/effect/alien/weeds/node/pylon
+
+ var/obj/effect/alien/weeds/node/found = locate(parent_type) in orange(node_range, get_turf(src))
+ if(found)
+ found.add_child(src)
// NO MORE FOOD ON THE TABLE. WE DIE
- if(!parent || weed_strength > WEED_LEVEL_STANDARD)
+ if(!parent)
qdel(src)
/obj/effect/alien/weeds/proc/weed_expand()
diff --git a/code/modules/cm_marines/codebook.dm b/code/modules/cm_marines/codebook.dm
index 08e1b4352bcf..11013f764538 100644
--- a/code/modules/cm_marines/codebook.dm
+++ b/code/modules/cm_marines/codebook.dm
@@ -1,24 +1,56 @@
+GLOBAL_LIST_EMPTY(codebook_data)
-/obj/item/book/codebook
- name = "Almayer Code Book"
- unique = 1
- dat = ""
+/obj/item/book/codebook/proc/create_codebook(faction = FACTION_MARINE)
+ if(!GLOB.codebook_data[faction])
+ GLOB.codebook_data[faction] = generate_code()
-/obj/item/book/codebook/Initialize()
- . = ..()
+ dat = GLOB.codebook_data[faction]
+
+/obj/item/book/codebook/proc/generate_code()
var/number
var/letter
- dat = "Call | Response | |
"
+ var/code_data = "Call | Response | |
"
for(var/i in 1 to 10)
letter = pick(greek_letters)
number = rand(100,999)
- dat += "[letter]-[number] | "
+ code_data += "
[letter]-[number] | "
letter = pick(greek_letters)
number = rand(100,999)
- dat += "[letter]-[number] |
"
+ code_data += "[letter]-[number] | "
+ code_data += "
"
+ return code_data
+
+/obj/item/book/codebook
+ name = "USS Almayer Code Book"
+ author = "United States Colonial Marines"
+ unique = 1
+ dat = ""
+ var/faction = FACTION_MARINE
+
+/obj/item/book/codebook/Initialize()
+ . = ..()
+ title = name
+ create_codebook(faction)
+
+/obj/item/book/codebook/clf
+ name = "Liberation Front Authenticators"
+ faction = FACTION_CLF
+ author = "\[Obscured Ink\]"
+
+/obj/item/book/codebook/twe
+ name = "Imperial Authentication Codes"
+ faction = FACTION_TWE
+ author = "Royal Marines"
- dat += "
"
+/obj/item/book/codebook/upp
+ name = "Union Authentication Codes"
+ faction = FACTION_UPP
+ author = "People's Army"
+/obj/item/book/codebook/wey_yu
+ name = "Corporate Authentication Codes"
+ faction = FACTION_WY
+ author = "Weyland-Yutani Communications Division"
/obj/item/book/codebook/attackby(obj/item/W, mob/living/user)
if(istype(W, /obj/item/tool/kitchen/knife) || HAS_TRAIT(W, TRAIT_TOOL_WIRECUTTERS))
diff --git a/code/modules/cm_marines/m2c.dm b/code/modules/cm_marines/m2c.dm
new file mode 100644
index 000000000000..a0943bb7f0a6
--- /dev/null
+++ b/code/modules/cm_marines/m2c.dm
@@ -0,0 +1,629 @@
+#define M2C_SETUP_TIME (0.2 SECONDS)
+#define M2C_OVERHEAT_CRITICAL 25
+#define M2C_OVERHEAT_BAD 14
+#define M2C_OVERHEAT_OK 4
+#define M2C_OVERHEAT_DAMAGE 30
+#define M2C_LOW_COOLDOWN_ROLL 0.3
+#define M2C_HIGH_COOLDOWN_ROLL 0.45
+#define M2C_PASSIVE_COOLDOWN_AMOUNT 4
+#define M2C_OVERHEAT_OVERLAY 14
+#define M2C_CRUSHER_STUN 3 //amount in ticks (roughly 3 seconds)
+
+/*M2C HEAVY MACHINEGUN AND ITS COMPONENTS */
+// AMMO
+/obj/item/ammo_magazine/m2c
+ name = "M2C Ammunition Box (10x28mm tungsten rounds)"
+ desc = "A box of 125, 10x28mm tungsten rounds for the M2 Heavy Machinegun System. Click the heavy machinegun while there's no ammo box loaded to reload the M2C."
+ caliber = "10x28mm"
+ w_class = SIZE_LARGE
+ icon = 'icons/obj/items/weapons/guns/ammo_by_faction/uscm.dmi'
+ icon_state = "m56de"
+ item_state = "m56de"
+ max_rounds = 125
+ default_ammo = /datum/ammo/bullet/machinegun/auto
+ gun_type = null
+
+//STORAGE BOX FOR THE MACHINEGUN
+/obj/item/storage/box/m56d/m2c
+ name = "\improper M2C Assembly-Supply Crate"
+ desc = "A large case labelled 'M2C, 10x28mm caliber heavy machinegun', seems to be fairly heavy to hold. contains a deadly M2C Heavy Machinegun System and its ammunition."
+ icon = 'icons/turf/whiskeyoutpost.dmi'
+ icon_state = "M56D_case"
+ w_class = SIZE_HUGE
+ storage_slots = 5
+
+/obj/item/storage/box/m56d/m2c/fill_preset_inventory()
+ new /obj/item/device/m2c_gun(src)
+ new /obj/item/ammo_magazine/m2c(src)
+ new /obj/item/ammo_magazine/m2c(src)
+ new /obj/item/ammo_magazine/m2c(src)
+ new /obj/item/ammo_magazine/m2c(src)
+
+// THE GUN ITSELF
+
+/obj/item/device/m2c_gun
+ name = "\improper M2C heavy machine gun"
+ desc = "The disassembled M2C HMG, with its telescopic tripods folded up and unable to fire."
+ w_class = SIZE_HUGE
+ flags_equip_slot = SLOT_BACK
+ icon = 'icons/turf/whiskeyoutpost.dmi'
+ icon_state = "M56DE_gun_mount"
+ item_state = "M56DE_gun_mount"
+ var/rounds = 0
+ var/overheat_value = 0
+ var/anti_cadehugger_range = 1
+ var/broken_gun = FALSE
+ var/field_recovery = 130
+ health = 230
+
+/obj/item/device/m2c_gun/Initialize()
+ . = ..()
+ update_icon()
+
+/obj/item/device/m2c_gun/update_icon() //Lets generate the icon based on how much ammo it has.
+ var/icon_name = initial(icon_state)
+ if(broken_gun)
+ icon_name += "_broken"
+ if(!rounds)
+ icon_name += "_e"
+
+ else if(!broken_gun && !rounds)
+ icon_name += "_e"
+
+ icon_state = icon_name
+
+/obj/item/device/m2c_gun/proc/check_can_setup(mob/user, turf/rotate_check, turf/open/OT, list/ACR)
+ if(!ishuman(user))
+ return FALSE
+ if(broken_gun)
+ to_chat(user, SPAN_WARNING("You can't set up \the [src], it's completely broken!"))
+ return FALSE
+ if(SSinterior.in_interior(user))
+ to_chat(usr, SPAN_WARNING("It's too cramped in here to deploy \a [src]."))
+ return FALSE
+ if(OT.density || !isturf(OT) || !OT.allow_construction)
+ to_chat(user, SPAN_WARNING("You can't set up \the [src] here."))
+ return FALSE
+ if(rotate_check.density)
+ to_chat(user, SPAN_WARNING("You can't set up \the [src] that way, there's a wall behind you!"))
+ return FALSE
+ for(var/obj/structure/potential_blocker in rotate_check)
+ if(potential_blocker.density)
+ to_chat(user, SPAN_WARNING("You can't set up \the [src] that way, there's \a [potential_blocker] behind you!"))
+ return FALSE
+ if((locate(/obj/structure/barricade) in ACR) || (locate(/obj/structure/window_frame) in ACR) || (locate(/obj/structure/window) in ACR) || (locate(/obj/structure/windoor_assembly) in ACR))
+ to_chat(user, SPAN_WARNING("There are barriers nearby, you can't set up \the [src] here!"))
+ return FALSE
+ var/fail = FALSE
+ for(var/obj/X in OT.contents - src)
+ if(istype(X, /obj/structure/machinery/defenses))
+ fail = TRUE
+ break
+ else if(istype(X, /obj/structure/machinery/door))
+ fail = TRUE
+ break
+ else if(istype(X, /obj/structure/machinery/m56d_hmg))
+ fail = TRUE
+ break
+ if(fail)
+ to_chat(user, SPAN_WARNING("You can't install \the [src] here, something is in the way."))
+ return FALSE
+
+
+ if(!(user.alpha > 60))
+ to_chat(user, SPAN_WARNING("You can't set this up while cloaked!"))
+ return FALSE
+ return TRUE
+
+
+/obj/item/device/m2c_gun/attack_self(mob/user)
+ ..()
+ var/turf/rotate_check = get_step(user.loc, turn(user.dir, 180))
+ var/turf/open/OT = usr.loc
+ var/list/ACR = range(anti_cadehugger_range, user.loc)
+
+ if(!check_can_setup(user, rotate_check, OT, ACR))
+ return
+
+ if(!do_after(user, M2C_SETUP_TIME, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
+ return
+
+ if(!check_can_setup(user, rotate_check, OT, ACR))
+ return
+
+ var/obj/structure/machinery/m56d_hmg/auto/M = new /obj/structure/machinery/m56d_hmg/auto(user.loc)
+ transfer_label_component(M)
+ M.setDir(user.dir) // Make sure we face the right direction
+ M.anchored = TRUE
+ playsound(M, 'sound/items/m56dauto_setup.ogg', 75, TRUE)
+ to_chat(user, SPAN_NOTICE("You deploy [M]."))
+ if((rounds > 0) && !user.get_inactive_hand())
+ user.set_interaction(M)
+ give_action(user, /datum/action/human_action/mg_exit)
+ M.rounds = rounds
+ M.overheat_value = overheat_value
+ M.health = health
+ M.update_icon()
+ qdel(src)
+
+/obj/item/device/m2c_gun/attackby(obj/item/O as obj, mob/user as mob)
+ if(!ishuman(user))
+ return
+
+ if(!iswelder(O) || user.action_busy)
+ return
+
+ if(!HAS_TRAIT(O, TRAIT_TOOL_BLOWTORCH))
+ to_chat(user, SPAN_WARNING("You need a stronger blowtorch!"))
+ return
+
+ if(!broken_gun)
+ to_chat(user, SPAN_WARNING("[src] isn't critically broken, no need for field recovery operations."))
+ return
+
+ var/obj/item/tool/weldingtool/WT = O
+
+ if(WT.remove_fuel(2, user))
+ user.visible_message(SPAN_NOTICE("[user] begins field recovering \the [src]."), \
+ SPAN_NOTICE("You begin repairing the severe damages on \the [src] in an effort to restore its functions."))
+ playsound(src.loc, 'sound/items/Welder2.ogg', 25, 1)
+ if(!do_after(user, field_recovery * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src))
+ return
+ user.visible_message(SPAN_NOTICE("[user] field recovers \the [src], restoring it back to its original state."), \
+ SPAN_NOTICE("You repair \the [src] back to a functional state."))
+ broken_gun = FALSE
+ health = 110
+ update_icon()
+ return
+ else
+ to_chat(user, SPAN_WARNING("You need more fuel in \the [WT] to start field recovery on [src]."))
+
+// MACHINEGUN, AUTOMATIC
+/obj/structure/machinery/m56d_hmg/auto
+ name = "\improper M2C Heavy Machinegun"
+ desc = "A deployable, heavy machine gun. The M2C 'Chimp' HB is a modified M2 HB reconfigured to fire 10x28 Caseless Tungsten rounds for USCM use. It is capable of recoilless fire and fast-rotating. However it has a debilitating overheating issue due to the poor quality of metals used in the parts, forcing it to be used in decisive, crushing engagements as a squad support weapon. Click its sprite while behind it without holding anything to man it. Click-drag on NON-GRAB intent to disassemble the gun, GRAB INTENT to remove ammo magazines."
+ icon = 'icons/turf/whiskeyoutpost.dmi'
+ icon_state = "M56DE"
+ icon_full = "M56DE"
+ icon_empty = "M56DE_e"
+ rounds_max = 125
+ ammo = /datum/ammo/bullet/machinegun/auto
+ fire_delay = 0.1 SECONDS
+ var/grip_dir = null
+ var/fold_time = 1.5 SECONDS
+ var/repair_time = 5 SECONDS
+ density = TRUE
+ health = 230
+ health_max = 230
+ display_ammo = FALSE
+ var/list/cadeblockers = list()
+ var/cadeblockers_range = 1
+
+ var/static/image/barrel_overheat_image
+ var/has_barrel_overlay = FALSE
+
+ gun_noise = 'sound/weapons/gun_m56d_auto.ogg'
+ empty_alarm = 'sound/weapons/hmg_eject_mag.ogg'
+
+ // OVERHEAT MECHANIC VARIABLES
+ var/overheat_value = 0
+ var/overheat_threshold = 40
+ var/emergency_cooling = FALSE
+ var/overheat_text_cooldown = 0
+ var/force_cooldown_timer = 10
+ var/rotate_timer = 0
+ var/fire_stopper = FALSE
+
+ // Muzzle Flash Offsets
+ north_x_offset = 0
+ north_y_offset = 10
+ east_x_offset = 0
+ east_y_offset = 12
+ south_x_offset = 0
+ south_y_offset = 10
+ west_x_offset = 0
+ west_y_offset = 12
+
+// ANTI-CADE EFFECT, CREDIT TO WALTERMELDRON
+
+/obj/structure/machinery/m56d_hmg/auto/Initialize()
+ . = ..()
+ for(var/turf/T in range(cadeblockers_range, src))
+ var/obj/structure/blocker/anti_cade/CB = new(T)
+ CB.hmg = src
+
+ cadeblockers.Add(CB)
+
+ if(!barrel_overheat_image)
+ barrel_overheat_image = image('icons/turf/whiskeyoutpost.dmi', "+m56de_overheat")
+
+/obj/structure/machinery/m56d_hmg/auto/Destroy()
+ QDEL_NULL_LIST(cadeblockers)
+ return ..()
+
+/obj/structure/machinery/m56d_hmg/auto/process()
+
+ var/mob/user = operator
+ overheat_value -= M2C_PASSIVE_COOLDOWN_AMOUNT
+ if(overheat_value <= 0)
+ overheat_value = 0
+ STOP_PROCESSING(SSobj, src)
+
+ if(overheat_value >= M2C_OVERHEAT_CRITICAL)
+ to_chat(user, SPAN_HIGHDANGER("[src]'s barrel is critically hot, it might start melting at this rate."))
+ else if(overheat_value >= M2C_OVERHEAT_BAD)
+ to_chat(user, SPAN_DANGER("[src]'s barrel is terribly hot, but is still able to fire."))
+ else if(overheat_value >= M2C_OVERHEAT_OK)
+ to_chat(user, SPAN_DANGER("[src]'s barrel is pretty hot, although it's still stable."))
+ else if (overheat_value > 0)
+ to_chat(user, SPAN_WARNING("[src]'s barrel is mildly warm."))
+
+ update_icon()
+
+// ANTI-CADE EFFECT, CREDIT TO WALTERMELDRON
+/obj/structure/blocker/anti_cade
+ health = INFINITY
+ anchored = TRUE
+ density = FALSE
+ unacidable = TRUE
+ indestructible = TRUE
+ invisibility = 101 // no looking at it with alt click
+
+ var/obj/structure/machinery/m56d_hmg/auto/hmg
+
+ alpha = 0
+
+/obj/structure/blocker/anti_cade/BlockedPassDirs(atom/movable/AM, target_dir)
+ if(istype(AM, /obj/structure/barricade))
+ return BLOCKED_MOVEMENT
+ else if(istype(AM, /obj/structure/window))
+ return BLOCKED_MOVEMENT
+ else if(istype(AM, /obj/structure/windoor_assembly))
+ return BLOCKED_MOVEMENT
+ else if(istype(AM, /obj/structure/machinery/door))
+ return BLOCKED_MOVEMENT
+ return ..()
+
+/obj/structure/blocker/anti_cade/Destroy()
+ if(hmg)
+ hmg.cadeblockers.Remove(src)
+ hmg = null
+
+ return ..()
+
+/obj/structure/machinery/m56d_hmg/auto/update_icon() //Lets generate the icon based on how much ammo it has.
+ if(!rounds)
+ icon_state = "[icon_empty]"
+ else
+ icon_state = "[icon_full]"
+
+ if(overheat_value >= M2C_OVERHEAT_OVERLAY)
+ if(has_barrel_overlay)
+ return
+ overlays += barrel_overheat_image
+ has_barrel_overlay = TRUE
+ else if(has_barrel_overlay)
+ overlays -= barrel_overheat_image
+ has_barrel_overlay = FALSE
+
+// DED
+
+/obj/structure/machinery/m56d_hmg/auto/update_health(amount) //Negative values restores health.
+ health -= amount
+ if(health <= 0)
+ playsound(src.loc, 'sound/items/Welder2.ogg', 25, 1)
+ visible_message(SPAN_WARNING("[src] has broken down completely!"))
+ var/obj/item/device/m2c_gun/HMG = new(src.loc)
+ HMG.rounds = rounds
+ HMG.broken_gun = TRUE
+ HMG.unacidable = FALSE
+ HMG.health = 0
+ HMG.update_icon()
+ qdel(src)
+ return
+
+ if(health > health_max)
+ health = health_max
+ update_damage_state()
+ update_icon()
+
+/obj/structure/machinery/m56d_hmg/auto/attackby(obj/item/O as obj, mob/user as mob)
+ if(!ishuman(user))
+ return
+ // RELOADING
+ if(istype(O, /obj/item/ammo_magazine/m2c))
+ var/obj/item/ammo_magazine/m2c/M = O
+ if(rounds)
+ to_chat(user, SPAN_WARNING("There's already an ammo box inside of [src], remove it first!"))
+ return
+ if(user.action_busy) return
+ user.visible_message(SPAN_NOTICE("[user] loads [src] with an ammo box! "), SPAN_NOTICE("You load [src] with an ammo box!"))
+ playsound(src.loc, 'sound/items/m56dauto_load.ogg', 75, 1)
+ rounds = min(rounds + M.current_rounds, rounds_max)
+ update_icon()
+ user.temp_drop_inv_item(O)
+ qdel(O)
+ return
+
+ // WELDER REPAIR
+ if(iswelder(O))
+ if(!HAS_TRAIT(O, TRAIT_TOOL_BLOWTORCH))
+ to_chat(user, SPAN_WARNING("You need a stronger blowtorch!"))
+ return
+ if(user.action_busy)
+ return
+
+ var/obj/item/tool/weldingtool/WT = O
+
+ if(health == health_max)
+ to_chat(user, SPAN_WARNING("[src] doesn't need repairs, it's well-maintained."))
+ return
+
+ if(WT.remove_fuel(2, user))
+ user.visible_message(SPAN_NOTICE("[user] begins repairing damage on \the [src]."), \
+ SPAN_NOTICE("You begin repairing the damage on \the [src]."))
+ playsound(src.loc, 'sound/items/Welder2.ogg', 25, 1)
+ if(!do_after(user, repair_time * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src))
+ return
+ user.visible_message(SPAN_NOTICE("[user] repairs some of the damage on [src]."), \
+ SPAN_NOTICE("You repair [src]."))
+ update_health(-round(health_max*0.2))
+ playsound(src.loc, 'sound/items/Welder2.ogg', 25, 1)
+ else
+ to_chat(user, SPAN_WARNING("You need more fuel in [WT] to repair damage to [src]."))
+ return
+ return
+
+// AUTOMATIC FIRING
+
+/obj/structure/machinery/m56d_hmg/auto/try_fire()
+ if(fire_stopper)
+ return
+
+ if(overheat_value >= overheat_threshold)
+ if(world.time > overheat_text_cooldown)
+ operator.visible_message(SPAN_HIGHDANGER("[src] has overheated and has been shortly disabled!"), SPAN_HIGHDANGER("[src] has overheated! You have to wait for it to cooldown!"))
+ overheat_text_cooldown = world.time + 3 SECONDS
+
+ if(!emergency_cooling)
+ emergency_cooling = TRUE
+ to_chat(operator, SPAN_DANGER("You wait for [src]'s barrel to cooldown to continue sustained fire."))
+ fire_stopper = TRUE
+ STOP_PROCESSING(SSobj, src)
+ addtimer(CALLBACK(src, PROC_REF(force_cooldown)), force_cooldown_timer)
+ return
+
+ return ..()
+
+
+/obj/structure/machinery/m56d_hmg/auto/fire_shot()
+ . = ..()
+
+ handle_rotating_gun(operator)
+ if((. & AUTOFIRE_CONTINUE) && rounds)
+ overheat_value += 1
+ START_PROCESSING(SSobj, src)
+
+/obj/structure/machinery/m56d_hmg/auto/handle_ammo_out(mob/user)
+ visible_message(SPAN_NOTICE("[icon2html(src, viewers(src))] [src]'s ammo box drops onto the ground, now completely empty."))
+ playsound(loc, empty_alarm, 70, 1)
+ update_icon() //final safeguard.
+ var/obj/item/ammo_magazine/m2c/AM = new /obj/item/ammo_magazine/m2c(src.loc)
+ AM.current_rounds = 0
+ AM.update_icon()
+
+/obj/structure/machinery/m56d_hmg/auto/get_scatter()
+ return 0
+
+// ACTIVE COOLING
+
+/obj/structure/machinery/m56d_hmg/auto/proc/force_cooldown(mob/user)
+ user = operator
+
+ overheat_value = round((rand(M2C_LOW_COOLDOWN_ROLL, M2C_HIGH_COOLDOWN_ROLL) * overheat_threshold))
+ playsound(src.loc, 'sound/weapons/hmg_cooling.ogg', 75, 1)
+ to_chat(user, SPAN_NOTICE("[src]'s barrel has cooled down enough to restart firing."))
+ emergency_cooling = FALSE
+ fire_stopper = FALSE
+ fire_delay = initial(fire_delay)
+ update_health(M2C_OVERHEAT_DAMAGE)
+ START_PROCESSING(SSobj, src)
+ update_icon()
+
+// TOGGLE MODE
+
+/obj/structure/machinery/m56d_hmg/auto/clicked(mob/user, list/mods, atom/A)
+ if (mods["ctrl"])
+ if(operator != user)
+ return ..()
+ if(!CAN_PICKUP(user, src))
+ return ..()
+ to_chat(user, SPAN_NOTICE("You try to toggle a burst-mode on \the [src], but realize that it doesn't exist."))
+ return TRUE
+
+ return ..()
+
+//ATTACK WITH BOTH HANDS COMBO
+
+/obj/structure/machinery/m56d_hmg/auto/attack_hand(mob/user)
+ ..()
+
+ var/turf/user_turf = get_turf(user)
+ for(var/opp_dir in reverse_nearby_direction(src.dir))
+ if(get_step(src, opp_dir) == user_turf)
+ if(operator) //If there is already a operator then they're manning it.
+ if(operator.interactee == null)
+ operator = null //this shouldn't happen, but just in case
+ else
+ to_chat(user, "Someone's already controlling it.")
+ return
+ if(!(user.alpha > 60))
+ to_chat(user, SPAN_WARNING("You aren't going to be setting up while cloaked."))
+ return
+ else
+ if(user.interactee) //Make sure we're not manning two guns at once, tentacle arms.
+ to_chat(user, "You're already manning something!")
+ return
+
+ if(user.get_active_hand() == null && user.get_inactive_hand() == null)
+ user.freeze()
+ user.set_interaction(src)
+ give_action(user, /datum/action/human_action/mg_exit)
+ else
+ to_chat(usr, SPAN_NOTICE("Your hands are too busy holding things to grab the handles!"))
+ else
+ to_chat(usr, SPAN_NOTICE("You are too far from the handles to man [src]!"))
+
+// DISASSEMBLY
+
+/obj/structure/machinery/m56d_hmg/auto/MouseDrop(over_object, src_location, over_location)
+ if(!ishuman(usr)) return
+ var/mob/living/carbon/human/user = usr
+
+ if(over_object == user && in_range(src, user))
+ if((rounds > 0) && (user.a_intent & (INTENT_GRAB)))
+ playsound(src.loc, 'sound/items/m56dauto_load.ogg', 75, 1)
+ user.visible_message(SPAN_NOTICE(" [user] removes [src]'s ammo box."),SPAN_NOTICE(" You remove [src]'s ammo box, preparing the gun for disassembly."))
+ var/obj/item/ammo_magazine/m2c/used_ammo = new(user.loc)
+ used_ammo.current_rounds = rounds
+ user.put_in_active_hand(used_ammo)
+ rounds = 0
+
+ else
+ if(!do_after(user, fold_time* user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src)) // disassembly time reduced
+ return
+ user.visible_message(SPAN_NOTICE("[user] disassembles [src]."),SPAN_NOTICE("You fold up the tripod for [src], disassembling it."))
+ playsound(src.loc, 'sound/items/m56dauto_setup.ogg', 75, 1)
+ var/obj/item/device/m2c_gun/HMG = new(src.loc)
+ transfer_label_component(HMG)
+ HMG.rounds = src.rounds
+ HMG.overheat_value = round(0.5 * src.overheat_value)
+ if (HMG.overheat_value <= 10)
+ HMG.overheat_value = 0
+ HMG.update_icon()
+ HMG.health = health
+ user.put_in_active_hand(HMG)
+ if(user.equip_to_slot_if_possible(HMG, WEAR_BACK, disable_warning = TRUE))
+ to_chat(user, SPAN_NOTICE("You quickly heave the machine gun onto your back!"))
+ qdel(src)
+
+ update_icon()
+
+// MOUNT THE MG
+
+/obj/structure/machinery/m56d_hmg/auto/on_set_interaction(mob/user)
+ ..()
+ ADD_TRAIT(user, TRAIT_OVERRIDE_CLICKDRAG, TRAIT_SOURCE_WEAPON)
+ RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(disable_interaction))
+ RegisterSignal(user, COMSIG_MOB_POST_UPDATE_CANMOVE, PROC_REF(disable_canmove_interaction))
+
+// DISMOUNT THE MG
+
+/obj/structure/machinery/m56d_hmg/auto/on_unset_interaction(mob/user)
+ REMOVE_TRAIT(user, TRAIT_OVERRIDE_CLICKDRAG, TRAIT_SOURCE_WEAPON)
+ UnregisterSignal(user, list(
+ COMSIG_MOVABLE_PRE_MOVE,
+ COMSIG_MOB_POST_UPDATE_CANMOVE
+ ))
+ ..()
+
+// GET ANIMATED
+
+/obj/structure/machinery/m56d_hmg/auto/update_pixels(mob/user, mounting = TRUE)
+ if(mounting)
+ var/diff_x = 0
+ var/diff_y = 0
+ var/tilesize = 32
+ var/viewoffset = tilesize * 1
+
+ user.reset_view(src)
+ if(dir == EAST)
+ diff_x = -16 + user_old_x
+ user.client.pixel_x = viewoffset
+ user.client.pixel_y = 0
+ if(dir == WEST)
+ diff_x = 16 + user_old_x
+ user.client.pixel_x = -viewoffset
+ user.client.pixel_y = 0
+ if(dir == NORTH)
+ diff_y = -16 + user_old_y
+ user.client.pixel_x = 0
+ user.client.pixel_y = viewoffset
+ if(dir == SOUTH)
+ diff_y = 16 + user_old_y
+ user.client.pixel_x = 0
+ user.client.pixel_y = -viewoffset
+
+ animate(user, pixel_x=diff_x, pixel_y=diff_y, 0.4 SECONDS)
+ else
+ if(user.client)
+ user.client.change_view(world_view_size)
+ user.client.pixel_x = 0
+ user.client.pixel_y = 0
+
+ animate(user, pixel_x=user_old_x, pixel_y=user_old_y, 4, 1)
+
+
+//ROTATE THE MACHINEGUN
+
+/obj/structure/machinery/m56d_hmg/auto/proc/rotate_to(mob/user, atom/A)
+ if(!A || !user.x || !user.y || !A.x || !A.y)
+ return
+ var/dx = A.x - user.x
+ var/dy = A.y - user.y
+ if(!dx && !dy)
+ return
+
+ var/direction
+ if(abs(dx) < abs(dy))
+ if(dy > 0)
+ direction = NORTH
+ else
+ direction = SOUTH
+ else
+ if(dx > 0)
+ direction = EAST
+ else
+ direction = WEST
+
+ var/turf/rotate_check = get_step(src.loc, turn(direction,180))
+ if(rotate_check.density)
+ to_chat(user, SPAN_WARNING("You can't rotate it that way."))
+ return
+
+ src.setDir(direction)
+ user.setDir(direction)
+ update_pixels(user)
+ playsound(src.loc, 'sound/items/m56dauto_rotate.ogg', 25, 1)
+ to_chat(user, SPAN_NOTICE("You rotate [src], using the tripod to support your pivoting movement."))
+
+
+/obj/structure/machinery/m56d_hmg/auto/proc/disable_interaction(mob/user, NewLoc, direction)
+ SIGNAL_HANDLER
+
+ if(user.lying || get_dist(user,src) > 0 || user.is_mob_incapacitated() || !user.client)
+ user.unset_interaction()
+
+/obj/structure/machinery/m56d_hmg/auto/proc/disable_canmove_interaction(mob/user, canmove, laid_down, lying)
+ SIGNAL_HANDLER
+
+ if(laid_down)
+ user.unset_interaction()
+
+/obj/structure/machinery/m56d_hmg/auto/proc/handle_rotating_gun(mob/user)
+ var/angle = get_dir(src, target)
+ if(world.time > rotate_timer && !((dir & angle) && target.loc != src.loc && target.loc != operator.loc))
+ rotate_timer = world.time + 0.4 SECONDS
+ rotate_to(user, target)
+ return TRUE
+
+#undef M2C_OVERHEAT_CRITICAL
+#undef M2C_OVERHEAT_BAD
+#undef M2C_OVERHEAT_OK
+#undef M2C_SETUP_TIME
+#undef M2C_OVERHEAT_DAMAGE
+#undef M2C_LOW_COOLDOWN_ROLL
+#undef M2C_HIGH_COOLDOWN_ROLL
+#undef M2C_PASSIVE_COOLDOWN_AMOUNT
+#undef M2C_OVERHEAT_OVERLAY
+#undef M2C_CRUSHER_STUN
diff --git a/code/modules/cm_marines/smartgun_mount.dm b/code/modules/cm_marines/smartgun_mount.dm
index f1d5e56ee8d3..0066e96bb783 100644
--- a/code/modules/cm_marines/smartgun_mount.dm
+++ b/code/modules/cm_marines/smartgun_mount.dm
@@ -1,14 +1,3 @@
-#define M2C_SETUP_TIME 0.2 SECONDS
-#define M2C_OVERHEAT_CRITICAL 25
-#define M2C_OVERHEAT_BAD 14
-#define M2C_OVERHEAT_OK 4
-#define M2C_OVERHEAT_DAMAGE 30
-#define M2C_LOW_COOLDOWN_ROLL 0.3
-#define M2C_HIGH_COOLDOWN_ROLL 0.45
-#define M2C_PASSIVE_COOLDOWN_AMOUNT 4
-#define M2C_OVERHEAT_OVERLAY 14
-#define M2C_CRUSHER_STUN 3 //amount in ticks (roughly 3 seconds)
-
//////////////////////////////////////////////////////////////
//Mounted MG, Replacment for the current jury rig code.
@@ -426,7 +415,7 @@
// The actual Machinegun itself, going to borrow some stuff from current sentry code to make sure it functions. Also because they're similiar.
/obj/structure/machinery/m56d_hmg
name = "\improper M56D heavy machine gun"
- desc = "A deployable, heavy machine gun. While it is capable of taking the same rounds as the M56, it fires specialized tungsten rounds for increased armor penetration.
Drag its sprite onto yourself to man it. Ctrl-click it to toggle burst fire."
+ desc = "A deployable, heavy machine gun. While it is capable of taking the same rounds as the M56, it fires specialized tungsten rounds for increased armor penetration.
Drag its sprite onto yourself to man it. Ctrl-click it to cycle through firemodes."
icon = 'icons/turf/whiskeyoutpost.dmi'
icon_state = "M56D"
anchored = TRUE
@@ -438,18 +427,14 @@
projectile_coverage = PROJECTILE_COVERAGE_LOW
var/rounds = 0 //Have it be empty upon spawn.
var/rounds_max = 700
- var/fire_delay = 2 //Gotta have rounds down quick.
- var/last_fired = 0
- var/burst_fire = 0 //0 is non-burst mode, 1 is burst.
var/burst_scatter_mult = 4
- var/safety = 0 //Weapon safety, 0 is weapons hot, 1 is safe.
+ var/safety = FALSE
health = 200
var/health_max = 200 //Why not just give it sentry-tier health for now.
var/atom/target = null // required for shooting at things.
var/datum/ammo/bullet/machinegun/ammo = /datum/ammo/bullet/machinegun
var/obj/projectile/in_chamber = null
var/locked = 0 //1 means its locked inplace (this will be for sandbag MGs)
- var/is_bursting = 0
var/muzzle_flash_lum = 4
var/icon_full = "M56D" // Put this system in for other MGs or just other mounted weapons in general, future proofing.
var/icon_empty = "M56D_e" //Empty
@@ -473,6 +458,41 @@
var/user_old_x = 0
var/user_old_y = 0
+ /// How much time should pass in between full auto shots, slightly higher than burst due to click delay and similar things that slow firing down
+ var/fire_delay = 0.3 SECONDS
+ /// How much time should pass in between burst fire shots
+ var/burst_fire_delay = 0.2 SECONDS
+ /// How many rounds are fired per burst
+ var/burst_amount = 3
+ /// How many rounds have been fired in the current burst/auto
+ var/shots_fired = 0
+ /// What firemode the gun is currently in
+ var/gun_firemode = GUN_FIREMODE_AUTOMATIC
+ /// What firemodes this gun has
+ var/static/list/gun_firemodes = list(
+ GUN_FIREMODE_SEMIAUTO,
+ GUN_FIREMODE_BURSTFIRE,
+ GUN_FIREMODE_AUTOMATIC,
+ )
+ /// A multiplier for how slow this gun should fire in automatic as opposed to burst. 1 is normal, 1.2 is 20% slower, 0.8 is 20% faster, etc.
+ var/autofire_slow_mult = 1
+ /// If the gun is currently burst firing
+ VAR_PROTECTED/burst_firing = FALSE
+ /// If the gun is currently auto firing
+ VAR_PROTECTED/auto_firing = FALSE
+ /// If the gun should display its ammo count
+ var/display_ammo = TRUE
+ /// How many degrees in each direction the gun should be able to fire
+ var/shoot_degree = 80
+ /// Semi auto cooldown
+ COOLDOWN_DECLARE(semiauto_fire_cooldown)
+ /// How long between semi-auto shots this should wait, to reduce possible spam
+ var/semiauto_cooldown_time = 0.2 SECONDS
+
+/obj/structure/machinery/m56d_hmg/get_examine_text(mob/user)
+ . = ..()
+ . += "It is currently set to [gun_firemode]."
+
/obj/structure/machinery/m56d_hmg/initialize_pass_flags(datum/pass_flags_container/PF)
..()
if (PF)
@@ -491,12 +511,13 @@
else
return ..()
-/obj/structure/machinery/m56d_hmg/New()
- ..()
+/obj/structure/machinery/m56d_hmg/Initialize(mapload, ...)
+ . = ..()
ammo = GLOB.ammo_list[ammo] //dunno how this works but just sliding this in from sentry-code.
burst_scatter_mult = SCATTER_AMOUNT_TIER_7
update_icon()
+ AddComponent(/datum/component/automatedfire/autofire, fire_delay, burst_fire_delay, burst_amount, gun_firemode, autofire_slow_mult, CALLBACK(src, PROC_REF(set_burst_firing)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(try_fire)), CALLBACK(src, PROC_REF(display_ammo)), CALLBACK(src, PROC_REF(set_auto_firing)))
/obj/structure/machinery/m56d_hmg/Destroy() //Make sure we pick up our trash.
if(operator)
@@ -573,7 +594,7 @@
if(user.action_busy) return
if(!do_after(user, 25 * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL, BUSY_ICON_FRIENDLY))
return
- user.visible_message(SPAN_NOTICE(" [user] loads [src]! "),SPAN_NOTICE(" You load [src]!"))
+ user.visible_message(SPAN_NOTICE("[user] loads [src]! "),SPAN_NOTICE("You load [src]!"))
playsound(loc, 'sound/weapons/gun_minigun_cocked.ogg', 25, 1)
if(rounds)
var/obj/item/ammo_magazine/m56d/D = new(user.loc)
@@ -632,10 +653,10 @@
update_health(severity)
return
-/obj/structure/machinery/m56d_hmg/proc/exit_interaction(mob/user)
+/obj/structure/machinery/m56d_hmg/proc/exit_interaction()
SIGNAL_HANDLER
- user.unset_interaction()
+ operator.unset_interaction()
/obj/structure/machinery/m56d_hmg/proc/update_damage_state()
var/health_percent = round(health/health_max * 100)
@@ -674,77 +695,56 @@
in_chamber.generate_bullet(ammo)
return 1
-/obj/structure/machinery/m56d_hmg/proc/process_shot(mob/user)
- set waitfor = FALSE
-
- if(isnull(target))
- return //Acqure our victim.
-
- if(!ammo)
- update_icon() //safeguard.
+/obj/structure/machinery/m56d_hmg/proc/fire_shot() //Bang Bang
+ if(!ammo || safety)
return
- if(burst_fire && target && !last_fired)
- if(rounds > 3)
- for(var/i = 1 to 3)
- is_bursting = 1
- fire_shot(i, user)
- sleep(2)
- spawn(0)
- last_fired = 1
- spawn(fire_delay)
- last_fired = 0
- else burst_fire = 0
- is_bursting = 0
-
- if(!burst_fire && target && !last_fired)
- fire_shot(1, user)
-
- target = null
-
-/obj/structure/machinery/m56d_hmg/proc/fire_shot(shots_fired = 1, mob/user) //Bang Bang
- if(!ammo) return //No ammo.
- if(last_fired) return //still shooting.
-
- if(!is_bursting)
- last_fired = 1
- spawn(fire_delay)
- last_fired = 0
-
var/turf/T = get_turf(src)
var/turf/U = get_turf(target)
if (!istype(T) || !istype(U))
return
- if(load_into_chamber() == 1)
- if(istype(in_chamber,/obj/projectile))
- in_chamber.original = target
-
- var/initial_angle = Get_Angle(T, U)
- var/final_angle = initial_angle
-
- var/total_scatter_angle = get_scatter()
-
- if(total_scatter_angle > 0)
- final_angle += rand(-total_scatter_angle, total_scatter_angle)
- target = get_angle_target_turf(T, final_angle, 30)
-
- in_chamber.weapon_cause_data = create_cause_data(initial(name), user)
- in_chamber.setDir(dir)
- in_chamber.def_zone = pick("chest","chest","chest","head")
- SEND_SIGNAL(in_chamber, COMSIG_BULLET_USER_EFFECTS, user)
- playsound(loc,gun_noise, 50, 1)
- in_chamber.fire_at(target,user,src,ammo.max_range,ammo.shell_speed)
- if(target)
- muzzle_flash(final_angle)
- in_chamber = null
- rounds--
- if(!rounds)
- handle_ammo_out()
- return
+ if(!load_into_chamber())
+ return
+
+ if(!istype(in_chamber, /obj/projectile))
+ return
+
+ var/angle = get_angle(T, U)
+
+ if((dir == NORTH) && (angle > 180) && (abs(360 - angle) > shoot_degree)) // If north and shooting to the left, we do some extra math
+ return
+
+ else if((dir != NORTH) && (abs(angle - dir2angle(dir)) > shoot_degree))
+ return
+
+ in_chamber.original = target
+
+ var/initial_angle = Get_Angle(T, U)
+ var/final_angle = initial_angle
+
+ var/total_scatter_angle = get_scatter()
-/obj/structure/machinery/m56d_hmg/proc/get_scatter(shots_fired = 1)
+ if(total_scatter_angle > 0)
+ final_angle += rand(-total_scatter_angle, total_scatter_angle)
+ target = get_angle_target_turf(T, final_angle, 30)
+
+ in_chamber.weapon_cause_data = create_cause_data(initial(name), operator)
+ in_chamber.setDir(dir)
+ in_chamber.def_zone = pick("chest","chest","chest","head")
+ SEND_SIGNAL(in_chamber, COMSIG_BULLET_USER_EFFECTS, operator)
+ playsound(loc, gun_noise, 50, 1)
+ in_chamber.fire_at(target, operator, src, ammo.max_range, ammo.shell_speed)
+ if(target)
+ muzzle_flash(final_angle)
+ in_chamber = null
+ rounds--
+ if(!rounds)
+ handle_ammo_out()
+ return AUTOFIRE_CONTINUE
+
+/obj/structure/machinery/m56d_hmg/proc/get_scatter()
var/total_scatter_angle = in_chamber.ammo.scatter
if (shots_fired > 1)
@@ -752,67 +752,25 @@
return total_scatter_angle
/obj/structure/machinery/m56d_hmg/proc/handle_ammo_out(mob/user)
- visible_message(SPAN_NOTICE("[icon2html(src, viewers(src))] \The [src] beeps steadily and its ammo light blinks red."))
+ visible_message(SPAN_NOTICE("[icon2html(src, viewers(src))] [src] beeps steadily and its ammo light blinks red."))
playsound(loc, empty_alarm, 25, 1)
update_icon() //final safeguard.
-// New proc for MGs and stuff replaced handle_manual_fire(). Same arguements though, so alls good.
-/obj/structure/machinery/m56d_hmg/handle_click(mob/living/carbon/human/user, atom/A, list/mods)
- if(!operator)
- return HANDLE_CLICK_UNHANDLED
- if(operator != user)
- return HANDLE_CLICK_UNHANDLED
- if(istype(A,/atom/movable/screen))
- return HANDLE_CLICK_UNHANDLED
- if(is_bursting)
- return HANDLE_CLICK_UNHANDLED
- if(user.lying || get_dist(user,src) > 1 || user.is_mob_incapacitated())
- user.unset_interaction()
- return HANDLE_CLICK_UNHANDLED
- if(user.get_active_hand() || user.get_inactive_hand())
- to_chat(usr, SPAN_WARNING("You need two free hands to shoot \the [src]."))
- return HANDLE_CLICK_UNHANDLED
- if(!user.allow_gun_usage)
- to_chat(user, SPAN_WARNING("You aren't allowed to use firearms!"))
- return HANDLE_CLICK_UNHANDLED
-
- target = A
- if(!istype(target))
- return HANDLE_CLICK_UNHANDLED
-
- if(target.z != src.z || target.z == 0 || src.z == 0 || isnull(operator.loc) || isnull(src.loc))
- return HANDLE_CLICK_UNHANDLED
-
- if(get_dist(target,src.loc) > 15)
- return HANDLE_CLICK_UNHANDLED
-
- if(mods["middle"] || mods["shift"] || mods["alt"] || mods["ctrl"])
- handle_modded_clicks(user, mods)
- return HANDLE_CLICK_PASS_THRU
-
- var/angle = get_dir(src, target)
- //we can only fire in a 90 degree cone
- if(target.loc != src.loc && target.loc != operator.loc)
- if(dir & angle)
- try_fire(user)
- return HANDLE_CLICK_HANDLED
- else if(handle_outside_cone(user))
- return HANDLE_CLICK_HANDLED
- return HANDLE_CLICK_UNHANDLED
-
-/obj/structure/machinery/m56d_hmg/proc/try_fire(mob/living/carbon/human/user)
+/obj/structure/machinery/m56d_hmg/proc/try_fire()
if(!rounds)
- to_chat(user, SPAN_WARNING("*click*"))
+ to_chat(operator, SPAN_WARNING("*click*"))
playsound(src, 'sound/weapons/gun_empty.ogg', 25, 1, 5)
- else
- process_shot(user)
+ return
+
+ if(operator.l_hand || operator.r_hand)
+ to_chat(operator, SPAN_WARNING("Your hands need to be free to fire [src]!"))
+ return
+
+ return fire_shot()
/obj/structure/machinery/m56d_hmg/proc/handle_outside_cone(mob/living/carbon/human/user)
return FALSE
-/obj/structure/machinery/m56d_hmg/proc/handle_modded_clicks(mob/living/carbon/human/user, list/mods)
- return HANDLE_CLICK_PASS_THRU
-
/obj/structure/machinery/m56d_hmg/proc/muzzle_flash(angle) // Might as well keep this too.
if(isnull(angle))
return
@@ -886,11 +844,13 @@
to_chat(usr, SPAN_NOTICE("You are too far from the handles to man [src]!"))
/obj/structure/machinery/m56d_hmg/on_set_interaction(mob/user)
- RegisterSignal(user, COMSIG_MOB_RESISTED, PROC_REF(exit_interaction))
- RegisterSignal(user, COMSIG_MOB_MG_EXIT, PROC_REF(exit_interaction))
+ RegisterSignal(user, list(COMSIG_MOB_MG_EXIT, COMSIG_MOB_RESISTED, COMSIG_MOB_DEATH, COMSIG_MOB_KNOCKED_DOWN), PROC_REF(exit_interaction))
flags_atom |= RELAY_CLICK
user.status_flags |= IMMOBILE_ACTION
user.visible_message(SPAN_NOTICE("[user] mans \the [src]."),SPAN_NOTICE("You man \the [src], locked and loaded!"))
+ RegisterSignal(user, COMSIG_MOB_MOUSEDOWN, PROC_REF(start_fire))
+ RegisterSignal(user, COMSIG_MOB_MOUSEDRAG, PROC_REF(change_target))
+ RegisterSignal(user, COMSIG_MOB_MOUSEUP, PROC_REF(stop_fire))
user.forceMove(src.loc)
user.setDir(dir)
user_old_x = user.pixel_x
@@ -904,7 +864,9 @@
user.status_flags &= ~IMMOBILE_ACTION
user.visible_message(SPAN_NOTICE("[user] lets go of \the [src]."),SPAN_NOTICE("You let go of \the [src], letting the gun rest."))
user.unfreeze()
+ UnregisterSignal(user, list(COMSIG_MOB_MOUSEUP, COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEDRAG))
user.reset_view(null)
+ user.remove_temp_pass_flags(PASS_MOB_THRU) // this is necessary because being knocked over while using the gun makes you incorporeal
user.Move(get_step(src, reverse_direction(src.dir)))
user.setDir(dir) //set the direction of the player to the direction the gun is facing
user_old_x = 0 //reset our x
@@ -915,7 +877,9 @@
remove_action(user, /datum/action/human_action/mg_exit)
UnregisterSignal(user, list(
COMSIG_MOB_MG_EXIT,
- COMSIG_MOB_RESISTED
+ COMSIG_MOB_RESISTED,
+ COMSIG_MOB_DEATH,
+ COMSIG_MOB_KNOCKED_DOWN,
))
@@ -959,15 +923,15 @@
if(user.lying || get_dist(user,src) > 0 || user.is_mob_incapacitated() || !user.client)
user.unset_interaction()
-/obj/structure/machinery/m56d_hmg/clicked(mob/user, list/mods) //Making it possible to toggle burst fire. Perhaps have altclick be the safety on the gun?
+/obj/structure/machinery/m56d_hmg/clicked(mob/user, list/mods)
if (mods["ctrl"])
if(operator != user)
return ..()//only the operatore can toggle fire mode
if(!CAN_PICKUP(user, src))
return ..()
- burst_fire = !burst_fire
- to_chat(user, SPAN_NOTICE("You set [src] to [burst_fire ? "burst fire" : "single fire"] mode."))
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 25, 1)
+
+ do_toggle_firemode(user)
+ playsound(src, 'sound/items/Deconstruct.ogg', 25, 1)
return TRUE
return ..()
@@ -976,724 +940,167 @@
if(operator)
to_chat(operator, SPAN_HIGHDANGER("You are knocked off the gun by the sheer force of the ram!"))
operator.unset_interaction()
- operator.apply_effect(M2C_CRUSHER_STUN, WEAKEN)
+ operator.apply_effect(3, WEAKEN)
-/obj/structure/machinery/m56d_hmg/mg_turret //Our mapbound version with stupid amounts of ammo.
- name = "\improper scoped M56D heavy machine gun nest"
- desc = "A scoped M56D heavy machine gun mounted upon a small reinforced post with sandbags to provide a small machine gun nest for all your defensive needs. Drag its sprite onto yourself to man it. Ctrl-click it to toggle burst fire."
- burst_fire = 1
- fire_delay = 2
- rounds = 1500
- rounds_max = 1500
- locked = 1
- projectile_coverage = PROJECTILE_COVERAGE_HIGH
- icon = 'icons/turf/whiskeyoutpost.dmi'
- zoom = 1
-
-/obj/structure/machinery/m56d_hmg/mg_turret/dropship
- name = "\improper scoped M56D heavy machine gun"
- desc = "A scoped M56D heavy machine gun mounted behind a metal shield. Drag its sprite onto yourself to man it. Ctrl-click it to toggle burst fire."
- icon_full = "towergun_folding"
- icon_empty = "towergun_folding"
- var/obj/structure/dropship_equipment/mg_holder/deployment_system
-
-/obj/structure/machinery/m56d_hmg/mg_turret/dropship/Destroy()
- if(deployment_system)
- deployment_system.deployed_mg = null
- deployment_system = null
- return ..()
+/// Getter for burst_firing
+/obj/structure/machinery/m56d_hmg/proc/get_burst_firing()
+ return burst_firing
-/*M2C HEAVY MACHINEGUN AND ITS COMPONENTS */
-// AMMO
-/obj/item/ammo_magazine/m2c
- name = "M2C Ammunition Box (10x28mm tungsten rounds)"
- desc = "A box of 125, 10x28mm tungsten rounds for the M2 Heavy Machinegun System. Click the heavy machinegun while there's no ammo box loaded to reload the M2C."
- caliber = "10x28mm"
- w_class = SIZE_LARGE
- icon = 'icons/obj/items/weapons/guns/ammo_by_faction/uscm.dmi'
- icon_state = "m56de"
- item_state = "m56de"
- max_rounds = 125
- default_ammo = /datum/ammo/bullet/machinegun/auto
- gun_type = null
-
-//STORAGE BOX FOR THE MACHINEGUN
-/obj/item/storage/box/m56d/m2c
- name = "\improper M2C Assembly-Supply Crate"
- desc = "A large case labelled 'M2C, 10x28mm caliber heavy machinegun', seems to be fairly heavy to hold. contains a deadly M2C Heavy Machinegun System and its ammunition."
- icon = 'icons/turf/whiskeyoutpost.dmi'
- icon_state = "M56D_case"
- w_class = SIZE_HUGE
- storage_slots = 5
+/// Setter for burst_firing
+/obj/structure/machinery/m56d_hmg/proc/set_burst_firing(bursting = FALSE)
+ burst_firing = bursting
-/obj/item/storage/box/m56d/m2c/fill_preset_inventory()
- new /obj/item/device/m2c_gun(src)
- new /obj/item/ammo_magazine/m2c(src)
- new /obj/item/ammo_magazine/m2c(src)
- new /obj/item/ammo_magazine/m2c(src)
- new /obj/item/ammo_magazine/m2c(src)
+/// Clean up the target, shots fired, and other things related to when you stop firing
+/obj/structure/machinery/m56d_hmg/proc/reset_fire()
+ set_target(null)
+ set_auto_firing(FALSE)
+ shots_fired = 0
-// THE GUN ITSELF
-
-/obj/item/device/m2c_gun
- name = "\improper M2C heavy machine gun"
- desc = "The disassembled M2C HMG, with its telescopic tripods folded up and unable to fire."
- w_class = SIZE_HUGE
- flags_equip_slot = SLOT_BACK
- icon = 'icons/turf/whiskeyoutpost.dmi'
- icon_state = "M56DE_gun_mount"
- item_state = "M56DE_gun_mount"
- var/rounds = 0
- var/overheat_value = 0
- var/anti_cadehugger_range = 1
- var/broken_gun = FALSE
- var/field_recovery = 130
- health = 230
-
-/obj/item/device/m2c_gun/Initialize()
- . = ..()
- update_icon()
-
-/obj/item/device/m2c_gun/update_icon() //Lets generate the icon based on how much ammo it has.
- var/icon_name = initial(icon_state)
- if(broken_gun)
- icon_name += "_broken"
- if(!rounds)
- icon_name += "_e"
-
- else if(!broken_gun && !rounds)
- icon_name += "_e"
-
- icon_state = icon_name
-
-/obj/item/device/m2c_gun/proc/check_can_setup(mob/user, turf/rotate_check, turf/open/OT, list/ACR)
- if(!ishuman(user))
- return FALSE
- if(broken_gun)
- to_chat(user, SPAN_WARNING("You can't set up \the [src], it's completely broken!"))
- return FALSE
- if(SSinterior.in_interior(user))
- to_chat(usr, SPAN_WARNING("It's too cramped in here to deploy \a [src]."))
- return FALSE
- if(OT.density || !isturf(OT) || !OT.allow_construction)
- to_chat(user, SPAN_WARNING("You can't set up \the [src] here."))
- return FALSE
- if(rotate_check.density)
- to_chat(user, SPAN_WARNING("You can't set up \the [src] that way, there's a wall behind you!"))
- return FALSE
- for(var/obj/structure/potential_blocker in rotate_check)
- if(potential_blocker.density)
- to_chat(user, SPAN_WARNING("You can't set up \the [src] that way, there's \a [potential_blocker] behind you!"))
- return FALSE
- if((locate(/obj/structure/barricade) in ACR) || (locate(/obj/structure/window_frame) in ACR) || (locate(/obj/structure/window) in ACR) || (locate(/obj/structure/windoor_assembly) in ACR))
- to_chat(user, SPAN_WARNING("There are barriers nearby, you can't set up \the [src] here!"))
- return FALSE
- var/fail = FALSE
- for(var/obj/X in OT.contents - src)
- if(istype(X, /obj/structure/machinery/defenses))
- fail = TRUE
- break
- else if(istype(X, /obj/structure/machinery/door))
- fail = TRUE
- break
- else if(istype(X, /obj/structure/machinery/m56d_hmg))
- fail = TRUE
- break
- if(fail)
- to_chat(user, SPAN_WARNING("You can't install \the [src] here, something is in the way."))
- return FALSE
-
-
- if(!(user.alpha > 60))
- to_chat(user, SPAN_WARNING("You can't set this up while cloaked!"))
- return FALSE
- return TRUE
-
-
-/obj/item/device/m2c_gun/attack_self(mob/user)
- ..()
- var/turf/rotate_check = get_step(user.loc, turn(user.dir, 180))
- var/turf/open/OT = usr.loc
- var/list/ACR = range(anti_cadehugger_range, user.loc)
-
- if(!check_can_setup(user, rotate_check, OT, ACR))
+///Set the target and take care of hard delete
+/obj/structure/machinery/m56d_hmg/proc/set_target(atom/object)
+ if(object == target || object == loc)
return
-
- if(!do_after(user, M2C_SETUP_TIME, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
- return
-
- if(!check_can_setup(user, rotate_check, OT, ACR))
- return
-
- var/obj/structure/machinery/m56d_hmg/auto/M = new /obj/structure/machinery/m56d_hmg/auto(user.loc)
- transfer_label_component(M)
- M.setDir(user.dir) // Make sure we face the right direction
- M.anchored = TRUE
- playsound(M, 'sound/items/m56dauto_setup.ogg', 75, TRUE)
- to_chat(user, SPAN_NOTICE("You deploy \the [M]."))
- if((rounds > 0) && !user.get_inactive_hand())
- user.set_interaction(M)
- give_action(user, /datum/action/human_action/mg_exit)
- M.rounds = rounds
- M.overheat_value = overheat_value
- M.health = health
- M.update_icon()
- qdel(src)
-
-/obj/item/device/m2c_gun/attackby(obj/item/O as obj, mob/user as mob)
- if(!ishuman(user))
- return
-
- if(!iswelder(O) || user.action_busy)
+ if(target)
+ UnregisterSignal(target, COMSIG_PARENT_QDELETING)
+ target = object
+ if(target)
+ RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clean_target))
+
+/// Setter for auto_firing
+/obj/structure/machinery/m56d_hmg/proc/set_auto_firing(auto = FALSE)
+ auto_firing = auto
+
+/// Print how much ammo is left to chat
+/obj/structure/machinery/m56d_hmg/proc/display_ammo()
+ if(!operator)
return
- if(!HAS_TRAIT(O, TRAIT_TOOL_BLOWTORCH))
- to_chat(user, SPAN_WARNING("You need a stronger blowtorch!"))
- return
+ if(display_ammo)
+ var/chambered = in_chamber ? TRUE : FALSE
+ to_chat(operator, SPAN_DANGER("[rounds][chambered ? "+1" : ""] / [rounds_max] ROUNDS REMAINING"))
- if(!broken_gun)
- to_chat(user, SPAN_WARNING("\The [src] isn't critically broken, no need for field recovery operations."))
+/// Toggles the gun's firemode one down the list
+/obj/structure/machinery/m56d_hmg/proc/do_toggle_firemode(mob/user, new_firemode)
+ if(get_burst_firing())//can't toggle mid burst
return
- var/obj/item/tool/weldingtool/WT = O
+ if(!length(gun_firemodes))
+ CRASH("[src] called do_toggle_firemode() with an empty gun_firemodes")
- if(WT.remove_fuel(2, user))
- user.visible_message(SPAN_NOTICE("[user] begins field recovering \the [src]."), \
- SPAN_NOTICE("You begin repairing the severe damages on \the [src] in an effort to restore its functions."))
- playsound(src.loc, 'sound/items/Welder2.ogg', 25, 1)
- if(!do_after(user, field_recovery * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src))
- return
- user.visible_message(SPAN_NOTICE("[user] field recovers \the [src], restoring it back to its original state."), \
- SPAN_NOTICE("You repair \the [src] back to a functional state."))
- broken_gun = FALSE
- health = 110
- update_icon()
+ if(length(gun_firemodes) == 1)
+ to_chat(user, SPAN_NOTICE("[icon2html(src, user)] This gun only has one firemode."))
return
- else
- to_chat(user, SPAN_WARNING("You need more fuel in \the [WT] to start field recovery on [src]."))
-// MACHINEGUN, AUTOMATIC
-/obj/structure/machinery/m56d_hmg/auto
- name = "\improper M2C Heavy Machinegun"
- desc = "A deployable, heavy machine gun. The M2C 'Chimp' HB is a modified M2 HB reconfigured to fire 10x28 Caseless Tungsten rounds for USCM use. It is capable of recoilless fire and fast-rotating. However it has a debilitating overheating issue due to the poor quality of metals used in the parts, forcing it to be used in decisive, crushing engagements as a squad support weapon. Click its sprite while behind it without holding anything to man it. Click-drag on NON-GRAB intent to disassemble the gun, GRAB INTENT to remove ammo magazines."
- icon = 'icons/turf/whiskeyoutpost.dmi'
- icon_state = "M56DE"
- icon_full = "M56DE"
- icon_empty = "M56DE_e"
- rounds_max = 125
- ammo = /datum/ammo/bullet/machinegun/auto
- fire_delay = 1.1
- last_fired = 0
- var/grip_dir = null
- var/fold_time = 1.5 SECONDS
- var/repair_time = 5 SECONDS
- density = TRUE
- health = 230
- health_max = 230
- var/list/cadeblockers = list()
- var/cadeblockers_range = 1
-
- var/static/image/barrel_overheat_image
- var/has_barrel_overlay = FALSE
-
- gun_noise = 'sound/weapons/gun_m56d_auto.ogg'
- empty_alarm = 'sound/weapons/hmg_eject_mag.ogg'
-
- // OVERHEAT MECHANIC VARIABLES
- var/overheat_value = 0
- var/overheat_threshold = 40
- var/emergency_cooling = FALSE
- var/overheat_text_cooldown = 0
- var/force_cooldown_timer = 10
- var/rotate_timer = 0
- var/fire_stopper = FALSE
-
- // Muzzle Flash Offsets
- north_x_offset = 0
- north_y_offset = 10
- east_x_offset = 0
- east_y_offset = 12
- south_x_offset = 0
- south_y_offset = 10
- west_x_offset = 0
- west_y_offset = 12
-
-// ANTI-CADE EFFECT, CREDIT TO WALTERMELDRON
-
-/obj/structure/machinery/m56d_hmg/auto/Initialize()
- . = ..()
- for(var/turf/T in range(cadeblockers_range, src))
- var/obj/structure/blocker/anti_cade/CB = new(T)
- CB.hmg = src
-
- cadeblockers.Add(CB)
-
- if(!barrel_overheat_image)
- barrel_overheat_image = image('icons/turf/whiskeyoutpost.dmi', "+m56de_overheat")
-
-/obj/structure/machinery/m56d_hmg/auto/Destroy()
- QDEL_NULL_LIST(cadeblockers)
- return ..()
-
-/obj/structure/machinery/m56d_hmg/auto/process()
-
- var/mob/user = operator
- overheat_value -= M2C_PASSIVE_COOLDOWN_AMOUNT
- if(overheat_value <= 0)
- overheat_value = 0
- STOP_PROCESSING(SSobj, src)
-
- if(overheat_value >= M2C_OVERHEAT_CRITICAL)
- to_chat(user, SPAN_HIGHDANGER("[src]'s barrel is critically hot, it might start melting at this rate."))
- else if(overheat_value >= M2C_OVERHEAT_BAD)
- to_chat(user, SPAN_DANGER("[src]'s barrel is terribly hot, but is still able to fire."))
- else if(overheat_value >= M2C_OVERHEAT_OK)
- to_chat(user, SPAN_DANGER("[src]'s barrel is pretty hot, although it's still stable."))
- else if (overheat_value > 0)
- to_chat(user, SPAN_WARNING("[src]'s barrel is mildly warm."))
-
- update_icon()
-
-// ANTI-CADE EFFECT, CREDIT TO WALTERMELDRON
-/obj/structure/blocker/anti_cade
- health = INFINITY
- anchored = TRUE
- density = FALSE
- unacidable = TRUE
- indestructible = TRUE
- invisibility = 101 // no looking at it with alt click
-
- var/obj/structure/machinery/m56d_hmg/auto/hmg
-
- alpha = 0
-
-/obj/structure/blocker/anti_cade/BlockedPassDirs(atom/movable/AM, target_dir)
- if(istype(AM, /obj/structure/barricade))
- return BLOCKED_MOVEMENT
- else if(istype(AM, /obj/structure/window))
- return BLOCKED_MOVEMENT
- else if(istype(AM, /obj/structure/windoor_assembly))
- return BLOCKED_MOVEMENT
- else if(istype(AM, /obj/structure/machinery/door))
- return BLOCKED_MOVEMENT
- return ..()
-
-/obj/structure/blocker/anti_cade/Destroy()
- if(hmg)
- hmg.cadeblockers.Remove(src)
- hmg = null
-
- return ..()
-
-/obj/structure/machinery/m56d_hmg/auto/update_icon() //Lets generate the icon based on how much ammo it has.
- if(!rounds)
- icon_state = "[icon_empty]"
+ if(new_firemode)
+ if(!(new_firemode in gun_firemodes))
+ CRASH("[src] called do_toggle_firemode() with [new_firemode] new_firemode, not on gun_firemodes")
+ gun_firemode = new_firemode
else
- icon_state = "[icon_full]"
-
- if(overheat_value >= M2C_OVERHEAT_OVERLAY)
- if(has_barrel_overlay)
- return
- overlays += barrel_overheat_image
- has_barrel_overlay = TRUE
- else if(has_barrel_overlay)
- overlays -= barrel_overheat_image
- has_barrel_overlay = FALSE
-
-// DED
-
-/obj/structure/machinery/m56d_hmg/auto/update_health(amount) //Negative values restores health.
- health -= amount
- if(health <= 0)
- playsound(src.loc, 'sound/items/Welder2.ogg', 25, 1)
- visible_message(SPAN_WARNING("[src] has broken down completely!"))
- var/obj/item/device/m2c_gun/HMG = new(src.loc)
- HMG.rounds = rounds
- HMG.broken_gun = TRUE
- HMG.unacidable = FALSE
- HMG.health = 0
- HMG.update_icon()
- qdel(src)
- return
-
- if(health > health_max)
- health = health_max
- update_damage_state()
- update_icon()
-
-/obj/structure/machinery/m56d_hmg/auto/attackby(obj/item/O as obj, mob/user as mob)
- if(!ishuman(user))
- return
- // RELOADING
- if(istype(O, /obj/item/ammo_magazine/m2c))
- var/obj/item/ammo_magazine/m2c/M = O
- if(rounds)
- to_chat(user, SPAN_WARNING("There's already an ammo box inside of the machinegun, remove it first!"))
- return
- if(user.action_busy) return
- user.visible_message(SPAN_NOTICE(" [user] loads [src] with an ammo box! "),SPAN_NOTICE(" You load [src] with an ammo box!"))
- playsound(src.loc, 'sound/items/m56dauto_load.ogg', 75, 1)
- rounds = min(rounds + M.current_rounds, rounds_max)
- update_icon()
- user.temp_drop_inv_item(O)
- qdel(O)
- return
-
- // WELDER REPAIR
- if(iswelder(O))
- if(!HAS_TRAIT(O, TRAIT_TOOL_BLOWTORCH))
- to_chat(user, SPAN_WARNING("You need a stronger blowtorch!"))
- return
- if(user.action_busy)
- return
-
- var/obj/item/tool/weldingtool/WT = O
-
- if(health == health_max)
- to_chat(user, SPAN_WARNING("[src] doesn't need repairs, it's well-maintained."))
- return
-
- if(WT.remove_fuel(2, user))
- user.visible_message(SPAN_NOTICE("[user] begins repairing damage on \the [src]."), \
- SPAN_NOTICE("You begin repairing the damage on \the [src]."))
- playsound(src.loc, 'sound/items/Welder2.ogg', 25, 1)
- if(!do_after(user, repair_time * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src))
- return
- user.visible_message(SPAN_NOTICE("[user] repairs some of the damage on [src]."), \
- SPAN_NOTICE("You repair [src]."))
- update_health(-round(health_max*0.2))
- playsound(src.loc, 'sound/items/Welder2.ogg', 25, 1)
+ var/mode_index = gun_firemodes.Find(gun_firemode)
+ if(++mode_index <= length(gun_firemodes))
+ gun_firemode = gun_firemodes[mode_index]
else
- to_chat(user, SPAN_WARNING("You need more fuel in [WT] to repair damage to [src]."))
- return
- return
+ gun_firemode = gun_firemodes[1]
-/obj/structure/machinery/m56d_hmg/auto/handle_modded_clicks(mob/living/carbon/human/user, list/mods)
- if(mods["middle"])
- handle_rotating_gun(user)
+ playsound(user, 'sound/weapons/handling/gun_burst_toggle.ogg', 15, 1)
- return ..()
+ to_chat(user, SPAN_NOTICE("[icon2html(src, user)] You switch to [gun_firemode]."))
+ SEND_SIGNAL(src, COMSIG_GUN_FIRE_MODE_TOGGLE, gun_firemode)
-// AUTOMATIC FIRING
-
-/obj/structure/machinery/m56d_hmg/auto/proc/auto_fire_start(client/source, atom/A, params)
+///Set the target to its turf, so we keep shooting even when it was qdeled
+/obj/structure/machinery/m56d_hmg/proc/clean_target()
SIGNAL_HANDLER
- if(!(source.mob == operator) || !A)
- return
- var/mob/living/carbon/human/user = operator
- target = A
+ target = get_turf(target)
- if(params["shift"] || params["ctrl"] || params["alt"])
- return
-
- if(istype(A, /atom/movable/screen))
- return
-
- if(user.get_active_hand() || user.get_inactive_hand())
- return
-
- if(!rounds)
- to_chat(user, SPAN_WARNING("*click*"))
- playsound(src, 'sound/weapons/gun_empty.ogg', 30, 1, 5)
+/obj/structure/machinery/m56d_hmg/proc/stop_fire()
+ SIGNAL_HANDLER
+ if(!target)
return
- params = params
- target = A
-
- handle_rotating_gun(user)
+ if(gun_firemode == GUN_FIREMODE_AUTOMATIC)
+ reset_fire()
+ display_ammo()
+ SEND_SIGNAL(src, COMSIG_GUN_STOP_FIRE)
- INVOKE_ASYNC(src, PROC_REF(auto_fire_repeat), user)
-
-/obj/structure/machinery/m56d_hmg/auto/proc/auto_fire_stop(client/source, atom/A, params)
+///Update the target if you draged your mouse
+/obj/structure/machinery/m56d_hmg/proc/change_target(datum/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params)
SIGNAL_HANDLER
- target = null
+ set_target(get_turf_on_clickcatcher(over_object, operator, params))
+ operator?.face_atom(target)
-/obj/structure/machinery/m56d_hmg/auto/proc/auto_fire_new_target(client/source, atom/start, atom/hovered, params)
+///Check if the gun can fire and add it to bucket auto_fire system if needed, or just fire the gun if not
+/obj/structure/machinery/m56d_hmg/proc/start_fire(datum/source, atom/object, turf/location, control, params, bypass_checks = FALSE)
SIGNAL_HANDLER
- if(!(source.mob == operator))
- return
- var/mob/user = operator
- if(istype(hovered, /atom/movable/screen))
+ var/list/modifiers = params2list(params)
+ if(modifiers["shift"] || modifiers["middle"] || modifiers["right"])
return
- if(get_turf(hovered) == get_turf(user))
+ // Don't allow doing anything else if inside a container of some sort, like a locker.
+ if(!isturf(operator.loc))
return
- target = hovered
-
- handle_rotating_gun(user)
-
-/obj/structure/machinery/m56d_hmg/auto/proc/auto_fire_repeat(mob/living/carbon/human/user, atom/A)
- if(!target)
- return
- if(operator != user)
- return
- if(fire_stopper)
+ if(istype(object, /atom/movable/screen))
return
- if(user.get_active_hand() || user.get_inactive_hand())
- to_chat(usr, SPAN_WARNING("You need both your hands free to shoot [src]."))
- return
- if(!user.allow_gun_usage)
- to_chat(user, SPAN_WARNING("You aren't allowed to use firearms!"))
- return
-
- var/angle = get_dir(src,target)
- if((dir & angle) && target.loc != src.loc && target.loc != operator.loc)
-
- if(overheat_value >= overheat_threshold)
- if(world.time > overheat_text_cooldown)
- user.visible_message(SPAN_HIGHDANGER("[src] has overheated and has been shortly disabled!"),SPAN_HIGHDANGER("[src] has overheated! You have to wait for it to cooldown!"))
- overheat_text_cooldown = world.time + 3 SECONDS
- if(!emergency_cooling)
- emergency_cooling = TRUE
- to_chat(user, SPAN_DANGER("You wait for [src]'s barrel to cooldown to continue sustained fire."))
- fire_stopper = TRUE
- STOP_PROCESSING(SSobj, src)
- addtimer(CALLBACK(src, PROC_REF(force_cooldown)), force_cooldown_timer)
-
- else if(overheat_value < overheat_threshold)
- fire_shot(1, user)
- if(rounds)
- overheat_value = overheat_value + 1
- START_PROCESSING(SSobj, src)
-
- addtimer(CALLBACK(src, PROC_REF(auto_fire_repeat), user), fire_delay)
-
-/obj/structure/machinery/m56d_hmg/auto/handle_ammo_out(mob/user)
- visible_message(SPAN_NOTICE("[icon2html(src, viewers(src))] \The [src]'s ammo box drops onto the ground, now completely empty."))
- playsound(loc, empty_alarm, 70, 1)
- update_icon() //final safeguard.
- var/obj/item/ammo_magazine/m2c/AM = new /obj/item/ammo_magazine/m2c(src.loc)
- AM.current_rounds = 0
- AM.update_icon()
-
-/obj/structure/machinery/m56d_hmg/auto/get_scatter()
- return 0
-
-// ACTIVE COOLING
-
-/obj/structure/machinery/m56d_hmg/auto/proc/force_cooldown(mob/user)
- user = operator
-
- overheat_value = round((rand(M2C_LOW_COOLDOWN_ROLL,M2C_HIGH_COOLDOWN_ROLL) * overheat_threshold))
- playsound(src.loc, 'sound/weapons/hmg_cooling.ogg', 75, 1)
- to_chat(user, SPAN_NOTICE("[src]'s barrel has cooled down enough to restart firing."))
- emergency_cooling = FALSE
- fire_stopper = FALSE
- fire_delay = initial(fire_delay)
- update_health(M2C_OVERHEAT_DAMAGE)
- START_PROCESSING(SSobj, src)
- update_icon()
-
-// TOGGLE MODE
-
-/obj/structure/machinery/m56d_hmg/auto/clicked(mob/user, list/mods, atom/A)
- if (mods["ctrl"])
- if(operator != user)
- return ..()
- if(!CAN_PICKUP(user, src))
- return ..()
- to_chat(user, SPAN_NOTICE("You try to toggle a burst-mode on \the [src], but realize that it doesn't exist."))
- return TRUE
-
- return ..()
-
-/obj/structure/machinery/m56d_hmg/auto/fire_shot(shots_fired = 1, mob/user)
- if(fire_stopper) return
-
- return ..()
-
-//ATTACK WITH BOTH HANDS COMBO
-
-/obj/structure/machinery/m56d_hmg/auto/attack_hand(mob/user)
- ..()
-
- var/turf/user_turf = get_turf(user)
- for(var/opp_dir in reverse_nearby_direction(src.dir))
- if(get_step(src, opp_dir) == user_turf)
- if(operator) //If there is already a operator then they're manning it.
- if(operator.interactee == null)
- operator = null //this shouldn't happen, but just in case
- else
- to_chat(user, "Someone's already controlling it.")
- return
- if(!(user.alpha > 60))
- to_chat(user, SPAN_WARNING("You aren't going to be setting up while cloaked."))
- return
- else
- if(user.interactee) //Make sure we're not manning two guns at once, tentacle arms.
- to_chat(user, "You're already manning something!")
- return
-
- if(user.get_active_hand() == null && user.get_inactive_hand() == null)
- user.freeze()
- user.set_interaction(src)
- give_action(user, /datum/action/human_action/mg_exit)
- else
- to_chat(usr, SPAN_NOTICE("Your hands are too busy holding things to grab the handles!"))
- else
- to_chat(usr, SPAN_NOTICE("You are too far from the handles to man [src]!"))
-
-// DISASSEMBLY
-
-/obj/structure/machinery/m56d_hmg/auto/MouseDrop(over_object, src_location, over_location)
- if(!ishuman(usr)) return
- var/mob/living/carbon/human/user = usr
-
- if(over_object == user && in_range(src, user))
- if((rounds > 0) && (user.a_intent & (INTENT_GRAB)))
- playsound(src.loc, 'sound/items/m56dauto_load.ogg', 75, 1)
- user.visible_message(SPAN_NOTICE(" [user] removes [src]'s ammo box."),SPAN_NOTICE(" You remove [src]'s ammo box, preparing the gun for disassembly."))
- var/obj/item/ammo_magazine/m2c/used_ammo = new(user.loc)
- used_ammo.current_rounds = rounds
- user.put_in_active_hand(used_ammo)
- rounds = 0
-
- else
- if(!do_after(user, fold_time* user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src)) // disassembly time reduced
- return
- user.visible_message(SPAN_NOTICE("[user] disassembles [src]."),SPAN_NOTICE("You fold up the tripod for [src], disassembling it."))
- playsound(src.loc, 'sound/items/m56dauto_setup.ogg', 75, 1)
- var/obj/item/device/m2c_gun/HMG = new(src.loc)
- transfer_label_component(HMG)
- HMG.rounds = src.rounds
- HMG.overheat_value = round(0.5 * src.overheat_value)
- if (HMG.overheat_value <= 10)
- HMG.overheat_value = 0
- HMG.update_icon()
- HMG.health = health
- user.put_in_active_hand(HMG)
- if(user.equip_to_slot_if_possible(HMG, WEAR_BACK, disable_warning = TRUE))
- to_chat(user, SPAN_NOTICE("You quickly heave the machine gun onto your back!"))
- qdel(src)
-
- update_icon()
-
-// MOUNT THE MG
-
-/obj/structure/machinery/m56d_hmg/auto/on_set_interaction(mob/user)
- ..()
- ADD_TRAIT(user, TRAIT_OVERRIDE_CLICKDRAG, TRAIT_SOURCE_WEAPON)
- if(user.client)
- RegisterSignal(user.client, COMSIG_CLIENT_LMB_DOWN, PROC_REF(auto_fire_start))
- RegisterSignal(user.client, COMSIG_CLIENT_LMB_UP, PROC_REF(auto_fire_stop))
- RegisterSignal(user.client, COMSIG_CLIENT_LMB_DRAG, PROC_REF(auto_fire_new_target))
- RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(disable_interaction))
- RegisterSignal(user, COMSIG_MOB_POST_UPDATE_CANMOVE, PROC_REF(disable_canmove_interaction))
-
-// DISMOUNT THE MG
-
-/obj/structure/machinery/m56d_hmg/auto/on_unset_interaction(mob/user)
- REMOVE_TRAIT(user, TRAIT_OVERRIDE_CLICKDRAG, TRAIT_SOURCE_WEAPON)
- UnregisterSignal(user, list(
- COMSIG_MOVABLE_PRE_MOVE,
- COMSIG_MOB_POST_UPDATE_CANMOVE
- ))
- ..()
-
-// GET ANIMATED
-
-/obj/structure/machinery/m56d_hmg/auto/update_pixels(mob/user, mounting = TRUE)
- if(mounting)
- var/diff_x = 0
- var/diff_y = 0
- var/tilesize = 32
- var/viewoffset = tilesize * 1
-
- user.reset_view(src)
- if(dir == EAST)
- diff_x = -16 + user_old_x
- user.client.pixel_x = viewoffset
- user.client.pixel_y = 0
- if(dir == WEST)
- diff_x = 16 + user_old_x
- user.client.pixel_x = -viewoffset
- user.client.pixel_y = 0
- if(dir == NORTH)
- diff_y = -16 + user_old_y
- user.client.pixel_x = 0
- user.client.pixel_y = viewoffset
- if(dir == SOUTH)
- diff_y = 16 + user_old_y
- user.client.pixel_x = 0
- user.client.pixel_y = -viewoffset
-
- animate(user, pixel_x=diff_x, pixel_y=diff_y, 0.4 SECONDS)
- else
- if(user.client)
- user.client.change_view(world_view_size)
- user.client.pixel_x = 0
- user.client.pixel_y = 0
- UnregisterSignal(user.client, list(
- COMSIG_CLIENT_LMB_DOWN,
- COMSIG_CLIENT_LMB_UP,
- COMSIG_CLIENT_LMB_DRAG,
- ))
-
- animate(user, pixel_x=user_old_x, pixel_y=user_old_y, 4, 1)
+ if(!bypass_checks)
+ if(operator.throw_mode)
+ return
-//ROTATE THE MACHINEGUN
+ if(operator.Adjacent(object)) //Dealt with by attack code
+ return
-/obj/structure/machinery/m56d_hmg/auto/proc/rotate_to(mob/user, atom/A)
- if(!A || !user.x || !user.y || !A.x || !A.y)
+ if(QDELETED(object))
return
- var/dx = A.x - user.x
- var/dy = A.y - user.y
- if(!dx && !dy)
- return
-
- var/direction
- if(abs(dx) < abs(dy))
- if(dy > 0)
- direction = NORTH
- else
- direction = SOUTH
- else
- if(dx > 0)
- direction = EAST
- else
- direction = WEST
- var/turf/rotate_check = get_step(src.loc, turn(direction,180))
- if(rotate_check.density)
- to_chat(user, SPAN_WARNING("You can't rotate it that way."))
+ set_target(get_turf_on_clickcatcher(object, operator, params))
+ if((gun_firemode == GUN_FIREMODE_SEMIAUTO) && COOLDOWN_FINISHED(src, semiauto_fire_cooldown))
+ COOLDOWN_START(src, semiauto_fire_cooldown, semiauto_cooldown_time)
+ fire_shot()
+ reset_fire()
+ display_ammo()
return
+ SEND_SIGNAL(src, COMSIG_GUN_FIRE)
- src.setDir(direction)
- user.setDir(direction)
- update_pixels(user)
- playsound(src.loc, 'sound/items/m56dauto_rotate.ogg', 25, 1)
- to_chat(user, SPAN_NOTICE("You rotate [src], using the tripod to support your pivoting movement."))
-
+/// setter for fire_delay
+/obj/structure/machinery/m56d_hmg/proc/set_fire_delay(value)
+ fire_delay = value
+ SEND_SIGNAL(src, COMSIG_GUN_AUTOFIREDELAY_MODIFIED, fire_delay)
-/obj/structure/machinery/m56d_hmg/auto/proc/disable_interaction(mob/user, NewLoc, direction)
- SIGNAL_HANDLER
+/// getter for fire_delay
+/obj/structure/machinery/m56d_hmg/proc/get_fire_delay(value)
+ return fire_delay
- if(user.lying || get_dist(user,src) > 0 || user.is_mob_incapacitated() || !user.client)
- user.unset_interaction()
+/// setter for burst_amount
+/obj/structure/machinery/m56d_hmg/proc/set_burst_amount(value, mob/user)
+ burst_amount = value
+ SEND_SIGNAL(src, COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED, burst_amount)
-/obj/structure/machinery/m56d_hmg/auto/proc/disable_canmove_interaction(mob/user, canmove, laid_down, lying)
- SIGNAL_HANDLER
+/// Setter for burst_delay
+/obj/structure/machinery/m56d_hmg/proc/set_burst_fire_delay(value, mob/user)
+ burst_fire_delay = value
+ SEND_SIGNAL(src, COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED, burst_fire_delay)
- if(laid_down)
- user.unset_interaction()
+/obj/structure/machinery/m56d_hmg/mg_turret //Our mapbound version with stupid amounts of ammo.
+ name = "\improper scoped M56D heavy machine gun nest"
+ desc = "A scoped M56D heavy machine gun mounted upon a small reinforced post with sandbags to provide a small machine gun nest for all your defensive needs. Drag its sprite onto yourself to man it. Ctrl-click it to toggle burst fire."
+ fire_delay = 2
+ rounds = 1500
+ rounds_max = 1500
+ locked = 1
+ projectile_coverage = PROJECTILE_COVERAGE_HIGH
+ icon = 'icons/turf/whiskeyoutpost.dmi'
+ zoom = 1
-/obj/structure/machinery/m56d_hmg/auto/proc/handle_rotating_gun(mob/user)
- var/angle = get_dir(src, target)
- if(world.time > rotate_timer && !((dir & angle) && target.loc != src.loc && target.loc != operator.loc))
- rotate_timer = world.time + 0.4 SECONDS
- rotate_to(user, target)
- return TRUE
+/obj/structure/machinery/m56d_hmg/mg_turret/dropship
+ name = "\improper scoped M56D heavy machine gun"
+ desc = "A scoped M56D heavy machine gun mounted behind a metal shield. Drag its sprite onto yourself to man it. Ctrl-click it to toggle burst fire."
+ icon_full = "towergun_folding"
+ icon_empty = "towergun_folding"
+ var/obj/structure/dropship_equipment/mg_holder/deployment_system
-#undef M2C_OVERHEAT_CRITICAL
-#undef M2C_OVERHEAT_BAD
-#undef M2C_OVERHEAT_OK
-#undef M2C_SETUP_TIME
-#undef M2C_OVERHEAT_DAMAGE
-#undef M2C_LOW_COOLDOWN_ROLL
-#undef M2C_HIGH_COOLDOWN_ROLL
-#undef M2C_PASSIVE_COOLDOWN_AMOUNT
-#undef M2C_OVERHEAT_OVERLAY
-#undef M2C_CRUSHER_STUN
+/obj/structure/machinery/m56d_hmg/mg_turret/dropship/Destroy()
+ if(deployment_system)
+ deployment_system.deployed_mg = null
+ deployment_system = null
+ return ..()
diff --git a/code/modules/cm_preds/yaut_bracers.dm b/code/modules/cm_preds/yaut_bracers.dm
index c9976c7fea89..4e8dbf9d711a 100644
--- a/code/modules/cm_preds/yaut_bracers.dm
+++ b/code/modules/cm_preds/yaut_bracers.dm
@@ -677,6 +677,8 @@
if (exploding)
return
+ notify_ghosts(header = "Yautja self destruct", message = "[victim] is self destructing to protect their honor!", source = victim, action = NOTIFY_ORBIT)
+
exploding = 1
var/turf/T = get_turf(src)
if(explosion_type == SD_TYPE_BIG && victim.stat == CONSCIOUS && (is_ground_level(T.z) || MODE_HAS_TOGGLEABLE_FLAG(MODE_SHIPSIDE_SD)))
diff --git a/code/modules/economy/ATM.dm b/code/modules/economy/ATM.dm
index ecf76b577c1d..2e9142dcef91 100644
--- a/code/modules/economy/ATM.dm
+++ b/code/modules/economy/ATM.dm
@@ -358,7 +358,7 @@ log transactions
//stamp the paper
var/image/stampoverlay = image('icons/obj/items/paper.dmi')
- stampoverlay.icon_state = "paper_stamp-cent"
+ stampoverlay.icon_state = "paper_stamp-weyyu"
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/tool/stamp
@@ -400,7 +400,7 @@ log transactions
//stamp the paper
var/image/stampoverlay = image('icons/obj/items/paper.dmi')
- stampoverlay.icon_state = "paper_stamp-cent"
+ stampoverlay.icon_state = "paper_stamp-weyyu"
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/tool/stamp
diff --git a/code/modules/economy/EFTPOS.dm b/code/modules/economy/EFTPOS.dm
index fbaf1f52adea..a5b36fd0bf3e 100644
--- a/code/modules/economy/EFTPOS.dm
+++ b/code/modules/economy/EFTPOS.dm
@@ -47,12 +47,12 @@
//stamp the paper
var/image/stampoverlay = image('icons/obj/items/paper.dmi')
- stampoverlay.icon_state = "paper_stamp-cent"
+ stampoverlay.icon_state = "paper_stamp-rd"
if(!R.stamped)
R.stamped = new
R.offset_x += 0
R.offset_y += 0
- R.ico += "paper_stamp-cent"
+ R.ico += "paper_stamp-rd"
R.stamped += /obj/item/tool/stamp
R.overlays += stampoverlay
R.stamps += "
This paper has been stamped by the EFTPOS device."
@@ -70,7 +70,7 @@
//stamp the paper
var/image/stampoverlay = image('icons/obj/items/paper.dmi')
- stampoverlay.icon_state = "paper_stamp-cent"
+ stampoverlay.icon_state = "paper_stamp-rd"
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/tool/stamp
diff --git a/code/modules/gear_presets/corpses.dm b/code/modules/gear_presets/corpses.dm
index 62782b77eae5..f0ad6f85a8b4 100644
--- a/code/modules/gear_presets/corpses.dm
+++ b/code/modules/gear_presets/corpses.dm
@@ -213,33 +213,6 @@
//*****************************************************************************************************/
-/datum/equipment_preset/corpse/clown
- name = "Corpse - Clown"
- assignment = "Clown"
- uses_special_name = TRUE
-
-/datum/equipment_preset/corpse/clown/New()
- . = ..()
- //As a joke, clown has all access so they can clown everywhere...
- access = get_access(ACCESS_LIST_DELIVERY)
-
-/datum/equipment_preset/corpse/clown/load_name(mob/living/carbon/human/new_human, randomise)
- . = ..() //To load gender, randomise appearance, etc.
- new_human.change_real_name(new_human, pick(clown_names)) //Picking a proper clown name!
-
-/datum/equipment_preset/corpse/clown/load_gear(mob/living/carbon/human/new_human)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/rank/clown(new_human), WEAR_BODY)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/clown_shoes(new_human), WEAR_FEET)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(new_human), WEAR_FACE)
- new_human.equip_to_slot_or_del(new /obj/item/toy/bikehorn(new_human), WEAR_R_STORE)
- new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/clown(new_human), WEAR_BACK)
- if(SSmapping.configs[GROUND_MAP].environment_traits[MAP_COLD])
- add_ice_colony_survivor_equipment(new_human)
- else
- new_human.equip_to_slot_or_del(new /obj/item/device/radio(new_human), WEAR_IN_BACK)
-
-//*****************************************************************************************************/
-
/datum/equipment_preset/corpse/scientist
name = "Corpse - Scientist"
assignment = "Scientist"
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 3b10c757f2f4..f78ca9ef5473 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -427,7 +427,7 @@
var/image/stampoverlay = image('icons/obj/items/paper.dmi')
var/x
var/y
- if(istype(P, /obj/item/tool/stamp/captain) || istype(P, /obj/item/tool/stamp/centcomm))
+ if(istype(P, /obj/item/tool/stamp/captain) || istype(P, /obj/item/tool/stamp/weyyu))
x = rand(-2, 0)
y = rand(-1, 2)
else
diff --git a/code/modules/shuttle/computers/escape_pod_computer.dm b/code/modules/shuttle/computers/escape_pod_computer.dm
index 1054bf5e90d7..6f9292cfc048 100644
--- a/code/modules/shuttle/computers/escape_pod_computer.dm
+++ b/code/modules/shuttle/computers/escape_pod_computer.dm
@@ -66,6 +66,9 @@
var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle = SSshuttle.getShuttle(shuttleId)
switch(action)
if("force_launch")
+ if(pod_state != STATE_READY && pod_state != STATE_DELAYED)
+ return
+
shuttle.evac_launch()
pod_state = STATE_LAUNCHING
. = TRUE
diff --git a/colonialmarines.dme b/colonialmarines.dme
index 5ac3a8e32d66..79ddef81b976 100644
--- a/colonialmarines.dme
+++ b/colonialmarines.dme
@@ -1523,6 +1523,7 @@ s// DM Environment file for colonialmarines.dme.
#include "code\modules\cm_marines\Donator_Kits.dm"
#include "code\modules\cm_marines\dropship_ammo.dm"
#include "code\modules\cm_marines\dropship_equipment.dm"
+#include "code\modules\cm_marines\m2c.dm"
#include "code\modules\cm_marines\marines_consoles.dm"
#include "code\modules\cm_marines\NonLethalRestraints.dm"
#include "code\modules\cm_marines\orbital_cannon.dm"
diff --git a/html/changelogs/AutoChangeLog-pr-4111.yml b/html/changelogs/AutoChangeLog-pr-4111.yml
deleted file mode 100644
index 7d6a5f024ee7..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4111.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "realforest2001"
-delete-after: True
-changes:
- - rscadd: "Finally adds fully functional access request tickets to APOLLO console for entry to AI core."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4208.yml b/html/changelogs/AutoChangeLog-pr-4208.yml
deleted file mode 100644
index f27bd9ca4a91..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4208.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "realforest2001"
-delete-after: True
-changes:
- - maptweak: "Adds a couple APOLLO consoles to upper and lower medical. Moves the one outside ARES reception slightly."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4225.yml b/html/changelogs/AutoChangeLog-pr-4225.yml
deleted file mode 100644
index dec1d322ec9b..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4225.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-author: "realforest2001"
-delete-after: True
-changes:
- - bugfix: "Fixes ARES Security Logs and stops ARES logs recording mob datums instead of names."
- - rscadd: "Moves AntiAir records to Security Logs."
- - rscadd: "Adds Flight Records to ARES Interface, detailing launches and setting changes. Does not include CAS details."
- - code_imp: "Changes ARES log procs from using 'user' to 'user_name' to identify it should be the string rather than mob datum."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4304.yml b/html/changelogs/AutoChangeLog-pr-4304.yml
deleted file mode 100644
index 6781eac2c3ac..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4304.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "cuberound"
-delete-after: True
-changes:
- - balance: "GAU can hit mobs that are on ground now"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4350.yml b/html/changelogs/AutoChangeLog-pr-4350.yml
deleted file mode 100644
index 4780d592b9da..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4350.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-author: "realforest2001"
-delete-after: True
-changes:
- - rscadd: "Adds CN20-X Nerve Gas, an alteration of base CN20 that can affect xenos."
- - rscadd: "CN20 and CN20-X are now translucent and do not obstruct vision much."
- - admin: "Adds a VV list dropdown to release gas from vents as the manual proc was too clunky."
- - rscadd: "Adds nerve gas grenades for CN20 and CN20-X"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4352.yml b/html/changelogs/AutoChangeLog-pr-4352.yml
deleted file mode 100644
index 17a65c454e91..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4352.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Morrow"
-delete-after: True
-changes:
- - balance: "Cryorines now cost 6 points. It increases by 6 each purchase."
- - balance: "Cryorines now give 5 marines. 1 SL (for the first one only), 1 medic, 1 engi, rest rifleman."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4353.yml b/html/changelogs/AutoChangeLog-pr-4353.yml
deleted file mode 100644
index 13aa7a1a9f81..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4353.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "Morrow"
-delete-after: True
-changes:
- - balance: "Lowered the xeno endgame start to 55 minutes into the round"
- - balance: "Lowered the nuke endgame start to 115 minutes into the round"
- - balance: "Lowered the nuke cost to 5 points"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4354.yml b/html/changelogs/AutoChangeLog-pr-4354.yml
deleted file mode 100644
index eaed52c4651c..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4354.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Morrow"
-delete-after: True
-changes:
- - rscadd: "Added cryo specialist tech that can be purchased once for eight points"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4356.yml b/html/changelogs/AutoChangeLog-pr-4356.yml
deleted file mode 100644
index 36c53f8811d3..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4356.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Morrow"
-delete-after: True
-changes:
- - bugfix: "Fixed repeatable techs not having correct overlays"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4358.yml b/html/changelogs/AutoChangeLog-pr-4358.yml
deleted file mode 100644
index d83bf6aef916..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4358.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Morrow"
-delete-after: True
-changes:
- - bugfix: "Removed annoying and inaccurate to_chat from join response team menu"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4360.yml b/html/changelogs/AutoChangeLog-pr-4360.yml
deleted file mode 100644
index 01a6ceb93414..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4360.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Morrow"
-delete-after: True
-changes:
- - bugfix: "Firing flares into the air now produces light again"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4367.yml b/html/changelogs/AutoChangeLog-pr-4367.yml
deleted file mode 100644
index 6493aa6ffc4d..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4367.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-author: "realforest2001"
-delete-after: True
-changes:
- - code_imp: "Tidied up the TWE presets so they're easier to read."
- - rscdel: "Removed duplicate surgical line from all TWE presets."
- - rscadd: "Added an MRE box to the TWE MRE carrier preset."
- - spellcheck: "Added unique names to the RMC armors."
- - bugfix: "Fixed iconstate names being backwards for TWE pointman and SG."
- - code_imp: "Removed unnecessary repeated values for TWE armors."
- - code_imp: "Tidied the RMC skillsets to be consistent in ordering of skills."
- - rscadd: "Added an SG specific skillset for RMCs."
- - bugfix: "Fixed duplicate entry for medical training on RMC TL skillset."
- - spellcheck: "Renamed default RMC skillset to Royal Marines Commando rather than Royal Marines Commando Rifleman."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4371.yml b/html/changelogs/AutoChangeLog-pr-4371.yml
deleted file mode 100644
index 34e18a5e8e4f..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4371.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Morrow"
-delete-after: True
-changes:
- - rscadd: "Powerloader wreckage now can be attacked by xenos"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4372.yml b/html/changelogs/AutoChangeLog-pr-4372.yml
deleted file mode 100644
index e452bf1ee5b0..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4372.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Morrow"
-delete-after: True
-changes:
- - qol: "Recalibrating limbs can now be done with the patient standing"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4373.yml b/html/changelogs/AutoChangeLog-pr-4373.yml
deleted file mode 100644
index a2d3ba29c53d..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4373.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Morrow"
-delete-after: True
-changes:
- - rscdel: "Removed the shipside announcement for working joes joining"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4374.yml b/html/changelogs/AutoChangeLog-pr-4374.yml
deleted file mode 100644
index 1722b22bbf56..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4374.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Morrow"
-delete-after: True
-changes:
- - bugfix: "Fixed queens prying open lifeboat double doors"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4381.yml b/html/changelogs/AutoChangeLog-pr-4381.yml
deleted file mode 100644
index fe2c3cca9231..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4381.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "realforest2001"
-delete-after: True
-changes:
- - bugfix: "Fixes WY access to Almayer Research."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4384.yml b/html/changelogs/AutoChangeLog-pr-4384.yml
deleted file mode 100644
index f1998657fa3a..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4384.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Waseemq1235"
-delete-after: True
-changes:
- - admin: "Subtle messages are now much larger."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4392.yml b/html/changelogs/AutoChangeLog-pr-4392.yml
new file mode 100644
index 000000000000..5f22ab70e802
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4392.yml
@@ -0,0 +1,4 @@
+author: "Morrow"
+delete-after: True
+changes:
+ - bugfix: "Fixed lifepods still working after evac canceled"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4393.yml b/html/changelogs/AutoChangeLog-pr-4393.yml
new file mode 100644
index 000000000000..c04d711dbb7f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4393.yml
@@ -0,0 +1,4 @@
+author: "realforest2001"
+delete-after: True
+changes:
+ - rscadd: "Codebooks are now faction based rather than individually unique."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4399.yml b/html/changelogs/AutoChangeLog-pr-4399.yml
new file mode 100644
index 000000000000..ab2b1eb9aa4f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4399.yml
@@ -0,0 +1,4 @@
+author: "Zonespace27"
+delete-after: True
+changes:
+ - balance: "Coffins now layer above beds"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4403.yml b/html/changelogs/AutoChangeLog-pr-4403.yml
new file mode 100644
index 000000000000..8071a06ba537
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4403.yml
@@ -0,0 +1,4 @@
+author: "Morrow"
+delete-after: True
+changes:
+ - rscadd: "Added a ghost notification for yautja self destructs"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4406.yml b/html/changelogs/AutoChangeLog-pr-4406.yml
new file mode 100644
index 000000000000..d015f575c6e5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4406.yml
@@ -0,0 +1,9 @@
+author: "realforest2001"
+delete-after: True
+changes:
+ - imageadd: "Added a CMB stamp icon."
+ - imageadd: "Changes the icon_state name of the WY stamp from centcom to weyyu."
+ - rscadd: "Changes EFTPOS stamp icon to use RD instead of weyyu."
+ - bugfix: "Changes the pre-spawned QMs stamp to use the proper stamp."
+ - spellcheck: "Renames Requisiton Officer's stamp to Quartermaster's Stamp."
+ - maptweak: "Renamed the spare Req Officer's stamp to spare Quartermaster's stamp."
\ No newline at end of file
diff --git a/html/changelogs/archive/2023-09.yml b/html/changelogs/archive/2023-09.yml
index 750ae67a264e..ddcc704cd5cb 100644
--- a/html/changelogs/archive/2023-09.yml
+++ b/html/changelogs/archive/2023-09.yml
@@ -132,3 +132,62 @@
kylerace, lemoninthedark, harry:
- refactor: optimized icon-in-chat code
- bugfix: weird icons on the smoothed walls when examining or alt+clicking
+2023-09-12:
+ Morrow:
+ - balance: Lowered the xeno endgame start to 55 minutes into the round
+ - balance: Lowered the nuke endgame start to 115 minutes into the round
+ - balance: Lowered the nuke cost to 5 points
+ - rscdel: Removed the shipside announcement for working joes joining
+ - rscadd: Added cryo specialist tech that can be purchased once for eight points
+ - balance: Cryorines now cost 6 points. It increases by 6 each purchase.
+ - balance: Cryorines now give 5 marines. 1 SL (for the first one only), 1 medic,
+ 1 engi, rest rifleman.
+ - bugfix: Fixed queens prying open lifeboat double doors
+ - rscadd: Powerloader wreckage now can be attacked by xenos
+ - bugfix: Removed annoying and inaccurate to_chat from join response team menu
+ - bugfix: Firing flares into the air now produces light again
+ - bugfix: Fixed repeatable techs not having correct overlays
+ - qol: Recalibrating limbs can now be done with the patient standing
+ Waseemq1235:
+ - admin: Subtle messages are now much larger.
+ cuberound:
+ - balance: GAU can hit mobs that are on ground now
+ realforest2001:
+ - bugfix: Fixes ARES Security Logs and stops ARES logs recording mob datums instead
+ of names.
+ - rscadd: Moves AntiAir records to Security Logs.
+ - rscadd: Adds Flight Records to ARES Interface, detailing launches and setting
+ changes. Does not include CAS details.
+ - code_imp: Changes ARES log procs from using 'user' to 'user_name' to identify
+ it should be the string rather than mob datum.
+ - maptweak: Adds a couple APOLLO consoles to upper and lower medical. Moves the
+ one outside ARES reception slightly.
+ - bugfix: Fixes WY access to Almayer Research.
+ - rscadd: Finally adds fully functional access request tickets to APOLLO console
+ for entry to AI core.
+ - rscadd: Adds CN20-X Nerve Gas, an alteration of base CN20 that can affect xenos.
+ - rscadd: CN20 and CN20-X are now translucent and do not obstruct vision much.
+ - admin: Adds a VV list dropdown to release gas from vents as the manual proc was
+ too clunky.
+ - rscadd: Adds nerve gas grenades for CN20 and CN20-X
+ - code_imp: Tidied up the TWE presets so they're easier to read.
+ - rscdel: Removed duplicate surgical line from all TWE presets.
+ - rscadd: Added an MRE box to the TWE MRE carrier preset.
+ - spellcheck: Added unique names to the RMC armors.
+ - bugfix: Fixed iconstate names being backwards for TWE pointman and SG.
+ - code_imp: Removed unnecessary repeated values for TWE armors.
+ - code_imp: Tidied the RMC skillsets to be consistent in ordering of skills.
+ - rscadd: Added an SG specific skillset for RMCs.
+ - bugfix: Fixed duplicate entry for medical training on RMC TL skillset.
+ - spellcheck: Renamed default RMC skillset to Royal Marines Commando rather than
+ Royal Marines Commando Rifleman.
+2023-09-13:
+ Morrow:
+ - rscdel: Removed some mapped clown gear
+ TeDGamer:
+ - balance: Hive weeds can be supported by other structures when original parent
+ structure is destroyed.
+ Zonespace27:
+ - balance: M56D now has full auto mode.
+ - qol: M56D now has an ammo counter when firing.
+ - rscdel: M2C can no longer rotate with MMB
diff --git a/icons/obj/items/paper.dmi b/icons/obj/items/paper.dmi
index d0c918a65e59..c39fede23679 100644
Binary files a/icons/obj/items/paper.dmi and b/icons/obj/items/paper.dmi differ
diff --git a/maps/map_files/FOP_v3_Sciannex/Fiorina_SciAnnex.dmm b/maps/map_files/FOP_v3_Sciannex/Fiorina_SciAnnex.dmm
index 9d8033ae0ae8..e8c3bb319b7e 100644
--- a/maps/map_files/FOP_v3_Sciannex/Fiorina_SciAnnex.dmm
+++ b/maps/map_files/FOP_v3_Sciannex/Fiorina_SciAnnex.dmm
@@ -12808,9 +12808,7 @@
/area/fiorina/lz/near_lzII)
"hTr" = (
/obj/structure/closet,
-/obj/item/clothing/mask/gas/clown_hat,
/obj/effect/spawner/random/gun/shotgun/midchance,
-/obj/item/clothing/under/marine/ucf_clown,
/turf/open/floor/plating/prison,
/area/fiorina/maintenance)
"hTs" = (
@@ -25559,8 +25557,6 @@
/area/fiorina/tumor/aux_engi)
"pON" = (
/obj/structure/closet,
-/obj/item/storage/backpack/clown,
-/obj/item/toy/bikehorn,
/turf/open/floor/prison{
dir = 4;
icon_state = "bluecorner"
diff --git a/maps/map_files/Kutjevo/Kutjevo.dmm b/maps/map_files/Kutjevo/Kutjevo.dmm
index 646ed4dcbc8c..fed056caf3d4 100644
--- a/maps/map_files/Kutjevo/Kutjevo.dmm
+++ b/maps/map_files/Kutjevo/Kutjevo.dmm
@@ -16657,13 +16657,6 @@
/obj/structure/blocker/invisible_wall,
/turf/open/floor/kutjevo/colors/red/tile,
/area/kutjevo/interior/oob/dev_room)
-"wSN" = (
-/obj/structure/blocker/invisible_wall,
-/obj/effect/landmark/corpsespawner/clown,
-/turf/open/desert/desert_shore/desert_shore1{
- dir = 1
- },
-/area/kutjevo/interior/oob/dev_room)
"wSU" = (
/obj/structure/machinery/light{
dir = 4
@@ -20023,7 +20016,7 @@ rkt
jBJ
fOU
ibm
-wSN
+rYs
fAF
fQB
uam
diff --git a/maps/map_files/New_Varadero/New_Varadero.dmm b/maps/map_files/New_Varadero/New_Varadero.dmm
index d315d9bfd84b..ae2d59345596 100644
--- a/maps/map_files/New_Varadero/New_Varadero.dmm
+++ b/maps/map_files/New_Varadero/New_Varadero.dmm
@@ -29173,7 +29173,6 @@
/area/varadero/interior/cargo)
"sCK" = (
/obj/structure/closet/secure_closet/scientist,
-/obj/item/clothing/mask/gas/clown_hat,
/turf/open/floor/shiva{
dir = 8;
icon_state = "purple"
diff --git a/maps/map_files/Sorokyne_Strata/Sorokyne_Strata.dmm b/maps/map_files/Sorokyne_Strata/Sorokyne_Strata.dmm
index ff1d99eb8f78..edc1340df385 100644
--- a/maps/map_files/Sorokyne_Strata/Sorokyne_Strata.dmm
+++ b/maps/map_files/Sorokyne_Strata/Sorokyne_Strata.dmm
@@ -402,13 +402,6 @@
/obj/effect/blocker/sorokyne_cold_water,
/turf/open/gm/river,
/area/strata/ag/exterior/paths/cabin_area)
-"abx" = (
-/obj/effect/landmark/corpsespawner/clown,
-/turf/open/floor/strata{
- dir = 10;
- icon_state = "multi_tiles"
- },
-/area/strata/ag/interior/outpost/gen/bball/nest)
"aby" = (
/obj/structure/machinery/camera/autoname{
dir = 8
@@ -61048,7 +61041,7 @@ aac
aac
rKG
bsS
-abx
+cjq
bvt
rKG
aac
diff --git a/maps/map_files/USS_Almayer/USS_Almayer.dmm b/maps/map_files/USS_Almayer/USS_Almayer.dmm
index 8007d13db89e..eb05927b5f18 100644
--- a/maps/map_files/USS_Almayer/USS_Almayer.dmm
+++ b/maps/map_files/USS_Almayer/USS_Almayer.dmm
@@ -32952,8 +32952,7 @@
eftpos_name = "Cargo Bay EFTPOS scanner";
pixel_x = -10
},
-/obj/item/tool/stamp{
- name = "Requisition Officer's stamp";
+/obj/item/tool/stamp/ro{
pixel_x = -8;
pixel_y = 10
},
@@ -63207,7 +63206,7 @@
"rBx" = (
/obj/structure/surface/table/reinforced/almayer_B,
/obj/item/tool/stamp/ro{
- name = "spare requisitions officer's rubber stamp";
+ name = "spare quartermaster's rubber stamp";
pixel_x = -7;
pixel_y = 11
},
diff --git a/tgui/packages/tgui/interfaces/EscapePodConsole.tsx b/tgui/packages/tgui/interfaces/EscapePodConsole.tsx
index 893ece49f8bc..b4bc410a433d 100644
--- a/tgui/packages/tgui/interfaces/EscapePodConsole.tsx
+++ b/tgui/packages/tgui/interfaces/EscapePodConsole.tsx
@@ -19,16 +19,15 @@ export const EscapePodConsole = (_props, context) => {
switch (data.docking_status) {
case 4:
- statusMessage = 'SYSTEMS OK';
- buttonColor = 'good';
- operable = 1;
+ statusMessage = 'NO EVACUATION';
+ buttonColor = 'neutral';
break;
case 5:
statusMessage = 'SYSTEMS DOWN';
break;
case 6:
statusMessage = 'STANDING BY';
- buttonColor = 'neutral';
+ buttonColor = 'good';
operable = 1;
break;
case 7: