diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm index 2e14fb96eb..7bb32fa75c 100644 --- a/code/__defines/damage_organs.dm +++ b/code/__defines/damage_organs.dm @@ -49,6 +49,7 @@ #define ORGAN_ASSISTED 1 // Like pacemakers, not robotic #define ORGAN_ROBOT 2 // Fully robotic, no organic parts #define ORGAN_LIFELIKE 3 // Robotic, made to appear organic +#define ORGAN_NANOFORM 4 // VOREStation Add - Fully nanoswarm organ //Germs and infections. #define GERM_LEVEL_AMBIENT 110 // Maximum germ level you can reach by standing still. diff --git a/code/__defines/mobs_vr.dm b/code/__defines/mobs_vr.dm index b8a1f86a24..2b573e334d 100644 --- a/code/__defines/mobs_vr.dm +++ b/code/__defines/mobs_vr.dm @@ -8,3 +8,7 @@ #define VIS_AUGMENTED 25 #define VIS_COUNT 25 + +//Protean organs +#define O_ORCH "orchestrator" +#define O_FACT "refactory" diff --git a/code/modules/mob/living/carbon/human/human_defines_vr.dm b/code/modules/mob/living/carbon/human/human_defines_vr.dm index fabc19d584..d3bb4f0b57 100644 --- a/code/modules/mob/living/carbon/human/human_defines_vr.dm +++ b/code/modules/mob/living/carbon/human/human_defines_vr.dm @@ -6,3 +6,4 @@ var/wagging = 0 //UGH. var/flapping = 0 var/vantag_pref = VANTAG_NONE //What's my status? + var/impersonate_bodytype //For impersonating a bodytype \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_species_vr.dm b/code/modules/mob/living/carbon/human/human_species_vr.dm index 52ca3f0426..45b615c240 100644 --- a/code/modules/mob/living/carbon/human/human_species_vr.dm +++ b/code/modules/mob/living/carbon/human/human_species_vr.dm @@ -18,4 +18,10 @@ ..(new_loc, "Xenomorph Hybrid") /mob/living/carbon/human/spider/New(var/new_loc) - ..(new_loc, "Vasilissan") \ No newline at end of file + ..(new_loc, "Vasilissan") + +/mob/living/carbon/human/vulpkanin/New(var/new_loc) + ..(new_loc, "Vulpkanin") + +/mob/living/carbon/human/protean/New(var/new_loc) + ..(new_loc, "Protean") diff --git a/code/modules/mob/living/carbon/human/species/station/monkey_vr.dm b/code/modules/mob/living/carbon/human/species/station/monkey_vr.dm index 2ea5ee3c1a..f56faa515a 100644 --- a/code/modules/mob/living/carbon/human/species/station/monkey_vr.dm +++ b/code/modules/mob/living/carbon/human/species/station/monkey_vr.dm @@ -65,5 +65,5 @@ /mob/living/carbon/human/sparram/New(var/new_loc) ..(new_loc, "Sparra") -/mob/living/carbon/human/vulpkaninm/New(var/new_loc) +/mob/living/carbon/human/wolpin/New(var/new_loc) ..(new_loc, "Wolpin") \ No newline at end of file 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 new file mode 100644 index 0000000000..f51510a535 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm @@ -0,0 +1,309 @@ +// Simple animal nanogoopeyness +/mob/living/simple_animal/protean_blob + name = "protean blob" + desc = "Some sort of big viscous pool of jelly." + tt_desc = "Animated nanogoop" + icon = 'icons/mob/species/protean/protean.dmi' + icon_state = "to_puddle" + icon_living = "puddle2" + icon_rest = "rest" + icon_dead = "puddle" + + faction = "neutral" + maxHealth = 200 + health = 200 + + ai_inactive = TRUE //Always off + show_stat_health = FALSE //We will do it ourselves + + response_help = "pats the" + response_disarm = "gently pushes aside the" + response_harm = "hits the" + + harm_intent_damage = 2 + melee_damage_lower = 10 + melee_damage_upper = 10 + attacktext = list("slashed") + + min_oxy = 0 + max_oxy = 0 + min_tox = 0 + max_tox = 0 + min_co2 = 0 + max_co2 = 0 + min_n2 = 0 + max_n2 = 0 + minbodytemp = 0 + maxbodytemp = 900 + + speak_chance = 1 + speak = list("Blrb?","Sqrsh.","Glrsh!") + emote_hear = list("squishes softly","spluts quietly","makes wet noises") + emote_see = list("shifts wetly","undulates placidly") + + var/mob/living/carbon/human/humanform + var/obj/item/organ/internal/nano/refactory/refactory + var/datum/modifier/healing + + 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!" + +//Constructor allows passing the human to sync damages +/mob/living/simple_animal/protean_blob/New(var/newloc, var/mob/living/carbon/human/H) + ..() + if(H) + humanform = H + updatehealth() + refactory = locate() in humanform.internal_organs + verbs |= /mob/living/simple_animal/protean_blob/proc/revert_form + verbs |= /mob/living/proc/ventcrawl + verbs |= /mob/living/proc/hide + else + update_icon() + +/mob/living/simple_animal/protean_blob/Destroy() + humanform = null + refactory = null + vore_organs = null + vore_selected = null + if(healing) + healing.expire() + return ..() + +/mob/living/simple_animal/protean_blob/Stat() + ..() + if(statpanel("Status")) + stat(null, "- -- --- Protean Stats --- -- -") + stat(null, "Condition: [health]/[maxHealth]") + if(refactory) + var/max = refactory.max_storage + for(var/material in refactory.materials) + var/amount = refactory.get_stored_material(material) + stat(null, "[capitalize(material)]: [amount]/[max]") + +/mob/living/simple_animal/protean_blob/proc/revert_form() + set name = "Ref - Humanoid" + set desc = "Regain your humanoid form." + set category = "Abilities" + + if(health < maxHealth*0.5) + to_chat(src,"You're too injured for that! Regenerate using steel first.") + return + + if(humanform) + humanform.nano_outofblob(src) + else + to_chat(src,"Something's gone terribly wrong and we can't find your human body. Admin-help this.") + return + +/mob/living/simple_animal/protean_blob/update_icon() + if(humanform) + //Still have a refactory + if(istype(refactory)) + icon_living = "puddle2" + + //Else missing one + else + icon_living = "puddle1" + + //Not human-based + else + icon_living = "puddle0" + + ..() + +/mob/living/simple_animal/protean_blob/updatehealth() + if(humanform) + //Set the max + maxHealth = humanform.getMaxHealth()*2 //HUMANS, and their 'double health', bleh. + //Set us to their health, but, human health ignores robolimbs so we do it 'the hard way' + health = maxHealth - humanform.getOxyLoss() - humanform.getToxLoss() - humanform.getCloneLoss() - humanform.getActualFireLoss() - humanform.getActualBruteLoss() + + //Alive, becoming dead + if((stat < DEAD) && (health <= 0)) + death() + + //Overhealth + if(health > getMaxHealth()) + health = getMaxHealth() + + //Update our hud if we have one + if(healths) + if(stat != DEAD) + var/heal_per = (health / getMaxHealth()) * 100 + switch(heal_per) + if(100 to INFINITY) + healths.icon_state = "health0" + if(80 to 100) + healths.icon_state = "health1" + if(60 to 80) + healths.icon_state = "health2" + if(40 to 60) + healths.icon_state = "health3" + if(20 to 40) + healths.icon_state = "health4" + if(0 to 20) + healths.icon_state = "health5" + else + healths.icon_state = "health6" + else + healths.icon_state = "health7" + else + ..() + +/mob/living/simple_animal/protean_blob/adjustBruteLoss(var/amount) + if(humanform) + humanform.adjustBruteLoss(amount) + else + ..() + +/mob/living/simple_animal/protean_blob/adjustFireLoss(var/amount) + if(humanform) + humanform.adjustFireLoss(amount) + else + ..() + +/mob/living/simple_animal/protean_blob/death(gibbed, deathmessage = "dissolves away, leaving only a few spare parts!") + if(humanform) + humanform.death(gibbed = gibbed) + for(var/organ in humanform.internal_organs) + 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) + sleep(2 SECONDS) + qdel(src) + + ..() + +/mob/living/simple_animal/protean_blob/Life() + . = ..() + if(. && istype(refactory) && humanform) + if(!healing && health < maxHealth && refactory.get_stored_material(DEFAULT_WALL_MATERIAL) >= 100) + healing = humanform.add_modifier(/datum/modifier/protean/steel, origin = refactory) + else if(healing && health == maxHealth) + healing.expire() + healing = null + +/mob/living/simple_animal/protean_blob/lay_down() + ..() + if(resting) + animate(src,alpha = 40,time = 1 SECOND) + mouse_opacity = 0 + else + mouse_opacity = 1 + icon_state = "wake" + animate(src,alpha = 255,time = 1 SECOND) + sleep(7) + update_icon() + //Potential glob noms + if(can_be_drop_pred) //Toggleable in vore panel + var/list/potentials = living_mobs(0) + if(potentials.len) + var/mob/living/target = pick(potentials) + if(istype(target) && vore_selected) + target.forceMove(vore_selected) + to_chat(target,"\The [src] quickly engulfs you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!") + +/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 + 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 + return ..() + +/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 + 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 + return ..() + +/mob/living/simple_animal/protean_blob/MouseEntered(location,control,params) + if(resting) + return + ..() + +// Helpers - Unsafe, WILL perform change. +/mob/living/carbon/human/proc/nano_intoblob() + if(buckled) + buckled.unbuckle_mob() + if(pulledby) + pulledby.stop_pulling() + stop_pulling() + + //Record where they should go + var/atom/creation_spot = drop_location() + + //Create our new blob + var/mob/living/simple_animal/protean_blob/blob = new(creation_spot,src) + + //Put our owner in it (don't transfer var/mind) + blob.ckey = ckey + temporary_form = blob + + //Mail them to nullspace + forceMove(null) + + //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 + + //Transfer vore organs + blob.vore_organs = vore_organs + blob.vore_selected = vore_selected + for(var/belly in vore_organs) + var/obj/belly/B = belly + B.forceMove(blob) + + //Return our blob in case someone wants it + return blob + +/mob/living/carbon/human/proc/nano_outofblob(var/mob/living/simple_animal/protean_blob/blob) + if(!istype(blob)) + return + if(buckled) + buckled.unbuckle_mob() + if(pulledby) + pulledby.stop_pulling() + stop_pulling() + + //Stop healing if we are + if(blob.healing) + blob.healing.expire() + + //Play the animation + blob.icon_state = "from_puddle" + + //Message + blob.visible_message("[src.name] reshapes into a humanoid appearance!") + + //Duration of above animation + sleep(8) + + //Record where they should go + var/atom/reform_spot = blob.drop_location() + + //Move them back where the blob was + forceMove(reform_spot) + + //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 + for(var/belly in vore_organs) + var/obj/belly/B = belly + B.forceMove(src) + + //Get rid of friend blob + qdel(blob) + + //Return ourselves in case someone wants it + return src 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 new file mode 100644 index 0000000000..df6b44acdf --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_powers.dm @@ -0,0 +1,284 @@ +#define PER_LIMB_STEEL_COST SHEET_MATERIAL_AMOUNT +//// +// One-part Refactor +//// +/mob/living/carbon/human/proc/nano_partswap() + set name = "Ref - Single Limb" + set desc = "Allows you to replace and reshape your limbs as you see fit." + set category = "Abilities" + set hidden = TRUE + + if(stat) + to_chat(src,"You must be awake and standing to perform this action!") + return + + var/obj/item/organ/internal/nano/refactory/refactory = locate() in internal_organs + if(!refactory || refactory.status & ORGAN_DEAD) + to_chat(src,"You don't have a refactory module!") + return + + var/choice = input(src,"Pick the bodypart to change:", "Refactor - One Bodypart") as null|anything in species.has_limbs + if(!choice) + return + + //Organ is missing, needs restoring + if(!organs_by_name[choice]) + 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 + var/regen = alert(src,"That limb is missing, do you want to regenerate it in exchange for [PER_LIMB_STEEL_COST] steel?","Regenerate limb?","Yes","No") + if(regen != "Yes") + return + if(!refactory.use_stored_material(DEFAULT_WALL_MATERIAL,PER_LIMB_STEEL_COST)) + return + + var/mob/living/simple_animal/protean_blob/blob = nano_intoblob() + active_regen = TRUE + if(do_after(blob,5 SECONDS)) + var/list/limblist = species.has_limbs[choice] + var/limbpath = limblist["path"] + var/obj/item/organ/external/new_eo = new limbpath(src) + organs_by_name[choice] = new_eo + new_eo.robotize(synthetic ? synthetic.company : null) //Use the base we started with + regenerate_icons() + active_regen = FALSE + nano_outofblob(blob) + return + + //Organ exists, let's reshape it + var/list/usable_manufacturers = list() + for(var/company in chargen_robolimbs) + var/datum/robolimb/M = chargen_robolimbs[company] + if(!(choice in M.parts)) + continue + if(species.name in M.species_cannot_use) + continue + if(M.whitelisted_to && !(ckey in M.whitelisted_to)) + continue + 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 + + if(!manu_choice) + return //Changed mind + + var/obj/item/organ/external/eo = organs_by_name[choice] + if(!eo) + return //Lost it meanwhile + + eo.robotize(manu_choice) + visible_message("[src]'s ") + update_icons_body() +#undef PER_LIMB_STEEL_COST + +//// +// Full Refactor +//// +/mob/living/carbon/human/proc/nano_regenerate() + set name = "Ref - Whole Body" + set desc = "Allows you to regrow limbs and replace organs, given you have enough materials." + set category = "Abilities" + set hidden = TRUE + + if(stat) + to_chat(src,"You must be awake and standing to perform this action!") + return + + var/obj/item/organ/internal/nano/refactory/refactory = locate() in internal_organs + //Missing the organ that does this + if(!istype(refactory)) + to_chat(src,"You don't have a refactory module!") + return + + //Already regenerating + if(active_regen) + 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") + if(swap_not_rebuild == "Cancel") + return + if(swap_not_rebuild == "Reshape") + var/list/usable_manufacturers = list() + for(var/company in chargen_robolimbs) + var/datum/robolimb/M = chargen_robolimbs[company] + if(!(BP_TORSO in M.parts)) + continue + if(species.name in M.species_cannot_use) + continue + if(M.whitelisted_to && !(ckey in M.whitelisted_to)) + continue + 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 + + if(!manu_choice) + return //Changed mind + if(!organs_by_name[BP_TORSO]) + return //Ain't got a torso! + + 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)) + synthetic = usable_manufacturers[manu_choice] + torso.robotize(manu_choice) //Will cascade to all other organs. + regenerate_icons() + visible_message("[src]'s form reshapes into a new one...") + active_regen = FALSE + nano_outofblob(blob) + return + + //Not enough resources (AND spends the resources, should be the last check) + if(!refactory.use_stored_material(DEFAULT_WALL_MATERIAL,refactory.max_storage)) + to_chat(src, "You need to be maxed out on normal metal to do this!") + return + + var/delay_length = round(active_regen_delay * species.active_regen_mult) + to_chat(src, "Remain still while the process takes place! It will take [delay_length/10] seconds.") + 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)) + 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) + LAZYCLEARLIST(blood_DNA) + LAZYCLEARLIST(feet_blood_DNA) + blood_color = null + feet_blood_color = null + regenerate_icons() //Probably worth it, yeah. + var/obj/item/organ/internal/nano/refactory/new_refactory = locate() in internal_organs + if(!new_refactory) + log_debug("[src] protean-regen'd but lacked a refactory when done.") + else + new_refactory.materials = holder + to_chat(src, "Your refactoring is complete!") + else + to_chat(src, "Your refactoring is interrupted!") + nano_outofblob() + + +//// +// Storing metal +//// +/mob/living/carbon/human/proc/nano_metalnom() + set name = "Ref - Store Metals" + set desc = "If you're holding a stack of material, you can consume some and store it for later." + set category = "Abilities" + set hidden = TRUE + + var/obj/item/organ/internal/nano/refactory/refactory = locate() in internal_organs + //Missing the organ that does this + if(!istype(refactory)) + to_chat(src,"You don't have a refactory module!") + return + + var/held = get_active_hand() + if(!istype(held,/obj/item/stack/material)) + to_chat(src,"You aren't holding a stack of materials in your active hand...!") + return + + var/obj/item/stack/material/matstack = held + 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 < howmuch) + to_chat(src,"Your refactory module is now full, so only [actually_added] units were stored.") + else + to_chat(src,"You store [actually_added] units of [substance].") + +//// +// Blob Form +//// +/mob/living/carbon/human/proc/nano_blobform() + set name = "Become Amorphous" + set desc = "Drop your shape and assume a more natural form." + set category = "Abilities" + set hidden = TRUE + + if(stat) + to_chat(src,"You must be awake and standing to perform this action!") + return + + nano_intoblob() + +//// +// Change fitting +//// + +/mob/living/carbon/human/proc/nano_change_fitting() + set name = "Change Species Fit" + set desc = "Tweak your shape to change what suits you fit into (and their sprites!)." + set category = "Abilities" + + 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 + regenerate_icons() + +/// /// /// Ability objects for stat panel +/obj/effect/protean_ability + name = "Activate" + desc = "" + icon = 'icons/mob/species/protean/protean_powers.dmi' + var/ability_name + var/to_call + +/obj/effect/protean_ability/proc/atom_button_text() + return src + +/obj/effect/protean_ability/Click(var/location, var/control, var/params) + var/list/clickprops = params2list(params) + var/opts = clickprops["shift"] + + if(opts) + to_chat(usr,"[ability_name] - [desc]") + else + do_ability(usr) + +/obj/effect/protean_ability/proc/do_ability(var/mob/living/carbon/human/H) + if(istype(H) && !H.stat) + call(H,to_call)() + return FALSE + +/// The actual abilities +/obj/effect/protean_ability/into_blob + ability_name = "Become Amorphous" + desc = "Discard your shape entirely, changing to a low-energy blob that can fit into small spaces. You'll consume steel to repair yourself in this form." + icon_state = "blob" + to_call = /mob/living/carbon/human/proc/nano_blobform + +/obj/effect/protean_ability/reform_limb + ability_name = "Ref - Single Limb" + 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." + icon_state = "body" + to_call = /mob/living/carbon/human/proc/nano_regenerate + +/obj/effect/protean_ability/metal_nom + ability_name = "Ref - Store Metals" + desc = "Store the metal you're holding. Your refactory can only store steel, and all other metals will be converted into nanites ASAP for various effects." + icon_state = "metal" + to_call = /mob/living/carbon/human/proc/nano_metalnom 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 new file mode 100644 index 0000000000..53b84c33a7 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm @@ -0,0 +1,303 @@ +#define DAM_SCALE_FACTOR 0.01 +/datum/species/protean + name = "Protean" + name_plural = "Proteans" + blurb = "Sometimes very advanced civilizations will produce the ability to swap into manufactured, robotic bodies. And sometimes \ + VERY advanced civilizations have the option of 'nanoswarm' bodies. Effectively a single robot body comprised \ + of millions of tiny nanites working in concert to maintain cohesion." + show_ssd = "totally quiescent" + death_message = "rapidly loses cohesion, dissolving into a cloud of gray dust..." + knockout_message = "collapses inwards, forming a disordered puddle of gray goo." + remains_type = /obj/effect/decal/cleanable/ash + + blood_color = "#000000" + flesh_color = "#000000" + + flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT | NO_HALLUCINATION | NO_INFECT | NO_PAIN + appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_HAIR_COLOR | HAS_UNDERWEAR | HAS_LIPS + spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED + health_hud_intensity = 2 + num_alternate_languages = 3 + species_language = LANGUAGE_SOL_COMMON + + breath_type = null + poison_type = null + + virus_immune = 1 + blood_volume = 0 + min_age = 18 + max_age = 200 + brute_mod = 0.2 //Brute isn't very effective, they're made of dust + burn_mod = 2.0 //Burn, however, is + oxy_mod = 0 + + cold_level_1 = 280 //Default 260 - Lower is better + cold_level_2 = 220 //Default 200 + cold_level_3 = 130 //Default 120 + + heat_level_1 = 320 //Default 360 + heat_level_2 = 370 //Default 400 + heat_level_3 = 600 //Default 1000 + + //Space doesn't bother them + hazard_low_pressure = -1 + hazard_high_pressure = 200 //They can cope with slightly higher pressure + + //Cold/heat does affect them, but it's done in special ways below + cold_level_1 = -INFINITY + cold_level_2 = -INFINITY + cold_level_3 = -INFINITY + heat_level_1 = INFINITY + heat_level_2 = INFINITY + heat_level_3 = INFINITY + + body_temperature = 290 + + siemens_coefficient = 3 //Very bad zappy times + rarity_value = 5 + + has_organ = list( + O_BRAIN = /obj/item/organ/internal/mmi_holder/posibrain/nano, + O_ORCH = /obj/item/organ/internal/nano/orchestrator, + O_FACT = /obj/item/organ/internal/nano/refactory + ) + has_limbs = list( + BP_TORSO = list("path" = /obj/item/organ/external/chest/unbreakable/nano), + BP_GROIN = list("path" = /obj/item/organ/external/groin/unbreakable/nano), + BP_HEAD = list("path" = /obj/item/organ/external/head/unbreakable/nano), + BP_L_ARM = list("path" = /obj/item/organ/external/arm/unbreakable/nano), + BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/unbreakable/nano), + BP_L_LEG = list("path" = /obj/item/organ/external/leg/unbreakable/nano), + BP_R_LEG = list("path" = /obj/item/organ/external/leg/right/unbreakable/nano), + BP_L_HAND = list("path" = /obj/item/organ/external/hand/unbreakable/nano), + BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/unbreakable/nano), + BP_L_FOOT = list("path" = /obj/item/organ/external/foot/unbreakable/nano), + BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/unbreakable/nano) + ) + + heat_discomfort_strings = list("You feel too warm.") + cold_discomfort_strings = list("You feel too cool.") + + //These verbs are hidden, for hotkey use only + inherent_verbs = list( + /mob/living/carbon/human/proc/nano_regenerate, //These verbs are hidden so you can macro them, + /mob/living/carbon/human/proc/nano_partswap, + /mob/living/carbon/human/proc/nano_metalnom, + /mob/living/carbon/human/proc/nano_blobform, + /mob/living/carbon/human/proc/nano_change_fitting, //These verbs are displayed normally, + /mob/living/carbon/human/proc/shapeshifter_select_hair, + /mob/living/carbon/human/proc/shapeshifter_select_hair_colors, + /mob/living/carbon/human/proc/shapeshifter_select_colour, + /mob/living/carbon/human/proc/shapeshifter_select_eye_colour + ) + + var/global/list/abilities = list() + + var/monochromatic = FALSE //IGNORE ME + +/datum/species/protean/New() + ..() + if(!LAZYLEN(abilities)) + var/list/powertypes = subtypesof(/obj/effect/protean_ability) + for(var/path in powertypes) + abilities += new path() + +/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.forceMove(null) + ..() + if(saved_nif) + saved_nif.quick_implant(H) + +/datum/species/protean/get_bodytype(var/mob/living/carbon/human/H) + if(H) + return H.impersonate_bodytype || ..() + return ..() + +/datum/species/protean/handle_post_spawn(var/mob/living/carbon/human/H) + ..() + H.synth_color = TRUE + +/datum/species/protean/equip_survival_gear(var/mob/living/carbon/human/H) + var/obj/item/stack/material/steel/metal_stack = new() + metal_stack.amount = 3 + + var/obj/item/clothing/accessory/permit/nanotech/permit = new() + permit.set_name(H.real_name) + + if(H.backbag == 1) //Somewhat misleading, 1 == no bag (not boolean) + H.equip_to_slot_or_del(permit, slot_l_hand) + H.equip_to_slot_or_del(metal_stack, slot_r_hand) + else + H.equip_to_slot_or_del(permit, slot_in_backpack) + H.equip_to_slot_or_del(metal_stack, slot_in_backpack) + + spawn(0) //Let their real nif load if they have one + if(!H.nif) + var/obj/item/device/nif/bioadap/new_nif = new() + new_nif.quick_implant(H) + else + H.nif.durability = rand(21,25) + +/datum/species/protean/hug(var/mob/living/carbon/human/H, var/mob/living/target) + return ..() //Wut + +/datum/species/protean/get_blood_colour(var/mob/living/carbon/human/H) + return rgb(80,80,80,230) + +/datum/species/protean/get_flesh_colour(var/mob/living/carbon/human/H) + return rgb(80,80,80,230) + +/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) + 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() + + var/obj/item/organ/internal/nano/refactory/refactory = locate() in H.internal_organs + if(refactory && !(refactory.status & ORGAN_DEAD)) + + //MHydrogen adds speeeeeed + if(refactory.get_stored_material("mhydrogen") >= 100) + H.add_modifier(/datum/modifier/protean/mhydrogen, origin = refactory) + + //Plasteel adds brute armor + if(refactory.get_stored_material("plasteel") >= 100) + H.add_modifier(/datum/modifier/protean/plasteel, origin = refactory) + + //Diamond adds burn armor + if(refactory.get_stored_material("diamond") >= 100) + H.add_modifier(/datum/modifier/protean/diamond, origin = refactory) + + return ..() + +/datum/species/protean/get_additional_examine_text(var/mob/living/carbon/human/H) + return ..() //Hmm, what could be done here? + +/datum/species/protean/Stat(var/mob/living/carbon/human/H) + ..() + if(statpanel("Protean")) + var/obj/item/organ/internal/nano/refactory/refactory = locate() in H.internal_organs + if(refactory && !(refactory.status & ORGAN_DEAD)) + stat(null, "- -- --- Refactory Metal Storage --- -- -") + var/max = refactory.max_storage + for(var/material in refactory.materials) + var/amount = refactory.get_stored_material(material) + stat("[capitalize(material)]", "[amount]/[max]") + else + stat(null, "- -- --- REFACTORY ERROR! --- -- -") + + stat(null, "- -- --- Abilities (Shift+LMB Examines) --- -- -") + for(var/ability in abilities) + var/obj/effect/protean_ability/A = ability + stat("[A.ability_name]",A.atom_button_text()) + +// Various modifiers +/datum/modifier/protean + stacks = MODIFIER_STACK_FORBID + var/material_use = 100 + var/material_name = DEFAULT_WALL_MATERIAL + +/datum/modifier/protean/on_applied() + . = ..() + if(holder.temporary_form) + to_chat(holder.temporary_form,on_created_text) + +/datum/modifier/protean/on_expire() + . = ..() + if(holder.temporary_form) + to_chat(holder.temporary_form,on_expired_text) + +/datum/modifier/protean/tick() + //No origin set + if(!istype(origin)) + expire() + + //No refactory + var/obj/item/organ/internal/nano/refactory/refactory = origin.resolve() + if(!istype(refactory) || refactory.status & ORGAN_DEAD) + expire() + + //Out of materials + if(!refactory.use_stored_material(material_name,material_use)) + expire() + +/datum/modifier/protean/mhydrogen + name = "Protean Effect - M.Hydrogen" + desc = "You're affected by the presence of metallic hydrogen." + + on_created_text = "You feel yourself accelerate, the metallic hydrogen increasing your speed temporarily." + on_expired_text = "Your refactory finishes consuming the metallic hydrogen, and you return to normal speed." + + material_use = 100 + material_name = "mhydrogen" + + slowdown = -1 + +/datum/modifier/protean/plasteel + name = "Protean Effect - Plasteel" + desc = "You're affected by the presence of plasteel." + + on_created_text = "You feel yourself become nearly impervious to physical attacks as plasteel nanites are made." + on_expired_text = "Your refactory finishes consuming the plasteel, and you return to your normal nanites." + + material_use = 100 + material_name = "plasteel" + + incoming_brute_damage_percent = 0.5 + +/datum/modifier/protean/diamond + name = "Protean Effect - Diamond" + desc = "You're affected by the presence of diamond." + + on_created_text = "You feel yourself become more reflective, able to resist heat and fire better for a time." + on_expired_text = "Your refactory finishes consuming the diamond, and you return to your normal nanites." + + material_use = 100 + material_name = "diamond" + + incoming_fire_damage_percent = 0.2 + +/datum/modifier/protean/steel + name = "Protean Effect - Steel" + desc = "You're affected by the presence of steel." + + on_created_text = "You feel new nanites being produced from your stockpile of steel, healing you slowly." + on_expired_text = "Your steel supply has either run out, or is no longer needed, and your healing stops." + + material_use = 100 + material_name = "steel" + +/datum/modifier/protean/steel/tick() + ..() + holder.adjustBruteLoss(-10,include_robo = TRUE) //Looks high, but these ARE modified by species resistances, so this is really 20% of this + holder.adjustFireLoss(-1,include_robo = TRUE) //And this is really double this + var/mob/living/carbon/human/H = holder + for(var/organ in H.internal_organs) + var/obj/item/organ/O = organ + // Fix internal damage + if(O.damage > 0) + O.damage = max(0,O.damage-0.1) + // If not damaged, but dead, fix it + else if(O.status & ORGAN_DEAD) + O.status &= ~ORGAN_DEAD //Unset dead if we repaired it entirely + +// PAN Card +/obj/item/clothing/accessory/permit/nanotech + name = "\improper P.A.N. card" + desc = "This is a 'Permit for Advanced Nanotechnology' card. It allows the owner to possess and operate advanced nanotechnology on NanoTrasen property. It must be renewed on a monthly basis." + icon = 'icons/mob/species/protean/protean.dmi' + icon_state = "permit_pan" +/obj/item/clothing/accessory/permit/nanotech/set_name(var/new_name) + owner = 1 + if(new_name) + src.name += " ([new_name])" + desc += "\nVALID THROUGH END OF: [time2text(world.timeofday, "Month") +" "+ num2text(text2num(time2text(world.timeofday, "YYYY"))+544)]\nREGISTRANT: [new_name]" + +#undef DAM_SCALE_FACTOR \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 6c7e0114ab..7ccfbec7d6 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -265,7 +265,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() if(part.robotic >= ORGAN_ROBOT) icon_key += "2[part.model ? "-[part.model]": ""]" robolimb_count++ - if(part.organ_tag == BP_HEAD || part.organ_tag == BP_TORSO || part.organ_tag == BP_GROIN) + if((part.robotic == ORGAN_ROBOT || part.robotic == ORGAN_LIFELIKE) && (part.organ_tag == BP_HEAD || part.organ_tag == BP_TORSO || part.organ_tag == BP_GROIN)) //VOREStation Edit - Not for nanoform parts robobody_count ++ else if(part.status & ORGAN_DEAD) icon_key += "3" diff --git a/code/modules/mob/mob_defines_vr.dm b/code/modules/mob/mob_defines_vr.dm index ab1670560f..829ae9b8fe 100644 --- a/code/modules/mob/mob_defines_vr.dm +++ b/code/modules/mob/mob_defines_vr.dm @@ -1,5 +1,4 @@ /mob - var/vantag_hud = 0 // Do I have the HUD enabled? - var/flying = 0 //Allows flight - var/can_be_drop_prey = 0 - var/can_be_drop_pred = 1 //Mobs are pred by default. \ No newline at end of file + var/vantag_hud = 0 // Do I have the HUD enabled? + var/flying = 0 // Allows flight + var/mob/temporary_form // For holding onto a temporary form diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index ba5de23d8e..4f85ee689d 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -816,7 +816,11 @@ Note that amputating the affected organ does in fact remove the infection from t if(!cannot_amputate) if(nonsolid && damage >= max_damage) - droplimb(DROPLIMB_BLUNT) + droplimb(TRUE, DROPLIMB_BLUNT) + //VOREStation Add Start + if(robotic >= ORGAN_NANOFORM && damage >= max_damage) + droplimb(TRUE, DROPLIMB_BURN) + //VOREStation Add End /**************************************************** DISMEMBERMENT @@ -827,8 +831,10 @@ Note that amputating the affected organ does in fact remove the infection from t if(cannot_amputate || !owner) return - - if(disintegrate == DROPLIMB_EDGE && nonsolid) + //VOREStation Add + if(robotic >= ORGAN_NANOFORM) + disintegrate = DROPLIMB_BURN //Ashes will be fine + else if(disintegrate == DROPLIMB_EDGE && nonsolid) //VOREStation Add End disintegrate = DROPLIMB_BLUNT //splut switch(disintegrate) diff --git a/code/modules/organs/subtypes/nano.dm b/code/modules/organs/subtypes/nano.dm new file mode 100644 index 0000000000..639fdec4e5 --- /dev/null +++ b/code/modules/organs/subtypes/nano.dm @@ -0,0 +1,155 @@ +// // // External Organs +/obj/item/organ/external/chest/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 50 // <-- This is different from the rest + min_broken_damage = 1000 + vital = TRUE // <-- This is different from the rest +/obj/item/organ/external/groin/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 30 // <-- This is different from the rest + min_broken_damage = 1000 //Multiple + vital = FALSE +/obj/item/organ/external/head/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 10 + min_broken_damage = 1000 //Inheritance + vital = FALSE +/obj/item/organ/external/arm/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 10 + min_broken_damage = 1000 //Please + vital = FALSE +/obj/item/organ/external/arm/right/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 10 + min_broken_damage = 1000 + vital = FALSE +/obj/item/organ/external/leg/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 10 + min_broken_damage = 1000 + vital = FALSE +/obj/item/organ/external/leg/right/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 10 + min_broken_damage = 1000 + vital = FALSE +/obj/item/organ/external/hand/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 10 + min_broken_damage = 1000 + vital = FALSE +/obj/item/organ/external/hand/right/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 10 + min_broken_damage = 1000 + vital = FALSE +/obj/item/organ/external/foot/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 10 + min_broken_damage = 1000 + vital = FALSE +/obj/item/organ/external/foot/right/unbreakable/nano + robotic = ORGAN_NANOFORM + encased = FALSE + max_damage = 10 + min_broken_damage = 1000 + vital = FALSE + +//Sideways override for nanoform limbs (ugh) +/obj/item/organ/external/robotize(var/company, var/skip_prosthetics = FALSE, var/keep_organs = FALSE) + var/original_robotic = robotic + if(original_robotic >= ORGAN_NANOFORM) + var/o_encased = encased + var/o_max_damage = max_damage + var/o_min_broken_damage = min_broken_damage + robotic = FALSE + ..(company = company, keep_organs = TRUE) + robotic = original_robotic + encased = o_encased + max_damage = o_max_damage + min_broken_damage = o_min_broken_damage + else + ..() + +// // // Internal Organs +/obj/item/organ/internal/nano + robotic = ORGAN_ROBOT + +/obj/item/organ/internal/nano/orchestrator + name = "orchestrator module" + desc = "A small computer, designed for highly parallel workloads." + icon = 'icons/mob/species/protean/protean.dmi' + icon_state = "orchestrator" + organ_tag = O_ORCH + parent_organ = BP_TORSO + vital = TRUE + +/obj/item/organ/internal/nano/refactory + name = "refactory module" + desc = "A miniature metal processing unit and nanite factory." + icon = 'icons/mob/species/protean/protean.dmi' + icon_state = "refactory" + organ_tag = O_FACT + parent_organ = BP_TORSO + + var/list/materials = list(DEFAULT_WALL_MATERIAL = 0) + var/max_storage = 10000 + +/obj/item/organ/internal/nano/refactory/proc/get_stored_material(var/material) + if(status & ORGAN_DEAD) + return 0 + return materials[material] || 0 + +/obj/item/organ/internal/nano/refactory/proc/add_stored_material(var/material,var/amt) + if(status & ORGAN_DEAD) + return 0 + var/increase = min(amt,max(max_storage-materials[material],0)) + if(isnum(materials[material])) + materials[material] += increase + else + materials[material] = increase + + return increase + +/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 + if(new_amt == 0) + materials -= material + else + materials[material] = new_amt + return amt + + //Failure + return 0 + +/obj/item/organ/internal/mmi_holder/posibrain/nano + name = "protean posibrain" + desc = "A more advanced version of the standard posibrain, typically found in protean bodies." + icon = 'icons/mob/species/protean/protean.dmi' + icon_state = "posi" + parent_organ = BP_TORSO + +/obj/item/organ/internal/mmi_holder/posibrain/nano/update_from_mmi() + ..() + icon = initial(icon) + icon_state = "posi1" + + stored_mmi.brainmob.languages = owner.languages diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm index bd4699533f..0e83e9ff21 100644 --- a/code/modules/surgery/robotics.dm +++ b/code/modules/surgery/robotics.dm @@ -18,7 +18,7 @@ return 0 if (affected.status & ORGAN_DESTROYED) return 0 - if (!(affected.robotic >= ORGAN_ROBOT)) + if (!(affected.robotic == ORGAN_ROBOT || affected.robotic == ORGAN_LIFELIKE)) //VOREStation Edit - No good on ORGAN_NANOFORM return 0 return 1 diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 2afba124df..d433572837 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -19,6 +19,8 @@ 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. var/fuzzy = 1 // Preference toggle for sharp/fuzzy icon. + var/can_be_drop_prey = 0 + var/can_be_drop_pred = 1 //Mobs are pred by default. // // Hook for generic creation of stuff on new creatures diff --git a/icons/mob/species/protean/protean.dmi b/icons/mob/species/protean/protean.dmi new file mode 100644 index 0000000000..f644aa051a Binary files /dev/null and b/icons/mob/species/protean/protean.dmi differ diff --git a/icons/mob/species/protean/protean_powers.dmi b/icons/mob/species/protean/protean_powers.dmi new file mode 100644 index 0000000000..48debef854 Binary files /dev/null and b/icons/mob/species/protean/protean_powers.dmi differ diff --git a/vorestation.dme b/vorestation.dme index d096cff779..4677710138 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2019,6 +2019,9 @@ #include "code\modules\mob\living\carbon\human\species\station\station_special_abilities_vr.dm" #include "code\modules\mob\living\carbon\human\species\station\station_special_vr.dm" #include "code\modules\mob\living\carbon\human\species\station\station_vr.dm" +#include "code\modules\mob\living\carbon\human\species\station\protean_vr\protean_blob.dm" +#include "code\modules\mob\living\carbon\human\species\station\protean_vr\protean_powers.dm" +#include "code\modules\mob\living\carbon\human\species\station\protean_vr\protean_species.dm" #include "code\modules\mob\living\carbon\human\species\station\traits_vr\negative.dm" #include "code\modules\mob\living\carbon\human\species\station\traits_vr\neutral.dm" #include "code\modules\mob\living\carbon\human\species\station\traits_vr\positive.dm" @@ -2274,6 +2277,7 @@ #include "code\modules\organs\internal\organ_internal.dm" #include "code\modules\organs\subtypes\diona.dm" #include "code\modules\organs\subtypes\machine.dm" +#include "code\modules\organs\subtypes\nano.dm" #include "code\modules\organs\subtypes\seromi.dm" #include "code\modules\organs\subtypes\slime.dm" #include "code\modules\organs\subtypes\standard.dm"