Skip to content

Commit

Permalink
Reimplements halloween pumpkin helmets event (#4623)
Browse files Browse the repository at this point in the history
# About the pull request

<!-- Remove this text and explain what the purpose of your PR is.

Mention if you have tested your changes. If you changed a map, make sure
you used the mapmerge tool.
If this is an Issue Correction, you can type "Fixes Issue #169420" to
link the PR to the corresponding Issue number #169420.

Remember: something that is self-evident to you might not be to others.
Explain your rationale fully, even if you feel it goes without saying.
-->

This reimplements the Halloween Pumpkins spawning on map and being
carvable as helmets which was apparetnly a thing a number of years ago

# Explain why it's good for the game
Variety

# Changelog
:cl: Firartix and Frans_Feiffer
add: Readded Halloween pumpkin helmets.
/:cl:

---------

Co-authored-by: harryob <[email protected]>
  • Loading branch information
fira and harryob committed Nov 6, 2023
1 parent a6344b3 commit b421490
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 65 deletions.
35 changes: 35 additions & 0 deletions code/controllers/subsystem/game_decorator.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Essentially the same as decorators but that apply to the whole game state instead of individual atoms
SUBSYSTEM_DEF(game_decorator)
name = "Game Decorator"
init_order = SS_INIT_DECORATOR
flags = SS_NO_FIRE

/datum/controller/subsystem/game_decorator/Initialize()
. = ..()
for(var/decorator_type in subtypesof(/datum/game_decorator))
var/datum/game_decorator/decorator = new decorator_type()
if(!decorator.is_active_decor())
continue
if(!decorator.defer_decoration)
decorator.decorate()
CHECK_TICK

return SS_INIT_SUCCESS

/datum/game_decorator
var/defer_decoration = TRUE //! So map decoration is done post-setup after nightmare and spawners

/datum/game_decorator/New()
if(defer_decoration)
RegisterSignal(SSdcs, COMSIG_GLOB_MODE_POSTSETUP, PROC_REF(defered_decoration))

/datum/game_decorator/proc/is_active_decor()
return FALSE

/datum/game_decorator/proc/defered_decoration(dcs)
SIGNAL_HANDLER
decorate()

/datum/game_decorator/proc/decorate()
set waitfor = FALSE
return
4 changes: 4 additions & 0 deletions code/game/turfs/open.dm
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
name = "cave"
icon = 'icons/turf/floors/bigred.dmi'
icon_state = "mars_cave_1"
is_groundmap_turf = TRUE


/turf/open/mars_cave/Initialize(mapload, ...)
Expand Down Expand Up @@ -283,6 +284,7 @@
name = "ground dirt"
icon = 'icons/turf/ground_map.dmi'
icon_state = "desert"
is_groundmap_turf = TRUE

/turf/open/gm/attackby(obj/item/I, mob/user)

Expand Down Expand Up @@ -646,6 +648,7 @@
baseturfs = /turf/open/gm/riverdeep
supports_surgery = FALSE
minimap_color = MINIMAP_WATER
is_groundmap_turf = FALSE // Not real ground


/turf/open/gm/riverdeep/Initialize(mapload, ...)
Expand Down Expand Up @@ -724,6 +727,7 @@
allow_construction = FALSE
var/bushes_spawn = 1
var/plants_spawn = 1
is_groundmap_turf = TRUE
name = "wet grass"
desc = "Thick, long, wet grass."
icon = 'icons/turf/floors/jungle.dmi'
Expand Down
2 changes: 1 addition & 1 deletion code/modules/cm_aliens/weeds.dm
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@
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)
Expand Down
63 changes: 0 additions & 63 deletions code/modules/decorators/halloween.dm

This file was deleted.

108 changes: 108 additions & 0 deletions code/modules/holidays/halloween/decorators.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/datum/game_decorator/halloween

/datum/game_decorator/halloween/is_active_decor()
return (get_days_remaining() != -1)

/// Get the number of days remaining to event, or -1 if not applicable
/datum/game_decorator/halloween/proc/get_days_remaining()
. = -1
var/cur_day = text2num(time2text(world.timeofday, "DD"))
var/cur_mon = text2num(time2text(world.timeofday, "MM"))
if(cur_mon == 10)
return max(0, 31 - cur_day)
if(cur_mon == 11 && cur_day < 4)
return 0

/// Pumpkins decorator: adds patches of carvable/wearable pumpkins around the ground level
/datum/game_decorator/halloween/pumpkins
var/pumpkin_count = 60 //! Amount of pumpkins to place
var/pumpkin_count_decrease = 1 //! Amount of pumpkins to remove per day to halloween
var/pumpkin_prob_corruption = 20
var/pumpkin_prob_decrease = 0.5 //! Chance reduction per day before halloween
var/exclusion_range = 10

/datum/game_decorator/halloween/pumpkins/decorate()
var/list/turf/valid_turfs = list()
var/list/ground_levels = SSmapping.levels_by_trait(ZTRAIT_GROUND)
for(var/ground_z in ground_levels)
var/list/turf/all_turfs = block(locate(1, 1, ground_z), locate(world.maxx, world.maxy, ground_z))
for(var/turf/open/turf in all_turfs)
if(turf.is_groundmap_turf)
var/valid = TRUE
for(var/atom/movable/movable as anything in turf.contents)
if(movable.density && movable.can_block_movement)
valid = FALSE
break
if(valid)
valid_turfs += turf
CHECK_TICK

var/list/turf/picked_turfs = list()
for(var/step in 1 to (pumpkin_count - pumpkin_count_decrease * get_days_remaining()))
if(!length(valid_turfs))
break
var/turf/considered_turf = pick(valid_turfs)
var/x_min = max(1, considered_turf.x - exclusion_range)
var/y_min = max(1, considered_turf.y - exclusion_range)
var/x_max = min(world.maxx, considered_turf.x + exclusion_range)
var/y_max = min(world.maxy, considered_turf.y + exclusion_range)
var/list/turf/denied_turfs = block(locate(x_min, y_min, considered_turf.z), locate(x_max, y_max, considered_turf.z))
valid_turfs -= denied_turfs
picked_turfs += considered_turf

var/corruption_chance = pumpkin_prob_corruption - (get_days_remaining() * pumpkin_prob_decrease)
for(var/turf/target in picked_turfs)
if(prob(corruption_chance))
new /obj/structure/pumpkin_patch/corrupted(target)
else
new /obj/structure/pumpkin_patch(target)

/// Cobweb decorator: adds more and more cobwebs as you go through the month
/datum/game_decorator/halloween/cobwebs
/// How much prob() chance to put a cobweb during halloween proper
var/base_chance = 25
/// How much to remove per day before date
var/ramp_chance = 0.5
/// How much to scale cobwebs alpha down per day (1 - ramp_scale * days, affects alpha & size)
var/ramp_scale = 0.01
/// Extra randomness removed onto scale before full blown halloween
var/scale_rand = 0.3

/datum/game_decorator/halloween/cobwebs/decorate()
for(var/turf/closed/wall/almayer/turf in world)
if(is_mainship_level(turf.z))
decorate_turf(turf)
CHECK_TICK

/datum/game_decorator/halloween/cobwebs/proc/decorate_turf(turf/closed/wall/almayer/turf)
var/static/list/order = list(NORTHWEST, SOUTHEAST, NORTHEAST, SOUTHWEST) // Ordering of wall_connections
if(length(turf.wall_connections) < 4)
return

var/event_progress = get_days_remaining()
var/placement_chance = base_chance - (event_progress * ramp_chance)
for(var/i = 1 to 4)
var/diag = order[i]
if(turf.wall_connections[i] != "5") // CORNER_CLOCKWISE | CORNER_COUNTERCLOCKWISE as string - don't ask me
continue
if(!prob(placement_chance))
continue

// Skip this if this corner is result of a door connection (mostly for Almayer shutters)
var/valid = TRUE
for(var/a_cardinal in cardinal)
var/cardinal_dir = diag & a_cardinal
if(!a_cardinal) // We check cardinals contributing to that diagonal
continue
var/turf/target = get_step(turf, cardinal_dir)
if(locate(/obj/structure/machinery/door) in target)
valid = FALSE
break

if(valid) // Actually place cobweb
var/turf/target = get_step(turf, diag)
if(istype(target, /turf/open))
var/scale = 1 - ramp_scale * event_progress
scale -= scale_rand * rand()
new /obj/effect/decal/cleanable/cobweb2/dynamic(target, diag, scale)

65 changes: 65 additions & 0 deletions code/modules/holidays/halloween/pumpkins/patches.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/// Patches of pumpkins spawned at roundstart from where marines can get their carvable pumpkins
/obj/structure/pumpkin_patch
icon = 'icons/misc/events/pumpkins.dmi'
name = "patch of pumpkins"
var/empty_name = "\proper vines"

can_block_movement = FALSE
unslashable = TRUE
health = 400 // To avoid explosions and stray gunfire destroying them too easily
layer = LOWER_ITEM_LAYER

var/has_vines = TRUE //! Whether there's still vines to display or not
var/pumpkin_count = 3 //! Amount of pumpkins currently in the patch
var/icon_prefix //! Prefix to prepend to icon states, for corrupted pumpkins
var/pumpkin_type = /obj/item/clothing/head/pumpkin

/obj/structure/pumpkin_patch/Initialize(mapload, ...)
. = ..()
update_icon()

/obj/structure/pumpkin_patch/update_icon()
overlays?.Cut()
. = ..()
switch(pumpkin_count)
if(3) icon_state = "[icon_prefix]pumpkins_full"
if(2) icon_state = "[icon_prefix]pumpkins_half"
if(1) icon_state = "[icon_prefix]pumpkin"
else icon_state = "empty"
if(has_vines)
overlays += image(icon, loc, "[icon_prefix]vines")

/obj/structure/pumpkin_patch/attack_hand(mob/user)
if(pumpkin_count < 1)
to_chat(user, SPAN_WARNING("No more pumpkins here..."))
return
if(!user.get_active_hand()) //if active hand is empty
pumpkin_count--
var/obj/item/clothing/head/pumpkin/pumpkin = new pumpkin_type(loc)
user.put_in_hands(pumpkin)
playsound(loc, 'sound/effects/vegetation_hit.ogg', 25, 1)
update_icon()
if(pumpkin_count < 1)
if(!has_vines)
qdel(src)
else
name = empty_name
return
return ..()

/obj/structure/pumpkin_patch/attackby(obj/item/tool, mob/user)
if(has_vines && (tool.sharp == IS_SHARP_ITEM_ACCURATE || tool.sharp == IS_SHARP_ITEM_BIG))
to_chat(user, SPAN_NOTICE("You cut down the vines."))
playsound(loc, "alien_resin_break", 25)
has_vines = FALSE
update_icon()
if(pumpkin_count < 1 && !has_vines)
qdel(src)
return
return ..()

/obj/structure/pumpkin_patch/corrupted
icon_prefix = "cor_"
name = "patch of corrupted pumpkins"
empty_name = "\proper corrupted vines"
pumpkin_type = /obj/item/clothing/head/pumpkin/corrupted
72 changes: 72 additions & 0 deletions code/modules/holidays/halloween/pumpkins/wearable.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/// Carved Pumpkin from the Halloween event
/obj/item/clothing/head/pumpkin
name = "pumpkin"
icon = 'icons/misc/events/pumpkins.dmi'
item_icons = list(
WEAR_HEAD = 'icons/misc/events/pumpkins.dmi',
)
desc = "An ominous looking pumpkin. Would look pretty spooky if worn on your head..."
w_class = SIZE_MEDIUM
flags_inv_hide = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
flags_armor_protection = BODY_FLAG_HEAD|BODY_FLAG_EYES
flags_inventory = COVEREYES|BLOCKSHARPOBJ|COVERMOUTH
flags_cold_protection = BODY_FLAG_HEAD
flags_heat_protection = BODY_FLAG_HEAD
min_cold_protection_temperature = HELMET_MIN_COLD_PROT
max_heat_protection_temperature = HELMET_MAX_HEAT_PROT
armor_melee = CLOTHING_ARMOR_MEDIUM
armor_bullet = CLOTHING_ARMOR_MEDIUM
armor_laser = CLOTHING_ARMOR_MEDIUMLOW
armor_energy = CLOTHING_ARMOR_NONE
armor_bomb = CLOTHING_ARMOR_LOW
armor_bio = CLOTHING_ARMOR_MEDIUM
armor_rad = CLOTHING_ARMOR_LOW
armor_internaldamage = CLOTHING_ARMOR_MEDIUM
health = 5
force = 15
var/prefix = "" //! Icon state prefix for corrupted pumpkin variants
var/carved_icon = "" //! Currently carved pumpkin overlay
var/carvable_icons = list("smile", "cheeky", "bugeyes", "upside_down_smile", "skelly", "ff")

/obj/item/clothing/head/pumpkin/Initialize(mapload, ...)
. = ..()
update_icon()

/obj/item/clothing/head/pumpkin/update_icon()
. = ..()
if(carved_icon)
icon_state = "[prefix]pumpkin_carved"
else
icon_state = "[prefix]pumpkin"
item_state_slots = list(
WEAR_HEAD = "[prefix]pumpkin_onmob",
)

/obj/item/clothing/head/pumpkin/mob_can_equip(mob/user, slot, disable_warning)
if(slot == WEAR_HEAD && !carved_icon)
to_chat(user, SPAN_WARNING("You can't put on a full pumpkin! Empty and carve it with a sharp object first."))
return FALSE
. = ..()

/obj/item/clothing/head/pumpkin/attackby(obj/item/tool, mob/user)
if(!carved_icon && (tool.sharp == IS_SHARP_ITEM_ACCURATE || tool.sharp == IS_SHARP_ITEM_BIG))
var/choice = tgui_input_list(user, "Select the pattern to carve on your pumpkin!", "Pumpkin Carving", carvable_icons)
if(choice)
playsound(loc, 'sound/effects/vegetation_hit.ogg', 25, 1)
carved_icon = choice
name = "carved pumpkin"
update_icon()
else
return ..()

/obj/item/clothing/head/pumpkin/get_mob_overlay(mob/user_mob, slot)
var/image/pumpkin = ..()
if(carved_icon && slot == WEAR_HEAD)
var/image/overlay = overlay_image(icon, "[prefix]pumpkin_[carved_icon]")
pumpkin.overlays += overlay
return pumpkin

/obj/item/clothing/head/pumpkin/corrupted
name = "corrupted pumpkin"
prefix = "cor_"
carvable_icons = list("cry", "sob", "sad", "why", "spooky", "ff")
Loading

0 comments on commit b421490

Please sign in to comment.