mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 18:02:57 +00:00
Ashdrake noms (#2868)
* Initial commit * probably a better way to check this * It compiled boys. Let's see if it works. * IT WAS ALL NULLS, BOYS * Hooray, it's not broken anymore boys! * Well it works, but we need transfer IDs to work locating them post-initialize would help, probably. Then assigning their links soon after. * Bellies linked, autotransfer, LoseTarget * half-thought sanity check needs to go away * A few last minute tweaks.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#define DM_DIGEST "Digest"
|
||||
#define DM_HEAL "Heal"
|
||||
#define DM_NOISY "Noisy"
|
||||
#define DM_DRAGON "Dragon"
|
||||
|
||||
#define VORE_STRUGGLE_EMOTE_CHANCE 40
|
||||
|
||||
|
||||
@@ -228,6 +228,9 @@
|
||||
if(!target || !CanAttack(target))
|
||||
LoseTarget()
|
||||
return 0
|
||||
if(isturf(target.loc))
|
||||
LoseTarget()
|
||||
return 0
|
||||
if(target in possible_targets)
|
||||
if(target.z != z)
|
||||
LoseTarget()
|
||||
|
||||
@@ -60,6 +60,7 @@ Difficulty: Medium
|
||||
score_type = DRAKE_SCORE
|
||||
deathmessage = "collapses into a pile of bones, its flesh sloughing away."
|
||||
death_sound = 'sound/magic/demon_dies.ogg'
|
||||
no_vore = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon
|
||||
vore_active = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/Initialize()
|
||||
// Create and register 'stomachs'
|
||||
var/datum/belly/megafauna/dragon/maw/maw = new(src)
|
||||
var/datum/belly/megafauna/dragon/gullet/gullet = new(src)
|
||||
var/datum/belly/megafauna/dragon/gut/gut = new(src)
|
||||
for(var/datum/belly/X in list(maw, gullet, gut))
|
||||
vore_organs[X.name] = X
|
||||
// Connect 'stomachs' together
|
||||
maw.transferlocation = gullet
|
||||
gullet.transferlocation = gut
|
||||
vore_selected = maw.name // NPC eats into maw
|
||||
return ..()
|
||||
|
||||
/datum/belly/megafauna/dragon
|
||||
human_prey_swallow_time = 50 // maybe enough to switch targets if distracted
|
||||
nonhuman_prey_swallow_time = 50
|
||||
|
||||
/datum/belly/megafauna/dragon/maw
|
||||
name = "maw"
|
||||
inside_flavor = "The maw of the dreaded Ash drake closes around you, engulfing you into a swelteringly hot, disgusting enviroment. The acidic saliva tingles over your form while that tongue pushes you further back...towards the dark gullet beyond."
|
||||
vore_verb = "scoop"
|
||||
vore_sound = 'sound/vore/pred/taurswallow.ogg'
|
||||
swallow_time = 20
|
||||
escapechance = 25
|
||||
// From above, will transfer into gullet
|
||||
transferchance = 25
|
||||
autotransferchance = 66
|
||||
autotransferwait = 200
|
||||
|
||||
/datum/belly/megafauna/dragon/gullet
|
||||
name = "gullet"
|
||||
inside_flavor = "A ripple of muscle and arching of the tongue pushes you down like any other food. No choice in the matter, you're simply consumed. The dark ambiance of the outside world is replaced with working, wet flesh. Your only light being what you brought with you."
|
||||
swallow_time = 60 // costs extra time to eat directly to here
|
||||
escapechance = 5
|
||||
// From above, will transfer into gut
|
||||
transferchance = 25
|
||||
autotransferchance = 50
|
||||
autotransferwait = 200
|
||||
|
||||
/datum/belly/megafauna/dragon/gut
|
||||
name = "stomach"
|
||||
vore_capacity = 5 //I doubt this many people will actually last in the gut, but...
|
||||
inside_flavor = "With a rush of burning ichor greeting you, you're introduced to the Drake's stomach. Wrinkled walls greedily grind against you, acidic slimes working into your body as you become fuel and nutriton for a superior predator. All that's left is your body's willingness to resist your destiny."
|
||||
digest_mode = DM_DRAGON
|
||||
digest_burn = 5
|
||||
swallow_time = 100 // costs extra time to eat directly to here
|
||||
escapechance = 0
|
||||
@@ -89,11 +89,15 @@
|
||||
. = ..()
|
||||
if(. && isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat >= SOFT_CRIT)
|
||||
if(vore_active == TRUE && L.devourable == TRUE)
|
||||
dragon_feeding(src,L)
|
||||
else if(L.stat == DEAD)
|
||||
devour(L)
|
||||
else
|
||||
if(L.stat != DEAD)
|
||||
if(!client && ranged && ranged_cooldown <= world.time)
|
||||
OpenFire()
|
||||
else
|
||||
devour(L)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/devour(mob/living/L)
|
||||
if(!L)
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
devourable = FALSE //insurance because who knows.
|
||||
var/vore_active = FALSE // If vore behavior is enabled for this mob
|
||||
|
||||
var/vore_capacity = 1 // The capacity (in people) this person can hold
|
||||
var/vore_default_mode = DM_DIGEST // Default bellymode (DM_DIGEST, DM_HOLD, DM_ABSORB)
|
||||
var/vore_digest_chance = 25 // Chance to switch to digest mode if resisted
|
||||
var/vore_absorb_chance = 0 // Chance to switch to absorb mode if resisted
|
||||
var/vore_escape_chance = 25 // Chance of resisting out of mob
|
||||
|
||||
var/vore_stomach_name // The name for the first belly if not "stomach"
|
||||
var/vore_stomach_flavor // The flavortext for the first belly if not the default
|
||||
|
||||
var/vore_fullness = 0 // How "full" the belly is (controls icons)
|
||||
|
||||
|
||||
// Release belly contents beforey being gc'd!
|
||||
/mob/living/simple_animal/Destroy()
|
||||
@@ -22,6 +22,37 @@
|
||||
prey_excludes.Cut()
|
||||
. = ..()
|
||||
|
||||
|
||||
// Update fullness based on size & quantity of belly contents
|
||||
/mob/living/simple_animal/proc/update_fullness(var/atom/movable/M)
|
||||
var/new_fullness = 0
|
||||
for(var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
if (!(M in B.internal_contents))
|
||||
return FALSE // Nothing's inside
|
||||
new_fullness += M
|
||||
|
||||
vore_fullness = new_fullness
|
||||
|
||||
|
||||
/mob/living/simple_animal/proc/swallow_check()
|
||||
for(var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
if(vore_active)
|
||||
update_fullness()
|
||||
if(!vore_fullness)
|
||||
// Nothing
|
||||
return
|
||||
else
|
||||
addtimer(CALLBACK(src, .proc/swallow_mob), B.swallow_time)
|
||||
|
||||
/mob/living/simple_animal/proc/swallow_mob()
|
||||
for(var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
for(var/mob/living/M in B.internal_contents)
|
||||
B.transfer_contents(M, B.transferlocation)
|
||||
|
||||
|
||||
/mob/living/simple_animal/death()
|
||||
for(var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
@@ -69,4 +100,3 @@
|
||||
"The stomach glorps and gurgles as it tries to work you into slop.")
|
||||
src.vore_organs[B.name] = B
|
||||
src.vore_selected = B.name
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
var/vore_verb = "ingest" // Verb for eating with this in messages
|
||||
var/human_prey_swallow_time = 10 SECONDS // Time in deciseconds to swallow /mob/living/carbon/human
|
||||
var/nonhuman_prey_swallow_time = 5 SECONDS // Time in deciseconds to swallow anything else
|
||||
var/emoteTime = 300 // How long between stomach emotes at prey
|
||||
var/emoteTime = 30 SECONDS // How long between stomach emotes at prey
|
||||
var/digest_brute = 0 // Brute damage per tick in digestion mode
|
||||
var/digest_burn = 1 // Burn damage per tick in digestion mode
|
||||
var/digest_tickrate = 9 // Modulus this of air controller tick number to iterate gurgles on
|
||||
@@ -25,15 +25,21 @@
|
||||
var/digestchance = 0 // % Chance of stomach beginning to digest if prey struggles
|
||||
// var/silenced = FALSE // Will the heartbeat/fleshy internal loop play?
|
||||
var/escapechance = 0 // % Chance of prey beginning to escape if prey struggles.
|
||||
var/transferchance = 0 // % Chance of prey being
|
||||
var/can_taste = FALSE // If this belly prints the flavor of prey when it eats someone.
|
||||
|
||||
var/datum/belly/transferlocation = null // Location that the prey is released if they struggle and get dropped off.
|
||||
var/transferchance = 0 // % Chance of prey being transferred to transfer location when resisting
|
||||
var/autotransferchance = 0 // % Chance of prey being autotransferred to transfer location
|
||||
var/autotransferwait = 10 // Time between trying to transfer.
|
||||
var/can_taste = FALSE // If this belly prints the flavor of prey when it eats someone.
|
||||
|
||||
var/tmp/digest_mode = DM_HOLD // Whether or not to digest. Default to not digest.
|
||||
var/tmp/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_HEAL,DM_NOISY) // Possible digest modes
|
||||
var/tmp/mob/living/owner // The mob whose belly this is.
|
||||
var/tmp/list/internal_contents = list() // People/Things you've eaten into this belly!
|
||||
var/tmp/is_full // Flag for if digested remeans are present. (for disposal messages)
|
||||
var/tmp/emotePend = FALSE // If there's already a spawned thing counting for the next emote
|
||||
var/swallow_time = 10 SECONDS // for mob transfering automation
|
||||
var/vore_capacity = 1 // The capacity (in people) this person can hold
|
||||
|
||||
// Don't forget to watch your commas at the end of each line if you change these.
|
||||
var/list/struggle_messages_outside = list(
|
||||
@@ -153,8 +159,41 @@
|
||||
// if(B.silenced == FALSE) //this needs more testing later
|
||||
prey << sound('sound/vore/prey/loop.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_PREYLOOP)
|
||||
|
||||
// Handle prey messages
|
||||
if(inside_flavor)
|
||||
to_chat(prey, "<span class='warning'><B>[src.inside_flavor]</B></span>")
|
||||
if(isliving(prey))
|
||||
var/mob/living/M = prey
|
||||
if(can_taste && M.get_taste_message(0))
|
||||
to_chat(owner, "<span class='notice'>[M] tastes of [M.get_taste_message(0)].</span>")
|
||||
|
||||
// Setup the autotransfer checks if needed
|
||||
if(transferlocation && autotransferchance > 0)
|
||||
addtimer(CALLBACK(src, /datum/belly/.proc/check_autotransfer, prey), autotransferwait)
|
||||
|
||||
/datum/belly/proc/check_autotransfer(var/mob/prey)
|
||||
// Some sanity checks
|
||||
if(transferlocation && (autotransferchance > 0) && (prey in internal_contents))
|
||||
if(prob(autotransferchance))
|
||||
// Double check transferlocation isn't insane
|
||||
if(verify_transferlocation())
|
||||
transfer_contents(prey, transferlocation)
|
||||
else
|
||||
// Didn't transfer, so wait before retrying
|
||||
addtimer(CALLBACK(src, /datum/belly/.proc/check_autotransfer, prey), autotransferwait)
|
||||
|
||||
/datum/belly/proc/verify_transferlocation()
|
||||
for(var/I in owner.vore_organs)
|
||||
var/datum/belly/B = owner.vore_organs[I]
|
||||
if(B == transferlocation)
|
||||
return TRUE
|
||||
|
||||
for(var/I in owner.vore_organs)
|
||||
var/datum/belly/B = owner.vore_organs[I]
|
||||
if(B.name == transferlocation.name)
|
||||
transferlocation = B
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Get the line that should show up in Examine message if the owner of this belly
|
||||
// is examined. By making this a proc, we not only take advantage of polymorphism,
|
||||
@@ -323,23 +362,9 @@
|
||||
return
|
||||
|
||||
else if(prob(transferchance) && istype(transferlocation)) //Next, let's have it see if they end up getting into an even bigger mess then when they started.
|
||||
var/location_found = FALSE
|
||||
var/name_found = FALSE
|
||||
for(var/I in owner.vore_organs)
|
||||
var/datum/belly/B = owner.vore_organs[I]
|
||||
if(B == transferlocation)
|
||||
location_found = TRUE
|
||||
break
|
||||
var/location_ok = verify_transferlocation()
|
||||
|
||||
if(!location_found)
|
||||
for(var/I in owner.vore_organs)
|
||||
var/datum/belly/B = owner.vore_organs[I]
|
||||
if(B.name == transferlocation.name)
|
||||
name_found = TRUE
|
||||
transferlocation = B
|
||||
break
|
||||
|
||||
if(!location_found && !name_found)
|
||||
if(!location_ok)
|
||||
to_chat(owner, "<span class='warning'>Something went wrong with your belly transfer settings.</span>")
|
||||
transferlocation = null
|
||||
return
|
||||
@@ -358,18 +383,14 @@
|
||||
to_chat(R, "<span class='warning'>But make no progress in escaping [owner]'s [name].</span>")
|
||||
to_chat(owner, "<span class='warning'>But appears to be unable to make any progress in escaping your [name].</span>")
|
||||
return
|
||||
|
||||
//Transfers contents from one belly to another
|
||||
/datum/belly/proc/transfer_contents(var/atom/movable/content, var/datum/belly/target, silent = 0)
|
||||
if(!(content in internal_contents))
|
||||
return
|
||||
internal_contents.Remove(content)
|
||||
target.internal_contents.Add(content)
|
||||
if(isliving(content))
|
||||
var/mob/living/M = content
|
||||
if(target.inside_flavor)
|
||||
to_chat(M, "<span class='notice'><B>[target.inside_flavor]</B></span>")
|
||||
if(target.can_taste && M.get_taste_message(0))
|
||||
to_chat(owner, "<span class='notice'>[M] tastes of [M.get_taste_message(0)].</span>")
|
||||
// Re-use nom_mob
|
||||
target.nom_mob(content, target.owner)
|
||||
if(!silent)
|
||||
for(var/mob/hearer in range(1,owner))
|
||||
hearer << sound(target.vore_sound,volume=80)
|
||||
@@ -398,6 +419,8 @@
|
||||
dupe.escapechance = escapechance
|
||||
dupe.transferchance = transferchance
|
||||
dupe.transferlocation = transferlocation
|
||||
dupe.autotransferchance = autotransferchance
|
||||
dupe.autotransferwait = autotransferwait
|
||||
|
||||
//// Object-holding variables
|
||||
//struggle_messages_outside - strings
|
||||
|
||||
@@ -91,3 +91,53 @@
|
||||
playsound(get_turf(owner),"digest_pred",35,0,-6,0,channel=CHANNEL_PRED)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local(get_turf(M), null, 45, S = prey_gurgle)
|
||||
|
||||
|
||||
//////////////////////////DM_DRAGON /////////////////////////////////////
|
||||
//because dragons need snowflake guts
|
||||
if(digest_mode == DM_DRAGON)
|
||||
for (var/mob/living/M in internal_contents)
|
||||
if(prob(25))
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(owner),"digest_pred",50,0,-6,0,channel=CHANNEL_PRED)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local(get_turf(M), null, 45, S = prey_gurgle)
|
||||
|
||||
//No digestion protection for megafauna.
|
||||
|
||||
//Person just died in guts!
|
||||
if(M.stat == DEAD)
|
||||
var/digest_alert_owner = pick(digest_messages_owner)
|
||||
var/digest_alert_prey = pick(digest_messages_prey)
|
||||
|
||||
//Replace placeholder vars
|
||||
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
|
||||
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
|
||||
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
|
||||
|
||||
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
|
||||
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
|
||||
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
|
||||
|
||||
//Send messages
|
||||
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
|
||||
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
|
||||
M.visible_message("<span class='notice'>You watch as [owner]'s guts loudly rumble as it finishes off a meal.</span>")
|
||||
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(owner),"death_pred",45,0,-6,0,channel=CHANNEL_PRED)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local(get_turf(M), null, 45, S = prey_digest)
|
||||
M.spill_organs(FALSE,TRUE,TRUE)
|
||||
M << sound(null, repeat = 0, wait = 0, volume = 80, channel = CHANNEL_PREYLOOP)
|
||||
digestion_death(M)
|
||||
owner.update_icons()
|
||||
continue
|
||||
|
||||
|
||||
// Deal digestion damage (and feed the pred)
|
||||
if(!(M.status_flags & GODMODE))
|
||||
M.adjustFireLoss(digest_burn)
|
||||
M.adjustToxLoss(4) // something something plasma based acids
|
||||
M.adjustCloneLoss(3) // eventually this'll kill you if you're healing everything else, you nerds.
|
||||
return
|
||||
@@ -121,6 +121,42 @@
|
||||
var/belly = input("Choose Belly") in pred.vore_organs
|
||||
return perform_the_nom(user, prey, pred, belly)
|
||||
|
||||
//Dragon noms need to be faster
|
||||
/mob/living/proc/dragon_feeding(var/mob/living/user, var/mob/living/prey)
|
||||
var/belly = user.vore_selected
|
||||
return perform_dragon(user, prey, user, belly)
|
||||
|
||||
/mob/living/proc/perform_dragon(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/belly, swallow_time = 20)
|
||||
//Sanity
|
||||
if(!user || !prey || !pred || !belly || !(belly in pred.vore_organs))
|
||||
return
|
||||
|
||||
// The belly selected at the time of noms
|
||||
var/datum/belly/belly_target = pred.vore_organs[belly]
|
||||
var/attempt_msg = "ERROR: Vore message couldn't be created. Notify a dev. (at)"
|
||||
var/success_msg = "ERROR: Vore message couldn't be created. Notify a dev. (sc)"
|
||||
|
||||
// Prepare messages
|
||||
if(user == pred) //Feeding someone to yourself
|
||||
attempt_msg = text("<span class='warning'>[] starts to [] [] into their []!</span>",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
success_msg = text("<span class='warning'>[] manages to [] [] into their []!</span>",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
|
||||
// Announce that we start the attempt!
|
||||
user.visible_message(attempt_msg)
|
||||
|
||||
if(!do_mob(src, user, swallow_time)) // one second should be good enough, right?
|
||||
return FALSE // Prey escaped (or user disabled) before timer expired.
|
||||
|
||||
// If we got this far, nom successful! Announce it!
|
||||
user.visible_message(success_msg)
|
||||
playsound(user, belly_target.vore_sound, 100, 1)
|
||||
|
||||
// Actually shove prey into the belly.
|
||||
belly_target.nom_mob(prey, user)
|
||||
if (pred == user)
|
||||
message_admins("[key_name(pred)] ate [key_name(prey)].")
|
||||
log_attack("[key_name(pred)] ate [key_name(prey)]")
|
||||
return TRUE
|
||||
//
|
||||
// Master vore proc that actually does vore procedures
|
||||
//
|
||||
@@ -250,6 +286,7 @@
|
||||
if(M.loc != src)
|
||||
B.internal_contents.Remove(M)
|
||||
|
||||
|
||||
// OOC Escape code for pref-breaking or AFK preds
|
||||
//
|
||||
/mob/living/proc/escapeOOC()
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
//
|
||||
/datum/vore_look
|
||||
var/datum/belly/selected
|
||||
var/show_interacts = FALSE
|
||||
var/show_interacts = TRUE
|
||||
var/datum/browser/popup
|
||||
var/loop = null; // Magic self-reference to stop the handler from being GC'd before user takes action.
|
||||
|
||||
|
||||
@@ -1823,6 +1823,7 @@
|
||||
#include "code\modules\mob\living\simple_animal\hostile\megafauna\bubblegum.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\megafauna\colossus.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\megafauna\dragon.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\megafauna\dragon_vore.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\megafauna\hierophant.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\megafauna\legion.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\megafauna\megafauna.dm"
|
||||
|
||||
Reference in New Issue
Block a user