diff --git a/code/_helpers/global_lists_ch.dm b/code/_helpers/global_lists_ch.dm index 5bd21c42dd..89048a1169 100644 --- a/code/_helpers/global_lists_ch.dm +++ b/code/_helpers/global_lists_ch.dm @@ -36,4 +36,49 @@ var/global/list/item_digestion_blacklist = list( /obj/item/device/perfect_tele_beacon, /obj/item/organ/internal/brain/slime, /obj/item/device/mmi/digital/posibrain, - /obj/item/weapon/rig/protean) \ No newline at end of file + /obj/item/weapon/rig/protean) + +// Options for transforming into a different mob in virtual reality. +var/global/list/vr_mob_tf_options = list( + "Borg" = /mob/living/silicon/robot, + "Cortical borer" = /mob/living/simple_mob/animal/borer/non_antag, + "Hyena" = /mob/living/simple_mob/animal/hyena, + "Giant spider" = /mob/living/simple_mob/animal/giant_spider/thermic, + "Armadillo" = /mob/living/simple_mob/animal/passive/armadillo, + "Parrot" = /mob/living/simple_mob/animal/passive/bird/parrot, + "Cat" = /mob/living/simple_mob/animal/passive/cat, + "Corgi" = /mob/living/simple_mob/animal/passive/dog/corgi, + "Fox" = /mob/living/simple_mob/animal/passive/fox, + "Racoon" = /mob/living/simple_mob/animal/passive/raccoon_ch, + "Shantak" = /mob/living/simple_mob/animal/sif/shantak, + "Goose" = /mob/living/simple_mob/animal/space/goose, + "Space shark" = /mob/living/simple_mob/animal/space/shark, + "Synx" = /mob/living/simple_mob/animal/synx, + "Dire wolf" = /mob/living/simple_mob/animal/wolf/direwolf, + "Construct Artificer" = /mob/living/simple_mob/construct/artificer, + "Tech golem" = /mob/living/simple_mob/mechanical/technomancer_golem, + "Metroid" = /mob/living/simple_mob/metroid/juvenile/baby, + "Otie" = /mob/living/simple_mob/otie/cotie/chubby, + "Shadekin" = /mob/living/simple_mob/shadekin, + "Slime" = /mob/living/simple_mob/slime/xenobio/metal, + "Corrupt hound" = /mob/living/simple_mob/vore/aggressive/corrupthound, + "Deathclaw" = /mob/living/simple_mob/vore/aggressive/deathclaw/den, + "Mimic" = /mob/living/simple_mob/vore/aggressive/mimic/floor/plating, + "Giant rat" = /mob/living/simple_mob/vore/aggressive/rat, + "Catslug" = /mob/living/simple_mob/vore/alienanimals/catslug, + "Dust jumper" = /mob/living/simple_mob/vore/alienanimals/dustjumper, + "Space ghost" = /mob/living/simple_mob/vore/alienanimals/spooky_ghost, + "Teppi" = /mob/living/simple_mob/vore/alienanimals/teppi, + "Bee" = /mob/living/simple_mob/vore/bee, + //"Dragon" = /mob/living/simple_mob/vore/bigdragon/friendly, //Currently adds 12 bellies to the user when transformed into. Do not uncomment without fixing this. + "Riftwalker" = /mob/living/simple_mob/vore/demon/wendigo, + "Horse" = /mob/living/simple_mob/vore/horse/big, + "Morph" = /mob/living/simple_mob/vore/hostile/morph, + "Leopardmander" = /mob/living/simple_mob/vore/leopardmander, + "Rabbit" = /mob/living/simple_mob/vore/rabbit, + "Red panda" = /mob/living/simple_mob/vore/redpanda, + "Sect drone" = /mob/living/simple_mob/vore/sect_drone, + "Armalis vox" = /mob/living/simple_mob/vox/armalis, + "Xeno hunter" = /mob/living/simple_mob/xeno_ch/hunter, + "Xeno queen" = /mob/living/simple_mob/xeno_ch/queen/maid, + "Xeno sentinel" = /mob/living/simple_mob/xeno_ch/sentinel) diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index f1a7f22248..d1c17f532f 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -160,7 +160,10 @@ #define ui_genetic_master "EAST-1:16,NORTH-3:16" // Ghost ones -#define ui_ghost_returntomenu "SOUTH:6,CENTER-3:24" +// CHOMPedit +#define ui_ghost_returntomenu "SOUTH:6,CENTER-4:24" +// CHOMPedit +#define ui_ghost_vr "SOUTH: 6,CENTER-3:24" #define ui_ghost_jumptomob "SOUTH:6,CENTER-2:24" #define ui_ghost_orbit "SOUTH:6,CENTER-1:24" #define ui_ghost_reenter_corpse "SOUTH:6,CENTER:24" @@ -195,4 +198,4 @@ #define ui_mech_deco1_f "WEST+2:-7, SOUTH+8" #define ui_mech_deco2_f "WEST+2:-7, SOUTH+9" -#define ui_smallquad "EAST-4:22,SOUTH:5" \ No newline at end of file +#define ui_smallquad "EAST-4:22,SOUTH:5" diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm index 5120348488..399f736fdd 100644 --- a/code/_onclick/hud/ghost.dm +++ b/code/_onclick/hud/ghost.dm @@ -91,12 +91,25 @@ var/mob/observer/dead/G = usr G.zMove(DOWN) +// CHOMPedit start +/obj/screen/ghost/vr + name = "Enter VR" + desc = "Enter virtual reality." + icon = 'modular_chomp/icons/mob/screen_ghost.dmi' + icon_state = "entervr" + +/obj/screen/ghost/vr/Click() + ..() + var/mob/observer/dead/G = usr + G.fake_enter_vr() +// CHOMPedit end + /mob/observer/dead/create_mob_hud(datum/hud/HUD, apply_to_client = TRUE) ..() var/list/adding = list() HUD.adding = adding - + var/obj/screen/using using = new /obj/screen/ghost/returntomenu() using.screen_loc = ui_ghost_returntomenu @@ -138,6 +151,13 @@ using.hud = src adding += using + //CHOMPedit start + using = new /obj/screen/ghost/vr() + using.screen_loc = ui_ghost_vr + using.hud = src + adding += using + //CHOMPedit end + /* using = new /obj/screen/language_menu using.icon = ui_style @@ -173,4 +193,4 @@ if (istype(O) && O.observetarget) return . = ..() -*/ \ No newline at end of file +*/ diff --git a/code/game/machinery/virtual_reality/vr_console.dm b/code/game/machinery/virtual_reality/vr_console.dm index b66bc2dff8..6cf461dd0c 100644 --- a/code/game/machinery/virtual_reality/vr_console.dm +++ b/code/game/machinery/virtual_reality/vr_console.dm @@ -1,3 +1,5 @@ +//CHOMPedit: This file has been disabled and moved to the modular_chomp folder. Check that one if you're bug-fixing! + /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." @@ -262,4 +264,3 @@ else occupant.enter_vr(avatar) - 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 0054bbb623..2326de811b 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 @@ -91,6 +91,11 @@ if(!vr_holder) return + if(tfed_into_mob_check()) //CHOMPedit start: make sure we're not TFed and revert if we are before checking for a mind. + var/mob/living/M = loc + if(istype(M)) // Sanity check, though shouldn't be needed since this is already checked by the proc. + M.revert_mob_tf() // CHOMPedit end + if(!mind) return diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index eb7462967e..86a9afb81e 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -74,6 +74,8 @@ handle_tf_holder() //VOREStation Addition + handle_vr_derez() // CHOMPedit + /mob/living/proc/handle_breathing() return diff --git a/code/modules/mob/living/living_ch.dm b/code/modules/mob/living/living_ch.dm deleted file mode 100644 index 5307dfedd0..0000000000 --- a/code/modules/mob/living/living_ch.dm +++ /dev/null @@ -1,2 +0,0 @@ -/mob/living/proc/handle_vorefootstep(m_intent, turf/T) - return FALSE \ No newline at end of file diff --git a/modular_chomp/code/game/machinery/virtual_reality/vr_console.dm b/modular_chomp/code/game/machinery/virtual_reality/vr_console.dm new file mode 100644 index 0000000000..592903efd7 --- /dev/null +++ b/modular_chomp/code/game/machinery/virtual_reality/vr_console.dm @@ -0,0 +1,328 @@ +/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 = "body_scanner_0" + + var/base_state = "body_scanner_" + + density = TRUE + anchored = TRUE + 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 = USE_POWER_IDLE + idle_power_usage = 15 + active_power_usage = 200 + light_color = "#FF0000" + //var/global/list/vr_mob_tf_options // Global var located in global_list_ch.dm + + +/obj/machinery/vr_sleeper/Initialize() + . = ..() + default_apply_parts() + +/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("\The [src] emits a low droning sound, before the pod door clicks open.") + return + else if(eject_dead && occupant && occupant.stat == DEAD) // If someone dies somehow while inside, spit them out. + visible_message("\The [src] sounds an alarm, swinging its hatch open.") + go_out() + +/obj/machinery/vr_sleeper/update_icon() + icon_state = "[base_state][occupant ? "1" : "0"]" + +// CHOMPedit +/obj/machinery/vr_sleeper/examine(mob/user) + . = ..() + if(occupant) + . += "[occupant] is inside." + +/obj/machinery/vr_sleeper/Topic(href, href_list) + if(..()) + return 1 + + if(usr == occupant) + to_chat(usr, "You can't reach the controls from the inside.") + 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/vr_sleeper/relaymove(var/mob/user) + ..() + if(user.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("\The [src]'s internal lighting flashes rapidly, before the hatch swings open with a cloud of smoke.") + smoke.set_up(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, "\The [src] rejects [M] with a sharp beep.") + if(occupant) + to_chat(user, "\The [src] is already occupied.") + 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, "\The [src] is already occupied.") + return + M.stop_pulling() + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + update_use_power(USE_POWER_ACTIVE) + occupant = M + + update_icon() + + enter_vr() + return + +/obj/machinery/vr_sleeper/proc/go_out(var/forced = TRUE) + if(!occupant) + return + + if(!forced && avatar && tgui_alert(avatar, "Someone wants to remove you from virtual reality. Do you want to leave?", "Leave VR?", list("Yes", "No")) == "No") + return + + if(avatar) + 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(USE_POWER_IDLE) + 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 && tgui_alert(occupant, "You already have a [avatar.stat == DEAD ? "" : "deceased "]Virtual Reality avatar. Would you like to use it?", "New avatar", list("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 = tgui_input_list(occupant, "Please select a location to spawn your avatar at:", "Spawn location", vr_landmarks) + if(!S) + return 0 + + //CHOMPedit: mob TF masquerading as mob spawning because that's somehow less spaghetti + var/tf = null + if(tgui_alert(occupant, "Would you like to play as a different creature?", "Join as a mob?", list("Yes", "No")) == "Yes") + var/k = tgui_input_list(occupant, "Please select a creature:", "Mob list", vr_mob_tf_options) + if(!k) + return 0 + tf = vr_mob_tf_options[k] + + for(var/obj/effect/landmark/virtual_reality/i in landmarks_list) + if(i.name == S) + S = i + break + + avatar = new(S, "Virtual Reality Avatar") + //CHOMPedit start: rewriting this to spawn a copy of the user and allow mob TF. + // I know this is a modular file now but perhaps keeping old comments will help with documentation. + if(mirror_first_occupant && occupant.client && occupant.client.prefs) + occupant.client.prefs.copy_to(avatar) + + avatar.forceMove(get_turf(S)) // Put the mob on the landmark, instead of inside it + occupant.enter_vr(avatar) + avatar.regenerate_icons() + avatar.update_transform() + avatar.species.equip_survival_gear(avatar) + avatar.verbs += /mob/living/carbon/human/proc/exit_vr + avatar.verbs += /mob/living/carbon/human/proc/vr_transform_into_mob + avatar.verbs |= /mob/living/proc/set_size // Introducing NeosVR + avatar.virtual_reality_mob = TRUE + + // Prompt for username after they've enterred the body. + var/newname = sanitize(tgui_input_text(avatar, "You are entering virtual reality. Your username is currently [src.name]. Would you like to change it to something else?", "Name change", null, MAX_NAME_LEN), MAX_NAME_LEN) + if(newname) + avatar.real_name = newname + avatar.name = newname + + if(tf) + var/mob/living/new_form = avatar.transform_into_mob(tf, TRUE) // No need to check prefs when the occupant already chose to transform. + if(isliving(new_form)) // Make sure the mob spawned properly. + new_form.verbs += /mob/living/proc/vr_revert_mob_tf + new_form.virtual_reality_mob = TRUE + + else + // If TFed, revert TF. Easier than coding mind transfer stuff for edge cases. + if(avatar.tfed_into_mob_check()) + var/mob/living/M = loc + if(istype(M)) // Sanity check, though shouldn't be needed since this is already checked by the proc. + M.revert_mob_tf() + occupant.enter_vr(avatar) + +// I am not making a new file just for vr-specific mob procs. +/mob/living/carbon/human/proc/vr_transform_into_mob() + set name = "Transform Into Creature" + set category = "Abilities" + set desc = "Become a different creature" + + var/tf = null + var/k = tgui_input_list(usr, "Please select a creature:", "Mob list", vr_mob_tf_options) + if(!k) + return 0 + tf = vr_mob_tf_options[k] + + var/mob/living/new_form = transform_into_mob(tf, TRUE, TRUE) + if(isliving(new_form)) // Sanity check + new_form.verbs += /mob/living/proc/vr_revert_mob_tf + new_form.virtual_reality_mob = TRUE + +/mob/living/proc/vr_revert_mob_tf() + set name = "Revert Transformation" + set category = "Abilities" + + revert_mob_tf() + +// Exiting VR but for ghosts +/mob/living/carbon/human/proc/fake_exit_vr() + set name = "Log Out Of Virtual Reality" + set category = "Abilities" + + if(tgui_alert(usr, "Would you like to log out of virtual reality?", "Log out?", list("Yes", "No")) == "Yes") + release_vore_contents(TRUE) + for(var/obj/item/I in src) + drop_from_inventory(I) + qdel(src) +//CHOMPedit end diff --git a/modular_chomp/code/modules/mob/dead/observer/observer.dm b/modular_chomp/code/modules/mob/dead/observer/observer.dm index 5c9b519416..57f06022f2 100644 --- a/modular_chomp/code/modules/mob/dead/observer/observer.dm +++ b/modular_chomp/code/modules/mob/dead/observer/observer.dm @@ -6,3 +6,66 @@ if(body_backup) qdel(body_backup) ..() + +// Persistence vars not included as we probably don't want losing limbs in the game mean losing limbs in real life. Definitely can't backfire. +/mob/observer/dead/verb/fake_enter_vr() + set name = "Join virtual reality" + set category = "Ghost" + set desc = "Log into NanoTrasen's local virtual reality server." + + var/time_till_respawn = time_till_respawn() + if(time_till_respawn == -1) // Special case, never allowed to respawn + to_chat(usr, "Respawning is not allowed!") + return + if(time_till_respawn) // Nonzero time to respawn + to_chat(usr, "You can't do that yet! You died too recently. You need to wait another [round(time_till_respawn/10/60, 0.1)] minutes.") + return + + var/datum/data/record/record_found + record_found = find_general_record("name", client.prefs.real_name) + // Found their record, they were spawned previously. Remind them corpses cannot play games. + if(record_found) + var/answer = tgui_alert(src,"You seem to have previously joined this round. If you are currently dead, you should not enter VR as this character. Would you still like to proceed?","Previously spawned",list("Yes","No")) + if(answer != "Yes") + return + + var/S = null + var/list/vr_landmarks = list() + for(var/obj/effect/landmark/virtual_reality/sloc in landmarks_list) + vr_landmarks += sloc.name + + S = tgui_input_list(usr, "Please select a location to spawn your avatar at:", "Spawn location", vr_landmarks) + if(!S) + return 0 + for(var/obj/effect/landmark/virtual_reality/i in landmarks_list) + if(i.name == S) + S = i + break + + var/mob/living/carbon/human/avatar = new(get_turf(S), "Virtual Reality Avatar") + if(!avatar) + to_chat(src, "Something went wrong and spawning failed.") + return + + //Write the appearance and whatnot out to the character + var/client/C = client + C.prefs.copy_to(avatar) // Unfortunately the cascade of procs this calls will add the body to the transcore body DB. Don't see a simple way to prevent that. + avatar.key = key + for(var/lang in C.prefs.alternate_languages) + var/datum/language/chosen_language = GLOB.all_languages[lang] + if(chosen_language) + if(is_lang_whitelisted(usr,chosen_language) || (avatar.species && (chosen_language.name in avatar.species.secondary_langs))) + avatar.add_language(lang) + + avatar.regenerate_icons() + avatar.update_transform() + avatar.species.equip_survival_gear(avatar) + avatar.verbs += /mob/living/carbon/human/proc/fake_exit_vr + avatar.verbs += /mob/living/carbon/human/proc/vr_transform_into_mob + avatar.verbs |= /mob/living/proc/set_size // Introducing NeosVR + avatar.virtual_reality_mob = TRUE + log_and_message_admins("[key_name_admin(avatar)] joined virtual reality from the ghost menu.") + + var/newname = sanitize(tgui_input_text(avatar, "You are entering virtual reality. Your username is currently [src.name]. Would you like to change it to something else?", "Name change", null, MAX_NAME_LEN), MAX_NAME_LEN) + if(newname) + avatar.real_name = newname diff --git a/modular_chomp/code/modules/mob/living/living.dm b/modular_chomp/code/modules/mob/living/living.dm index 3a45d96a4f..76c36f6309 100644 --- a/modular_chomp/code/modules/mob/living/living.dm +++ b/modular_chomp/code/modules/mob/living/living.dm @@ -10,6 +10,7 @@ var/pain_emote_3p = null var/species_sounds = "None" // By default, we have nothing. var/death_sound_override = null + var/virtual_reality_mob = FALSE // gross boolean for keeping VR mobs in VR /* // Not sure if needed, screams aren't a carbon thing rn. var/scream_sound = null var/female_scream_sound = null @@ -44,3 +45,98 @@ Maybe later, gotta figure out a way to click yourself when in a locker etc. ..() verbs |= /mob/living/proc/click_self */ + +/mob/living/proc/handle_vorefootstep(m_intent, turf/T) // Moved from living_ch.dm + return FALSE + +// Gross proc which is called on Life() to check for escaped VR mobs. Tried to do this with Exited() on area/vr but ended up being too heavy. +/mob/living/proc/handle_vr_derez() + if(virtual_reality_mob && !istype(get_area(src), /area/vr)) + log_debug("[src] escaped virtual reality") + visible_message("[src] blinks out of existence.") + for(var/obj/belly/B in vore_organs) // Assume anybody inside an escaped VR mob is also an escaped VR mob. + for(var/mob/living/L in B) + log_debug("[L] was inside an escaped VR mob and has been deleted.") + qdel(L) + qdel(src) // Would like to convert escaped players into AR holograms in the future to encourage exploit finding. + +// TRANSFORMATION PROCS + +// Used to check if THIS MOB has been transformed into a different mob, as only the NEW mob uses tf_mob_holder. +// Necessary in niche cases where a proc interacts with the old body and needs to know it's been transformed (such as transforming into a mob then dying in virtual reality). +// Use this if you cannot use the tf_mob_holder var. Returns TRUE if transformed, FALSE if not. +/mob/living/proc/tfed_into_mob_check() + if(loc && isliving(loc)) + var/mob/living/M = loc + if(istype(M) && M.tf_mob_holder && (M.tf_mob_holder == src)) + return TRUE + else + return FALSE + else + return FALSE + +// For some reason upstream made a general revert proc but not a general transform proc, so here it is. +// Requires a /mob/living type path for transformation. Returns the new mob on success, null in all other cases. +// Just handles mob TF right now, but maybe we'll want to do something similar for items in the future. +/mob/living/proc/transform_into_mob(mob/living/new_form, pref_override = FALSE, revert = FALSE) + if(!src.mind) + return + if(!src.allow_spontaneous_tf && !pref_override) + return + if(src.tf_mob_holder) //If we're already transformed + if(revert) + revert_mob_tf() + return + else + return + else + if(src.stat == DEAD) + return + if(!ispath(new_form, /mob/living)) + return + var/mob/living/new_mob = new new_form(get_turf(src)) + new_mob.faction = src.faction + + if(new_mob && isliving(new_mob)) + for(var/obj/belly/B as anything in new_mob.vore_organs) + new_mob.vore_organs -= B + qdel(B) + new_mob.vore_organs = list() + new_mob.name = src.name + new_mob.real_name = src.real_name + for(var/lang in src.languages) + new_mob.languages |= lang + src.copy_vore_prefs_to_mob(new_mob) + new_mob.vore_selected = src.vore_selected + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(ishuman(new_mob)) + var/mob/living/carbon/human/N = new_mob + N.gender = H.gender + N.identifying_gender = H.identifying_gender + else + new_mob.gender = H.gender + else + new_mob.gender = src.gender + if(ishuman(new_mob)) + var/mob/living/carbon/human/N = new_mob + N.identifying_gender = src.gender + + for(var/obj/belly/B as anything in src.vore_organs) + B.loc = new_mob + B.forceMove(new_mob) + B.owner = new_mob + src.vore_organs -= B + new_mob.vore_organs += B + + new_mob.ckey = src.ckey + if(src.ai_holder && new_mob.ai_holder) + var/datum/ai_holder/old_AI = src.ai_holder + old_AI.set_stance(STANCE_SLEEP) + var/datum/ai_holder/new_AI = new_mob.ai_holder + new_AI.hostile = old_AI.hostile + new_AI.retaliate = old_AI.retaliate + src.loc = new_mob + src.forceMove(new_mob) + new_mob.tf_mob_holder = src + return new_mob diff --git a/modular_chomp/icons/mob/screen_ghost.dmi b/modular_chomp/icons/mob/screen_ghost.dmi new file mode 100644 index 0000000000..31eb23dcde Binary files /dev/null and b/modular_chomp/icons/mob/screen_ghost.dmi differ diff --git a/vorestation.dme b/vorestation.dme index b65fdc5e3f..a9d7ffb688 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1035,7 +1035,6 @@ #include "code\game\machinery\telecomms\telemonitor.dm" #include "code\game\machinery\telecomms\traffic_control.dm" #include "code\game\machinery\virtual_reality\ar_console.dm" -#include "code\game\machinery\virtual_reality\vr_console.dm" #include "code\game\magic\Uristrunes.dm" #include "code\game\mecha\mech_bay.dm" #include "code\game\mecha\mech_fabricator.dm" @@ -2942,7 +2941,6 @@ #include "code\modules\mob\living\inventory.dm" #include "code\modules\mob\living\life.dm" #include "code\modules\mob\living\living.dm" -#include "code\modules\mob\living\living_ch.dm" #include "code\modules\mob\living\living_defense.dm" #include "code\modules\mob\living\living_defines.dm" #include "code\modules\mob\living\living_defines_vr.dm" @@ -4559,6 +4557,7 @@ #include "modular_chomp\code\game\machinery\autolathe_armory.dm" #include "modular_chomp\code\game\machinery\colormate.dm" #include "modular_chomp\code\game\machinery\petrification.dm" +#include "modular_chomp\code\game\machinery\virtual_reality\vr_console.dm" #include "modular_chomp\code\game\objects\items.dm" #include "modular_chomp\code\game\objects\items\petrifier.dm" #include "modular_chomp\code\game\objects\items\clockwork\ratvarian_spear.dm"