diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index d7e7f2a169..3788735d76 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1531,54 +1531,3 @@
var/obj/item/clothing/accessory/permit/drone/permit = new(T)
permit.set_name(real_name)
equip_to_appropriate_slot(permit) // If for some reason it can't find room, it'll still be on the floor.
-
-// enter_vr is called on the original mob, and puts the mind into the supplied vr mob
-/mob/living/carbon/human/proc/enter_vr(var/mob/living/carbon/human/avatar) // Avatar is currently a human, because we have preexisting setup code for appearance manipulation, etc.
- if(!istype(avatar))
- return
-
- // Link the two mobs for client transfer
- avatar.vr_holder = src
- src.teleop = avatar
- src.vr_link = avatar // Can't reuse vr_holder so that death can automatically eject users from VR
-
- // Move the mind
- avatar.Sleeping(1)
- src.mind.transfer_to(avatar)
- to_chat(avatar, "You have enterred Virtual Reality!\nAll normal gameplay rules still apply.\nWounds you suffer here won't persist when you leave VR, but some of the pain will.\nYou can leave VR at any time by using the \"Exit Virtual Reality\" verb in the Abilities tab, or by ghosting.\nYou can modify your appearance by using various \"Change \[X\]\" verbs in the Abilities tab.")
- to_chat(avatar, " You black out for a moment, and wake to find yourself in a new body in virtual reality.") // So this is what VR feels like?
-
-// exit_vr is called on the vr mob, and puts the mind back into the original mob
-/mob/living/carbon/human/verb/exit_vr()
- set name = "Exit Virtual Reality"
- set category = "Abilities"
-
- if(!vr_holder)
- return
- if(!mind)
- return
-
- var/total_damage
- // Tally human damage
- if(ishuman(src))
- var/mob/living/carbon/human/H = src
- total_damage = H.getBruteLoss() + H.getFireLoss() + H.getOxyLoss() + H.getToxLoss()
-
- // Move the mind back to the original mob
-// vr_holder.Sleeping(1)
- src.mind.transfer_to(vr_holder)
- to_chat(vr_holder, "You black out for a moment, and wake to find yourself back in your own body.")
- // Two-thirds damage is transferred as agony for /humans
- // Getting hurt in VR doesn't damage the physical body, but you still got hurt.
- if(ishuman(vr_holder) && total_damage)
- var/mob/living/carbon/human/V = vr_holder
- V.stun_effect_act(0, total_damage*2/3, null) // 200 damage leaves the user in paincrit for several seconds, agony reaches 0 after around 2m.
- to_chat(vr_holder, "Pain from your time in VR lingers.") // 250 damage leaves the user unconscious for several seconds in addition to paincrit
-
- // Maintain a link with the mob, but don't use teleop
- vr_holder.vr_link = src
- vr_holder.teleop = null
-
- if(istype(vr_holder.loc, /obj/machinery/vr_sleeper))
- var/obj/machinery/vr_sleeper/V = vr_holder.loc
- V.go_out()
diff --git a/code/modules/mob/living/carbon/human/species/species_shapeshift.dm b/code/modules/mob/living/carbon/human/species/species_shapeshift.dm
index f1f36322a2..3837a3a5e6 100644
--- a/code/modules/mob/living/carbon/human/species/species_shapeshift.dm
+++ b/code/modules/mob/living/carbon/human/species/species_shapeshift.dm
@@ -223,4 +223,67 @@ var/list/wrapped_species_by_ref = list()
/mob/living/carbon/human/proc/shapeshifter_set_facial_color(var/new_fhair)
- change_facial_hair_color(hex2num(copytext(new_fhair, 2, 4)), hex2num(copytext(new_fhair, 4, 6)), hex2num(copytext(new_fhair, 6, 8)))
\ No newline at end of file
+ change_facial_hair_color(hex2num(copytext(new_fhair, 2, 4)), hex2num(copytext(new_fhair, 4, 6)), hex2num(copytext(new_fhair, 6, 8)))
+
+// Replaces limbs and copies wounds
+/mob/living/carbon/human/proc/shapeshifter_change_species(var/new_species)
+ if(!species)
+ return
+
+ dna.species = new_species
+
+ var/list/limb_exists = list(
+ BP_TORSO = 0,
+ BP_GROIN = 0,
+ BP_HEAD = 0,
+ BP_L_ARM = 0,
+ BP_R_ARM = 0,
+ BP_L_LEG = 0,
+ BP_R_LEG = 0,
+ BP_L_HAND = 0,
+ BP_R_HAND = 0,
+ BP_L_FOOT = 0,
+ BP_R_FOOT = 0
+ )
+ var/list/wounds_by_limb = list(
+ BP_TORSO = new/list(),
+ BP_GROIN = new/list(),
+ BP_HEAD = new/list(),
+ BP_L_ARM = new/list(),
+ BP_R_ARM = new/list(),
+ BP_L_LEG = new/list(),
+ BP_R_LEG = new/list(),
+ BP_L_HAND = new/list(),
+ BP_R_HAND = new/list(),
+ BP_L_FOOT = new/list(),
+ BP_R_FOOT = new/list()
+ )
+
+ // Copy damage values
+ for(var/limb in organs_by_name)
+ var/obj/item/organ/external/O = organs_by_name[limb]
+ limb_exists[O.organ_tag] = 1
+ wounds_by_limb[O.organ_tag] = O.wounds
+
+ species = all_species[new_species]
+ species.create_organs(src)
+// species.handle_post_spawn(src)
+
+ for(var/limb in organs_by_name)
+ var/obj/item/organ/external/O = organs_by_name[limb]
+ if(limb_exists[O.organ_tag])
+ O.species = all_species[new_species]
+ O.wounds = wounds_by_limb[O.organ_tag]
+ // sync the organ's damage with its wounds
+ O.update_damages()
+ O.owner.updatehealth() //droplimb will call updatehealth() again if it does end up being called
+ else
+ organs.Remove(O)
+ organs_by_name.Remove(O)
+
+ spawn(0)
+ regenerate_icons()
+
+ if(species && mind)
+ apply_traits()
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm
index 8fbf47022d..43182ac386 100644
--- a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm
+++ b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm
@@ -24,9 +24,89 @@
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch, /datum/unarmed_attack/bite)
has_organ = list(O_BRAIN = /obj/item/organ/internal/brain/slime, O_EYES = /obj/item/organ/internal/eyes) // Slime core.
heal_rate = 0 // Avatars don't naturally heal like prometheans, at least not for now
+ inherent_verbs = list(
+ /mob/living/carbon/human/proc/shapeshifter_select_shape,
+ /mob/living/carbon/human/proc/shapeshifter_select_colour,
+ /mob/living/carbon/human/proc/shapeshifter_select_hair,
+ /mob/living/carbon/human/proc/shapeshifter_select_hair_colors,
+ /mob/living/carbon/human/proc/shapeshifter_select_gender,
+ /mob/living/carbon/human/proc/regenerate,
+ /mob/living/carbon/human/proc/shapeshifter_change_opacity,
+ /mob/living/carbon/human/proc/exit_vr
+ )
+
/datum/species/shapeshifter/promethean/avatar/handle_death(var/mob/living/carbon/human/H)
return
/datum/species/shapeshifter/promethean/avatar/handle_environment_special(var/mob/living/carbon/human/H)
- return
\ No newline at end of file
+ return
+
+/mob/living/carbon/human/proc/shapeshifter_change_opacity()
+
+ set name = "Toggle Opacity"
+ set category = "Abilities"
+
+ if(stat || world.time < last_special)
+ return
+
+ last_special = world.time + 10
+
+ if(src.icon_state == "promethean")
+ icon_state = lowertext(src.species.get_bodytype(src))
+ shapeshifter_change_species("Virtual Reality [src.species.get_bodytype(src)]")
+ else
+ icon_state = "promethean"
+ shapeshifter_change_species("Virtual Reality Avatar")
+
+
+// enter_vr is called on the original mob, and puts the mind into the supplied vr mob
+/mob/living/carbon/human/proc/enter_vr(var/mob/living/carbon/human/avatar) // Avatar is currently a human, because we have preexisting setup code for appearance manipulation, etc.
+ if(!istype(avatar))
+ return
+
+ // Link the two mobs for client transfer
+ avatar.vr_holder = src
+ src.teleop = avatar
+ src.vr_link = avatar // Can't reuse vr_holder so that death can automatically eject users from VR
+
+ // Move the mind
+ avatar.Sleeping(1)
+ src.mind.transfer_to(avatar)
+ to_chat(avatar, "You have enterred Virtual Reality!\nAll normal gameplay rules still apply.\nWounds you suffer here won't persist when you leave VR, but some of the pain will.\nYou can leave VR at any time by using the \"Exit Virtual Reality\" verb in the Abilities tab, or by ghosting.\nYou can modify your appearance by using various \"Change \[X\]\" verbs in the Abilities tab.")
+ to_chat(avatar, " You black out for a moment, and wake to find yourself in a new body in virtual reality.") // So this is what VR feels like?
+
+// exit_vr is called on the vr mob, and puts the mind back into the original mob
+/mob/living/carbon/human/proc/exit_vr()
+ set name = "Exit Virtual Reality"
+ set category = "Abilities"
+
+ if(!vr_holder)
+ return
+ if(!mind)
+ return
+
+ var/total_damage
+ // Tally human damage
+ if(ishuman(src))
+ var/mob/living/carbon/human/H = src
+ total_damage = H.getBruteLoss() + H.getFireLoss() + H.getOxyLoss() + H.getToxLoss()
+
+ // Move the mind back to the original mob
+// vr_holder.Sleeping(1)
+ src.mind.transfer_to(vr_holder)
+ to_chat(vr_holder, "You black out for a moment, and wake to find yourself back in your own body.")
+ // Two-thirds damage is transferred as agony for /humans
+ // Getting hurt in VR doesn't damage the physical body, but you still got hurt.
+ if(ishuman(vr_holder) && total_damage)
+ var/mob/living/carbon/human/V = vr_holder
+ V.stun_effect_act(0, total_damage*2/3, null) // 200 damage leaves the user in paincrit for several seconds, agony reaches 0 after around 2m.
+ to_chat(vr_holder, "Pain from your time in VR lingers.") // 250 damage leaves the user unconscious for several seconds in addition to paincrit
+
+ // Maintain a link with the mob, but don't use teleop
+ vr_holder.vr_link = src
+ vr_holder.teleop = null
+
+ if(istype(vr_holder.loc, /obj/machinery/vr_sleeper))
+ var/obj/machinery/vr_sleeper/V = vr_holder.loc
+ V.go_out()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species/virtual_reality/opaque_form.dm b/code/modules/mob/living/carbon/human/species/virtual_reality/opaque_form.dm
new file mode 100644
index 0000000000..e8ae58f617
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/virtual_reality/opaque_form.dm
@@ -0,0 +1,121 @@
+// Species for the opaque appearance
+// Due to sprite construction, they have to have separate limb lists
+
+/datum/species/shapeshifter/promethean/avatar/human
+ name = "Virtual Reality Human"
+ icobase = 'icons/mob/human_races/r_human.dmi'
+ deform = 'icons/mob/human_races/r_def_human.dmi'
+ appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_TONE | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR
+ has_limbs = list(
+ BP_TORSO = list("path" = /obj/item/organ/external/chest),
+ BP_GROIN = list("path" = /obj/item/organ/external/groin),
+ BP_HEAD = list("path" = /obj/item/organ/external/head),
+ BP_L_ARM = list("path" = /obj/item/organ/external/arm),
+ BP_R_ARM = list("path" = /obj/item/organ/external/arm/right),
+ BP_L_LEG = list("path" = /obj/item/organ/external/leg),
+ BP_R_LEG = list("path" = /obj/item/organ/external/leg/right),
+ BP_L_HAND = list("path" = /obj/item/organ/external/hand),
+ BP_R_HAND = list("path" = /obj/item/organ/external/hand/right),
+ BP_L_FOOT = list("path" = /obj/item/organ/external/foot),
+ BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
+ )
+
+/datum/species/shapeshifter/promethean/avatar/unathi
+ name = "Virtual Reality Unathi"
+ icobase = 'icons/mob/human_races/r_lizard.dmi'
+ deform = 'icons/mob/human_races/r_def_lizard.dmi'
+ tail = "sogtail"
+ tail_animation = 'icons/mob/species/unathi/tail.dmi'
+ appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR
+ has_limbs = list(
+ BP_TORSO = list("path" = /obj/item/organ/external/chest/unathi),
+ BP_GROIN = list("path" = /obj/item/organ/external/groin/unathi),
+ BP_HEAD = list("path" = /obj/item/organ/external/head/unathi),
+ BP_L_ARM = list("path" = /obj/item/organ/external/arm),
+ BP_R_ARM = list("path" = /obj/item/organ/external/arm/right),
+ BP_L_LEG = list("path" = /obj/item/organ/external/leg),
+ BP_R_LEG = list("path" = /obj/item/organ/external/leg/right),
+ BP_L_HAND = list("path" = /obj/item/organ/external/hand),
+ BP_R_HAND = list("path" = /obj/item/organ/external/hand/right),
+ BP_L_FOOT = list("path" = /obj/item/organ/external/foot),
+ BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
+ )
+
+/datum/species/shapeshifter/promethean/avatar/tajaran
+ name = "Virtual Reality Tajara"
+ icobase = 'icons/mob/human_races/r_tajaran.dmi'
+ deform = 'icons/mob/human_races/r_def_tajaran.dmi'
+ tail = "tajtail"
+ tail_animation = 'icons/mob/species/tajaran/tail.dmi'
+ appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR
+ has_limbs = list(
+ BP_TORSO = list("path" = /obj/item/organ/external/chest),
+ BP_GROIN = list("path" = /obj/item/organ/external/groin),
+ BP_HEAD = list("path" = /obj/item/organ/external/head),
+ BP_L_ARM = list("path" = /obj/item/organ/external/arm),
+ BP_R_ARM = list("path" = /obj/item/organ/external/arm/right),
+ BP_L_LEG = list("path" = /obj/item/organ/external/leg),
+ BP_R_LEG = list("path" = /obj/item/organ/external/leg/right),
+ BP_L_HAND = list("path" = /obj/item/organ/external/hand),
+ BP_R_HAND = list("path" = /obj/item/organ/external/hand/right),
+ BP_L_FOOT = list("path" = /obj/item/organ/external/foot),
+ BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
+ )
+
+/datum/species/shapeshifter/promethean/avatar/skrell
+ name = "Virtual Reality Skrell"
+ icobase = 'icons/mob/human_races/r_skrell.dmi'
+ deform = 'icons/mob/human_races/r_def_skrell.dmi'
+ appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR
+ has_limbs = list(
+ BP_TORSO = list("path" = /obj/item/organ/external/chest),
+ BP_GROIN = list("path" = /obj/item/organ/external/groin),
+ BP_HEAD = list("path" = /obj/item/organ/external/head/skrell),
+ BP_L_ARM = list("path" = /obj/item/organ/external/arm),
+ BP_R_ARM = list("path" = /obj/item/organ/external/arm/right),
+ BP_L_LEG = list("path" = /obj/item/organ/external/leg),
+ BP_R_LEG = list("path" = /obj/item/organ/external/leg/right),
+ BP_L_HAND = list("path" = /obj/item/organ/external/hand),
+ BP_R_HAND = list("path" = /obj/item/organ/external/hand/right),
+ BP_L_FOOT = list("path" = /obj/item/organ/external/foot),
+ BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
+ )
+
+/datum/species/shapeshifter/promethean/avatar/teshari
+ name = "Virtual Reality Teshari"
+ icobase = 'icons/mob/human_races/r_seromi.dmi'
+ deform = 'icons/mob/human_races/r_seromi.dmi'
+ appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_EYE_COLOR
+ has_limbs = list(
+ BP_TORSO = list("path" = /obj/item/organ/external/chest),
+ BP_GROIN = list("path" = /obj/item/organ/external/groin),
+ BP_HEAD = list("path" = /obj/item/organ/external/head/seromi),
+ BP_L_ARM = list("path" = /obj/item/organ/external/arm),
+ BP_R_ARM = list("path" = /obj/item/organ/external/arm/right),
+ BP_L_LEG = list("path" = /obj/item/organ/external/leg),
+ BP_R_LEG = list("path" = /obj/item/organ/external/leg/right),
+ BP_L_HAND = list("path" = /obj/item/organ/external/hand/seromi),
+ BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/seromi),
+ BP_L_FOOT = list("path" = /obj/item/organ/external/foot/seromi),
+ BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/seromi)
+ )
+
+/datum/species/shapeshifter/promethean/avatar/diona
+ name = "Virtual Reality Diona"
+ icobase = 'icons/mob/human_races/r_diona.dmi'
+ deform = 'icons/mob/human_races/r_def_plant.dmi'
+ appearance_flags = 0
+ has_limbs = list(
+ BP_TORSO = list("path" = /obj/item/organ/external/diona/chest),
+ BP_GROIN = list("path" = /obj/item/organ/external/diona/groin),
+ BP_HEAD = list("path" = /obj/item/organ/external/head/no_eyes/diona),
+ BP_L_ARM = list("path" = /obj/item/organ/external/diona/arm),
+ BP_R_ARM = list("path" = /obj/item/organ/external/diona/arm/right),
+ BP_L_LEG = list("path" = /obj/item/organ/external/diona/leg),
+ BP_R_LEG = list("path" = /obj/item/organ/external/diona/leg/right),
+ BP_L_HAND = list("path" = /obj/item/organ/external/diona/hand),
+ BP_R_HAND = list("path" = /obj/item/organ/external/diona/hand/right),
+ BP_L_FOOT = list("path" = /obj/item/organ/external/diona/foot),
+ BP_R_FOOT = list("path" = /obj/item/organ/external/diona/foot/right)
+ )
+
diff --git a/html/changelogs/Atermonera - VR-Avatars.yml b/html/changelogs/Atermonera - VR-Avatars.yml
new file mode 100644
index 0000000000..f586902287
--- /dev/null
+++ b/html/changelogs/Atermonera - VR-Avatars.yml
@@ -0,0 +1,5 @@
+author: Atermonera
+
+delete-after: True
+
+ - rscadd: "Mobs in VR can switch between translucent and opaque forms."
diff --git a/polaris.dme b/polaris.dme
index 20c4844f0c..88140df325 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -1756,6 +1756,7 @@
#include "code\modules\mob\living\carbon\human\species\station\seromi.dm"
#include "code\modules\mob\living\carbon\human\species\station\station.dm"
#include "code\modules\mob\living\carbon\human\species\virtual_reality\avatar.dm"
+#include "code\modules\mob\living\carbon\human\species\virtual_reality\opaque_form.dm"
#include "code\modules\mob\living\carbon\human\species\xenomorphs\alien_powers.dm"
#include "code\modules\mob\living\carbon\human\species\xenomorphs\alien_species.dm"
#include "code\modules\mob\living\carbon\human\species\xenomorphs\xenomorphs.dm"