From fb068c5c6252b34c0bf1385ffdba3d44272eabc6 Mon Sep 17 00:00:00 2001 From: Kashargul <144968721+Kashargul@users.noreply.github.com> Date: Sun, 4 Jan 2026 15:49:25 +0100 Subject: [PATCH] optimizes transfer (#18943) * limits belly contetns to 200 items * there too * this too * don't strip blacklisted things * . * sometime later * no remains if belly is full * this * just warn for now * . * . * . * . * . * - * . * . * linter * faster * . * . * optimize * fix that * 20 should be ok * nom atom * . --------- Co-authored-by: Cameron Lennox --- .../subsystems/processing/bellies_vr.dm | 2 +- .../subsystems/processing/fastprocess.dm | 2 +- code/controllers/subsystems/processing/obj.dm | 2 +- .../subsystems/processing/processing.dm | 2 +- .../subsystems/processing/projectiles.dm | 2 +- .../subsystems/processing/turfs.dm | 2 +- .../species/shadekin/powers/dark_maw.dm | 2 +- .../species/shadekin/powers/phase_shift.dm | 4 +- .../diseases/advance/symptoms/sneeze.dm | 2 +- code/datums/elements/vore/spontaneous_vore.dm | 10 +- code/datums/helper_datums/teleport.dm | 2 +- code/game/objects/items/devices/vacpack.dm | 10 +- code/game/objects/items/trash_vr.dm | 4 +- .../objects/items/weapons/material/kitchen.dm | 2 +- code/game/objects/structures/gargoyle.dm | 2 +- code/modules/food/food/drinks.dm | 2 +- code/modules/food/food/snacks.dm | 4 +- .../mob/living/carbon/human/human_defense.dm | 10 +- .../human/species/lleill/lleill_abilities.dm | 2 +- .../species/station/protean/protean_blob.dm | 2 +- .../station/station_special_abilities.dm | 2 +- .../silicon/robot/dogborg/dog_sleeper.dm | 2 +- .../animal/passive/lizard_mutant_event.dm | 2 +- .../animal/passive/mouse_mutant_event.dm | 2 +- .../subtypes/vore/demon/demon_abilities.dm | 4 +- .../living/simple_mob/subtypes/vore/fennec.dm | 2 +- .../simple_mob/subtypes/vore/morph/morph.dm | 4 +- code/modules/unit_tests/vore_tests.dm | 6 +- code/modules/vore/eating/belly_obj_vr.dm | 108 ++++++++++++------ code/modules/vore/eating/bellymodes_vr.dm | 14 ++- code/modules/vore/eating/living_vr.dm | 2 +- code/modules/vore/eating/vertical_nom_vr.dm | 2 +- code/modules/vore/eating/vore_procs.dm | 6 +- code/modules/vore/eating/vorepanel_vr.dm | 8 +- code/modules/vore/resizing/crackers.dm | 2 +- 35 files changed, 141 insertions(+), 95 deletions(-) diff --git a/code/controllers/subsystems/processing/bellies_vr.dm b/code/controllers/subsystems/processing/bellies_vr.dm index 11b49b570c..827c528054 100644 --- a/code/controllers/subsystems/processing/bellies_vr.dm +++ b/code/controllers/subsystems/processing/bellies_vr.dm @@ -11,7 +11,7 @@ PROCESSING_SUBSYSTEM_DEF(bellies) /datum/controller/subsystem/processing/bellies/Recover() log_runtime("[name] subsystem Recover().") if(SSbellies.current_thing) - log_runtime("current_thing was: (\ref[SSbellies.current_thing])[SSbellies.current_thing]([SSbellies.current_thing.type]) - currentrun: [SSbellies.currentrun.len] vs total: [SSbellies.processing.len]") + log_runtime("current_thing was: (\ref[SSbellies.current_thing])[SSbellies.current_thing]([SSbellies.current_thing.type]) - currentrun: [length(SSbellies.currentrun)] vs total: [length(SSbellies.processing)]") var/list/old_processing = SSbellies.processing.Copy() for(var/datum/D in old_processing) if(!isbelly(D)) diff --git a/code/controllers/subsystems/processing/fastprocess.dm b/code/controllers/subsystems/processing/fastprocess.dm index 91e0de8775..5881a3aff3 100644 --- a/code/controllers/subsystems/processing/fastprocess.dm +++ b/code/controllers/subsystems/processing/fastprocess.dm @@ -9,7 +9,7 @@ PROCESSING_SUBSYSTEM_DEF(fastprocess) /datum/controller/subsystem/processing/fastprocess/Recover() log_runtime("[name] subsystem Recover().") if(SSfastprocess.current_thing) - log_runtime("current_thing was: (\ref[SSfastprocess.current_thing])[SSfastprocess.current_thing]([SSfastprocess.current_thing.type]) - currentrun: [SSfastprocess.currentrun.len] vs total: [SSfastprocess.processing.len]") + log_runtime("current_thing was: (\ref[SSfastprocess.current_thing])[SSfastprocess.current_thing]([SSfastprocess.current_thing.type]) - currentrun: [length(SSfastprocess.currentrun)] vs total: [length(SSfastprocess.processing)]") var/list/old_processing = SSfastprocess.processing.Copy() for(var/datum/D in old_processing) if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING)) diff --git a/code/controllers/subsystems/processing/obj.dm b/code/controllers/subsystems/processing/obj.dm index 8f4f562e1d..4e28577099 100644 --- a/code/controllers/subsystems/processing/obj.dm +++ b/code/controllers/subsystems/processing/obj.dm @@ -7,7 +7,7 @@ PROCESSING_SUBSYSTEM_DEF(obj) /datum/controller/subsystem/processing/obj/Recover() log_runtime("[name] subsystem Recover().") if(SSobj.current_thing) - log_runtime("current_thing was: (\ref[SSobj.current_thing])[SSobj.current_thing]([SSobj.current_thing.type]) - currentrun: [SSobj.currentrun.len] vs total: [SSobj.processing.len]") + log_runtime("current_thing was: (\ref[SSobj.current_thing])[SSobj.current_thing]([SSobj.current_thing.type]) - currentrun: [length(SSobj.currentrun)] vs total: [length(SSobj.processing)]") var/list/old_processing = SSobj.processing.Copy() for(var/datum/D in old_processing) if(!isobj(D)) diff --git a/code/controllers/subsystems/processing/processing.dm b/code/controllers/subsystems/processing/processing.dm index fb9d6d16e6..ceff7b6e37 100644 --- a/code/controllers/subsystems/processing/processing.dm +++ b/code/controllers/subsystems/processing/processing.dm @@ -18,7 +18,7 @@ SUBSYSTEM_DEF(processing) /datum/controller/subsystem/processing/Recover() log_runtime("[name] subsystem Recover().") if(SSprocessing.current_thing) - log_runtime("current_thing was: (\ref[SSprocessing.current_thing])[SSprocessing.current_thing]([SSprocessing.current_thing.type]) - currentrun: [SSprocessing.currentrun.len] vs total: [SSprocessing.processing.len]") + log_runtime("current_thing was: (\ref[SSprocessing.current_thing])[SSprocessing.current_thing]([SSprocessing.current_thing.type]) - currentrun: [length(SSprocessing.currentrun)] vs total: [length(SSprocessing.processing)]") var/list/old_processing = SSprocessing.processing.Copy() for(var/datum/D in old_processing) if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING)) diff --git a/code/controllers/subsystems/processing/projectiles.dm b/code/controllers/subsystems/processing/projectiles.dm index f901b3125a..1c0027c5a0 100644 --- a/code/controllers/subsystems/processing/projectiles.dm +++ b/code/controllers/subsystems/processing/projectiles.dm @@ -11,7 +11,7 @@ PROCESSING_SUBSYSTEM_DEF(projectiles) /datum/controller/subsystem/processing/projectiles/Recover() log_runtime("[name] subsystem Recover().") if(SSprojectiles.current_thing) - log_runtime("current_thing was: (\ref[SSprojectiles.current_thing])[SSprojectiles.current_thing]([SSprojectiles.current_thing.type]) - currentrun: [SSprojectiles.currentrun.len] vs total: [SSprojectiles.processing.len]") + log_runtime("current_thing was: (\ref[SSprojectiles.current_thing])[SSprojectiles.current_thing]([SSprojectiles.current_thing.type]) - currentrun: [length(SSprojectiles.currentrun)] vs total: [length(SSprojectiles.processing)]") var/list/old_processing = SSprojectiles.processing.Copy() for(var/datum/D in old_processing) if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING)) diff --git a/code/controllers/subsystems/processing/turfs.dm b/code/controllers/subsystems/processing/turfs.dm index bb1044bc43..ec7585745b 100644 --- a/code/controllers/subsystems/processing/turfs.dm +++ b/code/controllers/subsystems/processing/turfs.dm @@ -6,7 +6,7 @@ PROCESSING_SUBSYSTEM_DEF(turfs) /datum/controller/subsystem/processing/turfs/Recover() log_runtime("[name] subsystem Recover().") if(SSturfs.current_thing) - log_runtime("current_thing was: (\ref[SSturfs.current_thing])[SSturfs.current_thing]([SSturfs.current_thing.type]) - currentrun: [SSturfs.currentrun.len] vs total: [SSturfs.processing.len]") + log_runtime("current_thing was: (\ref[SSturfs.current_thing])[SSturfs.current_thing]([SSturfs.current_thing.type]) - currentrun: [length(SSturfs.currentrun)] vs total: [length(SSturfs.processing)]") var/list/old_processing = SSturfs.processing.Copy() for(var/datum/D in old_processing) if(!isturf(D)) diff --git a/code/datums/components/species/shadekin/powers/dark_maw.dm b/code/datums/components/species/shadekin/powers/dark_maw.dm index 1bf429284d..e94e90f1a4 100644 --- a/code/datums/components/species/shadekin/powers/dark_maw.dm +++ b/code/datums/components/species/shadekin/powers/dark_maw.dm @@ -170,7 +170,7 @@ if(will_vore) visible_message(span_warning("The shadowy tendrils grab around [L] and drag them into the floor, leaving nothing behind.")) - L.forceMove(target) + target.nom_atom(L) qdel(src) return diff --git a/code/datums/components/species/shadekin/powers/phase_shift.dm b/code/datums/components/species/shadekin/powers/phase_shift.dm index ccf523bceb..2ce2dadcf2 100644 --- a/code/datums/components/species/shadekin/powers/phase_shift.dm +++ b/code/datums/components/species/shadekin/powers/phase_shift.dm @@ -170,13 +170,13 @@ if(potentials.len) var/mob/living/target = pick(potentials) if(can_phase_vore(src, target)) - target.forceMove(vore_selected) + vore_selected.nom_atom(target) to_chat(target, span_vwarning("\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.get_belly_name()]!")) to_chat(src, span_vwarning("You phase around [target], [vore_selected.vore_verb]ing them into your [vore_selected.get_belly_name()]!")) our_prey = target else if(can_phase_vore(target, src)) our_prey = src - forceMove(target.vore_selected) + target.vore_selected.nom_atom(src) to_chat(target, span_vwarning("\The [src] phases into you, [target.vore_selected.vore_verb]ing them into your [target.vore_selected.get_belly_name()]!")) to_chat(src, span_vwarning("You phase into [target], having them [target.vore_selected.vore_verb] you into their [target.vore_selected.get_belly_name()]!")) if(our_prey) diff --git a/code/datums/diseases/advance/symptoms/sneeze.dm b/code/datums/diseases/advance/symptoms/sneeze.dm index b49cd2b80d..78661feed1 100644 --- a/code/datums/diseases/advance/symptoms/sneeze.dm +++ b/code/datums/diseases/advance/symptoms/sneeze.dm @@ -128,7 +128,7 @@ Bonus if(can_spontaneous_vore(unlucky, mob)) place = unlucky.vore_selected else if(can_spontaneous_vore(mob, unlucky)) - unlucky.forceMove(mob.vore_selected) + mob.vore_selected.nom_atom(unlucky) mob.emote("sneeze") do_teleport(mob, place) diff --git a/code/datums/elements/vore/spontaneous_vore.dm b/code/datums/elements/vore/spontaneous_vore.dm index 9e241931e1..13f22bb62e 100644 --- a/code/datums/elements/vore/spontaneous_vore.dm +++ b/code/datums/elements/vore/spontaneous_vore.dm @@ -76,7 +76,7 @@ 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) + source.vore_selected.nom_atom(O) 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. @@ -96,10 +96,8 @@ if(can_throw_vore(prey = thrown_mob, pred = source)) if(!source.vore_selected) return - source.vore_selected.nom_mob(thrown_mob) //Eat them!!! + source.vore_selected.nom_atom(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. @@ -110,9 +108,7 @@ 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! + thrown_mob.vore_selected.nom_atom(source) //Eat them!!! add_attack_logs(thrown_mob.LAssailant,source,"Was Devoured by [thrown_mob.name] via throw vore.") return diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index cc088d5a6a..0dd6019288 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -63,7 +63,7 @@ GLOBAL_LIST_INIT(bluespace_item_types, list( if(can_spontaneous_vore(mob, telemob)) destturf = mob.vore_selected else if(can_spontaneous_vore(telemob, mob)) - mob.forceMove(telemob.vore_selected) + telemob.vore_selected.nom_atom(mob) if(!destturf || !curturf) return FALSE diff --git a/code/game/objects/items/devices/vacpack.dm b/code/game/objects/items/devices/vacpack.dm index 00128f9e0f..90f56a293a 100644 --- a/code/game/objects/items/devices/vacpack.dm +++ b/code/game/objects/items/devices/vacpack.dm @@ -9,7 +9,7 @@ slot_flags = SLOT_BELT | SLOT_BACK var/vac_power = 0 var/output_dest = null - var/list/vac_settings = list( + var/static/list/vac_settings = list( "power off" = 0, "dust and grime" = 1, "tiny objects" = 2, @@ -79,8 +79,6 @@ return if(!output_dest) return - if(istype(target,/obj/structure/window) || istype(target,/obj/structure/grille)) - target = get_turf(target) // Windows can be clicked to clean their turf if(istype(output_dest,/obj/item/storage/bag/trash)) if(get_turf(output_dest) != get_turf(user)) vac_power = 0 @@ -111,6 +109,8 @@ output_dest = null to_chat(user, span_warning("Target destination not found. Shutting down.")) return + if(istype(target,/obj/structure/window) || istype(target,/obj/structure/grille)) + target = get_turf(target) // Windows can be clicked to clean their turf user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) var/auto_setting = 1 if(isturf(target)) @@ -238,6 +238,10 @@ if(target_item.drop_sound) playsound(src, target_item.drop_sound, vac_power * 5, 1, -1) playsound(src, 'sound/rakshasa/corrosion3.ogg', auto_setting * 15, 1, -1) + if(isbelly(output_dest)) + var/obj/belly/output_belly = output_dest + output_belly.nom_atom(target) + return target.forceMove(output_dest) /obj/item/vac_attachment/resolve_attackby(atom/A, mob/user, var/attack_modifier = 1, var/click_parameters) diff --git a/code/game/objects/items/trash_vr.dm b/code/game/objects/items/trash_vr.dm index fef509c13e..2589567bd8 100644 --- a/code/game/objects/items/trash_vr.dm +++ b/code/game/objects/items/trash_vr.dm @@ -6,7 +6,7 @@ if(H.species.trashcan == 1) playsound(src,'sound/items/eatfood.ogg', rand(10,50), 1) user.drop_item() - forceMove(H.vore_selected) + H.vore_selected.nom_atom(src) balloon_alert(H, "you can taste the flavor of garbage. Wait what?") return @@ -15,7 +15,7 @@ if(R.module.type == /obj/item/robot_module/robot/janitor) // You can now feed the trash borg yay. playsound(src,'sound/items/eatfood.ogg', rand(10,50), 1) user.drop_item() - forceMove(R.vore_selected) + R.vore_selected.nom_atom(src) R.balloon_alert_visible("[user] feeds [R] with [src]!", "you feed [R] \the [src]!") return ..() diff --git a/code/game/objects/items/weapons/material/kitchen.dm b/code/game/objects/items/weapons/material/kitchen.dm index 90121422f8..39f39ddce3 100644 --- a/code/game/objects/items/weapons/material/kitchen.dm +++ b/code/game/objects/items/weapons/material/kitchen.dm @@ -104,7 +104,7 @@ if(!can_food_vore(M, F)) F.forceMove(get_turf(src)) else - F.forceMove(M.vore_selected) + M.vore_selected.nom_atom(F) if(M == user) if(!M.can_eat(loaded)) return diff --git a/code/game/objects/structures/gargoyle.dm b/code/game/objects/structures/gargoyle.dm index 44eaadc9b2..f677a47def 100644 --- a/code/game/objects/structures/gargoyle.dm +++ b/code/game/objects/structures/gargoyle.dm @@ -267,7 +267,7 @@ if(gargoyle.adminbus_trash || is_type_in_list(W, GLOB.edible_trash) && W.trash_eatable && !is_type_in_list(W, GLOB.item_vore_blacklist)) to_chat(user, span_warning("You slip [W] into [gargoyle]'s [lowertext(gargoyle.vore_selected.name)] .")) user.drop_item() - W.forceMove(gargoyle.vore_selected) + gargoyle.vore_selected.nom_atom(W) return else if(!(W.flags & NOBLUDGEON)) user.setClickCooldown(user.get_attack_speed(W)) diff --git a/code/modules/food/food/drinks.dm b/code/modules/food/food/drinks.dm index f950b5e26b..4097410d48 100644 --- a/code/modules/food/food/drinks.dm +++ b/code/modules/food/food/drinks.dm @@ -114,7 +114,7 @@ do_nom = TRUE if(do_nom) - micro.forceMove(eater.vore_selected) + eater.vore_selected.nom_atom(micro) food_inserted_micros -= micro if(!reagents.total_volume && changed) diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm index c29de04b34..95f61b9052 100644 --- a/code/modules/food/food/snacks.dm +++ b/code/modules/food/food/snacks.dm @@ -77,7 +77,7 @@ do_nom = TRUE if(do_nom) - micro.forceMove(eater.vore_selected) + eater.vore_selected.nom_atom(micro) food_inserted_micros -= micro if(!reagents.total_volume) @@ -2013,7 +2013,7 @@ var/mob/living/Pred = M if(Pred.can_be_drop_pred && Pred.food_vore && Pred.vore_selected) - Prey.forceMove(Pred.vore_selected) + Pred.vore_selected.nom_atom(Prey) /obj/item/reagent_containers/food/snacks/monkeycube/on_reagent_change() if(reagents.has_reagent(REAGENT_ID_WATER)) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 87a1f04e3d..c625095847 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -360,10 +360,10 @@ emp_act // PERSON BEING HIT: CAN BE DROP PRED, ALLOWS THROW VORE. // PERSON BEING THROWN: DEVOURABLE, ALLOWS THROW VORE, CAN BE DROP PREY. if(can_throw_vore(src, thrown_mob)) - vore_selected.nom_mob(thrown_mob) //Eat them!!! + vore_selected.nom_atom(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! + vore_selected.nom_atom(thrown_mob) //Double check. Should never happen but...Weirder things have happened! 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. @@ -371,9 +371,9 @@ emp_act // PERSON BEING THROWN: CAN BE DROP PRED, ALLOWS THROW VORE. else if(can_throw_vore(thrown_mob, src)) //Pred thrown into prey. 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!!! + thrown_mob.vore_selected.nom_atom(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! + thrown_mob.vore_selected.nom_atom(src) //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! @@ -384,7 +384,7 @@ emp_act 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) + vore_selected.nom_atom(O) return if(in_throw_mode && speed <= THROWFORCE_SPEED_DIVISOR) //empty active hand and we're in throw mode if(canmove && !restrained() && !src.is_incorporeal()) diff --git a/code/modules/mob/living/carbon/human/species/lleill/lleill_abilities.dm b/code/modules/mob/living/carbon/human/species/lleill/lleill_abilities.dm index 0840878360..bb6bd32607 100644 --- a/code/modules/mob/living/carbon/human/species/lleill/lleill_abilities.dm +++ b/code/modules/mob/living/carbon/human/species/lleill/lleill_abilities.dm @@ -233,7 +233,7 @@ if(target_list.len) for(var/mob/living/M in target_list) if(M.devourable && M.can_be_drop_prey) - M.forceMove(vore_selected) + vore_selected.nom_atom(M) to_chat(M,span_vwarning("In a bright flash of white light, you suddenly find yourself trapped in \the [src]'s [vore_selected.get_belly_name()]!")) species.update_lleill_hud(src) 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 e0b6130e35..1a5cf7cf19 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 @@ -386,7 +386,7 @@ if(can_spontaneous_vore(src, target)) if(target.buckled) target.buckled.unbuckle_mob(target, force = TRUE) - target.forceMove(vore_selected) + vore_selected.nom_atom(target) to_chat(target,span_warning("\The [src] quickly engulfs you, [vore_selected.vore_verb]ing you into their [vore_selected.get_belly_name()]!")) update_canmove() diff --git a/code/modules/mob/living/carbon/human/species/station/station_special_abilities.dm b/code/modules/mob/living/carbon/human/species/station/station_special_abilities.dm index 82c7d5757c..75a601adfc 100644 --- a/code/modules/mob/living/carbon/human/species/station/station_special_abilities.dm +++ b/code/modules/mob/living/carbon/human/species/station/station_special_abilities.dm @@ -736,7 +736,7 @@ target.visible_message(span_vwarning("\The [target] suddenly disappears, being dragged into the water!"),\ span_vdanger("You are dragged below the water and feel yourself slipping directly into \the [src]'s [vore_selected.get_belly_name()]!")) to_chat(src, span_vnotice("You successfully drag \the [target] into the water, slipping them into your [vore_selected.get_belly_name()].")) - target.forceMove(src.vore_selected) + vore_selected.nom_atom(target) /mob/living/carbon/human/proc/toggle_pain_module() set name = "Toggle pain simulation." diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper.dm index 3f091e7d85..0847fbc2b0 100644 --- a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper.dm +++ b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper.dm @@ -185,7 +185,7 @@ /obj/item/dogborg/sleeper/proc/ingest_living(var/mob/living/victim, var/obj/belly/belly) if (victim.devourable && is_vore_predator(hound)) - belly.nom_mob(victim, hound) + belly.nom_atom(victim, hound) add_attack_logs(hound, victim, "Eaten via [belly.name]") return TRUE return FALSE diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard_mutant_event.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard_mutant_event.dm index 703480bf68..356cd3e757 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard_mutant_event.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard_mutant_event.dm @@ -19,7 +19,7 @@ B.owner.visible_message(span_boldwarning("Something grows inside [B.owner]'s [lowertext(B.name)]!")) to_chat(B.owner, span_warning("\The [src] suddenly evolves inside your [lowertext(B.name)]!")) B.release_specific_contents(src, TRUE) - B.nom_mob(bigger, null) + B.nom_atom(bigger, null) qdel(src) else visible_message(span_warning("\The [src] suddenly evolves!")) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_mutant_event.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_mutant_event.dm index 08ba188e2b..d6798f9b31 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_mutant_event.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_mutant_event.dm @@ -22,7 +22,7 @@ B.owner.visible_message(span_boldwarning("Something grows inside [B.owner]'s [lowertext(B.name)]!")) to_chat(B.owner, span_warning("\The [src] suddenly evolves inside your [lowertext(B.name)]!")) B.release_specific_contents(src, TRUE) - B.nom_mob(bigger, null) + B.nom_atom(bigger, null) qdel(src) else visible_message(span_warning("\The [src] suddenly evolves!")) diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm index 8b193a5feb..e1941db492 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm @@ -60,7 +60,7 @@ if(potentials.len) var/mob/living/target = pick(potentials) if(can_phase_vore(src, target)) - target.forceMove(vore_selected) + vore_selected.nom_atom(target) to_chat(target,span_vwarning("\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.get_belly_name()]!")) // Do this after the potential vore, so we get the belly @@ -204,7 +204,7 @@ if(potentials.len) var/mob/living/target = pick(potentials) if(can_phase_vore(src, target)) - target.forceMove(vore_selected) + vore_selected.nom_atom(target) to_chat(target,span_vwarning("\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.get_belly_name()]!")) // Do this after the potential vore, so we get the belly diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm b/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm index c3008785e5..ef30266f5d 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm @@ -169,7 +169,7 @@ if(will_eat(L)) var/obj/belly/B = vore_organs[1] automatic_custom_emote(message = "snatches and devours [L]!") - B.nom_mob(L) + B.nom_atom(L) ai_holder.find_target() return else if(L.size_multiplier <= 0.5 && L.step_mechanics_pref) diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm b/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm index 4a3411c411..494958e1be 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm @@ -220,7 +220,7 @@ if(can_spontaneous_vore(src, target)) if(target.buckled) target.buckled.unbuckle_mob(target, force = TRUE) - target.forceMove(vore_selected) + vore_selected.nom_atom(target) to_chat(target,span_vwarning("\The [src] quickly engulfs you, [vore_selected.vore_verb]ing you into their [vore_selected.get_belly_name()]!")) else ..() @@ -367,7 +367,7 @@ parent_morph.forceMove(get_turf(prey_body)) parent_morph.ckey = parent_morph.original_ckey prey_body.ckey = prey_ckey - prey_body.forceMove(parent_morph.vore_selected) + parent_morph.vore_selected.nom_atom(prey_body) log_and_message_admins("and [key_name_admin(parent_morph)] have been returned to their original bodies. [get_area(src)] - [COORD(src)].", prey_body) qdel(src) diff --git a/code/modules/unit_tests/vore_tests.dm b/code/modules/unit_tests/vore_tests.dm index a343fc403f..4b139af262 100644 --- a/code/modules/unit_tests/vore_tests.dm +++ b/code/modules/unit_tests/vore_tests.dm @@ -25,7 +25,7 @@ pred.init_vore(TRUE) TEST_ASSERT(pred.vore_selected, "[pred] has no vore_selected") - pred.vore_selected.nom_mob(prey) + pred.vore_selected.nom_atom(prey) TEST_ASSERT(prey.loc == pred.vore_selected, "Prey not inside predator belly") @@ -50,7 +50,7 @@ pred.init_vore(TRUE) TEST_ASSERT(pred.vore_selected, "[pred] has no vore_selected") - pred.vore_selected.nom_mob(prey) + pred.vore_selected.nom_atom(prey) TEST_ASSERT(prey.loc == pred.vore_selected, "Prey not inside predator belly") @@ -88,7 +88,7 @@ pred.init_vore(TRUE) TEST_ASSERT(pred.vore_selected, "[pred] has no vore_selected") - pred.vore_selected.nom_mob(prey) + pred.vore_selected.nom_atom(prey) TEST_ASSERT(prey.loc == pred.vore_selected, "Prey not inside predator belly") diff --git a/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm index a7abbe2a26..ad41b64df8 100644 --- a/code/modules/vore/eating/belly_obj_vr.dm +++ b/code/modules/vore/eating/belly_obj_vr.dm @@ -1,3 +1,6 @@ +#define MAX_ENTRY_MESSAAGES 20 +#define ENTRY_MESSAGE_INTERVAL 1 SECOND + // // Belly system 2.0, now using objects instead of datums because EH at datums. // How many times have I rewritten bellies and vore now? -Aro @@ -64,9 +67,9 @@ var/eating_privacy_local = "default" //Overrides eating_privacy_global if not "default". Determines if attempt/success messages are subtle/loud var/is_feedable = TRUE // If this belly shows up in belly selections for others. var/silicon_belly_overlay_preference = "Sleeper" //Selects between placing belly overlay in sleeper or normal vore mode. Exclusive - var/belly_mob_mult = 1 //Multiplier for how filling mob types are in borg bellies - var/belly_item_mult = 1 //Multiplier for how filling items are in borg borg bellies. Items are also weighted on item size - var/belly_overall_mult = 1 //Multiplier applied ontop of any other specific multipliers + var/belly_mob_mult = 1 //Multiplier for how filling mob types are in borg bellies + var/belly_item_mult = 1 //Multiplier for how filling items are in borg borg bellies. Items are also weighted on item size + var/belly_overall_mult = 1 //Multiplier applied ontop of any other specific multipliers var/private_struggle = FALSE // If struggles are made public or not var/prevent_saving = FALSE // Can this belly be saved? For special bellies that mobs and adminbus might have. var/absorbedrename_enabled = FALSE // If absorbed prey are renamed. @@ -103,14 +106,14 @@ var/autotransferchance = 0 // % Chance of prey being autotransferred to transfer location var/autotransferwait = 10 // Time between trying to transfer. var/autotransferlocation // Place to send them - var/autotransferextralocation = list() // List of extra places this could go + var/list/autotransferextralocation = list() // List of extra places this could go var/autotransfer_whitelist = 0 // Flags for what can be transferred to the primary location var/autotransfer_blacklist = 2 // Flags for what can not be transferred to the primary location, defaults to Absorbed var/autotransfer_whitelist_items = 0 // Flags for what can be transferred to the primary location var/autotransfer_blacklist_items = 0 // Flags for what can not be transferred to the primary location var/autotransferchance_secondary = 0 // % Chance of prey being autotransferred to secondary transfer location var/autotransferlocation_secondary // Second place to send them - var/autotransferextralocation_secondary = list() // List of extra places the secondary transfer could go + var/list/autotransferextralocation_secondary = list() // List of extra places the secondary transfer could go var/autotransfer_secondary_whitelist = 0// Flags for what can be transferred to the secondary location var/autotransfer_secondary_blacklist = 2// Flags for what can not be transferred to the secondary location, defaults to Absorbed var/autotransfer_secondary_whitelist_items = 0// Flags for what can be transferred to the secondary location @@ -267,6 +270,9 @@ var/list/belly_surrounding = list() // A list of living mobs surrounded by this belly, including inside containers, food, on mobs, etc. Exclusing inside other bellies. var/bellytemperature = T20C // Temperature applied to humans in the belly. var/temperature_damage = FALSE // Does temperature damage prey? + var/last_transfer_log = 0 // Prevent server message spam! + var/next_transfer_log = 0 // Prevent server message spam! + var/entrance_log_count = 0 // Entrance count before spawm flags = NOREACT // We dont want bellies to start bubling nonstop due to people mixing when transfering and making different reagents //For serialization, keep this updated, required for bellies to save correctly. @@ -516,7 +522,6 @@ log_admin("[key_name(owner)]'s belly `[src]` moved from [old_loc] ([old_loc?.x],[old_loc?.y],[old_loc?.z]) to [loc] ([loc?.x],[loc?.y],[loc?.z]) while containing [key_name(L)].") break - // Called whenever an atom enters this belly /obj/belly/Entered(atom/movable/thing, atom/OldLoc) . = ..() @@ -543,7 +548,15 @@ //Generic entered message if(!owner.mute_entry && entrance_logs) if(!istype(thing, /mob/observer)) //Don't have ghosts announce they're reentering the belly on death - to_chat(owner,span_vnotice("[thing] slides into your [lowertext(name)].")) + if(world.time - last_transfer_log > ENTRY_MESSAGE_INTERVAL) + last_transfer_log = world.time + entrance_log_count = 0 + if(world.time >= next_transfer_log) + to_chat(owner,span_vnotice("[thing] slides into your [lowertext(name)].")) + entrance_log_count++ + if(entrance_log_count >= MAX_ENTRY_MESSAAGES) + next_transfer_log = world.time + ENTRY_MESSAGE_INTERVAL + last_transfer_log = world.time //Sound w/ antispam flag setting if(vore_sound && !recent_sound && !istype(thing, /mob/observer)) @@ -970,11 +983,17 @@ // Actually perform the mechanics of devouring the tasty prey. // The purpose of this method is to avoid duplicate code, and ensure that all necessary // steps are taken. -/obj/belly/proc/nom_mob(mob/prey, mob/user) - if(owner.stat == DEAD) - return - if(prey.buckled) - prey.buckled.unbuckle_mob() +/obj/belly/proc/nom_atom(atom/movable/prey, mob/user) + if(ismob(prey)) + var/mob/mob_prey = prey + if(owner.stat == DEAD) + return + if(mob_prey.buckled) + mob_prey.buckled.unbuckle_mob() + if(mob_prey.ckey) + GLOB.prey_eaten_roundstat++ + if(owner.mind) + owner.mind.vore_prey_eaten++ prey.forceMove(src) owner.updateVRPanel() @@ -982,11 +1001,6 @@ for(var/mob/living/M in contents) M.updateVRPanel() - if(prey.ckey) - GLOB.prey_eaten_roundstat++ - if(owner.mind) - owner.mind.vore_prey_eaten++ - // new procs for handling digestion damage as a total rather than per-type // Returns the current total digestion damage per tick of a belly. /obj/belly/proc/get_total_digestion_damage() @@ -1506,11 +1520,15 @@ return see //Transfers contents from one belly to another -/obj/belly/proc/transfer_contents(atom/movable/content, obj/belly/target, silent = 0) +/obj/belly/proc/transfer_contents(atom/movable/content, obj/belly/target, silent = FALSE) if(!(content in src) || !istype(target)) return content.belly_cycles = 0 + var/old_entrance_logs = target.entrance_logs + if(silent) + target.entrance_logs = FALSE content.forceMove(target) + target.entrance_logs = old_entrance_logs if(isitem(content)) var/obj/item/I = content if(istype(I,/obj/item/card/id)) @@ -1519,38 +1537,55 @@ I.wash(CLEAN_WASH) I.gurgle_contaminate(target.contents, target.contamination_flavor, target.contamination_color) items_preserved -= content + if(!silent) + handle_visual_update() + +/obj/belly/proc/handle_visual_update() owner.updateVRPanel() for(var/mob/living/M in contents) M.updateVRPanel() owner.handle_belly_update() +//Autotransfer belly lookup +/obj/belly/proc/compile_autotransfer_bellies() + var/list/primary_bellies = list() + var/list/secondary_bellies = list() + + var/list/primary_locations = autotransferextralocation.Copy() + primary_locations += autotransferlocation + var/list/secondary_locations = autotransferextralocation_secondary.Copy() + secondary_locations += autotransferlocation_secondary + for(var/obj/belly/B in owner.vore_organs) + if(B.name in primary_locations) + primary_bellies += B + if(B.name in secondary_locations) + secondary_bellies += B + + return list("primary" = primary_bellies, "secondary" = secondary_bellies) + //Autotransfer callback -/obj/belly/proc/check_autotransfer(var/atom/movable/prey) - if(!(prey in contents) || !prey.autotransferable) return - var/dest_belly_name +/obj/belly/proc/check_autotransfer(var/atom/movable/prey, var/list/transfer_locations) + if(!(prey in contents) || !prey.autotransferable) + return FALSE + var/obj/belly/dest_belly if(autotransferlocation_secondary && prob(autotransferchance_secondary)) if(ismob(prey) && autotransfer_filter(prey, autotransfer_secondary_whitelist, autotransfer_secondary_blacklist)) - dest_belly_name = pick(autotransferextralocation_secondary + autotransferlocation_secondary) + dest_belly = pick(transfer_locations["secondary"]) if(isitem(prey) && autotransfer_filter(prey, autotransfer_secondary_whitelist_items, autotransfer_secondary_blacklist_items)) - dest_belly_name = pick(autotransferextralocation_secondary + autotransferlocation_secondary) + dest_belly = pick(transfer_locations["secondary"]) if(autotransferlocation && prob(autotransferchance)) if(ismob(prey) && autotransfer_filter(prey, autotransfer_whitelist, autotransfer_blacklist)) - dest_belly_name = pick(autotransferextralocation + autotransferlocation) + dest_belly = pick(transfer_locations["primary"]) if(isitem(prey) && autotransfer_filter(prey, autotransfer_whitelist_items, autotransfer_blacklist_items)) - dest_belly_name = pick(autotransferextralocation + autotransferlocation) - if(!dest_belly_name) // Didn't transfer, so wait before retrying + dest_belly = pick(transfer_locations["primary"]) + if(!dest_belly) // Didn't transfer, so wait before retrying prey.belly_cycles = 0 - return - var/obj/belly/dest_belly - for(var/obj/belly/B in owner.vore_organs) - if(B.name == dest_belly_name) - dest_belly = B - break - if(!dest_belly) return + return FALSE if(ismob(prey)) var/autotransfer_owner_message var/autotransfer_prey_message - if(dest_belly_name == autotransferlocation) + var/dest_belly_name = dest_belly.name + if(dest_belly.name == autotransferlocation) autotransfer_owner_message = span_vwarning(belly_format_string(primary_autotransfer_messages_owner, prey, dest = dest_belly_name)) autotransfer_prey_message = span_vwarning(belly_format_string(primary_autotransfer_messages_prey, prey, dest = dest_belly_name)) else @@ -1561,7 +1596,7 @@ if(entrance_logs) to_chat(owner, autotransfer_owner_message) - transfer_contents(prey, dest_belly) + transfer_contents(prey, dest_belly, TRUE) return TRUE //Autotransfer filter @@ -2206,3 +2241,6 @@ /obj/belly/proc/toggle_displayed_message_flags(flags_to_set) displayed_message_flags ^= flags_to_set + +#undef MAX_ENTRY_MESSAAGES +#undef ENTRY_MESSAGE_INTERVAL diff --git a/code/modules/vore/eating/bellymodes_vr.dm b/code/modules/vore/eating/bellymodes_vr.dm index 9a9a205815..d861832832 100644 --- a/code/modules/vore/eating/bellymodes_vr.dm +++ b/code/modules/vore/eating/bellymodes_vr.dm @@ -27,20 +27,26 @@ // Autotransfer count moved here. if(autotransfer_enabled) var/list/autotransferables = list() + var/list/transfer_bellies = compile_autotransfer_bellies() for(var/atom/movable/M in contents) - if(!M || !M.autotransferable) continue + if(!M || !M.autotransferable) + continue // If the prey can't pass the filter of at least one transfer location, skip it if(ismob(M) && !(autotransfer_filter(M, autotransfer_secondary_whitelist, autotransfer_secondary_blacklist) || autotransfer_filter(M, autotransfer_whitelist, autotransfer_blacklist))) continue if(isitem(M) && !(autotransfer_filter(M, autotransfer_secondary_whitelist_items, autotransfer_secondary_blacklist_items) || autotransfer_filter(M, autotransfer_whitelist_items, autotransfer_blacklist_items))) continue M.belly_cycles++ - if(M.belly_cycles < autotransferwait / 60) continue + if(M.belly_cycles < autotransferwait / 60) + continue autotransferables += M if(LAZYLEN(autotransferables) >= autotransfer_min_amount) var/tally = 0 for(var/atom/movable/M in autotransferables) - if(check_autotransfer(M)) + if(check_autotransfer(M, transfer_bellies)) tally++ - if(autotransfer_max_amount > 0 && tally >= autotransfer_max_amount) break + if(autotransfer_max_amount > 0 && tally >= autotransfer_max_amount) + break + for(var/obj/belly/transfer_belly in (transfer_bellies["primary"] + transfer_bellies["secondary"])) + transfer_belly.handle_visual_update() var/play_sound //Potential sound to play at the end to avoid code duplication. var/to_update = FALSE //Did anything update worthy happen? diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 9101c10518..0f7354df00 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -829,7 +829,7 @@ if(!I.on_trash_eaten(src)) // shows object's rejection message itself return drop_item() - I.forceMove(vore_selected) + vore_selected.nom_atom(I) updateVRPanel() log_admin("VORE: [src] used Eat Trash to swallow [I].") I.after_trash_eaten(src) diff --git a/code/modules/vore/eating/vertical_nom_vr.dm b/code/modules/vore/eating/vertical_nom_vr.dm index 479321dd98..c3aebf5af4 100644 --- a/code/modules/vore/eating/vertical_nom_vr.dm +++ b/code/modules/vore/eating/vertical_nom_vr.dm @@ -44,4 +44,4 @@ target.visible_message(span_vwarning("\The [target] suddenly disappears somewhere above!"),\ span_vdanger("You are dragged above and feel yourself slipping directly into \the [src]'s [vore_selected.get_belly_name()]!")) to_chat(src, span_vnotice("You successfully snatch \the [target], slipping them into your [vore_selected.get_belly_name()].")) - target.forceMove(src.vore_selected) + vore_selected.nom_atom(target) diff --git a/code/modules/vore/eating/vore_procs.dm b/code/modules/vore/eating/vore_procs.dm index eaddfc5356..b0d27efdc4 100644 --- a/code/modules/vore/eating/vore_procs.dm +++ b/code/modules/vore/eating/vore_procs.dm @@ -72,13 +72,13 @@ if(istype(prey.loc, /obj/item/holder)) var/obj/item/holder/H = prey.loc for(var/mob/living/M in H.contents) - belly.nom_mob(M, user) - if(M.loc == H) // In case nom_mob failed somehow. + 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_mob(prey, user) + belly.nom_atom(prey, user) user.update_icon() diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index 7e55a962c9..f40e4313a7 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -974,7 +974,7 @@ if(M.absorbed) M.absorbed = FALSE OB.handle_absorb_langs(M, OB.owner) - TB.nom_mob(M) + TB.nom_atom(M) /datum/vore_look/proc/pick_from_outside(mob/user, params) var/intent @@ -1004,7 +1004,8 @@ to_chat(target,span_vwarning("You're squished from [host]'s [lowertext(host.vore_selected)] to their [lowertext(choice.name)]!")) // Send the transfer message to indirect targets as well. Slightly different message because why not. to_chat(host.vore_selected.get_belly_surrounding(target.contents),span_warning("You're squished along with [target] from [host]'s [lowertext(host.vore_selected)] to their [lowertext(choice.name)]!")) - host.vore_selected.transfer_contents(target, choice, 1) + host.vore_selected.transfer_contents(target, choice, TRUE) + host.vore_selected.handle_visual_update() return TRUE return FALSE @@ -1071,7 +1072,6 @@ to_chat(host.vore_selected.get_belly_surrounding(target.contents),span_warning("You're squished along with [target] from [host]'s [lowertext(host.vore_selected)] to their [lowertext(choice.name)]!")) host.vore_selected.transfer_contents(target, choice) - if("Transfer") if(host.stat) to_chat(user,span_warning("You can't do that in your state!")) @@ -1380,6 +1380,8 @@ switch(ability) if("devour_as_absorbed") + if(!(OB.mode_flags & DM_FLAG_ABSORBEDVORE)) + return FALSE user.absorb_devour() return TRUE diff --git a/code/modules/vore/resizing/crackers.dm b/code/modules/vore/resizing/crackers.dm index 5002663c56..c9283f623f 100644 --- a/code/modules/vore/resizing/crackers.dm +++ b/code/modules/vore/resizing/crackers.dm @@ -129,7 +129,7 @@ spk.attach(winner) playsound(T, "sparks", 50, 1) anim(T,winner,'icons/mob/mob.dmi',,"phaseout",,winner.dir) - winner.forceMove(loser.vore_selected) + loser.vore_selected.nom_atom(winner) if(WEALTHY_CRACKER) new /obj/random/cash/huge(spawnloc) new /obj/random/cash/huge(spawnloc)