Skip to content

Commit

Permalink
Food gets stink lines when about to go rotten (#76038)
Browse files Browse the repository at this point in the history
Title says it all, food that decomposes gets stink lines halfway
through.

![image](https://github.com/tgstation/tgstation/assets/82850673/ae90220c-4b27-49dd-873a-6f349055f891)

![image](https://github.com/tgstation/tgstation/assets/82850673/c982055d-ed69-4935-bda5-7851836fad2c)

Moldy messes always gets stink lines.

1. It's funny
2. It's a visual indicator for food going bad which is kinda nice

:cl:
add: Food now gets stink lines when going bad. Uh oh, stinky.
/:cl:

---------

Co-authored-by: san7890 <the@san7890.com>
  • Loading branch information
2 people authored and AlbertNanotracen committed Jan 29, 2024
1 parent 8940653 commit 5a9a661
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 26 deletions.
86 changes: 61 additions & 25 deletions code/datums/components/food/decomposition.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,27 @@
var/handled = TRUE
/// Used to stop food in someone's hand & in storage slots from decomposing.
var/protected = FALSE
/// Used to stop the timer & check for the examine proc
var/timerid
/// The total time that this takes to decompose
var/original_time = DECOMPOSITION_TIME
/// Used so the timer won't reset.
var/time_remaining = DECOMPOSITION_TIME
/// Used to create stink lines when the food is close to going bad
var/stink_timerid
/// Used to stop decomposition & check for the examine proc
var/decomp_timerid
/// Used to give raw/gross food lower timers
var/decomp_flags
/// Use for determining what kind of item the food decomposes into.
var/decomp_result
/// Does our food attract ants?
var/produce_ants = FALSE
/// Stink particle type, if we are supposed to create stink particles
var/stink_particles
/// Stink particle holder
var/obj/effect/abstract/particle_holder/particle_effect

/datum/component/decomposition/Initialize(mapload, decomp_req_handle, decomp_flags = NONE, decomp_result, ant_attracting = FALSE, custom_time = 0)
if(!isobj(parent))
/datum/component/decomposition/Initialize(mapload, decomp_req_handle, decomp_flags = NONE, decomp_result, ant_attracting = FALSE, custom_time = 0, stink_particles = /particles/stink)
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE

src.decomp_flags = decomp_flags
Expand All @@ -33,17 +39,6 @@
handled = FALSE
src.produce_ants = ant_attracting

RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(handle_movement))
RegisterSignals(parent, list(
COMSIG_ITEM_PICKUP, //person picks up an item
COMSIG_ATOM_ENTERED), //Object enters a storage object (boxes, etc.)
PROC_REF(picked_up))
RegisterSignals(parent, list(
COMSIG_ITEM_DROPPED, //Object is dropped anywhere
COMSIG_ATOM_EXITED), //Object exits a storage object (boxes, etc)
PROC_REF(dropped))
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examine))

if(custom_time) // We have a custom decomposition time, set it to that
original_time = custom_time
else if(decomp_flags & RAW) // Raw food overrides gross
Expand All @@ -53,8 +48,28 @@

time_remaining = original_time

src.stink_particles = stink_particles

handle_movement()

/datum/component/decomposition/Destroy()
. = ..()
if(particle_effect)
QDEL_NULL(particle_effect)

/datum/component/decomposition/RegisterWithParent()
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(handle_movement))
RegisterSignals(parent, list(
COMSIG_ITEM_PICKUP, //person picks up an item
COMSIG_ATOM_ENTERED), //Object enters a storage object (boxes, etc.)
PROC_REF(picked_up),
)
RegisterSignals(parent, list(
COMSIG_ITEM_DROPPED, //Object is dropped anywhere
COMSIG_ATOM_EXITED), //Object exits a storage object (boxes, etc)
PROC_REF(dropped),
)
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examine))

/datum/component/decomposition/UnregisterFromParent()
UnregisterSignal(parent, list(
Expand All @@ -67,8 +82,10 @@

/datum/component/decomposition/proc/handle_movement()
SIGNAL_HANDLER

if(!handled) // If maploaded, has someone touched this previously?
return

var/obj/food = parent // Doesn't HAVE to be food, that's just what it's intended for

var/turf/open/open_turf = food.loc
Expand All @@ -83,24 +100,35 @@
return

// If all other checks fail, then begin decomposition.
timerid = addtimer(CALLBACK(src, PROC_REF(decompose)), time_remaining, TIMER_STOPPABLE | TIMER_UNIQUE)
decomp_timerid = addtimer(CALLBACK(src, PROC_REF(decompose)), time_remaining, TIMER_STOPPABLE | TIMER_UNIQUE)

// Also start the stinking timer, if have stink particles and aren't stinking yet
if(!stink_particles || particle_effect)
return

var/stink_time = max(0, time_remaining - (original_time * 0.5))
stink_timerid = addtimer(CALLBACK(src, PROC_REF(stink_up)), stink_time, TIMER_STOPPABLE | TIMER_UNIQUE)

/datum/component/decomposition/Destroy()
remove_timer()
return ..()

/// Returns the time remaining in decomp, either from our potential timer or our own value, whichever is more useful
/datum/component/decomposition/proc/get_time()
if(!timerid)
if(!decomp_timerid)
return time_remaining
return timeleft(timerid)
return timeleft(decomp_timerid)

/datum/component/decomposition/proc/remove_timer()
if(!timerid)
if(!decomp_timerid)
return
time_remaining = timeleft(timerid)
deltimer(timerid)
timerid = null
time_remaining = timeleft(decomp_timerid)
deltimer(decomp_timerid)
decomp_timerid = null
if(!stink_timerid)
return
deltimer(stink_timerid)
stink_timerid = null

/datum/component/decomposition/proc/dropped()
SIGNAL_HANDLER
Expand All @@ -111,16 +139,24 @@
SIGNAL_HANDLER
remove_timer()
protected = TRUE
if(!handled)
handled = TRUE
handled = TRUE

/datum/component/decomposition/proc/stink_up()
stink_timerid = null
// Neither should happen, but to be sure
if(particle_effect || !stink_particles)
return
// we don't want stink lines on mobs (even though it'd be quite funny)
particle_effect = new(parent, stink_particles, isitem(parent) ? NONE : PARTICLE_ATTACH_MOB)

/datum/component/decomposition/proc/decompose()
decomp_timerid = null
var/obj/decomp = parent //Lets us spawn things at decomp
if(produce_ants)
new /obj/effect/decal/cleanable/ants(decomp.loc)
if(decomp_result)
new decomp_result(decomp.loc)
decomp.visible_message("<span class='notice'>[decomp] gets overtaken by mold[produce_ants ? " and ants":""]! Gross!</span>")
decomp.visible_message(span_warning("[decomp] gets overtaken by mold[produce_ants ? " and ants":""]! Gross!"))
qdel(decomp)
return

Expand Down
13 changes: 13 additions & 0 deletions code/game/objects/effects/particles/misc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,16 @@
position = generator(GEN_BOX, list(-240, -240), list(240, 240), NORMAL_RAND)
drift = generator(GEN_VECTOR, list(-0.1, 0), list(0.1, 0))
rotation = generator(GEN_NUM, 0, 360, NORMAL_RAND)

/particles/stink
icon = 'icons/effects/particles/stink.dmi'
icon_state = list("stink_1" = 1, "stink_2" = 2, "stink_3" = 2)
color = "#0BDA51"
width = 100
height = 100
count = 25
spawning = 0.25
lifespan = 1 SECONDS
fade = 1 SECONDS
position = generator(GEN_CIRCLE, 0, 16, UNIFORM_RAND)
gravity = list(0, 0.25)
2 changes: 1 addition & 1 deletion code/game/objects/items/food/_food.dm
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,4 @@
///Set decomp_req_handle to TRUE to only make it decompose when someone picks it up.
/obj/item/food/proc/make_decompose(mapload)
if(!preserved_food)
AddComponent(/datum/component/decomposition, mapload, decomp_req_handle, decomp_flags = foodtypes, decomp_result = decomp_type, ant_attracting = ant_attracting, custom_time = decomposition_time)
AddComponent(/datum/component/decomposition, mapload, decomp_req_handle, decomp_flags = foodtypes, decomp_result = decomp_type, ant_attracting = ant_attracting, custom_time = decomposition_time, stink_particles = decomposition_particles)
5 changes: 5 additions & 0 deletions code/game/objects/items/food/misc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,14 @@
foodtypes = GROSS
w_class = WEIGHT_CLASS_SMALL
preserved_food = TRUE //Can't decompose any more than this
/// Variable that holds the reference to the stink lines we get when we're moldy, yucky yuck
var/stink_particles

/obj/item/food/badrecipe/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_ITEM_GRILL_PROCESS, PROC_REF(OnGrill))
if(stink_particles)
particles = new stink_particles

/obj/item/food/badrecipe/moldy
name = "moldy mess"
Expand All @@ -103,6 +107,7 @@
ant_attracting = TRUE
decomp_type = null
decomposition_time = 30 SECONDS
stink_particles = /particles/stink

/obj/item/food/badrecipe/moldy/bacteria
name = "bacteria rich moldy mess"
Expand Down
Binary file added icons/effects/particles/stink.dmi
Binary file not shown.

0 comments on commit 5a9a661

Please sign in to comment.