diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm index 2b99823c49d..8a1d2bd8e7b 100644 --- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm +++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm @@ -45,6 +45,9 @@ var/obj/item/organ/internal/nano/refactory/refactory var/datum/modifier/healing + var/obj/prev_left_hand + var/obj/prev_right_hand + player_msg = "In this form, you can move a little faster, your health will regenerate as long as you have metal in you, and you can ventcrawl!" can_buckle = TRUE //Blobsurfing @@ -152,8 +155,14 @@ var/obj/item/organ/internal/O = organ O.removed() O.forceMove(drop_location()) - QDEL_NULL(humanform) //Don't leave it just sitting in nullspace - animate(src,alpha = 0,time = 2 SECONDS) + var/list/items = humanform.get_equipped_items() + if(prev_left_hand) items += prev_left_hand + if(prev_right_hand) items += prev_right_hand + for(var/obj/object in items) + object.forceMove(drop_location()) + qdel_null(humanform) //Don't leave it just sitting in nullspace + +animate(src,alpha = 0,time = 2 SECONDS) sleep(2 SECONDS) qdel(src) @@ -193,6 +202,13 @@ /mob/living/simple_animal/protean_blob/DoPunch(var/atom/A) if(refactory && istype(A,/obj/item/stack/material)) var/obj/item/stack/material/S = A + var/substance = S.material.name + var/list/edible_materials = list("steel", "plasteel", "diamond", "mhydrogen") //Can't eat all materials, just useful ones. + var allowed = FALSE + for(var/material in edible_materials) + if(material == substance) allowed = TRUE + if(!allowed) + return if(refactory.add_stored_material(S.material.name,1*S.perunit) && S.use(1)) visible_message("[name] gloms over some of \the [S], absorbing it.") else @@ -201,6 +217,13 @@ /mob/living/simple_animal/protean_blob/attackby(var/obj/item/O, var/mob/user) if(refactory && istype(O,/obj/item/stack/material)) var/obj/item/stack/material/S = O + var/substance = S.material.name + var/list/edible_materials = list("steel", "plasteel", "diamond", "mhydrogen") //Can't eat all materials, just useful ones. + var allowed = FALSE + for(var/material in edible_materials) + if(material == substance) allowed = TRUE + if(!allowed) + return if(refactory.add_stored_material(S.material.name,1*S.perunit) && S.use(1)) visible_message("[name] gloms over some of \the [S], absorbing it.") else @@ -213,11 +236,13 @@ // Helpers - Unsafe, WILL perform change. /mob/living/carbon/human/proc/nano_intoblob() + handle_grasp() //It's possible to blob out before some key parts of the life loop. This results in things getting dropped at null. TODO: Fix the code so this can be done better. + remove_micros(src, src) //Living things don't fare well in roblobs. if(buckled) buckled.unbuckle_mob() if(LAZYLEN(buckled_mobs)) for(var/buckledmob in buckled_mobs) - unbuckle_mob(buckledmob, force = TRUE) + riding_datum.force_dismount(buckledmob) if(pulledby) pulledby.stop_pulling() stop_pulling() @@ -256,6 +281,9 @@ blob.transform = matrix()*size_multiplier blob.size_multiplier = size_multiplier + if(l_hand) blob.prev_left_hand = l_hand //Won't save them if dropped above, but necessary if handdrop is disabled. + if(r_hand) blob.prev_right_hand = r_hand + //Put our owner in it (don't transfer var/mind) blob.ckey = ckey temporary_form = blob @@ -265,7 +293,7 @@ //Message blob.visible_message("[src.name] collapses into a gooey blob!") - + //Duration of the to_puddle iconstate that the blob starts with sleep(13) blob.update_icon() //Will remove the collapse anim @@ -281,6 +309,13 @@ //Return our blob in case someone wants it return blob +//For some reason, there's no way to force drop all the mobs grabbed. This ought to fix that. And be moved elsewhere. Call with caution, doesn't handle cycles. +/proc/remove_micros(var/src, var/mob/root) + for(var/obj/item/I in src) + remove_micros(I, root) //Recursion. I'm honestly depending on there being no containment loop, but at the cost of performance that can be fixed too. + if(istype(I, /obj/item/weapon/holder)) + root.remove_from_mob(I) + /mob/living/carbon/human/proc/nano_outofblob(var/mob/living/simple_animal/protean_blob/blob) if(!istype(blob)) return @@ -288,11 +323,11 @@ buckled.unbuckle_mob() if(LAZYLEN(buckled_mobs)) for(var/buckledmob in buckled_mobs) - unbuckle_mob(buckledmob, force = TRUE) + riding_datum.force_dismount(buckledmob) if(pulledby) pulledby.stop_pulling() stop_pulling() - + //Stop healing if we are if(blob.healing) blob.healing.expire() @@ -302,7 +337,7 @@ //Message blob.visible_message("[src.name] reshapes into a humanoid appearance!") - + //Duration of above animation sleep(8) @@ -319,7 +354,6 @@ //Put our owner in it (don't transfer var/mind) ckey = blob.ckey temporary_form = null - Life(1) //Fix my blindness right meow //Transfer vore organs vore_selected = blob.vore_selected @@ -327,7 +361,12 @@ var/obj/belly/B = belly B.forceMove(src) B.owner = src - + + if(blob.prev_left_hand) put_in_l_hand(blob.prev_left_hand) //The restore for when reforming. + if(blob.prev_right_hand) put_in_r_hand(blob.prev_right_hand) + + Life(1) //Fix my blindness right meow //Has to be moved up here, there exists a circumstance where blob could be deleted without vore organs moving right. + //Get rid of friend blob qdel(blob) diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_powers.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_powers.dm index 4b3b6891add..d6f65e6f636 100644 --- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_powers.dm +++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_powers.dm @@ -24,7 +24,7 @@ return //Organ is missing, needs restoring - if(!organs_by_name[choice]) + if(!organs_by_name[choice] || istype(organs_by_name[choice], /obj/item/organ/external/stump)) //allows limb stumps to regenerate like removed limbs. if(refactory.get_stored_material(DEFAULT_WALL_MATERIAL) < PER_LIMB_STEEL_COST) to_chat(src,"You're missing that limb, and need to store at least [PER_LIMB_STEEL_COST] steel to regenerate it.") return @@ -33,6 +33,10 @@ return if(!refactory.use_stored_material(DEFAULT_WALL_MATERIAL,PER_LIMB_STEEL_COST)) return + if(organs_by_name[choice]) + var/obj/item/organ/external/oldlimb = organs_by_name[choice] + oldlimb.removed() + qdel(oldlimb) var/mob/living/simple_animal/protean_blob/blob = nano_intoblob() active_regen = TRUE @@ -60,7 +64,7 @@ usable_manufacturers[company] = M if(!usable_manufacturers.len) return - var/manu_choice = input(src, "Which manufacturer do you wish to mimmic for this limb?", "Manufacturer for [choice]") as null|anything in usable_manufacturers + var/manu_choice = input(src, "Which manufacturer do you wish to mimic for this limb?", "Manufacturer for [choice]") as null|anything in usable_manufacturers if(!manu_choice) return //Changed mind @@ -70,13 +74,13 @@ return //Lost it meanwhile eo.robotize(manu_choice) - visible_message("[src]'s ") + visible_message("[src]'s [choice] loses its shape, then reforms.") update_icons_body() //// // Full Refactor //// -/mob/living/carbon/human/proc/nano_regenerate() +/mob/living/carbon/human/proc/nano_regenerate() //fixed the proc, it used to leave active_regen true. set name = "Ref - Whole Body" set desc = "Allows you to regrow limbs and replace organs, given you have enough materials." set category = "Abilities" @@ -97,7 +101,7 @@ to_chat(src, "You are already refactoring!") return - var/swap_not_rebuild = alert(src,"Do you want to rebuild, or reshape?","Rebuild or Reshape","Rebuild","Cancel","Reshape") + var/swap_not_rebuild = alert(src,"Do you want to rebuild, or reshape?","Rebuild or Reshape","Reshape","Cancel","Rebuild") if(swap_not_rebuild == "Cancel") return if(swap_not_rebuild == "Reshape") @@ -113,7 +117,7 @@ usable_manufacturers[company] = M if(!usable_manufacturers.len) return - var/manu_choice = input(src, "Which manufacturer do you wish to mimmic?", "Manufacturer") as null|anything in usable_manufacturers + var/manu_choice = input(src, "Which manufacturer do you wish to mimic?", "Manufacturer") as null|anything in usable_manufacturers if(!manu_choice) return //Changed mind @@ -123,7 +127,7 @@ var/obj/item/organ/external/torso = organs_by_name[BP_TORSO] to_chat(src, "Remain still while the process takes place! It will take 5 seconds.") visible_message("[src]'s form collapses into an amorphous blob of black ichor...") - + var/mob/living/simple_animal/protean_blob/blob = nano_intoblob() active_regen = TRUE if(do_after(blob,5 SECONDS)) @@ -145,13 +149,13 @@ visible_message("[src]'s form begins to shift and ripple as if made of oil...") active_regen = TRUE - nano_intoblob() - if(do_after(src,delay_length)) + var/mob/living/simple_animal/protean_blob/blob = nano_intoblob() + if(do_after(blob, delay_length, null, 0)) if(stat != DEAD && refactory) var/list/holder = refactory.materials species.create_organs(src) var/obj/item/organ/external/torso = organs_by_name[BP_TORSO] - torso.robotize(synthetic.company) + torso.robotize() //synthetic wasn't defined here. LAZYCLEARLIST(blood_DNA) LAZYCLEARLIST(feet_blood_DNA) blood_color = null @@ -162,9 +166,15 @@ log_debug("[src] protean-regen'd but lacked a refactory when done.") else new_refactory.materials = holder - to_chat(src, "Your refactoring is complete!") + to_chat(src, "Your refactoring is complete.") //Guarantees the message shows no matter how bad the timing. + to_chat(blob, "Your refactoring is complete!") + else + to_chat(src, "Your refactoring has failed.") + to_chat(blob, "Your refactoring has failed!") else - to_chat(src, "Your refactoring is interrupted!") + to_chat(src, "Your refactoring is interrupted.") + to_chat(blob, "Your refactoring is interrupted!") + active_regen = FALSE nano_outofblob() @@ -189,11 +199,19 @@ return var/obj/item/stack/material/matstack = held + var/substance = matstack.material.name + var/list/edible_materials = list("steel", "plasteel", "diamond", "mhydrogen") //Can't eat all materials, just useful ones. + var allowed = FALSE + for(var/material in edible_materials) + if(material == substance) allowed = TRUE + if(!allowed) + to_chat(src,"You can't process [substance]!") + return //Only a few things matter, the rest are best not cluttering the lists. + var/howmuch = input(src,"How much do you want to store? (0-[matstack.amount])","Select amount") as null|num if(!howmuch || matstack != get_active_hand() || howmuch > matstack.amount) return //Quietly fail - var/substance = matstack.material.name var/actually_added = refactory.add_stored_material(substance,howmuch*matstack.perunit) matstack.use(Ceiling(actually_added/matstack.perunit)) if(actually_added && actually_added < howmuch) @@ -222,7 +240,7 @@ to_chat(temporary_form,"You can only do this while not stunned.") else nano_outofblob(temporary_form) - + //Human form else if(stat) to_chat(src,"You can only do this while not stunned.") @@ -241,7 +259,7 @@ if(stat) to_chat(src,"You must be awake and standing to perform this action!") return - + var/new_species = input("Please select a species to emulate.", "Shapeshifter Body") as null|anything in playable_species if(new_species) impersonate_bodytype = new_species @@ -269,7 +287,7 @@ return var/size_factor = new_size/100 - + //Will be: -1.75 for 200->25, and 1.75 for 25->200 var/sizediff = size_factor - user.size_multiplier @@ -361,7 +379,7 @@ desc = "Rebuild or replace a single limb, assuming you have 2000 steel." icon_state = "limb" to_call = /mob/living/carbon/human/proc/nano_partswap - + /obj/effect/protean_ability/reform_body ability_name = "Ref - Whole Body" desc = "Rebuild your entire body into whatever design you want, assuming you have 10,000 metal." diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm index 05237f5742a..52aad66fccf 100644 --- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm +++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm @@ -21,6 +21,7 @@ health_hud_intensity = 2 num_alternate_languages = 3 species_language = LANGUAGE_SOL_COMMON + assisted_langs = list(LANGUAGE_EAL) color_mult = TRUE breath_type = null @@ -115,7 +116,7 @@ /datum/species/protean/create_organs(var/mob/living/carbon/human/H) var/obj/item/device/nif/saved_nif = H.nif if(saved_nif) - H.nif.unimplant() + H.nif.unimplant(H) //Needs reference to owner to unimplant right. H.nif.forceMove(null) ..() if(saved_nif) @@ -162,13 +163,14 @@ /datum/species/protean/handle_death(var/mob/living/carbon/human/H) to_chat(H,"You died as a Protean. Please sit out of the round for at least 30 minutes before respawning, to represent the time it would take to ship a new-you to the station.") - spawn(1) + spawn(1) //This spawn is here so that if the protean_blob calls qdel, it doesn't try to gib the humanform. if(H) H.gib() /datum/species/protean/handle_environment_special(var/mob/living/carbon/human/H) if((H.getActualBruteLoss() + H.getActualFireLoss()) > H.maxHealth*0.5 && isturf(H.loc)) //So, only if we're not a blob (we're in nullspace) or in someone (or a locker, really, but whatever) H.nano_intoblob() + return ..() //Any instakill shot runtimes since there are no organs after this. No point to not skip these checks, going to nullspace anyway. var/obj/item/organ/internal/nano/refactory/refactory = locate() in H.internal_organs if(refactory && !(refactory.status & ORGAN_DEAD)) diff --git a/code/modules/organs/subtypes/nano.dm b/code/modules/organs/subtypes/nano.dm index 39398f5909a..fe23f37f851 100644 --- a/code/modules/organs/subtypes/nano.dm +++ b/code/modules/organs/subtypes/nano.dm @@ -109,9 +109,9 @@ /obj/item/organ/internal/nano/refactory/proc/use_stored_material(var/material,var/amt) if(status & ORGAN_DEAD) return 0 - + var/available = materials[material] - + //Success if(available >= amt) var/new_amt = available-amt @@ -141,12 +141,13 @@ . = ..() icon_state = "posi1" + /obj/item/organ/internal/mmi_holder/posibrain/nano/update_from_mmi() . = ..() icon = initial(icon) icon_state = "posi1" stored_mmi.icon_state = "posi1" - + stored_mmi.brainmob.languages = owner.languages // The 'out on the ground' object, not the organ holder