From 11a4471110d8a54b31376f527da85b3133751b03 Mon Sep 17 00:00:00 2001 From: CHOMPStation2StaffMirrorBot <94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com> Date: Mon, 6 Oct 2025 14:17:26 -0700 Subject: [PATCH] [MIRROR] Spontaneous Vore Element (#11785) Co-authored-by: Cameron Lennox --- code/__defines/dcs/signals.dm | 15 ++ code/datums/components/traits/unlucky.dm | 2 +- code/datums/components/turfslip.dm | 2 + code/datums/elements/vore/spontaneous_vore.dm | 193 ++++++++++++++++++ code/game/objects/buckling.dm | 4 +- .../species/station/protean/protean_blob.dm | 13 -- code/modules/mob/living/living.dm | 2 + code/modules/mob/living/living_defense.dm | 39 +--- code/modules/mob/living/living_movement.dm | 88 ++++---- code/modules/multiz/movement_vr.dm | 87 +++----- code/modules/vore/eating/mob_vr.dm | 10 +- code/modules/vore/eating/slipvore_vr.dm | 67 ------ code/modules/vore/eating/stumblevore_vr.dm | 52 ++--- vorestation.dme | 1 + 14 files changed, 310 insertions(+), 265 deletions(-) create mode 100644 code/datums/elements/vore/spontaneous_vore.dm diff --git a/code/__defines/dcs/signals.dm b/code/__defines/dcs/signals.dm index 8fb61f2dd9..71b4524ad5 100644 --- a/code/__defines/dcs/signals.dm +++ b/code/__defines/dcs/signals.dm @@ -968,6 +968,21 @@ // Hose Connector Component #define COMSIG_HOSE_FORCEPUMP "hose_force_pump" + +// 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_TESTS #define COMSIG_UNITTEST_DATA "unittest_send_data" diff --git a/code/datums/components/traits/unlucky.dm b/code/datums/components/traits/unlucky.dm index 28ba800060..10316314da 100644 --- a/code/datums/components/traits/unlucky.dm +++ b/code/datums/components/traits/unlucky.dm @@ -165,7 +165,7 @@ continue //Don't do anything to ourselves. if(living_mob.stat) continue - if(!living_mob.CanStumbleVore(living_guy) && !living_guy.CanStumbleVore(living_mob)) //Works both ways! Either way, someone's getting eaten! + if(!CanStumbleVore(living_guy, living_mob) && !CanStumbleVore(living_mob, living_guy)) //Works both ways! Either way, someone's getting eaten! continue living_mob.stumble_into(living_guy) //logic reversed here because the game is DUMB. This means that living_guy is stumbling into the target! living_guy.visible_message(span_danger("[living_guy] loses their balance and slips into [living_mob]!"), span_boldwarning("You lose your balance, slipping into [living_mob]!")) diff --git a/code/datums/components/turfslip.dm b/code/datums/components/turfslip.dm index 88e3aa675c..b55b03dad7 100644 --- a/code/datums/components/turfslip.dm +++ b/code/datums/components/turfslip.dm @@ -59,6 +59,7 @@ /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 @@ -70,6 +71,7 @@ /datum/component/turfslip/Destroy(force = FALSE) UnregisterSignal(owner, COMSIG_MOVABLE_MOVED) owner.inertia_dir = 0 + owner.is_slipping = FALSE owner = null slip_dist = 0 . = ..() diff --git a/code/datums/elements/vore/spontaneous_vore.dm b/code/datums/elements/vore/spontaneous_vore.dm new file mode 100644 index 0000000000..629ccb5962 --- /dev/null +++ b/code/datums/elements/vore/spontaneous_vore.dm @@ -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 diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index c0bb4713f2..6853929a5a 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -129,7 +129,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]!")) @@ -218,7 +218,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 diff --git a/code/modules/mob/living/carbon/human/species/station/protean/protean_blob.dm b/code/modules/mob/living/carbon/human/species/station/protean/protean_blob.dm index 3534a28c32..e1564ee35d 100644 --- a/code/modules/mob/living/carbon/human/species/station/protean/protean_blob.dm +++ b/code/modules/mob/living/carbon/human/species/station/protean/protean_blob.dm @@ -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."))) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index c48d84bfac..a12fee4d75 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -18,6 +18,8 @@ selected_image = image(icon = GLOB.buildmode_hud, loc = src, icon_state = "ai_sel") + AddElement(/datum/element/spontaneous_vore) + /mob/living/proc/get_visible_name() var/datum/component/shadekin/SK = get_shadekin_component() if(SK && SK.in_phase) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 57f9106cb6..d303c7d71f 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -272,14 +272,10 @@ /mob/living/hitby(atom/movable/source, var/speed = THROWFORCE_SPEED_DIVISOR)//Standardization and logging -Sieve if(is_incorporeal()) return + if(SEND_SIGNAL(src, COMSIG_LIVING_HIT_BY_THROWN_ENTITY, source, speed) & COMSIG_CANCEL_HITBY) + return if(isitem(source)) var/obj/item/O = source - if(stat != DEAD && trash_catching && vore_selected) - if(adminbus_trash || is_type_in_list(O, GLOB.edible_trash) && O.trash_eatable && !is_type_in_list(O, GLOB.item_vore_blacklist)) - visible_message(span_vwarning("[O] is thrown directly into [src]'s [lowertext(vore_selected.name)]!")) - O.throwing = 0 - O.forceMove(vore_selected) - return var/dtype = O.damtype var/throw_damage = O.throwforce*(speed/THROWFORCE_SPEED_DIVISOR) @@ -336,37 +332,6 @@ src.anchored = TRUE src.pinned += O - //VORESTATION EDIT START - Allows for thrown vore! //CHOMPEdit Start - //Throwing a prey into a pred takes priority. After that it checks to see if the person being thrown is a pred. - if(isliving(source)) - var/mob/living/thrown_mob = source - - // PERSON BEING HIT: CAN BE DROP PRED, ALLOWS THROW VORE. - // PERSON BEING THROWN: DEVOURABLE, ALLOWS THROW VORE, CAN BE DROP PREY. - if((can_be_drop_pred && throw_vore) && (thrown_mob.devourable && thrown_mob.throw_vore && thrown_mob.can_be_drop_prey)) //Prey thrown into pred. - if(!thrown_mob.allowmobvore && isanimal(src) && !ckey || !vore_selected) //Does the person being thrown not allow mob vore and is the person being hit (us) a simple_mob? - return - vore_selected.nom_mob(thrown_mob) //Eat them!!! - visible_message(span_vwarning("[thrown_mob] is thrown right into [src]'s [lowertext(vore_selected.name)]!")) - if(thrown_mob.loc != vore_selected) - thrown_mob.forceMove(vore_selected) //Double check. Should never happen but...Weirder things have happened! - on_throw_vore_special(TRUE, thrown_mob) - add_attack_logs(thrown_mob.thrower,src,"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((can_be_drop_prey && throw_vore && devourable) && (thrown_mob.can_be_drop_pred && thrown_mob.throw_vore)) //Pred thrown into prey. - if(!allowmobvore && isanimal(thrown_mob) && !thrown_mob.ckey || !thrown_mob.vore_selected) //Does the person being hit not allow mob vore and the perrson being thrown a simple_mob? - return - visible_message(span_vwarning("[src] 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(src) //Eat them!!! - if(src.loc != thrown_mob.vore_selected) - src.forceMove(thrown_mob.vore_selected) //Double check. Should never happen but...Weirder things have happened! - add_attack_logs(thrown_mob.LAssailant,src,"Was Devoured by [thrown_mob.name] via throw vore.") - return - //VORESTATION EDIT END - Allows for thrown vore! //CHOMPEdit End - /mob/living/proc/on_throw_vore_special(var/pred = TRUE, var/mob/living/target) return diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index 10b1d3ea0e..0e63125f8d 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -24,33 +24,33 @@ return ..() // Parent call should make the mob move. /*one proc, four uses -swapping: if it's 1, the mobs are trying to switch, if 0, non-passive is pushing passive +swapping: if it's TRUE, the mobs are trying to switch, if FALSE, non-passive is pushing passive default behaviour is: - non-passive mob passes the passive version - passive mob checks to see if its mob_bump_flag is in the non-passive's mob_bump_flags - if si, the proc returns */ -/mob/living/proc/can_move_mob(var/mob/living/swapped, swapping = 0, passive = 0) +/mob/living/proc/can_move_mob(var/mob/living/swapped, swapping = FALSE, passive = FALSE) if(!swapped) - return 1 + return TRUE if(!passive) - return swapped.can_move_mob(src, swapping, 1) + return swapped.can_move_mob(src, swapping, TRUE) else - var/context_flags = 0 + var/context_flags = FALSE if(swapping) context_flags = swapped.mob_swap_flags else context_flags = swapped.mob_push_flags if(!mob_bump_flag) //nothing defined, go wild - return 1 + return TRUE if(mob_bump_flag & context_flags) - return 1 - return 0 + return TRUE + return FALSE /mob/living/Bump(atom/movable/AM) if(now_pushing || !loc || buckled == AM || AM.is_incorporeal()) return - now_pushing = 1 + now_pushing = TRUE if (isliving(AM)) var/mob/living/tmob = AM @@ -58,94 +58,92 @@ default behaviour is: spreadFire(tmob) for(var/mob/living/M in range(tmob, 1)) - if(tmob.pinned.len || ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/grab, tmob.grabbed_by.len)) ) + if(tmob.pinned.len || ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == CONSCIOUS)) || locate(/obj/item/grab, tmob.grabbed_by.len)) ) if ( !(world.time % 5) ) to_chat(src, span_warning("[tmob] is restrained, you cannot push past")) - now_pushing = 0 + now_pushing = FALSE return - if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) ) + if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == CONSCIOUS) ) if ( !(world.time % 5) ) to_chat(src, span_warning("[tmob] is restraining [M], you cannot push past")) - now_pushing = 0 + now_pushing = FALSE return //BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller - var/can_swap = 1 + var/can_swap = TRUE if(loc.density || tmob.loc.density) - can_swap = 0 + can_swap = FALSE if(can_swap) for(var/atom/movable/A in loc) if(A == src) continue if(!A.CanPass(tmob, loc)) - can_swap = 0 + can_swap = FALSE if(!can_swap) break if(can_swap) for(var/atom/movable/A in tmob.loc) if(A == tmob) continue if(!A.CanPass(src, tmob.loc)) - can_swap = 0 + can_swap = FALSE if(!can_swap) break //Leaping mobs just land on the tile, no pushing, no anything. if(status_flags & LEAPING) loc = tmob.loc status_flags &= ~LEAPING - now_pushing = 0 + now_pushing = FALSE return if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !tmob.buckled && !buckled && can_swap && can_move_mob(tmob, 1, 0)) // mutual brohugs all around! var/turf/oldloc = loc - //VOREstation Edit - Begin //check bumpnom chance, if it's a simplemob that's doing the bumping var/mob/living/simple_mob/srcsimp = src if(istype(srcsimp)) if(srcsimp.tryBumpNom(tmob)) - now_pushing = 0 + now_pushing = FALSE return //if it's a simplemob being bumped, and the above didn't make them start getting bumpnommed, they get a chance to bumpnom var/mob/living/simple_mob/tmobsimp = tmob if(istype(tmobsimp)) if(tmobsimp.tryBumpNom(src)) - now_pushing = 0 + now_pushing = FALSE return - //VOREstation Edit - End forceMove(tmob.loc) //CHOMPSTATION Edit - Making macro/micro step mechanics mandatory again for balance, but removing the fetish aspects if pref denied. //There's nothing fetishistic about politely stepping past someone. // In case of micros, we don't swap positions; instead occupying the same square! if(handle_micro_bump_helping(tmob)) - now_pushing = 0 + now_pushing = FALSE return // TODO - Check if we need to do something about the slime.UpdateFeed() we are skipping below. // CHOMPSTATION Edit - End tmob.forceMove(oldloc) - now_pushing = 0 + now_pushing = FALSE return else if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && canmove && can_swap && handle_micro_bump_helping(tmob)) forceMove(tmob.loc) - now_pushing = 0 + now_pushing = FALSE return - if(!can_move_mob(tmob, 0, 0)) - now_pushing = 0 + if(!can_move_mob(tmob, FALSE, FALSE)) + now_pushing = FALSE return if(a_intent == I_HELP || src.restrained()) - now_pushing = 0 + now_pushing = FALSE return // Plow that nerd. if(ishuman(tmob)) var/mob/living/carbon/human/H = tmob - if(H.species.lightweight == 1 && prob(50)) + if(H.species.lightweight == TRUE && prob(50)) if(HULK in H.mutations) //No knocking over the hulk return H.visible_message(span_warning("[src] bumps into [H], knocking them off balance!")) H.Weaken(5) - now_pushing = 0 + now_pushing = FALSE return //CHOMPSTATION edit Adding alternative to lightweight if(H.species.lightweight_light == 1 && H.a_intent == I_HELP) @@ -163,55 +161,45 @@ default behaviour is: if(ishuman(tmob) && (FAT in tmob.mutations)) if(prob(40) && !(FAT in src.mutations)) to_chat(src, span_danger("You fail to push [tmob]'s fat ass out of the way.")) - now_pushing = 0 + now_pushing = FALSE return if(tmob.r_hand && istype(tmob.r_hand, /obj/item/shield/riot)) if(prob(99)) - now_pushing = 0 + now_pushing = FALSE return if(tmob.l_hand && istype(tmob.l_hand, /obj/item/shield/riot)) if(prob(99)) - now_pushing = 0 + now_pushing = FALSE return if(!(tmob.status_flags & CANPUSH)) - now_pushing = 0 + now_pushing = FALSE return tmob.LAssailant = src - now_pushing = 0 + now_pushing = FALSE . = ..() if (!istype(AM, /atom/movable) || AM.anchored) - //VOREStation Edit - object-specific proc for running into things if(((confused || is_blind()) && stat == CONSCIOUS && prob(50) && m_intent==I_RUN) || flying) AM.stumble_into(src) - //VOREStation Edit End - /* VOREStation Removal - See above - if(confused && prob(50) && m_intent==I_RUN) - Weaken(2) - playsound(src, "punch", 25, 1, -1) - visible_message(span_warning("[src] [pick("ran", "slammed")] into \the [AM]!")) - src.apply_damage(5, BRUTE) - to_chat(src, span_warning("You just [pick("ran", "slammed")] into \the [AM]!")) - */ // VOREStation Removal End return if (!now_pushing) if(isobj(AM)) var/obj/I = AM if(!can_pull_size || can_pull_size < I.w_class) return - now_pushing = 1 + now_pushing = TRUE var/t = get_dir(src, AM) if (istype(AM, /obj/structure/window)) for(var/obj/structure/window/win in get_step(AM,t)) - now_pushing = 0 + now_pushing = FALSE return var/turf/T = AM.loc var/turf/T2 = get_step(AM,t) if(!T2) // Map edge - now_pushing = 0 + now_pushing = FALSE return var/move_time = movement_delay(loc, t) move_time = DS2NEARESTTICK(move_time) @@ -220,9 +208,9 @@ default behaviour is: if(ishuman(AM) && AM:grabbed_by) for(var/obj/item/grab/G in AM:grabbed_by) - step(G:assailant, get_dir(G:assailant, AM)) + step(G.assailant, get_dir(G.assailant, AM)) G.adjust_position() - now_pushing = 0 + now_pushing = FALSE /mob/living/CanPass(atom/movable/mover, turf/target) if(istype(mover, /obj/structure/blob) && faction == "blob") //Blobs should ignore things on their faction. diff --git a/code/modules/multiz/movement_vr.dm b/code/modules/multiz/movement_vr.dm index d220eef751..002d770ea2 100644 --- a/code/modules/multiz/movement_vr.dm +++ b/code/modules/multiz/movement_vr.dm @@ -1,78 +1,57 @@ /mob/living/handle_fall(var/turf/landing) - var/mob/drop_mob = locate(/mob/living, landing) + var/mob/living/drop_mob = locate(/mob/living, landing) if(locate(/obj/structure/stairs) in landing) for(var/atom/A in landing) - if(!A.CanPass(src, src.loc, 1, 0)) + if(!A.CanPass(src, src.loc)) return FALSE Move(landing) if(isliving(src)) var/mob/living/L = src if(L.pulling) L.pulling.forceMove(landing) - return 1 + return TRUE for(var/obj/O in loc) if(!O.CanFallThru(src, landing)) - return 1 + return TRUE - if(drop_mob && !(drop_mob == src)) //Shitload of checks. This is because the game finds various ways to screw me over. - var/mob/living/drop_living = drop_mob - if(drop_living.dropped_onto(src)) - return + if(SEND_SIGNAL(src, COMSIG_LIVING_FALLING_DOWN, landing, drop_mob) & COMSIG_CANCEL_FALL) + return + + if(drop_mob && drop_mob != src) + ///Varible to tell if we take damage or not for falling. + var/safe_fall = FALSE + if(drop_mob.softfall || (isanimal(drop_mob) && drop_mob.mob_size <= MOB_SMALL)) + safe_fall = TRUE + + if(ishuman(drop_mob)) + var/mob/living/carbon/human/H = drop_mob + if(H.species.soft_landing) + safe_fall = TRUE + + forceMove(get_turf(drop_mob)) + if(!safe_fall) + drop_mob.Weaken(8) + Weaken(8) + playsound(src, "punch", 25, 1, -1) + var/tdamage + for(var/i = 1 to 5) //Twice as less damage because cushioned fall, but both get damaged. + tdamage = rand(0, 5) + drop_mob.adjustBruteLoss(tdamage) + adjustBruteLoss(tdamage) + drop_mob.updatehealth() + updatehealth() + drop_mob.visible_message(span_danger("\The [drop_mob] falls onto \the [src]!")) + else + drop_mob.visible_message(span_notice("\The [drop_mob] safely brushes past \the [src] as they land.")) // Then call parent to have us actually fall return ..() /mob/CheckFall(var/atom/movable/falling_atom) return falling_atom.fall_impact(src) -/mob/living/proc/dropped_onto(var/atom/hit_atom) - if(!isliving(hit_atom)) - return 0 - - var/mob/living/pred = hit_atom - if(pred.is_incorporeal()) - return - var/safe_fall = FALSE - if(pred.softfall || (isanimal(pred) && pred.mob_size <= MOB_SMALL)) // TODO: add ability for mob below to be 'soft' and cushion fall - safe_fall = TRUE - - if(ishuman(pred)) - var/mob/living/carbon/human/H = pred - if(H.species.soft_landing) - safe_fall = TRUE - - var/mob/living/prey = src - var/fallloc = prey.loc - if(pred.vore_selected && pred.can_be_drop_pred && prey.can_be_drop_prey && pred.drop_vore && prey.drop_vore) - pred.feed_grabbed_to_self_falling_nom(pred,prey) - pred.loc = fallloc - if(!safe_fall) - pred.Weaken(8) - pred.visible_message(span_vdanger("\The [pred] falls right onto \the [prey]!")) - else if(prey.vore_selected && prey.can_be_drop_pred && pred.can_be_drop_prey && pred.drop_vore && prey.drop_vore) - prey.feed_grabbed_to_self_falling_nom(prey,pred) - prey.Weaken(4) - prey.visible_message(span_vdanger("\The [pred] falls right into \the [prey]!")) - else - pred.loc = prey.loc - if(!safe_fall) - pred.Weaken(8) - prey.Weaken(8) - playsound(src, "punch", 25, 1, -1) - var/tdamage - for(var/i = 1 to 5) //Twice as less damage because cushioned fall, but both get damaged. - tdamage = rand(0, 5) - pred.adjustBruteLoss(tdamage) - prey.adjustBruteLoss(tdamage) - pred.updatehealth() - prey.updatehealth() - pred.visible_message(span_danger("\The [pred] falls onto \the [prey]!")) - else - pred.visible_message(span_notice("\The [pred] safely brushes past \the [prey] as they land.")) - return 1 - /mob/observer/dead/CheckFall() return diff --git a/code/modules/vore/eating/mob_vr.dm b/code/modules/vore/eating/mob_vr.dm index 6ef18c317c..be5c0bea0e 100644 --- a/code/modules/vore/eating/mob_vr.dm +++ b/code/modules/vore/eating/mob_vr.dm @@ -14,11 +14,11 @@ var/vore_smell = null // What the character smells like var/noisy = FALSE // Toggle audible hunger. var/permit_healbelly = TRUE - var/stumble_vore = TRUE //Enabled by default since you have to enable drop pred/prey to do this anyway - var/slip_vore = TRUE //Enabled by default since you have to enable drop pred/prey to do this anyway - var/drop_vore = TRUE //Enabled by default since you have to enable drop pred/prey to do this anyway - var/throw_vore = TRUE //Enabled by default since you have to enable drop pred/prey to do this anyway - var/food_vore = TRUE //Enabled by default since you have to enable drop pred/prey to do this anyway + var/stumble_vore = TRUE + var/slip_vore = TRUE + var/drop_vore = TRUE + var/throw_vore = TRUE + var/food_vore = TRUE var/consume_liquid_belly = FALSE //starting off because if someone is into that, they'll toggle it first time they get the error. Otherway around would be more pref breaky. var/digest_pain = TRUE var/can_be_drop_prey = FALSE diff --git a/code/modules/vore/eating/slipvore_vr.dm b/code/modules/vore/eating/slipvore_vr.dm index 26557862d6..2e73a815bf 100644 --- a/code/modules/vore/eating/slipvore_vr.dm +++ b/code/modules/vore/eating/slipvore_vr.dm @@ -2,71 +2,4 @@ /mob/living var/is_slipping = FALSE - var/slip_vore_in_progress = FALSE var/slip_protect = 1 - -/mob/living/proc/can_slip_vore(var/mob/living/target) - if(!target.is_slipping) //Obviously they have to be slipping to get slip vored - return FALSE - if(is_incorporeal()) - return FALSE - if(!target.allowmobvore && isanimal(src) && !ckey) - return FALSE - if(world.time <= target.slip_protect) - return FALSE - if(!(src.can_be_drop_pred && target.devourable && target.can_be_drop_prey)) //Make sure both of their prefs align with what we're gonna do. - return FALSE - if(!is_vore_predator(src)) //Check their bellies and stuff - return FALSE - if(!src.vore_selected) //Gotta have one selected as well. - return FALSE - if(!slip_vore || !target.slip_vore) - return FALSE - return TRUE - -/mob/living/proc/can_be_slip_vored_by(var/mob/living/target) - if(!target.is_slipping) //Obviously they have to be slipping to get slip vored - return FALSE - if(is_incorporeal()) - return FALSE - if(!allowmobvore && isanimal(target) && !target.ckey) - return FALSE - if(world.time <= target.slip_protect) - return FALSE - if(!(target.can_be_drop_pred && src.devourable && src.can_be_drop_prey)) //Make sure both of their prefs align with what we're gonna do. - return FALSE - if(!is_vore_predator(target)) //Check their bellies and stuff - return FALSE - if(!target.vore_selected) //Gotta have one selected as well. - return FALSE - if(!slip_vore || !target.slip_vore) - return FALSE - return TRUE - -/mob/living/Crossed(var/atom/movable/AM) - ..() - var/mob/living/target = AM - if(istype(target) && !target.is_incorporeal() && !src.is_incorporeal()) //The slip vore begins - if(can_slip_vore(target) && !src.slip_vore_in_progress && !target.slip_vore_in_progress) //If we can vore them go for it - begin_instant_nom(src,target,src,src.vore_selected) - target.slip_vore_in_progress = FALSE - target.is_slipping = FALSE - return - else if(can_be_slip_vored_by(target) && !src.slip_vore_in_progress && !target.slip_vore_in_progress) //Otherwise, if they can vore us, make it happen. - begin_instant_nom(target,src,target,target.vore_selected) - slip_vore_in_progress = FALSE - is_slipping = FALSE - return - - -/mob/living/carbon/slip(var/slipped_on,stun_duration=8) - . = ..() - if(.) - is_slipping = TRUE - return . - -/mob/living/update_canmove() - . = ..() - if(is_slipping && !lying) - is_slipping = FALSE - return . diff --git a/code/modules/vore/eating/stumblevore_vr.dm b/code/modules/vore/eating/stumblevore_vr.dm index 4c1555902d..1ef0259c40 100644 --- a/code/modules/vore/eating/stumblevore_vr.dm +++ b/code/modules/vore/eating/stumblevore_vr.dm @@ -1,18 +1,3 @@ -/mob/living/proc/CanStumbleVore(mob/living/target) - if(!can_be_drop_pred) - return FALSE - if(is_incorporeal() || target.is_incorporeal()) - return FALSE - if(!is_vore_predator(src)) - return FALSE - if(!target.devourable) - return FALSE - if(!target.can_be_drop_prey) - return FALSE - if(!target.stumble_vore || !stumble_vore) - return FALSE - return TRUE - /mob/living/Bump(atom/movable/AM) //. = ..() if(isliving(AM)) @@ -30,32 +15,27 @@ ..() /mob/living/stumble_into(mob/living/M) - var/mob/living/carbon/human/S = src - if(S.buckled || M.buckled) + if(buckled || M.buckled) return + + //Stumblevore occurs here. Look at the 'stumblevore' element for more information. + if(SEND_SIGNAL(src, COMSIG_LIVING_STUMBLED_INTO, M) & CANCEL_STUMBLED_INTO) + return + playsound(src, "punch", 25, 1, -1) M.Weaken(4) M.stop_flying() - if(CanStumbleVore(M)) //This is if the person stumbling into us is able to eat us! - visible_message(span_vwarning("[M] flops carelessly into [src]!")) - M.forceMove(get_turf(src)) - begin_instant_nom(src,M,src,src.vore_selected) - return - if(M.CanStumbleVore(src)) //This is if the person stumbling into us is able to be eaten by us! BROKEN! - visible_message(span_vwarning("[M] flops carelessly into [src]!")) - M.forceMove(get_turf(src)) - begin_instant_nom(M,src,M,M.vore_selected) - return - - if(istype(S) && S.species.lightweight == 1) - visible_message(span_vwarning("[M] carelessly bowls [src] over!")) - M.forceMove(get_turf(src)) - M.apply_damage(0.5, BRUTE) - Weaken(4) - stop_flying() - apply_damage(0.5, BRUTE) - return + if(ishuman(src)) + var/mob/living/carbon/human/S = src + if(S.species.lightweight == 1) + visible_message(span_vwarning("[M] carelessly bowls [src] over!")) + M.forceMove(get_turf(src)) + M.apply_damage(0.5, BRUTE) + Weaken(4) + stop_flying() + apply_damage(0.5, BRUTE) + return if(round(weight) > 474) var/throwtarget = get_edge_target_turf(M, reverse_direction(M.dir)) diff --git a/vorestation.dme b/vorestation.dme index fa1e904ecd..436dd59621 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -763,6 +763,7 @@ #include "code\datums\elements\lootable\misc.dm" #include "code\datums\elements\lootable\surface.dm" #include "code\datums\elements\lootable\trash.dm" +#include "code\datums\elements\vore\spontaneous_vore.dm" #include "code\datums\game_masters\_common.dm" #include "code\datums\helper_datums\construction_datum.dm" #include "code\datums\helper_datums\events.dm"