mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-05-17 20:30:46 +01:00
202 lines
8.9 KiB
Plaintext
202 lines
8.9 KiB
Plaintext
//Vore procs! Can be delayed or instant.
|
|
//If delayed, the chain is: perform_the_nom -> begin_delayed_nom -> vore_sanity_checks -> attempt_to_devour_prey -> devour_and_move_prey
|
|
//If instant, the chain is: perform_the_nom -> begin_instant_nom -> vore_sanity_checks -> devour_and_move_prey
|
|
|
|
|
|
|
|
/**
|
|
* Vore proc that actually does the main part of eating
|
|
* Written to be compatible with instant or delayed noms. Alternatively, call begin_instant_nom if the vore is going to be instant.
|
|
* Params: user, prey, pred, belly, delay_time
|
|
*/
|
|
/mob/living/proc/perform_the_nom(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly, delay_time)
|
|
if(!delay_time || delay_time > 0)
|
|
return begin_delayed_nom(user, prey, pred, belly, delay_time)
|
|
else //This is here to catch when delay_time is set to a negative number, aka, 'we want this to be instant.' Any uses of this should be replaced by begin_instant_nom
|
|
return begin_instant_nom(user, prey, pred, belly)
|
|
|
|
/**
|
|
* Vore proc that actually does the main part of eating
|
|
* Params: user, prey, pred, belly, delay_time
|
|
*/
|
|
/proc/begin_delayed_nom(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly, delay_time)
|
|
if(vore_sanity_checks(user, prey, pred, belly))
|
|
return attempt_to_devour_prey(user, prey, pred, belly, delay_time)
|
|
else
|
|
return FALSE
|
|
|
|
/**
|
|
* Vore proc that actually tries to instantly eat the preey
|
|
* Params: user, prey, pred, belly
|
|
* NOTE: THIS MUST NOT SLEEP, THIS IS CALLED BY THINGS THAT USE SIGNAL_HANDLER
|
|
*/
|
|
/mob/living/proc/begin_instant_nom(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
if(vore_sanity_checks(user, prey, pred, belly))
|
|
return devour_and_move_prey(user, prey, pred, belly)
|
|
else
|
|
return FALSE //We failed
|
|
|
|
/proc/attempt_to_devour_prey(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly, delay_time)
|
|
var/message_range = get_vore_message_range(user, pred, prey, belly)
|
|
var/attempt_msg = generate_vore_attempt_message(user, prey, pred, belly)
|
|
// Announce that we start the attempt!
|
|
user.visible_message(attempt_msg, range = message_range)
|
|
// Now give the prey time to escape... return if they did
|
|
var/swallow_time
|
|
if(delay_time < 0) //Shouldn't happen, but let's just be sane..
|
|
swallow_time = 0
|
|
else if(delay_time)
|
|
swallow_time = delay_time
|
|
else
|
|
swallow_time = ishuman(prey) ? belly.human_prey_swallow_time : belly.nonhuman_prey_swallow_time
|
|
|
|
// Their AI should get notified so they can stab us
|
|
prey.ai_holder?.react_to_attack(user)
|
|
|
|
//Timer and progress bar
|
|
if(!user.client && prey.weakened > 0) // stop crwaling instantly break swallow attempt for mobvore
|
|
prey.Stun(min(prey.weakened, 2)) // stop crawling instantly break swallow attempt for mobvore
|
|
if(!do_after(user, swallow_time, target = prey, hidden = TRUE))
|
|
return FALSE // Prey escaped (or user disabled) before timer expired.
|
|
|
|
// If we got this far, nom successful! Announce it and move the prey!
|
|
return devour_and_move_prey(user, prey, pred, belly, message_range)
|
|
|
|
/proc/devour_and_move_prey(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly, message_range)
|
|
var/success_msg = generate_vore_success_message(user, prey, pred, belly)
|
|
if(!message_range)
|
|
message_range = get_vore_message_range(user, pred, prey, belly)
|
|
user.visible_message(success_msg, range = message_range)
|
|
// Actually shove prey into the belly.
|
|
if(istype(prey.loc, /obj/item/holder))
|
|
var/obj/item/holder/H = prey.loc
|
|
for(var/mob/living/M in H.contents)
|
|
belly.nom_atom(M, user)
|
|
if(M.loc == H) // In case nom_atom failed somehow.
|
|
M.forceMove(get_turf(user))
|
|
H.held_mob = null
|
|
qdel(H)
|
|
else
|
|
belly.nom_atom(prey, user)
|
|
|
|
user.update_icon()
|
|
|
|
var/mob/living/carbon/victim = prey // Check for afk vore
|
|
if(istype(victim) && !victim.client && !victim.ai_holder && victim.ckey)
|
|
log_and_message_admins("ate [key_name_admin(prey)] whilst the prey was AFK ([pred ? ADMIN_JMP(pred) : "null"])", pred)
|
|
var/mob/living/carbon/victim_pred = pred // Check for afk vore
|
|
if(istype(victim_pred) && !victim_pred.client && !victim_pred.ai_holder && victim_pred.ckey)
|
|
log_and_message_admins("ate [key_name_admin(prey)] whilst the pred was AFK ([pred ? ADMIN_JMP(pred) : "null"])", pred)
|
|
|
|
// Inform Admins
|
|
if(pred == user)
|
|
add_attack_logs(pred, prey, "Eaten via [belly.name]")
|
|
else
|
|
add_attack_logs(user, pred, "Forced to eat [key_name(prey)]")
|
|
return TRUE
|
|
|
|
///VORE HELPER PROCS UNDER HERE
|
|
|
|
/**
|
|
* Vore helper proc that creates the vore success message we'll be using
|
|
* Params: user, prey, pred, belly, delay_time
|
|
* Returns: success_msg
|
|
*/
|
|
/proc/generate_vore_success_message(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly)
|
|
//Determining vore attempt privacy
|
|
var/success_msg = "ERROR: Vore message couldn't be created. Notify a dev. (sc)"
|
|
|
|
if(prey.is_slipping)
|
|
success_msg = span_vwarning("[prey] suddenly slides into [pred]'s [lowertext(belly.name)]!")
|
|
else if(pred.is_slipping)
|
|
success_msg = span_vwarning("[prey] suddenly slips inside of [pred]'s [lowertext(belly.name)] as [pred] slides into them!")
|
|
else if(user == pred) //Feeding someone to yourself
|
|
success_msg = span_vwarning("[pred] manages to [lowertext(belly.vore_verb)] [prey] into their [lowertext(belly.name)]!")
|
|
else //Feeding someone to another person
|
|
success_msg = span_vwarning("[user] manages to make [pred] [lowertext(belly.vore_verb)] [prey] into their [lowertext(belly.name)]!")
|
|
return success_msg
|
|
|
|
/**
|
|
* Vore proc helper that creates the vore attempt message we'll be using
|
|
* Params: user, prey, pred, belly, delay_time
|
|
* Returns: attempt_msg
|
|
*/
|
|
/proc/generate_vore_attempt_message(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly)
|
|
//Determining vore attempt privacy
|
|
var/attempt_msg = "ERROR: Vore message couldn't be created. Notify a dev. (sc)"
|
|
|
|
if(prey.is_slipping)
|
|
attempt_msg = span_vwarning("It seems like [prey] is about to slide into [pred]'s [lowertext(belly.name)]!")
|
|
else if(pred.is_slipping)
|
|
attempt_msg = span_vwarning("It seems like [prey] is gonna end up inside [pred]'s [lowertext(belly.name)] as [pred] comes sliding over!")
|
|
else if(user == pred) //Feeding someone to yourself
|
|
attempt_msg = span_vwarning("[pred] is attempting to [lowertext(belly.vore_verb)] [prey] into their [lowertext(belly.name)]!")
|
|
else //Feeding someone to another person
|
|
attempt_msg = span_vwarning("[user] is attempting to make [pred] [lowertext(belly.vore_verb)] [prey] into their [lowertext(belly.name)]!")
|
|
return attempt_msg
|
|
|
|
/**
|
|
* Vore proc helper that finds what range our message should be
|
|
* Params: user, prey, pred, belly, delay_time
|
|
* Returns: attempt_msg
|
|
*/
|
|
/proc/get_vore_message_range(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly)
|
|
var/message_range = world.view
|
|
if(!pred.is_slipping && !prey.is_slipping) //We only care about privacy preference if it's NOT a spontaneous vore.
|
|
switch(belly.eating_privacy_local) //if("loud") case not added, as it would not modify message_range
|
|
if("default")
|
|
if(pred.eating_privacy_global)
|
|
message_range = 1
|
|
if("subtle")
|
|
message_range = 1
|
|
return message_range
|
|
|
|
/**
|
|
* Vore proc helper that sees if we can actually do the vore attempt
|
|
* Params: user, prey, pred, belly
|
|
* Returns: TRUE/FALSE
|
|
* FALSE: Can not eat.
|
|
* TRUE: Can eat.
|
|
*/
|
|
/proc/vore_sanity_checks(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly)
|
|
//Sanity
|
|
if(!user || !prey || !pred || !istype(belly) || !(belly in pred.vore_organs))
|
|
log_vore("[user] attempted to feed [prey] to [pred], via [belly ? lowertext(belly.name) : "*null*"] but it went wrong.")
|
|
return FALSE
|
|
if(pred == prey)
|
|
return FALSE
|
|
|
|
//Final distance check. Time has passed, menus have come and gone. Can't use do_after adjacent because doesn't behave for held micros
|
|
var/user_to_pred = get_dist(get_turf(user),get_turf(pred))
|
|
var/user_to_prey = get_dist(get_turf(user),get_turf(prey))
|
|
|
|
if(user == pred && isAI(user))
|
|
var/mob/living/silicon/ai/AI = user
|
|
if(AI.holo && AI.holo.masters[AI])
|
|
user_to_prey = get_dist(get_turf(AI.holo.masters[AI]), get_turf(prey))
|
|
|
|
if(user_to_pred > 1 || user_to_prey > 1)
|
|
return FALSE
|
|
|
|
if(!prey.devourable)
|
|
to_chat(user, span_vnotice("They aren't able to be devoured."))
|
|
log_and_message_admins("attempted to devour [key_name_admin(prey)] against their prefs ([prey ? ADMIN_JMP(prey) : "null"])", user)
|
|
return FALSE
|
|
if(prey.absorbed || pred.absorbed)
|
|
to_chat(user, span_vwarning("They aren't aren't in a state to be devoured."))
|
|
return FALSE
|
|
if(!pred.can_be_afk_pred && (!pred.client || pred.away_from_keyboard))
|
|
if(user == pred)
|
|
to_chat(user, span_vwarning("You aren't set as being able to pred while AFK"))
|
|
return FALSE
|
|
to_chat(user, span_vnotice("The predator prefers not to be fed while AFK"))
|
|
return FALSE
|
|
if(!prey.is_dead() && !prey.can_be_afk_prey && (!prey.client || prey.away_from_keyboard))
|
|
if(user == prey)
|
|
to_chat(user, span_vwarning("You aren't set as being able to prey while AFK"))
|
|
return FALSE
|
|
to_chat(user, span_vnotice("The prey prefers not to be eaten while AFK"))
|
|
return FALSE
|
|
return TRUE
|