-
Notifications
You must be signed in to change notification settings - Fork 565
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The weeds are hungry: Bodies for the weeds (#3644)
# About the pull request This PR adds Kugamo's sprites where bodies can be integrated into the weeds. The bodies lose their interactivity, examinability, and HUDs when merged with the weeds, and are anchored. Destroying the weeds though will restore the body to normal. Currently requires the body to not be grabbable by a xeno (as in not impregnated or bursted) as well as unrevivable. Once they are permadead it currently waits 5 minutes to start merging, then 1 minute on each sprite state (there are 5). Support is basically already in place for non-humans to also use this system (just uncomment two blocks of commented out code), but I am unsure what sprites or method to hide their corpses would be used instead. I also see no issues (visual or code) with this merging nested hosts, but it will not currently merge bursts until they are no longer considered grabbable. # Explain why it's good for the game Less clutter, and it just looks neat. ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/9b8cde21-b12c-4340-b9f9-ecb48480f286) After fixing the flipped lighting: ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/4a420b14-46d3-4586-afa2-9c4bbae9888e) # Testing Photographs and Procedure <details> <summary>Screenshots & Videos</summary> As an animation when it was fast: ![weeds](https://github.com/cmss13-devs/cmss13/assets/76988376/d4e6de2c-532c-451d-ab55-964ec54a5de4) Earlier testing: ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/48bd6f9d-d14c-423b-aa87-1036b0a632d4) ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/40b402fc-db1e-413d-b8e4-6da3804d7ef1) Tested with zombies (they don't have undefib set when they die so won't be consumed before revival, and revival removes the component off of them until they die again - if they decap they will get a undefib signal to cause them to be consumed), smols (look at that cute little tail), rollers, coffins (now they don't suck up anchored mobs), beds, chairs, and fulton: ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/fa92e380-4e02-4377-9d7e-25fadcfd43ed) </details> # Changelog :cl: Drathek Kugamo add: Added the ability for weeds to merge with unrevivable corpses imageadd: Added human shaped weeds by Kugamo code: Added a signal for weeds sent to the turf to indicate it is now weeded, and added a signal for afterbuckle. fix: Closets (including coffins) can no longer move anchored mobs. /:cl:
- Loading branch information
Showing
12 changed files
with
360 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,297 @@ | ||
#define WEED_FOOD_DELAY 5 MINUTES | ||
#define WEED_FOOD_STATE_DELAY 1 MINUTES | ||
|
||
/atom/movable/vis_obj/weed_food | ||
name = "weeds" | ||
desc = "Weird black weeds in the shape of a body..." | ||
gender = PLURAL | ||
vis_flags = VIS_INHERIT_DIR|VIS_INHERIT_PLANE|VIS_INHERIT_LAYER | ||
icon = 'icons/mob/xenos/weeds.dmi' | ||
var/static/list/icon_states = list("human_1","human_2","human_3","human_4","human_5") | ||
var/static/list/icon_states_flipped = list("human_1_f","human_2_f","human_3_f","human_4_f","human_5_f") | ||
var/icon_state_idx = 0 | ||
var/timer_id = null | ||
var/flipped = FALSE | ||
|
||
/atom/movable/vis_obj/weed_food/Initialize(mapload, is_flipped, ...) | ||
flipped = is_flipped | ||
timer_id = addtimer(CALLBACK(src, PROC_REF(on_animation_timer)), WEED_FOOD_STATE_DELAY, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_LOOP|TIMER_DELETE_ME) | ||
on_animation_timer() | ||
return ..() | ||
|
||
/// Timer callback for changing the icon_state | ||
/atom/movable/vis_obj/weed_food/proc/on_animation_timer() | ||
icon_state_idx++ | ||
if(icon_state_idx > length(icon_states)) | ||
deltimer(timer_id) | ||
timer_id = null | ||
return | ||
icon_state = flipped ? icon_states_flipped[icon_state_idx] : icon_states[icon_state_idx] | ||
|
||
/** | ||
* A component that can be attached to a mob/living to be merged with weeds after a delay. | ||
* Attempting to attach a new weed_food even if one already exists is equivalent to calling start(). | ||
* | ||
* Attach this to any mob/living that is dead (death or initialized dead) and it should handle the rest. | ||
*/ | ||
/datum/component/weed_food | ||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS | ||
/// Whether we are waiting on timer to merge | ||
var/active = FALSE | ||
/// Whether we are merged with weeds | ||
var/merged = FALSE | ||
/// The time we were unmerged (just to handle weeds upgrading) | ||
var/unmerged_time | ||
/// Any active timer for a pending merge | ||
var/timer_id = null | ||
/// The living mob that we are bound to | ||
var/mob/living/parent_mob | ||
/// The turf that our parent is on | ||
var/turf/parent_turf | ||
/// The obj that our parent is buckled to and we have registered a signal | ||
var/obj/parent_buckle | ||
/// The weeds that we are merging/merged with | ||
var/obj/effect/alien/weeds/absorbing_weeds | ||
/// The overlay image when merged | ||
var/atom/movable/vis_obj/weed_food/weed_appearance | ||
|
||
/datum/component/weed_food/Initialize(...) | ||
parent_mob = parent | ||
//if(!istype(parent_mob)) | ||
//return COMPONENT_INCOMPATIBLE | ||
if(!istype(parent_mob, /mob/living/carbon/human)) | ||
return COMPONENT_INCOMPATIBLE // TODO: At the moment we only support humans | ||
|
||
parent_turf = get_turf(parent_mob) | ||
if(parent_turf != parent_mob.loc) | ||
parent_turf = null // if our location is actually a container, we want to be safe from weeds | ||
|
||
start() | ||
|
||
/datum/component/weed_food/InheritComponent(datum/component/C, i_am_original) | ||
start() | ||
|
||
/datum/component/weed_food/Destroy(force, silent) | ||
. = ..() | ||
|
||
unmerge_with_weeds() | ||
QDEL_NULL(weed_appearance) | ||
parent_mob = null | ||
parent_turf = null | ||
|
||
/datum/component/weed_food/RegisterWithParent() | ||
RegisterSignal(parent_mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) | ||
RegisterSignal(parent_mob, list(COMSIG_LIVING_REJUVENATED, COMSIG_HUMAN_REVIVED), PROC_REF(on_rejuv)) | ||
RegisterSignal(parent_mob, COMSIG_HUMAN_SET_UNDEFIBBABLE, PROC_REF(on_update)) | ||
if(parent_turf) | ||
RegisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH, PROC_REF(on_update)) | ||
|
||
/datum/component/weed_food/UnregisterFromParent() | ||
if(parent_mob) | ||
UnregisterSignal(parent_mob, list( | ||
COMSIG_MOVABLE_MOVED, | ||
COMSIG_LIVING_REJUVENATED, | ||
COMSIG_HUMAN_REVIVED, | ||
COMSIG_HUMAN_SET_UNDEFIBBABLE, | ||
)) | ||
if(absorbing_weeds) | ||
UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) | ||
if(parent_turf) | ||
UnregisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH) | ||
if(parent_buckle) | ||
UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) | ||
|
||
/// SIGNAL_HANDLER for COMSIG_MOVABLE_MOVED | ||
/datum/component/weed_food/proc/on_move() | ||
SIGNAL_HANDLER | ||
|
||
if(absorbing_weeds) | ||
UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) | ||
absorbing_weeds = null | ||
|
||
if(parent_turf) | ||
UnregisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH) | ||
parent_turf = get_turf(parent_mob) | ||
if(parent_turf != parent_mob.loc) | ||
parent_turf = null // if our location is actually a container, we want to be safe from weeds | ||
else | ||
RegisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH, PROC_REF(on_update)) | ||
|
||
// We moved, restart or start the proccess | ||
if(stop() || !merged) | ||
start() | ||
return | ||
|
||
// If we somehow moved when we were merged, handle that | ||
absorbing_weeds = parent_turf?.weeds | ||
if(absorbing_weeds) | ||
RegisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion)) | ||
return | ||
unmerge_with_weeds() | ||
|
||
/// SIGNAL_HANDLER for COMSIG_LIVING_REJUVENATED and COMSIG_HUMAN_REVIVED | ||
/datum/component/weed_food/proc/on_rejuv() | ||
SIGNAL_HANDLER | ||
|
||
qdel(src) | ||
|
||
/// SIGNAL_HANDLER for COSMIG_OBJ_AFTER_BUCKLE | ||
/datum/component/weed_food/proc/on_after_buckle(obj/source, mob/buckled) | ||
SIGNAL_HANDLER | ||
|
||
if(buckled) | ||
return | ||
start() // We unbuckled, so lets try to start again | ||
|
||
/// SIGNAL_HANDLER for COMSIG_HUMAN_SET_UNDEFIBBABLE & COMSIG_WEEDNODE_GROWTH | ||
/datum/component/weed_food/proc/on_update() | ||
SIGNAL_HANDLER | ||
|
||
start() | ||
|
||
/// SIGNAL_HANDLER for COMSIG_PARENT_QDELETING of weeds | ||
/datum/component/weed_food/proc/on_weed_deletion() | ||
SIGNAL_HANDLER | ||
|
||
if(active) | ||
stop() | ||
return | ||
if(merged) | ||
unmerge_with_weeds() | ||
return | ||
|
||
/** | ||
* Try to start the process to turn into weeds | ||
* Returns TRUE if started successfully | ||
*/ | ||
/datum/component/weed_food/proc/start() | ||
if(active) | ||
return FALSE | ||
if(merged) | ||
return FALSE | ||
if(QDELETED(parent_mob)) | ||
return FALSE | ||
|
||
if(parent_mob.buckled) | ||
if(parent_mob.buckled == parent_buckle) | ||
return FALSE // Still buckled to the same thing | ||
if(!istype(parent_mob.buckled, /obj/structure/bed/nest)) | ||
if(parent_buckle) // Still have a lingering reference somehow? | ||
UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) | ||
parent_buckle = parent_mob.buckled | ||
RegisterSignal(parent_mob.buckled, COSMIG_OBJ_AFTER_BUCKLE, PROC_REF(on_after_buckle)) | ||
return FALSE | ||
if(parent_buckle) | ||
UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) | ||
parent_buckle = null | ||
|
||
if(parent_mob.is_xeno_grabbable()) | ||
return FALSE | ||
if(!(parent_mob.status_flags & PERMANENTLY_DEAD)) | ||
var/mob/living/carbon/human/parent_human = parent_mob | ||
if(istype(parent_human) && !parent_human.undefibbable) | ||
return FALSE | ||
if(!parent_turf?.weeds) | ||
return FALSE | ||
|
||
if(unmerged_time == world.time) | ||
return merge_with_weeds() // Weeds upgraded, re-merge now re-using the apperance | ||
QDEL_NULL(weed_appearance) | ||
absorbing_weeds = parent_turf.weeds | ||
RegisterSignal(parent_turf.weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion)) | ||
|
||
active = TRUE | ||
timer_id = addtimer(CALLBACK(src, PROC_REF(merge_with_weeds)), WEED_FOOD_DELAY, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_DELETE_ME|TIMER_OVERRIDE) | ||
|
||
return TRUE | ||
|
||
/** | ||
* Try to stop the process turning into weeds | ||
* Returns TRUE if stopped successfully (was active when called) | ||
*/ | ||
/datum/component/weed_food/proc/stop() | ||
if(!active) | ||
return FALSE | ||
|
||
active = FALSE | ||
deltimer(timer_id) | ||
timer_id = null | ||
|
||
return TRUE | ||
|
||
/** | ||
* Finish becomming one with the weeds | ||
* Returns TRUE if merged successfully | ||
*/ | ||
/datum/component/weed_food/proc/merge_with_weeds() | ||
if(merged) | ||
return FALSE | ||
if(QDELETED(parent_mob)) | ||
return FALSE | ||
|
||
if(absorbing_weeds) // Remove the signal that would call stop | ||
UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) | ||
|
||
if(parent_mob.buckled) | ||
if(parent_mob.buckled == parent_buckle) | ||
return FALSE // Still buckled to the same thing somehow? | ||
if(!istype(parent_mob.buckled, /obj/structure/bed/nest)) | ||
if(parent_buckle) // Still have a lingering reference somehow? | ||
UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) | ||
parent_buckle = parent_mob.buckled | ||
RegisterSignal(parent_mob.buckled, COSMIG_OBJ_AFTER_BUCKLE, PROC_REF(on_after_buckle)) | ||
return FALSE | ||
if(parent_buckle) | ||
UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) | ||
parent_buckle = null | ||
|
||
absorbing_weeds = parent_turf?.weeds | ||
if(!absorbing_weeds) | ||
return FALSE | ||
RegisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion)) | ||
// Technically we could have just left the signal alone, but both because of the posibility of other conditions preventing a merge or weeds somehow changing and on_move didn't catch it, this is less fragile | ||
|
||
active = FALSE | ||
merged = TRUE | ||
|
||
parent_mob.density = FALSE | ||
parent_mob.anchored = TRUE | ||
parent_mob.mouse_opacity = MOUSE_OPACITY_TRANSPARENT | ||
parent_mob.plane = FLOOR_PLANE | ||
parent_mob.remove_from_all_mob_huds() | ||
|
||
if(!weed_appearance) // Make a new sprite if we aren't re-merging | ||
var/is_flipped = parent_mob.transform.b == -1 // Technically we should check if d is 1 too, but corpses can only be rotated 90 or 270 (1/-1 or -1/1) | ||
if(parent_mob.dir & WEST) | ||
is_flipped = !is_flipped // The direction reversed the effect of the flip! | ||
weed_appearance = new(null, is_flipped) | ||
weed_appearance.color = absorbing_weeds.color | ||
// TODO: For non-humans change the icon_state or something here | ||
parent_mob.vis_contents += weed_appearance | ||
|
||
return TRUE | ||
|
||
/** | ||
* Undo the weedening | ||
* Returns TRUE if unmerged successfully (always) | ||
*/ | ||
/datum/component/weed_food/proc/unmerge_with_weeds() | ||
merged = FALSE | ||
unmerged_time = world.time | ||
|
||
if(absorbing_weeds) | ||
UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) | ||
absorbing_weeds = null | ||
|
||
parent_mob.anchored = FALSE | ||
parent_mob.mouse_opacity = MOUSE_OPACITY_ICON | ||
parent_mob.plane = GAME_PLANE | ||
parent_mob.vis_contents -= weed_appearance | ||
|
||
if(!QDELETED(parent_mob)) | ||
parent_mob.add_to_all_mob_huds() | ||
|
||
return TRUE | ||
|
||
#undef WEED_FOOD_DELAY | ||
#undef WEED_FOOD_STATE_DELAY |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.