diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index a8f303577c4..63319d1b5d3 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -50,6 +50,8 @@ #define ismachinery(A) (istype(A, /obj/machinery)) +#define isairlock(A) (istype(A, /obj/machinery/door)) + #define isapc(A) (istype(A, /obj/machinery/power/apc)) #define ismecha(A) (istype(A, /obj/mecha)) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 30891c98d31..0ac014a7c9c 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -126,6 +126,8 @@ #define STATUS_EFFECT_REVERSED_HIGH_PRIESTESS /datum/status_effect/reversed_high_priestess //Bubblegum will chase the person hit by the effect, grabbing people at random. This can and WILL include the caster. +#define STATUS_EFFECT_C_FOAMED /datum/status_effect/c_foamed + //#define STATUS_EFFECT_NECROPOLIS_CURSE /datum/status_effect/necropolis_curse //#define CURSE_BLINDING 1 //makes the edges of the target's screen obscured //#define CURSE_SPAWNING 2 //spawns creatures that attack the target only diff --git a/code/datums/station_state.dm b/code/datums/station_state.dm index 7359c4a21ae..2175d7bd69a 100644 --- a/code/datums/station_state.dm +++ b/code/datums/station_state.dm @@ -52,7 +52,7 @@ if(!GR.broken) grille += 1 - else if(istype(O, /obj/machinery/door)) + else if(isairlock(O)) door += 1 else if(istype(O, /obj/machinery)) diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index c8373ec00c0..f07c59d45a0 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -1353,6 +1353,52 @@ new /obj/effect/abstract/bubblegum_rend_helper(get_turf(src), null, 10) qdel(src) +/datum/status_effect/c_foamed + id = "c_foamed up" + duration = 1 MINUTES + status_type = STATUS_EFFECT_REFRESH + tick_interval = 10 SECONDS + var/foam_level = 1 + var/mutable_appearance/foam_overlay + +/datum/status_effect/c_foamed/on_apply() + . = ..() + foam_overlay = mutable_appearance('icons/obj/foam_blobs.dmi', "foamed_1") + owner.add_overlay(foam_overlay) + owner.next_move_modifier *= 1.5 + owner.Slowed(10 SECONDS, 1.5) + +/datum/status_effect/c_foamed/Destroy() + if(owner) + owner.cut_overlay(foam_overlay) + owner.next_move_modifier /= 1.5 + + QDEL_NULL(foam_overlay) + return ..() + +/datum/status_effect/c_foamed/tick() + . = ..() + if(--foam_level <= 0) + qdel(src) + refresh_overlay() + +/datum/status_effect/c_foamed/refresh() + . = ..() + // Our max slow is 50 seconds + foam_level = min(foam_level + 1, 5) + + refresh_overlay() + + if(foam_level == 5) + owner.Paralyse(4 SECONDS) + +/datum/status_effect/c_foamed/proc/refresh_overlay() + // Refresh overlay + owner.cut_overlay(foam_overlay) + QDEL_NULL(foam_overlay) + foam_overlay = mutable_appearance('icons/obj/foam_blobs.dmi', "foamed_[foam_level]") + owner.add_overlay(foam_overlay) + /datum/status_effect/judo_armbar id = "armbar" duration = 5 SECONDS diff --git a/code/datums/uplink_items/uplink_general.dm b/code/datums/uplink_items/uplink_general.dm index 5d83a5aec80..074048268ca 100644 --- a/code/datums/uplink_items/uplink_general.dm +++ b/code/datums/uplink_items/uplink_general.dm @@ -668,6 +668,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/organ_extractor cost = 20 +/datum/uplink_item/device_tools/c_foam_launcher + name = "C-Foam Launcher" + desc = "A gun that shoots blobs of foam. Will block airlocks, and slow down humanoids. Not rated for xenomorph usage." + reference = "CFOAM" + item = /obj/item/gun/projectile/c_foam_launcher + cost = 25 + /datum/uplink_item/device_tools/tar_spray name = "Sticky Tar Applicator" desc = "A spray bottle containing an extremely viscous fluid that will leave behind tar whenever it is sprayed, greatly slowing down anyone who tries to walk over it. \ diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 8226b164759..72cf7fbdbe9 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -422,7 +422,6 @@ item_state = "grenade" materials = list(MAT_METAL = 500, MAT_GLASS = 300) //plasma burned up for power or something, plus not that much to reclaim - /obj/item/storage/box/syndie_kit/dropwall name = "dropwall generator box" @@ -474,6 +473,33 @@ turret.owner_uid = owner_uid qdel(src) +/obj/structure/barricade/foam + name = "foam blockage" + desc = "This foam blocks the airlock from being opened." + icon = 'icons/obj/foam_blobs.dmi' + icon_state = "foamed_1" + layer = DOOR_HELPER_LAYER + // The integrity goes up with 25 per level, with an extra 25 when going from 4 to 5 + obj_integrity = 25 + max_integrity = 25 + /// What level is the foam at? + var/foam_level = 1 + +/obj/structure/barricade/foam/Destroy() + for(var/obj/machinery/door/airlock in loc.contents) + airlock.foam_level = 0 + return ..() + +/obj/structure/barricade/foam/examine(mob/user) + . = ..() + . += "It would need [(5 - foam_level)] more blobs of foam to fully block the airlock." + +/obj/structure/barricade/foam/CanPass(atom/movable/mover, turf/target) + return istype(mover, /obj/item/projectile/c_foam) // Only c_foam blobs hit the airlock underneat/pass through the foam. The rest is hitting the barricade + +/obj/structure/barricade/foam/welder_act(mob/user, obj/item/I) + return FALSE + #undef SINGLE #undef VERTICAL #undef HORIZONTAL diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index a07d1427dfd..1abf4875068 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -48,9 +48,13 @@ var/polarized_glass = FALSE var/polarized_on + /// How many levels of foam do we have on us? Capped at 5 + var/foam_level = 0 + /// How much this door reduces superconductivity to when closed. var/superconductivity = DOOR_HEAT_TRANSFER_COEFFICIENT + /obj/machinery/door/Initialize(mapload) . = ..() set_init_door_layer() @@ -93,7 +97,7 @@ return ..() /obj/machinery/door/Bumped(atom/AM) - if(operating || emagged) + if(operating || emagged || foam_level) return if(ismob(AM)) var/mob/B = AM @@ -150,6 +154,9 @@ return add_fingerprint(user) + if(foam_level) + return + if(density && !emagged) if(allowed(user)) if(HAS_TRAIT(src, TRAIT_CMAGGED)) @@ -172,8 +179,12 @@ if(isterrorspider(user)) return + if(foam_level) + return + if(!HAS_TRAIT(user, TRAIT_FORCE_DOORS)) return FALSE + var/datum/antagonist/vampire/V = user.mind?.has_antag_datum(/datum/antagonist/vampire) if(V && HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT)) if(!V.bloodusable) @@ -209,7 +220,7 @@ /obj/machinery/door/proc/try_to_activate_door(mob/user) add_fingerprint(user) - if(operating || emagged) + if(operating || emagged || foam_level) return if(requiresID() && (allowed(user) || user.can_advanced_admin_interact())) if(density) @@ -574,3 +585,29 @@ for(var/obj/airlock_filler_object/filler as anything in fillers) filler.set_opacity(opacity) + +#define MAX_FOAM_LEVEL 5 +// Adds foam to the airlock, which will block it from being opened +/obj/machinery/door/proc/foam_up() + if(!foam_level) + new /obj/structure/barricade/foam(get_turf(src)) + foam_level++ + return + + if(foam_level == MAX_FOAM_LEVEL) + return + + for(var/obj/structure/barricade/foam/blockage in loc.contents) + blockage.foam_level = min(++blockage.foam_level, 5) + // The last level will increase the integrity by 50 instead of 25 + if(foam_level == 4) + blockage.obj_integrity += 50 + blockage.max_integrity += 50 + else + blockage.obj_integrity += 25 + blockage.max_integrity += 25 + foam_level++ + blockage.icon_state = "foamed_[foam_level]" + blockage.update_icon_state() + +#undef MAX_FOAM_LEVEL diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm index cb5cf0a9046..64a264cf40a 100644 --- a/code/game/mecha/equipment/tools/medical_tools.dm +++ b/code/game/mecha/equipment/tools/medical_tools.dm @@ -527,7 +527,7 @@ if(!action_checks(target)) return if(isobj(target)) - if(!istype(target, /obj/machinery/door))//early return if we're not trying to open a door + if(!isairlock(target))//early return if we're not trying to open a door return var/obj/machinery/door/D = target //the door we want to open D.try_to_crowbar(chassis.occupant, src)//use the door's crowbar function diff --git a/code/game/objects/items/weapons/c_foam_launcher.dm b/code/game/objects/items/weapons/c_foam_launcher.dm new file mode 100644 index 00000000000..6d24188c78d --- /dev/null +++ b/code/game/objects/items/weapons/c_foam_launcher.dm @@ -0,0 +1,45 @@ +/* + * The C-Foam launcher from GTFO + * Shoots a blob of goo. If it hits an airlock, it will get closed shut, and you will have to either destroy the goo by force, or weld it off. The RnD foam is instant, and the traitor version has a `do_after` + * RnD printed needs canisters, while the traitor variant will slowly regenerate foam. + * The traitor variant also slows down mobs if they are hit by the foam. + * Overall, a good support tool designed to + */ + +/obj/item/gun/projectile/c_foam_launcher + name = "\improper C-Foam launcher" + desc = "The C-Foam launcher. Shoots blobs of quickly hardening and growing foam. Can be used to slow down humanoids or block airlocks" + icon_state = "c_foam_launcher" + item_state = "c_foam_launcher" + w_class = WEIGHT_CLASS_NORMAL + origin_tech = "combat=4;syndicate=1;materials=3" + needs_permit = FALSE + + fire_sound = 'sound/effects/bamf.ogg' + fire_sound_text = "thunk" + mag_type = /obj/item/ammo_box/magazine/c_foam + +/obj/item/gun/projectile/c_foam_launcher/update_icon_state() + icon_state = "c_foam_launcher[magazine ? "_loaded" : ""]" + +/obj/item/projectile/c_foam + name = "blob of foam" + icon_state = "foam_blob" + damage = 0 + +/obj/item/projectile/c_foam/on_hit(atom/target, blocked, hit_zone) + . = ..() + if(isairlock(target)) + var/obj/machinery/door/airlock = target + airlock.foam_up() + return + + if(istype(target, /obj/structure/mineral_door)) + var/obj/structure/mineral_door/door = target + door.foam_up() + return + + if(iscarbon(target)) // For that funny xeno foam action + var/mob/living/carbon/sticky = target + sticky.foam_up() + return diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 550be956d60..5c7dfda7990 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -54,7 +54,7 @@ origin_tech = "magnets=2" /obj/item/card/emag/magic_key/afterattack(atom/target, mob/user, proximity) - if(!istype(target, /obj/machinery/door)) + if(!isairlock(target)) return var/obj/machinery/door/D = target D.locked = FALSE diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm index a41b3295448..6776d7fdede 100644 --- a/code/game/objects/items/weapons/explosives.dm +++ b/code/game/objects/items/weapons/explosives.dm @@ -90,7 +90,7 @@ log_game("[key_name(user)] planted [name] on [target.name] at ([target.x],[target.y],[target.z]) with [det_time] second fuse") plastic_overlay.layer = HIGH_OBJ_LAYER - if(isturf(target) || istype(target, /obj/machinery/door)) + if(isturf(target) || isairlock(target)) plastic_overlay_target = new /obj/effect/plastic(get_turf(user)) else plastic_overlay_target = target diff --git a/code/game/objects/items/weapons/paiwire.dm b/code/game/objects/items/weapons/paiwire.dm index 2e0ddfa828d..5206005e089 100644 --- a/code/game/objects/items/weapons/paiwire.dm +++ b/code/game/objects/items/weapons/paiwire.dm @@ -1,5 +1,5 @@ /obj/item/pai_cable/proc/plugin(obj/machinery/M as obj, mob/user as mob) - if(istype(M, /obj/machinery/door) || istype(M, /obj/machinery/camera)) + if(isairlock(M) || istype(M, /obj/machinery/camera)) user.visible_message("[user] inserts [src] into a data port on [M].", "You insert [src] into a data port on [M].", "You hear the satisfying click of a wire jack fastening into place.") user.drop_item() src.loc = M diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index cb5dc18f242..9d598c5e905 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -446,7 +446,7 @@ if(T.density) return for(var/atom/A in T.contents) - if(A.density && istype(A, /obj/machinery/door)) + if(A.density && isairlock(A)) return UpdateTransparency(src, NewLoc) forceMove(NewLoc) diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index f17c3f0dba5..d28a65a973e 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -22,6 +22,8 @@ var/open_sound = 'sound/effects/stonedoor_openclose.ogg' var/close_sound = 'sound/effects/stonedoor_openclose.ogg' var/damageSound = null + /// How much foam is on the door. Max 5 levels. + var/foam_level = 0 /obj/structure/mineral_door/Initialize() . = ..() @@ -68,6 +70,8 @@ /obj/structure/mineral_door/proc/try_to_operate(atom/user) if(is_operating) return + if(foam_level) + return if(isliving(user)) var/mob/living/M = user if(M.client) @@ -216,3 +220,29 @@ /obj/structure/mineral_door/wood/Initialize() . = ..() AddComponent(/datum/component/debris, DEBRIS_WOOD, -20, 10) + +#define MAX_FOAM_LEVEL 5 +// Adds foam to the airlock, which will block it from being opened +/obj/structure/mineral_door/proc/foam_up() + if(!foam_level) + new /obj/structure/barricade/foam(get_turf(src)) + foam_level++ + return + + if(foam_level == MAX_FOAM_LEVEL) + return + + for(var/obj/structure/barricade/foam/blockage in loc.contents) + blockage.foam_level = min(++blockage.foam_level, 5) + // The last level will increase the integrity by 50 instead of 25 + if(foam_level == 4) + blockage.obj_integrity += 50 + blockage.max_integrity += 50 + else + blockage.obj_integrity += 25 + blockage.max_integrity += 25 + foam_level++ + blockage.icon_state = "foamed_[foam_level]" + blockage.update_icon_state() + +#undef MAX_FOAM_LEVEL diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index 360d5ee184f..f84af512c5e 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -76,7 +76,7 @@ if(!has_buckled_mobs()) return var/mob/living/buckled_mob = buckled_mobs[1] - if(istype(A, /obj/machinery/door)) + if(isairlock(A)) A.Bumped(buckled_mob) if(propelled) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 1c1810d2cda..681856dc683 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -76,3 +76,7 @@ if(!affecting) //bruh where's your chest return FALSE apply_damage(damage, BRUTE, affecting) + +// Adds the foam status effect to the carbon, which will slow it's movement speed and attack speed +/mob/living/carbon/proc/foam_up(amount) + apply_status_effect(STATUS_EFFECT_C_FOAMED) diff --git a/code/modules/projectiles/ammunition/ammo_casings.dm b/code/modules/projectiles/ammunition/ammo_casings.dm index 1f3d72d994d..20d383224e1 100644 --- a/code/modules/projectiles/ammunition/ammo_casings.dm +++ b/code/modules/projectiles/ammunition/ammo_casings.dm @@ -508,3 +508,12 @@ muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL muzzle_flash_color = LIGHT_COLOR_DARKRED icon_state = "lasercasing" + +/obj/item/ammo_casing/caseless/c_foam + name = "\improper C-Foam blob" + desc = "You shouldn't see this! Make an issue report on Github!" + caliber = "c_foam" + projectile_type = /obj/item/projectile/c_foam + muzzle_flash_strength = MUZZLE_FLASH_RANGE_WEAK + muzzle_flash_range = MUZZLE_FLASH_RANGE_WEAK + muzzle_flash_color = LIGHT_COLOR_DARKRED diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm index f1e7fe2fd48..b764ae1ce09 100644 --- a/code/modules/projectiles/ammunition/magazines.dm +++ b/code/modules/projectiles/ammunition/magazines.dm @@ -624,3 +624,13 @@ /obj/item/ammo_box/magazine/detective/speedcharger/attackby() return + +/obj/item/ammo_box/magazine/c_foam + name = "\improper C-Foam canister" + desc = "A canister containing inert foam for the C-Foam launcher." + icon_state = "foam_canister" + ammo_type = /obj/item/ammo_casing/caseless/c_foam + max_ammo = 12 + +/obj/item/ammo_box/magazine/c_foam/attack_self(mob/user) + return diff --git a/code/modules/projectiles/projectile/magic_projectiles.dm b/code/modules/projectiles/projectile/magic_projectiles.dm index 8ccc59ffc30..99c40d5929c 100644 --- a/code/modules/projectiles/projectile/magic_projectiles.dm +++ b/code/modules/projectiles/projectile/magic_projectiles.dm @@ -149,7 +149,7 @@ else if(isturf(T) && T.density) if(!(istype(T, /turf/simulated/wall/indestructible))) CreateDoor(T) - else if(istype(target, /obj/machinery/door)) + else if(isairlock(target)) OpenDoor(target) else if(istype(target, /obj/structure/closet)) OpenCloset(target) diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index f0bdda2848e..2ec5338c334 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -729,7 +729,6 @@ build_path = /obj/item/flamethrower/full category = list("hacked", "Security") - /datum/design/electropack name = "Electropack" id = "electropack" @@ -842,6 +841,14 @@ build_path = /obj/item/ammo_box/c9mm category = list("hacked", "Security") +/datum/design/c_foam_ammo + name = "C-Foam cartridge" + id = "c_foam" + build_type = AUTOLATHE + materials = list(MAT_METAL = 5000, MAT_GLASS = 2000) + build_path = /obj/item/ammo_box/magazine/c_foam + category = list("hacked", "Security") + /datum/design/cleaver name = "Butcher's Cleaver" id = "cleaver" diff --git a/code/modules/vehicle/vehicle.dm b/code/modules/vehicle/vehicle.dm index 96d276aa504..b62ee6a76cf 100644 --- a/code/modules/vehicle/vehicle.dm +++ b/code/modules/vehicle/vehicle.dm @@ -209,7 +209,7 @@ return FALSE . = ..() if(auto_door_open) - if(istype(M, /obj/machinery/door) && has_buckled_mobs()) + if(isairlock(M) && has_buckled_mobs()) for(var/m in buckled_mobs) M.Bumped(m) diff --git a/icons/mob/inhands/guns_lefthand.dmi b/icons/mob/inhands/guns_lefthand.dmi index 6ba217d1d51..b69abf84133 100644 Binary files a/icons/mob/inhands/guns_lefthand.dmi and b/icons/mob/inhands/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/guns_righthand.dmi b/icons/mob/inhands/guns_righthand.dmi index 1aee6bb9652..5a63844e0fa 100644 Binary files a/icons/mob/inhands/guns_righthand.dmi and b/icons/mob/inhands/guns_righthand.dmi differ diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi index c1175b0c242..301305fcac1 100644 Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ diff --git a/icons/obj/foam_blobs.dmi b/icons/obj/foam_blobs.dmi new file mode 100644 index 00000000000..679ce893f52 Binary files /dev/null and b/icons/obj/foam_blobs.dmi differ diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi index de9e8b65028..d510c4fa9af 100644 Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 8164d961ab5..f56034e9cca 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/paradise.dme b/paradise.dme index 5515832316a..cdaabb5dbba 100644 --- a/paradise.dme +++ b/paradise.dme @@ -100,8 +100,8 @@ #include "code\__DEFINES\pipes.dm" #include "code\__DEFINES\power_defines.dm" #include "code\__DEFINES\preferences_defines.dm" -#include "code\__DEFINES\procpath.dm" #include "code\__DEFINES\proc_refs.dm" +#include "code\__DEFINES\procpath.dm" #include "code\__DEFINES\qdel_defines.dm" #include "code\__DEFINES\radiation_defines.dm" #include "code\__DEFINES\radio_defines.dm" @@ -1125,6 +1125,7 @@ #include "code\game\objects\items\weapons\alien_specific.dm" #include "code\game\objects\items\weapons\batons.dm" #include "code\game\objects\items\weapons\bee_briefcase.dm" +#include "code\game\objects\items\weapons\c_foam_launcher.dm" #include "code\game\objects\items\weapons\cards_ids.dm" #include "code\game\objects\items\weapons\cash.dm" #include "code\game\objects\items\weapons\caution.dm"