mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-13 03:02:38 +00:00
## About The Pull Request A ground-up rewrite of Vore 3.0 (Virgo's current system) as a /datum/component. Resolves #464 Resolves #845 Remaining work: - [ ] Fix any bugs found in testing ## Why It's Good For The Game See bounty. People want this to enjoy themselves. ## Proof Of Testing            ## Changelog 🆑 add: Mechanical Vore /🆑 <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Be sure to properly mark your PRs to prevent unnecessary GBP loss. You can read up on GBP and it's effects on PRs in the tgstation guides for contributors. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> <!-- 🆑 add: Added new mechanics or gameplay changes add: Added more things del: Removed old things qol: made something easier to use balance: rebalanced something fix: fixed a few things sound: added/modified/removed audio or sound effects image: added/modified/removed some icons or images spellcheck: fixed a few typos code: changed some code refactor: refactored some code config: changed some config setting admin: messed with admin stuff server: something server ops should know /🆑 --> <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. --> <!-- By opening a pull request. You have read and understood the repository rules located on the main README.md on this project. --> --------- Co-authored-by: The Sharkening <95130227+StrangeWeirdKitten@users.noreply.github.com>
201 lines
6.5 KiB
Plaintext
201 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
|
|
// No player, no deal
|
|
return FALSE
|
|
#else
|
|
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
|
|
#endif
|
|
|
|
/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.adjustBruteLoss(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.adjustFireLoss(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)
|