Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions code/__defines/dcs/signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,21 @@
///from /datum/species/xenochimera/handle_environment_special()
#define COMSIG_XENOCHIMERA_COMPONENT "xenochimera_component"


// Spontaneous vore stuff.
///from /mob/living/stumble_into(mob/living/M)
#define COMSIG_LIVING_STUMBLED_INTO "living_stumbled_into"
///Something has special handling. Don't continue.
#define CANCEL_STUMBLED_INTO (1<<0)
///from /mob/living/handle_fall(var/turf/landing) args: landing, drop_mob)
#define COMSIG_LIVING_FALLING_DOWN "living_falling_down"
//Special handling. Cancel the fall chain.
#define COMSIG_CANCEL_FALL (1<<0)
///from /mob/living/hitby(atom/movable/source, var/speed = THROWFORCE_SPEED_DIVISOR)
#define COMSIG_LIVING_HIT_BY_THROWN_ENTITY "hit_by_thrown_entity"
//Special handling. Cancel the hitby proc.
#define COMSIG_CANCEL_HITBY (1<<0)

//Unittest data update
#ifdef UNIT_TEST
#define COMSIG_UNITTEST_DATA "unittest_send_data"
Expand Down
544 changes: 544 additions & 0 deletions code/datums/components/traits/unlucky.dm

Large diffs are not rendered by default.

93 changes: 93 additions & 0 deletions code/datums/components/turfslip.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/datum/component/turfslip
var/mob/living/owner
var/slip_dist = TURFSLIP_WET
var/dirtslip = FALSE

/datum/component/turfslip/Initialize()
if (!isliving(parent))
return COMPONENT_INCOMPATIBLE
owner = parent
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(move_react))

/datum/component/turfslip/proc/start_slip(var/turf/simulated/start, var/is_dirt)
var/slip_stun = 6
var/floor_type = "wet"
var/already_slipping = (slip_dist > 1)

// Handle dirt slipping
dirtslip = is_dirt
if(dirtslip)
slip_stun = 10
if(start.dirt > 50)
floor_type = "dirty"
else if(start.is_outdoors())
floor_type = "uneven"

// Proper sliding behavior
switch(start.wet)
if(TURFSLIP_LUBE)
floor_type = "slippery"
slip_dist = 99 //Skill issue.
slip_stun = 10
dirtslip = FALSE
if(TURFSLIP_ICE)
floor_type = "icy"
slip_stun = 4
slip_dist = rand(1,3)
dirtslip = FALSE

// Only start the slip timer if we are not already sliding
if(!already_slipping)
owner.slip("the [floor_type] floor", slip_stun)
addtimer(CALLBACK(src, PROC_REF(next_slip)), 1)

/datum/component/turfslip/proc/move_react(atom/source, atom/oldloc, direction, forced, list/old_locs, momentum_change)
SIGNAL_HANDLER

// Can the mob slip?
if(QDELETED(owner) || isbelly(owner.loc))
qdel(src)
return

// Can the turf be slipped on?
var/turf/simulated/ground = get_turf(owner)
if(!ground || !ground.check_slipping(owner,dirtslip))
qdel(src)
return

addtimer(CALLBACK(src, PROC_REF(next_slip)), 1)

/datum/component/turfslip/proc/next_slip()
// check tile for next slip
owner.is_slipping = TRUE
if(!step(owner, owner.dir) || dirtslip) // done sliding, failed to move, dirt also only slips once
qdel(src)
return
// Kill the slip if it's over
if(!--slip_dist)
qdel(src)
return

/datum/component/turfslip/Destroy(force = FALSE)
UnregisterSignal(owner, COMSIG_MOVABLE_MOVED)
owner.inertia_dir = 0
owner.is_slipping = FALSE
owner = null
slip_dist = 0
. = ..()


////////////////////////////////////////////////////////////////////////////////////////
// Helper proc
////////////////////////////////////////////////////////////////////////////////////////
/turf/proc/check_slipping(var/mob/living/M)
return FALSE

/turf/simulated/check_slipping(var/mob/living/M,var/dirtslip)
if(M.buckled)
return FALSE
if(!wet && !(dirtslip && (dirt > 50 || is_outdoors() == OUTDOORS_YES)))
return FALSE
if(wet == TURFSLIP_WET && M.m_intent == I_WALK)
return FALSE
return TRUE
193 changes: 193 additions & 0 deletions code/datums/elements/vore/spontaneous_vore.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/datum/element/spontaneous_vore

/datum/element/spontaneous_vore/Attach(datum/target)
. = ..()
if(!isliving(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_LIVING_STUMBLED_INTO, PROC_REF(handle_stumble))
RegisterSignal(target, COMSIG_LIVING_FALLING_DOWN, PROC_REF(handle_fall))
RegisterSignal(target, COMSIG_LIVING_HIT_BY_THROWN_ENTITY, PROC_REF(handle_hitby))
RegisterSignal(target, COMSIG_MOVABLE_CROSS, PROC_REF(handle_crossed))

/datum/element/spontaneous_vore/Detach(datum/target)
. = ..()
UnregisterSignal(target, list(COMSIG_LIVING_STUMBLED_INTO, COMSIG_LIVING_FALLING_DOWN, COMSIG_LIVING_HIT_BY_THROWN_ENTITY, COMSIG_MOVABLE_CROSS))

///Source is the one being bumped into (Owner of this component)
///Target is the one bumping into us.
/datum/element/spontaneous_vore/proc/handle_stumble(mob/living/source, mob/living/target)
SIGNAL_HANDLER

//snowflake protean code to prevent protean blobform from eating their human form and humanform from eating their protean blob...gross.
//We are trying to eat our blobform
if(istype(target, /mob/living/simple_mob/protean_blob))
var/mob/living/simple_mob/protean_blob/PB = target
if(PB.humanform == source)
return
//Our blobform is trying to eat us
if(istype(source, /mob/living/simple_mob/protean_blob))
var/mob/living/simple_mob/protean_blob/PB = source
if(PB.humanform == target)
return

//We are able to eat the person stumbling into us.
if(CanStumbleVore(prey = target, pred = source)) //This is if the person stumbling into us is able to eat us!
source.visible_message(span_vwarning("[target] flops carelessly into [source]!"))
source.begin_instant_nom(source, prey = target, pred = source, belly = source.vore_selected)
target.stop_flying()
return CANCEL_STUMBLED_INTO

//The person stumbling into us is able to eat us.
if(CanStumbleVore(prey = source, pred = target)) //This is if the person stumbling into us is able to be eaten by us! BROKEN!
source.visible_message(span_vwarning("[target] flops carelessly into [source]!"))
target.forceMove(get_turf(source))
source.begin_instant_nom(target, prey = source, pred = target, belly = target.vore_selected)
source.stop_flying()
return CANCEL_STUMBLED_INTO

//Source is the one dropping (us)
//Landing is the tile we're falling onto
//drop_mob is whatever mob is found in the turf we're dropping onto.
/datum/element/spontaneous_vore/proc/handle_fall(mob/living/source, turf/landing, mob/living/drop_mob)
SIGNAL_HANDLER

if(!drop_mob || drop_mob == source)
return

//pred = drop_mob
//prey = source
//result: source is eaten by drop_mob
if(CanDropVore(prey = source, pred = drop_mob))
drop_mob.feed_grabbed_to_self_falling_nom(drop_mob, prey = source)
drop_mob.visible_message(span_vdanger("\The [drop_mob] falls right onto \the [source]!"))
return COMSIG_CANCEL_FALL

//pred = source
//prey = drop_mob
//result: drop_mob is eaten by source
if(CanDropVore(prey = drop_mob, pred = source))
source.feed_grabbed_to_self_falling_nom(source, prey = drop_mob)
source.Weaken(4)
source.visible_message(span_vdanger("\The [drop_mob] falls right into \the [source]!"))
return COMSIG_CANCEL_FALL

/datum/element/spontaneous_vore/proc/handle_hitby(mob/living/source, atom/movable/hitby, speed)
SIGNAL_HANDLER

//Handle object throw vore
if(isitem(hitby))
var/obj/item/O = hitby
if(source.stat != DEAD && source.trash_catching && source.vore_selected)
if(source.adminbus_trash || is_type_in_list(O, GLOB.edible_trash) && O.trash_eatable && !is_type_in_list(O, GLOB.item_vore_blacklist))
source.visible_message(span_vwarning("[O] is thrown directly into [source]'s [lowertext(source.vore_selected.name)]!"))
O.throwing = 0
O.forceMove(source.vore_selected)
return COMSIG_CANCEL_HITBY

//Throwing a prey into a pred takes priority. After that it checks to see if the person being thrown is a pred.
if(isliving(hitby))
var/mob/living/thrown_mob = hitby

//If we don't allow mobvore and the thrown mob is an NPC animal, stop here.
if(!source.allowmobvore && isanimal(thrown_mob) && !thrown_mob.ckey)
return

//If we're an NPC animal and the person thrown into us doesn't allow mobvore, stop here.
if(!thrown_mob.allowmobvore && isanimal(source) && !source.ckey)
return

// PERSON BEING HIT: CAN BE DROP PRED, ALLOWS THROW VORE.
// PERSON BEING THROWN: DEVOURABLE, ALLOWS THROW VORE, CAN BE DROP PREY.
if(CanThrowVore(prey = thrown_mob, pred = source))
if(!source.vore_selected)
return
source.vore_selected.nom_mob(thrown_mob) //Eat them!!!
source.visible_message(span_vwarning("[thrown_mob] is thrown right into [source]'s [lowertext(source.vore_selected.name)]!"))
if(thrown_mob.loc != source.vore_selected)
thrown_mob.forceMove(source.vore_selected) //Double check. Should never happen but...Weirder things have happened!
source.on_throw_vore_special(TRUE, thrown_mob)
add_attack_logs(thrown_mob.thrower,source,"Devoured [thrown_mob.name] via throw vore.")
return //We can stop here. We don't need to calculate damage or anything else. They're eaten.

// PERSON BEING HIT: CAN BE DROP PREY, ALLOWS THROW VORE, AND IS DEVOURABLE.
// PERSON BEING THROWN: CAN BE DROP PRED, ALLOWS THROW VORE.
else if(CanThrowVore(prey = source, pred = thrown_mob))//Pred thrown into prey.
if(!thrown_mob.vore_selected)
return
source.visible_message(span_vwarning("[source] suddenly slips inside of [thrown_mob]'s [lowertext(thrown_mob.vore_selected.name)] as [thrown_mob] flies into them!"))
thrown_mob.vore_selected.nom_mob(source) //Eat them!!!
if(source.loc != thrown_mob.vore_selected)
source.forceMove(thrown_mob.vore_selected) //Double check. Should never happen but...Weirder things have happened!
add_attack_logs(thrown_mob.LAssailant,source,"Was Devoured by [thrown_mob.name] via throw vore.")
return

//source = person standing up
//crossed = person sliding
/datum/element/spontaneous_vore/proc/handle_crossed(mob/living/source, mob/living/crossed)
SIGNAL_HANDLER

if(source == crossed || !istype(crossed))
return

//Person being slipped into eats the person slipping
if(can_slip_vore(pred = source, prey = crossed)) //If we can vore them go for it
source.begin_instant_nom(source, prey = crossed, pred = source, belly = source.vore_selected)
return COMPONENT_BLOCK_CROSS

//The person slipping eats the person being slipped into
else if(can_slip_vore(pred = crossed, prey = source))
source.begin_instant_nom(crossed, prey = source, pred = crossed, belly = crossed.vore_selected) //Must be
return //We DON'T block it here. Pred can slip onto the prey's tile, no problem.


///Helper Procs
/proc/CanStumbleVore(mob/living/prey, mob/living/pred)
if(!can_spontaneous_vore(pred, prey))
return FALSE
if(!prey.stumble_vore || !pred.stumble_vore)
return FALSE
return TRUE

/proc/CanDropVore(mob/living/prey, mob/living/pred)
if(!can_spontaneous_vore(pred, prey))
return FALSE
if(!pred.drop_vore || !prey.drop_vore)
return FALSE
return TRUE

/proc/CanThrowVore(mob/living/prey, mob/living/pred)
if(!can_spontaneous_vore(pred, prey))
return FALSE
if(!pred.throw_vore || !prey.throw_vore)
return FALSE
return TRUE

/proc/can_slip_vore(mob/living/pred, mob/living/prey)
if(!can_spontaneous_vore(pred, prey))
return FALSE
if(!prey.is_slipping && !pred.is_slipping) //Obviously they have to be slipping to get slip vored
return FALSE
if(world.time <= prey.slip_protect)
return FALSE
if(!pred.slip_vore || !prey.slip_vore)
return FALSE
return TRUE

///This is a general 'do we have the mechanical ability to do any type of spontaneous vore' without specialties.
/proc/can_spontaneous_vore(mob/living/pred, mob/living/prey)
if(!istype(pred) || !istype(prey))
return FALSE
//Unfortunately, can_be_drop_prey is 'spontanous prey' var and can_be_drop_pred is 'spontaneous pred' var...horribly named imo.
if(!prey.can_be_drop_prey || !pred.can_be_drop_pred)
return FALSE
if(prey.is_incorporeal() || pred.is_incorporeal())
return FALSE
if(!prey.devourable)
return FALSE
if(!is_vore_predator(pred)) //Check their bellies and stuff
return FALSE
if(!pred.vore_selected) //Gotta have one selected as well.
return FALSE
if(!prey.allowmobvore && isanimal(pred) && !pred.ckey || (!pred.allowmobvore && isanimal(prey) && !prey.ckey))
return FALSE
return TRUE
4 changes: 2 additions & 2 deletions code/game/objects/buckling.dm
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@

if(has_buckled_mobs() && buckled_mobs.len >= max_buckled_mobs)
for(var/mob/living/L in buckled_mobs)
if(istype(L) && M.CanStumbleVore(L))
if(istype(L) && CanStumbleVore(prey = L, pred = M))
unbuckle_mob(L, TRUE)
if(M == user)
M.visible_message(span_warning("[M.name] sits down on [L.name]!"))
Expand Down Expand Up @@ -215,7 +215,7 @@
if(has_buckled_mobs() && buckled_mobs.len >= max_buckled_mobs) //Handles trying to buckle yourself to the chair when someone is on it
if(can_do_spont_vore && is_vore_predator(M) && M.vore_selected)
for(var/mob/living/buckled in buckled_mobs)
if(M.CanStumbleVore(buckled))
if(CanStumbleVore(prey = buckled, pred = M))
return TRUE
to_chat(M, span_notice("\The [src] can't buckle any more people."))
return FALSE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -659,19 +659,6 @@
return 1
return 0

//Don't eat yourself, idiot
/mob/living/simple_mob/protean_blob/CanStumbleVore(mob/living/target)
if(target == humanform)
return FALSE
return ..()

/mob/living/carbon/human/CanStumbleVore(mob/living/target)
if(istype(target, /mob/living/simple_mob/protean_blob))
var/mob/living/simple_mob/protean_blob/PB = target
if(PB.humanform == src)
return FALSE
return ..()

/mob/living/simple_mob/protean_blob/handle_mutations_and_radiation()
if(!humanform)
to_chat(src, span_giant(span_boldwarning("You are currently a blob without a humanform and should be deleted shortly Please report what you were doing when this error occurred to the admins.")))
Expand Down
14 changes: 14 additions & 0 deletions code/modules/mob/living/living.dm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@

selected_image = image(icon = GLOB.buildmode_hud, loc = src, icon_state = "ai_sel")

<<<<<<< HEAD
=======
AddElement(/datum/element/spontaneous_vore)

/mob/living/proc/get_visible_name()
var/datum/component/shadekin/SK = get_shadekin_component()
if(SK && SK.in_phase)
return "Something"
if(real_name)
return real_name
else
return name

>>>>>>> 11a4471110 ([MIRROR] Spontaneous Vore Element (#11785))
/mob/living/Destroy()
SSradiation.listeners -= src
remove_all_modifiers(TRUE)
Expand Down
Loading
Loading