diff --git a/code/__defines/is_helpers.dm b/code/__defines/is_helpers.dm index 07c25a40ab..0fbcd3c719 100644 --- a/code/__defines/is_helpers.dm +++ b/code/__defines/is_helpers.dm @@ -13,7 +13,7 @@ #define isitem(D) istype(D, /obj/item) -#define isradio(A) istype(A, /obj/item/device/radio) +#define isradio(A) istype(A, /obj/item/device/radio) #define isairlock(A) istype(A, /obj/machinery/door/airlock) @@ -23,6 +23,8 @@ #define ismecha(A) istype(A, /obj/mecha) +#define isstructure(A) istype(A, /obj/structure) + //--------------- //#define isarea(D) istype(D, /area) //Built in diff --git a/code/datums/supplypacks/atmospherics.dm b/code/datums/supplypacks/atmospherics.dm index 3630b9bea0..a18b630892 100644 --- a/code/datums/supplypacks/atmospherics.dm +++ b/code/datums/supplypacks/atmospherics.dm @@ -106,3 +106,16 @@ cost = 35 containertype = /obj/structure/closet/crate/aether containername = "Emergency crate" + +/datum/supply_pack/atmos/firefighting + name = "Firefighting equipment" + contains = list( + /obj/item/clothing/suit/fire/heavy = 2, + /obj/item/weapon/tank/oxygen/red = 2, + /obj/item/weapon/watertank/atmos = 2, + /obj/item/device/flashlight = 2, + /obj/item/clothing/head/hardhat/firefighter/atmos = 2 + ) + cost = 35 + containertype = /obj/structure/closet/crate/aether + containername = "Firefighting crate" \ No newline at end of file diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm index c19c4b0097..18cc82af76 100644 --- a/code/datums/supplypacks/security.dm +++ b/code/datums/supplypacks/security.dm @@ -288,6 +288,16 @@ containername = "Riot armor crate" access = access_armory +/datum/supply_pack/security/riot_sprayer + name = "Gear - Riot sprayer" + contains = list( + /obj/item/weapon/watertank/pepperspray + ) + cost = 40 + containertype = /obj/structure/closet/crate/secure/lawson + containername = "Riot sprayer crate" + access = access_armory + /datum/supply_pack/security/ablative_armor name = "Armor - Ablative" contains = list( diff --git a/code/game/objects/random/_random.dm b/code/game/objects/random/_random.dm index df32a567d7..460ef4ef4f 100644 --- a/code/game/objects/random/_random.dm +++ b/code/game/objects/random/_random.dm @@ -59,7 +59,7 @@ var/list/random_useful_ if(prob(70)) // Misc. junk if(!random_junk_) random_junk_ = subtypesof(/obj/item/trash) - random_junk_ += /obj/effect/decal/cleanable/spiderling_remains + random_junk_ += /obj/effect/decal/cleanable/bug_remains random_junk_ += /obj/effect/decal/remains/mouse random_junk_ += /obj/effect/decal/remains/robot random_junk_ += /obj/item/weapon/paper/crumpled diff --git a/code/game/objects/random/mapping.dm b/code/game/objects/random/mapping.dm index 0a96e31f9f..76a4ccd067 100644 --- a/code/game/objects/random/mapping.dm +++ b/code/game/objects/random/mapping.dm @@ -24,7 +24,7 @@ /obj/effect/decal/cleanable/blood/gibs/robot, /obj/effect/decal/cleanable/blood/oil, /obj/effect/decal/cleanable/blood/oil/streak, - /obj/effect/decal/cleanable/spiderling_remains, + /obj/effect/decal/cleanable/bug_remains, /obj/effect/decal/remains/mouse, /obj/effect/decal/cleanable/vomit, /obj/effect/decal/cleanable/blood/splatter, diff --git a/code/game/objects/random/misc.dm b/code/game/objects/random/misc.dm index 63b5b8547e..c3c0544037 100644 --- a/code/game/objects/random/misc.dm +++ b/code/game/objects/random/misc.dm @@ -760,7 +760,7 @@ /obj/random/mouseremains/item_to_spawn() return pick(/obj/item/device/assembly/mousetrap, /obj/item/device/assembly/mousetrap/armed, - /obj/effect/decal/cleanable/spiderling_remains, + /obj/effect/decal/cleanable/bug_remains, /obj/effect/decal/cleanable/ash, /obj/item/trash/cigbutt, /obj/item/trash/cigbutt/cigarbutt, diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm index 61a8fe6afd..aaf93580ff 100644 --- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm @@ -97,7 +97,8 @@ starts_with = list( /obj/item/clothing/suit/fire/heavy, /obj/item/weapon/tank/oxygen/red, - /obj/item/weapon/extinguisher/atmo, + /obj/item/weapon/watertank/atmos, + /obj/item/device/flashlight, /obj/item/clothing/head/hardhat/firefighter/atmos) /* diff --git a/code/game/objects/structures/trash_pile_vr.dm b/code/game/objects/structures/trash_pile_vr.dm index ab9d13c97e..b84682dd29 100644 --- a/code/game/objects/structures/trash_pile_vr.dm +++ b/code/game/objects/structures/trash_pile_vr.dm @@ -283,10 +283,12 @@ /obj/structure/mob_spawner/mouse_nest name = "trash" - desc = "A small heap of trash, perfect for mice to nest in." + desc = "A small heap of trash, perfect for mice and other pests to nest in." icon = 'icons/obj/trash_piles.dmi' icon_state = "randompile" - spawn_types = list(/mob/living/simple_mob/animal/passive/mouse) + spawn_types = list( + /mob/living/simple_mob/animal/passive/mouse= 100, + /mob/living/simple_mob/animal/passive/cockroach = 25) simultaneous_spawns = 1 destructible = 1 spawn_delay = 1 HOUR diff --git a/code/modules/economy/vending_machines.dm b/code/modules/economy/vending_machines.dm index 4973281ccd..b05417013b 100644 --- a/code/modules/economy/vending_machines.dm +++ b/code/modules/economy/vending_machines.dm @@ -487,6 +487,7 @@ /obj/item/weapon/plantspray/pests = 20, /obj/item/weapon/reagent_containers/syringe = 5, /obj/item/weapon/reagent_containers/glass/beaker = 4, + /obj/item/weapon/watertank = 1, /obj/item/weapon/storage/bag/plants = 5) premium = list(/obj/item/weapon/reagent_containers/glass/bottle/ammonia = 10, /obj/item/weapon/reagent_containers/glass/bottle/diethylamine = 5) @@ -1521,7 +1522,8 @@ /obj/item/clothing/gloves/black = 5, /obj/item/weapon/storage/belt/janitor = 5, /obj/item/clothing/shoes/galoshes = 5, - /obj/item/weapon/cartridge/janitor = 5 + /obj/item/weapon/cartridge/janitor = 5, + /obj/item/weapon/watertank/janitor = 1 ) req_log_access = access_hop has_logs = 1 diff --git a/code/modules/gamemaster/event2/events/everyone/infestation.dm b/code/modules/gamemaster/event2/events/everyone/infestation.dm index 512679d2fc..fa07e60b4c 100644 --- a/code/modules/gamemaster/event2/events/everyone/infestation.dm +++ b/code/modules/gamemaster/event2/events/everyone/infestation.dm @@ -17,6 +17,10 @@ name = "infestation - spiders" event_type = /datum/event2/event/infestation/spiderlings +/datum/event2/event/infestation/cockroaches + vermin_string = "cockroaches" + max_vermin = 6 + things_to_spawn = list(/mob/living/simple_mob/animal/passive/cockroach) /datum/event2/event/infestation var/vermin_string = null diff --git a/code/modules/hydroponics/backtank.dm b/code/modules/hydroponics/backtank.dm new file mode 100644 index 0000000000..9ecb6b7bb5 --- /dev/null +++ b/code/modules/hydroponics/backtank.dm @@ -0,0 +1,295 @@ +/* + * Hydroponics tank and base code + */ +/obj/item/weapon/watertank + name = "backpack water tank" + desc = "A S.U.N.S.H.I.N.E. brand watertank backpack with nozzle to water plants." + icon = 'icons/inventory/back/item.dmi' + icon_state = "waterbackpack" + item_state = "waterbackpack" + w_class = ITEMSIZE_LARGE + slot_flags = SLOT_BACK + slowdown = 0.5 + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30) + + var/obj/item/noz + var/volume = 500 + +/obj/item/weapon/watertank/Initialize() + . = ..() + create_reagents(volume, OPENCONTAINER) + noz = make_noz() + +/obj/item/weapon/watertank/MouseDrop() + if(ismob(loc)) + if(!CanMouseDrop(src)) + return + var/mob/M = loc + if(!M.unEquip(src)) + return + add_fingerprint(usr) + M.put_in_any_hand_if_possible(src) + +/obj/item/weapon/watertank/Destroy() + QDEL_NULL(noz) + return ..() + +/obj/item/weapon/watertank/ui_action_click(mob/user) + toggle_mister(user) + +/obj/item/weapon/watertank/attack_hand(var/mob/user) + if(loc == user) + toggle_mister() + else + ..() + +/obj/item/weapon/watertank/item_action_slot_check(slot, mob/user) + if(slot == user.getBackSlot()) + return 1 + +//checks that the base unit is in the correct slot to be used +/obj/item/weapon/watertank/proc/slot_check() + var/mob/M = loc + if(!istype(M)) + return 0 //not equipped + + if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_back) == src) + return 1 + if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_s_store) == src) + return 1 + + return 0 + +/obj/item/weapon/watertank/verb/toggle_mister() + set name = "Toggle Mister" + set category = "Object" + + var/mob/living/carbon/human/user = usr + if(!noz) + to_chat(user, "The mister is missing!") + return + if(noz.loc != src) + remove_noz(user) //Remove from their hands and back onto the defib unit + return + if(!slot_check()) + to_chat(user, "You need to equip [src] before taking out [noz].") + else + if(!usr.put_in_hands(noz)) //Detach the handset into the user's hands + to_chat(user, "You need a free hand to hold the handset!") + update_icon() //success + +/obj/item/weapon/watertank/proc/make_noz() + return new /obj/item/weapon/reagent_containers/spray/mister(src) + +/obj/item/weapon/watertank/equipped(mob/user, slot) + ..() + if(slot != slot_back) + remove_noz() + +/obj/item/weapon/watertank/proc/remove_noz(var/mob/user) + if(!noz) return + + if(ismob(noz.loc)) + var/mob/M = noz.loc + if(M.drop_from_inventory(noz, src)) + to_chat(user, "\The [noz] snaps back into the main unit.") + else + noz.forceMove(src) + +/obj/item/weapon/watertank/attackby(obj/item/W, mob/user, params) + if(W == noz) + remove_noz() + return 1 + else + return ..() + +/obj/item/weapon/watertank/dropped(var/mob/user) + ..() + remove_noz(user) + +/* + * This mister item is intended as an extension of the watertank and always attached to it. + * Therefore, it's designed to be "locked" to the player's hands or extended back onto + * the watertank backpack. Allowing it to be placed elsewhere or created without a parent + * watertank object will likely lead to weird behaviour or runtimes. + */ + +/* + * Hydroponics mister + */ +/obj/item/weapon/reagent_containers/spray/mister + name = "water mister" + desc = "A mister nozzle attached to a water tank." + icon_state = "mister" + item_state = "mister" + w_class = ITEMSIZE_LARGE + amount_per_transfer_from_this = 50 + possible_transfer_amounts = list(50) + volume = 500 + item_flags = NOBLUDGEON + slot_flags = NONE + + var/obj/item/weapon/watertank/tank + +/obj/item/weapon/reagent_containers/spray/mister/Initialize() + . = ..() + tank = loc + if(!istype(tank)) + return INITIALIZE_HINT_QDEL + reagents = tank.reagents //This mister is really just a proxy for the tank's reagents + +/obj/item/weapon/reagent_containers/spray/mister/doMove(atom/destination) + if(destination && (destination != tank.loc || !ismob(destination))) + if (loc != tank) + to_chat(tank.loc, "The mister snaps back onto the watertank.") + destination = tank + ..() + +/obj/item/weapon/reagent_containers/spray/mister/afterattack(obj/target, mob/user, proximity) + if(target.loc == loc) //Safety check so you don't fill your mister with mutagen or something and then blast yourself in the face with it + return + ..() + +/* + * Janitor tank + */ +/obj/item/weapon/watertank/janitor + name = "backpack cleaner tank" + desc = "A janitorial cleaner backpack with nozzle to clean blood and graffiti." + icon_state = "waterbackpackjani" + item_state = "waterbackpackjani" + +/obj/item/weapon/watertank/janitor/Initialize() + . = ..() + reagents.add_reagent("cleaner", 500) + +/obj/item/weapon/watertank/janitor/make_noz() + return new /obj/item/weapon/reagent_containers/spray/mister/janitor(src) + +/* + * Janitor mister + */ +/obj/item/weapon/reagent_containers/spray/mister/janitor + name = "janitor spray nozzle" + desc = "A janitorial spray nozzle attached to a watertank, designed to clean up large messes." + icon_state = "misterjani" + item_state = "misterjani" + amount_per_transfer_from_this = 5 + possible_transfer_amounts = list(5,10) + spray_size = 4 + +/* + * Security tank + */ +/obj/item/weapon/watertank/pepperspray + name = "ANTI-TIDER-2500 suppression backpack" + desc = "The ultimate crowd-control device; this tool allows the user to quickly and efficiently pacify groups of hostile targets." + icon_state = "pepperbackpacksec" + item_state = "pepperbackpacksec" + volume = 1000 + +/obj/item/weapon/watertank/pepperspray/Initialize() + . = ..() + reagents.add_reagent("condensedcapsaicin", 1000) + +/obj/item/weapon/watertank/pepperspray/make_noz() + return new /obj/item/weapon/reagent_containers/spray/mister/pepperspray(src) + +/* + * Security mister + */ +/obj/item/weapon/reagent_containers/spray/mister/pepperspray + name = "security spray nozzle" + desc = "A pacifying spray nozzle attached to a pepperspray tank, designed to silence perps." + icon_state = "mistersec" + item_state = "mistersec" + amount_per_transfer_from_this = 5 + possible_transfer_amounts = list(5,10) + spray_size = 6 + +/* + * Operative tank + */ +/obj/item/weapon/watertank/op + name = "uborka tank" + desc = "A Russian backpack spray for systematic cleansing of carbon lifeforms." + icon_state = "waterbackpackop" + item_state = "waterbackpackop" + w_class = ITEMSIZE_NORMAL + volume = 2000 + slowdown = 0 + +/obj/item/weapon/watertank/op/Initialize() + . = ..() + reagents.add_reagent("fuel", 500) + reagents.add_reagent("cryptobiolin", 500) + reagents.add_reagent("phoron", 500) + reagents.add_reagent("condensedcapsaicin", 500) + +/obj/item/weapon/watertank/op/make_noz() + return new /obj/item/weapon/reagent_containers/spray/mister/op(src) + +/* + * Operative mister + */ +/obj/item/weapon/reagent_containers/spray/mister/op + name = "uborka spray nozzle" + desc = "A mister nozzle attached to several extended water tanks. It suspiciously has a compressor in the system and is labelled entirely in Cyrillic." + icon_state = "misterop" + item_state = "misterop" + w_class = ITEMSIZE_HUGE + volume = 2000 + amount_per_transfer_from_this = 100 + possible_transfer_amounts = list(75,100,150) + +/* + * Atmos tank + */ +/obj/item/weapon/watertank/atmos + name = "backpack firefighter tank" + desc = "A pressurized backpack tank with extinguisher nozzle, intended to fight fires." + icon_state = "waterbackpackatmos" + item_state = "waterbackpackatmos" + volume = 200 + +/obj/item/weapon/watertank/atmos/Initialize() + . = ..() + reagents.add_reagent("water", 200) + +/obj/item/weapon/watertank/atmos/make_noz() + return new /obj/item/weapon/reagent_containers/spray/mister/atmos(src) + +/* + * Atmos hose + */ +/obj/item/weapon/reagent_containers/spray/mister/atmos + name = "extinguisher nozzle" + desc = "A heavy duty nozzle attached to a firefighter's backpack tank." + icon_state = "atmos_nozzle" + item_state = "nozzleatmos" + w_class = ITEMSIZE_HUGE + volume = 200 + amount_per_transfer_from_this = 5 + possible_transfer_amounts = list(5,10) + spray_size = null + +/obj/item/weapon/reagent_containers/spray/mister/atmos/Spray_at(atom/A as mob|obj) + playsound(src, 'sound/effects/spray3.ogg', rand(50,1), -6) + var/direction = get_dir(src, A) + var/turf/T = get_turf(A) + var/turf/T1 = get_step(T,turn(direction, 90)) + var/turf/T2 = get_step(T,turn(direction, -90)) + var/list/the_targets = list(T, T1, T2) + + for(var/a = 1 to 3) + spawn(0) + if(reagents.total_volume < 1) break + var/obj/effect/effect/water/chempuff/D = new/obj/effect/effect/water/chempuff(get_turf(src)) + var/turf/my_target = the_targets[a] + D.create_reagents(amount_per_transfer_from_this) + if(!src) + return + reagents.trans_to_obj(D, amount_per_transfer_from_this) + D.set_color() + D.set_up(my_target, rand(6, 8), 2) + return \ No newline at end of file diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 445bd3895e..761ea37154 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -202,6 +202,23 @@ var/list/slot_equipment_priority = list( \ drop_from_inventory(I, target) return TRUE +//visibly unequips I but it is NOT MOVED AND REMAINS IN SRC +//item MUST BE FORCEMOVE'D OR QDEL'D +/mob/proc/temporarilyRemoveItemFromInventory(obj/item/I, force = FALSE, idrop = TRUE) + return u_equip(I, force, null, TRUE, idrop) + +///sometimes we only want to grant the item's action if it's equipped in a specific slot. +/obj/item/proc/item_action_slot_check(slot, mob/user) + if(slot == SLOT_BACK || slot == LEGS) //these aren't true slots, so avoid granting actions there + return FALSE + return TRUE + +///Get the item on the mob in the storage slot identified by the id passed in +/mob/proc/get_item_by_slot(slot_id) + return null + +/mob/proc/getBackSlot() + return SLOT_BACK //Attemps to remove an object on a mob. /mob/proc/remove_from_mob(var/obj/O, var/atom/target) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/cockroach.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/cockroach.dm new file mode 100644 index 0000000000..b170d192d0 --- /dev/null +++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/cockroach.dm @@ -0,0 +1,76 @@ +//Base cockroach +/mob/living/simple_mob/animal/passive/cockroach + name = "cockroach" + real_name = "cockroach" + desc = "This station is just crawling with bugs." + tt_desc = "E Blattella germanica" + icon_state = "cockroach" + item_state = "cockroach" + icon_living = "cockroach" + icon_dead = "cockroach_rest" //No real 'dead' sprite + icon_rest = "cockroach_rest" + + maxHealth = 1 + health = 1 + + movement_cooldown = 2.5 + + mob_size = MOB_MINISCULE + pass_flags = PASSTABLE + can_pull_mobs = MOB_PULL_NONE + layer = MOB_LAYER + density = FALSE + + response_help = "pokes" + response_disarm = "shoos" + response_harm = "splats" + + speak_emote = list("chitters") + + //Cockroaches are enviromentally superior + min_oxy = 0 + max_oxy = 0 + min_tox = 0 + max_tox = 0 + min_co2 = 0 + max_co2 = 0 + min_n2 = 0 + max_n2 = 0 + minbodytemp = 0 + maxbodytemp = 999999 + + var/squish_chance = 25 + +//Deletes the body upon death +/mob/living/simple_mob/animal/passive/cockroach/death() + new /obj/effect/decal/cleanable/bug_remains(src.loc) + qdel(src) + +//Squish code +/mob/living/simple_mob/animal/passive/cockroach/Crossed(var/atom/movable/AM) + if(ismob(AM)) + if(isliving(AM)) + var/mob/living/A = AM + if(A.mob_size > MOB_SMALL) + if(prob(squish_chance)) + A.visible_message("[A] squashed [src].", "You squashed [src].") + adjustBruteLoss(1) //kills a normal cockroach + else + visible_message("[src] avoids getting crushed.") + else + if(isstructure(AM)) + if(prob(squish_chance)) + AM.visible_message("[src] was crushed under [AM].") + adjustBruteLoss(1) + else + visible_message("[src] avoids getting crushed.") + +/mob/living/simple_mob/animal/passive/cockroach/ex_act() //Explosions are a terrible way to handle a cockroach. + return + +//Custom stain so it's not "spiderling remains" +/obj/effect/decal/cleanable/bug_remains + name = "bug remains" + desc = "Green squishy mess." + icon = 'icons/effects/effects.dmi' + icon_state = "greenshatter" \ No newline at end of file diff --git a/icons/inventory/back/item.dmi b/icons/inventory/back/item.dmi index 230b3950c8..73e6fae53f 100644 Binary files a/icons/inventory/back/item.dmi and b/icons/inventory/back/item.dmi differ diff --git a/icons/inventory/back/mob.dmi b/icons/inventory/back/mob.dmi index 3f11cc9dc1..e27f9d3048 100644 Binary files a/icons/inventory/back/mob.dmi and b/icons/inventory/back/mob.dmi differ diff --git a/icons/mob/items/lefthand_storage.dmi b/icons/mob/items/lefthand_storage.dmi index c8f275f173..aeaf11a4a3 100644 Binary files a/icons/mob/items/lefthand_storage.dmi and b/icons/mob/items/lefthand_storage.dmi differ diff --git a/icons/mob/items/righthand_storage.dmi b/icons/mob/items/righthand_storage.dmi index d8ce049aa5..0dbd0d7f55 100644 Binary files a/icons/mob/items/righthand_storage.dmi and b/icons/mob/items/righthand_storage.dmi differ diff --git a/vorestation.dme b/vorestation.dme index 024c2d13ba..15f9486259 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2369,6 +2369,7 @@ #include "code\modules\holomap\holomap_datum.dm" #include "code\modules\holomap\mapper.dm" #include "code\modules\holomap\station_holomap.dm" +#include "code\modules\hydroponics\backtank.dm" #include "code\modules\hydroponics\grown.dm" #include "code\modules\hydroponics\grown_inedible.dm" #include "code\modules\hydroponics\grown_predefined.dm" @@ -2996,6 +2997,7 @@ #include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\thermic.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\tunneler.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\webslinger.dm" +#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\cockroach.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\passive\crab.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\passive\fish.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\passive\fish_vr.dm"