Adds Alien Reality pods, aka AR pods, for use in events or PoIs. (#5798)

* Fix some VR issues, add new VR issues I don't forsee.

* Tweak re: Github Comments

* Why

* Mechoid stop being a me.

* Add VR_LINK to all organs list.
This commit is contained in:
Mechoid
2019-01-28 19:24:02 -08:00
committed by Anewbe
parent 158d8d3400
commit 83fc6b51e0
13 changed files with 886 additions and 230 deletions

View File

@@ -0,0 +1,134 @@
/*
* This file contains the alien mind-transfer pod, or 'Alien Reality' pod.
*/
/obj/machinery/vr_sleeper/alien
name = "strange pod"
desc = "A strange machine with what appears to be a comfortable, if quite vertical, bed. Numerous mechanical cylinders dot the ceiling, their purpose uncertain."
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "alienpod_0"
base_state = "alienpod_"
eject_dead = FALSE
var/produce_species = SPECIES_REPLICANT // The default species produced. Will be overridden if randomize_species is true.
var/randomize_species = FALSE
var/list/possible_species // Do we make the newly produced body a random species?
/obj/machinery/vr_sleeper/alien/Initialize()
. = ..()
if(possible_species && possible_species.len)
produce_species = pick(possible_species)
/obj/machinery/vr_sleeper/alien/process()
if(stat & (BROKEN))
if(occupant)
go_out()
visible_message("<span class='notice'>\The [src] emits a low droning sound, before the pod door clicks open.</span>")
return
else if(eject_dead && occupant && occupant.stat == DEAD)
visible_message("<span class='warning'>\The [src] sounds an alarm, swinging its hatch open.</span>")
go_out()
/obj/machinery/vr_sleeper/alien/attackby(var/obj/item/I, var/mob/user)
add_fingerprint(user)
if(occupant && (istype(I, /obj/item/device/healthanalyzer) || istype(I, /obj/item/device/robotanalyzer)))
I.attack(occupant, user)
return
/obj/machinery/vr_sleeper/alien/eject()
set src in view(1)
set category = "Object"
if(usr.incapacitated())
return
var/forced = FALSE
if(stat & (BROKEN) || (eject_dead && occupant && occupant.stat == DEAD))
forced = TRUE
go_out(forced)
add_fingerprint(usr)
/obj/machinery/vr_sleeper/alien/go_out(var/forced = TRUE)
if(!occupant)
return
if(!forced && avatar && avatar.stat != DEAD && alert(avatar, "Someone wants to remove you from virtual reality. Do you want to leave?", "Leave VR?", "Yes", "No") == "No")
return
avatar.exit_vr()
if(occupant && occupant.client)
occupant.client.eye = occupant.client.mob
occupant.client.perspective = MOB_PERSPECTIVE
occupant.loc = src.loc
occupant = null
for(var/atom/movable/A in src) // In case an object was dropped inside or something
if(A == circuit)
continue
if(A in component_parts)
continue
A.loc = src.loc
update_use_power(1)
update_icon()
/obj/machinery/vr_sleeper/alien/enter_vr()
if(!occupant)
return
if(!occupant.mind)
return
if(occupant.stat == DEAD && !occupant.client)
return
if(avatar && !occupant.stat)
to_chat(occupant,"<span class='alien'>\The [src] begins to [pick("whir","hum","pulse")] as a screen appears in front of you.</span>")
if(alert(occupant, "This pod is already linked. Are you certain you wish to engage?", "Commmit?", "Yes", "No") == "No")
visible_message("<span class='alien'>\The [src] pulses!</span>")
to_chat(occupant,"<span class='alien'>Your mind blurs as information bombards you.</span>")
if(!avatar)
var/turf/T = get_turf(src)
avatar = new(src, produce_species)
if(occupant.species.name != "Promethean" && occupant.species.name != "Human" && mirror_first_occupant)
avatar.shapeshifter_change_shape(occupant.species.name)
avatar.Sleeping(6)
occupant.enter_vr(avatar)
var/newname = sanitize(input(avatar, "Your mind feels foggy. You're certain your name is [occupant.real_name], but it could also be [avatar.name]. Would you like to change it to something else?", "Name change") as null|text, MAX_NAME_LEN)
if (newname)
avatar.real_name = newname
avatar.forceMove(T)
visible_message("<span class='alium'>\The [src] [pick("gurgles", "churns", "sloshes")] before spitting out \the [avatar]!</span>")
else
// There's only one body per one of these pods, so let's be kind.
var/newname = sanitize(input(avatar, "Your mind feels foggy. You're certain your name is [occupant.real_name], but it feels like it is [avatar.name]. Would you like to change it to something else?", "Name change") as null|text, MAX_NAME_LEN)
if(newname)
avatar.real_name = newname
occupant.enter_vr(avatar)
/*
* Subtypes
*/
/obj/machinery/vr_sleeper/alien/random_replicant
possible_species = list(SPECIES_REPLICANT, SPECIES_REPLICANT_ALPHA, SPECIES_REPLICANT_BETA)
/obj/machinery/vr_sleeper/alien/alpha_replicant
produce_species = SPECIES_REPLICANT_ALPHA
/obj/machinery/vr_sleeper/alien/beta_replicant
produce_species = SPECIES_REPLICANT_BETA

View File

@@ -1,227 +1,262 @@
/obj/machinery/vr_sleeper
name = "virtual reality sleeper"
desc = "A fancy bed with built-in sensory I/O ports and connectors to interface users' minds with their bodies in virtual reality."
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "syndipod_0"
density = 1
anchored = 1
circuit = /obj/item/weapon/circuitboard/vr_sleeper
var/mob/living/carbon/human/occupant = null
var/mob/living/carbon/human/avatar = null
var/datum/mind/vr_mind = null
use_power = 1
idle_power_usage = 15
active_power_usage = 200
light_color = "#FF0000"
/obj/machinery/vr_sleeper/New()
..()
component_parts = list()
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
component_parts += new /obj/item/stack/material/glass/reinforced(src, 2)
RefreshParts()
/obj/machinery/vr_sleeper/Initialize()
. = ..()
update_icon()
/obj/machinery/vr_sleeper/process()
if(stat & (NOPOWER|BROKEN))
return
/obj/machinery/vr_sleeper/update_icon()
icon_state = "syndipod_[occupant ? "1" : "0"]"
/obj/machinery/vr_sleeper/Topic(href, href_list)
if(..())
return 1
if(usr == occupant)
to_chat(usr, "<span class='warning'>You can't reach the controls from the inside.</span>")
return
add_fingerprint(usr)
if(href_list["eject"])
go_out()
return 1
/obj/machinery/vr_sleeper/attackby(var/obj/item/I, var/mob/user)
add_fingerprint(user)
if(default_deconstruction_screwdriver(user, I))
return
else if(default_deconstruction_crowbar(user, I))
if(occupant && avatar)
avatar.exit_vr()
avatar = null
go_out()
return
/obj/machinery/vr_sleeper/MouseDrop_T(var/mob/target, var/mob/user)
if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user)|| !isliving(target))
return
go_in(target, user)
/obj/machinery/sleeper/relaymove(var/mob/user)
..()
if(usr.incapacitated())
return
go_out()
/obj/machinery/vr_sleeper/emp_act(var/severity)
if(stat & (BROKEN|NOPOWER))
..(severity)
return
if(occupant)
// This will eject the user from VR
// ### Fry the brain?
go_out()
..(severity)
/obj/machinery/vr_sleeper/verb/eject()
set src in oview(1)
set category = "Object"
set name = "Eject VR Capsule"
if(usr.incapacitated())
return
if(usr != occupant && avatar && alert(avatar, "Someone wants to remove you from virtual reality. Do you want to leave?", "Leave VR?", "Yes", "No") == "No")
return
// The player in VR is fine with leaving, kick them out and reset avatar
avatar.exit_vr()
avatar = null
go_out()
add_fingerprint(usr)
/obj/machinery/vr_sleeper/verb/climb_in()
set src in oview(1)
set category = "Object"
set name = "Enter VR Capsule"
if(usr.incapacitated())
return
go_in(usr, usr)
add_fingerprint(usr)
/obj/machinery/vr_sleeper/relaymove(mob/user as mob)
if(user.incapacitated())
return 0 //maybe they should be able to get out with cuffs, but whatever
go_out()
/obj/machinery/vr_sleeper/proc/go_in(var/mob/M, var/mob/user)
if(!M)
return
if(stat & (BROKEN|NOPOWER))
return
if(!ishuman(M))
user << "<span class='warning'>\The [src] rejects [M] with a sharp beep.</span>"
if(occupant)
user << "<span class='warning'>\The [src] is already occupied.</span>"
return
if(M == user)
visible_message("\The [user] starts climbing into \the [src].")
else
visible_message("\The [user] starts putting [M] into \the [src].")
if(do_after(user, 20))
if(occupant)
to_chat(user, "<span class='warning'>\The [src] is already occupied.</span>")
return
M.stop_pulling()
if(M.client)
M.client.perspective = EYE_PERSPECTIVE
M.client.eye = src
M.loc = src
update_use_power(2)
occupant = M
update_icon()
enter_vr()
return
/obj/machinery/vr_sleeper/proc/go_out()
if(!occupant)
return
if(occupant.client)
occupant.client.eye = occupant.client.mob
occupant.client.perspective = MOB_PERSPECTIVE
occupant.loc = src.loc
occupant = null
for(var/atom/movable/A in src) // In case an object was dropped inside or something
if(A == circuit)
continue
if(A in component_parts)
continue
A.loc = src.loc
update_use_power(1)
update_icon()
/obj/machinery/vr_sleeper/proc/enter_vr()
// No mob to transfer a mind from
if(!occupant)
return
// No mind to transfer
if(!occupant.mind)
return
// Mob doesn't have an active consciousness to send/receive from
if(occupant.stat != CONSCIOUS)
return
avatar = occupant.vr_link
// If they've already enterred VR, and are reconnecting, prompt if they want a new body
if(avatar && alert(occupant, "You already have a Virtual Reality avatar. Would you like to use it?", "New avatar", "Yes", "No") == "No")
// Delink the mob
occupant.vr_link = null
avatar = null
if(!avatar)
// Get the desired spawn location to put the body
var/S = null
var/list/vr_landmarks = list()
for(var/obj/effect/landmark/virtual_reality/sloc in landmarks_list)
vr_landmarks += sloc.name
S = input(occupant, "Please select a location to spawn your avatar at:", "Spawn location") as null|anything in vr_landmarks
if(!S)
return 0
for(var/obj/effect/landmark/virtual_reality/i in landmarks_list)
if(i.name == S)
S = i
break
avatar = new(S, "Virtual Reality Avatar")
// If the user has a non-default (Human) bodyshape, make it match theirs.
if(occupant.species.name != "Promethean" && occupant.species.name != "Human")
avatar.shapeshifter_change_shape(occupant.species.name)
avatar.forceMove(get_turf(S)) // Put the mob on the landmark, instead of inside it
avatar.Sleeping(1)
occupant.enter_vr(avatar)
// Prompt for username after they've enterred the body.
var/newname = sanitize(input(avatar, "You are entering virtual reality. Your username is currently [src.name]. Would you like to change it to something else?", "Name change") as null|text, MAX_NAME_LEN)
if (newname)
avatar.real_name = newname
else
occupant.enter_vr(avatar)
/obj/machinery/vr_sleeper
name = "virtual reality sleeper"
desc = "A fancy bed with built-in sensory I/O ports and connectors to interface users' minds with their bodies in virtual reality."
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "syndipod_0"
var/base_state = "syndipod_"
density = 1
anchored = 1
circuit = /obj/item/weapon/circuitboard/vr_sleeper
var/mob/living/carbon/human/occupant = null
var/mob/living/carbon/human/avatar = null
var/datum/mind/vr_mind = null
var/datum/effect/effect/system/smoke_spread/bad/smoke
var/eject_dead = TRUE
var/mirror_first_occupant = TRUE // Do we force the newly produced body to look like the occupant?
use_power = 1
idle_power_usage = 15
active_power_usage = 200
light_color = "#FF0000"
/obj/machinery/vr_sleeper/New()
..()
component_parts = list()
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
component_parts += new /obj/item/stack/material/glass/reinforced(src, 2)
RefreshParts()
/obj/machinery/vr_sleeper/Initialize()
. = ..()
smoke = new
update_icon()
/obj/machinery/vr_sleeper/Destroy()
. = ..()
go_out()
/obj/machinery/vr_sleeper/process()
if(stat & (NOPOWER|BROKEN))
if(occupant)
go_out()
visible_message("<span class='notice'>\The [src] emits a low droning sound, before the pod door clicks open.</span>")
return
else if(eject_dead && occupant && occupant.stat == DEAD) // If someone dies somehow while inside, spit them out.
visible_message("<span class='warning'>\The [src] sounds an alarm, swinging its hatch open.</span>")
go_out()
/obj/machinery/vr_sleeper/update_icon()
icon_state = "[base_state][occupant ? "1" : "0"]"
/obj/machinery/vr_sleeper/Topic(href, href_list)
if(..())
return 1
if(usr == occupant)
to_chat(usr, "<span class='warning'>You can't reach the controls from the inside.</span>")
return
add_fingerprint(usr)
if(href_list["eject"])
go_out()
return 1
/obj/machinery/vr_sleeper/attackby(var/obj/item/I, var/mob/user)
add_fingerprint(user)
if(occupant && (istype(I, /obj/item/device/healthanalyzer) || istype(I, /obj/item/device/robotanalyzer)))
I.attack(occupant, user)
return
if(default_deconstruction_screwdriver(user, I))
return
else if(default_deconstruction_crowbar(user, I))
if(occupant && avatar)
avatar.exit_vr()
avatar = null
go_out()
return
/obj/machinery/vr_sleeper/MouseDrop_T(var/mob/target, var/mob/user)
if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user)|| !isliving(target))
return
go_in(target, user)
/obj/machinery/sleeper/relaymove(var/mob/user)
..()
if(usr.incapacitated())
return
go_out()
/obj/machinery/vr_sleeper/emp_act(var/severity)
if(stat & (BROKEN|NOPOWER))
..(severity)
return
if(occupant)
// This will eject the user from VR
// ### Fry the brain? Yes. Maybe.
if(prob(15 / ( severity / 4 )) && occupant.species.has_organ[O_BRAIN] && occupant.internal_organs_by_name[O_BRAIN])
var/obj/item/organ/O = occupant.internal_organs_by_name[O_BRAIN]
O.take_damage(severity * 2)
visible_message("<span class='danger'>\The [src]'s internal lighting flashes rapidly, before the hatch swings open with a cloud of smoke.</span>")
smoke.set_up(n = severity, 0, src)
smoke.start("#202020")
go_out()
..(severity)
/obj/machinery/vr_sleeper/verb/eject()
set src in view(1)
set category = "Object"
set name = "Eject VR Capsule"
if(usr.incapacitated())
return
var/forced = FALSE
if(stat & (BROKEN|NOPOWER) || occupant && occupant.stat == DEAD)
forced = TRUE
go_out(forced)
add_fingerprint(usr)
/obj/machinery/vr_sleeper/verb/climb_in()
set src in oview(1)
set category = "Object"
set name = "Enter VR Capsule"
if(usr.incapacitated())
return
go_in(usr, usr)
add_fingerprint(usr)
/obj/machinery/vr_sleeper/relaymove(mob/user as mob)
if(user.incapacitated())
return 0 //maybe they should be able to get out with cuffs, but whatever
go_out()
/obj/machinery/vr_sleeper/proc/go_in(var/mob/M, var/mob/user)
if(!M)
return
if(stat & (BROKEN|NOPOWER))
return
if(!ishuman(M))
to_chat(user, "<span class='warning'>\The [src] rejects [M] with a sharp beep.</span>")
if(occupant)
to_chat(user, "<span class='warning'>\The [src] is already occupied.</span>")
return
if(M == user)
visible_message("\The [user] starts climbing into \the [src].")
else
visible_message("\The [user] starts putting [M] into \the [src].")
if(do_after(user, 20))
if(occupant)
to_chat(user, "<span class='warning'>\The [src] is already occupied.</span>")
return
M.stop_pulling()
if(M.client)
M.client.perspective = EYE_PERSPECTIVE
M.client.eye = src
M.loc = src
update_use_power(2)
occupant = M
update_icon()
enter_vr()
return
/obj/machinery/vr_sleeper/proc/go_out(var/forced = TRUE)
if(!occupant)
return
if(!forced && avatar && alert(avatar, "Someone wants to remove you from virtual reality. Do you want to leave?", "Leave VR?", "Yes", "No") == "No")
return
avatar.exit_vr()
avatar = null
if(occupant.client)
occupant.client.eye = occupant.client.mob
occupant.client.perspective = MOB_PERSPECTIVE
occupant.loc = src.loc
occupant = null
for(var/atom/movable/A in src) // In case an object was dropped inside or something
if(A == circuit)
continue
if(A in component_parts)
continue
A.loc = src.loc
update_use_power(1)
update_icon()
/obj/machinery/vr_sleeper/proc/enter_vr()
// No mob to transfer a mind from
if(!occupant)
return
// No mind to transfer
if(!occupant.mind)
return
// Mob doesn't have an active consciousness to send/receive from
if(occupant.stat == DEAD)
return
avatar = occupant.vr_link
// If they've already enterred VR, and are reconnecting, prompt if they want a new body
if(avatar && alert(occupant, "You already have a [avatar.stat == DEAD ? "" : "deceased "]Virtual Reality avatar. Would you like to use it?", "New avatar", "Yes", "No") == "No")
// Delink the mob
occupant.vr_link = null
avatar = null
if(!avatar)
// Get the desired spawn location to put the body
var/S = null
var/list/vr_landmarks = list()
for(var/obj/effect/landmark/virtual_reality/sloc in landmarks_list)
vr_landmarks += sloc.name
S = input(occupant, "Please select a location to spawn your avatar at:", "Spawn location") as null|anything in vr_landmarks
if(!S)
return 0
for(var/obj/effect/landmark/virtual_reality/i in landmarks_list)
if(i.name == S)
S = i
break
avatar = new(S, "Virtual Reality Avatar")
// If the user has a non-default (Human) bodyshape, make it match theirs.
if(occupant.species.name != "Promethean" && occupant.species.name != "Human" && mirror_first_occupant)
avatar.shapeshifter_change_shape(occupant.species.name)
avatar.forceMove(get_turf(S)) // Put the mob on the landmark, instead of inside it
avatar.Sleeping(1)
occupant.enter_vr(avatar)
// Prompt for username after they've enterred the body.
var/newname = sanitize(input(avatar, "You are entering virtual reality. Your username is currently [src.name]. Would you like to change it to something else?", "Name change") as null|text, MAX_NAME_LEN)
if (newname)
avatar.real_name = newname
else
occupant.enter_vr(avatar)