diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 7d0a4ab1504..9da2c725a43 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -18,6 +18,7 @@ #define CLOSED_TURF_LAYER 2.05 #define BULLET_HOLE_LAYER 2.06 #define ABOVE_NORMAL_TURF_LAYER 2.08 +#define ABOVE_ICYOVERLAY_LAYER 2.11 #define LATTICE_LAYER 2.2 #define DISPOSAL_PIPE_LAYER 2.3 #define GAS_PIPE_HIDDEN_LAYER 2.35 diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index a485e447f89..614cd5bfa7c 100644 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -1720,6 +1720,14 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine ) containername = "hygiene station crate" +/datum/supply_packs/misc/snow_machine + name = "Snow Machine Crate" + cost = 20 + contains = list( + /obj/machinery/snow_machine + ) + special = TRUE + ////////////////////////////////////////////////////////////////////////////// //////////////////////////// Vending ///////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index fe9b20e0e69..1935869fb53 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -330,6 +330,16 @@ to destroy them and players will be able to make replacements. name = "circuit board (Freezer)" to_chat(user, "You set the board to cooling.") +/obj/item/circuitboard/snow_machine + name = "circuit board (snow machine)" + build_path = /obj/machinery/snow_machine + board_type = "machine" + origin_tech = "programming=2;materials=2" + frame_desc = "Requires 1 Matter Bin and 1 Micro Laser." + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/micro_laser = 1) + /obj/item/circuitboard/biogenerator name = "circuit board (Biogenerator)" build_path = /obj/machinery/biogenerator diff --git a/code/game/machinery/snow_machine.dm b/code/game/machinery/snow_machine.dm new file mode 100644 index 00000000000..2ae3bf22977 --- /dev/null +++ b/code/game/machinery/snow_machine.dm @@ -0,0 +1,133 @@ +/obj/machinery/snow_machine + name = "snow machine" + desc = "Just add water and you too can have your own winter wonderland! Carol singers not included." + icon_state = "snow_machine_off" + density = TRUE + anchored = FALSE + layer = OBJ_LAYER + var/active = FALSE + var/power_used_this_cycle = 0 + var/cooling_speed = 1 + var/power_efficiency = 1 + var/lower_temperature_limit = T0C - 10 //Set lower for a bigger freeze + var/infinite_snow = FALSE //Set this to have it not use water + +/obj/machinery/snow_machine/New() + ..() + create_reagents(300) //Makes 100 snow tiles! + reagents.add_reagent("water", 300) //But any reagent will do + reagents.flags |= REAGENT_NOREACT //Because a) this doesn't need to process and b) this way we can use any reagents without needing to worry about explosions and shit + container_type = REFILLABLE + component_parts = list() + component_parts += new /obj/item/circuitboard/snow_machine(null) + component_parts += new /obj/item/stock_parts/matter_bin(null) + component_parts += new /obj/item/stock_parts/micro_laser(null) + RefreshParts() + +/obj/machinery/snow_machine/examine(mob/user) + ..() + to_chat(user, "The internal reservoir indicates it is [infinite_snow ? "100" : round(reagents.total_volume / reagents.maximum_volume * 100)]% full.") + +/obj/machinery/snow_machine/RefreshParts() + power_efficiency = 0 + cooling_speed = 0 + for(var/obj/item/stock_parts/matter_bin/B in component_parts) + cooling_speed += B.rating + for(var/obj/item/stock_parts/micro_laser/L in component_parts) + power_efficiency += L.rating + +/obj/machinery/snow_machine/attack_hand(mob/user) + if(!powered() || !anchored) + return + if(turn_on_or_off(!active)) + to_chat(user, "You [active ? "turn on" : "turn off"] [src].") + return ..() + +/obj/machinery/snow_machine/attackby(obj/item/I, mob/user) + if(isscrewdriver(I)) + if(default_deconstruction_screwdriver(user, "snow_machine_openpanel", "snow_machine_off", I)) + turn_on_or_off(FALSE) + else if(iscrowbar(I)) + default_deconstruction_crowbar(I) + else if(iswrench(I)) + var/obj/item/wrench/W = I + anchored = !anchored + to_chat(user, "You [anchored ? "tighten" : "loosen"] [src]'s wheels.") + playsound(loc, W.usesound, 50, TRUE) + turn_on_or_off(FALSE) + else + return ..() + +/obj/machinery/snow_machine/process() + if(power_used_this_cycle) + power_used_this_cycle /= power_efficiency + use_power(power_used_this_cycle) + power_used_this_cycle = 0 + if(!active || !anchored) + return + if(!powered()) + return + if(!reagents.has_reagent(reagents.get_master_reagent_id(), 3)) + return //This means you don't need to top it up constantly to keep the nice snowclouds going + var/turf/T = get_turf(src) + if(isspaceturf(T) || T.density) //If the snowmachine is on a dense tile or in space, then it shouldn't be able to produce any snow and so will turn off + turn_on_or_off(FALSE, TRUE) + return + for(var/turf/TF in range(1, src)) + if(issimulatedturf(TF)) + var/turf/simulated/S = TF + affect_turf_temperature(S, cooling_speed) + if(prob(50)) + continue + make_snowcloud(TF) + +/obj/machinery/snow_machine/power_change() + ..() + if(!powered()) + turn_on_or_off(FALSE, TRUE) + update_icon() + +/obj/machinery/snow_machine/update_icon() + ..() + if(panel_open) + icon_state = "snow_machine_openpanel" + else + icon_state = "snow_machine_[active ? "on" : "off"]" + +/obj/machinery/snow_machine/proc/affect_turf_temperature(turf/T, modifier) + if(!issimulatedturf(T) || T.density) + return + var/turf/simulated/S = T + var/initial_temperature = S.air.temperature + if(initial_temperature <= lower_temperature_limit) //Can we actually cool this? + return + var/old_thermal_energy = S.air.thermal_energy() + var/amount_cooled = initial_temperature - modifier * 8000 / S.air.heat_capacity() + S.air.temperature = max(amount_cooled, lower_temperature_limit) + air_update_turf() + var/new_thermal_energy = S.air.thermal_energy() + power_used_this_cycle += (old_thermal_energy - new_thermal_energy) / 100 + +/obj/machinery/snow_machine/proc/make_snowcloud(turf/T) + if(isspaceturf(T)) + return + if(T.density) + return + if(issimulatedturf(T)) + var/turf/simulated/S = T + if(S.air.temperature > T0C + 1) + return + if(locate(/obj/effect/snowcloud, T)) //Ice to see you + return + if(infinite_snow || !reagents.remove_reagent(reagents.get_master_reagent_id(), 3)) + new /obj/effect/snowcloud(T, src) + power_used_this_cycle += 1000 + return TRUE + +/obj/machinery/snow_machine/proc/turn_on_or_off(activate, give_message = FALSE) + active = activate ? TRUE : FALSE + if(!active && give_message) + visible_message("[src] switches off!") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, FALSE) + update_icon() + return TRUE diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm index e2f1399a922..52ad55c48a4 100644 --- a/code/game/objects/effects/decals/misc.dm +++ b/code/game/objects/effects/decals/misc.dm @@ -16,6 +16,7 @@ anchored = TRUE layer = TURF_DECAL_LAYER icon = 'icons/turf/snow.dmi' + icon_state = "snow" /obj/effect/decal/snow/clean/edge icon_state = "snow_corner" diff --git a/code/game/objects/effects/snowcloud.dm b/code/game/objects/effects/snowcloud.dm new file mode 100644 index 00000000000..a67bbd3c5f7 --- /dev/null +++ b/code/game/objects/effects/snowcloud.dm @@ -0,0 +1,140 @@ +/obj/effect/snowcloud + name = "snow cloud" + desc = "Let it snow, let it snow, let it snow!" + icon_state = "snowcloud" + layer = FLY_LAYER + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + var/obj/machinery/snow_machine/parent_machine + +/obj/effect/snowcloud/New(turf, obj/machinery/snow_machine/SM) + ..() + processing_objects.Add(src) + if(SM && istype(SM)) + parent_machine = SM + +/obj/effect/snowcloud/Destroy() + processing_objects.Remove(src) + return ..() + +/obj/effect/snowcloud/process() + if(QDELETED(parent_machine)) + parent_machine = null + var/turf/T = get_turf(src) + if(isspaceturf(T)) + qdel(src) + return + var/turf_hotness + if(issimulatedturf(T)) + var/turf/simulated/S = T + turf_hotness = S.air.temperature + if(turf_hotness > T0C && prob(10 * (turf_hotness - T0C))) //Cloud disappears if it's too warm + qdel(src) + return + if(!parent_machine || !parent_machine.active || parent_machine.stat & NOPOWER) //All reasons a cloud could dissipate + if(prob(10)) + qdel(src) + return + try_to_snow() + try_to_spread_cloud() + parent_machine.affect_turf_temperature(T, 0.25 * parent_machine.cooling_speed) + +/obj/effect/snowcloud/proc/try_to_snow() + var/turf/T = get_turf(src) + if(locate(/obj/effect/snow, T)) + return + if(issimulatedturf(T)) + var/turf/simulated/S = T + if(prob(75 + S.air.temperature - T0C)) //Colder turf = more chance of snow + return + new /obj/effect/snow(T) + +/obj/effect/snowcloud/proc/try_to_spread_cloud() + if(prob(95 - parent_machine.cooling_speed * 5)) //10 / 15 / 20 / 25% chance to spawn a new cloud + return + var/list/random_dirs = shuffle(cardinal) + for(var/potential in random_dirs) + var/turf/T = get_turf(get_step(src, potential)) + if(isspaceturf(T) || T.density) + continue + if(!T.CanAtmosPass(T)) + continue + if(parent_machine.make_snowcloud(T)) + return + + +//Snow stuff below + +/obj/effect/snow + desc = "Perfect for making snow angels, or throwing at other people!" + icon = 'icons/effects/effects.dmi' + icon_state = "snow" + layer = ABOVE_ICYOVERLAY_LAYER + anchored = TRUE + +/obj/effect/snow/New() + processing_objects.Add(src) + icon_state = "snow[rand(1,6)]" + ..() + +/obj/effect/snow/Destroy() + processing_objects.Remove(src) + return ..() + +/obj/effect/snow/process() + var/turf/T = get_turf(src) + if(isspaceturf(T)) + qdel(src) + return + else if(issimulatedturf(T)) + var/turf/simulated/S = T + if(S.air.temperature <= T0C) + return + if(prob(10 + S.air.temperature - T0C)) + qdel(src) + +/obj/effect/snow/attack_hand(mob/living/carbon/human/user) + if(!istype(user)) //Nonhumans don't have the balls to fight in the snow + return + user.changeNext_move(CLICK_CD_MELEE) + var/obj/item/snowball/SB = new(get_turf(user)) + user.put_in_hands(SB) + to_chat(user, "You scoop up some snow and make \a [SB]!") + +/obj/effect/snow/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/shovel)) + var/obj/item/shovel/S = I + user.visible_message("[user] is clearing away [src]...", "You begin clearing away [src]...", "You hear a wettish digging sound.") + playsound(loc, S.usesound, 50, TRUE) + if(!do_after(user, 50 * S.toolspeed, target = src)) + return + user.visible_message("[user] clears away [src]!", "You clear away [src]!") + qdel(src) + else + return ..() + +/obj/effect/snow/fire_act() + qdel(src) + +/obj/effect/snow/ex_act(severity) + if(severity == 3 && prob(50)) + return + qdel(src) + +/obj/item/snowball + name = "snowball" + desc = "Get ready for a snowball fight!" + force = 0 + throwforce = 10 + icon_state = "snowball" + damtype = STAMINA + +/obj/item/snowball/throw_impact(atom/target) + ..() + qdel(src) + +/obj/item/snowball/fire_act() + qdel(src) + +/obj/item/snowball/ex_act(severity) + qdel(src) diff --git a/code/modules/holiday/christmas.dm b/code/modules/holiday/christmas.dm index 7b00171b348..5a9a8605442 100644 --- a/code/modules/holiday/christmas.dm +++ b/code/modules/holiday/christmas.dm @@ -6,6 +6,8 @@ new /obj/item/a_gift(T) for(var/mob/living/simple_animal/pet/corgi/Ian/Ian in GLOB.mob_list) Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian)) + var/datum/supply_packs/xmas = SSshuttle.supply_packs["[/datum/supply_packs/misc/snow_machine]"] //Snow! + xmas.special_enabled = TRUE /datum/holiday/xmas/handle_event() spawnTree() diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 060d8b77a27..95099bb00f3 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi index 9284e790cf8..07680638b6b 100644 Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ diff --git a/icons/obj/stationobjs.dmi b/icons/obj/stationobjs.dmi index 0b7ae5b5600..c8a9abd40f3 100755 Binary files a/icons/obj/stationobjs.dmi and b/icons/obj/stationobjs.dmi differ diff --git a/paradise.dme b/paradise.dme index 711a157e457..fcc4aa9c054 100644 --- a/paradise.dme +++ b/paradise.dme @@ -611,6 +611,7 @@ #include "code\game\machinery\shieldgen.dm" #include "code\game\machinery\Sleeper.dm" #include "code\game\machinery\slotmachine.dm" +#include "code\game\machinery\snow_machine.dm" #include "code\game\machinery\spaceheater.dm" #include "code\game\machinery\status_display.dm" #include "code\game\machinery\suit_storage_unit.dm" @@ -746,6 +747,7 @@ #include "code\game\objects\effects\misc.dm" #include "code\game\objects\effects\overlays.dm" #include "code\game\objects\effects\portals.dm" +#include "code\game\objects\effects\snowcloud.dm" #include "code\game\objects\effects\spiders.dm" #include "code\game\objects\effects\step_triggers.dm" #include "code\game\objects\effects\decals\cleanable.dm"