diff --git a/code/__defines/_planes+layers_vr.dm b/code/__defines/_planes+layers_vr.dm
index 30238bc6b0..744f299224 100644
--- a/code/__defines/_planes+layers_vr.dm
+++ b/code/__defines/_planes+layers_vr.dm
@@ -6,4 +6,4 @@
#define PLANE_AUGMENTED 40 //Augmented-reality plane
-#define ABOVE_WINDOW_LAYER 3.25 //Above full tile windows so wall items are clickable
\ No newline at end of file
+#define ABOVE_WINDOW_LAYER 3.25 //Above full tile windows so wall items are clickable
diff --git a/code/__defines/nifsoft.dm b/code/__defines/nifsoft.dm
index 2772aadede..dc03b2b411 100644
--- a/code/__defines/nifsoft.dm
+++ b/code/__defines/nifsoft.dm
@@ -38,9 +38,10 @@
#define NIF_COMPLIANCE 31
#define NIF_SIZECHANGE 32
#define NIF_SOULCATCHER 33
+#define NIF_WORLDBEND 34
// Must be equal to the highest number above
-#define TOTAL_NIF_SOFTWARE 33
+#define TOTAL_NIF_SOFTWARE 34
//////////////////////
// NIF flag list hints
diff --git a/code/modules/clothing/glasses/hud_vr.dm b/code/modules/clothing/glasses/hud_vr.dm
index ec91efe9b4..c2b198bc70 100644
--- a/code/modules/clothing/glasses/hud_vr.dm
+++ b/code/modules/clothing/glasses/hud_vr.dm
@@ -9,7 +9,7 @@
var/datum/nano_module/arscreen
var/arscreen_path
var/flash_prot = 0 //0 for none, 1 for flash weapon protection, 2 for welder protection
- enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR)
+ enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_AUGMENTED)
plane_slots = list(slot_glasses)
/obj/item/clothing/glasses/omnihud/New()
@@ -72,7 +72,7 @@
mode = "med"
action_button_name = "AR Console (Crew Monitor)"
arscreen_path = /datum/nano_module/crew_monitor
- enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_STATUS_R,VIS_CH_BACKUP)
+ enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_STATUS_R,VIS_CH_BACKUP,VIS_AUGMENTED)
ar_interact(var/mob/living/carbon/human/user)
if(arscreen)
@@ -87,7 +87,7 @@
flash_protection = FLASH_PROTECTION_MAJOR
action_button_name = "AR Console (Security Alerts)"
arscreen_path = /datum/nano_module/alarm_monitor/security
- enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_WANTED)
+ enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_WANTED,VIS_AUGMENTED)
ar_interact(var/mob/living/carbon/human/user)
if(arscreen)
diff --git a/code/modules/entopics_vr/alternate_appearance.dm b/code/modules/entopics_vr/alternate_appearance.dm
new file mode 100644
index 0000000000..4fd7d31ed0
--- /dev/null
+++ b/code/modules/entopics_vr/alternate_appearance.dm
@@ -0,0 +1,151 @@
+/*
+ Alternate Appearances! By RemieRichards
+ A framework for replacing an atom (and it's overlays) with an override = 1 image, that's less shit!
+ Example uses:
+ * hallucinating all mobs looking like skeletons
+ * people wearing cardborg suits appearing as Standard Cyborgs to the other Silicons
+ * !!use your imagination!!
+
+*/
+
+//This datum is built on-the-fly by some of the procs below
+//no need to instantiate it
+/datum/alternate_appearance
+ var/key = ""
+ var/image/img
+ var/list/viewers = list()
+ var/atom/owner = null
+
+
+/*
+ Displays the alternate_appearance
+ displayTo - a list of MOBS to show this appearance to
+*/
+/datum/alternate_appearance/proc/display_to(list/displayTo)
+ if(!displayTo || !displayTo.len)
+ return
+ for(var/m in displayTo)
+ var/mob/M = m
+ if(!M.viewing_alternate_appearances)
+ M.viewing_alternate_appearances = list()
+ viewers |= M
+ M.viewing_alternate_appearances |= src
+ if(M.client)
+ M.client.images |= img
+
+/*
+ Hides the alternate_appearance
+ hideFrom - optional list of MOBS to hide it from the list's mobs specifically
+*/
+/datum/alternate_appearance/proc/hide(list/hideFrom)
+ var/list/hiding = viewers
+ if(hideFrom)
+ hiding = hideFrom
+
+ for(var/m in hiding)
+ var/mob/M = m
+ if(M.client)
+ M.client.images -= img
+ if(M.viewing_alternate_appearances && M.viewing_alternate_appearances.len)
+ M.viewing_alternate_appearances -= src
+ viewers -= M
+
+
+/*
+ Removes the alternate_appearance from its owner's alternate_appearances list, hiding it also
+*/
+/datum/alternate_appearance/proc/remove()
+ hide()
+ if(owner && owner.alternate_appearances)
+ owner.alternate_appearances -= key
+
+
+/datum/alternate_appearance/Destroy()
+ remove()
+ return ..()
+
+
+
+/atom
+ var/list/alternate_appearances //the alternate appearances we own
+ var/list/viewing_alternate_appearances //the alternate appearances we're viewing, stored here to reestablish them after Logout()s
+ //these lists are built as necessary, so atoms aren't all lugging around empty lists
+
+/*
+ Builds an alternate_appearance datum for the supplied args, optionally displaying it straight away
+ key - the key to the assoc list of key = /datum/alternate_appearances
+ img - the image file to be the "alternate appearance"
+ WORKS BEST IF:
+ * it has override = 1 set
+ * the image's loc is the atom that will use the appearance (otherwise... it's not exactly an alt appearance of this atom is it?)
+ displayTo - optional list of MOBS to display to immediately
+
+ Example:
+ var/image/I = image(icon = 'disguise.dmi', icon_state = "disguise", loc = src)
+ I.override = 1
+ add_alt_appearance("super_secret_disguise", I, players)
+
+*/
+/atom/proc/add_alt_appearance(key, img, list/displayTo = list())
+ if(!key || !img)
+ return
+ if(!alternate_appearances)
+ alternate_appearances = list()
+
+ var/datum/alternate_appearance/AA = new()
+ AA.img = img
+ AA.key = key
+ AA.owner = src
+
+ if(alternate_appearances[key])
+ qdel(alternate_appearances[key])
+ alternate_appearances[key] = AA
+ if(displayTo && displayTo.len)
+ display_alt_appearance(key, displayTo)
+
+
+//////////////
+// WRAPPERS //
+//////////////
+
+/*
+ Removes an alternate_appearance from src's alternate_appearances list
+ Wrapper for: alternate_appearance/remove()
+ key - the key to the assoc list of key = /datum/alternate_appearance
+*/
+/atom/proc/remove_alt_appearance(key)
+ if(alternate_appearances)
+ if(alternate_appearances[key])
+ qdel(alternate_appearances[key])
+
+
+/*
+ Displays an alternate appearance from src's alternate_appearances list
+ Wrapper for: alternate_appearance/display_to()
+ key - the key to the assoc list of key = /datum/alternate_appearance
+ displayTo - a list of MOBS to show this appearance to
+*/
+/atom/proc/display_alt_appearance(key, list/displayTo)
+ if(!alternate_appearances || !key)
+ return
+ var/datum/alternate_appearance/AA = alternate_appearances[key]
+ if(!AA || !AA.img)
+ return
+ AA.display_to(displayTo)
+
+
+/*
+ Hides an alternate appearance from src's alternate_appearances list
+ Wrapper for: alternate_appearance/hide()
+ key - the key to the assoc list of key = /datum/alternate_appearance
+ hideFrom - optional list of MOBS to hide it from the list's mobs specifically
+*/
+/atom/proc/hide_alt_appearance(key, list/hideFrom)
+ if(!alternate_appearances || !key)
+ return
+ var/datum/alternate_appearance/AA = alternate_appearances[key]
+ if(!AA)
+ return
+ AA.hide(hideFrom)
+
+
diff --git a/code/modules/entopics_vr/entopics.dm b/code/modules/entopics_vr/entopics.dm
index 931728e321..1e146e0c05 100644
--- a/code/modules/entopics_vr/entopics.dm
+++ b/code/modules/entopics_vr/entopics.dm
@@ -1,28 +1,65 @@
//Augmented reality objects and their associated systems for attaching to things
var/global/list/entopic_images = list()
+var/global/list/entopic_users = list()
+
+var/global/list/alt_farmanimals = list()
/datum/entopic
- var/icon = null
- var/icon_state = null
- var/plane = PLANE_AUGMENTED
- var/layer = OBJ_LAYER
+ var/name
+ var/suffix
+ var/icon
+ var/icon_state
+ var/plane
+ var/layer
+ var/holder
+ var/alpha = 200 //Holo-ish
+ var/override = FALSE
var/image/my_image
var/registered = FALSE // Less expensive to make it a finite state than to use |= on entopic_images or anything like that.
-/datum/entopic/New(var/atom/aholder, var/icon/aicon, var/aicon_state, var/aplane, var/alayer)
+/datum/entopic/New(var/atom/aholder, var/icon/aicon, var/aicon_state, var/aalpha, var/aplane, var/alayer, var/aoverride, var/aname, var/asuffix)
ASSERT(aholder && (isicon(aicon) || isicon(icon)))
//Everything we need to set in the initializer
var/image/tempimage = image(icon = aicon || icon, loc = aholder, icon_state = aicon_state || icon_state)
- //And everything we don't
- tempimage.plane = plane = aplane || plane
- tempimage.layer = layer = alayer || layer
+ //And everything we don't (order of prescidence: directly passed, datum-specified, then natural byond)
+ if(aplane)
+ tempimage.plane = plane = aplane
+ else if(plane)
+ tempimage.plane = plane
+ if(alayer)
+ tempimage.layer = layer = alayer
+ else if(layer)
+ tempimage.layer = layer
+
+ if(aalpha)
+ tempimage.alpha = alpha = aalpha
+ else if(alpha)
+ tempimage.alpha = alpha
+
+ if(aoverride)
+ tempimage.override = override = aoverride
+ else if(override)
+ tempimage.override = override
+
+ if(aname)
+ tempimage.name = name = aname
+ else if(name)
+ tempimage.name = name
+
+ if(asuffix)
+ tempimage.suffix = suffix = asuffix
+ else if(suffix)
+ tempimage.suffix = suffix
+
+ //Save these for later
+ holder = aholder
if(aicon)
icon = aicon
- if(aicon_state)
+ if(icon_state)
icon_state = aicon_state
my_image = tempimage
@@ -38,16 +75,23 @@ var/global/list/entopic_images = list()
if(registered || !my_image)
return
- entopic_images += my_image
- world << my_image // *noises of disgust*
registered = TRUE
+ entopic_images += my_image
+ for(var/m in entopic_users)
+ var/mob/M = m
+ if(M.client)
+ M.client.images += my_image
/datum/entopic/proc/unregister_entopic()
if(!registered || !my_image)
return
- entopic_images -= my_image
registered = FALSE
+ entopic_images -= my_image
+ for(var/m in entopic_users)
+ var/mob/M = m
+ if(M.client)
+ M.client.images -= my_image
/datum/entopic/proc/show()
if(!my_image)
@@ -55,6 +99,8 @@ var/global/list/entopic_images = list()
my_image.mouse_opacity = 1
my_image.invisibility = 0
+ my_image.alpha = alpha
+ my_image.override = override
/datum/entopic/proc/hide()
if(!my_image)
@@ -62,3 +108,27 @@ var/global/list/entopic_images = list()
my_image.mouse_opacity = 0
my_image.invisibility = 101
+ my_image.alpha = 0
+ my_image.override = FALSE
+
+//////////////////////////////////////
+// Debug helper stuff
+/obj/item/entopic_debug
+ name = "Entopic Debugger"
+ desc = "You shouldn't see this..."
+ icon = 'icons/obj/machines/ar_elements.dmi'
+ icon_state = "proj0"
+
+ var/datum/entopic/ent_debug
+
+/obj/item/entopic_debug/New()
+ ..()
+ ent_debug = new(aholder = src, aicon = icon, aicon_state = "holo_Jin")
+
+/proc/entopic_icon_helper(var/atom/A,var/holo = TRUE)
+ ASSERT(A)
+
+ var/icon/CI = getCompoundIcon(A)
+ var/icon/HI = getHologramIcon(CI)
+
+ usr << ftp(holo ? HI : CI,"[A.name].dmi")
diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm
index d3d65faa31..121a7643ea 100644
--- a/code/modules/mob/dead/observer/login.dm
+++ b/code/modules/mob/dead/observer/login.dm
@@ -4,4 +4,5 @@
plane_holder.set_vis(VIS_GHOSTS, ghostvision)
plane_holder.set_vis(VIS_FULLBRIGHT, !seedarkness)
plane_holder.set_vis(VIS_AI_EYE, TRUE)
+ plane_holder.set_vis(VIS_AUGMENTED, TRUE) //VOREStation Add - GHOST VISION IS AUGMENTED
plane = PLANE_GHOSTS
diff --git a/code/modules/mob/living/carbon/human/human_vr.dm b/code/modules/mob/living/carbon/human/human_vr.dm
new file mode 100644
index 0000000000..f12836ad3d
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/human_vr.dm
@@ -0,0 +1,13 @@
+//Crazy alternate human stuff
+/mob/living/carbon/human/New()
+ . = ..()
+
+ var/animal = pick("cow","chicken_brown", "chicken_black", "chicken_white", "chick", "mouse_brown", "mouse_gray", "mouse_white", "lizard", "cat2", "goose", "penguin")
+ var/image/img = image('icons/mob/animal.dmi', src, animal)
+ img.override = TRUE
+ add_alt_appearance("animals", img, displayTo = alt_farmanimals)
+
+/mob/living/carbon/human/Destroy()
+ alt_farmanimals -= src
+
+ . = ..()
diff --git a/code/modules/mob/login_vr.dm b/code/modules/mob/login_vr.dm
new file mode 100644
index 0000000000..a9ce4bd51d
--- /dev/null
+++ b/code/modules/mob/login_vr.dm
@@ -0,0 +1,6 @@
+/mob/Login()
+ . = ..()
+
+ if(viewing_alternate_appearances && viewing_alternate_appearances.len)
+ for(var/datum/alternate_appearance/AA in viewing_alternate_appearances)
+ AA.display_to(list(src))
diff --git a/code/modules/mob/mob_planes.dm b/code/modules/mob/mob_planes.dm
index 437d70914b..a9b36bc6d3 100644
--- a/code/modules/mob/mob_planes.dm
+++ b/code/modules/mob/mob_planes.dm
@@ -37,7 +37,7 @@
/datum/plane_holder/Destroy()
my_mob = null
- plane_masters.Cut() //Goodbye my children, be free
+ qdel_null_list(plane_masters) //Goodbye my children, be free //VOREStation Edit - Need to qdel these now
return ..()
/datum/plane_holder/proc/set_vis(var/which = null, var/state = FALSE)
diff --git a/code/modules/mob/mob_planes_vr.dm b/code/modules/mob/mob_planes_vr.dm
index 55dba8e0a4..7883c9ccfb 100644
--- a/code/modules/mob/mob_planes_vr.dm
+++ b/code/modules/mob/mob_planes_vr.dm
@@ -5,4 +5,39 @@
plane_masters[VIS_CH_BACKUP] = new /obj/screen/plane_master{plane = PLANE_CH_BACKUP} //Backup implant status
plane_masters[VIS_CH_VANTAG] = new /obj/screen/plane_master{plane = PLANE_CH_VANTAG} //Vore Antags
- plane_masters[VIS_AUGMENTED] = new /obj/screen/plane_master{plane = PLANE_AUGMENTED} //Augmented reality
\ No newline at end of file
+ plane_masters[VIS_AUGMENTED] = new /obj/screen/plane_master/augmented(my_mob) //Augmented reality
+
+/////////////////
+//AR planemaster does some special image handling
+/obj/screen/plane_master/augmented
+ plane = PLANE_AUGMENTED
+ var/state = FALSE //Saves cost with the lists
+ var/mob/my_mob
+
+/obj/screen/plane_master/augmented/New(var/mob/M)
+ ..()
+ my_mob = M
+ logged_in_event.register(my_mob,src,/obj/screen/plane_master/augmented/proc/apply)
+
+/obj/screen/plane_master/augmented/Destroy()
+ logged_in_event.unregister(my_mob,src)
+ my_mob = null
+ return ..()
+
+/obj/screen/plane_master/augmented/set_visibility(var/want = FALSE)
+ . = ..()
+ state = want
+ apply()
+
+/obj/screen/plane_master/augmented/proc/apply()
+ if(!my_mob.client)
+ return
+
+ if(state)
+ entopic_users |= my_mob
+ if(my_mob.client)
+ my_mob.client.images |= entopic_images
+ else
+ entopic_users -= my_mob
+ if(my_mob.client)
+ my_mob.client.images -= entopic_images
diff --git a/code/modules/nifsoft/nif_softshop.dm b/code/modules/nifsoft/nif_softshop.dm
index e58ab917cf..1ac271036d 100644
--- a/code/modules/nifsoft/nif_softshop.dm
+++ b/code/modules/nifsoft/nif_softshop.dm
@@ -3,15 +3,50 @@
name = "NIFSoft Shop"
desc = "For all your mindware and mindware accessories."
product_ads = "Let us get into your head!;Looking for an upgrade?;Surpass Humanity!;Why be normal when you can be SUPERnormal?;Jack in with NIFSoft!"
- icon_state = "nifsoft"
- icon_vend = "nifsoft-purchase"
- icon_deny = "nifsoft-problem"
+
+ icon = 'icons/obj/machines/ar_elements.dmi'
+ icon_state = "proj"
+ icon_vend = "beacon_yes"
+ icon_deny = "beacon_no"
+
products = list()
contraband = list()
premium = list()
var/global/list/starting_legal_nifsoft
var/global/list/starting_illegal_nifsoft
+ density = 0
+ opacity = 0
+ var/datum/entopic/entopic
+
+/obj/machinery/vending/nifsoft_shop/initialize()
+ . = ..()
+ entopic = new(aholder = src, aicon = icon, aicon_state = "beacon")
+
+/obj/machinery/vending/nifsoft_shop/Destroy()
+ qdel_null(entopic)
+ return ..()
+
+/obj/machinery/vending/nifsoft_shop/power_change()
+ ..()
+ if(stat & BROKEN)
+ icon_state = "[initial(icon_state)]-broken"
+ entopic.hide()
+ else
+ if(!(stat & NOPOWER))
+ icon_state = initial(icon_state)
+ entopic.show()
+ else
+ spawn(rand(0, 15))
+ icon_state = "[initial(icon_state)]-off"
+ entopic.hide()
+
+/obj/machinery/vending/nifsoft_shop/malfunction()
+ stat |= BROKEN
+ icon_state = "[initial(icon_state)]-broken"
+ entopic.hide()
+ return
+
// Special Treatment!
/obj/machinery/vending/nifsoft_shop/build_inventory()
//Firsties
@@ -62,7 +97,7 @@
var/mob/living/carbon/human/H = user
if(!H.nif || !H.nif.stat == NIF_WORKING)
to_chat(H,"[src] seems unable to connect to your NIF...")
- flick(icon_deny,src)
+ flick(icon_deny,entopic.my_image)
return FALSE
return ..()
@@ -90,7 +125,7 @@
if((href_list["vend"]) && (vend_ready) && (!currently_vending))
if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH
usr << "Access denied." //Unless emagged of course
- flick(icon_deny,src)
+ flick(icon_deny,entopic.my_image)
return
var/key = text2num(href_list["vend"])
@@ -107,7 +142,7 @@
var/list/usr_access = usr.GetAccess()
if(!has_access(soft_access, list(), usr_access) && !emagged)
usr << "You aren't authorized to buy [initial(path.name)]."
- flick(icon_deny,src)
+ flick(icon_deny,entopic.my_image)
return
if(R.price <= 0)
@@ -138,7 +173,7 @@
var/mob/living/carbon/human/H = user
if((!allowed(usr)) && !emagged && scan_id && istype(H)) //For SECURE VENDING MACHINES YEAH
usr << "Purchase not allowed." //Unless emagged of course
- flick(icon_deny,src)
+ flick(icon_deny,entopic.my_image)
return
vend_ready = 0 //One thing at a time!!
status_message = "Installing..."
@@ -171,7 +206,7 @@
spawn(vend_delay)
R.amount--
new R.item_path(H.nif)
- flick(icon_vend,src)
+ flick(icon_vend,entopic.my_image)
if(has_logs)
do_logging(R, user, 1)
diff --git a/code/modules/nifsoft/software/01_vision.dm b/code/modules/nifsoft/software/01_vision.dm
index 5368636a7c..2ce33c1c88 100644
--- a/code/modules/nifsoft/software/01_vision.dm
+++ b/code/modules/nifsoft/software/01_vision.dm
@@ -5,8 +5,8 @@
desc = "Provides a general identification and health status overlay on your vision with no frills."
list_pos = NIF_CIVILIAN_AR
cost = 500
- a_drain = 0.05
- planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR)
+ a_drain = 0.01
+ planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_AUGMENTED)
vision_flags = (NIF_V_AR_CIVILIAN)
incompatible_with = list(NIF_MEDICAL_AR,NIF_SECURITY_AR,NIF_ENGINE_AR,NIF_SCIENCE_AR,NIF_OMNI_AR)
@@ -16,8 +16,8 @@
list_pos = NIF_MEDICAL_AR
cost = 750
access = access_medical
- a_drain = 0.05
- planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_STATUS_R,VIS_CH_BACKUP)
+ a_drain = 0.01
+ planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_STATUS_R,VIS_CH_BACKUP,VIS_AUGMENTED)
vision_flags = (NIF_V_AR_MEDICAL)
incompatible_with = list(NIF_CIVILIAN_AR,NIF_SECURITY_AR,NIF_ENGINE_AR,NIF_SCIENCE_AR,NIF_OMNI_AR)
@@ -27,8 +27,8 @@
list_pos = NIF_SECURITY_AR
cost = 750
access = access_security
- a_drain = 0.05
- planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_WANTED)
+ a_drain = 0.01
+ planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_WANTED,VIS_AUGMENTED)
vision_flags = (NIF_V_AR_SECURITY)
incompatible_with = list(NIF_CIVILIAN_AR,NIF_MEDICAL_AR,NIF_ENGINE_AR,NIF_SCIENCE_AR,NIF_OMNI_AR)
@@ -38,8 +38,8 @@
list_pos = NIF_ENGINE_AR
cost = 750
access = access_engine
- a_drain = 0.05
- planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR)
+ a_drain = 0.01
+ planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_AUGMENTED)
vision_flags = (NIF_V_AR_ENGINE)
incompatible_with = list(NIF_CIVILIAN_AR,NIF_MEDICAL_AR,NIF_SECURITY_AR,NIF_SCIENCE_AR,NIF_OMNI_AR)
@@ -49,8 +49,8 @@
list_pos = NIF_SCIENCE_AR
cost = 750
access = access_research
- a_drain = 0.05
- planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR)
+ a_drain = 0.01
+ planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_AUGMENTED)
vision_flags = (NIF_V_AR_SCIENCE)
incompatible_with = list(NIF_CIVILIAN_AR,NIF_MEDICAL_AR,NIF_SECURITY_AR,NIF_ENGINE_AR,NIF_OMNI_AR)
@@ -60,10 +60,11 @@
list_pos = NIF_OMNI_AR
cost = 750
access = access_captain
- a_drain = 0.05
- planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_STATUS_R,VIS_CH_BACKUP,VIS_CH_WANTED)
+ a_drain = 0.01
+ planes_enabled = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_STATUS_R,VIS_CH_BACKUP,VIS_CH_WANTED,VIS_AUGMENTED)
vision_flags = (NIF_V_AR_OMNI)
incompatible_with = list(NIF_CIVILIAN_AR,NIF_MEDICAL_AR,NIF_SECURITY_AR,NIF_ENGINE_AR,NIF_SCIENCE_AR)
+
//////////////
// Misc Vision
/datum/nifsoft/corrective
diff --git a/code/modules/nifsoft/software/13_soulcatcher.dm b/code/modules/nifsoft/software/13_soulcatcher.dm
index 7dbf0f9d5f..e8d14ab902 100644
--- a/code/modules/nifsoft/software/13_soulcatcher.dm
+++ b/code/modules/nifsoft/software/13_soulcatcher.dm
@@ -5,6 +5,7 @@
#define NIF_SC_ALLOW_EARS 0x4
#define NIF_SC_ALLOW_EYES 0x8
#define NIF_SC_BACKUPS 0x10
+#define NIF_SC_PROJECTING 0x20
///////////
// Soulcatcher - Like a posibrain, sorta!
@@ -15,9 +16,8 @@
cost = 100 //If I wanna trap people's minds and lood them, then by god I'll do so.
wear = 1
p_drain = 0.01
- other_flags = (NIF_O_SCOTHERS) // Default on when installed, clear when uninstalled
- var/setting_flags = (NIF_SC_CATCHING_OTHERS|NIF_SC_ALLOW_EARS|NIF_SC_ALLOW_EYES|NIF_SC_BACKUPS)
+ var/setting_flags = (NIF_SC_CATCHING_OTHERS|NIF_SC_ALLOW_EARS|NIF_SC_ALLOW_EYES|NIF_SC_BACKUPS|NIF_SC_PROJECTING)
var/list/brainmobs = list()
var/inside_flavor = "A small completely white room with a couch, and a window to what seems to be the outside world. A small sign in the corner says 'Configure Me'."
@@ -44,6 +44,7 @@
install()
if((. = ..()))
+ nif.set_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) //Required on install, because other_flags aren't sufficient for our complicated settings.
nif.human.verbs |= /mob/living/carbon/human/proc/nsay
nif.human.verbs |= /mob/living/carbon/human/proc/nme
@@ -73,23 +74,36 @@
to_chat(CS,"\[\icon[nif.big_icon]NIF\] Soulcatcher displays, \"[message]\"")
brainmob << sound
- proc/say_into(var/message, var/mob/living/sender)
- var/sender_name = sender.name
+ proc/say_into(var/message, var/mob/living/sender, var/mob/eyeobj)
+ var/sender_name = eyeobj ? eyeobj.name : sender.name
log_nsay("[sender_name]/[sender.key] : [message]",nif.human)
- to_chat(nif.human,"\[\icon[nif.big_icon]NIF\] [sender_name] speaks, \"[message]\"")
- for(var/brainmob in brainmobs)
- var/mob/living/carbon/brain/caught_soul/CS = brainmob
- to_chat(CS,"\[\icon[nif.big_icon]NIF\] [sender_name] speaks, \"[message]\"")
+ //AR Projecting
+ if(eyeobj)
+ sender.eyeobj.visible_message("[sender_name] says, \"[message]\"")
- proc/emote_into(var/message, var/mob/living/sender)
- var/sender_name = sender.name
+ //Not AR Projecting
+ else
+ log_nsay("[sender_name]/[sender.key] : [message]",nif.human)
+ to_chat(nif.human,"\[\icon[nif.big_icon]NIF\] [sender_name] speaks, \"[message]\"")
+ for(var/brainmob in brainmobs)
+ var/mob/living/carbon/brain/caught_soul/CS = brainmob
+ to_chat(CS,"\[\icon[nif.big_icon]NIF\] [sender_name] speaks, \"[message]\"")
+
+ proc/emote_into(var/message, var/mob/living/sender, var/mob/eyeobj)
+ var/sender_name = eyeobj ? eyeobj.name : sender.name
log_nme("[sender_name]/[sender.key] : [message]",nif.human)
- to_chat(nif.human,"\[\icon[nif.big_icon]NIF\] [sender_name] [message]")
- for(var/brainmob in brainmobs)
- var/mob/living/carbon/brain/caught_soul/CS = brainmob
- to_chat(CS,"\[\icon[nif.big_icon]NIF\] [sender_name] [message]")
+ //AR Projecting
+ if(eyeobj)
+ sender.eyeobj.visible_message("[sender_name] [message]")
+
+ //Not AR Projecting
+ else
+ to_chat(nif.human,"\[\icon[nif.big_icon]NIF\] [sender_name] [message]")
+ for(var/brainmob in brainmobs)
+ var/mob/living/carbon/brain/caught_soul/CS = brainmob
+ to_chat(CS,"\[\icon[nif.big_icon]NIF\] [sender_name] [message]")
proc/show_settings(var/mob/living/carbon/human/H)
set waitfor = FALSE
@@ -99,6 +113,7 @@
"Ext. Hearing \[[setting_flags & NIF_SC_ALLOW_EARS ? "Enabled" : "Disabled"]\]" = NIF_SC_ALLOW_EARS,
"Ext. Vision \[[setting_flags & NIF_SC_ALLOW_EYES ? "Enabled" : "Disabled"]\]" = NIF_SC_ALLOW_EYES,
"Mind Backups \[[setting_flags & NIF_SC_BACKUPS ? "Enabled" : "Disabled"]\]" = NIF_SC_BACKUPS,
+ "AR Projecting \[[setting_flags & NIF_SC_PROJECTING ? "Enabled" : "Disabled"]\]" = NIF_SC_PROJECTING,
"Design Inside",
"Erase Contents")
var/choice = input(nif.human,"Select a setting to modify:","Soulcatcher NIFSoft") as null|anything in settings_list
@@ -252,6 +267,10 @@
var/obj/item/device/nif/nif
var/datum/nifsoft/soulcatcher/soulcatcher
+/mob/living/carbon/brain/caught_soul/Login()
+ ..()
+ plane_holder.set_vis(VIS_AUGMENTED, TRUE)
+
/mob/living/carbon/brain/caught_soul/Destroy()
if(soulcatcher)
soulcatcher.notify_into("Mind unloaded: [name]")
@@ -259,6 +278,9 @@
soulcatcher = null
if(nif)
nif = null
+ if(eyeobj)
+ reenter_soulcatcher()
+ qdel_null(eyeobj)
container = null
return ..()
@@ -274,13 +296,15 @@
life_tick++
- if(!client && ++client_missing == 300)
- qdel(src)
+ if(!client)
+ if(++client_missing == 300)
+ qdel(src)
return
else
client_missing = 0
if(parent_mob) return
+
//If they're blinded
if(ext_blind)
eye_blind = 5
@@ -317,10 +341,22 @@
return FALSE
+/mob/living/carbon/brain/caught_soul/face_atom(var/atom/A)
+ if(eyeobj)
+ return eyeobj.face_atom(A)
+ else
+ return ..(A)
+
+/mob/living/carbon/brain/caught_soul/set_dir(var/direction)
+ if(eyeobj)
+ return eyeobj.set_dir(direction)
+ else
+ return ..(direction)
+
/mob/living/carbon/brain/caught_soul/say(var/message)
if(parent_mob) return ..()
if(silent) return FALSE
- soulcatcher.say_into(message,src)
+ soulcatcher.say_into(message,src,eyeobj)
/mob/living/carbon/brain/caught_soul/emote(var/act,var/m_type=1,var/message = null)
if(parent_mob) return ..()
@@ -342,7 +378,7 @@
/mob/living/carbon/brain/caught_soul/custom_emote(var/m_type, var/message)
if(silent) return FALSE
- soulcatcher.emote_into(message,src)
+ soulcatcher.emote_into(message,src,eyeobj)
/mob/living/carbon/brain/caught_soul/resist()
set name = "Resist"
@@ -350,6 +386,69 @@
to_chat(src,"There's no way out! You're stuck in VR.")
+///////////////////
+//A projected AR soul thing
+/mob/observer/eye/ar_soul
+ plane = PLANE_AUGMENTED
+ icon = 'icons/obj/machines/ar_elements.dmi'
+ icon_state = "beacon"
+ var/mob/living/carbon/human/parent_human
+
+/mob/observer/eye/ar_soul/New(var/mob/brainmob, var/human)
+ ASSERT(brainmob && brainmob.client)
+ ..()
+
+ owner = brainmob //Set eyeobj's owner
+ parent_human = human //E-z reference to human
+ sight |= SEE_SELF //Always see yourself
+
+ name = "[brainmob.name] (AR)" //Set the name
+ real_name = brainmob.real_name //And the OTHER name
+
+ forceMove(get_turf(parent_human))
+ moved_event.register(parent_human, src, /mob/observer/eye/ar_soul/proc/human_moved)
+
+ //Time to play dressup
+ if(brainmob.client.prefs)
+ var/mob/living/carbon/human/dummy/dummy = new ()
+ brainmob.client.prefs.dress_preview_mob(dummy)
+ sleep(1 SECOND) //Strange bug in preview code? Without this, certain things won't show up. Yay race conditions?
+ dummy.regenerate_icons()
+
+ var/icon/new_icon = getHologramIcon(getCompoundIcon(dummy))
+ qdel(dummy)
+ icon = new_icon
+
+/mob/observer/eye/ar_soul/Destroy()
+ parent_human = null
+ moved_event.unregister(parent_human, src)
+ return ..()
+
+/mob/observer/eye/ar_soul/EyeMove(n, direct)
+ var/initial = initial(sprint)
+ var/max_sprint = 50
+
+ if(cooldown && cooldown < world.timeofday)
+ sprint = initial
+
+ for(var/i = 0; i < max(sprint, initial); i += 20)
+ var/turf/stepn = get_turf(get_step(src, direct))
+ if(stepn)
+ set_dir(direct)
+ if(can_see(parent_human, stepn))
+ forceMove(stepn)
+
+ cooldown = world.timeofday + 5
+ if(acceleration)
+ sprint = min(sprint + 0.5, max_sprint)
+ else
+ sprint = initial
+ return 1
+
+/mob/observer/eye/ar_soul/proc/human_moved()
+ if(!can_see(parent_human,src))
+ forceMove(get_turf(parent_human))
+
///////////////////
//The catching hook
/hook/death/proc/nif_soulcatcher(var/mob/living/carbon/human/H)
@@ -364,7 +463,6 @@
var/datum/nifsoft/soulcatcher/SC = H.nif.imp_check(NIF_SOULCATCHER)
SC.catch_mob(H)
-
return TRUE
///////////////////
@@ -411,3 +509,70 @@
if(message)
var/sane_message = sanitize(message)
SC.emote_into(sane_message,src)
+
+///////////////////
+//Verbs for soulbrains
+/mob/living/carbon/brain/caught_soul/verb/ar_project()
+ set name = "AR Project"
+ set desc = "Project your form into Augmented Reality for those around your predator with the appearance of your loaded character."
+ set category = "Soulcatcher"
+
+ if(eyeobj)
+ to_chat(src,"You're already projecting in AR!")
+ return
+
+ if(!(soulcatcher.setting_flags & NIF_SC_PROJECTING))
+ to_chat(src,"Projecting from this NIF has been disabled!")
+ return
+
+ if(!client || !client.prefs)
+ return //Um...
+
+ eyeobj = new/mob/observer/eye/ar_soul(src,nif.human)
+ soulcatcher.notify_into("[src] now AR projecting.")
+
+/mob/living/carbon/brain/caught_soul/verb/jump_to_owner()
+ set name = "Jump to Owner"
+ set desc = "Jump your projection back to the owner of the soulcatcher you're inside."
+ set category = "Soulcatcher"
+
+ if(!eyeobj)
+ to_chat(src,"You're not projecting into AR!")
+ return
+
+ eyeobj.forceMove(get_turf(nif))
+
+/mob/living/carbon/brain/caught_soul/verb/reenter_soulcatcher()
+ set name = "Re-enter Soulcatcher"
+ set desc = "Leave AR projection and drop back into the soulcatcher."
+ set category = "Soulcatcher"
+
+ if(!eyeobj)
+ to_chat(src,"You're not projecting into AR!")
+ return
+
+ moved_event.unregister(nif.human, eyeobj)
+ qdel(eyeobj)
+ soulcatcher.notify_into("[src] ended AR projection.")
+
+/mob/living/carbon/brain/caught_soul/verb/nsay(message as text|null)
+ set name = "NSay"
+ set desc = "Speak into the NIF's Soulcatcher (circumventing AR speaking)."
+ set category = "Soulcatcher"
+
+ if(!message)
+ message = input("Type a message to say.","Speak into Soulcatcher") as text|null
+ if(message)
+ var/sane_message = sanitize(message)
+ soulcatcher.say_into(sane_message,src,null)
+
+/mob/living/carbon/brain/caught_soul/verb/nme(message as text|null)
+ set name = "NMe"
+ set desc = "Emote into the NIF's Soulcatcher (circumventing AR speaking)."
+ set category = "Soulcatcher"
+
+ if(!message)
+ message = input("Type an action to perform.","Emote into Soulcatcher") as text|null
+ if(message)
+ var/sane_message = sanitize(message)
+ soulcatcher.emote_into(sane_message,src,null)
diff --git a/code/modules/nifsoft/software/15_misc.dm b/code/modules/nifsoft/software/15_misc.dm
index e62e303235..9c8d6d7f0e 100644
--- a/code/modules/nifsoft/software/15_misc.dm
+++ b/code/modules/nifsoft/software/15_misc.dm
@@ -148,3 +148,30 @@
stat_text()
return "Change Size"
+
+/datum/nifsoft/worldbend
+ name = "World Bender"
+ desc = "Alters your perception of various objects in the world. Only has one setting for now: displaying all your crewmates as farm animals."
+ list_pos = NIF_WORLDBEND
+ cost = 200
+ a_drain = 0.01
+
+ activate()
+ if((. = ..()))
+ var/list/justme = list(nif.human)
+ for(var/human in human_mob_list)
+ if(human == nif.human)
+ continue
+ var/mob/living/carbon/human/H = human
+ H.display_alt_appearance("animals", justme)
+ alt_farmanimals += nif.human
+
+ deactivate()
+ if((. = ..()))
+ var/list/justme = list(nif.human)
+ for(var/human in human_mob_list)
+ if(human == nif.human)
+ continue
+ var/mob/living/carbon/human/H = human
+ H.hide_alt_appearance("animals", justme)
+ alt_farmanimals -= nif.human
diff --git a/icons/obj/machines/ar_elements.dmi b/icons/obj/machines/ar_elements.dmi
index 6259e32c4c..48df856990 100644
Binary files a/icons/obj/machines/ar_elements.dmi and b/icons/obj/machines/ar_elements.dmi differ
diff --git a/vorestation.dme b/vorestation.dme
index 88a0cbf137..d787515f9a 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -1575,6 +1575,7 @@
#include "code\modules\economy\price_list.dm"
#include "code\modules\economy\retail_scanner.dm"
#include "code\modules\economy\TradeDestinations.dm"
+#include "code\modules\entopics_vr\alternate_appearance.dm"
#include "code\modules\entopics_vr\entopics.dm"
#include "code\modules\error_handler\_defines.dm"
#include "code\modules\error_handler\error_handler.dm"
@@ -1800,6 +1801,7 @@
#include "code\modules\mob\holder.dm"
#include "code\modules\mob\inventory.dm"
#include "code\modules\mob\login.dm"
+#include "code\modules\mob\login_vr.dm"
#include "code\modules\mob\logout.dm"
#include "code\modules\mob\mob.dm"
#include "code\modules\mob\mob_defines.dm"
@@ -1927,6 +1929,7 @@
#include "code\modules\mob\living\carbon\human\human_powers.dm"
#include "code\modules\mob\living\carbon\human\human_species.dm"
#include "code\modules\mob\living\carbon\human\human_species_vr.dm"
+#include "code\modules\mob\living\carbon\human\human_vr.dm"
#include "code\modules\mob\living\carbon\human\inventory.dm"
#include "code\modules\mob\living\carbon\human\life.dm"
#include "code\modules\mob\living\carbon\human\life_vr.dm"