diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index d3d0a19a9a0..590000aabfb 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -5166,6 +5166,10 @@
},
/turf/open/floor/plasteel/dark,
/area/security/brig)
+"akV" = (
+/obj/effect/mapping_helpers/iannewyear,
+/turf/open/floor/carpet,
+/area/crew_quarters/heads/hop)
"akW" = (
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
/obj/machinery/door/airlock/security/glass{
@@ -26528,9 +26532,6 @@
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
/area/hallway/primary/central)
-"bqz" = (
-/turf/open/floor/carpet,
-/area/crew_quarters/heads/hop)
"bqA" = (
/obj/machinery/computer/card{
dir = 1
@@ -79035,7 +79036,7 @@ bkX
bmo
bnO
bpb
-bqz
+akV
bqq
brS
bsY
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index d88692fedcb..b1a339215a2 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -59,6 +59,11 @@
/obj/item/clothing/head/chefhat,
/turf/open/floor/plasteel,
/area/crew_quarters/kitchen)
+"aai" = (
+/obj/structure/disposalpipe/segment,
+/obj/effect/mapping_helpers/iannewyear,
+/turf/open/floor/plasteel/grimy,
+/area/crew_quarters/heads/hop)
"aao" = (
/obj/structure/lattice/catwalk,
/obj/structure/cable,
@@ -153221,7 +153226,7 @@ cge
ehb
cjB
ckX
-bZb
+aai
coa
cpE
caM
diff --git a/_maps/map_files/Donutstation/Donutstation.dmm b/_maps/map_files/Donutstation/Donutstation.dmm
index 9478a945784..b32ca4e5070 100644
--- a/_maps/map_files/Donutstation/Donutstation.dmm
+++ b/_maps/map_files/Donutstation/Donutstation.dmm
@@ -3353,6 +3353,17 @@
dir = 5
},
/area/crew_quarters/kitchen)
+"ahZ" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 5
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{
+ dir = 5
+ },
+/obj/structure/cable,
+/obj/effect/mapping_helpers/iannewyear,
+/turf/open/floor/carpet,
+/area/crew_quarters/heads/hop)
"aib" = (
/obj/structure/plasticflaps,
/obj/machinery/conveyor{
@@ -49825,16 +49836,6 @@
/obj/structure/cable,
/turf/open/floor/plasteel,
/area/engine/engineering)
-"woM" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 5
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{
- dir = 5
- },
-/obj/structure/cable,
-/turf/open/floor/carpet,
-/area/crew_quarters/heads/hop)
"woV" = (
/obj/machinery/light/small{
dir = 8
@@ -96066,7 +96067,7 @@ aiO
oBZ
buN
xyd
-woM
+ahZ
bCs
aiO
buh
diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm
index 20300614f63..67ea729090c 100644
--- a/_maps/map_files/KiloStation/KiloStation.dmm
+++ b/_maps/map_files/KiloStation/KiloStation.dmm
@@ -59865,6 +59865,10 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating,
/area/maintenance/port/aft)
+"bJY" = (
+/obj/effect/mapping_helpers/iannewyear,
+/turf/open/floor/wood,
+/area/crew_quarters/heads/hop)
"bKa" = (
/obj/structure/dresser,
/obj/machinery/button/door{
@@ -62323,9 +62327,6 @@
},
/turf/open/floor/plasteel/dark,
/area/hallway/primary/starboard)
-"bNB" = (
-/turf/open/floor/wood,
-/area/crew_quarters/heads/hop)
"bNC" = (
/obj/machinery/door/firedoor,
/obj/effect/turf_decal/caution/stand_clear,
@@ -124517,7 +124518,7 @@ adJ
bnP
atj
avV
-bNB
+bJY
bOx
atr
bVw
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 282505f5d71..f7ca9507b9c 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -1017,6 +1017,12 @@
/obj/structure/cable,
/turf/open/floor/plasteel,
/area/security/prison)
+"acw" = (
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
+/obj/structure/cable,
+/obj/effect/mapping_helpers/iannewyear,
+/turf/open/floor/carpet,
+/area/crew_quarters/heads/hop)
"acx" = (
/obj/machinery/airalarm{
dir = 8;
@@ -32166,11 +32172,6 @@
/obj/effect/mapping_helpers/ianbirthday,
/turf/open/floor/carpet,
/area/crew_quarters/heads/hop)
-"bsN" = (
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
-/obj/structure/cable,
-/turf/open/floor/carpet,
-/area/crew_quarters/heads/hop)
"bsO" = (
/obj/structure/cable,
/obj/machinery/photocopier,
@@ -100813,7 +100814,7 @@ bkz
bmp
bon
bqC
-bsN
+acw
buo
bwj
bol
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index 6aefb4039b5..9ed78033d07 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -356,6 +356,10 @@
/obj/effect/landmark/start/paramedic,
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
+"aaT" = (
+/obj/effect/mapping_helpers/iannewyear,
+/turf/open/floor/wood,
+/area/crew_quarters/heads/hop)
"abf" = (
/obj/structure/bed,
/turf/open/floor/plating,
@@ -91733,7 +91737,7 @@ aaa
aaa
aAH
aBD
-aCS
+aaT
aDV
aEO
aAH
diff --git a/code/datums/dog_fashion.dm b/code/datums/dog_fashion.dm
index 7b1c73548c4..fc192beeb0e 100644
--- a/code/datums/dog_fashion.dm
+++ b/code/datums/dog_fashion.dm
@@ -174,3 +174,8 @@
/datum/dog_fashion/back/deathsquad
name = "Trooper REAL_NAME"
desc = "That's not red paint. That's real corgi blood."
+
+/datum/dog_fashion/head/festive
+ name = "Festive REAL_NAME"
+ desc = "Ready to party!"
+ obj_icon_state = "festive"
diff --git a/code/game/objects/items/grenades/festive.dm b/code/game/objects/items/grenades/festive.dm
new file mode 100644
index 00000000000..4e35987cdd3
--- /dev/null
+++ b/code/game/objects/items/grenades/festive.dm
@@ -0,0 +1,117 @@
+//~*~*~*~*SPARKLER*~*~*~*~*~*~
+
+/obj/item/sparkler
+ name = "sparkler"
+ desc = "A little stick coated with metal power and barium nitrate, burns with a pleasing sparkle."
+ icon = 'icons/obj/holiday_misc.dmi'
+ icon_state = "sparkler"
+ w_class = WEIGHT_CLASS_TINY
+ heat = 1000
+ var/burntime = 60
+ var/lit = FALSE
+
+/obj/item/sparkler/fire_act(exposed_temperature, exposed_volume)
+ light()
+
+/obj/item/sparkler/attackby(obj/item/W, mob/user, params)
+ var/ignition_msg = W.ignition_effect(src, user)
+ if(ignition_msg)
+ light(user, ignition_msg)
+ else
+ return ..()
+
+/obj/item/sparkler/proc/light(mob/user, message)
+ if(lit)
+ return
+ if(user && message)
+ user.visible_message(message)
+ lit = TRUE
+ icon_state = "sparkler_on"
+ force = 6
+ hitsound = 'sound/items/welder.ogg'
+ name = "lit [initial(name)]"
+ attack_verb = list("burnt")
+ set_light(l_range = 2, l_power = 2)
+ damtype = "fire"
+ START_PROCESSING(SSobj, src)
+ playsound(src, 'sound/effects/fuse.ogg', 20, TRUE)
+ update_icon()
+
+/obj/item/sparkler/process()
+ burntime--
+ if(burntime < 1)
+ new /obj/item/stack/rods(drop_location())
+ qdel(src)
+ else
+ open_flame(heat)
+
+/obj/item/sparkler/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ ..()
+
+/obj/item/sparkler/ignition_effect(atom/A, mob/user)
+ . = "[user] gracefully lights [A] with [src]."
+
+/obj/item/sparkler/get_temperature()
+ return lit * heat
+
+//~*~*~*~*FIRECRACKER*~*~*~*~*~*~
+
+/obj/item/grenade/firecracker
+ name = "large firecracker"
+ desc = "Outlawed in most of the sector. Doubles as an excellent finger remover."
+ icon = 'icons/obj/holiday_misc.dmi'
+ icon_state = "firecracker"
+ lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
+ w_class = WEIGHT_CLASS_SMALL
+ item_state = "flare"
+ throw_speed = 3
+ throw_range = 7
+ det_time = 30
+
+/obj/item/grenade/firecracker/attack_self(mob/user) // You need to light it manually.
+ return
+
+/obj/item/grenade/firecracker/attackby(obj/item/W, mob/user, params)
+ var/ignition_msg = W.ignition_effect(src, user)
+ if(ignition_msg && !active)
+ visible_message(ignition_msg)
+ preprime(user)
+ else
+ return ..()
+
+/obj/item/grenade/firecracker/fire_act(exposed_temperature, exposed_volume)
+ prime()
+
+obj/item/grenade/firecracker/wirecutter_act(mob/living/user, obj/item/I)
+ if(active)
+ return
+ if(det_time)
+ det_time -= 10
+ to_chat(user, "You shorten the fuse of [src] with [I].")
+ playsound(src, 'sound/items/wirecutter.ogg', 20, TRUE)
+ icon_state = initial(icon_state) + "_[det_time]"
+ update_icon()
+ else
+ to_chat(user, "You've already removed all of the fuse!")
+
+obj/item/grenade/firecracker/preprime(mob/user, delayoverride, msg = TRUE, volume = 80)
+ var/turf/T = get_turf(src)
+ log_grenade(user, T)
+ if(user)
+ add_fingerprint(user)
+ if(msg)
+ to_chat(user, "You prime [src]! [capitalize(DisplayTimeText(det_time))]!")
+ playsound(src, 'sound/effects/fuse.ogg', volume, TRUE)
+ active = TRUE
+ icon_state = initial(icon_state) + "_active"
+ addtimer(CALLBACK(src, .proc/prime), isnull(delayoverride)? det_time : delayoverride)
+
+/obj/item/grenade/firecracker/prime()
+ update_mob()
+ var/explosion_loc = get_turf(src)
+ qdel(src)
+ explosion(explosion_loc,-1,-1,2)
+
+
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index 35d2c2685f4..3f73590ebb9 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -451,7 +451,7 @@
name = "box of teriyaki-flavoured donk-pockets"
icon_state = "donkpocketboxteriyaki"
donktype = /obj/item/reagent_containers/food/snacks/donkpocket/teriyaki
-
+
/obj/item/storage/box/donkpockets/donkpocketpizza
name = "box of pizza-flavoured donk-pockets"
icon_state = "donkpocketboxpizza"
@@ -466,7 +466,7 @@
name = "box of berry-flavoured donk-pockets"
icon_state = "donkpocketboxberry"
donktype = /obj/item/reagent_containers/food/snacks/donkpocket/berry
-
+
/obj/item/storage/box/donkpockets/donkpockethonk
name = "box of banana-flavoured donk-pockets"
icon_state = "donkpocketboxbanana"
@@ -1201,3 +1201,42 @@
/obj/item/storage/box/material=1
)
generate_items_inside(items_inside,src)
+
+/obj/item/storage/box/fireworks
+ name = "box of fireworks"
+ desc = "Contains an assortment of fireworks."
+ illustration = "flashbang"
+
+/obj/item/storage/box/fireworks/PopulateContents()
+ for(var/i in 1 to 3)
+ new/obj/item/sparkler(src)
+ new/obj/item/grenade/firecracker(src)
+ new /obj/item/toy/snappop(src)
+
+/obj/item/storage/box/fireworks/dangerous
+
+/obj/item/storage/box/fireworks/dangerous/PopulateContents()
+ for(var/i in 1 to 3)
+ new/obj/item/sparkler(src)
+ new/obj/item/grenade/firecracker(src)
+ if(prob(20))
+ new /obj/item/grenade/syndieminibomb/concussion/frag(src)
+ else
+ new /obj/item/toy/snappop(src)
+
+/obj/item/storage/box/firecrackers
+ name = "box of firecrackers"
+ desc = "A box filled with illegal firecracker. You wonder who still makes these."
+ icon_state = "syndiebox"
+
+/obj/item/storage/box/firecrackers/PopulateContents()
+ for(var/i in 1 to 7)
+ new/obj/item/grenade/firecracker(src)
+
+/obj/item/storage/box/sparklers
+ name = "box of sparklers"
+ desc = "A box of NT brand sparklers, burns hot even in the cold of space-winter."
+
+/obj/item/storage/box/sparklers/PopulateContents()
+ for(var/i in 1 to 7)
+ new/obj/item/sparkler(src)
diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm
index bd1cf9bf4ff..0842055aac4 100644
--- a/code/modules/events/holiday/xmas.dm
+++ b/code/modules/events/holiday/xmas.dm
@@ -38,6 +38,7 @@
desc = "A crappy paper hat that you are REQUIRED to wear."
flags_inv = 0
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
+ dog_fashion = /datum/dog_fashion/head/festive
/obj/effect/spawner/xmastree
name = "christmas tree spawner"
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm
index c5182fc486b..cb5c534bde6 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers.dm
@@ -301,6 +301,41 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
birthday()
qdel(src)
+//Ian, like most dogs, loves a good new years eve party.
+/obj/effect/mapping_helpers/iannewyear
+ name = "Ian's New Years Helper"
+ late = TRUE
+ icon_state = "iansnewyrshelper"
+
+/obj/effect/mapping_helpers/iannewyear/LateInitialize()
+ if(SSevents.holidays && SSevents.holidays[NEW_YEAR])
+ fireworks()
+ qdel(src)
+
+/obj/effect/mapping_helpers/iannewyear/proc/fireworks()
+ var/area/a = get_area(src)
+ var/list/table = list()//should only be one aka the front desk, but just in case...
+ var/list/openturfs = list()
+
+ for(var/thing in a.contents)
+ if(istype(thing, /obj/structure/table/reinforced))
+ table += thing
+ else if(isopenturf(thing))
+ if(locate(/obj/structure/bed/dogbed/ian) in thing)
+ new /obj/item/clothing/head/festive(thing)
+ var/obj/item/reagent_containers/food/drinks/bottle/champagne/iandrink = new(thing)
+ iandrink.name = "dog champagne"
+ iandrink.pixel_y += 8
+ iandrink.pixel_x += 8
+ else
+ openturfs += thing
+
+ var/turf/fireworks_turf = get_turf(pick(table))
+ var/obj/item/storage/box/matches/matchbox = new(fireworks_turf)
+ matchbox.pixel_y += 8
+ matchbox.pixel_x -= 3
+ new /obj/item/storage/box/fireworks/dangerous(fireworks_turf) //dangerous version for extra holiday memes.
+
//lets mappers place notes on airlocks with custom info or a pre-made note from a path
/obj/effect/mapping_helpers/airlock_note_placer
name = "Airlock Note Placer"
@@ -335,4 +370,3 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
log_mapping("[src] at [x],[y] could not find an airlock on current turf, cannot place paper note.")
qdel(src)
-
diff --git a/icons/effects/mapping_helpers.dmi b/icons/effects/mapping_helpers.dmi
index 008b093d462..849abcbea7a 100644
Binary files a/icons/effects/mapping_helpers.dmi and b/icons/effects/mapping_helpers.dmi differ
diff --git a/icons/mob/corgi_head.dmi b/icons/mob/corgi_head.dmi
index 1befce56caf..59ce1af198f 100644
Binary files a/icons/mob/corgi_head.dmi and b/icons/mob/corgi_head.dmi differ
diff --git a/icons/obj/holiday_misc.dmi b/icons/obj/holiday_misc.dmi
index 33cba0c6c2c..61bf41d5c8b 100644
Binary files a/icons/obj/holiday_misc.dmi and b/icons/obj/holiday_misc.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 9872f5ce072..2cdbf198df7 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -999,6 +999,7 @@
#include "code\game\objects\items\grenades\chem_grenade.dm"
#include "code\game\objects\items\grenades\clusterbuster.dm"
#include "code\game\objects\items\grenades\emgrenade.dm"
+#include "code\game\objects\items\grenades\festive.dm"
#include "code\game\objects\items\grenades\flashbang.dm"
#include "code\game\objects\items\grenades\ghettobomb.dm"
#include "code\game\objects\items\grenades\grenade.dm"