diff --git a/code/datums/browser.dm b/code/datums/browser.dm index d0fedd1316..e78833c958 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -15,9 +15,7 @@ var/content = "" var/title_buttons = "" - /datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null) - user = nuser window_id = nwindow_id if (ntitle) @@ -33,6 +31,14 @@ return add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs +//VOREStation Edit - Allow browser datums to be garbage collected +/datum/browser/Destroy() + close() + ref = null + user = null + . = ..() +//VOREStation Edit End - Allow browser datums to be garbage collected + /datum/browser/proc/set_title(ntitle) title = format_text(ntitle) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index d1bd905d4d..557a3dd83b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -57,7 +57,6 @@ for(var/organ in organs) qdel(organ) QDEL_NULL(nif) //VOREStation Add - QDEL_LIST_NULL(vore_organs) //VOREStation Add return ..() /mob/living/carbon/human/Stat() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index b504698afe..dd2bb820ea 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -32,6 +32,8 @@ if(buckled) buckled.unbuckle_mob(src, TRUE) qdel(selected_image) + QDEL_NULL(vorePanel) //VOREStation Add + QDEL_LIST_NULL(vore_organs) //VOREStation Add return ..() //mob verbs are faster than object verbs. See mob/verb/examine. diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm b/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm index 74b3f3aa33..7d32b7b350 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm @@ -121,7 +121,7 @@ /mob/living/simple_mob/vore/aggressive/corrupthound/space/Process_Spacemove(var/check_drift = 0) return TRUE -/mob/living/simple_mob/vore/hostile/corrupthound/init_vore() +/mob/living/simple_mob/vore/aggressive/corrupthound/init_vore() ..() var/obj/belly/B = vore_selected B.name = "fuel processor" @@ -143,7 +143,7 @@ "The longer you spend stewing away in the pool of hot, clingy juices surrounding you, the weaker and weaker you seem to feel!", "'FU3L mE A1RE@Dy, S0 sO SORrY!?', your corrupted captor growls as its synthetic innards begin oozing more potent juices, grinding down into your body with increasing fervor!") -/mob/living/simple_mob/vore/hostile/corrupthound/prettyboi/init_vore() +/mob/living/simple_mob/vore/aggressive/corrupthound/prettyboi/init_vore() ..() var/obj/belly/B = vore_selected B.name = "fuel processor" diff --git a/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm index a6221a4a57..c924cbcebd 100644 --- a/code/modules/vore/eating/belly_obj_vr.dm +++ b/code/modules/vore/eating/belly_obj_vr.dm @@ -59,7 +59,6 @@ var/tmp/list/items_preserved = list() // Stuff that wont digest so we shouldn't process it again. var/tmp/next_emote = 0 // When we're supposed to print our next emote, as a belly controller tick # var/tmp/recent_sound = FALSE // Prevent audio spam - var/tmp/list/hearing_mobs // Don't forget to watch your commas at the end of each line if you change these. var/list/struggle_messages_outside = list( @@ -177,7 +176,7 @@ . = ..() // Called whenever an atom enters this belly -/obj/belly/Entered(var/atom/movable/thing,var/atom/OldLoc) +/obj/belly/Entered(atom/movable/thing, atom/OldLoc) if(OldLoc in contents) return //Someone dropping something (or being stripdigested) @@ -207,8 +206,7 @@ // Release all contents of this belly into the owning mob's location. // If that location is another mob, contents are transferred into whichever of its bellies the owning mob is in. // Returns the number of mobs so released. -/obj/belly/proc/release_all_contents(var/include_absorbed = FALSE, var/silent = FALSE) - +/obj/belly/proc/release_all_contents(include_absorbed = FALSE, silent = FALSE) //Don't bother if we don't have contents if(!contents.len) return FALSE @@ -246,7 +244,7 @@ // Release a specific atom from the contents of this belly into the owning mob's location. // If that location is another mob, the atom is transferred into whichever of its bellies the owning mob is in. // Returns the number of atoms so released. -/obj/belly/proc/release_specific_contents(var/atom/movable/M, var/silent = FALSE) +/obj/belly/proc/release_specific_contents(atom/movable/M, silent = FALSE) if (!(M in contents)) return 0 // They weren't in this belly anyway @@ -294,10 +292,10 @@ // 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(var/mob/prey, var/mob/user) +/obj/belly/proc/nom_mob(mob/prey, mob/user) if(owner.stat == DEAD) return - if (prey.buckled) + if(prey.buckled) prey.buckled.unbuckle_mob() prey.forceMove(src) @@ -316,9 +314,9 @@ var/raw_message = pick(examine_messages) var/total_bulge = 0 - formatted_message = replacetext(raw_message,"%belly",lowertext(name)) - formatted_message = replacetext(formatted_message,"%pred",owner) - formatted_message = replacetext(formatted_message,"%prey",english_list(contents)) + formatted_message = replacetext(raw_message, "%belly" ,lowertext(name)) + formatted_message = replacetext(formatted_message, "%pred" ,owner) + formatted_message = replacetext(formatted_message, "%prey" ,english_list(contents)) for(var/mob/living/P in contents) if(!P.absorbed) //This is required first, in case there's a person absorbed and not absorbed in a stomach. total_bulge += P.size_multiplier @@ -330,10 +328,10 @@ // The next function gets the messages set on the belly, in human-readable format. // This is useful in customization boxes and such. The delimiter right now is \n\n so // in message boxes, this looks nice and is easily delimited. -/obj/belly/proc/get_messages(var/type, var/delim = "\n\n") +/obj/belly/proc/get_messages(type, delim = "\n\n") ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em") + var/list/raw_messages - switch(type) if("smo") raw_messages = struggle_messages_outside @@ -346,13 +344,13 @@ if("em") raw_messages = examine_messages - var/messages = list2text(raw_messages,delim) + var/messages = list2text(raw_messages, delim) return messages // The next function sets the messages on the belly, from human-readable var // replacement strings and linebreaks as delimiters (two \n\n by default). // They also sanitize the messages. -/obj/belly/proc/set_messages(var/raw_text, var/type, var/delim = "\n\n") +/obj/belly/proc/set_messages(raw_text, type, delim = "\n\n") ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em") var/list/raw_list = text2list(html_encode(raw_text),delim) @@ -389,8 +387,8 @@ // Called from the process_Life() methods of bellies that digest prey. // Default implementation calls M.death() and removes from internal contents. // Indigestable items are removed, and M is deleted. -/obj/belly/proc/digestion_death(var/mob/living/M) - message_admins("[key_name(owner)] has digested [key_name(M)] in their [lowertext(name)] ([owner ? "JMP" : "null"])") +/obj/belly/proc/digestion_death(mob/living/M) + message_admins("[key_name(owner)] has digested [key_name(M)] in their [lowertext(name)] ([owner ? ADMIN_JMP(owner) : "null"])") // If digested prey is also a pred... anyone inside their bellies gets moved up. if(is_vore_predator(M)) @@ -399,7 +397,7 @@ //Drop all items into the belly. if(config.items_survive_digestion) for(var/obj/item/W in M) - if(istype(W,/obj/item/organ/internal/mmi_holder/posibrain)) + if(istype(W, /obj/item/organ/internal/mmi_holder/posibrain)) var/obj/item/organ/internal/mmi_holder/MMI = W var/atom/movable/brain = MMI.removed() if(brain) @@ -410,7 +408,7 @@ var/obj/item/I = M.get_equipped_item(slot = slot) if(I) M.unEquip(I,force = TRUE) - if(contaminates || istype(I,/obj/item/weapon/card/id)) + if(contaminates || istype(I, /obj/item/weapon/card/id)) I.gurgle_contaminate(contents, contamination_flavor, contamination_color) //We do an initial contamination pass to get stuff like IDs wet. if(item_digest_mode == IM_HOLD) items_preserved |= I @@ -435,10 +433,10 @@ qdel(M) // Handle a mob being absorbed -/obj/belly/proc/absorb_living(var/mob/living/M) +/obj/belly/proc/absorb_living(mob/living/M) M.absorbed = 1 - to_chat(M,"[owner]'s [lowertext(name)] absorbs your body, making you part of them.") - to_chat(owner,"Your [lowertext(name)] absorbs [M]'s body, making them part of you.") + to_chat(M, "[owner]'s [lowertext(name)] absorbs your body, making you part of them.") + to_chat(owner, "Your [lowertext(name)] absorbs [M]'s body, making them part of you.") if(M.noisy) //Mute drained absorbee hunger if enabled. M.noisy = FALSE @@ -473,7 +471,7 @@ //Digest a single item //Receives a return value from digest_act that's how much nutrition //the item should be worth -/obj/belly/proc/digest_item(var/obj/item/item) +/obj/belly/proc/digest_item(obj/item/item) var/digested = item.digest_act(src, owner) if(!digested) items_preserved |= item @@ -482,6 +480,7 @@ if(isrobot(owner)) var/mob/living/silicon/robot/R = owner R.cell.charge += (50 * digested) + return digested //Determine where items should fall out of us into. //Typically just to the owner's location. @@ -499,20 +498,20 @@ /obj/belly/AllowDrop() return TRUE -/obj/belly/onDropInto(var/atom/movable/AM) +/obj/belly/onDropInto(atom/movable/AM) return null //Handle a mob struggling // Called from /mob/living/carbon/relaymove() -/obj/belly/proc/relay_resist(var/mob/living/R) +/obj/belly/proc/relay_resist(mob/living/R) if (!(R in contents)) return // User is not in this belly R.setClickCooldown(50) if(owner.stat) //If owner is stat (dead, KO) we can actually escape - to_chat(R,"You attempt to climb out of \the [lowertext(name)]. (This will take around [escapetime/10] seconds.)") - to_chat(owner,"Someone is attempting to climb out of your [lowertext(name)]!") + to_chat(R, "You attempt to climb out of \the [lowertext(name)]. (This will take around [escapetime/10] seconds.)") + to_chat(owner, "Someone is attempting to climb out of your [lowertext(name)]!") if(do_after(R, escapetime, owner, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) if((owner.stat || escapable) && (R.loc == src)) //Can still escape? @@ -528,20 +527,20 @@ var/struggle_outer_message = pick(struggle_messages_outside) var/struggle_user_message = pick(struggle_messages_inside) - struggle_outer_message = replacetext(struggle_outer_message,"%pred",owner) - struggle_outer_message = replacetext(struggle_outer_message,"%prey",R) - struggle_outer_message = replacetext(struggle_outer_message,"%belly",lowertext(name)) + struggle_outer_message = replacetext(struggle_outer_message, "%pred", owner) + struggle_outer_message = replacetext(struggle_outer_message, "%prey", R) + struggle_outer_message = replacetext(struggle_outer_message, "%belly", lowertext(name)) - struggle_user_message = replacetext(struggle_user_message,"%pred",owner) - struggle_user_message = replacetext(struggle_user_message,"%prey",R) - struggle_user_message = replacetext(struggle_user_message,"%belly",lowertext(name)) + struggle_user_message = replacetext(struggle_user_message, "%pred", owner) + struggle_user_message = replacetext(struggle_user_message, "%prey", R) + struggle_user_message = replacetext(struggle_user_message, "%belly", lowertext(name)) - struggle_outer_message = "" + struggle_outer_message + "" - struggle_user_message = "" + struggle_user_message + "" + struggle_outer_message = "[struggle_outer_message]" + struggle_user_message = "[struggle_user_message]" for(var/mob/M in hearers(4, owner)) M.show_message(struggle_outer_message, 2) // hearable - to_chat(R,struggle_user_message) + to_chat(R, struggle_user_message) var/sound/struggle_snuggle var/sound/struggle_rustle = sound(get_sfx("rustle")) @@ -557,8 +556,8 @@ if(escapable) //If the stomach has escapable enabled. if(prob(escapechance)) //Let's have it check to see if the prey escapes first. - to_chat(R,"You start to climb out of \the [lowertext(name)].") - to_chat(owner,"Someone is attempting to climb out of your [lowertext(name)]!") + to_chat(R, "You start to climb out of \the [lowertext(name)].") + to_chat(owner, "Someone is attempting to climb out of your [lowertext(name)]!") if(do_after(R, escapetime)) if((escapable) && (R.loc == src) && !R.absorbed) //Does the owner still have escapable enabled? release_specific_contents(R) @@ -588,26 +587,26 @@ transferlocation = null return - to_chat(R,"Your attempt to escape [lowertext(name)] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!") - to_chat(owner,"Someone slid into your [transferlocation] due to their struggling inside your [lowertext(name)]!") + to_chat(R, "Your attempt to escape [lowertext(name)] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!") + to_chat(owner, "Someone slid into your [transferlocation] due to their struggling inside your [lowertext(name)]!") transfer_contents(R, dest_belly) return else if(prob(absorbchance) && digest_mode != DM_ABSORB) //After that, let's have it run the absorb chance. - to_chat(R,"In response to your struggling, \the [lowertext(name)] begins to cling more tightly...") - to_chat(owner,"You feel your [lowertext(name)] start to cling onto its contents...") + to_chat(R, "In response to your struggling, \the [lowertext(name)] begins to cling more tightly...") + to_chat(owner, "You feel your [lowertext(name)] start to cling onto its contents...") digest_mode = DM_ABSORB return else if(prob(digestchance) && digest_mode != DM_DIGEST) //Finally, let's see if it should run the digest chance. - to_chat(R,"In response to your struggling, \the [lowertext(name)] begins to get more active...") - to_chat(owner,"You feel your [lowertext(name)] beginning to become active!") + to_chat(R, "In response to your struggling, \the [lowertext(name)] begins to get more active...") + to_chat(owner, "You feel your [lowertext(name)] beginning to become active!") digest_mode = DM_DIGEST return else //Nothing interesting happened. - to_chat(R,"You make no progress in escaping [owner]'s [lowertext(name)].") - to_chat(owner,"Your prey appears to be unable to make any progress in escaping your [lowertext(name)].") + to_chat(R, "You make no progress in escaping [owner]'s [lowertext(name)].") + to_chat(owner, "Your prey appears to be unable to make any progress in escaping your [lowertext(name)].") return /obj/belly/proc/get_mobs_and_objs_in_belly() @@ -624,7 +623,7 @@ return see //Transfers contents from one belly to another -/obj/belly/proc/transfer_contents(var/atom/movable/content, var/obj/belly/target, silent = 0) +/obj/belly/proc/transfer_contents(atom/movable/content, obj/belly/target, silent = 0) if(!(content in src) || !istype(target)) return content.forceMove(target) @@ -636,16 +635,6 @@ I.decontaminate() I.gurgle_contaminate(target.contents, target.contamination_flavor, target.contamination_color) items_preserved -= content - /* Disabling this part due to redundancy. Entered() on target belly will make the sound anyway. - if(!silent && target.vore_sound && !recent_sound) - var/soundfile - if(!target.fancy_vore) - soundfile = classic_vore_sounds[target.vore_sound] - else - soundfile = fancy_vore_sounds[target.vore_sound] - if(soundfile) - playsound(src, soundfile, vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF, preference = /datum/client_preference/digestion_noises) - */ owner.updateVRPanel() for(var/mob/living/M in contents) M.updateVRPanel() diff --git a/code/modules/vore/eating/bellymodes_tf_vr.dm b/code/modules/vore/eating/bellymodes_tf_vr.dm index d2a379a336..32a6e91a4c 100644 --- a/code/modules/vore/eating/bellymodes_tf_vr.dm +++ b/code/modules/vore/eating/bellymodes_tf_vr.dm @@ -1,4 +1,4 @@ -/obj/belly/proc/process_tf(var/mode,var/list/touchable_mobs) //We pass mode so it's mega-ultra local. +/obj/belly/proc/process_tf(mode, list/touchable_mobs) //We pass mode so it's mega-ultra local. /* May not be necessary... Transform only shows up in the panel for humans. if(!ishuman(owner)) return //Need DNA and junk for this. @@ -7,231 +7,86 @@ //Cast here for reduced duplication var/mob/living/carbon/human/O = owner -///////////////////////////// DM_TRANSFORM_HAIR_AND_EYES ///////////////////////////// - if(mode == DM_TRANSFORM_HAIR_AND_EYES) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) - continue + var/stabilize_nutrition = FALSE + var/changes_eyes = FALSE + var/changes_hair_solo = FALSE + var/changes_hairandskin = FALSE + var/changes_gender = FALSE + var/changes_gender_to = null + var/changes_species = FALSE + var/changes_ears_tail_wing_nocolor = FALSE + var/changes_ears_tail_wing_color = FALSE + var/eggs = FALSE - if(O.nutrition > 400 && P.nutrition < 400) + switch(mode) + if(DM_TRANSFORM_HAIR_AND_EYES) + stabilize_nutrition = TRUE + changes_eyes = TRUE + changes_hair_solo = TRUE + if(DM_TRANSFORM_MALE, DM_TRANSFORM_FEMALE, DM_TRANSFORM_MALE_EGG, DM_TRANSFORM_FEMALE_EGG) + changes_eyes = TRUE + changes_hairandskin = TRUE + changes_gender = TRUE + changes_gender_to = (mode == DM_TRANSFORM_MALE || mode == DM_TRANSFORM_MALE_EGG) ? MALE : FEMALE + stabilize_nutrition = TRUE + eggs = (mode == DM_TRANSFORM_MALE_EGG || mode == DM_TRANSFORM_FEMALE_EGG) + if(DM_TRANSFORM_KEEP_GENDER, DM_TRANSFORM_KEEP_GENDER_EGG) + changes_eyes = TRUE + changes_hairandskin = TRUE + stabilize_nutrition = TRUE + eggs = (mode == DM_TRANSFORM_KEEP_GENDER_EGG) + if(DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR, DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG) + changes_species = TRUE + changes_ears_tail_wing_nocolor = TRUE + stabilize_nutrition = TRUE + eggs = (mode == DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG) + if(DM_TRANSFORM_REPLICA, DM_TRANSFORM_REPLICA_EGG) + changes_eyes = TRUE + changes_hairandskin = TRUE + changes_species = TRUE + changes_ears_tail_wing_color = TRUE + eggs = (mode == DM_TRANSFORM_REPLICA_EGG) + if(DM_EGG) + eggs = TRUE + + /* This is designed to do *gradual* transformations. + * For each human in the TF belly per cycle, they can only have one "stage" of transformation applied to them. + * Some transformation modes have different amounts of stages than others and that's okay. + * All stages in order: Eyes, Hair & Skin, Ears & Tail & Wings & Species, Gender, Egg + */ + for(var/mob/living/carbon/human/H in touchable_mobs) + if(H.stat == DEAD) + continue + if(stabilize_nutrition) + if(O.nutrition > 400 && H.nutrition < 400) O.nutrition -= 2 - P.nutrition += 1.5 - - if(check_eyes(P) || check_hair(P)) - change_eyes(P) - change_hair(P,1) - -///////////////////////////// DM_TRANSFORM_MALE ///////////////////////////// - else if(mode == DM_TRANSFORM_MALE) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) + H.nutrition += 1.5 + if(changes_eyes && check_eyes(H)) + change_eyes(H, 1) + continue + if(changes_hair_solo && check_hair(H)) + change_hair(H) + continue + if(changes_hairandskin && (check_hair(H) || check_skin(H))) + change_hair(H) + change_skin(H, 1) + continue + if(changes_species) + if(changes_ears_tail_wing_nocolor && (check_ears(H) || check_tail_nocolor(H) || check_wing_nocolor(H) || check_species(H))) + change_ears(H) + change_tail_nocolor(H) + change_wing_nocolor(H) + change_species(H, 1, 1) // ,1) preserves coloring continue - - if(O.nutrition > 400 && P.nutrition < 400) - O.nutrition -= 2 - P.nutrition += 1.5 - - if(check_eyes(P)) - change_eyes(P,1) + if(changes_ears_tail_wing_color && (check_ears(H) || check_tail(H) || check_wing(H) || check_species(H))) + change_ears(H) + change_tail(H) + change_wing(H) + change_species(H, 1, 2) // ,2) does not preserve coloring. continue - - if(check_hair(P) || check_skin(P)) - change_hair(P) - change_skin(P,1) - continue - - if(check_gender(P,MALE)) - change_gender(P,MALE,1) - -///////////////////////////// DM_TRANSFORM_FEMALE ///////////////////////////// - else if(mode == DM_TRANSFORM_FEMALE) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) - continue - - if(O.nutrition > 400 && P.nutrition < 400) - O.nutrition -= 2 - P.nutrition += 1.5 - - if(check_eyes(P)) - change_eyes(P,1) - continue - - if(check_hair(P) || check_skin(P)) - change_hair(P) - change_skin(P,1) - continue - - if(check_gender(P,FEMALE)) - change_gender(P,FEMALE,1) - -///////////////////////////// DM_TRANSFORM_KEEP_GENDER ///////////////////////////// - else if(mode == DM_TRANSFORM_KEEP_GENDER) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) - continue - - if(O.nutrition > 400 && P.nutrition < 400) - O.nutrition -= 2 - P.nutrition += 1.5 - - if(check_eyes(P)) - change_eyes(P,1) - continue - - if(check_hair(P) || check_skin(P)) - change_hair(P) - change_skin(P,1) - -///////////////////////////// DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR ///////////////////////////// - else if(mode == DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) - continue - - if(O.nutrition > 400 && P.nutrition < 400) - O.nutrition -= 2 - P.nutrition += 1.5 - - if(check_ears(P) || check_tail_nocolor(P) || check_wing_nocolor(P) || check_species(P)) - change_ears(P) - change_tail_nocolor(P) - change_wing_nocolor(P) - change_species(P,1,1) - -///////////////////////////// DM_TRANSFORM_REPLICA ///////////////////////////// - else if(mode == DM_TRANSFORM_REPLICA) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) - continue - - if(O.nutrition > 400 && P.nutrition < 400) - O.nutrition -= 2 - P.nutrition += 1.5 - - if(check_eyes(P)) - change_eyes(P,1) - continue - - if(check_hair(P) || check_skin(P)) - change_hair(P) - change_skin(P,1) - continue - - if(check_ears(P) || check_tail(P) || check_wing(P) || check_species(P)) - change_ears(P) - change_tail(P) - change_wing(P) - change_species(P,1,2) - -///////////////////////////// DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG ///////////////////////////// - else if(mode == DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) - continue - - if(check_ears(P) || check_tail_nocolor(P) || check_wing_nocolor(P)|| check_species(P)) - change_ears(P) - change_tail_nocolor(P) - change_wing_nocolor(P) - change_species(P,1,1) - continue - - if(!P.absorbed) - put_in_egg(P,1) - -///////////////////////////// DM_TRANSFORM_KEEP_GENDER_EGG ///////////////////////////// - else if(mode == DM_TRANSFORM_KEEP_GENDER_EGG) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) - continue - - if(check_eyes(P)) - change_eyes(P,1) - continue - - if(check_hair(P) || check_skin(P)) - change_hair(P) - change_skin(P,1) - continue - - if(!P.absorbed) - put_in_egg(P,1) - -///////////////////////////// DM_TRANSFORM_REPLICA_EGG ///////////////////////////// - else if(mode == DM_TRANSFORM_REPLICA_EGG) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) - continue - - if(check_eyes(P)) - change_eyes(P,1) - continue - - if(check_hair(P) || check_skin(P)) - change_hair(P) - change_skin(P,1) - continue - - if(check_ears(P) || check_tail(P) || check_wing(P) || check_species(P)) - change_ears(P) - change_tail(P) - change_wing(P) - change_species(P,1,2) - continue - - if(!P.absorbed) - put_in_egg(P,1) - -///////////////////////////// DM_TRANSFORM_MALE_EGG ///////////////////////////// - else if(mode == DM_TRANSFORM_MALE_EGG) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) - continue - - if(check_eyes(P)) - change_eyes(P,1) - continue - - if(check_hair(P) || check_skin(P)) - change_hair(P) - change_skin(P,1) - continue - - if(check_gender(P,MALE)) - change_gender(P,MALE,1) - continue - - if(!P.absorbed) - put_in_egg(P,1) - -///////////////////////////// DM_TRANSFORM_FEMALE_EGG ///////////////////////////// - else if(mode == DM_TRANSFORM_FEMALE_EGG) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.stat == DEAD) - continue - - if(check_eyes(P)) - change_eyes(P,1) - continue - - if(check_hair(P) || check_skin(P)) - change_hair(P) - change_skin(P,1) - continue - - if(check_gender(P,MALE)) - change_gender(P,MALE,1) - continue - - if(!P.absorbed) - put_in_egg(P,1) - -///////////////////////////// DM_EGG ///////////////////////////// - else if(mode == DM_EGG) - for (var/mob/living/carbon/human/P in touchable_mobs) - if(P.absorbed || P.stat == DEAD) - continue - - put_in_egg(P,1) - + if(changes_gender && check_gender(H, changes_gender_to)) + change_gender(H, changes_gender_to, 1) + continue + if(eggs && (!H.absorbed)) + put_in_egg(H, 1) + continue \ No newline at end of file diff --git a/code/modules/vore/eating/bellymodes_vr.dm b/code/modules/vore/eating/bellymodes_vr.dm index 605fea6cd9..6bb6620c95 100644 --- a/code/modules/vore/eating/bellymodes_vr.dm +++ b/code/modules/vore/eating/bellymodes_vr.dm @@ -1,5 +1,5 @@ // Process the predator's effects upon the contents of its belly (i.e digestion/transformation etc) -/obj/belly/proc/process_belly(var/times_fired,var/wait) //Passed by controller +/obj/belly/proc/process_belly(times_fired, wait) //Passed by controller if((times_fired < next_process) || !contents.len) recent_sound = FALSE return SSBELLIES_IGNORED @@ -11,31 +11,13 @@ qdel(src) return SSBELLIES_PROCESSED - next_process = times_fired + (6 SECONDS/wait) //Set up our next process time. + next_process = times_fired + (6 SECONDS / wait) //Set up our next process time. + var/play_sound //Potential sound to play at the end to avoid code duplication. var/to_update = FALSE //Did anything update worthy happen? -/////////////////////////// Auto-Emotes /////////////////////////// - if(contents.len && next_emote <= times_fired) - next_emote = times_fired + round(emote_time/wait,1) - var/list/EL = emote_lists[digest_mode] - if(LAZYLEN(EL)) - for(var/mob/living/M in contents) - if(M.digestable || digest_mode != DM_DIGEST) // don't give digesty messages to indigestible people - to_chat(M,"[pick(EL)]") - ///////////////////// Prey Loop Refresh/hack ////////////////////// - for(var/mob/living/M in contents) - M.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case, because byond is whack and you can't trust it - if(isbelly(M.loc)) //sanity check - if(world.time > M.next_preyloop) //We don't want it to overlap, but we also want it to replay. - if(is_wet && wet_loop) // Is it a fleshy environment, and does the pred have a fleshy heartbeat loop to play? - if(!M.client) - continue - if(M.is_preference_enabled(/datum/client_preference/digestion_noises)) //then we check if the mob has sounds enabled at all - var/sound/preyloop = sound('sound/vore/sunesound/prey/loop.ogg') - M.playsound_local(get_turf(src),preyloop, 80,0, channel = CHANNEL_PREYLOOP) - M.next_preyloop = (world.time + (52 SECONDS)) + prey_loop() /////////////////////////// Sound Selections /////////////////////////// var/sound/prey_digest @@ -61,31 +43,30 @@ var/list/touchable_mobs = list() ///////////////////// Early Non-Mode Handling ///////////////////// - var/did_an_item = FALSE + if(contents.len && next_emote <= times_fired) + next_emote = times_fired + round(emote_time/wait,1) + var/list/EL = emote_lists[digest_mode] + if(LAZYLEN(EL)) + for(var/mob/living/M in contents) + if(M.digestable || digest_mode != DM_DIGEST) // don't give digesty messages to indigestible people + to_chat(M, "[pick(EL)]") + + var/did_an_item = FALSE // Only do one item per cycle. + var/digestion_noise_chance = 0 + for(var/A in touchable_atoms) //Handle stray items if(isitem(A) && !did_an_item) - var/obj/item/I = A - if(contaminates || istype(I,/obj/item/weapon/card/id)) - I.gurgle_contaminate(src, contamination_flavor, contamination_color) - if(item_digest_mode == IM_HOLD) - items_preserved |= I - else if(item_digest_mode == IM_DIGEST_FOOD) - if(istype(I,/obj/item/weapon/reagent_containers/food) || istype(I,/obj/item/organ)) - digest_item(I) - else - items_preserved |= I - if(prob(25)) //Less often than with normal digestion - play_sound = pick(pred_digest) - else if(item_digest_mode == IM_DIGEST) - if(I.digest_stage && I.digest_stage > 0) - digest_item(I) - else - digest_item(I) - did_an_item = TRUE + did_an_item = handle_digesting_item(A) + if(did_an_item) to_update = TRUE - if(prob(25)) //Less often than with normal digestion - play_sound = pick(pred_digest) + + //Less often than with normal digestion + if((item_digest_mode == IM_DIGEST_FOOD || item_digest_mode == IM_DIGEST) && prob(25)) + // This is a little weird, but the point of it is that we don't want to repeat code + // but we also want the prob(25) chance to run for -every- item we look at, not just once + // More gurgles the better~ + digestion_noise_chance = 25 //Handle eaten mobs else if(isliving(A)) @@ -105,278 +86,218 @@ H.bloodstr.add_reagent("numbenzyme",4) //Thickbelly flag - if(mode_flags & DM_FLAG_THICKBELLY) - if(!(H.muffled)) - H.muffled = 1 + if((mode_flags & DM_FLAG_THICKBELLY) && !H.muffled) + H.muffled = TRUE //Stripping flag if(mode_flags & DM_FLAG_STRIPPING) for(var/slot in slots) var/obj/item/I = H.get_equipped_item(slot = slot) - if(I) - H.unEquip(I,force = FALSE) - if(contaminates || istype(I,/obj/item/weapon/card/id)) - I.gurgle_contaminate(contents, contamination_flavor, contamination_color) - if(item_digest_mode == IM_HOLD) - items_preserved |= I - else if(item_digest_mode == IM_DIGEST_FOOD) - if(istype(I,/obj/item/weapon/reagent_containers/food) || istype(I,/obj/item/organ)) - digest_item(I) - else - items_preserved |= I - if(prob(25)) //Less often than with normal digestion - if(L && L.client && L.is_preference_enabled(/datum/client_preference/digestion_noises)) - SEND_SOUND(L,prey_digest) - play_sound = pick(pred_digest) - else if(item_digest_mode == IM_DIGEST) - digest_item(I) - if(prob(25)) //Less often than with normal digestion - if(L && L.client && L.is_preference_enabled(/datum/client_preference/digestion_noises)) - SEND_SOUND(L,prey_digest) - play_sound = pick(pred_digest) + if(I && H.unEquip(I, force = FALSE)) + handle_digesting_item(I) + digestion_noise_chance = 25 to_update = TRUE - break + break // Digest off one by one, not all at once + //get rid of things like blood drops and gibs that end up in there - else if(istype(A,/obj/effect/decal/cleanable/)) + else if(istype(A, /obj/effect/decal/cleanable)) qdel(A) -///////////////////////////// DM_HOLD ///////////////////////////// if(digest_mode == DM_HOLD) - return SSBELLIES_PROCESSED //Pretty boring, huh + //We deliberately do not want any gurgly noises if the belly is in DM_HOLD + if(to_update) + updateVRPanels() + return SSBELLIES_PROCESSED -//////////////////////////// DM_DIGEST //////////////////////////// - else if(digest_mode == DM_DIGEST) - - if(prob(50)) //Was SO OFTEN. AAAA. - for(var/mob/M in contents) - if(M && M.client && M.is_preference_enabled(/datum/client_preference/digestion_noises)) - SEND_SOUND(M,prey_digest) - play_sound = pick(pred_digest) - - for (var/target in touchable_mobs) - var/mob/living/M = target - //Pref protection! - if (!M.digestable || M.absorbed) - continue - - //Person just died in guts! - if(M.stat == DEAD) - var/digest_alert_owner = pick(digest_messages_owner) - var/digest_alert_prey = pick(digest_messages_prey) - var/compensation = M.getOxyLoss() //How much of the prey's damage was caused by passive crit oxyloss to compensate the lost nutrition. - - //Replace placeholder vars - digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner) - digest_alert_owner = replacetext(digest_alert_owner,"%prey",M) - digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name)) - - digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner) - digest_alert_prey = replacetext(digest_alert_prey,"%prey",M) - digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name)) - - //Send messages - to_chat(owner,"" + digest_alert_owner + "") - to_chat(M,"" + digest_alert_prey + "") - - play_sound = pick(pred_death) - if(M && M.client && M.is_preference_enabled(/datum/client_preference/digestion_noises)) - SEND_SOUND(M,prey_death) - if((mode_flags & DM_FLAG_LEAVEREMAINS) && M.digest_leave_remains) - handle_remains_leaving(M) - digestion_death(M) - if(!ishuman(owner)) - owner.update_icons() - if(compensation == 0) //Slightly sloppy way at making sure certain mobs don't give ZERO nutrition (fish and so on) - compensation = 21 //This reads as 20*4.5 due to the calculations afterward, making the backup nutrition value 94.5 per mob. Not op compared to regular prey. - if(compensation > 0) - if(isrobot(owner)) - var/mob/living/silicon/robot/R = owner - R.cell.charge += 25*compensation - else - owner.nutrition += (nutrition_percent / 100)*4.5*compensation - to_update = TRUE - - continue - - // Deal digestion damage (and feed the pred) - var/old_brute = M.getBruteLoss() - var/old_burn = M.getFireLoss() - M.adjustBruteLoss(digest_brute) - M.adjustFireLoss(digest_burn) - var/actual_brute = M.getBruteLoss() - old_brute - var/actual_burn = M.getFireLoss() - old_burn - var/damage_gain = actual_brute + actual_burn - - var/offset = (1 + ((M.weight - 137) / 137)) // 130 pounds = .95 140 pounds = 1.02 - var/difference = owner.size_multiplier / M.size_multiplier - if(isrobot(owner)) - var/mob/living/silicon/robot/R = owner - R.cell.charge += 25*damage_gain - if(offset) // If any different than default weight, multiply the % of offset. - owner.nutrition += offset*((nutrition_percent / 100)*4.5*(damage_gain)/difference) //4.5 nutrition points per health point. Normal same size 100+100 health prey with average weight would give 900 points if the digestion was instant. With all the size/weight offset taxes plus over time oxyloss+hunger taxes deducted with non-instant digestion, this should be enough to not leave the pred starved. - else - owner.nutrition += (nutrition_percent / 100)*4.5*(damage_gain)/difference - - -//////////////////////////// DM_ABSORB //////////////////////////// - else if(digest_mode == DM_ABSORB) - - for (var/target in touchable_mobs) - var/mob/living/M = target - if(M.absorbable == FALSE) - return - else - if(prob(10)) //Less often than gurgles. People might leave this on forever. - if(M && M.client && M.is_preference_enabled(/datum/client_preference/digestion_noises)) - SEND_SOUND(M,prey_digest) - play_sound = pick(pred_digest) - - if(M.absorbed) - continue - - if(M.nutrition >= 100) //Drain them until there's no nutrients left. Slowly "absorb" them. - var/oldnutrition = (M.nutrition * 0.05) - M.nutrition = (M.nutrition * 0.95) - owner.nutrition += oldnutrition - else if(M.nutrition < 100) //When they're finally drained. - absorb_living(M) - to_update = TRUE - -//////////////////////////// DM_UNABSORB //////////////////////////// - else if(digest_mode == DM_UNABSORB) - - for (var/target in touchable_mobs) - var/mob/living/M = target - - if(M.absorbed && owner.nutrition >= 100) - M.absorbed = 0 - to_chat(M,"You suddenly feel solid again ") - to_chat(owner,"You feel like a part of you is missing.") - owner.nutrition -= 100 - to_update = TRUE - -//////////////////////////// DM_DRAIN //////////////////////////// - else if(digest_mode == DM_DRAIN) - - for (var/target in touchable_mobs) - var/mob/living/M = target - - if(prob(10)) //Less often than gurgles. People might leave this on forever. - if(M && M.client && M.is_preference_enabled(/datum/client_preference/digestion_noises)) - SEND_SOUND(M,prey_digest) - play_sound = pick(pred_digest) - - if(M.nutrition >= 100) //Drain them until there's no nutrients left. - var/oldnutrition = (M.nutrition * 0.05) - M.nutrition = (M.nutrition * 0.95) - owner.nutrition += oldnutrition - -//////////////////////////// DM_SHRINK //////////////////////////// - else if(digest_mode == DM_SHRINK) - - for (var/target in touchable_mobs) - var/mob/living/M = target - - if(prob(10)) //Infinite gurgles! - if(M && M.client && M.is_preference_enabled(/datum/client_preference/digestion_noises)) - SEND_SOUND(M,prey_digest) - play_sound = pick(pred_digest) - - if(M.size_multiplier > shrink_grow_size) //Shrink until smol. - M.resize(M.size_multiplier-0.01) //Shrink by 1% per tick. - - if(M.nutrition >= 100) //Absorbing bodymass results in nutrition if possible. - var/oldnutrition = (M.nutrition * 0.05) - M.nutrition = (M.nutrition * 0.95) - owner.nutrition += oldnutrition - -//////////////////////////// DM_GROW //////////////////////////// - else if(digest_mode == DM_GROW) - - for (var/target in touchable_mobs) - var/mob/living/M = target - - if(prob(10)) - if(M && M.client && M.is_preference_enabled(/datum/client_preference/digestion_noises)) - SEND_SOUND(M,prey_digest) - play_sound = pick(pred_digest) - - if(M.size_multiplier < shrink_grow_size) //Grow until large. - M.resize(M.size_multiplier+0.01) //Grow by 1% per tick. - if(M.nutrition >= 100) - owner.nutrition = (owner.nutrition * 0.95) - -//////////////////////////// DM_SIZE_STEAL //////////////////////////// - else if(digest_mode == DM_SIZE_STEAL) - - for (var/target in touchable_mobs) - var/mob/living/M = target - - if(prob(10)) - if(M && M.client && M.is_preference_enabled(/datum/client_preference/digestion_noises)) - SEND_SOUND(M,prey_digest) - play_sound = pick(pred_digest) - - if(M.size_multiplier > shrink_grow_size && owner.size_multiplier < 2) //Grow until either pred is large or prey is small. - owner.resize(owner.size_multiplier+0.01) //Grow by 1% per tick. - M.resize(M.size_multiplier-0.01) //Shrink by 1% per tick - - if(M.nutrition >= 100) - var/oldnutrition = (M.nutrition * 0.05) - M.nutrition = (M.nutrition * 0.95) - owner.nutrition += oldnutrition - -///////////////////////////// DM_HEAL ///////////////////////////// - else if(digest_mode == DM_HEAL) - - if(prob(50)) //Wet heals! The secret is you can leave this on for gurgle noises for fun. - for(var/mob/M in contents) - if(M && M.client && M.is_preference_enabled(/datum/client_preference/digestion_noises)) - SEND_SOUND(M,prey_digest) - play_sound = pick(pred_digest) - - for (var/target in touchable_mobs) - var/mob/living/M = target - - if(M.stat == DEAD) - continue - - if(owner.nutrition > 90 && (M.health < M.maxHealth)) - M.adjustBruteLoss(-2.5) - M.adjustFireLoss(-2.5) - M.adjustToxLoss(-5) - M.adjustOxyLoss(-5) - M.adjustCloneLoss(-1.25) - owner.nutrition -= 2 - if(M.nutrition <= 400) - M.nutrition += 1 - else if(owner.nutrition > 90 && (M.nutrition <= 400)) - owner.nutrition -= 1 - M.nutrition += 1 - -/////////////////////////// DM_TRANSFORM /////////////////////////// - else if(digest_mode == DM_TRANSFORM) + if(digest_mode == DM_TRANSFORM) process_tf(tf_mode, touchable_mobs) + for(var/target in touchable_mobs) + var/mob/living/L = target + if(!istype(L)) + continue + switch(digest_mode) + if(DM_DIGEST) + digestion_noise_chance = 50 + //Pref protection! + if(!L.digestable || L.absorbed) + continue + + //Person just died in guts! + if(L.stat == DEAD) + play_sound = pred_death + if(L.is_preference_enabled(/datum/client_preference/digestion_noises)) + SEND_SOUND(L, prey_death) + handle_digestion_death(L) + to_update = TRUE + continue + + // Deal digestion damage (and feed the pred) + var/old_brute = L.getBruteLoss() + var/old_burn = L.getFireLoss() + L.adjustBruteLoss(digest_brute) + L.adjustFireLoss(digest_burn) + var/actual_brute = L.getBruteLoss() - old_brute + var/actual_burn = L.getFireLoss() - old_burn + var/damage_gain = actual_brute + actual_burn + + var/offset = (1 + ((L.weight - 137) / 137)) // 130 pounds = .95 140 pounds = 1.02 + var/difference = owner.size_multiplier / L.size_multiplier + if(isrobot(owner)) + var/mob/living/silicon/robot/R = owner + R.cell.charge += 25 * damage_gain + if(offset) // If any different than default weight, multiply the % of offset. + owner.nutrition += offset*((nutrition_percent / 100) * 4.5 * (damage_gain) / difference) //4.5 nutrition points per health point. Normal same size 100+100 health prey with average weight would give 900 points if the digestion was instant. With all the size/weight offset taxes plus over time oxyloss+hunger taxes deducted with non-instant digestion, this should be enough to not leave the pred starved. + else + owner.nutrition += (nutrition_percent / 100) * 4.5 * (damage_gain) / difference + if(DM_ABSORB) + if(!L.absorbable || L.absorbed) + continue + digestion_noise_chance = 10 + steal_nutrition(L) + if(L.nutrition < 100) + absorb_living(L) + to_update = TRUE + if(DM_UNABSORB) + if(L.absorbed && owner.nutrition >= 100) + L.absorbed = FALSE + to_chat(L, "You suddenly feel solid again.") + to_chat(owner,"You feel like a part of you is missing.") + owner.nutrition -= 100 + to_update = TRUE + if(DM_DRAIN) + digestion_noise_chance = 10 + steal_nutrition(L) + if(DM_SHRINK) + digestion_noise_chance = 10 + if(L.size_multiplier > shrink_grow_size) + L.resize(L.size_multiplier - 0.01) // Shrink by 1% per tick + steal_nutrition(L) + if(DM_GROW) + digestion_noise_chance = 10 + if(L.size_multiplier < shrink_grow_size) + L.resize(L.size_multiplier - 0.01) // Grow by 1% per tick + if(DM_SIZE_STEAL) + digestion_noise_chance = 10 + if(L.size_multiplier > shrink_grow_size && owner.size_multiplier < 2) //Grow until either pred is large or prey is small. + owner.resize(owner.size_multiplier+0.01) //Grow by 1% per tick. + L.resize(L.size_multiplier-0.01) //Shrink by 1% per tick + steal_nutrition(L) + if(DM_HEAL) + digestion_noise_chance = 50 //Wet heals! The secret is you can leave this on for gurgle noises for fun. + if(L.stat == DEAD) + continue // Can't heal the dead with healbelly + if(owner.nutrition > 90 && (L.health < L.maxHealth)) + L.adjustBruteLoss(-2.5) + L.adjustFireLoss(-2.5) + L.adjustToxLoss(-5) + L.adjustOxyLoss(-5) + L.adjustCloneLoss(-1.25) + owner.nutrition -= 2 + if(L.nutrition <= 400) + L.nutrition += 1 + else if(owner.nutrition > 90 && (L.nutrition <= 400)) + owner.nutrition -= 1 + L.nutrition += 1 + /////////////////////////// Make any noise /////////////////////////// + if(digestion_noise_chance && prob(digestion_noise_chance)) + for(var/mob/M in contents) + if(M && M.is_preference_enabled(/datum/client_preference/digestion_noises)) + SEND_SOUND(M, prey_digest) + play_sound = pred_digest + if(play_sound) - LAZYCLEARLIST(hearing_mobs) - for(var/mob/M in hearers(VORE_SOUND_RANGE, owner)) - if(!M.client || !(M.is_preference_enabled(/datum/client_preference/digestion_noises))) + for(var/mob/M in hearers(VORE_SOUND_RANGE, owner)) //so we don't fill the whole room with the sound effect + if(!M.is_preference_enabled(/datum/client_preference/digestion_noises)) continue - LAZYADD(hearing_mobs, M) - for(var/mob/M in hearing_mobs) //so we don't fill the whole room with the sound effect - if(M && M.client && (isturf(M.loc) || (M.loc != src.contents))) //to avoid people on the inside getting the outside sounds and their direct sounds + built in sound pref check + if(isturf(M.loc) || (M.loc != src)) //to avoid people on the inside getting the outside sounds and their direct sounds + built in sound pref check if(fancy_vore) M.playsound_local(owner.loc, play_sound, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF) else M.playsound_local(owner.loc, play_sound, vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF) //these are all external sound triggers now, so it's ok. + if(to_update) - for(var/mob/living/M in contents) - if(M.client) - M.updateVRPanel() - if(owner.client) - owner.updateVRPanel() + updateVRPanels() return SSBELLIES_PROCESSED + +/obj/belly/proc/prey_loop() + for(var/mob/living/M in contents) + //We don't bother executing any other code if the prey doesn't want to hear the noises. + if(!M.is_preference_enabled(/datum/client_preference/digestion_noises)) + M.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case, because byond is whack and you can't trust it + continue + + // We don't want the sounds to overlap, but we do want them to steadily replay. + // We also don't want the sounds to play if the pred hasn't marked this belly as fleshy, or doesn't + // have the right sounds to play. + if(isbelly(M.loc) && is_wet && wet_loop && (world.time > M.next_preyloop)) + M.stop_sound_channel(CHANNEL_PREYLOOP) + var/sound/preyloop = sound('sound/vore/sunesound/prey/loop.ogg') + M.playsound_local(get_turf(src), preyloop, 80, 0, channel = CHANNEL_PREYLOOP) + M.next_preyloop = (world.time + (52 SECONDS)) + +/obj/belly/proc/handle_digesting_item(obj/item/I) + var/did_an_item = FALSE + // We always contaminate IDs. + if(contaminates || istype(I, /obj/item/weapon/card/id)) + I.gurgle_contaminate(src, contamination_flavor, contamination_color) + + switch(item_digest_mode) + if(IM_HOLD) + items_preserved |= I + if(IM_DIGEST_FOOD) + if(istype(I,/obj/item/weapon/reagent_containers/food) || istype(I, /obj/item/organ)) + did_an_item = digest_item(I) + else + items_preserved |= I + if(IM_DIGEST) + did_an_item = digest_item(I) + return did_an_item + +/obj/belly/proc/handle_digestion_death(mob/living/M) + var/digest_alert_owner = pick(digest_messages_owner) + var/digest_alert_prey = pick(digest_messages_prey) + var/compensation = M.getOxyLoss() //How much of the prey's damage was caused by passive crit oxyloss to compensate the lost nutrition. + + //Replace placeholder vars + digest_alert_owner = replacetext(digest_alert_owner, "%pred", owner) + digest_alert_owner = replacetext(digest_alert_owner, "%prey", M) + digest_alert_owner = replacetext(digest_alert_owner, "%belly", lowertext(name)) + + digest_alert_prey = replacetext(digest_alert_prey, "%pred", owner) + digest_alert_prey = replacetext(digest_alert_prey, "%prey", M) + digest_alert_prey = replacetext(digest_alert_prey, "%belly", lowertext(name)) + + //Send messages + to_chat(owner, "[digest_alert_owner]") + to_chat(M, "[digest_alert_prey]") + + if((mode_flags & DM_FLAG_LEAVEREMAINS) && M.digest_leave_remains) + handle_remains_leaving(M) + digestion_death(M) + if(!ishuman(owner)) + owner.update_icons() + if(compensation == 0) //Slightly sloppy way at making sure certain mobs don't give ZERO nutrition (fish and so on) + compensation = 21 //This reads as 20*4.5 due to the calculations afterward, making the backup nutrition value 94.5 per mob. Not op compared to regular prey. + if(compensation > 0) + if(isrobot(owner)) + var/mob/living/silicon/robot/R = owner + R.cell.charge += 25*compensation + else + owner.nutrition += (nutrition_percent / 100)*4.5*compensation + +/obj/belly/proc/steal_nutrition(mob/living/L) + if(L.nutrition >= 100) + var/oldnutrition = (L.nutrition * 0.05) + L.nutrition = (L.nutrition * 0.95) + owner.nutrition += oldnutrition + +/obj/belly/proc/updateVRPanels() + for(var/mob/living/M in contents) + if(M.client) + M.updateVRPanel() + if(owner.client) + owner.updateVRPanel() \ No newline at end of file diff --git a/code/modules/vore/eating/contaminate_vr.dm b/code/modules/vore/eating/contaminate_vr.dm index 774d33331a..5bbbe902c7 100644 --- a/code/modules/vore/eating/contaminate_vr.dm +++ b/code/modules/vore/eating/contaminate_vr.dm @@ -22,7 +22,7 @@ var/list/gurgled_overlays = list( var/cleandesc var/gurgled_color -/obj/item/proc/gurgle_contaminate(var/atom/movable/item_storage = null, var/contamination_flavor = "Generic", var/contamination_color = "green") +/obj/item/proc/gurgle_contaminate(atom/movable/item_storage = null, contamination_flavor = "Generic", contamination_color = "green") if(!can_gurgle()) return FALSE @@ -65,28 +65,16 @@ var/list/gurgled_overlays = list( if(gurgled) decontaminate() -/obj/structure/sink/attackby(obj/item/O as obj, mob/user as mob) //Wash the soggy item before it can interact with the sink. - if(O.gurgled) - var/turf/location = user.loc - if(!isturf(location)) return - - var/obj/item/I = O - if(!I || !istype(I,/obj/item)) return - - to_chat(usr, "You start washing \the [I].") +/obj/structure/sink/attackby(obj/item/I, mob/user) //Wash the soggy item before it can interact with the sink. + if(istype(I) && I.gurgled) + to_chat(user, "You start washing [I].") busy = TRUE - sleep(40) + if(do_after(user, 40, src)) + I.clean_blood() + user.visible_message("[user] washes [I] using [src].", + "You wash [I] using [src].") busy = FALSE - - if(user.loc != location) return //User has moved - if(!I) return //Item's been destroyed while washing - if(user.get_active_hand() != I) return //Person has switched hands or the item in their hands - - O.clean_blood() - user.visible_message( \ - "[user] washes \a [I] using \the [src].", \ - "You wash \a [I] using \the [src].") else ..() diff --git a/code/modules/vore/eating/digest_act_vr.dm b/code/modules/vore/eating/digest_act_vr.dm index e9cf239e66..df59ffb35d 100644 --- a/code/modules/vore/eating/digest_act_vr.dm +++ b/code/modules/vore/eating/digest_act_vr.dm @@ -3,10 +3,10 @@ //return non-negative integer: Amount of nutrition/charge gained (scaled to nutrition, other end can multiply for charge scale). // Ye default implementation. -/obj/item/proc/digest_act(var/atom/movable/item_storage = null) - if(istype(item_storage,/obj/item/device/dogborg/sleeper)) +/obj/item/proc/digest_act(atom/movable/item_storage = null) + if(istype(item_storage, /obj/item/device/dogborg/sleeper)) for(var/obj/item/O in contents) - if(istype(O,/obj/item/weapon/storage/internal)) //Dump contents from dummy pockets. + if(istype(O, /obj/item/weapon/storage/internal)) //Dump contents from dummy pockets. for(var/obj/item/SO in O) if(item_storage) SO.forceMove(item_storage) @@ -15,12 +15,15 @@ O.forceMove(item_storage) qdel(src) return w_class + var/g_damage = 1 if(digest_stage == null) digest_stage = w_class + if(isbelly(item_storage)) var/obj/belly/B = item_storage g_damage = 0.25 * (B.digest_brute + B.digest_burn) + if(digest_stage > 0) if(g_damage > digest_stage) g_damage = digest_stage @@ -65,16 +68,16 @@ // Some special treatment ///////////// //PDAs need to lose their ID to not take it with them, so we can get a digested ID -/obj/item/device/pda/digest_act(var/atom/movable/item_storage = null) +/obj/item/device/pda/digest_act(atom/movable/item_storage = null) if(id) - if(istype(item_storage,/obj/item/device/dogborg/sleeper) || (!isnull(digest_stage) && digest_stage <= 0)) + if(istype(item_storage, /obj/item/device/dogborg/sleeper) || (!isnull(digest_stage) && digest_stage <= 0)) id = null . = ..() /obj/item/weapon/card/id var/lost_access = list() -/obj/item/weapon/card/id/digest_act(var/atom/movable/item_storage = null) +/obj/item/weapon/card/id/digest_act(atom/movable/item_storage = null) desc = "A partially digested card that has seen better days. The damage appears to be only cosmetic, but the access codes need to be reprogrammed at the HoP office." icon = 'icons/obj/card_vr.dmi' icon_state = "[initial(icon_state)]_digested" @@ -83,7 +86,7 @@ access = list() // Then lose it return FALSE -/obj/item/weapon/reagent_containers/food/digest_act(var/atom/movable/item_storage = null) +/obj/item/weapon/reagent_containers/food/digest_act(atom/movable/item_storage = null) if(isbelly(item_storage)) var/obj/belly/B = item_storage if(ishuman(B.owner)) @@ -96,7 +99,7 @@ return w_class . = ..() -/obj/item/weapon/holder/digest_act(var/atom/movable/item_storage = null) +/obj/item/weapon/holder/digest_act(atom/movable/item_storage = null) for(var/mob/living/M in contents) if(item_storage) M.forceMove(item_storage) @@ -104,7 +107,7 @@ . = ..() -/obj/item/organ/digest_act(var/atom/movable/item_storage = null) +/obj/item/organ/digest_act(atom/movable/item_storage = null) if((. = ..())) if(isbelly(item_storage)) var/obj/belly/B = item_storage @@ -112,7 +115,7 @@ else . += 30 //Organs give a little more -/obj/item/weapon/storage/digest_act(var/atom/movable/item_storage = null) +/obj/item/weapon/storage/digest_act(atom/movable/item_storage = null) for(var/obj/item/I in contents) I.screen_loc = null @@ -121,7 +124,7 @@ ///////////// // Some more complicated stuff ///////////// -/obj/item/device/mmi/digital/posibrain/digest_act(var/atom/movable/item_storage = null) +/obj/item/device/mmi/digital/posibrain/digest_act(atom/movable/item_storage = null) //Replace this with a VORE setting so all types of posibrains can/can't be digested on a whim return FALSE diff --git a/code/modules/vore/eating/leave_remains_vr.dm b/code/modules/vore/eating/leave_remains_vr.dm index 84374b44fe..a95adb094b 100644 --- a/code/modules/vore/eating/leave_remains_vr.dm +++ b/code/modules/vore/eating/leave_remains_vr.dm @@ -1,72 +1,62 @@ +/datum/species + var/skull_type = /obj/item/weapon/digestion_remains/skull +/datum/species/tajaran + skull_type = /obj/item/weapon/digestion_remains/skull/tajaran +/datum/species/unathi + skull_type = /obj/item/weapon/digestion_remains/skull/unathi +/datum/species/skrell + skull_type = /obj/item/weapon/digestion_remains/skull/skrell +/datum/species/spider + skull_type = /obj/item/weapon/digestion_remains/skull/vasilissan +/datum/species/akula + skull_type = /obj/item/weapon/digestion_remains/skull/akula +/datum/species/harpy + skull_type = /obj/item/weapon/digestion_remains/skull/rapala +/datum/species/vulpkanin + skull_type = /obj/item/weapon/digestion_remains/skull/vulpkanin +/datum/species/sergal + skull_type = /obj/item/weapon/digestion_remains/skull/sergal +/datum/species/hi_zorren + skull_type = /obj/item/weapon/digestion_remains/skull/zorren +/datum/species/nevrean + skull_type = /obj/item/weapon/digestion_remains/skull/nevrean +/datum/species/teshari + skull_type = /obj/item/weapon/digestion_remains/skull/teshari +/datum/species/vox + skull_type = /obj/item/weapon/digestion_remains/skull/vox + /obj/belly/proc/handle_remains_leaving(var/mob/living/M) - - if(istype(M,/mob/living/carbon/human)) //Are we even humanoid? - var/mob/living/carbon/human/H = M - - if((H.species.name in remainless_species) || H.isSynthetic()) //Don't leave anything if there is nothing to leave - return - - else - var/bones_amount = rand(2,3) //some random variety in amount of bones left - - if(prob(20)) //ribcage surviving whole is some luck - new /obj/item/weapon/digestion_remains/ribcage(src,owner) - bones_amount-- - - while(bones_amount) //throw in the rest - new /obj/item/weapon/digestion_remains(src,owner) - bones_amount-- - - var/skull_amount = 1 - switch(H.species.name) //oh boy here we go, finding us a right skull - if(SPECIES_HUMAN) - new /obj/item/weapon/digestion_remains/skull(src,owner) - skull_amount-- - if(SPECIES_TAJ) - new /obj/item/weapon/digestion_remains/skull/tajaran(src,owner) - skull_amount-- - if(SPECIES_UNATHI) - new /obj/item/weapon/digestion_remains/skull/unathi(src,owner) - skull_amount-- - if(SPECIES_SKRELL) - new /obj/item/weapon/digestion_remains/skull/skrell(src,owner) - skull_amount-- - if(SPECIES_VASILISSAN) - new /obj/item/weapon/digestion_remains/skull/vasilissan(src,owner) - skull_amount-- - if(SPECIES_AKULA) - new /obj/item/weapon/digestion_remains/skull/akula(src,owner) - skull_amount-- - if(SPECIES_RAPALA) - new /obj/item/weapon/digestion_remains/skull/rapala(src,owner) - skull_amount-- - if(SPECIES_VULPKANIN) - new /obj/item/weapon/digestion_remains/skull/vulpkanin(src,owner) - skull_amount-- - if(SPECIES_SERGAL) - new /obj/item/weapon/digestion_remains/skull/sergal(src,owner) - skull_amount-- - if(SPECIES_ZORREN_HIGH) - new /obj/item/weapon/digestion_remains/skull/zorren(src,owner) - skull_amount-- - if(SPECIES_NEVREAN) - new /obj/item/weapon/digestion_remains/skull/nevrean(src,owner) - skull_amount-- - if(SPECIES_TESHARI) - new /obj/item/weapon/digestion_remains/skull/teshari(src,owner) - skull_amount-- - if(SPECIES_VOX) - new /obj/item/weapon/digestion_remains/skull/vox(src,owner) - skull_amount-- - if(skull_amount && H.species.selects_bodytype) //We still haven't found correct skull... - if(H.species.base_species == SPECIES_HUMAN) - new /obj/item/weapon/digestion_remains/skull/unknown(src,owner) - else - new /obj/item/weapon/digestion_remains/skull/unknown/anthro(src,owner) - else if(skull_amount) //Something entirely different... - new /obj/item/weapon/digestion_remains/skull/unknown(src,owner) - else + if(!ishuman(M)) //Are we even humanoid? return + var/mob/living/carbon/human/H = M + + if((H.species.name in remainless_species) || H.isSynthetic()) //Don't leave anything if there is nothing to leave + return + + var/bones_amount = rand(2,3) //some random variety in amount of bones left + if(prob(20)) //ribcage surviving whole is some luck + new /obj/item/weapon/digestion_remains/ribcage(src,owner) + bones_amount-- + + while(bones_amount) //throw in the rest + new /obj/item/weapon/digestion_remains(src,owner) + bones_amount-- + + var/skull_amount = 1 + if(H.species.skull_type) + new H.species.skull_type(src, owner) + skull_amount-- + + if(skull_amount && H.species.selects_bodytype) + // We still haven't found correct skull... + if(H.species.base_species == SPECIES_HUMAN) + new /obj/item/weapon/digestion_remains/skull/unknown(src,owner) + else + new /obj/item/weapon/digestion_remains/skull/unknown/anthro(src,owner) + else if(skull_amount) + // Something entirely different... + new /obj/item/weapon/digestion_remains/skull/unknown(src,owner) + /obj/item/weapon/digestion_remains name = "bone" @@ -80,7 +70,7 @@ var/pred_ckey var/pred_name -/obj/item/weapon/digestion_remains/New(var/newloc,var/mob/living/pred) +/obj/item/weapon/digestion_remains/New(newloc, mob/living/pred) ..(newloc) pred_ckey = pred.ckey pred_name = pred.name diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 3a100d212e..e890b00883 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -19,7 +19,6 @@ var/metabolism = 0.0015 var/vore_taste = null // What the character tastes like var/no_vore = FALSE // If the character/mob can vore. - var/openpanel = FALSE // Is the vore panel open? var/noisy = FALSE // Toggle audible hunger. var/absorbing_prey = 0 // Determines if the person is using the succubus drain or not. See station_special_abilities_vr. var/drain_finalized = 0 // Determines if the succubus drain will be KO'd/absorbed. Can be toggled on at any time. @@ -41,6 +40,7 @@ M.verbs += /mob/living/proc/switch_scaling if(M.no_vore) //If the mob isn't supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach. return TRUE + M.vorePanel = new M.verbs += /mob/living/proc/insidePanel //Tries to load prefs if a client is present otherwise gives freebie stomach @@ -88,26 +88,25 @@ // // Handle being clicked, perhaps with something to devour // -/mob/living/proc/vore_attackby(obj/item/I,mob/user) +/mob/living/proc/vore_attackby(obj/item/I, mob/user) //Handle case: /obj/item/weapon/grab - if(istype(I,/obj/item/weapon/grab)) + if(istype(I, /obj/item/weapon/grab)) var/obj/item/weapon/grab/G = I //Has to be aggressive grab, has to be living click-er and non-silicon grabbed - if((G.state >= GRAB_AGGRESSIVE) && (isliving(user) && !issilicon(G.affecting))) - + if(G.state >= GRAB_AGGRESSIVE && (isliving(user) && !issilicon(G.affecting))) var/mob/living/attacker = user // Typecast to living // src is the mob clicked on and attempted predator ///// If user clicked on themselves - if((src == G.assailant) && (is_vore_predator(src))) - if(!(G.affecting.devourable)) + if(src == G.assailant && is_vore_predator(src)) + if(!G.affecting.devourable) to_chat(user, "They aren't able to be devoured.") - log_and_message_admins("[key_name(src)] ([src.real_name]) attempted to devour [key_name(G.affecting)] ([G.affecting.real_name]) against their prefs ([G.affecting ? "JMP" : "null"])") - + log_and_message_admins("[key_name_admin(src)] attempted to devour [key_name_admin(G.affecting)] against their prefs ([G.affecting ? ADMIN_JMP(G.affecting) : "null"])") return FALSE - if(src.feed_grabbed_to_self(src, G.affecting)) + + if(feed_grabbed_to_self(src, G.affecting)) qdel(G) return TRUE else @@ -115,57 +114,62 @@ ///// If user clicked on their grabbed target else if((src == G.affecting) && (attacker.a_intent == I_GRAB) && (attacker.zone_sel.selecting == BP_TORSO) && (is_vore_predator(G.affecting))) - if(!(G.affecting.feeding)) + if(!G.affecting.feeding) to_chat(user, "[G.affecting] isn't willing to be fed.") - log_and_message_admins("[key_name(src)] ([src.real_name]) attempted to feed themselves to [key_name(G.affecting)] ([G.affecting.real_name]) against their prefs ([G.affecting ? "JMP" : "null"])") + log_and_message_admins("[key_name_admin(src)] attempted to feed themselves to [key_name_admin(G.affecting)] against their prefs ([G.affecting ? ADMIN_JMP(G.affecting) : "null"])") return FALSE - if (attacker.feed_self_to_grabbed(attacker, G.affecting)) + + if(attacker.feed_self_to_grabbed(attacker, G.affecting)) qdel(G) return TRUE else - log_debug("[attacker] attempted to feed [user] to [G.affecting] ([G.affecting.type]) but it failed.") + log_debug("[attacker] attempted to feed [user] to [G.affecting] ([G.affecting ? G.affecting.type : "null"]) but it failed.") ///// If user clicked on anyone else but their grabbed target else if((src != G.affecting) && (src != G.assailant) && (is_vore_predator(src))) - if(!(src.feeding)) + if(!feeding) to_chat(user, "[src] isn't willing to be fed.") - log_and_message_admins("[key_name(attacker)] ([attacker.real_name]) attempted to feed [key_name(G.affecting)] ([G.affecting.real_name]) to [key_name(src)] ([src.real_name]) against predator's prefs ([src ? "JMP" : "null"])") + log_and_message_admins("[key_name_admin(attacker)] attempted to feed [key_name_admin(G.affecting)] to [key_name_admin(src)] against predator's prefs ([src ? ADMIN_JMP(src) : "null"])") return FALSE if(!(G.affecting.devourable)) to_chat(user, "[G.affecting] isn't able to be devoured.") - log_and_message_admins("[key_name(attacker)] ([attacker.real_name]) attempted to feed [key_name(G.affecting)] ([G.affecting.real_name]) to [key_name(src)] ([src.real_name]) against prey's prefs ([G.affecting ? "JMP" : "null"])") + log_and_message_admins("[key_name_admin(attacker)] attempted to feed [key_name_admin(G.affecting)] to [key_name_admin(src)] against prey's prefs ([G.affecting ? ADMIN_JMP(G.affecting) : "null"])") return FALSE - - if (attacker.feed_grabbed_to_other(attacker, G.affecting, src)) + if(attacker.feed_grabbed_to_other(attacker, G.affecting, src)) qdel(G) return TRUE else - log_debug("[attacker] attempted to feed [G.affecting] to [src] ([src.type]) but it failed.") + log_debug("[attacker] attempted to feed [G.affecting] to [src] ([type]) but it failed.") //Handle case: /obj/item/weapon/holder - else if(istype(I,/obj/item/weapon/holder)) + else if(istype(I, /obj/item/weapon/holder)) var/obj/item/weapon/holder/H = I - if(!isliving(user)) return FALSE // return FALSE to continue upper procs + if(!isliving(user)) + return FALSE // return FALSE to continue upper procs + var/mob/living/attacker = user // Typecast to living - - if (is_vore_predator(src)) - for (var/mob/living/M in H.contents) - if (attacker.eat_held_mob(attacker, M, src)) - if (H.held_mob == M) + if(is_vore_predator(src)) + for(var/mob/living/M in H.contents) + if(attacker.eat_held_mob(attacker, M, src)) + if(H.held_mob == M) H.held_mob = null return TRUE //return TRUE to exit upper procs else - log_debug("[attacker] attempted to feed [H.contents] to [src] ([src.type]) but it failed.") + log_debug("[attacker] attempted to feed [H.contents] to [src] ([type]) but it failed.") //Handle case: /obj/item/device/radio/beacon else if(istype(I,/obj/item/device/radio/beacon)) - var/confirm = alert(user, "[src == user ? "Eat the beacon?" : "Feed the beacon to [src]?"]", "Confirmation", "Yes!", "Cancel") + var/confirm = alert(user, + "[src == user ? "Eat the beacon?" : "Feed the beacon to [src]?"]", + "Confirmation", + "Yes!", "Cancel") if(confirm == "Yes!") - var/obj/belly/B = input("Which belly?","Select A Belly") as null|anything in vore_organs + var/obj/belly/B = input("Which belly?", "Select A Belly") as null|anything in vore_organs if(!istype(B)) return TRUE - visible_message("[user] is trying to stuff a beacon into [src]'s [lowertext(B.name)]!","[user] is trying to stuff a beacon into you!") + visible_message("[user] is trying to stuff a beacon into [src]'s [lowertext(B.name)]!", + "[user] is trying to stuff a beacon into you!") if(do_after(user,30,src)) user.drop_item() I.forceMove(B) @@ -179,7 +183,6 @@ // Our custom resist catches for /mob/living // /mob/living/proc/vore_process_resist() - //Are we resisting from inside a belly? if(isbelly(loc)) var/obj/belly/B = loc @@ -187,7 +190,6 @@ return TRUE //resist() on living does this TRUE thing. //Other overridden resists go here - return FALSE // @@ -310,13 +312,12 @@ if(suit.hides_bulges) return FALSE - return ..() // // Clearly super important. Obviously. // -/mob/living/proc/lick(var/mob/living/tasted in living_mobs(1)) +/mob/living/proc/lick(mob/living/tasted in living_mobs(1)) set name = "Lick" set category = "IC" set desc = "Lick someone nearby!" @@ -402,11 +403,11 @@ // // Eating procs depending on who clicked what // -/mob/living/proc/feed_grabbed_to_self(var/mob/living/user, var/mob/living/prey) +/mob/living/proc/feed_grabbed_to_self(mob/living/user, mob/living/prey) var/belly = user.vore_selected return perform_the_nom(user, prey, user, belly) -/mob/living/proc/eat_held_mob(var/mob/living/user, var/mob/living/prey, var/mob/living/pred) +/mob/living/proc/eat_held_mob(mob/living/user, mob/living/prey, mob/living/pred) var/belly if(user != pred) belly = input("Choose Belly") in pred.vore_organs @@ -414,18 +415,18 @@ belly = pred.vore_selected return perform_the_nom(user, prey, pred, belly) -/mob/living/proc/feed_self_to_grabbed(var/mob/living/user, var/mob/living/pred) +/mob/living/proc/feed_self_to_grabbed(mob/living/user, mob/living/pred) var/belly = input("Choose Belly") in pred.vore_organs return perform_the_nom(user, user, pred, belly) -/mob/living/proc/feed_grabbed_to_other(var/mob/living/user, var/mob/living/prey, var/mob/living/pred) +/mob/living/proc/feed_grabbed_to_other(mob/living/user, mob/living/prey, mob/living/pred) var/belly = input("Choose Belly") in pred.vore_organs return perform_the_nom(user, prey, pred, belly) // // Master vore proc that actually does vore procedures // -/mob/living/proc/perform_the_nom(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/obj/belly/belly, var/delay) +/mob/living/proc/perform_the_nom(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly, delay) //Sanity if(!user || !prey || !pred || !istype(belly) || !(belly in pred.vore_organs)) log_debug("[user] attempted to feed [prey] to [pred], via [belly ? lowertext(belly.name) : "*null*"] but it went wrong.") @@ -444,11 +445,11 @@ // Prepare messages if(user == pred) //Feeding someone to yourself - attempt_msg = text("[] is attempting to [] [] into their []!",pred,lowertext(belly.vore_verb),prey,lowertext(belly.name)) - success_msg = text("[] manages to [] [] into their []!",pred,lowertext(belly.vore_verb),prey,lowertext(belly.name)) + attempt_msg = "[pred] is attempting to [lowertext(belly.vore_verb)] [prey] into their [lowertext(belly.name)]!" + success_msg = "[pred] manages to [lowertext(belly.vore_verb)] [prey] into their [lowertext(belly.name)]!" else //Feeding someone to another person - attempt_msg = text("[] is attempting to make [] [] [] into their []!",user,pred,lowertext(belly.vore_verb),prey,lowertext(belly.name)) - success_msg = text("[] manages to make [] [] [] into their []!",user,pred,lowertext(belly.vore_verb),prey,lowertext(belly.name)) + attempt_msg = "[user] is attempting to make [pred] [lowertext(belly.vore_verb)] [prey] into their [lowertext(belly.name)]!" + success_msg = "[user] manages to make [pred] [lowertext(belly.vore_verb)] [prey] into their [lowertext(belly.name)]!" // Announce that we start the attempt! user.visible_message(attempt_msg) @@ -477,10 +478,10 @@ to_chat(belly.owner, "[prey] tastes of [prey.get_taste_message(FALSE)].") // Inform Admins - if (pred == user) - add_attack_logs(pred,prey,"Eaten via [belly.name]") + if(pred == user) + add_attack_logs(pred, prey, "Eaten via [belly.name]") else - add_attack_logs(user,pred,"Forced to eat [key_name(prey)]") + add_attack_logs(user, pred, "Forced to eat [key_name(prey)]") return TRUE // @@ -522,7 +523,7 @@ to_chat(src,"You're pinned back underfoot!") to_chat(H,"You pin the escapee back underfoot!") return - if(src.loc != C) + if(loc != C) return sleep(1) @@ -538,7 +539,7 @@ to_chat(src,"You're pinned underfoot!") to_chat(H,"You pin the escapee underfoot!") return - if(src.loc != C) + if(loc != C) return sleep(1) to_chat(src,"You manage to escape \the [C]!") @@ -599,7 +600,7 @@ if(is_type_in_list(I,edible_trash) | adminbus_trash) if(I.hidden_uplink) to_chat(src, "You really should not be eating this.") - message_admins("[key_name(src)] has attempted to ingest an uplink item. ([src ? "JMP" : "null"])") + message_admins("[key_name(src)] has attempted to ingest an uplink item. ([src ? ADMIN_JMP(src) : "null"])") return if(istype(I,/obj/item/device/pda)) var/obj/item/device/pda/P = I diff --git a/code/modules/vore/eating/silicon_vr.dm b/code/modules/vore/eating/silicon_vr.dm index 9c8b2b3387..ba9e279043 100644 --- a/code/modules/vore/eating/silicon_vr.dm +++ b/code/modules/vore/eating/silicon_vr.dm @@ -37,7 +37,7 @@ playsound('sound/effects/stealthoff.ogg',50,0) bellied.forceMove(get_turf(src)) bellied.Weaken(2) - bellied.visible_message("[bellied] flops out of \the [src].","You flop out of \the [src].","You hear a thud.") + bellied.visible_message("[bellied] flops out of [src].","You flop out of [src].","You hear a thud.") bellied = null desc = "[initial(desc)]" @@ -64,7 +64,7 @@ //Already full if (hologram.bellied) - var/choice = alert("You can only contain one person. [hologram.bellied] is in you.","Already Full","Drop Mob","Cancel") + var/choice = alert("You can only contain one person. [hologram.bellied] is in you.", "Already Full", "Drop Mob", "Cancel") if(choice == "Drop Mob") hologram.drop_prey() return @@ -93,7 +93,7 @@ /mob/living/AIShiftClick(var/mob/user) //Shift-click as AI overridden on mobs to examine. if(user.client) - src.examine(user) + examine(user) return //This can go here with all the references. diff --git a/code/modules/vore/eating/simple_animal_vr.dm b/code/modules/vore/eating/simple_animal_vr.dm index 05e8e84601..9e68ad631a 100644 --- a/code/modules/vore/eating/simple_animal_vr.dm +++ b/code/modules/vore/eating/simple_animal_vr.dm @@ -6,21 +6,22 @@ // // Simple nom proc for if you get ckey'd into a simple_mob mob! Avoids grabs. // -/mob/living/simple_mob/proc/animal_nom(var/mob/living/T in living_mobs(1)) +/mob/living/simple_mob/proc/animal_nom(mob/living/T in living_mobs(1)) set name = "Animal Nom" set category = "IC" set desc = "Since you can't grab, you get a verb!" - if (stat != CONSCIOUS) + if(stat != CONSCIOUS) return - if (istype(src,/mob/living/simple_mob/animal/passive/mouse) && T.ckey == null) + // Verbs are horrifying. They don't call overrides. So we're stuck with this. + if(istype(src, /mob/living/simple_mob/animal/passive/mouse) && !T.ckey) + // Mice can't eat logged out players! return - if (client && IsAdvancedToolUser()) + if(client && IsAdvancedToolUser()) to_chat(src, "Put your hands to good use instead!") return feed_grabbed_to_self(src,T) update_icon() - return // // Simple proc for animals to have their digestion toggled on/off externally @@ -45,8 +46,7 @@ var/confirm = alert(user, "Enabling digestion on [name] will cause it to digest all stomach contents. Using this to break OOC prefs is against the rules. Digestion will reset after 20 minutes.", "Enabling [name]'s Digestion", "Enable", "Cancel") if(confirm == "Enable") vore_selected.digest_mode = DM_DIGEST - spawn(20 MINUTES) - if(src) vore_selected.digest_mode = vore_default_mode + addtimer(VARSET_CALLBACK(vore_selected, digest_mode, vore_default_mode), 20 MINUTES) else var/confirm = alert(user, "This mob is currently set to process all stomach contents. Do you want to disable this?", "Disabling [name]'s Digestion", "Disable", "Cancel") if(confirm == "Disable") @@ -69,28 +69,31 @@ to_chat(user, "[src] is now using [vore_selected.fancy_vore ? "Fancy" : "Classic"] vore sounds.") /mob/living/simple_mob/attackby(var/obj/item/O, var/mob/user) - if (istype(O, /obj/item/weapon/newspaper) && !(ckey || (ai_holder.hostile && faction != user.faction)) && isturf(user.loc)) - if (ai_holder.retaliate && prob(vore_pounce_chance/2)) // This is a gamble! + if(istype(O, /obj/item/weapon/newspaper) && !(ckey || (ai_holder.hostile && faction != user.faction)) && isturf(user.loc)) + if(ai_holder.retaliate && prob(vore_pounce_chance/2)) // This is a gamble! user.Weaken(5) //They get tackled anyway whether they're edible or not. - user.visible_message("\the [user] swats \the [src] with \the [O] and promptly gets tackled!!") - if (will_eat(user)) + user.visible_message("[user] swats [src] with [O] and promptly gets tackled!!") + if(will_eat(user)) set_AI_busy(TRUE) animal_nom(user) update_icon() set_AI_busy(FALSE) - else if (!ai_holder.target) // no using this to clear a retaliate mob's target + else if(!ai_holder.target) // no using this to clear a retaliate mob's target ai_holder.target = user //just because you're not tasty doesn't mean you get off the hook. A swat for a swat. //AttackTarget() //VOREStation AI Temporary Removal //LoseTarget() // only make one attempt at an attack rather than going into full rage mode else - user.visible_message("\the [user] swats \the [src] with \the [O]!!") + user.visible_message("[user] swats [src] with [O]!") release_vore_contents() for(var/mob/living/L in living_mobs(0)) //add everyone on the tile to the do-not-eat list for a while if(!(L in prey_excludes)) // Unless they're already on it, just to avoid fuckery. prey_excludes += L - spawn(5 MINUTES) - if(src && L) - prey_excludes -= L + addtimer(CALLBACK(src, .proc/removeMobFromPreyExcludes, weakref(L)), 5 MINUTES) else ..() +/mob/living/simple_mob/proc/removeMobFromPreyExcludes(weakref/target) + if(isweakref(target)) + var/mob/living/L = target.resolve() + if(L) + LAZYREMOVE(prey_excludes, L) diff --git a/code/modules/vore/eating/transforming_vr.dm b/code/modules/vore/eating/transforming_vr.dm index 2f261980ec..3e78920419 100644 --- a/code/modules/vore/eating/transforming_vr.dm +++ b/code/modules/vore/eating/transforming_vr.dm @@ -241,7 +241,6 @@ BI.forceMove(torso) torso.implants += BI - if(message) to_chat(M, "You lose sensation of your body, feeling only the warmth of everything around you... ") to_chat(O, "Your body shifts as you make dramatic changes to your captive's body.") diff --git a/code/modules/vore/eating/vore_vr.dm b/code/modules/vore/eating/vore_vr.dm index ea77dd5c6b..9aaa4b0cef 100644 --- a/code/modules/vore/eating/vore_vr.dm +++ b/code/modules/vore/eating/vore_vr.dm @@ -70,7 +70,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE // // Check if an object is capable of eating things, based on vore_organs // -/proc/is_vore_predator(var/mob/living/O) +/proc/is_vore_predator(mob/living/O) if(istype(O,/mob/living)) if(O.vore_organs.len > 0) return TRUE @@ -87,8 +87,9 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE // // Save/Load Vore Preferences // -/datum/vore_preferences/proc/load_path(ckey,slot,filename="character",ext="json") - if(!ckey || !slot) return +/datum/vore_preferences/proc/load_path(ckey, slot, filename="character", ext="json") + if(!ckey || !slot) + return path = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/vore/[filename][slot].[ext]" @@ -102,7 +103,8 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE load_path(client_ckey,slot) - if(!path) return FALSE //Path couldn't be set? + if(!path) + return FALSE //Path couldn't be set? if(!fexists(path)) //Never saved before save_vore() //Make the file first return TRUE @@ -151,7 +153,8 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE return TRUE /datum/vore_preferences/proc/save_vore() - if(!path) return FALSE + if(!path) + return FALSE var/version = VORE_VERSION //For "good times" use in the future var/list/settings_list = list( diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index fe0b86d9de..5caf70d602 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -8,68 +8,72 @@ #define BELLIES_DESC_MAX 2048 #define FLAVOR_MAX 40 +/mob/living + var/datum/vore_look/vorePanel + /mob/living/proc/insidePanel() set name = "Vore Panel" set category = "IC" - var/datum/vore_look/picker_holder = new() - picker_holder.loop = picker_holder - picker_holder.selected = vore_selected + if(!vorePanel) + log_debug("[src] ([type], \ref[src]) didn't have a vorePanel and tried to use the verb.") + vorePanel = new - var/dat = picker_holder.gen_ui(src) - - picker_holder.popup = new(src, "insidePanel","Inside!", 450, 700, picker_holder) - picker_holder.popup.set_content(dat) - picker_holder.popup.open() - src.openpanel = 1 + vorePanel.selected = vore_selected + vorePanel.show(src) /mob/living/proc/updateVRPanel() //Panel popup update call from belly events. - if(src.openpanel == 1) - var/datum/vore_look/picker_holder = new() - picker_holder.loop = picker_holder - picker_holder.selected = vore_selected + if(!vorePanel) + log_debug("[src] ([type], \ref[src]) didn't have a vorePanel and something tried to update it.") + vorePanel = new - var/dat = picker_holder.gen_ui(src) - - picker_holder.popup = new(src, "insidePanel","Inside!", 450, 700, picker_holder) - picker_holder.popup.set_content(dat) - picker_holder.popup.open() + if(vorePanel.open) + vorePanel.selected = vore_selected + vorePanel.show(src) // // Callback Handler for the Inside form // /datum/vore_look + var/datum/browser/popup var/obj/belly/selected var/show_interacts = 0 - var/datum/browser/popup - var/loop = null; // Magic self-reference to stop the handler from being GC'd before user takes action. + var/open = FALSE /datum/vore_look/Destroy() - loop = null selected = null - return QDEL_HINT_HARDDEL // TODO - Until I can better analyze how this weird thing works, lets be safe + QDEL_NULL(popup) + . = ..() /datum/vore_look/Topic(href,href_list[]) - if (vp_interact(href, href_list)) + if(vp_interact(href, href_list)) popup.set_content(gen_ui(usr)) usr << output(popup.get_content(), "insidePanel.browser") +/datum/vore_look/proc/show(mob/living/user) + if(popup) + QDEL_NULL(popup) + popup = new(user, "insidePanel", "Inside!", 450, 700, src) + popup.set_content(gen_ui(user)) + popup.open() + open = TRUE + /datum/vore_look/proc/gen_ui(var/mob/living/user) var/dat var/atom/userloc = user.loc - if (isbelly(userloc)) + if(isbelly(userloc)) var/obj/belly/inside_belly = userloc var/mob/living/eater = inside_belly.owner //Don't display this part if we couldn't find the belly since could be held in hand. if(inside_belly) - dat += "You are currently [user.absorbed ? "absorbed into " : "inside "] [eater]'s [inside_belly]!

" + dat += "You are currently [user.absorbed ? "absorbed into " : "inside "] [eater]'s [inside_belly]!

" if(inside_belly.desc) dat += "[inside_belly.desc]

" - if (inside_belly.contents.len > 1) + if(inside_belly.contents.len > 1) dat += "You can see the following around you:
" for (var/atom/movable/O in inside_belly) if(istype(O,/mob/living)) @@ -374,11 +378,9 @@ /datum/vore_look/proc/vp_interact(href, href_list) var/mob/living/user = usr - for(var/H in href_list) - if(href_list["close"]) - qdel(src) // Cleanup - user.openpanel = 0 + open = FALSE + QDEL_NULL(popup) return if(href_list["show_int"]) diff --git a/code/modules/vore/resizing/grav_pull_vr.dm b/code/modules/vore/resizing/grav_pull_vr.dm index 921d1ab2b9..64b8581aff 100644 --- a/code/modules/vore/resizing/grav_pull_vr.dm +++ b/code/modules/vore/resizing/grav_pull_vr.dm @@ -18,8 +18,8 @@ /datum/effect/effect/system/grav_pull/start() spawn(0) if(holder) - src.location = get_turf(holder) - for(var/i=0, i < number, i++) + location = get_turf(holder) + for(var/i = 0, i < number, i++) do_pull() sleep(25) @@ -29,35 +29,35 @@ defer_powernet_rebuild = 1 // Let's just make this one loop. - for(var/atom/X in orange(pull_radius, location)) + for(var/X in orange(pull_radius, location)) // Movable atoms only - if(istype(X, /atom/movable)) - if(istype(X, /obj/effect/overlay)) continue - if(X && !istype(X, /mob/living/carbon/human)) - if(break_windows && istype(X, /obj/structure/window)) //shatter windows - var/obj/structure/window/W = X - W.ex_act(2.0) + if(!ismovableatom(X) || istype(X, /obj/effect/overlay)) + continue - if(istype(X, /obj)) - var/obj/O = X - if(O.anchored) - if (!pull_anchored) continue // Don't pull anchored stuff unless configured - step_towards(X, location) // step just once if anchored - continue + if(ishuman(X)) + var/mob/living/carbon/human/H = X + if(istype(H.shoes, /obj/item/clothing/shoes/magboots)) + var/obj/item/clothing/shoes/magboots/M = H.shoes + if(M.magpulse) + step_towards(H, location) //step just once with magboots + continue + step_towards(H, location) //step twice + step_towards(H, location) + else + if(break_windows && istype(X, /obj/structure/window)) //shatter windows + var/obj/structure/window/W = X + W.ex_act(2.0) - step_towards(X, location) // Step twice - step_towards(X, location) + if(isobj(X)) + var/obj/O = X + if(O.anchored) + if(!pull_anchored) + continue // Don't pull anchored stuff unless configured + step_towards(X, location) // step just once if anchored + continue - else if(istype(X,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = X - if(istype(H.shoes,/obj/item/clothing/shoes/magboots)) - var/obj/item/clothing/shoes/magboots/M = H.shoes - if(M.magpulse) - step_towards(H, location) //step just once with magboots - continue - step_towards(H, location) //step twice - step_towards(H, location) + step_towards(X, location) // Step twice + step_towards(X, location) if(defer_powernet_rebuild != 2) defer_powernet_rebuild = 0 - return diff --git a/code/modules/vore/resizing/holder_micro_vr.dm b/code/modules/vore/resizing/holder_micro_vr.dm index 574be02e0f..b797ef4f5f 100644 --- a/code/modules/vore/resizing/holder_micro_vr.dm +++ b/code/modules/vore/resizing/holder_micro_vr.dm @@ -10,36 +10,34 @@ item_icons = list() // No in-hand sprites (for now, anyway, we could totally add some) pixel_y = 0 // Override value from parent. -/obj/item/weapon/holder/micro/examine(var/mob/user) +/obj/item/weapon/holder/micro/examine(mob/user) for(var/mob/living/M in contents) M.examine(user) -/obj/item/weapon/holder/MouseDrop(mob/M as mob) +/obj/item/weapon/holder/MouseDrop(mob/M) ..() if(M != usr) return if(usr == src) return if(!Adjacent(usr)) return - if(istype(M,/mob/living/silicon/ai)) return + if(isAI(M)) return for(var/mob/living/carbon/human/O in contents) O.show_inv(usr) /obj/item/weapon/holder/micro/attack_self(mob/living/carbon/user) //reworked so it works w/ nonhumans for(var/L in contents) - if(!isliving(L)) - continue - if(ishuman(L) && user.canClick()) + if(ishuman(L) && user.canClick()) // These canClicks() are repeated here to make sure users can't avoid the click delay var/mob/living/carbon/human/H = L H.help_shake_act(user) user.setClickCooldown(user.get_attack_speed()) //uses the same cooldown as regular attack_hand return - if(istype(L, /mob/living/simple_mob) && user.canClick()) + if(isanimal(L) && user.canClick()) var/mob/living/simple_mob/S = L user.visible_message("[user] [S.response_help] \the [S].") user.setClickCooldown(user.get_attack_speed()) /obj/item/weapon/holder/micro/update_state() - if(istype(loc,/turf) || !(held_mob) || !(held_mob.loc == src)) + if(isturf(loc) || !held_mob || held_mob.loc != src) qdel(src) /obj/item/weapon/holder/micro/Destroy() diff --git a/code/modules/vore/resizing/resize_vr.dm b/code/modules/vore/resizing/resize_vr.dm index e43ce011d0..f30ba72251 100644 --- a/code/modules/vore/resizing/resize_vr.dm +++ b/code/modules/vore/resizing/resize_vr.dm @@ -43,7 +43,7 @@ var/const/RESIZE_A_SMALLTINY = (RESIZE_SMALL + RESIZE_TINY) / 2 var/matrix/M = matrix() M.Scale(size_multiplier) M.Translate(0, 16*(size_multiplier-1)) - src.transform = M + transform = M /** * Get the effective size of a mob. @@ -55,7 +55,7 @@ var/const/RESIZE_A_SMALLTINY = (RESIZE_SMALL + RESIZE_TINY) / 2 return 100000 //Whatever it is, it's too big to pick up, or it's a ghost, or something. /mob/living/get_effective_size() - return src.size_multiplier + return size_multiplier /** * Resizes the mob immediately to the desired mod, animating it growing/shrinking. @@ -111,10 +111,11 @@ var/const/RESIZE_A_SMALLTINY = (RESIZE_SMALL + RESIZE_TINY) / 2 var/nagmessage = "Adjust your mass to be a size between 25 to 200% (DO NOT ABUSE)" var/new_size = input(nagmessage, "Pick a Size") as num|null - if(new_size && ISINRANGE(new_size,25,200)) - src.resize(new_size/100) - message_admins("[key_name(src)] used the resize command in-game to be [new_size]% size. \ - ([src ? "JMP" : "null"])") + if(new_size && ISINRANGE(new_size, 25, 200)) + resize(new_size/100) + // I'm not entirely convinced that `src ? ADMIN_JMP(src) : "null"` here does anything + // but just in case it does, I'm leaving the null-src checking + message_admins("[key_name(src)] used the resize command in-game to be [new_size]% size. [src ? ADMIN_JMP(src) : "null"]") /* //Add the set_size() proc to usable verbs. By commenting this out, we can leave the proc and hand it to species that need it. @@ -127,7 +128,7 @@ var/const/RESIZE_A_SMALLTINY = (RESIZE_SMALL + RESIZE_TINY) / 2 * Attempt to scoop up this mob up into H's hands, if the size difference is large enough. * @return false if normal code should continue, 1 to prevent normal code. */ -/mob/living/proc/attempt_to_scoop(var/mob/living/M, var/mob/living/G) //second one is for the Grabber, only exists for animals to self-grab +/mob/living/proc/attempt_to_scoop(mob/living/M, mob/living/G) //second one is for the Grabber, only exists for animals to self-grab var/size_diff = M.get_effective_size() - get_effective_size() if(!holder_default && holder_type) holder_default = holder_type @@ -156,37 +157,42 @@ var/const/RESIZE_A_SMALLTINY = (RESIZE_SMALL + RESIZE_TINY) / 2 * Called from /mob/living/Bump() in the 'brohugs all around' section. * @return false if normal code should continue, true to prevent normal code. */ -/mob/living/proc/handle_micro_bump_helping(var/mob/living/tmob) +/mob/living/proc/handle_micro_bump_helping(mob/living/tmob) //Both small! Go ahead and go. - if(src.get_effective_size() <= RESIZE_A_SMALLTINY && tmob.get_effective_size() <= RESIZE_A_SMALLTINY) + if(get_effective_size() <= RESIZE_A_SMALLTINY && tmob.get_effective_size() <= RESIZE_A_SMALLTINY) return TRUE //Worthy of doing messages at all if(abs(get_effective_size() - tmob.get_effective_size()) >= 0.50) + var/src_message = null + var/tmob_message = null //Smaller person being stepped onto if(get_effective_size() > tmob.get_effective_size() && ishuman(src)) + src_message = "You carefully step over [tmob]." + tmob_message = "[src] steps over you carefully!" var/mob/living/carbon/human/H = src if(H.flying) return TRUE //Silently pass without a message. if(isTaurTail(H.tail_style)) var/datum/sprite_accessory/tail/taur/tail = H.tail_style - to_chat(src,STEP_TEXT_OWNER(tail.msg_owner_help_run)) - to_chat(tmob,STEP_TEXT_PREY(tail.msg_prey_help_run)) - else - to_chat(src,"You carefully step over [tmob].") - to_chat(tmob,"[src] steps over you carefully!") + src_message = tail.msg_owner_help_run + tmob_message = tail.msg_prey_help_run //Smaller person stepping under larger person - else if(tmob.get_effective_size() > get_effective_size() && ishuman(tmob)) + else if(get_effective_size() < tmob.get_effective_size() && ishuman(tmob)) + src_message = "You run between [tmob]'s legs." + tmob_message = "[src] runs between your legs." var/mob/living/carbon/human/H = tmob if(isTaurTail(H.tail_style)) var/datum/sprite_accessory/tail/taur/tail = H.tail_style - to_chat(src,STEP_TEXT_OWNER(tail.msg_prey_stepunder)) - to_chat(tmob,STEP_TEXT_PREY(tail.msg_owner_stepunder)) - else - to_chat(src,"You run between [tmob]'s legs.") - to_chat(tmob,"[src] runs between your legs.") + src_message = tail.msg_prey_stepunder + tmob_message = tail.msg_owner_stepunder + + if(src_message) + to_chat(src, STEP_TEXT_OWNER(src_message)) + if(tmob_message) + to_chat(tmob, STEP_TEXT_PREY(tmob_message)) return TRUE return FALSE @@ -196,202 +202,124 @@ var/const/RESIZE_A_SMALLTINY = (RESIZE_SMALL + RESIZE_TINY) / 2 * * @return false if normal code should continue, 1 to prevent normal code. */ -/mob/living/proc/handle_micro_bump_other(var/mob/living/tmob) +/mob/living/proc/handle_micro_bump_other(mob/living/tmob) ASSERT(istype(tmob)) - - //If they're flying, don't do any special interactions. - if(ishuman(src)) - var/mob/living/carbon/human/P = src - if(P.flying) - return - + //If we're flying, don't do any special interactions. + if(flying) + return //If the prey is flying, don't smush them. - if(ishuman(tmob)) - var/mob/living/carbon/human/D = tmob - if(D.flying) - return - - //They can't be stepping on anyone + if(tmob.flying) + return + //We can't be stepping on anyone if(!canmove || buckled) return //Test/set if human - var/mob/living/carbon/human/H - if(ishuman(src)) - H = src - else + var/mob/living/carbon/human/pred = src + if(!istype(pred)) //If we're not human, can't do the steppy return FALSE - var/mob/living/carbon/human/Ht - if(ishuman(tmob)) - Ht = tmob - else + var/mob/living/carbon/human/prey = tmob + if(!istype(prey)) //If they're not human, steppy shouldn't happen return FALSE - //Depending on intent... - switch(a_intent) + // We need to be above a certain size ratio in order to do anything to the prey. + // For DISARM and HURT intent, this is >=0.75, for GRAB it is >=0.5 + var/size_ratio = get_effective_size() - tmob.get_effective_size() + if(a_intent == I_GRAB && size_ratio < 0.5) + return FALSE + if((a_intent == I_DISARM || a_intent == I_HURT) && size_ratio < 0.75) + return FALSE + if(a_intent == I_HELP) // Theoretically not possible, but just in case. + return FALSE - //src stepped on someone with disarm intent - if(I_DISARM) - // If bigger than them by at least 0.75, move onto them and print message. - if((get_effective_size() - tmob.get_effective_size()) >= 0.75) - now_pushing = 0 - forceMove(tmob.loc) + now_pushing = 0 + forceMove(tmob.loc) + if(a_intent == I_GRAB || a_intent == I_DISARM) + tmob.resting = 1 - //Running on I_DISARM - if(m_intent == "run") - tmob.resting = 1 //Force them down to the ground. + var/size_damage_multiplier = size_multiplier - tmob.size_multiplier + // This technically means that I_GRAB will set this value to the same as I_HARM, but + // I_GRAB won't ever trigger the damage-giving code, so it doesn't matter. + // I_HARM: Rand 1-3 multiplied by 1 min or 1.75 max. 1 min 5.25 max damage to each limb. + // I_DISARM: Perform some HALLOSS damage to the smaller. + // Since stunned is broken, let's do this. Rand 15-30 multiplied by 1 min or 1.75 max. 15 holo to 52.5 holo, depending on RNG and size differnece. + var/damage = (a_intent == I_DISARM) ? (rand(15, 30) * size_damage_multiplier) : (rand(1, 3) * size_damage_multiplier) + // I_HARM only + var/calculated_damage = damage / 2 //This will sting, but not kill. Does .5 to 2.625 damage, randomly, to each limb. - //Log it for admins (as opposed to walk which logs damage) - add_attack_logs(src,tmob,"Pinned underfoot (run, no halloss)") + var/message_pred = null + var/message_prey = null + var/datum/sprite_accessory/tail/taur/tail = null + if(isTaurTail(pred.tail_style)) + tail = pred.tail_style - //Not a human, or not a taur, generic message only - if(!H || !isTaurTail(H.tail_style)) - to_chat(src,"You quickly push [tmob] to the ground with your foot!") - to_chat(tmob,"[src] pushes you down to the ground with their foot!") + if(a_intent == I_GRAB) + // You can only grab prey if you have no shoes on. + if(pred.shoes) + message_pred = "You step down onto [prey], squishing them and forcing them down to the ground!" + message_prey = "[pred] steps down and squishes you with their foot, forcing you down to the ground!" + if(tail) + message_pred = STEP_TEXT_OWNER(tail.msg_owner_grab_fail) + message_prey = STEP_TEXT_PREY(tail.msg_prey_grab_fail) + add_attack_logs(pred, prey,"Grabbed underfoot ([tail ? "taur" : "nontaur"], shoes)") + else + message_pred = "You pin [prey] down onto the floor with your foot and curl your toes up around their body, trapping them inbetween them!" + message_prey = "[pred] pins you down to the floor with their foot and curls their toes up around your body, trapping you inbetween them!" + if(tail) + message_pred = STEP_TEXT_OWNER(tail.msg_owner_grab_success) + message_prey = STEP_TEXT_PREY(tail.msg_prey_grab_success) + equip_to_slot_if_possible(prey.get_scooped(pred), slot_shoes, 0, 1) + add_attack_logs(pred, prey, "Grabbed underfoot ([tail ? "taur" : "nontaur"], no shoes)") - //Human with taur tail, special messages are sent - else - var/datum/sprite_accessory/tail/taur/tail = H.tail_style - to_chat(src,STEP_TEXT_OWNER("[tail.msg_owner_disarm_run]")) - to_chat(tmob,STEP_TEXT_PREY("[tail.msg_prey_disarm_run]")) + if(m_intent == "run") + switch(a_intent) + if(I_DISARM) + message_pred = "You quickly push [prey] to the ground with your foot!" + message_prey = "[pred] pushes you down to the ground with their foot!" + if(tail) + message_pred = STEP_TEXT_OWNER(tail.msg_owner_disarm_run) + message_prey = STEP_TEXT_PREY(tail.msg_prey_disarm_run) + add_attack_logs(pred, prey, "Pinned underfoot (run, no halloss)") + if(I_HURT) + message_pred = "You carelessly step down onto [prey], crushing them!" + message_prey = "[pred] steps carelessly on your body, crushing you!" + if(tail) + message_pred = STEP_TEXT_OWNER(tail.msg_owner_harm_run) + message_prey = STEP_TEXT_PREY(tail.msg_prey_harm_run) - //Walking on I_DISARM - else - //Perform some HALLOSS damage to the smaller. - var/size_damage_multiplier = (src.size_multiplier - tmob.size_multiplier) - var/damage = (rand(15,30)* size_damage_multiplier) //Since stunned is broken, let's do this. Rand 15-30 multiplied by 1 min or 1.75 max. 15 holo to 52.5 holo, depending on RNG and size differnece. - tmob.apply_damage(damage, HALLOSS) - tmob.resting = 1 + for(var/obj/item/organ/external/I in prey.organs) + I.take_damage(calculated_damage, 0) // 5 damage min, 26.25 damage max, depending on size & RNG. If they're only stepped on once, the damage will (probably not...) heal over time. + prey.drip(0.1) + add_attack_logs(pred, prey, "Crushed underfoot (run, about [calculated_damage] damage)") + else + switch(a_intent) + if(I_DISARM) + message_pred = "You firmly push your foot down on [prey], painfully but harmlessly pinning them to the ground!" + message_prey = "[pred] firmly pushes their foot down on you, quite painfully but harmlessly pinning you to the ground!" + if(tail) + message_pred = STEP_TEXT_OWNER(tail.msg_owner_disarm_walk) + message_prey = STEP_TEXT_PREY(tail.msg_prey_disarm_walk) + add_attack_logs(pred, prey, "Pinned underfoot (walk, about [damage] halloss)") + tmob.apply_damage(damage, HALLOSS) + if(I_HURT) + message_pred = "You methodically place your foot down upon [prey]'s body, slowly applying pressure, crushing them against the floor below!" + message_prey = "[pred] methodically places their foot upon your body, slowly applying pressure, crushing you against the floor below!" + if(tail) + message_pred = STEP_TEXT_OWNER(tail.msg_owner_harm_walk) + message_prey = STEP_TEXT_PREY(tail.msg_prey_harm_walk) + // Multiplies the above damage by 3.5. This means a min of 1.75 damage, or a max of 9.1875. damage to each limb, depending on size and RNG. + calculated_damage *= 3.5 + for(var/obj/item/organ/I in prey.organs) + I.take_damage(calculated_damage, 0) + prey.drip(3) + add_attack_logs(pred, prey, "Crushed underfoot (walk, about [calculated_damage] damage)") - //Log it for admins (as opposed to run which logs no damage) - add_attack_logs(src,tmob,"Pinned underfoot (walk, about [damage] halloss)") - - //Not a human, or not a taur, generic message only - if(!H || !isTaurTail(H.tail_style)) - to_chat(src,"You firmly push your foot down on [tmob], painfully but harmlessly pinning them to the ground!") - to_chat(tmob,"[src] firmly pushes their foot down on you, quite painfully but harmlessly pinning you to the ground!") - - //Human with taur tail, special messages are sent - else - var/datum/sprite_accessory/tail/taur/tail = H.tail_style - to_chat(src,STEP_TEXT_OWNER("[tail.msg_owner_disarm_walk]")) - to_chat(tmob,STEP_TEXT_PREY("[tail.msg_prey_disarm_walk]")) - - //Return true, the sizediff was enough that we handled it. - return TRUE - - //Not enough sizediff for I_DISARM to do anything. - else - return FALSE - - //src stepped on someone with harm intent - if(I_HURT) - // If bigger than them by at least 0.75, move onto them and print message. - if((get_effective_size() - tmob.get_effective_size()) >= 0.75) - now_pushing = 0 - forceMove(tmob.loc) - - //Precalculate base damage - var/size_damage_multiplier = (src.size_multiplier - tmob.size_multiplier) - var/damage = (rand(1,3)* size_damage_multiplier) //Rand 1-3 multiplied by 1 min or 1.75 max. 1 min 5.25 max damage to each limb. - var/calculated_damage = damage/2 //This will sting, but not kill. Does .5 to 2.625 damage, randomly, to each limb. - - //Running on I_HURT - if(m_intent == "run") - - //Not a human, or not a taur, generic message only - if(!H || !isTaurTail(H.tail_style)) - to_chat(src,"You carelessly step down onto [tmob], crushing them!") - to_chat(tmob,"[src] steps carelessly on your body, crushing you!") - - //Human with taur tail, special messages are sent - else - var/datum/sprite_accessory/tail/taur/tail = H.tail_style - to_chat(src,STEP_TEXT_OWNER("[tail.msg_owner_harm_run]")) - to_chat(tmob,STEP_TEXT_PREY("[tail.msg_prey_harm_run]")) - - //If they are a human, do damage (doesn't hurt other mobs...?) - if(Ht) - for(var/obj/item/organ/external/I in Ht.organs) - I.take_damage(calculated_damage, 0) // 5 damage min, 26.25 damage max, depending on size & RNG. If they're only stepped on once, the damage will (probably not...) heal over time. - Ht.drip(0.1) - add_attack_logs(src,tmob,"Crushed underfoot (run, about [calculated_damage] damage)") - - //Walking on I_HURT - else - //Multiplies the above damage by 3.5. This means a min of 1.75 damage, or a max of 9.1875. damage to each limb, depending on size and RNG. - calculated_damage *= 3.5 - - //If they are a human, do damage (doesn't hurt other mobs...?) - if(Ht) - for(var/obj/item/organ/I in Ht.organs) - I.take_damage(calculated_damage, 0) - Ht.drip(3) - add_attack_logs(src,tmob,"Crushed underfoot (walk, about [calculated_damage] damage)") - - //Not a human, or not a taur, generic message only - if(!H || !isTaurTail(H.tail_style)) - to_chat(src,"You methodically place your foot down upon [tmob]'s body, slowly applying pressure, crushing them against the floor below!") - to_chat(tmob,"[src] methodically places their foot upon your body, slowly applying pressure, crushing you against the floor below!") - - //Human with taur tail, special messages are sent - else - var/datum/sprite_accessory/tail/taur/tail = H.tail_style - to_chat(src,STEP_TEXT_OWNER("[tail.msg_owner_harm_walk]")) - to_chat(tmob,STEP_TEXT_PREY("[tail.msg_prey_harm_walk]")) - - //Return true, the sizediff was enough that we handled it. - return TRUE - - //Not enough sizediff for I_HURT to do anything. - else - return FALSE - - //src stepped on someone with grab intent - if(I_GRAB) - // If bigger than them by at least 0.50, move onto them and print message. - if((get_effective_size() - tmob.get_effective_size()) >= 0.50) - now_pushing = 0 - tmob.resting = 1 - forceMove(tmob.loc) - - //Not a human, or not a taur while wearing shoes = no grab - if(!H || (!isTaurTail(H.tail_style) && H.shoes)) - to_chat(src,"You step down onto [tmob], squishing them and forcing them down to the ground!") - to_chat(tmob,"[src] steps down and squishes you with their foot, forcing you down to the ground!") - add_attack_logs(src,tmob,"Grabbed underfoot (nontaur, shoes)") - - //Human, not a taur, but not wearing shoes = yes grab - else if(H && (!isTaurTail(H.tail_style) && !H.shoes)) - to_chat(src,"You pin [tmob] down onto the floor with your foot and curl your toes up around their body, trapping them inbetween them!") - to_chat(tmob,"[src] pins you down to the floor with their foot and curls their toes up around your body, trapping you inbetween them!") - equip_to_slot_if_possible(tmob.get_scooped(H), slot_shoes, 0, 1) - add_attack_logs(src,tmob,"Grabbed underfoot (nontaur, no shoes)") - - //Human, taur, shoes = no grab, special message - else if(H.shoes) - var/datum/sprite_accessory/tail/taur/tail = H.tail_style - to_chat(src,STEP_TEXT_OWNER("[tail.msg_owner_grab_fail]")) - to_chat(tmob,STEP_TEXT_PREY("[tail.msg_prey_grab_fail]")) - add_attack_logs(src,tmob,"Grabbed underfoot (taur, shoes)") - - //Human, taur, no shoes = yes grab, special message - else - var/datum/sprite_accessory/tail/taur/tail = H.tail_style - to_chat(src,STEP_TEXT_OWNER("[tail.msg_owner_grab_success]")) - to_chat(tmob,STEP_TEXT_PREY("[tail.msg_prey_grab_success]")) - equip_to_slot_if_possible(tmob.get_scooped(H), slot_shoes, 0, 1) - add_attack_logs(src,tmob,"Grabbed underfoot (taur, no shoes)") - - //Return true, the sizediff was enough that we handled it. - return TRUE - - //Not enough sizediff for I_GRAB to do anything. - else - return FALSE + to_chat(pred, "[message_pred]") + to_chat(prey, "[message_prey]") + return TRUE #undef STEP_TEXT_OWNER #undef STEP_TEXT_PREY \ No newline at end of file diff --git a/code/modules/vore/resizing/sizegun_vr.dm b/code/modules/vore/resizing/sizegun_vr.dm index 2c1dbe8d04..491ffdf7de 100644 --- a/code/modules/vore/resizing/sizegun_vr.dm +++ b/code/modules/vore/resizing/sizegun_vr.dm @@ -41,8 +41,8 @@ set category = "Object" set src in view(1) - var/size_select = input("Put the desired size (25-200%)", "Set Size", size_set_to*100) as num - if(size_select>200 || size_select<25) + var/size_select = input("Put the desired size (25-200%)", "Set Size", size_set_to * 100) as num + if(size_select > 200 || size_select < 25) to_chat(usr, "Invalid size.") return size_set_to = (size_select/100) @@ -69,24 +69,17 @@ tracer_type = /obj/effect/projectile/tracer/xray impact_type = /obj/effect/projectile/impact/xray - on_hit(var/atom/target) - var/mob/living/M = target - if(ishuman(target)) - var/mob/living/carbon/human/H = M - H.resize(set_size) - H.show_message(" The beam fires into your body, changing your size!") - H.updateicon() - else if (istype(target, /mob/living/)) - var/mob/living/H = M - H.resize(set_size) - H.updateicon() - else - return 1 - +/obj/item/projectile/beam/sizelaser/on_hit(var/atom/target) + var/mob/living/M = target + if(istype(M)) + M.resize(set_size) + to_chat(M, " The beam fires into your body, changing your size!") + M.updateicon() + return + return 1 /obj/item/projectile/beam/sizelaser/shrink set_size = 0.5 //50% of current size - /obj/item/projectile/beam/sizelaser/grow - set_size = 2.0 //200% of current size \ No newline at end of file + set_size = 2.0 //200% of current size diff --git a/code/modules/vore/weight/fitness_machines_vr.dm b/code/modules/vore/weight/fitness_machines_vr.dm index 4a7c5fe2bb..82d2b9910b 100644 --- a/code/modules/vore/weight/fitness_machines_vr.dm +++ b/code/modules/vore/weight/fitness_machines_vr.dm @@ -11,7 +11,7 @@ var/cooldown = 10 var/weightloss_power = 1 -/obj/machinery/fitness/attack_hand(var/mob/living/user) +/obj/machinery/fitness/attack_hand(mob/living/user) if(user.nutrition < 70) to_chat(user, "You need more energy to workout with the [src]!") @@ -21,12 +21,12 @@ else //If they have enough nutrition and body weight, they can exercise. user.setClickCooldown(cooldown) user.nutrition -= 10 * weightloss_power - user.weight -= 0.025 * weightloss_power * (0.01*user.weight_loss) - flick("[icon_state]2",src) + user.weight -= 0.025 * weightloss_power * (0.01 * user.weight_loss) + flick("[icon_state]2", src) var/message = pick(messages) to_chat(user, "[message].") for(var/s in workout_sounds) - playsound(src.loc, s, 50, 1) + playsound(loc, s, 50, 1) /obj/machinery/fitness/punching_bag name = "punching bag" @@ -54,20 +54,20 @@ "You hammer the clown right in it's face with your fist", "A honk emits from the punching bag as you hit it") -/obj/machinery/fitness/heavy/attackby(obj/item/W, var/mob/living/user) +/obj/machinery/fitness/heavy/attackby(obj/item/W, mob/living/user) if(W.is_wrench()) - src.add_fingerprint(user) + add_fingerprint(user) user.visible_message("[user] has [anchored ? "un" : ""]secured \the [src].", "You [anchored ? "un" : ""]secure \the [src].") anchored = !anchored - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) return -/obj/machinery/fitness/heavy/attack_hand(var/mob/living/user) +/obj/machinery/fitness/heavy/attack_hand(mob/living/user) if(!anchored) to_chat(user, "For safety reasons, you are required to have this equipment wrenched down before using it!") return - else if(user.loc != src.loc) + else if(user.loc != loc) to_chat(user, "For safety reasons, you need to be sitting in the [src] for it to work!") return