Files
nevimer baf3837ae8 Merge remote-tracking branch 'tgstation/master' into upstream-2025-11-29
# Conflicts:
#	_maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm
#	_maps/RandomRuins/SpaceRuins/garbagetruck2.dmm
#	_maps/map_files/CatwalkStation/CatwalkStation_2023.dmm
#	_maps/map_files/tramstation/tramstation.dmm
#	code/_onclick/hud/new_player.dm
#	code/datums/components/squashable.dm
#	code/datums/diseases/advance/symptoms/heal.dm
#	code/datums/diseases/chronic_illness.dm
#	code/datums/status_effects/buffs.dm
#	code/datums/status_effects/debuffs/drunk.dm
#	code/datums/status_effects/debuffs/stamcrit.dm
#	code/game/machinery/computer/crew.dm
#	code/game/objects/items/devices/scanners/health_analyzer.dm
#	code/game/objects/items/wall_mounted.dm
#	code/game/turfs/closed/indestructible.dm
#	code/modules/admin/view_variables/filterrific.dm
#	code/modules/antagonists/heretic/influences.dm
#	code/modules/cargo/orderconsole.dm
#	code/modules/client/preferences.dm
#	code/modules/events/space_vines/vine_mutations.dm
#	code/modules/mob/dead/new_player/new_player.dm
#	code/modules/mob/living/carbon/human/death.dm
#	code/modules/mob/living/carbon/human/species_types/jellypeople.dm
#	code/modules/mob/living/damage_procs.dm
#	code/modules/mob/living/living.dm
#	code/modules/mob_spawn/ghost_roles/mining_roles.dm
#	code/modules/mob_spawn/mob_spawn.dm
#	code/modules/projectiles/ammunition/energy/laser.dm
#	code/modules/projectiles/guns/ballistic/launchers.dm
#	code/modules/projectiles/guns/energy/laser.dm
#	code/modules/reagents/chemistry/machinery/chem_dispenser.dm
#	code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm
#	code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm
#	code/modules/reagents/chemistry/reagents/medicine_reagents.dm
#	code/modules/surgery/healing.dm
#	code/modules/unit_tests/designs.dm
#	icons/mob/inhands/items_lefthand.dmi
#	icons/mob/inhands/items_righthand.dmi
#	tgui/packages/tgui/interfaces/ChemDispenser.tsx
2025-11-29 22:49:21 -05:00

198 lines
6.5 KiB
Plaintext

GLOBAL_LIST_INIT(digest_modes, init_digest_modes())
/proc/init_digest_modes()
var/list/digest_modes = list()
for(var/datum/digest_mode/digest_mode as anything in subtypesof(/datum/digest_mode))
var/datum/digest_mode/DM = new digest_mode()
digest_modes[DM.name] = DM
return digest_modes
/datum/digest_mode
var/name = ""
var/gurgle_noises = FALSE
/datum/digest_mode/proc/handle_belly(obj/vore_belly/vore_belly, seconds_per_tick)
if(gurgle_noises)
vore_belly.try_play_gurgle_sound()
/datum/digest_mode/safe
name = DIGEST_MODE_SAFE
gurgle_noises = FALSE
/datum/digest_mode/digest
name = DIGEST_MODE_DIGEST
gurgle_noises = TRUE
/mob/living/proc/vore_can_negatively_affect()
if(REQUIRES_PLAYER)
return FALSE
if(mind)
// they were at some point a player, we don't digest them until they get back
return FALSE
// Animal, melt em
return TRUE
/mob/living/proc/vore_can_digest()
if(client)
var/datum/vore_preferences/vore_prefs = client.get_vore_prefs()
return vore_prefs?.read_preference(/datum/vore_pref/toggle/digestion)
return vore_can_negatively_affect()
/mob/living/proc/vore_can_qdel()
if(client)
var/datum/vore_preferences/vore_prefs = client.get_vore_prefs()
return vore_prefs?.read_preference(/datum/vore_pref/toggle/digestion_qdel)
return vore_can_negatively_affect()
/obj/machinery/cryopod/quiet/vore
name = "vore cryopod"
/obj/machinery/cryopod/quiet/vore/process()
return
/obj/machinery/cryopod/quiet/vore/find_control_computer(urgent)
return
GLOBAL_DATUM_INIT(vore_cryopod, /obj/machinery/cryopod/quiet/vore, new /obj/machinery/cryopod/quiet/vore(null))
// This is hilariously cursed
/proc/remove_player_from_round_safely(mob/living/L)
// Immediately kick them out of their body so they don't get ghosted in nullspace
L.ghostize(FALSE)
// Have to do this before we let the cryopod have them, or it'll throw all their items into nullspace without qdeling them
for(var/obj/item/item_content as anything in L)
if(!istype(item_content) || HAS_TRAIT(item_content, TRAIT_NODROP))
continue
if(issilicon(L) && istype(item_content, /obj/item/mmi))
continue
qdel(item_content)
GLOB.vore_cryopod.close_machine(L)
L = null // make sure we're not keeping a ref
GLOB.vore_cryopod.despawn_occupant()
/obj/vore_belly/proc/digestion_death(mob/living/L)
if(!L.vore_can_qdel())
return FALSE
var/mob/living/living_parent = owner.parent
if(fancy_sounds)
play_vore_sound_preypred("vore_sounds_death_fancy_prey", "vore_sounds_death_fancy", pref = /datum/vore_pref/toggle/digestion_noises)
else
play_vore_sound_preypred("vore_sounds_death_classic", "vore_sounds_death_classic", pref = /datum/vore_pref/toggle/digestion_noises)
living_parent.adjust_nutrition(NUTRITION_PER_KILL)
to_chat(living_parent, span_notice(get_digest_messages_pred(L)))
to_chat(L, span_notice(get_digest_messages_prey(L)))
living_parent.log_message("digested and qdel'd [key_name(L)].", LOG_ATTACK)
L.log_message("was digested and qdel'd by [key_name(living_parent)].", LOG_VICTIM)
remove_player_from_round_safely(L)
return TRUE
/datum/digest_mode/digest/handle_belly(obj/vore_belly/vore_belly, seconds_per_tick)
var/mob/living/living_parent = vore_belly.owner.parent
for(var/mob/living/L in vore_belly)
if(!L.vore_can_digest())
continue
if(L.stat == DEAD)
if(L.vore_can_qdel())
vore_belly.digestion_death(L)
continue
if(vore_belly.brute_damage > 0)
L.adjust_brute_loss(vore_belly.brute_damage * seconds_per_tick)
living_parent.adjust_nutrition(NUTRITION_PER_DAMAGE * vore_belly.brute_damage * seconds_per_tick)
if(vore_belly.burn_damage > 0)
L.adjust_fire_loss(vore_belly.burn_damage * seconds_per_tick)
living_parent.adjust_nutrition(NUTRITION_PER_DAMAGE * vore_belly.burn_damage * seconds_per_tick)
/datum/digest_mode/absorb
name = DIGEST_MODE_ABSORB
gurgle_noises = TRUE
/mob/living/proc/vore_can_absorb()
if(client)
var/datum/vore_preferences/vore_prefs = client.get_vore_prefs()
return vore_prefs?.read_preference(/datum/vore_pref/toggle/absorb)
// Arguably, absorption is completely reversable and therefore harmless
// and this could just return TRUE
// But in case there's a player that logs out and really really doesn't like absorption...
return vore_can_negatively_affect()
/obj/vore_belly/proc/absorb(mob/living/L)
if(!L.vore_can_absorb())
return FALSE
// Already absorbed
if(HAS_TRAIT_FROM(L, TRAIT_RESTRAINED, TRAIT_SOURCE_VORE))
return FALSE
var/mob/living/living_parent = owner.parent
// Add full restraints
ADD_TRAIT(L, TRAIT_RESTRAINED, TRAIT_SOURCE_VORE)
ADD_TRAIT(L, TRAIT_STASIS, TRAIT_SOURCE_VORE)
to_chat(living_parent, span_notice(get_absorb_messages_owner(L)))
to_chat(L, span_notice(get_absorb_messages_prey(L)))
return TRUE
/datum/digest_mode/absorb/handle_belly(obj/vore_belly/vore_belly, seconds_per_tick)
var/mob/living/living_parent = vore_belly.owner.parent
for(var/mob/living/L in vore_belly)
if(!L.vore_can_absorb())
continue
if(HAS_TRAIT_FROM(L, TRAIT_RESTRAINED, TRAIT_SOURCE_VORE))
continue
if(L.nutrition < ABSORB_NUTRITION_BARRIER)
vore_belly.absorb(L)
continue
// Times 2 because we assume a baseline of 2 "damage" in absorb mode
var/nutrition_transfer = NUTRITION_PER_DAMAGE * 2 * seconds_per_tick
L.adjust_nutrition(-nutrition_transfer)
living_parent.adjust_nutrition(nutrition_transfer)
/datum/digest_mode/unabsorb
name = DIGEST_MODE_UNABSORB
gurgle_noises = TRUE
/obj/vore_belly/proc/unabsorb(mob/living/L)
// Not absorbed
if(!HAS_TRAIT_FROM(L, TRAIT_RESTRAINED, TRAIT_SOURCE_VORE))
return FALSE
var/mob/living/living_parent = owner.parent
// Remove full restraints
REMOVE_TRAIT(L, TRAIT_RESTRAINED, TRAIT_SOURCE_VORE)
REMOVE_TRAIT(L, TRAIT_STASIS, TRAIT_SOURCE_VORE)
to_chat(living_parent, span_notice(get_unabsorb_messages_owner(L)))
to_chat(L, span_notice(get_unabsorb_messages_prey(L)))
// Unabsorbs kick them back out
var/datum/component/absorb_control/AC = living_parent.GetComponent(/datum/component/absorb_control)
if(AC && AC.controller == L)
AC.revert()
return TRUE
/datum/digest_mode/unabsorb/handle_belly(obj/vore_belly/vore_belly, seconds_per_tick)
var/mob/living/living_parent = vore_belly.owner.parent
for(var/mob/living/L in vore_belly)
if(!HAS_TRAIT_FROM(L, TRAIT_RESTRAINED, TRAIT_SOURCE_VORE))
continue
// Parent can only reform if they have ABSORB_NUTRITION_BARRIER worth of nutrition
// Note that this nutrition is deliberately lost and not given back to the prey
if(living_parent.nutrition > ABSORB_NUTRITION_BARRIER)
living_parent.adjust_nutrition(-ABSORB_NUTRITION_BARRIER)
vore_belly.unabsorb(L)