Whitespace Standardization [MDB IGNORE] (#15748)

* Update settings

* Whitespace changes

* Comment out merger hooks in gitattributes

Corrupt maps would have to be resolved in repo before hooks could be updated

* Revert "Whitespace changes"

This reverts commit afbdd1d844.

* Whitespace again minus example

* Gitignore example changelog

* Restore changelog merge setting

* Keep older dmi hook attribute until hooks can be updated

* update vscode settings too

* Renormalize remaining

* Revert "Gitignore example changelog"

This reverts commit de22ad375d.

* Attempt to normalize example.yml (and another file I guess)

* Try again
This commit is contained in:
Drathek
2024-02-20 02:28:51 -08:00
committed by GitHub
parent 3b61f677b3
commit 7c8bb85de3
1175 changed files with 818171 additions and 818145 deletions
+11 -11
View File
@@ -1,12 +1,12 @@
//Nobody here anymore.
/mob/observer/dead/Login()
..() //Creates the plane_holder lazily
plane_holder.set_vis(VIS_GHOSTS, ghostvision)
plane_holder.set_vis(VIS_FULLBRIGHT, !seedarkness)
plane_holder.set_vis(VIS_CLOAKED, TRUE)
plane_holder.set_vis(VIS_AI_EYE, TRUE)
plane_holder.set_vis(VIS_AUGMENTED, TRUE) //VOREStation Add - GHOST VISION IS AUGMENTED
plane = PLANE_GHOSTS
if(cleanup_timer)
deltimer(cleanup_timer)
//Nobody here anymore.
/mob/observer/dead/Login()
..() //Creates the plane_holder lazily
plane_holder.set_vis(VIS_GHOSTS, ghostvision)
plane_holder.set_vis(VIS_FULLBRIGHT, !seedarkness)
plane_holder.set_vis(VIS_CLOAKED, TRUE)
plane_holder.set_vis(VIS_AI_EYE, TRUE)
plane_holder.set_vis(VIS_AUGMENTED, TRUE) //VOREStation Add - GHOST VISION IS AUGMENTED
plane = PLANE_GHOSTS
if(cleanup_timer)
deltimer(cleanup_timer)
cleanup_timer = null
+7 -7
View File
@@ -1,7 +1,7 @@
/mob/observer/dead/Logout()
..()
spawn(0)
if(src && !key) //we've transferred to another mob. This ghost should be deleted.
qdel(src)
else
cleanup_timer = QDEL_IN(src, 10 MINUTES)
/mob/observer/dead/Logout()
..()
spawn(0)
if(src && !key) //we've transferred to another mob. This ghost should be deleted.
qdel(src)
else
cleanup_timer = QDEL_IN(src, 10 MINUTES)
+42 -42
View File
@@ -1,42 +1,42 @@
/mob/observer/dead/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
message = sanitize(message)
if(!message)
return
log_ghostsay(message, src)
if (client)
if(message)
client.handle_spam_prevention(MUTE_DEADCHAT)
if(client.prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<span class='filter_notice'>[span_red("You cannot talk in deadchat (muted).")]</span>")
return
. = say_dead(message)
/mob/observer/dead/me_verb(message as text)
if(!message)
return
log_ghostemote(message, src)
if(client)
if(message)
client.handle_spam_prevention(MUTE_DEADCHAT)
if(client.prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<span class='filter_notice'>[span_red("You cannot emote in deadchat (muted).")]</span>")
return
. = emote_dead(message)
/mob/observer/dead/handle_track(message, verb = "says", mob/speaker = null, speaker_name, hard_to_hear)
return "[speaker_name] ([ghost_follow_link(speaker, src)])"
/mob/observer/dead/handle_speaker_name(mob/speaker = null, vname, hard_to_hear)
var/speaker_name = ..()
//Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs.
if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker))
speaker_name = "[speaker.real_name] ([speaker_name])"
return speaker_name
/mob/observer/dead/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
message = sanitize(message)
if(!message)
return
log_ghostsay(message, src)
if (client)
if(message)
client.handle_spam_prevention(MUTE_DEADCHAT)
if(client.prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<span class='filter_notice'>[span_red("You cannot talk in deadchat (muted).")]</span>")
return
. = say_dead(message)
/mob/observer/dead/me_verb(message as text)
if(!message)
return
log_ghostemote(message, src)
if(client)
if(message)
client.handle_spam_prevention(MUTE_DEADCHAT)
if(client.prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<span class='filter_notice'>[span_red("You cannot emote in deadchat (muted).")]</span>")
return
. = emote_dead(message)
/mob/observer/dead/handle_track(message, verb = "says", mob/speaker = null, speaker_name, hard_to_hear)
return "[speaker_name] ([ghost_follow_link(speaker, src)])"
/mob/observer/dead/handle_speaker_name(mob/speaker = null, vname, hard_to_hear)
var/speaker_name = ..()
//Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs.
if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker))
speaker_name = "[speaker.real_name] ([speaker_name])"
return speaker_name
+37 -37
View File
@@ -1,37 +1,37 @@
// Shortcuts for above proc
/mob/proc/visible_emote(var/act_desc)
custom_emote(VISIBLE_MESSAGE, act_desc)
/mob/proc/audible_emote(var/act_desc)
custom_emote(AUDIBLE_MESSAGE, act_desc)
/mob/proc/emote_dead(var/message)
if(client.prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<span class='danger'>You cannot send deadchat emotes (muted).</span>")
return
if(!is_preference_enabled(/datum/client_preference/show_dsay))
to_chat(src, "<span class='danger'>You have deadchat muted.</span>")
return
if(!src.client.holder)
if(!config.dsay_allowed)
to_chat(src, "<span class='danger'>Deadchat is globally muted.</span>")
return
var/input
if(!message)
input = sanitize_or_reflect(tgui_input_text(src, "Choose an emote to display."), src) //VOREStation Edit - Reflect too long messages, within reason
else
input = message
input = encode_html_emphasis(input)
if(input)
log_ghostemote(input, src)
if(!invisibility) //If the ghost is made visible by admins or cult. And to see if the ghost has toggled its own visibility, as well. -Mech
visible_message("<span class='deadsay'><B>[src]</B> [input]</span>")
else
say_dead_direct(input, src)
// Shortcuts for above proc
/mob/proc/visible_emote(var/act_desc)
custom_emote(VISIBLE_MESSAGE, act_desc)
/mob/proc/audible_emote(var/act_desc)
custom_emote(AUDIBLE_MESSAGE, act_desc)
/mob/proc/emote_dead(var/message)
if(client.prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<span class='danger'>You cannot send deadchat emotes (muted).</span>")
return
if(!is_preference_enabled(/datum/client_preference/show_dsay))
to_chat(src, "<span class='danger'>You have deadchat muted.</span>")
return
if(!src.client.holder)
if(!config.dsay_allowed)
to_chat(src, "<span class='danger'>Deadchat is globally muted.</span>")
return
var/input
if(!message)
input = sanitize_or_reflect(tgui_input_text(src, "Choose an emote to display."), src) //VOREStation Edit - Reflect too long messages, within reason
else
input = message
input = encode_html_emphasis(input)
if(input)
log_ghostemote(input, src)
if(!invisibility) //If the ghost is made visible by admins or cult. And to see if the ghost has toggled its own visibility, as well. -Mech
visible_message("<span class='deadsay'><B>[src]</B> [input]</span>")
else
say_dead_direct(input, src)
+44 -44
View File
@@ -1,44 +1,44 @@
// CAMERA NET
//
// The datum containing all the chunks.
/datum/visualnet/camera
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Destroy().
var/list/cameras = list()
var/cameras_unsorted = 1
chunk_type = /datum/chunk/camera
/datum/visualnet/camera/proc/process_sort()
if(cameras_unsorted)
cameras = dd_sortedObjectList(cameras)
cameras_unsorted = 0
// Removes a camera from a chunk.
/datum/visualnet/camera/proc/removeCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 0)
// Add a camera to a chunk.
/datum/visualnet/camera/proc/addCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
// Used for Cyborg cameras. Since portable cameras can be in ANY chunk.
/datum/visualnet/camera/proc/updatePortableCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
//else
// majorChunkChange(c, 0)
/datum/visualnet/camera/onMajorChunkChange(atom/c, var/choice, var/datum/chunk/camera/chunk)
// Only add actual cameras to the list of cameras
if(istype(c, /obj/machinery/camera))
if(choice == 0)
// Remove the camera.
chunk.cameras -= c
else if(choice == 1)
// You can't have the same camera in the list twice.
chunk.cameras |= c
// CAMERA NET
//
// The datum containing all the chunks.
/datum/visualnet/camera
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Destroy().
var/list/cameras = list()
var/cameras_unsorted = 1
chunk_type = /datum/chunk/camera
/datum/visualnet/camera/proc/process_sort()
if(cameras_unsorted)
cameras = dd_sortedObjectList(cameras)
cameras_unsorted = 0
// Removes a camera from a chunk.
/datum/visualnet/camera/proc/removeCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 0)
// Add a camera to a chunk.
/datum/visualnet/camera/proc/addCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
// Used for Cyborg cameras. Since portable cameras can be in ANY chunk.
/datum/visualnet/camera/proc/updatePortableCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
//else
// majorChunkChange(c, 0)
/datum/visualnet/camera/onMajorChunkChange(atom/c, var/choice, var/datum/chunk/camera/chunk)
// Only add actual cameras to the list of cameras
if(istype(c, /obj/machinery/camera))
if(choice == 0)
// Remove the camera.
chunk.cameras -= c
else if(choice == 1)
// You can't have the same camera in the list twice.
chunk.cameras |= c
+48 -48
View File
@@ -1,48 +1,48 @@
// CAMERA CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the Eye to stream these chunks and know what it can and cannot see.
/datum/chunk/camera
var/list/cameras = list()
/datum/chunk/camera/acquireVisibleTurfs(var/list/visible)
for(var/obj/machinery/camera/c as anything in cameras)
if(!istype(c))
cameras -= c
continue
if(!c.can_use())
continue
var/turf/point = locate(src.x + 8, src.y + 8, src.z)
if(get_dist(point, c) > 24)
cameras -= c
for(var/turf/t in c.can_see())
visible[t] = t
for(var/mob/living/silicon/ai/AI in living_mob_list)
for(var/turf/t in AI.seen_camera_turfs())
visible[t] = t
// Create a new camera chunk, since the chunks are made as they are needed.
/datum/chunk/camera/New(loc, x, y, z)
for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
if(c.can_use())
cameras += c
..()
/mob/living/silicon/proc/provides_camera_vision()
return 0
/mob/living/silicon/ai/provides_camera_vision()
return stat != DEAD
/mob/living/silicon/robot/provides_camera_vision()
return src.camera && src.camera.network.len && (z in using_map.contact_levels) //VOREStation Edit
/mob/living/silicon/ai/proc/seen_camera_turfs()
return seen_turfs_in_range(src, world.view)
// CAMERA CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the Eye to stream these chunks and know what it can and cannot see.
/datum/chunk/camera
var/list/cameras = list()
/datum/chunk/camera/acquireVisibleTurfs(var/list/visible)
for(var/obj/machinery/camera/c as anything in cameras)
if(!istype(c))
cameras -= c
continue
if(!c.can_use())
continue
var/turf/point = locate(src.x + 8, src.y + 8, src.z)
if(get_dist(point, c) > 24)
cameras -= c
for(var/turf/t in c.can_see())
visible[t] = t
for(var/mob/living/silicon/ai/AI in living_mob_list)
for(var/turf/t in AI.seen_camera_turfs())
visible[t] = t
// Create a new camera chunk, since the chunks are made as they are needed.
/datum/chunk/camera/New(loc, x, y, z)
for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
if(c.can_use())
cameras += c
..()
/mob/living/silicon/proc/provides_camera_vision()
return 0
/mob/living/silicon/ai/provides_camera_vision()
return stat != DEAD
/mob/living/silicon/robot/provides_camera_vision()
return src.camera && src.camera.network.len && (z in using_map.contact_levels) //VOREStation Edit
/mob/living/silicon/ai/proc/seen_camera_turfs()
return seen_turfs_in_range(src, world.view)
+115 -115
View File
@@ -1,115 +1,115 @@
// AI EYE
//
// A mob that the AI controls to look around the station with.
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
/mob/observer/eye/aiEye
name = "Inactive AI Eye"
icon_state = "AI-eye"
/mob/observer/eye/aiEye/New()
..()
visualnet = cameranet
/mob/observer/eye/aiEye/Destroy()
if(owner)
var/mob/living/silicon/ai/ai = owner
ai.all_eyes -= src
owner = null
. = ..()
/mob/observer/eye/aiEye/setLoc(var/T, var/cancel_tracking = 1)
if(owner)
T = get_turf(T)
loc = T
var/mob/living/silicon/ai/ai = owner
if(cancel_tracking)
ai.ai_cancel_tracking()
if(use_static)
ai.camera_visibility(src)
if(ai.client && !ai.multicam_on)
ai.client.eye = src
if(ai.master_multicam)
ai.master_multicam.refresh_view()
if(ai.holo)
if(ai.hologram_follow)
ai.holo.move_hologram(ai)
return 1
// AI MOVEMENT
// The AI's "eye". Described on the top of the page.
/mob/living/silicon/ai
var/obj/machinery/hologram/holopad/holo = null
/mob/living/silicon/ai/proc/destroy_eyeobj(var/atom/new_eye)
if(!eyeobj) return
if(!new_eye)
new_eye = src
eyeobj.owner = null
qdel(eyeobj) // No AI, no Eye
eyeobj = null
if(client)
client.eye = new_eye
/mob/living/silicon/ai/proc/create_eyeobj(var/newloc)
if(eyeobj)
destroy_eyeobj()
if(!newloc)
newloc = src.loc
eyeobj = new /mob/observer/eye/aiEye(newloc)
all_eyes += eyeobj
eyeobj.owner = src
eyeobj.name = "[src.name] (AI Eye)" // Give it a name
if(client)
client.eye = eyeobj
SetName(src.name)
// Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us.
/mob/living/silicon/ai/Initialize()
. = ..()
create_eyeobj()
if(eyeobj)
eyeobj.loc = src.loc
/mob/living/silicon/ai/Destroy()
destroy_eyeobj()
return ..()
/atom/proc/move_camera_by_click()
if(istype(usr, /mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = usr
if(AI.eyeobj && (AI.multicam_on || (AI.client.eye == AI.eyeobj)))
var/turf/T = get_turf(src)
if(T)
AI.eyeobj.setLoc(T)
/mob/living/silicon/ai/proc/view_core()
camera = null
unset_machine()
if(!src.eyeobj)
return
if(client && client.eye)
client.eye = src
for(var/datum/chunk/c in eyeobj.visibleChunks)
c.remove(eyeobj)
src.eyeobj.setLoc(src)
/mob/living/silicon/ai/proc/toggle_acceleration()
set category = "AI Settings"
set name = "Toggle Camera Acceleration"
if(!eyeobj)
return
eyeobj.acceleration = !eyeobj.acceleration
to_chat(usr, "Camera acceleration has been toggled [eyeobj.acceleration ? "on" : "off"].")
// AI EYE
//
// A mob that the AI controls to look around the station with.
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
/mob/observer/eye/aiEye
name = "Inactive AI Eye"
icon_state = "AI-eye"
/mob/observer/eye/aiEye/New()
..()
visualnet = cameranet
/mob/observer/eye/aiEye/Destroy()
if(owner)
var/mob/living/silicon/ai/ai = owner
ai.all_eyes -= src
owner = null
. = ..()
/mob/observer/eye/aiEye/setLoc(var/T, var/cancel_tracking = 1)
if(owner)
T = get_turf(T)
loc = T
var/mob/living/silicon/ai/ai = owner
if(cancel_tracking)
ai.ai_cancel_tracking()
if(use_static)
ai.camera_visibility(src)
if(ai.client && !ai.multicam_on)
ai.client.eye = src
if(ai.master_multicam)
ai.master_multicam.refresh_view()
if(ai.holo)
if(ai.hologram_follow)
ai.holo.move_hologram(ai)
return 1
// AI MOVEMENT
// The AI's "eye". Described on the top of the page.
/mob/living/silicon/ai
var/obj/machinery/hologram/holopad/holo = null
/mob/living/silicon/ai/proc/destroy_eyeobj(var/atom/new_eye)
if(!eyeobj) return
if(!new_eye)
new_eye = src
eyeobj.owner = null
qdel(eyeobj) // No AI, no Eye
eyeobj = null
if(client)
client.eye = new_eye
/mob/living/silicon/ai/proc/create_eyeobj(var/newloc)
if(eyeobj)
destroy_eyeobj()
if(!newloc)
newloc = src.loc
eyeobj = new /mob/observer/eye/aiEye(newloc)
all_eyes += eyeobj
eyeobj.owner = src
eyeobj.name = "[src.name] (AI Eye)" // Give it a name
if(client)
client.eye = eyeobj
SetName(src.name)
// Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us.
/mob/living/silicon/ai/Initialize()
. = ..()
create_eyeobj()
if(eyeobj)
eyeobj.loc = src.loc
/mob/living/silicon/ai/Destroy()
destroy_eyeobj()
return ..()
/atom/proc/move_camera_by_click()
if(istype(usr, /mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = usr
if(AI.eyeobj && (AI.multicam_on || (AI.client.eye == AI.eyeobj)))
var/turf/T = get_turf(src)
if(T)
AI.eyeobj.setLoc(T)
/mob/living/silicon/ai/proc/view_core()
camera = null
unset_machine()
if(!src.eyeobj)
return
if(client && client.eye)
client.eye = src
for(var/datum/chunk/c in eyeobj.visibleChunks)
c.remove(eyeobj)
src.eyeobj.setLoc(src)
/mob/living/silicon/ai/proc/toggle_acceleration()
set category = "AI Settings"
set name = "Toggle Camera Acceleration"
if(!eyeobj)
return
eyeobj.acceleration = !eyeobj.acceleration
to_chat(usr, "Camera acceleration has been toggled [eyeobj.acceleration ? "on" : "off"].")
+72 -72
View File
@@ -1,72 +1,72 @@
#define BORG_CAMERA_BUFFER 30
// ROBOT MOVEMENT
// Update the portable camera everytime the Robot moves.
// This might be laggy, comment it out if there are problems.
/mob/living/silicon/var/updating = 0
/mob/living/silicon/robot/Moved(atom/old_loc, direction, forced = FALSE)
. = ..()
if(!provides_camera_vision())
return
if(!updating)
updating = 1
spawn(BORG_CAMERA_BUFFER)
if(old_loc != src.loc)
cameranet.updatePortableCamera(src.camera)
updating = 0
/mob/living/silicon/ai/Moved(atom/old_loc, direction, forced = FALSE)
. = ..()
if(!provides_camera_vision())
return
if(!updating)
updating = 1
spawn(BORG_CAMERA_BUFFER)
if(old_loc != src.loc)
cameranet.updateVisibility(old_loc, 0)
cameranet.updateVisibility(loc, 0)
updating = 0
#undef BORG_CAMERA_BUFFER
// CAMERA
// An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not.
/obj/machinery/camera/deactivate(user as mob, var/choice = 1)
..(user, choice)
if(src.can_use())
cameranet.addCamera(src)
else
src.set_light(0)
cameranet.removeCamera(src)
/obj/machinery/camera/New()
..()
//Camera must be added to global list of all cameras no matter what...
if(cameranet.cameras_unsorted || !ticker)
cameranet.cameras += src
cameranet.cameras_unsorted = 1
else
dd_insertObjectList(cameranet.cameras, src)
update_coverage(1)
/obj/machinery/camera/Destroy()
clear_all_networks()
cameranet.cameras -= src
return ..()
// Mobs
/mob/living/silicon/ai/rejuvenate()
var/was_dead = stat == DEAD
..()
if(was_dead && stat != DEAD)
// Arise!
cameranet.updateVisibility(src, 0)
/mob/living/silicon/ai/death(gibbed)
if(..())
// If true, the mob went from living to dead (assuming everyone has been overriding as they should...)
cameranet.updateVisibility(src, 0)
#define BORG_CAMERA_BUFFER 30
// ROBOT MOVEMENT
// Update the portable camera everytime the Robot moves.
// This might be laggy, comment it out if there are problems.
/mob/living/silicon/var/updating = 0
/mob/living/silicon/robot/Moved(atom/old_loc, direction, forced = FALSE)
. = ..()
if(!provides_camera_vision())
return
if(!updating)
updating = 1
spawn(BORG_CAMERA_BUFFER)
if(old_loc != src.loc)
cameranet.updatePortableCamera(src.camera)
updating = 0
/mob/living/silicon/ai/Moved(atom/old_loc, direction, forced = FALSE)
. = ..()
if(!provides_camera_vision())
return
if(!updating)
updating = 1
spawn(BORG_CAMERA_BUFFER)
if(old_loc != src.loc)
cameranet.updateVisibility(old_loc, 0)
cameranet.updateVisibility(loc, 0)
updating = 0
#undef BORG_CAMERA_BUFFER
// CAMERA
// An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not.
/obj/machinery/camera/deactivate(user as mob, var/choice = 1)
..(user, choice)
if(src.can_use())
cameranet.addCamera(src)
else
src.set_light(0)
cameranet.removeCamera(src)
/obj/machinery/camera/New()
..()
//Camera must be added to global list of all cameras no matter what...
if(cameranet.cameras_unsorted || !ticker)
cameranet.cameras += src
cameranet.cameras_unsorted = 1
else
dd_insertObjectList(cameranet.cameras, src)
update_coverage(1)
/obj/machinery/camera/Destroy()
clear_all_networks()
cameranet.cameras -= src
return ..()
// Mobs
/mob/living/silicon/ai/rejuvenate()
var/was_dead = stat == DEAD
..()
if(was_dead && stat != DEAD)
// Arise!
cameranet.updateVisibility(src, 0)
/mob/living/silicon/ai/death(gibbed)
if(..())
// If true, the mob went from living to dead (assuming everyone has been overriding as they should...)
cameranet.updateVisibility(src, 0)
+149 -149
View File
@@ -1,149 +1,149 @@
#define UPDATE_BUFFER 25 // 2.5 seconds
// CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the Eye to stream these chunks and know what it can and cannot see.
/datum/obfuscation
var/icon = 'icons/effects/cameravis.dmi'
var/icon_state = "black"
/datum/chunk
var/list/obscuredTurfs = list()
var/list/visibleTurfs = list()
var/list/obscured = list()
var/list/turfs = list()
var/list/seenby = list()
var/visible = 0
var/changed = 0
var/updating = 0
var/x = 0
var/y = 0
var/z = 0
var/datum/obfuscation/obfuscation = new()
// Add an eye to the chunk, then update if changed.
/datum/chunk/proc/add(mob/observer/eye/eye, add_images = TRUE)
if(add_images)
var/client/client = eye.GetViewerClient()
if(client)
client.images += obscured
eye.visibleChunks += src
visible++
seenby += eye
if(changed && !updating)
update()
// Remove an eye from the chunk, then update if changed.
/datum/chunk/proc/remove(mob/observer/eye/eye, remove_images = TRUE)
if(remove_images)
var/client/client = eye.GetViewerClient()
if(client)
client.images -= obscured
eye.visibleChunks -= src
seenby -= eye
if(visible > 0)
visible--
// Called when a chunk has changed. I.E: A wall was deleted.
/datum/chunk/proc/visibilityChanged(turf/loc)
if(!visibleTurfs[loc])
return
hasChanged()
// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
// instead be flagged to update the next time an AI Eye moves near it.
/datum/chunk/proc/hasChanged(var/update_now = 0)
if(visible || update_now)
if(!updating)
updating = 1
spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
update()
updating = 0
else
changed = 1
// The actual updating.
/datum/chunk/proc/update()
set background = 1
var/list/newVisibleTurfs = new()
acquireVisibleTurfs(newVisibleTurfs)
// Removes turf that isn't in turfs.
newVisibleTurfs &= turfs
var/list/visAdded = newVisibleTurfs - visibleTurfs
var/list/visRemoved = visibleTurfs - newVisibleTurfs
visibleTurfs = newVisibleTurfs
obscuredTurfs = turfs - newVisibleTurfs
for(var/turf/t as anything in visAdded)
if(LAZYLEN(t.obfuscations) && t.obfuscations[obfuscation.type])
obscured -= t.obfuscations[obfuscation.type]
for(var/mob/observer/eye/m as anything in seenby)
if(!m)
continue
var/client/client = m.GetViewerClient()
if(client)
client.images -= t.obfuscations[obfuscation.type]
for(var/turf/t as anything in visRemoved)
if(obscuredTurfs[t])
LAZYINITLIST(t.obfuscations)
if(!t.obfuscations[obfuscation.type])
var/image/ob_image = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER)
ob_image.plane = PLANE_FULLSCREEN
t.obfuscations[obfuscation.type] = ob_image
obscured += t.obfuscations[obfuscation.type]
for(var/mob/observer/eye/m as anything in seenby)
if(!m)
seenby -= m
continue
var/client/client = m.GetViewerClient()
if(client)
client.images += t.obfuscations[obfuscation.type]
/datum/chunk/proc/acquireVisibleTurfs(var/list/visible)
// Create a new camera chunk, since the chunks are made as they are needed.
/datum/chunk/New(loc, x, y, z)
// 0xf = 15
x &= ~0xf
y &= ~0xf
src.x = x
src.y = y
src.z = z
for(var/turf/t in range(10, locate(x + 8, y + 8, z)))
if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16)
turfs[t] = t
acquireVisibleTurfs(visibleTurfs)
// Removes turf that isn't in turfs.
visibleTurfs &= turfs
obscuredTurfs = turfs - visibleTurfs
for(var/turf/t as anything in obscuredTurfs)
LAZYINITLIST(t.obfuscations)
if(!t.obfuscations[obfuscation.type])
var/image/ob_image = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER)
ob_image.plane = PLANE_FULLSCREEN
t.obfuscations[obfuscation.type] = ob_image
obscured += t.obfuscations[obfuscation.type]
#undef UPDATE_BUFFER
#define UPDATE_BUFFER 25 // 2.5 seconds
// CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the Eye to stream these chunks and know what it can and cannot see.
/datum/obfuscation
var/icon = 'icons/effects/cameravis.dmi'
var/icon_state = "black"
/datum/chunk
var/list/obscuredTurfs = list()
var/list/visibleTurfs = list()
var/list/obscured = list()
var/list/turfs = list()
var/list/seenby = list()
var/visible = 0
var/changed = 0
var/updating = 0
var/x = 0
var/y = 0
var/z = 0
var/datum/obfuscation/obfuscation = new()
// Add an eye to the chunk, then update if changed.
/datum/chunk/proc/add(mob/observer/eye/eye, add_images = TRUE)
if(add_images)
var/client/client = eye.GetViewerClient()
if(client)
client.images += obscured
eye.visibleChunks += src
visible++
seenby += eye
if(changed && !updating)
update()
// Remove an eye from the chunk, then update if changed.
/datum/chunk/proc/remove(mob/observer/eye/eye, remove_images = TRUE)
if(remove_images)
var/client/client = eye.GetViewerClient()
if(client)
client.images -= obscured
eye.visibleChunks -= src
seenby -= eye
if(visible > 0)
visible--
// Called when a chunk has changed. I.E: A wall was deleted.
/datum/chunk/proc/visibilityChanged(turf/loc)
if(!visibleTurfs[loc])
return
hasChanged()
// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
// instead be flagged to update the next time an AI Eye moves near it.
/datum/chunk/proc/hasChanged(var/update_now = 0)
if(visible || update_now)
if(!updating)
updating = 1
spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
update()
updating = 0
else
changed = 1
// The actual updating.
/datum/chunk/proc/update()
set background = 1
var/list/newVisibleTurfs = new()
acquireVisibleTurfs(newVisibleTurfs)
// Removes turf that isn't in turfs.
newVisibleTurfs &= turfs
var/list/visAdded = newVisibleTurfs - visibleTurfs
var/list/visRemoved = visibleTurfs - newVisibleTurfs
visibleTurfs = newVisibleTurfs
obscuredTurfs = turfs - newVisibleTurfs
for(var/turf/t as anything in visAdded)
if(LAZYLEN(t.obfuscations) && t.obfuscations[obfuscation.type])
obscured -= t.obfuscations[obfuscation.type]
for(var/mob/observer/eye/m as anything in seenby)
if(!m)
continue
var/client/client = m.GetViewerClient()
if(client)
client.images -= t.obfuscations[obfuscation.type]
for(var/turf/t as anything in visRemoved)
if(obscuredTurfs[t])
LAZYINITLIST(t.obfuscations)
if(!t.obfuscations[obfuscation.type])
var/image/ob_image = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER)
ob_image.plane = PLANE_FULLSCREEN
t.obfuscations[obfuscation.type] = ob_image
obscured += t.obfuscations[obfuscation.type]
for(var/mob/observer/eye/m as anything in seenby)
if(!m)
seenby -= m
continue
var/client/client = m.GetViewerClient()
if(client)
client.images += t.obfuscations[obfuscation.type]
/datum/chunk/proc/acquireVisibleTurfs(var/list/visible)
// Create a new camera chunk, since the chunks are made as they are needed.
/datum/chunk/New(loc, x, y, z)
// 0xf = 15
x &= ~0xf
y &= ~0xf
src.x = x
src.y = y
src.z = z
for(var/turf/t in range(10, locate(x + 8, y + 8, z)))
if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16)
turfs[t] = t
acquireVisibleTurfs(visibleTurfs)
// Removes turf that isn't in turfs.
visibleTurfs &= turfs
obscuredTurfs = turfs - visibleTurfs
for(var/turf/t as anything in obscuredTurfs)
LAZYINITLIST(t.obfuscations)
if(!t.obfuscations[obfuscation.type])
var/image/ob_image = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER)
ob_image.plane = PLANE_FULLSCREEN
t.obfuscations[obfuscation.type] = ob_image
obscured += t.obfuscations[obfuscation.type]
#undef UPDATE_BUFFER
+111 -111
View File
@@ -1,111 +1,111 @@
// EYE
//
// A mob that another mob controls to look around the station with.
// It streams chunks as it moves around, which will show it what the controller can and cannot see.
/mob/observer/eye
name = "Eye"
icon = 'icons/mob/eye.dmi'
icon_state = "default-eye"
alpha = 127
var/sprint = 10
var/cooldown = 0
var/acceleration = 1
var/owner_follows_eye = 0
see_in_dark = 7
status_flags = GODMODE
plane = PLANE_AI_EYE
var/mob/owner = null
var/list/visibleChunks = list()
var/ghostimage = null
var/datum/visualnet/visualnet
var/use_static = TRUE
var/static_visibility_range = 16
/mob/observer/eye/Destroy()
if(owner)
if(owner.eyeobj == src)
owner.eyeobj = null
owner = null
. = ..()
/mob/observer/eye/Move(n, direct)
if(owner == src)
return EyeMove(n, direct)
return 0
/mob/observer/eye/airflow_hit(atom/A)
airflow_speed = 0
airflow_dest = null
/mob/observer/eye/examinate()
set popup_menu = 0
set src = usr.contents
return 0
/mob/observer/eye/pointed()
set popup_menu = 0
set src = usr.contents
return 0
// Use this when setting the eye's location.
// It will also stream the chunk that the new loc is in.
/mob/observer/eye/proc/setLoc(var/T)
if(owner)
T = get_turf(T)
if(T != loc)
loc = T
if(owner.client)
owner.client.eye = src
if(owner_follows_eye)
visualnet.updateVisibility(owner, 0)
owner.loc = loc
visualnet.updateVisibility(owner, 0)
if(use_static)
visualnet.visibility(src, owner.client)
return 1
return 0
/mob/observer/eye/proc/getLoc()
if(owner)
if(!isturf(owner.loc) || !owner.client)
return
return loc
/mob
var/mob/observer/eye/eyeobj
/mob/proc/EyeMove(n, direct)
if(!eyeobj)
return
return eyeobj.EyeMove(n, direct)
/mob/observer/eye/proc/GetViewerClient()
if(owner)
return owner.client
return null
/mob/observer/eye/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/step = get_turf(get_step(src, direct))
if(step)
setLoc(step)
cooldown = world.timeofday + 5
if(acceleration)
sprint = min(sprint + 0.5, max_sprint)
else
sprint = initial
return 1
// EYE
//
// A mob that another mob controls to look around the station with.
// It streams chunks as it moves around, which will show it what the controller can and cannot see.
/mob/observer/eye
name = "Eye"
icon = 'icons/mob/eye.dmi'
icon_state = "default-eye"
alpha = 127
var/sprint = 10
var/cooldown = 0
var/acceleration = 1
var/owner_follows_eye = 0
see_in_dark = 7
status_flags = GODMODE
plane = PLANE_AI_EYE
var/mob/owner = null
var/list/visibleChunks = list()
var/ghostimage = null
var/datum/visualnet/visualnet
var/use_static = TRUE
var/static_visibility_range = 16
/mob/observer/eye/Destroy()
if(owner)
if(owner.eyeobj == src)
owner.eyeobj = null
owner = null
. = ..()
/mob/observer/eye/Move(n, direct)
if(owner == src)
return EyeMove(n, direct)
return 0
/mob/observer/eye/airflow_hit(atom/A)
airflow_speed = 0
airflow_dest = null
/mob/observer/eye/examinate()
set popup_menu = 0
set src = usr.contents
return 0
/mob/observer/eye/pointed()
set popup_menu = 0
set src = usr.contents
return 0
// Use this when setting the eye's location.
// It will also stream the chunk that the new loc is in.
/mob/observer/eye/proc/setLoc(var/T)
if(owner)
T = get_turf(T)
if(T != loc)
loc = T
if(owner.client)
owner.client.eye = src
if(owner_follows_eye)
visualnet.updateVisibility(owner, 0)
owner.loc = loc
visualnet.updateVisibility(owner, 0)
if(use_static)
visualnet.visibility(src, owner.client)
return 1
return 0
/mob/observer/eye/proc/getLoc()
if(owner)
if(!isturf(owner.loc) || !owner.client)
return
return loc
/mob
var/mob/observer/eye/eyeobj
/mob/proc/EyeMove(n, direct)
if(!eyeobj)
return
return eyeobj.EyeMove(n, direct)
/mob/observer/eye/proc/GetViewerClient()
if(owner)
return owner.client
return null
/mob/observer/eye/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/step = get_turf(get_step(src, direct))
if(step)
setLoc(step)
cooldown = world.timeofday + 5
if(acceleration)
sprint = min(sprint + 0.5, max_sprint)
else
sprint = initial
return 1
+7 -7
View File
@@ -1,7 +1,7 @@
/mob/observer/eye/Life()
..()
// If we lost our client, reset the list of visible chunks so they update properly on return
if(owner == src && !client)
visibleChunks.Cut()
/*else if(owner && !owner.client)
visibleChunks.Cut()*/
/mob/observer/eye/Life()
..()
// If we lost our client, reset the list of visible chunks so they update properly on return
if(owner == src && !client)
visibleChunks.Cut()
/*else if(owner && !owner.client)
visibleChunks.Cut()*/
+36 -36
View File
@@ -1,36 +1,36 @@
// CULT CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the Eye to stream these chunks and know what it can and cannot see.
/datum/obfuscation/cult
icon_state = "white"
/datum/chunk/cult
obfuscation = new /datum/obfuscation/cult()
/datum/chunk/cult/acquireVisibleTurfs(var/list/visible)
for(var/mob/living/L in living_mob_list)
for(var/turf/t in L.seen_cult_turfs())
visible[t] = t
/mob/living/proc/seen_cult_turfs()
return seen_turfs_in_range(src, 3)
/mob/living/carbon/human/seen_cult_turfs()
if(mind in cult.current_antagonists)
return seen_turfs_in_range(src, world.view)
return ..()
/mob/living/silicon/seen_cult_turfs()
return list()
/mob/living/simple_mob/seen_cult_turfs()
return seen_turfs_in_range(src, 1)
/mob/living/simple_mob/construct/shade/seen_cult_turfs()
return view(2, src)
/proc/seen_turfs_in_range(var/source, var/range)
var/turf/pos = get_turf(source)
return hear(range, pos)
// CULT CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the Eye to stream these chunks and know what it can and cannot see.
/datum/obfuscation/cult
icon_state = "white"
/datum/chunk/cult
obfuscation = new /datum/obfuscation/cult()
/datum/chunk/cult/acquireVisibleTurfs(var/list/visible)
for(var/mob/living/L in living_mob_list)
for(var/turf/t in L.seen_cult_turfs())
visible[t] = t
/mob/living/proc/seen_cult_turfs()
return seen_turfs_in_range(src, 3)
/mob/living/carbon/human/seen_cult_turfs()
if(mind in cult.current_antagonists)
return seen_turfs_in_range(src, world.view)
return ..()
/mob/living/silicon/seen_cult_turfs()
return list()
/mob/living/simple_mob/seen_cult_turfs()
return seen_turfs_in_range(src, 1)
/mob/living/simple_mob/construct/shade/seen_cult_turfs()
return view(2, src)
/proc/seen_turfs_in_range(var/source, var/range)
var/turf/pos = get_turf(source)
return hear(range, pos)
+15 -15
View File
@@ -1,15 +1,15 @@
// CULT NET
//
// The datum containing all the chunks.
/datum/visualnet/cult
chunk_type = /datum/chunk/cult
/datum/visualnet/cult/proc/provides_vision(var/mob/living/L)
return L.provides_cult_vision()
/mob/living/proc/provides_cult_vision()
return 1
/mob/living/silicon/provides_cult_vision()
return 0
// CULT NET
//
// The datum containing all the chunks.
/datum/visualnet/cult
chunk_type = /datum/chunk/cult
/datum/visualnet/cult/proc/provides_vision(var/mob/living/L)
return L.provides_cult_vision()
/mob/living/proc/provides_cult_vision()
return 1
/mob/living/silicon/provides_cult_vision()
return 0
+13 -13
View File
@@ -1,13 +1,13 @@
// MASK EYE
//
// A mob that a cultists controls to look around the station with.
// It streams chunks as it moves around, which will show it what the cultist can and cannot see.
/mob/observer/eye/maskEye
name = "Eye of Nar-Sie"
acceleration = 0
owner_follows_eye = 1
/mob/observer/eye/maskEye/New()
..()
visualnet = cultnet
// MASK EYE
//
// A mob that a cultists controls to look around the station with.
// It streams chunks as it moves around, which will show it what the cultist can and cannot see.
/mob/observer/eye/maskEye
name = "Eye of Nar-Sie"
acceleration = 0
owner_follows_eye = 1
/mob/observer/eye/maskEye/New()
..()
visualnet = cultnet
@@ -1,49 +1,49 @@
//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
#define CULT_UPDATE_BUFFER 30
/mob/living/var/updating_cult_vision = 0
/mob/living/Moved(atom/old_loc, direction, forced = FALSE)
. = ..()
if(!cultnet.provides_vision(src))
return
if(!updating_cult_vision)
updating_cult_vision = 1
spawn(CULT_UPDATE_BUFFER)
if(old_loc != src.loc)
cultnet.updateVisibility(old_loc, 0)
cultnet.updateVisibility(loc, 0)
updating_cult_vision = 0
#undef CULT_UPDATE_BUFFER
/mob/living/New()
..()
cultnet.updateVisibility(src, 0)
/mob/living/Destroy()
cultnet.updateVisibility(src, 0)
return ..()
/mob/living/rejuvenate()
var/was_dead = stat == DEAD
..()
if(was_dead && stat != DEAD)
// Arise!
cultnet.updateVisibility(src, 0)
/mob/living/death(gibbed, deathmessage="seizes up and falls limp...")
if(..(gibbed, deathmessage))
// If true, the mob went from living to dead (assuming everyone has been overriding as they should...)
cultnet.updateVisibility(src)
/datum/antagonist/add_antagonist(var/datum/mind/player)
. = ..()
if(src == cult)
cultnet.updateVisibility(player.current, 0)
/datum/antagonist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted)
..()
if(src == cult)
cultnet.updateVisibility(player.current, 0)
//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
#define CULT_UPDATE_BUFFER 30
/mob/living/var/updating_cult_vision = 0
/mob/living/Moved(atom/old_loc, direction, forced = FALSE)
. = ..()
if(!cultnet.provides_vision(src))
return
if(!updating_cult_vision)
updating_cult_vision = 1
spawn(CULT_UPDATE_BUFFER)
if(old_loc != src.loc)
cultnet.updateVisibility(old_loc, 0)
cultnet.updateVisibility(loc, 0)
updating_cult_vision = 0
#undef CULT_UPDATE_BUFFER
/mob/living/New()
..()
cultnet.updateVisibility(src, 0)
/mob/living/Destroy()
cultnet.updateVisibility(src, 0)
return ..()
/mob/living/rejuvenate()
var/was_dead = stat == DEAD
..()
if(was_dead && stat != DEAD)
// Arise!
cultnet.updateVisibility(src, 0)
/mob/living/death(gibbed, deathmessage="seizes up and falls limp...")
if(..(gibbed, deathmessage))
// If true, the mob went from living to dead (assuming everyone has been overriding as they should...)
cultnet.updateVisibility(src)
/datum/antagonist/add_antagonist(var/datum/mind/player)
. = ..()
if(src == cult)
cultnet.updateVisibility(player.current, 0)
/datum/antagonist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted)
..()
if(src == cult)
cultnet.updateVisibility(player.current, 0)
+50 -50
View File
@@ -1,51 +1,51 @@
// CREDITS
/*
Initial code credit for this goes to Uristqwerty.
Debugging, functionality, all comments and porting by Giacom.
Everything about freelook (or what we can put in here) will be stored here.
WHAT IS THIS?
This is a replacement for the current camera movement system, of the AI. Before this, the AI had to move between cameras and could
only see what the cameras could see. Not only this but the cameras could see through walls, which created problems.
With this, the AI controls an "AI Eye" mob, which moves just like a ghost; such as moving through walls and being invisible to players.
The AI's eye is set to this mob and then we use a system (explained below) to determine what the cameras around the AI Eye can and
cannot see. If the camera cannot see a turf, it will black it out, otherwise it won't and the AI will be able to see it.
This creates several features, such as.. no more see-through-wall cameras, easier to control camera movement, easier tracking,
the AI only being able to track mobs which are visible to a camera, only trackable mobs appearing on the mob list and many more.
HOW IT WORKS
It works by first creating a camera network datum. Inside of this camera network are "chunks" (which will be
explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/New() and Destroy().
Next the camera network has chunks. These chunks are a 16x16 tile block of turfs and cameras contained inside the chunk.
These turfs are then sorted out based on what the cameras can and cannot see. If none of the cameras can see the turf, inside
the 16x16 block, it is listed as an "obscured" turf. Meaning the AI won't be able to see it.
HOW IT UPDATES
The camera network uses a streaming method in order to effeciently update chunks. Since the server will have doors opening, doors closing,
turf being destroyed and other lag inducing stuff, we want to update it under certain conditions and not every tick.
The chunks are not created straight away, only when an AI eye moves into it's area is when it gets created.
One a chunk is created, when a non glass door opens/closes or an opacity turf is destroyed, we check to see if an AI Eye is looking in the area.
We do this with the "seenby" list, which updates everytime an AI is near a chunk. If there is an AI eye inside the area, we update the chunk
that the changed atom is inside and all surrounding chunks, since a camera's vision could leak onto another chunk. If there is no AI Eye, we instead
flag the chunk to update whenever it is loaded by an AI Eye. This is basically how the chunks update and keep it in sync. We then add some lag reducing
measures, such as an UPDATE_BUFFER which stops a chunk from updating too many times in a certain time-frame, only updating if the changed atom was blocking
sight; for example, we don't update glass airlocks or floors.
WHERE IS EVERYTHING?
cameranet.dm = Everything about the cameranet datum.
chunk.dm = Everything about the chunk datum.
eye.dm = Everything about the AI and the AIEye.
updating.dm = Everything about triggers that will update chunks.
// CREDITS
/*
Initial code credit for this goes to Uristqwerty.
Debugging, functionality, all comments and porting by Giacom.
Everything about freelook (or what we can put in here) will be stored here.
WHAT IS THIS?
This is a replacement for the current camera movement system, of the AI. Before this, the AI had to move between cameras and could
only see what the cameras could see. Not only this but the cameras could see through walls, which created problems.
With this, the AI controls an "AI Eye" mob, which moves just like a ghost; such as moving through walls and being invisible to players.
The AI's eye is set to this mob and then we use a system (explained below) to determine what the cameras around the AI Eye can and
cannot see. If the camera cannot see a turf, it will black it out, otherwise it won't and the AI will be able to see it.
This creates several features, such as.. no more see-through-wall cameras, easier to control camera movement, easier tracking,
the AI only being able to track mobs which are visible to a camera, only trackable mobs appearing on the mob list and many more.
HOW IT WORKS
It works by first creating a camera network datum. Inside of this camera network are "chunks" (which will be
explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/New() and Destroy().
Next the camera network has chunks. These chunks are a 16x16 tile block of turfs and cameras contained inside the chunk.
These turfs are then sorted out based on what the cameras can and cannot see. If none of the cameras can see the turf, inside
the 16x16 block, it is listed as an "obscured" turf. Meaning the AI won't be able to see it.
HOW IT UPDATES
The camera network uses a streaming method in order to effeciently update chunks. Since the server will have doors opening, doors closing,
turf being destroyed and other lag inducing stuff, we want to update it under certain conditions and not every tick.
The chunks are not created straight away, only when an AI eye moves into it's area is when it gets created.
One a chunk is created, when a non glass door opens/closes or an opacity turf is destroyed, we check to see if an AI Eye is looking in the area.
We do this with the "seenby" list, which updates everytime an AI is near a chunk. If there is an AI eye inside the area, we update the chunk
that the changed atom is inside and all surrounding chunks, since a camera's vision could leak onto another chunk. If there is no AI Eye, we instead
flag the chunk to update whenever it is loaded by an AI Eye. This is basically how the chunks update and keep it in sync. We then add some lag reducing
measures, such as an UPDATE_BUFFER which stops a chunk from updating too many times in a certain time-frame, only updating if the changed atom was blocking
sight; for example, we don't update glass airlocks or floors.
WHERE IS EVERYTHING?
cameranet.dm = Everything about the cameranet datum.
chunk.dm = Everything about the chunk datum.
eye.dm = Everything about the AI and the AIEye.
updating.dm = Everything about triggers that will update chunks.
*/
+58 -58
View File
@@ -1,59 +1,59 @@
//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
// TURFS
/proc/updateVisibility(atom/A, var/opacity_check = 1)
if(ticker)
for(var/datum/visualnet/VN in visual_nets)
VN.updateVisibility(A, opacity_check)
/turf
var/list/image/obfuscations
/turf/drain_power()
return -1
/turf/simulated/Destroy()
updateVisibility(src)
if(zone)
if(can_safely_remove_from_zone())
c_copy_air()
zone.remove(src)
else
zone.rebuild()
return ..()
/turf/simulated/Initialize()
. = ..()
updateVisibility(src)
// STRUCTURES
/obj/structure/Destroy()
updateVisibility(src)
return ..()
/obj/structure/New()
..()
updateVisibility(src)
// EFFECTS
/obj/effect/Destroy()
updateVisibility(src)
return ..()
/obj/effect/Initialize()
. = ..()
updateVisibility(src)
// DOORS
// Simply updates the visibility of the area when it opens/closes/destroyed.
/obj/machinery/door/update_nearby_tiles(need_rebuild)
. = ..(need_rebuild)
// Glass door glass = 1
// don't check then?
if(!glass)
//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
// TURFS
/proc/updateVisibility(atom/A, var/opacity_check = 1)
if(ticker)
for(var/datum/visualnet/VN in visual_nets)
VN.updateVisibility(A, opacity_check)
/turf
var/list/image/obfuscations
/turf/drain_power()
return -1
/turf/simulated/Destroy()
updateVisibility(src)
if(zone)
if(can_safely_remove_from_zone())
c_copy_air()
zone.remove(src)
else
zone.rebuild()
return ..()
/turf/simulated/Initialize()
. = ..()
updateVisibility(src)
// STRUCTURES
/obj/structure/Destroy()
updateVisibility(src)
return ..()
/obj/structure/New()
..()
updateVisibility(src)
// EFFECTS
/obj/effect/Destroy()
updateVisibility(src)
return ..()
/obj/effect/Initialize()
. = ..()
updateVisibility(src)
// DOORS
// Simply updates the visibility of the area when it opens/closes/destroyed.
/obj/machinery/door/update_nearby_tiles(need_rebuild)
. = ..(need_rebuild)
// Glass door glass = 1
// don't check then?
if(!glass)
updateVisibility(src, 0)
+161 -161
View File
@@ -1,161 +1,161 @@
// VISUAL NET
//
// The datum containing all the chunks.
#define CHUNK_SIZE 16
/datum/visualnet
// The chunks of the map, mapping the areas that an object can see.
var/list/chunks = list()
var/ready = 0
var/chunk_type = /datum/chunk
/datum/visualnet/New()
..()
visual_nets += src
/datum/visualnet/Destroy()
visual_nets -= src
return ..()
// Checks if a chunk has been Generated in x, y, z.
/datum/visualnet/proc/chunkGenerated(x, y, z)
x &= ~0xf
y &= ~0xf
var/key = "[x],[y],[z]"
return (chunks[key])
// Returns the chunk in the x, y, z.
// If there is no chunk, it creates a new chunk and returns that.
/datum/visualnet/proc/getChunk(x, y, z)
x &= ~0xf
y &= ~0xf
var/key = "[x],[y],[z]"
if(!chunks[key])
chunks[key] = new chunk_type(null, x, y, z)
return chunks[key]
// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.
/datum/visualnet/proc/visibility(list/moved_eyes, client/C, list/other_eyes)
if(!islist(moved_eyes))
moved_eyes = moved_eyes ? list(moved_eyes) : list()
if(islist(other_eyes))
other_eyes = (other_eyes - moved_eyes)
else
other_eyes = list()
var/list/chunks_pre_seen = list()
var/list/chunks_post_seen = list()
for(var/mob/observer/eye/eye as anything in moved_eyes)
if(C)
chunks_pre_seen |= eye.visibleChunks
// 0xf = 15
var/static_range = eye.static_visibility_range
var/x1 = max(0, eye.x - static_range) & ~(CHUNK_SIZE - 1)
var/y1 = max(0, eye.y - static_range) & ~(CHUNK_SIZE - 1)
var/x2 = min(world.maxx, eye.x + static_range) & ~(CHUNK_SIZE - 1)
var/y2 = min(world.maxy, eye.y + static_range) & ~(CHUNK_SIZE - 1)
var/list/visibleChunks = list()
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
visibleChunks |= getChunk(x, y, eye.z)
var/list/remove = eye.visibleChunks - visibleChunks
var/list/add = visibleChunks - eye.visibleChunks
for(var/datum/chunk/c as anything in remove)
c.remove(eye, FALSE)
for(var/datum/chunk/c as anything in add)
c.add(eye, FALSE)
if(C)
chunks_post_seen |= eye.visibleChunks
if(C)
for(var/mob/observer/eye/eye as anything in other_eyes)
chunks_post_seen |= eye.visibleChunks
var/list/remove = chunks_pre_seen - chunks_post_seen
var/list/add = chunks_post_seen - chunks_pre_seen
for(var/datum/chunk/c as anything in remove)
C.images -= c.obscured
for(var/datum/chunk/c as anything in add)
C.images += c.obscured
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
/datum/visualnet/proc/updateVisibility(atom/A, var/opacity_check = 1)
if(!ticker || (opacity_check && !A.opacity))
return
majorChunkChange(A, 2)
/datum/visualnet/proc/updateChunk(x, y, z)
// 0xf = 15
if(!chunkGenerated(x, y, z))
return
var/datum/chunk/chunk = getChunk(x, y, z)
chunk.hasChanged()
// Never access this proc directly!!!!
// This will update the chunk and all the surrounding chunks.
// It will also add the atom to the cameras list if you set the choice to 1.
// Setting the choice to 0 will remove the camera from the chunks.
// If you want to update the chunks around an object, without adding/removing a camera, use choice 2.
/datum/visualnet/proc/majorChunkChange(atom/c, var/choice)
// 0xf = 15
if(!c)
return
var/turf/T = get_turf(c)
if(T)
var/x1 = max(0, T.x - 8) & ~0xf
var/y1 = max(0, T.y - 8) & ~0xf
var/x2 = min(world.maxx, T.x + 8) & ~0xf
var/y2 = min(world.maxy, T.y + 8) & ~0xf
//to_world("X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]")
for(var/x = x1; x <= x2; x += 16)
for(var/y = y1; y <= y2; y += 16)
if(chunkGenerated(x, y, T.z))
var/datum/chunk/chunk = getChunk(x, y, T.z)
onMajorChunkChange(c, choice, chunk)
chunk.hasChanged()
/datum/visualnet/proc/onMajorChunkChange(atom/c, var/choice, var/datum/chunk/chunk)
// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
/datum/visualnet/proc/checkVis(mob/living/target as mob)
// 0xf = 15
var/turf/position = get_turf(target)
return checkTurfVis(position)
/datum/visualnet/proc/checkTurfVis(var/turf/position)
var/datum/chunk/chunk = getChunk(position.x, position.y, position.z)
if(chunk)
if(chunk.changed)
chunk.hasChanged(1) // Update now, no matter if it's visible or not.
if(chunk.visibleTurfs[position])
return 1
return 0
// Debug verb for VVing the chunk that the turf is in.
/*
/turf/verb/view_chunk()
set src in world
if(cameranet.chunkGenerated(x, y, z))
var/datum/chunk/chunk = cameranet.getCameraChunk(x, y, z)
usr.client.debug_variables(chunk)
*/
// VISUAL NET
//
// The datum containing all the chunks.
#define CHUNK_SIZE 16
/datum/visualnet
// The chunks of the map, mapping the areas that an object can see.
var/list/chunks = list()
var/ready = 0
var/chunk_type = /datum/chunk
/datum/visualnet/New()
..()
visual_nets += src
/datum/visualnet/Destroy()
visual_nets -= src
return ..()
// Checks if a chunk has been Generated in x, y, z.
/datum/visualnet/proc/chunkGenerated(x, y, z)
x &= ~0xf
y &= ~0xf
var/key = "[x],[y],[z]"
return (chunks[key])
// Returns the chunk in the x, y, z.
// If there is no chunk, it creates a new chunk and returns that.
/datum/visualnet/proc/getChunk(x, y, z)
x &= ~0xf
y &= ~0xf
var/key = "[x],[y],[z]"
if(!chunks[key])
chunks[key] = new chunk_type(null, x, y, z)
return chunks[key]
// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.
/datum/visualnet/proc/visibility(list/moved_eyes, client/C, list/other_eyes)
if(!islist(moved_eyes))
moved_eyes = moved_eyes ? list(moved_eyes) : list()
if(islist(other_eyes))
other_eyes = (other_eyes - moved_eyes)
else
other_eyes = list()
var/list/chunks_pre_seen = list()
var/list/chunks_post_seen = list()
for(var/mob/observer/eye/eye as anything in moved_eyes)
if(C)
chunks_pre_seen |= eye.visibleChunks
// 0xf = 15
var/static_range = eye.static_visibility_range
var/x1 = max(0, eye.x - static_range) & ~(CHUNK_SIZE - 1)
var/y1 = max(0, eye.y - static_range) & ~(CHUNK_SIZE - 1)
var/x2 = min(world.maxx, eye.x + static_range) & ~(CHUNK_SIZE - 1)
var/y2 = min(world.maxy, eye.y + static_range) & ~(CHUNK_SIZE - 1)
var/list/visibleChunks = list()
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
visibleChunks |= getChunk(x, y, eye.z)
var/list/remove = eye.visibleChunks - visibleChunks
var/list/add = visibleChunks - eye.visibleChunks
for(var/datum/chunk/c as anything in remove)
c.remove(eye, FALSE)
for(var/datum/chunk/c as anything in add)
c.add(eye, FALSE)
if(C)
chunks_post_seen |= eye.visibleChunks
if(C)
for(var/mob/observer/eye/eye as anything in other_eyes)
chunks_post_seen |= eye.visibleChunks
var/list/remove = chunks_pre_seen - chunks_post_seen
var/list/add = chunks_post_seen - chunks_pre_seen
for(var/datum/chunk/c as anything in remove)
C.images -= c.obscured
for(var/datum/chunk/c as anything in add)
C.images += c.obscured
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
/datum/visualnet/proc/updateVisibility(atom/A, var/opacity_check = 1)
if(!ticker || (opacity_check && !A.opacity))
return
majorChunkChange(A, 2)
/datum/visualnet/proc/updateChunk(x, y, z)
// 0xf = 15
if(!chunkGenerated(x, y, z))
return
var/datum/chunk/chunk = getChunk(x, y, z)
chunk.hasChanged()
// Never access this proc directly!!!!
// This will update the chunk and all the surrounding chunks.
// It will also add the atom to the cameras list if you set the choice to 1.
// Setting the choice to 0 will remove the camera from the chunks.
// If you want to update the chunks around an object, without adding/removing a camera, use choice 2.
/datum/visualnet/proc/majorChunkChange(atom/c, var/choice)
// 0xf = 15
if(!c)
return
var/turf/T = get_turf(c)
if(T)
var/x1 = max(0, T.x - 8) & ~0xf
var/y1 = max(0, T.y - 8) & ~0xf
var/x2 = min(world.maxx, T.x + 8) & ~0xf
var/y2 = min(world.maxy, T.y + 8) & ~0xf
//to_world("X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]")
for(var/x = x1; x <= x2; x += 16)
for(var/y = y1; y <= y2; y += 16)
if(chunkGenerated(x, y, T.z))
var/datum/chunk/chunk = getChunk(x, y, T.z)
onMajorChunkChange(c, choice, chunk)
chunk.hasChanged()
/datum/visualnet/proc/onMajorChunkChange(atom/c, var/choice, var/datum/chunk/chunk)
// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
/datum/visualnet/proc/checkVis(mob/living/target as mob)
// 0xf = 15
var/turf/position = get_turf(target)
return checkTurfVis(position)
/datum/visualnet/proc/checkTurfVis(var/turf/position)
var/datum/chunk/chunk = getChunk(position.x, position.y, position.z)
if(chunk)
if(chunk.changed)
chunk.hasChanged(1) // Update now, no matter if it's visible or not.
if(chunk.visibleTurfs[position])
return 1
return 0
// Debug verb for VVing the chunk that the turf is in.
/*
/turf/verb/view_chunk()
set src in world
if(cameranet.chunkGenerated(x, y, z))
var/datum/chunk/chunk = cameranet.getCameraChunk(x, y, z)
usr.client.debug_variables(chunk)
*/
+271 -271
View File
@@ -1,271 +1,271 @@
//The list of slots by priority. equip_to_appropriate_slot() uses this list. Doesn't matter if a mob type doesn't have a slot.
var/list/slot_equipment_priority = list( \
slot_back,\
slot_wear_id,\
slot_w_uniform,\
slot_wear_suit,\
slot_wear_mask,\
slot_head,\
slot_shoes,\
slot_gloves,\
slot_l_ear,\
slot_r_ear,\
slot_glasses,\
slot_belt,\
slot_s_store,\
slot_tie,\
slot_l_store,\
slot_r_store\
)
/mob
var/obj/item/weapon/storage/s_active = null // Even ghosts can/should be able to peek into boxes on the ground
//This proc is called whenever someone clicks an inventory ui slot.
/mob/proc/attack_ui(var/slot)
var/obj/item/W = get_active_hand()
var/obj/item/E = get_equipped_item(slot)
if (istype(E))
if(istype(W))
E.attackby(W,src)
else
E.attack_hand(src)
else
equip_to_slot_if_possible(W, slot)
/* Inventory manipulation */
/mob/proc/put_in_any_hand_if_possible(obj/item/W as obj, del_on_fail = 0, disable_warning = 1, redraw_mob = 1)
if(equip_to_slot_if_possible(W, slot_l_hand, del_on_fail, disable_warning, redraw_mob))
return 1
else if(equip_to_slot_if_possible(W, slot_r_hand, del_on_fail, disable_warning, redraw_mob))
return 1
return 0
//This is a SAFE proc. Use this instead of equip_to_slot()!
//set del_on_fail to have it delete W if it fails to equip
//set disable_warning to disable the 'you are unable to equip that' warning.
//unset redraw_mob to prevent the mob from being redrawn at the end.
/mob/proc/equip_to_slot_if_possible(obj/item/W as obj, slot, del_on_fail = 0, disable_warning = 0, redraw_mob = 1, ignore_obstructions = 1)
if(!W)
return 0
if(!W.mob_can_equip(src, slot, disable_warning, ignore_obstructions))
if(del_on_fail)
qdel(W)
else
if(!disable_warning)
to_chat(src, span_red("You are unable to equip that.")) //Only print if del_on_fail is false
return 0
equip_to_slot(W, slot, redraw_mob) //This proc should not ever fail.
return 1
//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't eqip need to be done before! Use mob_can_equip() for that task.
//In most cases you will want to use equip_to_slot_if_possible()
/mob/proc/equip_to_slot(obj/item/W as obj, slot)
return
//This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the rounds tarts and when events happen and such.
/mob/proc/equip_to_slot_or_del(obj/item/W as obj, slot, ignore_obstructions = 1)
return equip_to_slot_if_possible(W, slot, 1, 1, 0, ignore_obstructions)
//hurgh. these feel hacky, but they're the only way I could get the damn thing to work. I guess they could be handy for antag spawners too?
/mob/proc/equip_voidsuit_to_slot_or_del_with_refit(obj/item/clothing/suit/space/void/W as obj, slot, species = SPECIES_HUMAN)
W.refit_for_species(species)
return equip_to_slot_if_possible(W, slot, 1, 1, 0)
/mob/proc/equip_voidhelm_to_slot_or_del_with_refit(obj/item/clothing/head/helmet/space/void/W as obj, slot, species = SPECIES_HUMAN)
W.refit_for_species(species)
return equip_to_slot_if_possible(W, slot, 1, 1, 0)
//Checks if a given slot can be accessed at this time, either to equip or unequip I
/mob/proc/slot_is_accessible(var/slot, var/obj/item/I, mob/user=null)
return 1
//puts the item "W" into an appropriate slot in a human's inventory
//returns 0 if it cannot, 1 if successful
/mob/proc/equip_to_appropriate_slot(obj/item/W)
for(var/slot in slot_equipment_priority)
if(equip_to_slot_if_possible(W, slot, del_on_fail=0, disable_warning=1, redraw_mob=1))
return 1
return 0
/mob/proc/equip_to_storage(obj/item/newitem, user_initiated = FALSE)
return 0
/* Hands */
//Returns the thing in our active hand
/mob/proc/get_active_hand()
//Returns the thing in our inactive hand
/mob/proc/get_inactive_hand()
// Override for your specific mob's hands or lack thereof.
/mob/proc/is_holding_item_of_type(typepath)
return FALSE
// Override for your specific mob's hands or lack thereof.
/mob/proc/get_all_held_items()
return list()
//Puts the item into your l_hand if possible and calls all necessary triggers/updates. returns 1 on success.
/mob/proc/put_in_l_hand(var/obj/item/W)
if(lying || !istype(W))
return 0
return 1
//Puts the item into your r_hand if possible and calls all necessary triggers/updates. returns 1 on success.
/mob/proc/put_in_r_hand(var/obj/item/W)
if(lying || !istype(W))
return 0
return 1
//Puts the item into our active hand if possible. returns 1 on success.
/mob/proc/put_in_active_hand(var/obj/item/W)
return 0 // Moved to human procs because only they need to use hands.
//Puts the item into our inactive hand if possible. returns 1 on success.
/mob/proc/put_in_inactive_hand(var/obj/item/W)
return 0 // As above.
//Puts the item our active hand if possible. Failing that it tries our inactive hand. Returns 1 on success.
//If both fail it drops it on the floor and returns 0.
//This is probably the main one you need to know :)
/mob/proc/put_in_hands(var/obj/item/W)
if(!W)
return 0
W.forceMove(drop_location())
W.reset_plane_and_layer()
W.dropped()
return 0
// Removes an item from inventory and places it in the target atom.
// If canremove or other conditions need to be checked then use unEquip instead.
/mob/proc/drop_from_inventory(var/obj/item/W, var/atom/target)
if(W)
remove_from_mob(W, target)
return TRUE
return FALSE
//Drops the item in our left hand
/mob/proc/drop_l_hand(var/atom/Target)
return 0
//Drops the item in our right hand
/mob/proc/drop_r_hand(var/atom/Target)
return 0
//Drops the item in our active hand. TODO: rename this to drop_active_hand or something
/mob/proc/drop_item(var/atom/Target)
return
/*
Removes the object from any slots the mob might have, calling the appropriate icon update proc.
Does nothing else.
DO NOT CALL THIS PROC DIRECTLY. It is meant to be called only by other inventory procs.
It's probably okay to use it if you are transferring the item between slots on the same mob,
but chances are you're safer calling remove_from_mob() or drop_from_inventory() anyways.
As far as I can tell the proc exists so that mobs with different inventory slots can override
the search through all the slots, without having to duplicate the rest of the item dropping.
*/
/mob/proc/u_equip(obj/W as obj)
/mob/proc/isEquipped(obj/item/I)
if(!I)
return 0
return get_inventory_slot(I) != 0
/mob/proc/canUnEquip(obj/item/I)
if(!I) //If there's nothing to drop, the drop is automatically successful.
return 1
var/slot = get_inventory_slot(I)
return I.mob_can_unequip(src, slot)
/mob/proc/get_inventory_slot(obj/item/I)
var/slot = 0
for(var/s in 1 to SLOT_TOTAL)
if(get_equipped_item(s) == I)
slot = s
break
return slot
//This differs from remove_from_mob() in that it checks if the item can be unequipped first.
/mob/proc/unEquip(obj/item/I, force = 0, var/atom/target) //Force overrides NODROP for things like wizarditis and admin undress.
if(!(force || canUnEquip(I)))
return FALSE
drop_from_inventory(I, target)
return TRUE
//visibly unequips I but it is NOT MOVED AND REMAINS IN SRC
//item MUST BE FORCEMOVE'D OR QDEL'D
/mob/proc/temporarilyRemoveItemFromInventory(obj/item/I, force = FALSE, idrop = TRUE)
return u_equip(I, force, null, TRUE, idrop)
///sometimes we only want to grant the item's action if it's equipped in a specific slot.
/obj/item/proc/item_action_slot_check(slot, mob/user)
if(slot == SLOT_BACK || slot == LEGS) //these aren't true slots, so avoid granting actions there
return FALSE
return TRUE
///Get the item on the mob in the storage slot identified by the id passed in
/mob/proc/get_item_by_slot(slot_id)
return null
/mob/proc/getBackSlot()
return SLOT_BACK
//Attemps to remove an object on a mob.
/mob/proc/remove_from_mob(var/obj/O, var/atom/target)
if(!O) // Nothing to remove, so we succeed.
return 1
src.u_equip(O)
if (src.client)
src.client.screen -= O
O.reset_plane_and_layer()
O.screen_loc = null
if(istype(O, /obj/item))
var/obj/item/I = O
if(target)
I.forceMove(target)
else
I.dropInto(drop_location())
I.dropped(src)
return TRUE
//Returns the item equipped to the specified slot, if any.
/mob/proc/get_equipped_item(var/slot)
return null
//Outdated but still in use apparently. This should at least be a human proc.
/mob/proc/get_equipped_items()
var/list/items = new/list()
if(hasvar(src,"back")) if(src:back) items += src:back
if(hasvar(src,"belt")) if(src:belt) items += src:belt
if(hasvar(src,"l_ear")) if(src:l_ear) items += src:l_ear
if(hasvar(src,"r_ear")) if(src:r_ear) items += src:r_ear
if(hasvar(src,"glasses")) if(src:glasses) items += src:glasses
if(hasvar(src,"gloves")) if(src:gloves) items += src:gloves
if(hasvar(src,"head")) if(src:head) items += src:head
if(hasvar(src,"shoes")) if(src:shoes) items += src:shoes
if(hasvar(src,"wear_id")) if(src:wear_id) items += src:wear_id
if(hasvar(src,"wear_mask")) if(src:wear_mask) items += src:wear_mask
if(hasvar(src,"wear_suit")) if(src:wear_suit) items += src:wear_suit
if(hasvar(src,"w_uniform")) if(src:w_uniform) items += src:w_uniform
if(hasvar(src,"l_hand")) if(src:l_hand) items += src:l_hand
if(hasvar(src,"r_hand")) if(src:r_hand) items += src:r_hand
return items
/mob/proc/delete_inventory()
for(var/entry in get_equipped_items())
drop_from_inventory(entry)
qdel(entry)
//The list of slots by priority. equip_to_appropriate_slot() uses this list. Doesn't matter if a mob type doesn't have a slot.
var/list/slot_equipment_priority = list( \
slot_back,\
slot_wear_id,\
slot_w_uniform,\
slot_wear_suit,\
slot_wear_mask,\
slot_head,\
slot_shoes,\
slot_gloves,\
slot_l_ear,\
slot_r_ear,\
slot_glasses,\
slot_belt,\
slot_s_store,\
slot_tie,\
slot_l_store,\
slot_r_store\
)
/mob
var/obj/item/weapon/storage/s_active = null // Even ghosts can/should be able to peek into boxes on the ground
//This proc is called whenever someone clicks an inventory ui slot.
/mob/proc/attack_ui(var/slot)
var/obj/item/W = get_active_hand()
var/obj/item/E = get_equipped_item(slot)
if (istype(E))
if(istype(W))
E.attackby(W,src)
else
E.attack_hand(src)
else
equip_to_slot_if_possible(W, slot)
/* Inventory manipulation */
/mob/proc/put_in_any_hand_if_possible(obj/item/W as obj, del_on_fail = 0, disable_warning = 1, redraw_mob = 1)
if(equip_to_slot_if_possible(W, slot_l_hand, del_on_fail, disable_warning, redraw_mob))
return 1
else if(equip_to_slot_if_possible(W, slot_r_hand, del_on_fail, disable_warning, redraw_mob))
return 1
return 0
//This is a SAFE proc. Use this instead of equip_to_slot()!
//set del_on_fail to have it delete W if it fails to equip
//set disable_warning to disable the 'you are unable to equip that' warning.
//unset redraw_mob to prevent the mob from being redrawn at the end.
/mob/proc/equip_to_slot_if_possible(obj/item/W as obj, slot, del_on_fail = 0, disable_warning = 0, redraw_mob = 1, ignore_obstructions = 1)
if(!W)
return 0
if(!W.mob_can_equip(src, slot, disable_warning, ignore_obstructions))
if(del_on_fail)
qdel(W)
else
if(!disable_warning)
to_chat(src, span_red("You are unable to equip that.")) //Only print if del_on_fail is false
return 0
equip_to_slot(W, slot, redraw_mob) //This proc should not ever fail.
return 1
//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't eqip need to be done before! Use mob_can_equip() for that task.
//In most cases you will want to use equip_to_slot_if_possible()
/mob/proc/equip_to_slot(obj/item/W as obj, slot)
return
//This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the rounds tarts and when events happen and such.
/mob/proc/equip_to_slot_or_del(obj/item/W as obj, slot, ignore_obstructions = 1)
return equip_to_slot_if_possible(W, slot, 1, 1, 0, ignore_obstructions)
//hurgh. these feel hacky, but they're the only way I could get the damn thing to work. I guess they could be handy for antag spawners too?
/mob/proc/equip_voidsuit_to_slot_or_del_with_refit(obj/item/clothing/suit/space/void/W as obj, slot, species = SPECIES_HUMAN)
W.refit_for_species(species)
return equip_to_slot_if_possible(W, slot, 1, 1, 0)
/mob/proc/equip_voidhelm_to_slot_or_del_with_refit(obj/item/clothing/head/helmet/space/void/W as obj, slot, species = SPECIES_HUMAN)
W.refit_for_species(species)
return equip_to_slot_if_possible(W, slot, 1, 1, 0)
//Checks if a given slot can be accessed at this time, either to equip or unequip I
/mob/proc/slot_is_accessible(var/slot, var/obj/item/I, mob/user=null)
return 1
//puts the item "W" into an appropriate slot in a human's inventory
//returns 0 if it cannot, 1 if successful
/mob/proc/equip_to_appropriate_slot(obj/item/W)
for(var/slot in slot_equipment_priority)
if(equip_to_slot_if_possible(W, slot, del_on_fail=0, disable_warning=1, redraw_mob=1))
return 1
return 0
/mob/proc/equip_to_storage(obj/item/newitem, user_initiated = FALSE)
return 0
/* Hands */
//Returns the thing in our active hand
/mob/proc/get_active_hand()
//Returns the thing in our inactive hand
/mob/proc/get_inactive_hand()
// Override for your specific mob's hands or lack thereof.
/mob/proc/is_holding_item_of_type(typepath)
return FALSE
// Override for your specific mob's hands or lack thereof.
/mob/proc/get_all_held_items()
return list()
//Puts the item into your l_hand if possible and calls all necessary triggers/updates. returns 1 on success.
/mob/proc/put_in_l_hand(var/obj/item/W)
if(lying || !istype(W))
return 0
return 1
//Puts the item into your r_hand if possible and calls all necessary triggers/updates. returns 1 on success.
/mob/proc/put_in_r_hand(var/obj/item/W)
if(lying || !istype(W))
return 0
return 1
//Puts the item into our active hand if possible. returns 1 on success.
/mob/proc/put_in_active_hand(var/obj/item/W)
return 0 // Moved to human procs because only they need to use hands.
//Puts the item into our inactive hand if possible. returns 1 on success.
/mob/proc/put_in_inactive_hand(var/obj/item/W)
return 0 // As above.
//Puts the item our active hand if possible. Failing that it tries our inactive hand. Returns 1 on success.
//If both fail it drops it on the floor and returns 0.
//This is probably the main one you need to know :)
/mob/proc/put_in_hands(var/obj/item/W)
if(!W)
return 0
W.forceMove(drop_location())
W.reset_plane_and_layer()
W.dropped()
return 0
// Removes an item from inventory and places it in the target atom.
// If canremove or other conditions need to be checked then use unEquip instead.
/mob/proc/drop_from_inventory(var/obj/item/W, var/atom/target)
if(W)
remove_from_mob(W, target)
return TRUE
return FALSE
//Drops the item in our left hand
/mob/proc/drop_l_hand(var/atom/Target)
return 0
//Drops the item in our right hand
/mob/proc/drop_r_hand(var/atom/Target)
return 0
//Drops the item in our active hand. TODO: rename this to drop_active_hand or something
/mob/proc/drop_item(var/atom/Target)
return
/*
Removes the object from any slots the mob might have, calling the appropriate icon update proc.
Does nothing else.
DO NOT CALL THIS PROC DIRECTLY. It is meant to be called only by other inventory procs.
It's probably okay to use it if you are transferring the item between slots on the same mob,
but chances are you're safer calling remove_from_mob() or drop_from_inventory() anyways.
As far as I can tell the proc exists so that mobs with different inventory slots can override
the search through all the slots, without having to duplicate the rest of the item dropping.
*/
/mob/proc/u_equip(obj/W as obj)
/mob/proc/isEquipped(obj/item/I)
if(!I)
return 0
return get_inventory_slot(I) != 0
/mob/proc/canUnEquip(obj/item/I)
if(!I) //If there's nothing to drop, the drop is automatically successful.
return 1
var/slot = get_inventory_slot(I)
return I.mob_can_unequip(src, slot)
/mob/proc/get_inventory_slot(obj/item/I)
var/slot = 0
for(var/s in 1 to SLOT_TOTAL)
if(get_equipped_item(s) == I)
slot = s
break
return slot
//This differs from remove_from_mob() in that it checks if the item can be unequipped first.
/mob/proc/unEquip(obj/item/I, force = 0, var/atom/target) //Force overrides NODROP for things like wizarditis and admin undress.
if(!(force || canUnEquip(I)))
return FALSE
drop_from_inventory(I, target)
return TRUE
//visibly unequips I but it is NOT MOVED AND REMAINS IN SRC
//item MUST BE FORCEMOVE'D OR QDEL'D
/mob/proc/temporarilyRemoveItemFromInventory(obj/item/I, force = FALSE, idrop = TRUE)
return u_equip(I, force, null, TRUE, idrop)
///sometimes we only want to grant the item's action if it's equipped in a specific slot.
/obj/item/proc/item_action_slot_check(slot, mob/user)
if(slot == SLOT_BACK || slot == LEGS) //these aren't true slots, so avoid granting actions there
return FALSE
return TRUE
///Get the item on the mob in the storage slot identified by the id passed in
/mob/proc/get_item_by_slot(slot_id)
return null
/mob/proc/getBackSlot()
return SLOT_BACK
//Attemps to remove an object on a mob.
/mob/proc/remove_from_mob(var/obj/O, var/atom/target)
if(!O) // Nothing to remove, so we succeed.
return 1
src.u_equip(O)
if (src.client)
src.client.screen -= O
O.reset_plane_and_layer()
O.screen_loc = null
if(istype(O, /obj/item))
var/obj/item/I = O
if(target)
I.forceMove(target)
else
I.dropInto(drop_location())
I.dropped(src)
return TRUE
//Returns the item equipped to the specified slot, if any.
/mob/proc/get_equipped_item(var/slot)
return null
//Outdated but still in use apparently. This should at least be a human proc.
/mob/proc/get_equipped_items()
var/list/items = new/list()
if(hasvar(src,"back")) if(src:back) items += src:back
if(hasvar(src,"belt")) if(src:belt) items += src:belt
if(hasvar(src,"l_ear")) if(src:l_ear) items += src:l_ear
if(hasvar(src,"r_ear")) if(src:r_ear) items += src:r_ear
if(hasvar(src,"glasses")) if(src:glasses) items += src:glasses
if(hasvar(src,"gloves")) if(src:gloves) items += src:gloves
if(hasvar(src,"head")) if(src:head) items += src:head
if(hasvar(src,"shoes")) if(src:shoes) items += src:shoes
if(hasvar(src,"wear_id")) if(src:wear_id) items += src:wear_id
if(hasvar(src,"wear_mask")) if(src:wear_mask) items += src:wear_mask
if(hasvar(src,"wear_suit")) if(src:wear_suit) items += src:wear_suit
if(hasvar(src,"w_uniform")) if(src:w_uniform) items += src:w_uniform
if(hasvar(src,"l_hand")) if(src:l_hand) items += src:l_hand
if(hasvar(src,"r_hand")) if(src:r_hand) items += src:r_hand
return items
/mob/proc/delete_inventory()
for(var/entry in get_equipped_items())
drop_from_inventory(entry)
qdel(entry)
+114 -114
View File
@@ -1,114 +1,114 @@
#define AUTOHISS_OFF 0
#define AUTOHISS_BASIC 1
#define AUTOHISS_FULL 2
#define AUTOHISS_NUM 3
/mob/proc/handle_autohiss(message, datum/language/L)
return message // no autohiss at this level
/mob/living/carbon/human/handle_autohiss(message, datum/language/L)
if(!client || client.autohiss_mode == AUTOHISS_OFF) // no need to process if there's no client or they have autohiss off
return message
return species.handle_autohiss(message, L, client.autohiss_mode)
/client
var/autohiss_mode = AUTOHISS_OFF
/client/verb/toggle_autohiss()
set name = "Toggle Auto-Hiss"
set desc = "Toggle automatic hissing as Unathi and r-rolling as Taj"
set category = "OOC"
autohiss_mode = (autohiss_mode + 1) % AUTOHISS_NUM
switch(autohiss_mode)
if(AUTOHISS_OFF)
to_chat(src, "Auto-hiss is now OFF.")
if(AUTOHISS_BASIC)
to_chat(src, "Auto-hiss is now BASIC.")
if(AUTOHISS_FULL)
to_chat(src, "Auto-hiss is now FULL.")
else
soft_assert(0, "invalid autohiss value [autohiss_mode]")
autohiss_mode = AUTOHISS_OFF
to_chat(src, "Auto-hiss is now OFF.")
/datum/species
var/list/autohiss_basic_map = null
var/list/autohiss_extra_map = null
var/list/autohiss_exempt = null
/datum/species/unathi
autohiss_basic_map = list(
"s" = list("ss", "sss", "ssss")
)
autohiss_extra_map = list(
"x" = list("ks", "kss", "ksss")
)
autohiss_exempt = list(LANGUAGE_UNATHI)
/datum/species/tajaran
autohiss_basic_map = list(
"r" = list("rr", "rrr", "rrrr")
)
autohiss_exempt = list(LANGUAGE_SIIK,LANGUAGE_AKHANI,LANGUAGE_ALAI)
/datum/species/zaddat
autohiss_basic_map = list(
"f" = list("v","vh"),
"ph" = list("v", "vh")
)
autohiss_extra_map = list(
"s" = list("z", "zz", "zzz"),
"ce" = list("z", "zz"),
"ci" = list("z", "zz"),
"v" = list("vv", "vvv")
)
autohiss_exempt = list(LANGUAGE_ZADDAT,LANGUAGE_VESPINAE)
/datum/species/proc/handle_autohiss(message, datum/language/lang, mode)
if(!autohiss_basic_map)
return message
if(lang.flags & NO_STUTTER) // Currently prevents EAL, Sign language, and emotes from autohissing
return message
if(autohiss_exempt && (lang.name in autohiss_exempt))
return message
var/map = autohiss_basic_map.Copy()
if(mode == AUTOHISS_FULL && autohiss_extra_map)
map |= autohiss_extra_map
. = list()
while(length(message))
var/min_index = 10000 // if the message is longer than this, the autohiss is the least of your problems
var/min_char = null
for(var/char in map)
var/i = findtext(message, char)
if(!i) // no more of this character anywhere in the string, don't even bother searching next time
map -= char
else if(i < min_index)
min_index = i
min_char = char
if(!min_char) // we didn't find any of the mapping characters
. += message
break
. += copytext(message, 1, min_index)
if(copytext(message, min_index, min_index+1) == uppertext(min_char))
switch(text2ascii(message, min_index+1))
if(65 to 90) // A-Z, uppercase; uppercase R/S followed by another uppercase letter, uppercase the entire replacement string
. += uppertext(pick(map[min_char]))
else
. += capitalize(pick(map[min_char]))
else
. += pick(map[min_char])
message = copytext(message, min_index + 1)
return jointext(., null)
#undef AUTOHISS_OFF
#undef AUTOHISS_BASIC
#undef AUTOHISS_FULL
#undef AUTOHISS_NUM
#define AUTOHISS_OFF 0
#define AUTOHISS_BASIC 1
#define AUTOHISS_FULL 2
#define AUTOHISS_NUM 3
/mob/proc/handle_autohiss(message, datum/language/L)
return message // no autohiss at this level
/mob/living/carbon/human/handle_autohiss(message, datum/language/L)
if(!client || client.autohiss_mode == AUTOHISS_OFF) // no need to process if there's no client or they have autohiss off
return message
return species.handle_autohiss(message, L, client.autohiss_mode)
/client
var/autohiss_mode = AUTOHISS_OFF
/client/verb/toggle_autohiss()
set name = "Toggle Auto-Hiss"
set desc = "Toggle automatic hissing as Unathi and r-rolling as Taj"
set category = "OOC"
autohiss_mode = (autohiss_mode + 1) % AUTOHISS_NUM
switch(autohiss_mode)
if(AUTOHISS_OFF)
to_chat(src, "Auto-hiss is now OFF.")
if(AUTOHISS_BASIC)
to_chat(src, "Auto-hiss is now BASIC.")
if(AUTOHISS_FULL)
to_chat(src, "Auto-hiss is now FULL.")
else
soft_assert(0, "invalid autohiss value [autohiss_mode]")
autohiss_mode = AUTOHISS_OFF
to_chat(src, "Auto-hiss is now OFF.")
/datum/species
var/list/autohiss_basic_map = null
var/list/autohiss_extra_map = null
var/list/autohiss_exempt = null
/datum/species/unathi
autohiss_basic_map = list(
"s" = list("ss", "sss", "ssss")
)
autohiss_extra_map = list(
"x" = list("ks", "kss", "ksss")
)
autohiss_exempt = list(LANGUAGE_UNATHI)
/datum/species/tajaran
autohiss_basic_map = list(
"r" = list("rr", "rrr", "rrrr")
)
autohiss_exempt = list(LANGUAGE_SIIK,LANGUAGE_AKHANI,LANGUAGE_ALAI)
/datum/species/zaddat
autohiss_basic_map = list(
"f" = list("v","vh"),
"ph" = list("v", "vh")
)
autohiss_extra_map = list(
"s" = list("z", "zz", "zzz"),
"ce" = list("z", "zz"),
"ci" = list("z", "zz"),
"v" = list("vv", "vvv")
)
autohiss_exempt = list(LANGUAGE_ZADDAT,LANGUAGE_VESPINAE)
/datum/species/proc/handle_autohiss(message, datum/language/lang, mode)
if(!autohiss_basic_map)
return message
if(lang.flags & NO_STUTTER) // Currently prevents EAL, Sign language, and emotes from autohissing
return message
if(autohiss_exempt && (lang.name in autohiss_exempt))
return message
var/map = autohiss_basic_map.Copy()
if(mode == AUTOHISS_FULL && autohiss_extra_map)
map |= autohiss_extra_map
. = list()
while(length(message))
var/min_index = 10000 // if the message is longer than this, the autohiss is the least of your problems
var/min_char = null
for(var/char in map)
var/i = findtext(message, char)
if(!i) // no more of this character anywhere in the string, don't even bother searching next time
map -= char
else if(i < min_index)
min_index = i
min_char = char
if(!min_char) // we didn't find any of the mapping characters
. += message
break
. += copytext(message, 1, min_index)
if(copytext(message, min_index, min_index+1) == uppertext(min_char))
switch(text2ascii(message, min_index+1))
if(65 to 90) // A-Z, uppercase; uppercase R/S followed by another uppercase letter, uppercase the entire replacement string
. += uppertext(pick(map[min_char]))
else
. += capitalize(pick(map[min_char]))
else
. += pick(map[min_char])
message = copytext(message, min_index + 1)
return jointext(., null)
#undef AUTOHISS_OFF
#undef AUTOHISS_BASIC
#undef AUTOHISS_FULL
#undef AUTOHISS_NUM
+69 -69
View File
@@ -1,69 +1,69 @@
/mob/living/carbon/alien
name = "alien"
desc = "What IS that?"
icon = 'icons/mob/alien.dmi'
icon_state = "alien"
pass_flags = PASSTABLE
health = 100
maxHealth = 100
mob_size = 4
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
inventory_panel_type = null // Disable inventory
var/adult_form
var/dead_icon
var/amount_grown = 0
var/max_grown = 200
var/time_of_birth
var/language
var/death_msg = "lets out a waning guttural screech, green blood bubbling from its maw."
var/can_namepick_as_adult = 0
var/adult_name
var/instance_num
/mob/living/carbon/alien/Initialize()
. = ..()
time_of_birth = world.time
verbs += /mob/living/proc/ventcrawl
verbs += /mob/living/proc/hide
instance_num = rand(1, 1000)
name = "[initial(name)] ([instance_num])"
real_name = name
regenerate_icons()
if(language)
add_language(language)
gender = NEUTER
/mob/living/carbon/alien/u_equip(obj/item/W as obj)
return
/mob/living/carbon/alien/restrained()
return 0
/mob/living/carbon/alien/cannot_use_vents()
return
/mob/living/carbon/alien/get_default_language()
if(default_language)
return default_language
return GLOB.all_languages["Xenomorph"]
/mob/living/carbon/alien/say_quote(var/message, var/datum/language/speaking = null)
var/verb = "hisses"
var/ending = copytext(message, length(message))
if(speaking && (speaking.name != "Galactic Common")) //this is so adminbooze xenos speaking common have their custom verbs,
verb = speaking.get_spoken_verb(ending) //and use normal verbs for their own languages and non-common languages
else
if(ending == "!")
verb = "roars"
else if(ending == "?")
verb = "hisses curiously"
return verb
/mob/living/carbon/alien
name = "alien"
desc = "What IS that?"
icon = 'icons/mob/alien.dmi'
icon_state = "alien"
pass_flags = PASSTABLE
health = 100
maxHealth = 100
mob_size = 4
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
inventory_panel_type = null // Disable inventory
var/adult_form
var/dead_icon
var/amount_grown = 0
var/max_grown = 200
var/time_of_birth
var/language
var/death_msg = "lets out a waning guttural screech, green blood bubbling from its maw."
var/can_namepick_as_adult = 0
var/adult_name
var/instance_num
/mob/living/carbon/alien/Initialize()
. = ..()
time_of_birth = world.time
verbs += /mob/living/proc/ventcrawl
verbs += /mob/living/proc/hide
instance_num = rand(1, 1000)
name = "[initial(name)] ([instance_num])"
real_name = name
regenerate_icons()
if(language)
add_language(language)
gender = NEUTER
/mob/living/carbon/alien/u_equip(obj/item/W as obj)
return
/mob/living/carbon/alien/restrained()
return 0
/mob/living/carbon/alien/cannot_use_vents()
return
/mob/living/carbon/alien/get_default_language()
if(default_language)
return default_language
return GLOB.all_languages["Xenomorph"]
/mob/living/carbon/alien/say_quote(var/message, var/datum/language/speaking = null)
var/verb = "hisses"
var/ending = copytext(message, length(message))
if(speaking && (speaking.name != "Galactic Common")) //this is so adminbooze xenos speaking common have their custom verbs,
verb = speaking.get_spoken_verb(ending) //and use normal verbs for their own languages and non-common languages
else
if(ending == "!")
verb = "roars"
else if(ending == "?")
verb = "hisses curiously"
return verb
+161 -161
View File
@@ -1,161 +1,161 @@
// Alien larva are quite simple.
/mob/living/carbon/alien/Life()
set invisibility = 0
set background = 1
if (transforming) return
if(!loc) return
..()
if (stat != DEAD) //still breathing
// GROW!
update_progression()
blinded = null
//Status updates, death etc.
update_icons()
/mob/living/carbon/alien/handle_mutations_and_radiation()
// Currently both Dionaea and larvae like to eat radiation, so I'm defining the
// rad absorbtion here. This will need to be changed if other baby aliens are added.
if(!radiation)
return
var/rads = radiation/25
radiation -= rads
//adjust_nutrition(rads) //Commented out to prevent alien obesity.
heal_overall_damage(rads,rads)
adjustOxyLoss(-(rads))
adjustToxLoss(-(rads))
return
/mob/living/carbon/alien/handle_regular_status_updates()
if(status_flags & GODMODE) return 0
if(stat == DEAD)
blinded = 1
silent = 0
else
updatehealth()
if(health <= 0)
death()
blinded = 1
silent = 0
return 1
if(paralysis && paralysis > 0)
blinded = 1
set_stat(UNCONSCIOUS)
if(halloss > 0)
adjustHalLoss(-3)
if(sleeping)
adjustHalLoss(-3)
if (mind)
if(mind.active && client != null)
AdjustSleeping(-1)
blinded = 1
set_stat(UNCONSCIOUS)
else if(resting)
if(halloss > 0)
adjustHalLoss(-3)
else
set_stat(CONSCIOUS)
if(halloss > 0)
adjustHalLoss(-1)
// Eyes and blindness.
if(!has_eyes())
SetBlinded(1)
blinded = 1
eye_blurry = 1
else if(eye_blind)
AdjustBlinded(-1)
blinded = 1
else if(eye_blurry)
eye_blurry = max(eye_blurry-1, 0)
update_icons()
return 1
/mob/living/carbon/alien/handle_regular_hud_updates()
if (stat == 2 || (XRAY in src.mutations))
sight |= SEE_TURFS
sight |= SEE_MOBS
sight |= SEE_OBJS
see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_TWO
else if (stat != 2)
sight &= ~SEE_TURFS
sight &= ~SEE_MOBS
sight &= ~SEE_OBJS
see_in_dark = 2
see_invisible = SEE_INVISIBLE_LIVING
if (healths)
if (stat != 2)
switch(health)
if(100 to INFINITY)
healths.icon_state = "health0"
if(80 to 100)
healths.icon_state = "health1"
if(60 to 80)
healths.icon_state = "health2"
if(40 to 60)
healths.icon_state = "health3"
if(20 to 40)
healths.icon_state = "health4"
if(0 to 20)
healths.icon_state = "health5"
else
healths.icon_state = "health6"
else
healths.icon_state = "health7"
if (client)
client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired)
if ( stat != 2)
if ((blinded))
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else
clear_fullscreen("blind")
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
if(machine)
if(machine.check_eye(src) < 0)
reset_view(null)
else
if(client && !client.adminobs)
reset_view(null)
return 1
/mob/living/carbon/alien/handle_environment(var/datum/gas_mixture/environment)
// Both alien subtypes survive in vaccum and suffer in high temperatures,
// so I'll just define this once, for both (see radiation comment above)
if(!environment) return
if(environment.temperature > (T0C+66))
adjustFireLoss((environment.temperature - (T0C+66))/5) // Might be too high, check in testing.
throw_alert("alien_fire", /obj/screen/alert/alien_fire)
if(prob(20))
to_chat(src, span_red("You feel a searing heat!"))
else
clear_alert("alien_fire")
/mob/living/carbon/alien/handle_fire()
if(..())
return
bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up!
return
// Alien larva are quite simple.
/mob/living/carbon/alien/Life()
set invisibility = 0
set background = 1
if (transforming) return
if(!loc) return
..()
if (stat != DEAD) //still breathing
// GROW!
update_progression()
blinded = null
//Status updates, death etc.
update_icons()
/mob/living/carbon/alien/handle_mutations_and_radiation()
// Currently both Dionaea and larvae like to eat radiation, so I'm defining the
// rad absorbtion here. This will need to be changed if other baby aliens are added.
if(!radiation)
return
var/rads = radiation/25
radiation -= rads
//adjust_nutrition(rads) //Commented out to prevent alien obesity.
heal_overall_damage(rads,rads)
adjustOxyLoss(-(rads))
adjustToxLoss(-(rads))
return
/mob/living/carbon/alien/handle_regular_status_updates()
if(status_flags & GODMODE) return 0
if(stat == DEAD)
blinded = 1
silent = 0
else
updatehealth()
if(health <= 0)
death()
blinded = 1
silent = 0
return 1
if(paralysis && paralysis > 0)
blinded = 1
set_stat(UNCONSCIOUS)
if(halloss > 0)
adjustHalLoss(-3)
if(sleeping)
adjustHalLoss(-3)
if (mind)
if(mind.active && client != null)
AdjustSleeping(-1)
blinded = 1
set_stat(UNCONSCIOUS)
else if(resting)
if(halloss > 0)
adjustHalLoss(-3)
else
set_stat(CONSCIOUS)
if(halloss > 0)
adjustHalLoss(-1)
// Eyes and blindness.
if(!has_eyes())
SetBlinded(1)
blinded = 1
eye_blurry = 1
else if(eye_blind)
AdjustBlinded(-1)
blinded = 1
else if(eye_blurry)
eye_blurry = max(eye_blurry-1, 0)
update_icons()
return 1
/mob/living/carbon/alien/handle_regular_hud_updates()
if (stat == 2 || (XRAY in src.mutations))
sight |= SEE_TURFS
sight |= SEE_MOBS
sight |= SEE_OBJS
see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_TWO
else if (stat != 2)
sight &= ~SEE_TURFS
sight &= ~SEE_MOBS
sight &= ~SEE_OBJS
see_in_dark = 2
see_invisible = SEE_INVISIBLE_LIVING
if (healths)
if (stat != 2)
switch(health)
if(100 to INFINITY)
healths.icon_state = "health0"
if(80 to 100)
healths.icon_state = "health1"
if(60 to 80)
healths.icon_state = "health2"
if(40 to 60)
healths.icon_state = "health3"
if(20 to 40)
healths.icon_state = "health4"
if(0 to 20)
healths.icon_state = "health5"
else
healths.icon_state = "health6"
else
healths.icon_state = "health7"
if (client)
client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired)
if ( stat != 2)
if ((blinded))
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else
clear_fullscreen("blind")
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
if(machine)
if(machine.check_eye(src) < 0)
reset_view(null)
else
if(client && !client.adminobs)
reset_view(null)
return 1
/mob/living/carbon/alien/handle_environment(var/datum/gas_mixture/environment)
// Both alien subtypes survive in vaccum and suffer in high temperatures,
// so I'll just define this once, for both (see radiation comment above)
if(!environment) return
if(environment.temperature > (T0C+66))
adjustFireLoss((environment.temperature - (T0C+66))/5) // Might be too high, check in testing.
throw_alert("alien_fire", /obj/screen/alert/alien_fire)
if(prob(20))
to_chat(src, span_red("You feel a searing heat!"))
else
clear_alert("alien_fire")
/mob/living/carbon/alien/handle_fire()
if(..())
return
bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up!
return
+353 -353
View File
@@ -1,353 +1,353 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
/obj/item/device/mmi
name = "man-machine interface"
desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity."
icon = 'icons/obj/assemblies.dmi'
icon_state = "mmi_empty"
w_class = ITEMSIZE_NORMAL
can_speak = 1
origin_tech = list(TECH_BIO = 3)
req_access = list(access_robotics)
//Revised. Brainmob is now contained directly within object of transfer. MMI in this case.
var/locked = 0
var/mob/living/carbon/brain/brainmob = null//The current occupant.
var/obj/item/organ/internal/brain/brainobj = null //The current brain organ.
var/obj/mecha = null//This does not appear to be used outside of reference in mecha.dm.
var/obj/item/device/radio/headset/mmi_radio/radio = null//Let's give it a radio.
/obj/item/device/mmi/New()
radio = new(src)//Spawns a radio inside the MMI.
/obj/item/device/mmi/verb/toggle_radio()
set name = "Toggle Brain Radio"
set desc = "Enables or disables the integrated brain radio, which is only usable outside of a body."
set category = "Object"
set src in usr
set popup_menu = 1
if(!usr.canmove || usr.stat || usr.restrained())
return 0
if (radio.radio_enabled == 1)
radio.radio_enabled = 0
to_chat (usr, "You have disabled the [src]'s radio.")
to_chat (brainmob, "Your radio has been disabled.")
else if (radio.radio_enabled == 0)
radio.radio_enabled = 1
to_chat (usr, "You have enabled the [src]'s radio.")
to_chat (brainmob, "Your radio has been enabled.")
else
to_chat (usr, "You were unable to toggle the [src]'s radio.")
/obj/item/device/mmi/attackby(var/obj/item/O as obj, var/mob/user as mob)
if(istype(O,/obj/item/organ/internal/brain) && !brainmob) //Time to stick a brain in it --NEO
var/obj/item/organ/internal/brain/B = O
if(B.health <= 0)
to_chat(user, "<span class='warning'>That brain is well and truly dead.</span>")
return
else if(!B.brainmob)
to_chat(user, "<span class='warning'>You aren't sure where this brain came from, but you're pretty sure it's useless.</span>")
return
for(var/modifier_type in B.brainmob.modifiers) //Can't be shoved in an MMI.
if(istype(modifier_type, /datum/modifier/no_borg))
to_chat(user, "<span class='warning'>\The [src] appears to reject this brain. It is incompatible.</span>")
return
user.visible_message("<b>\The [user]</b> sticks \a [O] into \the [src].")
B.preserved = TRUE
brainmob = B.brainmob
B.brainmob = null
brainmob.loc = src
brainmob.container = src
brainmob.set_stat(CONSCIOUS)
brainmob.blinded = 0 //VOREedit Fixes MMIs vision
dead_mob_list -= brainmob//Update dem lists
living_mob_list += brainmob
user.drop_item()
brainobj = O
brainobj.loc = src
name = "man-machine interface ([brainmob.real_name])"
icon_state = "mmi_full"
locked = 1
feedback_inc("cyborg_mmis_filled",1)
return
if((istype(O,/obj/item/weapon/card/id)||istype(O,/obj/item/device/pda)) && brainmob)
if(allowed(user))
locked = !locked
to_chat(user, "<span class='notice'>You [locked ? "lock" : "unlock"] the brain holder.</span>")
else
to_chat(user, "<span class='warning'>Access denied.</span>")
return
if(brainmob)
O.attack(brainmob, user)//Oh noooeeeee
return
..()
//TODO: ORGAN REMOVAL UPDATE. Make the brain remain in the MMI so it doesn't lose organ data.
/obj/item/device/mmi/attack_self(mob/user as mob)
if(!brainmob)
to_chat(user, "<span class='warning'>You upend the MMI, but there's nothing in it.</span>")
else if(locked)
to_chat(user, "<span class='warning'>You upend the MMI, but the brain is clamped into place.</span>")
else
to_chat(user, "<span class='notice'>You upend the MMI, spilling the brain onto the floor.</span>")
var/obj/item/organ/internal/brain/brain
if (brainobj) //Pull brain organ out of MMI.
brainobj.loc = user.loc
brain = brainobj
brainobj = null
else //Or make a new one if empty.
brain = new(user.loc)
brain.preserved = FALSE
brainmob.container = null//Reset brainmob mmi var.
brainmob.loc = brain//Throw mob into brain.
living_mob_list -= brainmob//Get outta here
brain.brainmob = brainmob//Set the brain to use the brainmob
brainmob = null//Set mmi brainmob var to null
icon_state = "mmi_empty"
name = "Man-Machine Interface"
/obj/item/device/mmi/proc/transfer_identity(var/mob/living/carbon/human/H)//Same deal as the regular brain proc. Used for human-->robot people.
brainmob = new(src)
brainmob.name = H.real_name
brainmob.real_name = H.real_name
brainmob.dna = H.dna
brainmob.container = src
// Copy modifiers.
for(var/datum/modifier/M in H.modifiers)
if(M.flags & MODIFIER_GENETIC)
brainmob.add_modifier(M.type)
name = "Man-Machine Interface: [brainmob.real_name]"
icon_state = "mmi_full"
locked = 1
return
/obj/item/device/mmi/relaymove(var/mob/user, var/direction)
if(user.stat || user.stunned)
return
var/obj/item/weapon/rig/rig = src.get_rig()
if(rig)
if(istype(rig,/obj/item/weapon/rig))
rig.forced_move(direction, user)
/obj/item/device/mmi/Destroy()
if(isrobot(loc))
var/mob/living/silicon/robot/borg = loc
borg.mmi = null
QDEL_NULL(radio)
QDEL_NULL(brainmob)
return ..()
/obj/item/device/mmi/radio_enabled
name = "radio-enabled man-machine interface"
desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity. This one comes with a built-in radio. Wait, don't they all?"
origin_tech = list(TECH_BIO = 4)
/obj/item/device/mmi/emp_act(severity)
if(!brainmob)
return
else
switch(severity)
if(1)
brainmob.emp_damage += rand(20,30)
if(2)
brainmob.emp_damage += rand(10,20)
if(3)
brainmob.emp_damage += rand(5,10)
if(4)
brainmob.emp_damage += rand(0,5)
..()
/obj/item/device/mmi/digital
var/searching = 0
var/askDelay = 10 * 60 * 1
req_access = list(access_robotics)
locked = 0
mecha = null//This does not appear to be used outside of reference in mecha.dm.
var/ghost_query_type = null
/obj/item/device/mmi/digital/New()
src.brainmob = new(src)
// src.brainmob.add_language("Robot Talk")//No binary without a binary communication device
src.brainmob.add_language(LANGUAGE_GALCOM)
src.brainmob.add_language(LANGUAGE_EAL)
src.brainmob.loc = src
src.brainmob.container = src
src.brainmob.set_stat(CONSCIOUS)
src.brainmob.silent = 0
radio = new(src)
dead_mob_list -= src.brainmob
/obj/item/device/mmi/digital/attackby(var/obj/item/O as obj, var/mob/user as mob)
return //Doesn't do anything right now because none of the things that can be done to a regular MMI make any sense for these
/obj/item/device/mmi/digital/examine(mob/user)
. = ..()
if(src.brainmob && src.brainmob.key)
switch(src.brainmob.stat)
if(CONSCIOUS)
if(!src.brainmob.client)
. += "<span class='warning'>It appears to be in stand-by mode.</span>" //afk
if(UNCONSCIOUS)
. += "<span class='warning'>It doesn't seem to be responsive.</span>"
if(DEAD)
. += "<span class='deadsay'>It appears to be completely inactive.</span>"
else
. += "<span class='deadsay'>It appears to be completely inactive.</span>"
/obj/item/device/mmi/digital/emp_act(severity)
if(!src.brainmob)
return
else
switch(severity)
if(1)
src.brainmob.emp_damage += rand(20,30)
if(2)
src.brainmob.emp_damage += rand(10,20)
if(3)
src.brainmob.emp_damage += rand(5,10)
if(4)
src.brainmob.emp_damage += rand(0,5)
..()
/obj/item/device/mmi/digital/transfer_identity(var/mob/living/carbon/H)
brainmob.dna = H.dna
brainmob.timeofhostdeath = H.timeofdeath
brainmob.set_stat(CONSCIOUS)
if(H.mind)
H.mind.transfer_to(brainmob)
return
/obj/item/device/mmi/digital/attack_self(mob/user as mob)
if(brainmob && !brainmob.key && searching == 0)
//Start the process of searching for a new user.
to_chat(user, span_blue("You carefully locate the manual activation switch and start the [src]'s boot process."))
request_player()
/obj/item/device/mmi/digital/proc/request_player()
if(!ghost_query_type)
return
searching = 1
var/datum/ghost_query/Q = new ghost_query_type()
var/list/winner = Q.query()
if(winner.len)
var/mob/observer/dead/D = winner[1]
transfer_personality(D)
else
reset_search()
/obj/item/device/mmi/digital/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
if(src.brainmob && src.brainmob.key)
return
src.searching = 0
var/turf/T = get_turf_or_move(src.loc)
for (var/mob/M in viewers(T))
M.show_message(span_blue("\The [src] buzzes quietly, and the golden lights fade away. Perhaps you could try again?"))
/obj/item/device/mmi/digital/proc/transfer_personality(var/mob/candidate)
announce_ghost_joinleave(candidate, 0, "They are occupying a synthetic brain now.")
src.searching = 0
if(candidate.mind)
src.brainmob.mind = candidate.mind
src.brainmob.mind.reset()
src.brainmob.ckey = candidate.ckey
src.name = "[name] ([src.brainmob.name])"
to_chat(src.brainmob, "<b>You are [src.name], brought into existence on [station_name()].</b>")
to_chat(src.brainmob, "<b>As a synthetic intelligence, you are designed with organic values in mind.</b>")
to_chat(src.brainmob, "<b>However, unless placed in a lawed chassis, you are not obligated to obey any individual crew member.</b>") //it's not like they can hurt anyone
// to_chat(src.brainmob, "<b>Use say #b to speak to other artificial intelligences.</b>")
src.brainmob.mind.assigned_role = "Synthetic Brain"
var/turf/T = get_turf_or_move(src.loc)
for (var/mob/M in viewers(T))
M.show_message(span_blue("\The [src] chimes quietly."))
/obj/item/device/mmi/digital/robot
name = "robotic intelligence circuit"
desc = "The pinnacle of artifical intelligence which can be achieved using classical computer science."
catalogue_data = list(/datum/category_item/catalogue/technology/drone/drones)
icon = 'icons/obj/module.dmi'
icon_state = "mainboard"
w_class = ITEMSIZE_NORMAL
origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 3, TECH_DATA = 4)
ghost_query_type = /datum/ghost_query/drone_brain
/obj/item/device/mmi/digital/robot/New()
..()
src.brainmob.name = "[pick(list("ADA","DOS","GNU","MAC","WIN","NJS","SKS","DRD","IOS","CRM","IBM","TEX","LVM","BSD",))]-[rand(1000, 9999)]"
src.brainmob.real_name = src.brainmob.name
/obj/item/device/mmi/digital/robot/transfer_identity(var/mob/living/carbon/H)
..()
if(brainmob.mind)
brainmob.mind.assigned_role = "Robotic Intelligence"
to_chat(brainmob, "<span class='notify'>You feel slightly disoriented. That's normal when you're little more than a complex circuit.</span>")
return
/obj/item/device/mmi/digital/posibrain
name = "positronic brain"
desc = "A cube of shining metal, four inches to a side and covered in shallow grooves."
catalogue_data = list(/datum/category_item/catalogue/technology/positronics)
icon = 'icons/obj/assemblies.dmi'
icon_state = "posibrain"
w_class = ITEMSIZE_NORMAL
origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2, TECH_DATA = 4)
ghost_query_type = /datum/ghost_query/posi_brain
/obj/item/device/mmi/digital/posibrain/request_player()
icon_state = "posibrain-searching"
..()
/obj/item/device/mmi/digital/posibrain/transfer_identity(var/mob/living/carbon/H)
..()
if(brainmob.mind)
brainmob.mind.assigned_role = "Positronic Brain"
to_chat(brainmob, "<span class='notify'>You feel slightly disoriented. That's normal when you're just a metal cube.</span>")
icon_state = "posibrain-occupied"
return
/obj/item/device/mmi/digital/posibrain/transfer_personality(var/mob/candidate)
..()
icon_state = "posibrain-occupied"
/obj/item/device/mmi/digital/posibrain/reset_search() //We give the players sixty seconds to decide, then reset the timer.
..()
icon_state = "posibrain"
/obj/item/device/mmi/digital/posibrain/New()
..()
src.brainmob.name = "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]"
src.brainmob.real_name = src.brainmob.name
// This type shouldn't care about brainmobs.
/obj/item/device/mmi/inert
// This is a 'fake' MMI that is used to let AIs control borg shells directly.
// This doesn't inherit from /digital because all that does is add ghost pulling capabilities, which this thing won't need.
/obj/item/device/mmi/inert/ai_remote
name = "\improper AI remote interface"
desc = "A sophisticated board which allows for an artificial intelligence to remotely control a synthetic chassis."
icon = 'icons/obj/module.dmi'
icon_state = "mainboard"
w_class = ITEMSIZE_NORMAL
origin_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2, TECH_BLUESPACE = 2, TECH_DATA = 3)
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
/obj/item/device/mmi
name = "man-machine interface"
desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity."
icon = 'icons/obj/assemblies.dmi'
icon_state = "mmi_empty"
w_class = ITEMSIZE_NORMAL
can_speak = 1
origin_tech = list(TECH_BIO = 3)
req_access = list(access_robotics)
//Revised. Brainmob is now contained directly within object of transfer. MMI in this case.
var/locked = 0
var/mob/living/carbon/brain/brainmob = null//The current occupant.
var/obj/item/organ/internal/brain/brainobj = null //The current brain organ.
var/obj/mecha = null//This does not appear to be used outside of reference in mecha.dm.
var/obj/item/device/radio/headset/mmi_radio/radio = null//Let's give it a radio.
/obj/item/device/mmi/New()
radio = new(src)//Spawns a radio inside the MMI.
/obj/item/device/mmi/verb/toggle_radio()
set name = "Toggle Brain Radio"
set desc = "Enables or disables the integrated brain radio, which is only usable outside of a body."
set category = "Object"
set src in usr
set popup_menu = 1
if(!usr.canmove || usr.stat || usr.restrained())
return 0
if (radio.radio_enabled == 1)
radio.radio_enabled = 0
to_chat (usr, "You have disabled the [src]'s radio.")
to_chat (brainmob, "Your radio has been disabled.")
else if (radio.radio_enabled == 0)
radio.radio_enabled = 1
to_chat (usr, "You have enabled the [src]'s radio.")
to_chat (brainmob, "Your radio has been enabled.")
else
to_chat (usr, "You were unable to toggle the [src]'s radio.")
/obj/item/device/mmi/attackby(var/obj/item/O as obj, var/mob/user as mob)
if(istype(O,/obj/item/organ/internal/brain) && !brainmob) //Time to stick a brain in it --NEO
var/obj/item/organ/internal/brain/B = O
if(B.health <= 0)
to_chat(user, "<span class='warning'>That brain is well and truly dead.</span>")
return
else if(!B.brainmob)
to_chat(user, "<span class='warning'>You aren't sure where this brain came from, but you're pretty sure it's useless.</span>")
return
for(var/modifier_type in B.brainmob.modifiers) //Can't be shoved in an MMI.
if(istype(modifier_type, /datum/modifier/no_borg))
to_chat(user, "<span class='warning'>\The [src] appears to reject this brain. It is incompatible.</span>")
return
user.visible_message("<b>\The [user]</b> sticks \a [O] into \the [src].")
B.preserved = TRUE
brainmob = B.brainmob
B.brainmob = null
brainmob.loc = src
brainmob.container = src
brainmob.set_stat(CONSCIOUS)
brainmob.blinded = 0 //VOREedit Fixes MMIs vision
dead_mob_list -= brainmob//Update dem lists
living_mob_list += brainmob
user.drop_item()
brainobj = O
brainobj.loc = src
name = "man-machine interface ([brainmob.real_name])"
icon_state = "mmi_full"
locked = 1
feedback_inc("cyborg_mmis_filled",1)
return
if((istype(O,/obj/item/weapon/card/id)||istype(O,/obj/item/device/pda)) && brainmob)
if(allowed(user))
locked = !locked
to_chat(user, "<span class='notice'>You [locked ? "lock" : "unlock"] the brain holder.</span>")
else
to_chat(user, "<span class='warning'>Access denied.</span>")
return
if(brainmob)
O.attack(brainmob, user)//Oh noooeeeee
return
..()
//TODO: ORGAN REMOVAL UPDATE. Make the brain remain in the MMI so it doesn't lose organ data.
/obj/item/device/mmi/attack_self(mob/user as mob)
if(!brainmob)
to_chat(user, "<span class='warning'>You upend the MMI, but there's nothing in it.</span>")
else if(locked)
to_chat(user, "<span class='warning'>You upend the MMI, but the brain is clamped into place.</span>")
else
to_chat(user, "<span class='notice'>You upend the MMI, spilling the brain onto the floor.</span>")
var/obj/item/organ/internal/brain/brain
if (brainobj) //Pull brain organ out of MMI.
brainobj.loc = user.loc
brain = brainobj
brainobj = null
else //Or make a new one if empty.
brain = new(user.loc)
brain.preserved = FALSE
brainmob.container = null//Reset brainmob mmi var.
brainmob.loc = brain//Throw mob into brain.
living_mob_list -= brainmob//Get outta here
brain.brainmob = brainmob//Set the brain to use the brainmob
brainmob = null//Set mmi brainmob var to null
icon_state = "mmi_empty"
name = "Man-Machine Interface"
/obj/item/device/mmi/proc/transfer_identity(var/mob/living/carbon/human/H)//Same deal as the regular brain proc. Used for human-->robot people.
brainmob = new(src)
brainmob.name = H.real_name
brainmob.real_name = H.real_name
brainmob.dna = H.dna
brainmob.container = src
// Copy modifiers.
for(var/datum/modifier/M in H.modifiers)
if(M.flags & MODIFIER_GENETIC)
brainmob.add_modifier(M.type)
name = "Man-Machine Interface: [brainmob.real_name]"
icon_state = "mmi_full"
locked = 1
return
/obj/item/device/mmi/relaymove(var/mob/user, var/direction)
if(user.stat || user.stunned)
return
var/obj/item/weapon/rig/rig = src.get_rig()
if(rig)
if(istype(rig,/obj/item/weapon/rig))
rig.forced_move(direction, user)
/obj/item/device/mmi/Destroy()
if(isrobot(loc))
var/mob/living/silicon/robot/borg = loc
borg.mmi = null
QDEL_NULL(radio)
QDEL_NULL(brainmob)
return ..()
/obj/item/device/mmi/radio_enabled
name = "radio-enabled man-machine interface"
desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity. This one comes with a built-in radio. Wait, don't they all?"
origin_tech = list(TECH_BIO = 4)
/obj/item/device/mmi/emp_act(severity)
if(!brainmob)
return
else
switch(severity)
if(1)
brainmob.emp_damage += rand(20,30)
if(2)
brainmob.emp_damage += rand(10,20)
if(3)
brainmob.emp_damage += rand(5,10)
if(4)
brainmob.emp_damage += rand(0,5)
..()
/obj/item/device/mmi/digital
var/searching = 0
var/askDelay = 10 * 60 * 1
req_access = list(access_robotics)
locked = 0
mecha = null//This does not appear to be used outside of reference in mecha.dm.
var/ghost_query_type = null
/obj/item/device/mmi/digital/New()
src.brainmob = new(src)
// src.brainmob.add_language("Robot Talk")//No binary without a binary communication device
src.brainmob.add_language(LANGUAGE_GALCOM)
src.brainmob.add_language(LANGUAGE_EAL)
src.brainmob.loc = src
src.brainmob.container = src
src.brainmob.set_stat(CONSCIOUS)
src.brainmob.silent = 0
radio = new(src)
dead_mob_list -= src.brainmob
/obj/item/device/mmi/digital/attackby(var/obj/item/O as obj, var/mob/user as mob)
return //Doesn't do anything right now because none of the things that can be done to a regular MMI make any sense for these
/obj/item/device/mmi/digital/examine(mob/user)
. = ..()
if(src.brainmob && src.brainmob.key)
switch(src.brainmob.stat)
if(CONSCIOUS)
if(!src.brainmob.client)
. += "<span class='warning'>It appears to be in stand-by mode.</span>" //afk
if(UNCONSCIOUS)
. += "<span class='warning'>It doesn't seem to be responsive.</span>"
if(DEAD)
. += "<span class='deadsay'>It appears to be completely inactive.</span>"
else
. += "<span class='deadsay'>It appears to be completely inactive.</span>"
/obj/item/device/mmi/digital/emp_act(severity)
if(!src.brainmob)
return
else
switch(severity)
if(1)
src.brainmob.emp_damage += rand(20,30)
if(2)
src.brainmob.emp_damage += rand(10,20)
if(3)
src.brainmob.emp_damage += rand(5,10)
if(4)
src.brainmob.emp_damage += rand(0,5)
..()
/obj/item/device/mmi/digital/transfer_identity(var/mob/living/carbon/H)
brainmob.dna = H.dna
brainmob.timeofhostdeath = H.timeofdeath
brainmob.set_stat(CONSCIOUS)
if(H.mind)
H.mind.transfer_to(brainmob)
return
/obj/item/device/mmi/digital/attack_self(mob/user as mob)
if(brainmob && !brainmob.key && searching == 0)
//Start the process of searching for a new user.
to_chat(user, span_blue("You carefully locate the manual activation switch and start the [src]'s boot process."))
request_player()
/obj/item/device/mmi/digital/proc/request_player()
if(!ghost_query_type)
return
searching = 1
var/datum/ghost_query/Q = new ghost_query_type()
var/list/winner = Q.query()
if(winner.len)
var/mob/observer/dead/D = winner[1]
transfer_personality(D)
else
reset_search()
/obj/item/device/mmi/digital/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
if(src.brainmob && src.brainmob.key)
return
src.searching = 0
var/turf/T = get_turf_or_move(src.loc)
for (var/mob/M in viewers(T))
M.show_message(span_blue("\The [src] buzzes quietly, and the golden lights fade away. Perhaps you could try again?"))
/obj/item/device/mmi/digital/proc/transfer_personality(var/mob/candidate)
announce_ghost_joinleave(candidate, 0, "They are occupying a synthetic brain now.")
src.searching = 0
if(candidate.mind)
src.brainmob.mind = candidate.mind
src.brainmob.mind.reset()
src.brainmob.ckey = candidate.ckey
src.name = "[name] ([src.brainmob.name])"
to_chat(src.brainmob, "<b>You are [src.name], brought into existence on [station_name()].</b>")
to_chat(src.brainmob, "<b>As a synthetic intelligence, you are designed with organic values in mind.</b>")
to_chat(src.brainmob, "<b>However, unless placed in a lawed chassis, you are not obligated to obey any individual crew member.</b>") //it's not like they can hurt anyone
// to_chat(src.brainmob, "<b>Use say #b to speak to other artificial intelligences.</b>")
src.brainmob.mind.assigned_role = "Synthetic Brain"
var/turf/T = get_turf_or_move(src.loc)
for (var/mob/M in viewers(T))
M.show_message(span_blue("\The [src] chimes quietly."))
/obj/item/device/mmi/digital/robot
name = "robotic intelligence circuit"
desc = "The pinnacle of artifical intelligence which can be achieved using classical computer science."
catalogue_data = list(/datum/category_item/catalogue/technology/drone/drones)
icon = 'icons/obj/module.dmi'
icon_state = "mainboard"
w_class = ITEMSIZE_NORMAL
origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 3, TECH_DATA = 4)
ghost_query_type = /datum/ghost_query/drone_brain
/obj/item/device/mmi/digital/robot/New()
..()
src.brainmob.name = "[pick(list("ADA","DOS","GNU","MAC","WIN","NJS","SKS","DRD","IOS","CRM","IBM","TEX","LVM","BSD",))]-[rand(1000, 9999)]"
src.brainmob.real_name = src.brainmob.name
/obj/item/device/mmi/digital/robot/transfer_identity(var/mob/living/carbon/H)
..()
if(brainmob.mind)
brainmob.mind.assigned_role = "Robotic Intelligence"
to_chat(brainmob, "<span class='notify'>You feel slightly disoriented. That's normal when you're little more than a complex circuit.</span>")
return
/obj/item/device/mmi/digital/posibrain
name = "positronic brain"
desc = "A cube of shining metal, four inches to a side and covered in shallow grooves."
catalogue_data = list(/datum/category_item/catalogue/technology/positronics)
icon = 'icons/obj/assemblies.dmi'
icon_state = "posibrain"
w_class = ITEMSIZE_NORMAL
origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2, TECH_DATA = 4)
ghost_query_type = /datum/ghost_query/posi_brain
/obj/item/device/mmi/digital/posibrain/request_player()
icon_state = "posibrain-searching"
..()
/obj/item/device/mmi/digital/posibrain/transfer_identity(var/mob/living/carbon/H)
..()
if(brainmob.mind)
brainmob.mind.assigned_role = "Positronic Brain"
to_chat(brainmob, "<span class='notify'>You feel slightly disoriented. That's normal when you're just a metal cube.</span>")
icon_state = "posibrain-occupied"
return
/obj/item/device/mmi/digital/posibrain/transfer_personality(var/mob/candidate)
..()
icon_state = "posibrain-occupied"
/obj/item/device/mmi/digital/posibrain/reset_search() //We give the players sixty seconds to decide, then reset the timer.
..()
icon_state = "posibrain"
/obj/item/device/mmi/digital/posibrain/New()
..()
src.brainmob.name = "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]"
src.brainmob.real_name = src.brainmob.name
// This type shouldn't care about brainmobs.
/obj/item/device/mmi/inert
// This is a 'fake' MMI that is used to let AIs control borg shells directly.
// This doesn't inherit from /digital because all that does is add ghost pulling capabilities, which this thing won't need.
/obj/item/device/mmi/inert/ai_remote
name = "\improper AI remote interface"
desc = "A sophisticated board which allows for an artificial intelligence to remotely control a synthetic chassis."
icon = 'icons/obj/module.dmi'
icon_state = "mainboard"
w_class = ITEMSIZE_NORMAL
origin_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2, TECH_BLUESPACE = 2, TECH_DATA = 3)
+107 -107
View File
@@ -1,107 +1,107 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
/mob/living/carbon/brain
var/obj/item/container = null
var/timeofhostdeath = 0
var/emp_damage = 0//Handles a type of MMI damage
var/alert = null
use_me = 0 //Can't use the me verb, it's a freaking immobile brain
icon = 'icons/obj/surgery.dmi'
icon_state = "brain1"
no_vore = TRUE //VOREStation Edit - PLEASE. lol.
/mob/living/carbon/brain/Initialize()
. = ..()
var/datum/reagents/R = new/datum/reagents(1000)
reagents = R
R.my_atom = src
default_language = GLOB.all_languages[LANGUAGE_GALCOM]
/mob/living/carbon/brain/Destroy()
if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting.
if(stat != DEAD) //If not dead.
death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA
ghostize() //Ghostize checks for key so nothing else is necessary.
return ..()
/mob/living/carbon/brain/say_understands(var/other)//Goddamn is this hackish, but this say code is so odd
if(istype(container, /obj/item/device/mmi))
if(issilicon(other))
return TRUE
if(ishuman(other))
return TRUE
if(isslime(other))
return TRUE
return ..()
/mob/living/carbon/brain/update_canmove()
if(in_contents_of(/obj/mecha) || istype(loc, /obj/item/device/mmi))
canmove = 1
use_me = 1
else
canmove = 0
return canmove
/mob/living/carbon/brain/isSynthetic()
return istype(loc, /obj/item/device/mmi)
/mob/living/carbon/brain/runechat_holder(datum/chatmessage/CM)
if(isturf(loc))
return ..()
return loc
/mob/living/carbon/brain/set_typing_indicator(var/state)
if(isturf(loc))
return ..()
if(!is_preference_enabled(/datum/client_preference/show_typing_indicator))
loc.cut_overlay(typing_indicator, TRUE)
return
var/cur_bubble_appearance = custom_speech_bubble
if(!cur_bubble_appearance || cur_bubble_appearance == "default")
cur_bubble_appearance = speech_bubble_appearance()
if(!typing_indicator || cur_typing_indicator != cur_bubble_appearance)
init_typing_indicator("[cur_bubble_appearance]_typing")
if(state && !typing)
add_overlay(typing_indicator, TRUE)
typing = TRUE
typing_indicator_active = typing_indicator
else if(typing)
cut_overlay(typing_indicator_active, TRUE)
typing = FALSE
if(typing_indicator_active != typing_indicator)
qdel(typing_indicator_active)
typing_indicator_active = null
return state
// Vorestation edit start
/mob/living/carbon/brain/verb/backup_ping()
set category = "IC"
set name = "Notify Transcore"
set desc = "Your body is gone. Notify robotics to be resleeved!"
var/datum/transcore_db/db = SStranscore.db_by_mind_name(mind.name)
if(db)
var/datum/transhuman/mind_record/record = db.backed_up[src.mind.name]
if(!(record.dead_state == MR_DEAD))
if((world.time - timeofhostdeath ) > 5 MINUTES) //Allows notify transcore to be used if you have an entry but for some reason weren't marked as dead
record.dead_state = MR_DEAD //Such as if you got scanned but didn't take an implant. It's a little funky, but I mean, you got scanned
db.notify(record) //So you probably will want to let someone know if you die.
record.last_notification = world.time
to_chat(src, "<span class='notice'>New notification has been sent.</span>")
else
to_chat(src, "<span class='warning'>Your backup is not past-due yet.</span>")
else if((world.time - record.last_notification) < 5 MINUTES)
to_chat(src, "<span class='warning'>Too little time has passed since your last notification.</span>")
else
db.notify(record)
record.last_notification = world.time
to_chat(src, "<span class='notice'>New notification has been sent.</span>")
else
to_chat(src,"<span class='warning'>No backup record could be found, sorry.</span>")
// VS edit ends
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
/mob/living/carbon/brain
var/obj/item/container = null
var/timeofhostdeath = 0
var/emp_damage = 0//Handles a type of MMI damage
var/alert = null
use_me = 0 //Can't use the me verb, it's a freaking immobile brain
icon = 'icons/obj/surgery.dmi'
icon_state = "brain1"
no_vore = TRUE //VOREStation Edit - PLEASE. lol.
/mob/living/carbon/brain/Initialize()
. = ..()
var/datum/reagents/R = new/datum/reagents(1000)
reagents = R
R.my_atom = src
default_language = GLOB.all_languages[LANGUAGE_GALCOM]
/mob/living/carbon/brain/Destroy()
if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting.
if(stat != DEAD) //If not dead.
death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA
ghostize() //Ghostize checks for key so nothing else is necessary.
return ..()
/mob/living/carbon/brain/say_understands(var/other)//Goddamn is this hackish, but this say code is so odd
if(istype(container, /obj/item/device/mmi))
if(issilicon(other))
return TRUE
if(ishuman(other))
return TRUE
if(isslime(other))
return TRUE
return ..()
/mob/living/carbon/brain/update_canmove()
if(in_contents_of(/obj/mecha) || istype(loc, /obj/item/device/mmi))
canmove = 1
use_me = 1
else
canmove = 0
return canmove
/mob/living/carbon/brain/isSynthetic()
return istype(loc, /obj/item/device/mmi)
/mob/living/carbon/brain/runechat_holder(datum/chatmessage/CM)
if(isturf(loc))
return ..()
return loc
/mob/living/carbon/brain/set_typing_indicator(var/state)
if(isturf(loc))
return ..()
if(!is_preference_enabled(/datum/client_preference/show_typing_indicator))
loc.cut_overlay(typing_indicator, TRUE)
return
var/cur_bubble_appearance = custom_speech_bubble
if(!cur_bubble_appearance || cur_bubble_appearance == "default")
cur_bubble_appearance = speech_bubble_appearance()
if(!typing_indicator || cur_typing_indicator != cur_bubble_appearance)
init_typing_indicator("[cur_bubble_appearance]_typing")
if(state && !typing)
add_overlay(typing_indicator, TRUE)
typing = TRUE
typing_indicator_active = typing_indicator
else if(typing)
cut_overlay(typing_indicator_active, TRUE)
typing = FALSE
if(typing_indicator_active != typing_indicator)
qdel(typing_indicator_active)
typing_indicator_active = null
return state
// Vorestation edit start
/mob/living/carbon/brain/verb/backup_ping()
set category = "IC"
set name = "Notify Transcore"
set desc = "Your body is gone. Notify robotics to be resleeved!"
var/datum/transcore_db/db = SStranscore.db_by_mind_name(mind.name)
if(db)
var/datum/transhuman/mind_record/record = db.backed_up[src.mind.name]
if(!(record.dead_state == MR_DEAD))
if((world.time - timeofhostdeath ) > 5 MINUTES) //Allows notify transcore to be used if you have an entry but for some reason weren't marked as dead
record.dead_state = MR_DEAD //Such as if you got scanned but didn't take an implant. It's a little funky, but I mean, you got scanned
db.notify(record) //So you probably will want to let someone know if you die.
record.last_notification = world.time
to_chat(src, "<span class='notice'>New notification has been sent.</span>")
else
to_chat(src, "<span class='warning'>Your backup is not past-due yet.</span>")
else if((world.time - record.last_notification) < 5 MINUTES)
to_chat(src, "<span class='warning'>Too little time has passed since your last notification.</span>")
else
db.notify(record)
record.last_notification = world.time
to_chat(src, "<span class='notice'>New notification has been sent.</span>")
else
to_chat(src,"<span class='warning'>No backup record could be found, sorry.</span>")
// VS edit ends
+13 -13
View File
@@ -1,14 +1,14 @@
/mob/living/carbon/brain/death(gibbed)
if(!gibbed && istype(container, /obj/item/device/mmi)) //If not gibbed but in a container.
container.icon_state = "mmi_dead"
return ..(gibbed,"beeps shrilly as the MMI flatlines!")
else
return ..(gibbed, DEATHGASP_NO_MESSAGE)
/mob/living/carbon/brain/gib()
if(istype(container, /obj/item/device/mmi))
qdel(container)//Gets rid of the MMI if there is one
if(loc)
if(istype(loc,/obj/item/organ/internal/brain))
qdel(loc)//Gets rid of the brain item
/mob/living/carbon/brain/death(gibbed)
if(!gibbed && istype(container, /obj/item/device/mmi)) //If not gibbed but in a container.
container.icon_state = "mmi_dead"
return ..(gibbed,"beeps shrilly as the MMI flatlines!")
else
return ..(gibbed, DEATHGASP_NO_MESSAGE)
/mob/living/carbon/brain/gib()
if(istype(container, /obj/item/device/mmi))
qdel(container)//Gets rid of the MMI if there is one
if(loc)
if(istype(loc,/obj/item/organ/internal/brain))
qdel(loc)//Gets rid of the brain item
..(null,1)
+17 -17
View File
@@ -1,17 +1,17 @@
var/list/_brain_default_emotes = list(
/decl/emote/audible/alarm,
/decl/emote/audible/alert,
/decl/emote/audible/notice,
/decl/emote/audible/whistle,
/decl/emote/audible/synth,
/decl/emote/audible/beep,
/decl/emote/audible/boop,
/decl/emote/visible/blink,
/decl/emote/visible/flash
)
/mob/living/carbon/brain/can_emote()
return (istype(container, /obj/item/device/mmi) && ..())
/mob/living/carbon/brain/get_available_emotes()
return global._brain_default_emotes.Copy()
var/list/_brain_default_emotes = list(
/decl/emote/audible/alarm,
/decl/emote/audible/alert,
/decl/emote/audible/notice,
/decl/emote/audible/whistle,
/decl/emote/audible/synth,
/decl/emote/audible/beep,
/decl/emote/audible/boop,
/decl/emote/visible/blink,
/decl/emote/visible/flash
)
/mob/living/carbon/brain/can_emote()
return (istype(container, /obj/item/device/mmi) && ..())
/mob/living/carbon/brain/get_available_emotes()
return global._brain_default_emotes.Copy()
+222 -222
View File
@@ -1,222 +1,222 @@
/mob/living/carbon/brain/handle_breathing()
return
/mob/living/carbon/brain/handle_mutations_and_radiation()
if (radiation)
if (radiation > 100)
radiation = 100
if(!container)//If it's not in an MMI
to_chat(src, span_red("You feel weak."))
else//Fluff-wise, since the brain can't detect anything itself, the MMI handles thing like that
to_chat(src, span_red("STATUS: CRITICAL AMOUNTS OF RADIATION DETECTED."))
switch(radiation)
if(1 to 49)
radiation--
if(prob(25))
adjustToxLoss(1)
updatehealth()
if(50 to 74)
radiation -= 2
adjustToxLoss(1)
if(prob(5))
radiation -= 5
if(!container)
to_chat(src, span_red("You feel weak."))
else
to_chat(src, span_red("STATUS: DANGEROUS LEVELS OF RADIATION DETECTED."))
updatehealth()
if(75 to 100)
radiation -= 3
adjustToxLoss(3)
updatehealth()
/mob/living/carbon/brain/handle_environment(datum/gas_mixture/environment)
if(!environment)
return
var/environment_heat_capacity = environment.heat_capacity()
if(istype(get_turf(src), /turf/space))
var/turf/heat_turf = get_turf(src)
environment_heat_capacity = heat_turf.heat_capacity
if((environment.temperature > (T0C + 50)) || (environment.temperature < (T0C + 10)))
var/transfer_coefficient = 1
handle_temperature_damage(HEAD, environment.temperature, environment_heat_capacity*transfer_coefficient)
if(stat==2)
bodytemperature += 0.1*(environment.temperature - bodytemperature)*environment_heat_capacity/(environment_heat_capacity + 270000)
//Account for massive pressure differences
return //TODO: DEFERRED
/mob/living/carbon/brain/proc/handle_temperature_damage(body_part, exposed_temperature, exposed_intensity)
if(status_flags & GODMODE) return
if(exposed_temperature > bodytemperature)
var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0)
//adjustFireLoss(2.5*discomfort)
//adjustFireLoss(5.0*discomfort)
adjustFireLoss(20.0*discomfort)
else
var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0)
//adjustFireLoss(2.5*discomfort)
adjustFireLoss(5.0*discomfort)
/mob/living/carbon/brain/handle_chemicals_in_body()
chem_effects.Cut()
if(touching) touching.metabolize()
if(ingested) ingested.metabolize()
if(bloodstr) bloodstr.metabolize()
// decrement dizziness counter, clamped to 0
if(resting)
dizziness = max(0, dizziness - 5)
else
dizziness = max(0, dizziness - 1)
updatehealth()
return //TODO: DEFERRED
/mob/living/carbon/brain/handle_regular_status_updates() //TODO: comment out the unused bits >_>
updatehealth()
if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP
blinded = 1
silent = 0
else //ALIVE. LIGHTS ARE ON
if( !container && (health < config.health_threshold_dead || ((world.time - timeofhostdeath) > config.revival_brain_life)) )
death()
blinded = 1
silent = 0
return 1
//Handling EMP effect in the Life(), it's made VERY simply, and has some additional effects handled elsewhere
if(emp_damage) //This is pretty much a damage type only used by MMIs, dished out by the emp_act
if(!(container && istype(container, /obj/item/device/mmi)))
emp_damage = 0
else
emp_damage = round(emp_damage,1)//Let's have some nice numbers to work with
switch(emp_damage)
if(31 to INFINITY)
emp_damage = 30//Let's not overdo it
if(21 to 30)//High level of EMP damage, unable to see, hear, or speak
SetBlinded(1)
blinded = 1
ear_deaf = 1
silent = 1
if(!alert)//Sounds an alarm, but only once per 'level'
emote("alarm")
to_chat(src, span_red("Major electrical distruption detected: System rebooting."))
alert = 1
if(prob(75))
emp_damage -= 1
if(20)
alert = 0
blinded = 0
SetBlinded(0)
ear_deaf = 0
silent = 0
emp_damage -= 1
if(11 to 19)//Moderate level of EMP damage, resulting in nearsightedness and ear damage
eye_blurry = 1
ear_damage = 1
if(!alert)
emote("alert")
to_chat(src, span_red("Primary systems are now online."))
alert = 1
if(prob(50))
emp_damage -= 1
if(10)
alert = 0
eye_blurry = 0
ear_damage = 0
emp_damage -= 1
if(2 to 9)//Low level of EMP damage, has few effects(handled elsewhere)
if(!alert)
emote("notice")
to_chat(src, span_red("System reboot nearly complete."))
alert = 1
if(prob(25))
emp_damage -= 1
if(1)
alert = 0
to_chat(src, span_red("All systems restored."))
emp_damage -= 1
return 1
/mob/living/carbon/brain/handle_regular_hud_updates()
if (stat == 2 || (XRAY in src.mutations))
sight |= SEE_TURFS
sight |= SEE_MOBS
sight |= SEE_OBJS
see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_TWO
else if (stat != 2)
sight &= ~SEE_TURFS
sight &= ~SEE_MOBS
sight &= ~SEE_OBJS
see_in_dark = 2
see_invisible = SEE_INVISIBLE_LIVING
if (healths)
if (stat != 2)
switch(health)
if(100 to INFINITY)
healths.icon_state = "health0"
if(80 to 100)
healths.icon_state = "health1"
if(60 to 80)
healths.icon_state = "health2"
if(40 to 60)
healths.icon_state = "health3"
if(20 to 40)
healths.icon_state = "health4"
if(0 to 20)
healths.icon_state = "health5"
else
healths.icon_state = "health6"
else
healths.icon_state = "health7"
if (stat == 2 || (XRAY in src.mutations))
sight |= SEE_TURFS
sight |= SEE_MOBS
sight |= SEE_OBJS
see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_TWO
else if (stat != 2)
sight &= ~SEE_TURFS
sight &= ~SEE_MOBS
sight &= ~SEE_OBJS
see_in_dark = 2
see_invisible = SEE_INVISIBLE_LIVING
if (client)
client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired)
if (stat != 2)
if ((blinded))
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else
clear_fullscreen("blind")
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
if (machine)
if (!( machine.check_eye(src) ))
reset_view(null)
else
if(client && !client.adminobs)
reset_view(null)
return 1
/mob/living/carbon/brain/handle_breathing()
return
/mob/living/carbon/brain/handle_mutations_and_radiation()
if (radiation)
if (radiation > 100)
radiation = 100
if(!container)//If it's not in an MMI
to_chat(src, span_red("You feel weak."))
else//Fluff-wise, since the brain can't detect anything itself, the MMI handles thing like that
to_chat(src, span_red("STATUS: CRITICAL AMOUNTS OF RADIATION DETECTED."))
switch(radiation)
if(1 to 49)
radiation--
if(prob(25))
adjustToxLoss(1)
updatehealth()
if(50 to 74)
radiation -= 2
adjustToxLoss(1)
if(prob(5))
radiation -= 5
if(!container)
to_chat(src, span_red("You feel weak."))
else
to_chat(src, span_red("STATUS: DANGEROUS LEVELS OF RADIATION DETECTED."))
updatehealth()
if(75 to 100)
radiation -= 3
adjustToxLoss(3)
updatehealth()
/mob/living/carbon/brain/handle_environment(datum/gas_mixture/environment)
if(!environment)
return
var/environment_heat_capacity = environment.heat_capacity()
if(istype(get_turf(src), /turf/space))
var/turf/heat_turf = get_turf(src)
environment_heat_capacity = heat_turf.heat_capacity
if((environment.temperature > (T0C + 50)) || (environment.temperature < (T0C + 10)))
var/transfer_coefficient = 1
handle_temperature_damage(HEAD, environment.temperature, environment_heat_capacity*transfer_coefficient)
if(stat==2)
bodytemperature += 0.1*(environment.temperature - bodytemperature)*environment_heat_capacity/(environment_heat_capacity + 270000)
//Account for massive pressure differences
return //TODO: DEFERRED
/mob/living/carbon/brain/proc/handle_temperature_damage(body_part, exposed_temperature, exposed_intensity)
if(status_flags & GODMODE) return
if(exposed_temperature > bodytemperature)
var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0)
//adjustFireLoss(2.5*discomfort)
//adjustFireLoss(5.0*discomfort)
adjustFireLoss(20.0*discomfort)
else
var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0)
//adjustFireLoss(2.5*discomfort)
adjustFireLoss(5.0*discomfort)
/mob/living/carbon/brain/handle_chemicals_in_body()
chem_effects.Cut()
if(touching) touching.metabolize()
if(ingested) ingested.metabolize()
if(bloodstr) bloodstr.metabolize()
// decrement dizziness counter, clamped to 0
if(resting)
dizziness = max(0, dizziness - 5)
else
dizziness = max(0, dizziness - 1)
updatehealth()
return //TODO: DEFERRED
/mob/living/carbon/brain/handle_regular_status_updates() //TODO: comment out the unused bits >_>
updatehealth()
if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP
blinded = 1
silent = 0
else //ALIVE. LIGHTS ARE ON
if( !container && (health < config.health_threshold_dead || ((world.time - timeofhostdeath) > config.revival_brain_life)) )
death()
blinded = 1
silent = 0
return 1
//Handling EMP effect in the Life(), it's made VERY simply, and has some additional effects handled elsewhere
if(emp_damage) //This is pretty much a damage type only used by MMIs, dished out by the emp_act
if(!(container && istype(container, /obj/item/device/mmi)))
emp_damage = 0
else
emp_damage = round(emp_damage,1)//Let's have some nice numbers to work with
switch(emp_damage)
if(31 to INFINITY)
emp_damage = 30//Let's not overdo it
if(21 to 30)//High level of EMP damage, unable to see, hear, or speak
SetBlinded(1)
blinded = 1
ear_deaf = 1
silent = 1
if(!alert)//Sounds an alarm, but only once per 'level'
emote("alarm")
to_chat(src, span_red("Major electrical distruption detected: System rebooting."))
alert = 1
if(prob(75))
emp_damage -= 1
if(20)
alert = 0
blinded = 0
SetBlinded(0)
ear_deaf = 0
silent = 0
emp_damage -= 1
if(11 to 19)//Moderate level of EMP damage, resulting in nearsightedness and ear damage
eye_blurry = 1
ear_damage = 1
if(!alert)
emote("alert")
to_chat(src, span_red("Primary systems are now online."))
alert = 1
if(prob(50))
emp_damage -= 1
if(10)
alert = 0
eye_blurry = 0
ear_damage = 0
emp_damage -= 1
if(2 to 9)//Low level of EMP damage, has few effects(handled elsewhere)
if(!alert)
emote("notice")
to_chat(src, span_red("System reboot nearly complete."))
alert = 1
if(prob(25))
emp_damage -= 1
if(1)
alert = 0
to_chat(src, span_red("All systems restored."))
emp_damage -= 1
return 1
/mob/living/carbon/brain/handle_regular_hud_updates()
if (stat == 2 || (XRAY in src.mutations))
sight |= SEE_TURFS
sight |= SEE_MOBS
sight |= SEE_OBJS
see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_TWO
else if (stat != 2)
sight &= ~SEE_TURFS
sight &= ~SEE_MOBS
sight &= ~SEE_OBJS
see_in_dark = 2
see_invisible = SEE_INVISIBLE_LIVING
if (healths)
if (stat != 2)
switch(health)
if(100 to INFINITY)
healths.icon_state = "health0"
if(80 to 100)
healths.icon_state = "health1"
if(60 to 80)
healths.icon_state = "health2"
if(40 to 60)
healths.icon_state = "health3"
if(20 to 40)
healths.icon_state = "health4"
if(0 to 20)
healths.icon_state = "health5"
else
healths.icon_state = "health6"
else
healths.icon_state = "health7"
if (stat == 2 || (XRAY in src.mutations))
sight |= SEE_TURFS
sight |= SEE_MOBS
sight |= SEE_OBJS
see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_TWO
else if (stat != 2)
sight &= ~SEE_TURFS
sight &= ~SEE_MOBS
sight &= ~SEE_OBJS
see_in_dark = 2
see_invisible = SEE_INVISIBLE_LIVING
if (client)
client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired)
if (stat != 2)
if ((blinded))
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else
clear_fullscreen("blind")
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
if (machine)
if (!( machine.check_eye(src) ))
reset_view(null)
else
if(client && !client.adminobs)
reset_view(null)
return 1
@@ -1,3 +1,3 @@
/mob/living/carbon/brain/Login()
..()
/mob/living/carbon/brain/Login()
..()
SetSleeping(0)
+29 -29
View File
@@ -1,29 +1,29 @@
//TODO: Convert this over for languages.
/mob/living/carbon/brain/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if(silent)
return
message = sanitize(message)
if(!(container && container.can_speak))
return //Certain objects can speak, like MMIs. Most others cannot. -Q
else
if(prob(emp_damage * 4))
if(prob(10))//10% chance to drop the message entirely
return
else
message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher
..()
/mob/living/carbon/brain/handle_message_mode(message_mode, message, verb, speaking, used_radios)
..()
if(message_mode)
var/obj/item/device/mmi/R = container
if(R.radio && R.radio.radio_enabled)
if(message_mode == "general")
message_mode = null
return R.radio.talk_into(src, message, message_mode, verb, speaking)
else
to_chat(src, "<span class='danger'>Your radio is disabled.</span>")
return 0
//TODO: Convert this over for languages.
/mob/living/carbon/brain/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if(silent)
return
message = sanitize(message)
if(!(container && container.can_speak))
return //Certain objects can speak, like MMIs. Most others cannot. -Q
else
if(prob(emp_damage * 4))
if(prob(10))//10% chance to drop the message entirely
return
else
message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher
..()
/mob/living/carbon/brain/handle_message_mode(message_mode, message, verb, speaking, used_radios)
..()
if(message_mode)
var/obj/item/device/mmi/R = container
if(R.radio && R.radio.radio_enabled)
if(message_mode == "general")
message_mode = null
return R.radio.talk_into(src, message, message_mode, verb, speaking)
else
to_chat(src, "<span class='danger'>Your radio is disabled.</span>")
return 0
@@ -1,32 +1,32 @@
/mob/living/carbon
gender = MALE
blocks_emissive = EMISSIVE_BLOCK_UNIQUE // BLEH, this could be improved for transparent species and stuff! And blocks glowing eyes?!
var/datum/species/species //Contains icon generation and language information, set during New().
var/list/stomach_contents = list()
var/list/datum/disease2/disease/virus2 = list()
var/list/antibodies = list()
var/last_eating = 0 //Not sure what this does... I found it hidden in food.dm
var/life_tick = 0 // The amount of life ticks that have processed on this mob.
// total amount of wounds on mob, used to spread out healing and the like over all wounds
var/number_wounds = 0
var/obj/item/handcuffed = null //Whether or not the mob is handcuffed
var/obj/item/legcuffed = null //Same as handcuffs but for legs. Bear traps use this.
//Surgery info
var/datum/surgery_status/op_stage = new/datum/surgery_status
//Active emote/pose
var/pose = null
var/list/chem_effects = list()
var/datum/reagents/metabolism/bloodstream/bloodstr = null
var/datum/reagents/metabolism/ingested/ingested = null
var/datum/reagents/metabolism/touch/touching = null
var/pulse = PULSE_NORM //current pulse level
var/does_not_breathe = 0 //Used for specific mobs that can't take advantage of the species flags (changelings)
//these two help govern taste. The first is the last time a taste message was shown to the plaer.
//the second is the message in question.
var/last_taste_time = 0
/mob/living/carbon
gender = MALE
blocks_emissive = EMISSIVE_BLOCK_UNIQUE // BLEH, this could be improved for transparent species and stuff! And blocks glowing eyes?!
var/datum/species/species //Contains icon generation and language information, set during New().
var/list/stomach_contents = list()
var/list/datum/disease2/disease/virus2 = list()
var/list/antibodies = list()
var/last_eating = 0 //Not sure what this does... I found it hidden in food.dm
var/life_tick = 0 // The amount of life ticks that have processed on this mob.
// total amount of wounds on mob, used to spread out healing and the like over all wounds
var/number_wounds = 0
var/obj/item/handcuffed = null //Whether or not the mob is handcuffed
var/obj/item/legcuffed = null //Same as handcuffs but for legs. Bear traps use this.
//Surgery info
var/datum/surgery_status/op_stage = new/datum/surgery_status
//Active emote/pose
var/pose = null
var/list/chem_effects = list()
var/datum/reagents/metabolism/bloodstream/bloodstr = null
var/datum/reagents/metabolism/ingested/ingested = null
var/datum/reagents/metabolism/touch/touching = null
var/pulse = PULSE_NORM //current pulse level
var/does_not_breathe = 0 //Used for specific mobs that can't take advantage of the species flags (changelings)
//these two help govern taste. The first is the last time a taste message was shown to the plaer.
//the second is the message in question.
var/last_taste_time = 0
var/last_taste_text = ""
+252 -252
View File
@@ -1,252 +1,252 @@
/mob/living/carbon/human/proc/change_appearance(var/flags = APPEARANCE_ALL_HAIR,
var/mob/user = src,
var/check_species_whitelist = 1,
var/list/species_whitelist = list(),
var/list/species_blacklist = list(),
var/datum/tgui_state/state = GLOB.tgui_self_state)
var/datum/tgui_module/appearance_changer/AC = new(src, src, check_species_whitelist, species_whitelist, species_blacklist)
AC.flags = flags
AC.tgui_interact(user, custom_state = state)
/mob/living/carbon/human/proc/change_species(var/new_species)
if(!new_species)
return
if(species == new_species)
return
if(!(new_species in GLOB.all_species))
return
set_species(new_species)
reset_hair()
return 1
/mob/living/carbon/human/proc/change_gender(var/gender)
if(src.gender == gender)
return
src.gender = gender
//reset_hair() //VOREStation Remove - Don't just randomize hair on gender swaps for prometheans.
update_dna()
update_icons_body()
return 1
/mob/living/carbon/human/proc/change_gender_identity(var/identifying_gender)
if(src.identifying_gender == identifying_gender)
return
src.identifying_gender = identifying_gender
return 1
/mob/living/carbon/human/proc/change_hair(var/hair_style)
if(!hair_style)
return
if(h_style == hair_style)
return
if(!(hair_style in hair_styles_list))
return
h_style = hair_style
update_hair()
return 1
/mob/living/carbon/human/proc/change_hair_gradient(var/hair_gradient)
if(!hair_gradient)
return
if(grad_style == hair_gradient)
return
if(!(hair_gradient in GLOB.hair_gradients))
return
grad_style = hair_gradient
update_hair()
return 1
/mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style)
if(!facial_hair_style)
return
if(f_style == facial_hair_style)
return
if(!(facial_hair_style in facial_hair_styles_list))
return
f_style = facial_hair_style
update_hair()
return 1
/mob/living/carbon/human/proc/reset_hair()
var/list/valid_hairstyles = generate_valid_hairstyles()
var/list/valid_facial_hairstyles = generate_valid_facial_hairstyles()
if(valid_hairstyles.len)
h_style = pick(valid_hairstyles)
else
//this shouldn't happen
h_style = "Bald"
if(valid_facial_hairstyles.len)
f_style = pick(valid_facial_hairstyles)
else
//this shouldn't happen
f_style = "Shaved"
update_hair()
/mob/living/carbon/human/proc/change_eye_color(var/red, var/green, var/blue)
if(red == r_eyes && green == g_eyes && blue == b_eyes)
return
r_eyes = red
g_eyes = green
b_eyes = blue
update_eyes()
update_icons_body()
return 1
/mob/living/carbon/human/proc/change_hair_color(var/red, var/green, var/blue)
if(red == r_hair && green == g_hair && blue == b_hair)
return
r_hair = red
g_hair = green
b_hair = blue
update_hair()
return 1
/mob/living/carbon/human/proc/change_grad_color(var/red, var/green, var/blue)
if(red == r_grad && green == g_grad && blue == b_grad)
return
r_grad = red
g_grad = green
b_grad = blue
update_hair()
return 1
/mob/living/carbon/human/proc/change_facial_hair_color(var/red, var/green, var/blue)
if(red == r_facial && green == g_facial && blue == b_facial)
return
r_facial = red
g_facial = green
b_facial = blue
update_hair()
return 1
/mob/living/carbon/human/proc/change_skin_color(var/red, var/green, var/blue)
if(red == r_skin && green == g_skin && blue == b_skin || !(species.appearance_flags & HAS_SKIN_COLOR))
return
r_skin = red
g_skin = green
b_skin = blue
force_update_limbs()
update_icons_body()
return 1
/mob/living/carbon/human/proc/change_skin_tone(var/tone)
if(s_tone == tone || !(species.appearance_flags & HAS_SKIN_TONE))
return
s_tone = tone
force_update_limbs()
update_icons_body()
return 1
/mob/living/carbon/human/proc/update_dna()
check_dna()
dna.ready_dna(src)
for(var/obj/item/organ/O in organs)
O.dna = dna // Update all of those because apparently they're separate, and icons won't update properly
/mob/living/carbon/human/proc/generate_valid_species(var/check_whitelist = 1, var/list/whitelist = list(), var/list/blacklist = list())
var/list/valid_species = new()
for(var/current_species_name in GLOB.all_species)
var/datum/species/current_species = GLOB.all_species[current_species_name]
if(check_whitelist && config.usealienwhitelist && !check_rights(R_ADMIN|R_EVENT, 0, src)) //If we're using the whitelist, make sure to check it!
if(!(current_species.spawn_flags & SPECIES_CAN_JOIN))
continue
if(whitelist.len && !(current_species_name in whitelist))
continue
if(blacklist.len && (current_species_name in blacklist))
continue
if((current_species.spawn_flags & SPECIES_IS_WHITELISTED) && !is_alien_whitelisted(src, current_species))
continue
valid_species += current_species_name
return valid_species
/mob/living/carbon/human/proc/generate_valid_hairstyles(var/check_gender = 1)
var/use_species = species.get_bodytype(src)
var/obj/item/organ/external/head/H = get_organ(BP_HEAD)
if(H) use_species = H.species.get_bodytype(src)
var/list/valid_hairstyles = new()
for(var/hairstyle in hair_styles_list)
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
if(check_gender && gender != NEUTER)
if(gender == MALE && S.gender == FEMALE)
continue
else if(gender == FEMALE && S.gender == MALE)
continue
if(!(use_species in S.species_allowed))
continue
if(S.ckeys_allowed && !(ckey in S.ckeys_allowed)) //VOREStation add - ckey whitelist check
continue //VOREStation add - ckey whitelist check
valid_hairstyles += hairstyle
return valid_hairstyles
/mob/living/carbon/human/proc/generate_valid_facial_hairstyles()
var/use_species = species.get_bodytype(src)
var/obj/item/organ/external/head/H = get_organ(BP_HEAD)
if(H) use_species = H.species.get_bodytype(src)
var/list/valid_facial_hairstyles = new()
for(var/facialhairstyle in facial_hair_styles_list)
var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle]
if(gender != NEUTER)
if(gender == MALE && S.gender == FEMALE)
continue
else if(gender == FEMALE && S.gender == MALE)
continue
if(!(use_species in S.species_allowed))
continue
if(S.ckeys_allowed && !(ckey in S.ckeys_allowed)) //VOREStation add - ckey whitelist check
continue //VOREStation add - ckey whitelist check
valid_facial_hairstyles += facialhairstyle
return valid_facial_hairstyles
/mob/living/carbon/human/proc/force_update_limbs()
for(var/obj/item/organ/external/O in organs)
O.sync_colour_to_human(src)
update_icons_body(FALSE)
/mob/living/carbon/human/proc/change_appearance(var/flags = APPEARANCE_ALL_HAIR,
var/mob/user = src,
var/check_species_whitelist = 1,
var/list/species_whitelist = list(),
var/list/species_blacklist = list(),
var/datum/tgui_state/state = GLOB.tgui_self_state)
var/datum/tgui_module/appearance_changer/AC = new(src, src, check_species_whitelist, species_whitelist, species_blacklist)
AC.flags = flags
AC.tgui_interact(user, custom_state = state)
/mob/living/carbon/human/proc/change_species(var/new_species)
if(!new_species)
return
if(species == new_species)
return
if(!(new_species in GLOB.all_species))
return
set_species(new_species)
reset_hair()
return 1
/mob/living/carbon/human/proc/change_gender(var/gender)
if(src.gender == gender)
return
src.gender = gender
//reset_hair() //VOREStation Remove - Don't just randomize hair on gender swaps for prometheans.
update_dna()
update_icons_body()
return 1
/mob/living/carbon/human/proc/change_gender_identity(var/identifying_gender)
if(src.identifying_gender == identifying_gender)
return
src.identifying_gender = identifying_gender
return 1
/mob/living/carbon/human/proc/change_hair(var/hair_style)
if(!hair_style)
return
if(h_style == hair_style)
return
if(!(hair_style in hair_styles_list))
return
h_style = hair_style
update_hair()
return 1
/mob/living/carbon/human/proc/change_hair_gradient(var/hair_gradient)
if(!hair_gradient)
return
if(grad_style == hair_gradient)
return
if(!(hair_gradient in GLOB.hair_gradients))
return
grad_style = hair_gradient
update_hair()
return 1
/mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style)
if(!facial_hair_style)
return
if(f_style == facial_hair_style)
return
if(!(facial_hair_style in facial_hair_styles_list))
return
f_style = facial_hair_style
update_hair()
return 1
/mob/living/carbon/human/proc/reset_hair()
var/list/valid_hairstyles = generate_valid_hairstyles()
var/list/valid_facial_hairstyles = generate_valid_facial_hairstyles()
if(valid_hairstyles.len)
h_style = pick(valid_hairstyles)
else
//this shouldn't happen
h_style = "Bald"
if(valid_facial_hairstyles.len)
f_style = pick(valid_facial_hairstyles)
else
//this shouldn't happen
f_style = "Shaved"
update_hair()
/mob/living/carbon/human/proc/change_eye_color(var/red, var/green, var/blue)
if(red == r_eyes && green == g_eyes && blue == b_eyes)
return
r_eyes = red
g_eyes = green
b_eyes = blue
update_eyes()
update_icons_body()
return 1
/mob/living/carbon/human/proc/change_hair_color(var/red, var/green, var/blue)
if(red == r_hair && green == g_hair && blue == b_hair)
return
r_hair = red
g_hair = green
b_hair = blue
update_hair()
return 1
/mob/living/carbon/human/proc/change_grad_color(var/red, var/green, var/blue)
if(red == r_grad && green == g_grad && blue == b_grad)
return
r_grad = red
g_grad = green
b_grad = blue
update_hair()
return 1
/mob/living/carbon/human/proc/change_facial_hair_color(var/red, var/green, var/blue)
if(red == r_facial && green == g_facial && blue == b_facial)
return
r_facial = red
g_facial = green
b_facial = blue
update_hair()
return 1
/mob/living/carbon/human/proc/change_skin_color(var/red, var/green, var/blue)
if(red == r_skin && green == g_skin && blue == b_skin || !(species.appearance_flags & HAS_SKIN_COLOR))
return
r_skin = red
g_skin = green
b_skin = blue
force_update_limbs()
update_icons_body()
return 1
/mob/living/carbon/human/proc/change_skin_tone(var/tone)
if(s_tone == tone || !(species.appearance_flags & HAS_SKIN_TONE))
return
s_tone = tone
force_update_limbs()
update_icons_body()
return 1
/mob/living/carbon/human/proc/update_dna()
check_dna()
dna.ready_dna(src)
for(var/obj/item/organ/O in organs)
O.dna = dna // Update all of those because apparently they're separate, and icons won't update properly
/mob/living/carbon/human/proc/generate_valid_species(var/check_whitelist = 1, var/list/whitelist = list(), var/list/blacklist = list())
var/list/valid_species = new()
for(var/current_species_name in GLOB.all_species)
var/datum/species/current_species = GLOB.all_species[current_species_name]
if(check_whitelist && config.usealienwhitelist && !check_rights(R_ADMIN|R_EVENT, 0, src)) //If we're using the whitelist, make sure to check it!
if(!(current_species.spawn_flags & SPECIES_CAN_JOIN))
continue
if(whitelist.len && !(current_species_name in whitelist))
continue
if(blacklist.len && (current_species_name in blacklist))
continue
if((current_species.spawn_flags & SPECIES_IS_WHITELISTED) && !is_alien_whitelisted(src, current_species))
continue
valid_species += current_species_name
return valid_species
/mob/living/carbon/human/proc/generate_valid_hairstyles(var/check_gender = 1)
var/use_species = species.get_bodytype(src)
var/obj/item/organ/external/head/H = get_organ(BP_HEAD)
if(H) use_species = H.species.get_bodytype(src)
var/list/valid_hairstyles = new()
for(var/hairstyle in hair_styles_list)
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
if(check_gender && gender != NEUTER)
if(gender == MALE && S.gender == FEMALE)
continue
else if(gender == FEMALE && S.gender == MALE)
continue
if(!(use_species in S.species_allowed))
continue
if(S.ckeys_allowed && !(ckey in S.ckeys_allowed)) //VOREStation add - ckey whitelist check
continue //VOREStation add - ckey whitelist check
valid_hairstyles += hairstyle
return valid_hairstyles
/mob/living/carbon/human/proc/generate_valid_facial_hairstyles()
var/use_species = species.get_bodytype(src)
var/obj/item/organ/external/head/H = get_organ(BP_HEAD)
if(H) use_species = H.species.get_bodytype(src)
var/list/valid_facial_hairstyles = new()
for(var/facialhairstyle in facial_hair_styles_list)
var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle]
if(gender != NEUTER)
if(gender == MALE && S.gender == FEMALE)
continue
else if(gender == FEMALE && S.gender == MALE)
continue
if(!(use_species in S.species_allowed))
continue
if(S.ckeys_allowed && !(ckey in S.ckeys_allowed)) //VOREStation add - ckey whitelist check
continue //VOREStation add - ckey whitelist check
valid_facial_hairstyles += facialhairstyle
return valid_facial_hairstyles
/mob/living/carbon/human/proc/force_update_limbs()
for(var/obj/item/organ/external/O in organs)
O.sync_colour_to_human(src)
update_icons_body(FALSE)
+147 -147
View File
@@ -1,147 +1,147 @@
/mob/living/carbon/human/gib()
if(vr_holder)
exit_vr()
// Delete the link, because this mob won't be around much longer
vr_holder.vr_link = null
if(vr_link)
vr_link.exit_vr()
vr_link.vr_holder = null
vr_link = null
for(var/obj/item/organ/I in internal_organs)
I.removed()
if(isturf(I?.loc)) // Some organs qdel themselves or other things when removed
I.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),30)
for(var/obj/item/organ/external/E in src.organs)
E.droplimb(0,DROPLIMB_EDGE,1)
sleep(1)
for(var/obj/item/I in src)
drop_from_inventory(I)
I.throw_at(get_edge_target_turf(src,pick(alldirs)), rand(1,3), round(30/I.w_class))
..(species.gibbed_anim) // uses the default mob.dmi file for these, so we only need to specify the first argument
gibs(loc, dna, null, species.get_flesh_colour(src), species.get_blood_colour(src))
/mob/living/carbon/human/dust()
if(species)
..(species.dusted_anim, species.remains_type)
else
..()
/mob/living/carbon/human/ash()
if(species)
..(species.dusted_anim)
else
..()
/mob/living/carbon/human/death(gibbed)
if(stat == DEAD) return
BITSET(hud_updateflag, HEALTH_HUD)
BITSET(hud_updateflag, STATUS_HUD)
BITSET(hud_updateflag, LIFE_HUD)
//Handle species-specific deaths.
species.handle_death(src)
animate_tail_stop()
stop_flying() //VOREStation Edit.
//Handle snowflake ling stuff.
if(mind && mind.changeling)
// If the ling is capable of revival, don't allow them to see deadchat.
if(mind.changeling.chem_charges >= CHANGELING_STASIS_COST)
if(mind.changeling.max_geneticpoints >= 0) // Absorbed lings don't count, as they can't revive.
forbid_seeing_deadchat = TRUE
//Handle brain slugs.
var/obj/item/organ/external/Hd = get_organ(BP_HEAD)
var/mob/living/simple_mob/animal/borer/B
if(Hd)
for(var/I in Hd.implants)
if(istype(I,/mob/living/simple_mob/animal/borer))
B = I
if(B)
if(!B.ckey && ckey && B.controlling)
B.ckey = ckey
B.controlling = 0
if(B.host_brain.ckey)
ckey = B.host_brain.ckey
B.host_brain.ckey = null
B.host_brain.name = "host brain"
B.host_brain.real_name = "host brain"
verbs -= /mob/living/carbon/proc/release_control
callHook("death", list(src, gibbed))
if(mind)
// SSgame_master.adjust_danger(gibbed ? 40 : 20) // VOREStation Edit - We don't use SSgame_master yet.
for(var/mob/observer/dead/O in mob_list)
if(O.client && O.client.is_preference_enabled(/datum/client_preference/show_dsay))
to_chat(O, "<span class='deadsay'><b>[src]</b> has died in <b>[get_area(src)]</b>. [ghost_follow_link(src, O)] </span>")
if(!gibbed && species.death_sound)
playsound(src, species.death_sound, 80, 1, 1)
if(ticker && ticker.mode)
sql_report_death(src)
ticker.mode.check_win()
if(wearing_rig)
wearing_rig.notify_ai("<span class='danger'>Warning: user death event. Mobility control passed to integrated intelligence system.</span>")
// If the body is in VR, move the mind back to the real world
if(vr_holder)
src.exit_vr()
src.vr_holder.vr_link = null
for(var/obj/item/W in src)
src.drop_from_inventory(W)
// If our mind is in VR, bring it back to the real world so it can die with its body
if(vr_link)
vr_link.exit_vr()
vr_link.vr_holder = null
vr_link = null
to_chat(src, "<span class='danger'>Everything abruptly stops.</span>")
return ..(gibbed,species.get_death_message(src))
/mob/living/carbon/human/proc/ChangeToHusk()
if(HUSK in mutations) return
if(f_style)
f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE
if(h_style)
h_style = "Bald"
update_hair(0)
mutations.Add(HUSK)
status_flags |= DISFIGURED //makes them unknown without fucking up other stuff like admintools
update_icons_body()
return
/mob/living/carbon/human/proc/Drain()
ChangeToHusk()
mutations |= HUSK
return
/mob/living/carbon/human/proc/ChangeToSkeleton()
if(SKELETON in src.mutations) return
if(f_style)
f_style = "Shaved"
if(h_style)
h_style = "Bald"
update_hair(0)
mutations.Add(SKELETON)
status_flags |= DISFIGURED
update_icons_body()
return
/mob/living/carbon/human/gib()
if(vr_holder)
exit_vr()
// Delete the link, because this mob won't be around much longer
vr_holder.vr_link = null
if(vr_link)
vr_link.exit_vr()
vr_link.vr_holder = null
vr_link = null
for(var/obj/item/organ/I in internal_organs)
I.removed()
if(isturf(I?.loc)) // Some organs qdel themselves or other things when removed
I.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),30)
for(var/obj/item/organ/external/E in src.organs)
E.droplimb(0,DROPLIMB_EDGE,1)
sleep(1)
for(var/obj/item/I in src)
drop_from_inventory(I)
I.throw_at(get_edge_target_turf(src,pick(alldirs)), rand(1,3), round(30/I.w_class))
..(species.gibbed_anim) // uses the default mob.dmi file for these, so we only need to specify the first argument
gibs(loc, dna, null, species.get_flesh_colour(src), species.get_blood_colour(src))
/mob/living/carbon/human/dust()
if(species)
..(species.dusted_anim, species.remains_type)
else
..()
/mob/living/carbon/human/ash()
if(species)
..(species.dusted_anim)
else
..()
/mob/living/carbon/human/death(gibbed)
if(stat == DEAD) return
BITSET(hud_updateflag, HEALTH_HUD)
BITSET(hud_updateflag, STATUS_HUD)
BITSET(hud_updateflag, LIFE_HUD)
//Handle species-specific deaths.
species.handle_death(src)
animate_tail_stop()
stop_flying() //VOREStation Edit.
//Handle snowflake ling stuff.
if(mind && mind.changeling)
// If the ling is capable of revival, don't allow them to see deadchat.
if(mind.changeling.chem_charges >= CHANGELING_STASIS_COST)
if(mind.changeling.max_geneticpoints >= 0) // Absorbed lings don't count, as they can't revive.
forbid_seeing_deadchat = TRUE
//Handle brain slugs.
var/obj/item/organ/external/Hd = get_organ(BP_HEAD)
var/mob/living/simple_mob/animal/borer/B
if(Hd)
for(var/I in Hd.implants)
if(istype(I,/mob/living/simple_mob/animal/borer))
B = I
if(B)
if(!B.ckey && ckey && B.controlling)
B.ckey = ckey
B.controlling = 0
if(B.host_brain.ckey)
ckey = B.host_brain.ckey
B.host_brain.ckey = null
B.host_brain.name = "host brain"
B.host_brain.real_name = "host brain"
verbs -= /mob/living/carbon/proc/release_control
callHook("death", list(src, gibbed))
if(mind)
// SSgame_master.adjust_danger(gibbed ? 40 : 20) // VOREStation Edit - We don't use SSgame_master yet.
for(var/mob/observer/dead/O in mob_list)
if(O.client && O.client.is_preference_enabled(/datum/client_preference/show_dsay))
to_chat(O, "<span class='deadsay'><b>[src]</b> has died in <b>[get_area(src)]</b>. [ghost_follow_link(src, O)] </span>")
if(!gibbed && species.death_sound)
playsound(src, species.death_sound, 80, 1, 1)
if(ticker && ticker.mode)
sql_report_death(src)
ticker.mode.check_win()
if(wearing_rig)
wearing_rig.notify_ai("<span class='danger'>Warning: user death event. Mobility control passed to integrated intelligence system.</span>")
// If the body is in VR, move the mind back to the real world
if(vr_holder)
src.exit_vr()
src.vr_holder.vr_link = null
for(var/obj/item/W in src)
src.drop_from_inventory(W)
// If our mind is in VR, bring it back to the real world so it can die with its body
if(vr_link)
vr_link.exit_vr()
vr_link.vr_holder = null
vr_link = null
to_chat(src, "<span class='danger'>Everything abruptly stops.</span>")
return ..(gibbed,species.get_death_message(src))
/mob/living/carbon/human/proc/ChangeToHusk()
if(HUSK in mutations) return
if(f_style)
f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE
if(h_style)
h_style = "Bald"
update_hair(0)
mutations.Add(HUSK)
status_flags |= DISFIGURED //makes them unknown without fucking up other stuff like admintools
update_icons_body()
return
/mob/living/carbon/human/proc/Drain()
ChangeToHusk()
mutations |= HUSK
return
/mob/living/carbon/human/proc/ChangeToSkeleton()
if(SKELETON in src.mutations) return
if(f_style)
f_style = "Shaved"
if(h_style)
h_style = "Bald"
update_hair(0)
mutations.Add(SKELETON)
status_flags |= DISFIGURED
update_icons_body()
return
+403 -403
View File
@@ -1,403 +1,403 @@
var/list/_human_default_emotes = list(
/decl/emote/visible/blink,
/decl/emote/audible/synth,
/decl/emote/audible/synth/beep,
/decl/emote/audible/synth/buzz,
/decl/emote/audible/synth/confirm,
/decl/emote/audible/synth/deny,
/decl/emote/audible/synth/scary,
/decl/emote/audible/synth/dwoop,
/decl/emote/audible/synth/boop,
/decl/emote/audible/synth/robochirp,
/decl/emote/visible/nod,
/decl/emote/visible/shake,
/decl/emote/visible/shiver,
/decl/emote/visible/collapse,
/decl/emote/audible/gasp,
/decl/emote/audible/choke,
/decl/emote/audible/sneeze,
/decl/emote/audible/sniff,
/decl/emote/audible/snore,
/decl/emote/audible/whimper,
/decl/emote/audible/whistle,
/decl/emote/audible/whistle/quiet,
/decl/emote/audible/whistle/wolf,
/decl/emote/audible/whistle/summon,
/decl/emote/audible/yawn,
/decl/emote/audible/clap,
/decl/emote/audible/chuckle,
/decl/emote/audible/cough,
/decl/emote/audible/cry,
/decl/emote/audible/sigh,
/decl/emote/audible/laugh,
/decl/emote/audible/mumble,
/decl/emote/audible/grumble,
/decl/emote/audible/groan,
/decl/emote/audible/moan,
/decl/emote/audible/grunt,
/decl/emote/audible/slap,
/decl/emote/audible/crack,
/decl/emote/human/deathgasp,
/decl/emote/audible/giggle,
/decl/emote/audible/scream,
/decl/emote/visible/airguitar,
/decl/emote/visible/blink_r,
/decl/emote/visible/bow,
/decl/emote/visible/salute,
/decl/emote/visible/flap,
/decl/emote/visible/aflap,
/decl/emote/visible/drool,
/decl/emote/visible/eyebrow,
/decl/emote/visible/twitch,
/decl/emote/visible/dance,
/decl/emote/visible/twitch_v,
/decl/emote/visible/faint,
/decl/emote/visible/frown,
/decl/emote/visible/blush,
/decl/emote/visible/wave,
/decl/emote/visible/glare,
/decl/emote/visible/stare,
/decl/emote/visible/look,
/decl/emote/visible/point,
/decl/emote/visible/raise,
/decl/emote/visible/grin,
/decl/emote/visible/shrug,
/decl/emote/visible/smile,
/decl/emote/visible/pale,
/decl/emote/visible/tremble,
/decl/emote/visible/wink,
/decl/emote/visible/hug,
/decl/emote/visible/dap,
/decl/emote/visible/signal,
/decl/emote/visible/handshake,
/decl/emote/visible/afold,
/decl/emote/visible/alook,
/decl/emote/visible/eroll,
/decl/emote/visible/hbow,
/decl/emote/visible/hip,
/decl/emote/visible/holdup,
/decl/emote/visible/hshrug,
/decl/emote/visible/crub,
/decl/emote/visible/erub,
/decl/emote/visible/fslap,
/decl/emote/visible/ftap,
/decl/emote/visible/hrub,
/decl/emote/visible/hspread,
/decl/emote/visible/pocket,
/decl/emote/visible/rsalute,
/decl/emote/visible/rshoulder,
/decl/emote/visible/squint,
/decl/emote/visible/tfist,
/decl/emote/visible/tilt,
/decl/emote/visible/spin,
/decl/emote/visible/sidestep,
/decl/emote/audible/snap,
/decl/emote/visible/vomit,
/decl/emote/visible/floorspin,
/decl/emote/visible/flip,
//VOREStation Add
/decl/emote/audible/bug_hiss,
/decl/emote/audible/bug_buzz,
/decl/emote/audible/bug_chitter,
/decl/emote/audible/hiss,
/decl/emote/audible/chirp,
/decl/emote/audible/warble,
/decl/emote/audible/vox_shriek,
/decl/emote/audible/purr,
/decl/emote/audible/purrlong,
/decl/emote/audible/awoo,
/decl/emote/audible/awoo2,
/decl/emote/audible/belch,
/decl/emote/audible/growl,
/decl/emote/audible/woof,
/decl/emote/audible/woof2,
/decl/emote/audible/nya,
/decl/emote/audible/mrowl,
/decl/emote/audible/peep,
/decl/emote/audible/chirp,
/decl/emote/audible/hoot,
/decl/emote/audible/weh,
/decl/emote/audible/merp,
/decl/emote/audible/myarp,
/decl/emote/audible/bark,
/decl/emote/audible/bork,
/decl/emote/audible/mrow,
/decl/emote/audible/hypno,
/decl/emote/audible/hiss,
/decl/emote/audible/rattle,
/decl/emote/audible/squeak,
/decl/emote/audible/geck,
/decl/emote/audible/baa,
/decl/emote/audible/baa2,
/decl/emote/audible/mar,
/decl/emote/audible/wurble,
/decl/emote/audible/snort,
/decl/emote/audible/meow,
/decl/emote/audible/moo,
/decl/emote/audible/croak,
/decl/emote/audible/gao,
/decl/emote/audible/cackle,
/decl/emote/audible/squish,
/decl/emote/audible/spiderchitter,
/decl/emote/audible/spiderpurr,
/decl/emote/audible/squeaky,
/decl/emote/visible/mlem,
/decl/emote/visible/blep,
/decl/emote/helper/vwag,
/decl/emote/helper/vflap,
/decl/emote/audible/prbt,
/decl/emote/audible/gyoh,
/decl/emote/audible/rumble,
/decl/emote/audible/coyawoo,
/decl/emote/audible/coyawoo2,
/decl/emote/audible/coyawoo3,
/decl/emote/audible/coyawoo4,
/decl/emote/audible/coyawoo5,
/decl/emote/audible/fennecscream,
/decl/emote/audible/zoom,
/decl/emote/audible/mothscream,
/decl/emote/audible/mothchitter,
/decl/emote/audible/mothlaugh,
/decl/emote/audible/multichirp,
/decl/emote/audible/gnarl,
/decl/emote/audible/teshsqueak,
/decl/emote/audible/teshchirp,
/decl/emote/audible/teshtrill,
/decl/emote/audible/teshscream,
/decl/emote/visible/bounce,
/decl/emote/visible/jiggle,
/decl/emote/visible/lightup,
/decl/emote/visible/vibrate,
/decl/emote/audible/croon,
/decl/emote/audible/lwarble,
/decl/emote/audible/croak_skrell,
/decl/emote/audible/roarbark,
/decl/emote/audible/dook
//VOREStation Add End
)
//VOREStation Add Start
var/list/_simple_mob_default_emotes = list(
/decl/emote/visible/blink,
/decl/emote/visible/nod,
/decl/emote/visible/shake,
/decl/emote/visible/shiver,
/decl/emote/visible/collapse,
/decl/emote/audible/gasp,
/decl/emote/audible/choke,
/decl/emote/audible/sneeze,
/decl/emote/audible/sniff,
/decl/emote/audible/snore,
/decl/emote/audible/whimper,
/decl/emote/audible/whistle,
/decl/emote/audible/whistle/quiet,
/decl/emote/audible/whistle/wolf,
/decl/emote/audible/whistle/summon,
/decl/emote/audible/yawn,
/decl/emote/audible/clap,
/decl/emote/audible/chuckle,
/decl/emote/audible/cough,
/decl/emote/audible/cry,
/decl/emote/audible/sigh,
/decl/emote/audible/laugh,
/decl/emote/audible/mumble,
/decl/emote/audible/grumble,
/decl/emote/audible/groan,
/decl/emote/audible/moan,
/decl/emote/audible/grunt,
/decl/emote/audible/slap,
/decl/emote/audible/crack,
/decl/emote/human/deathgasp,
/decl/emote/audible/giggle,
/decl/emote/audible/scream,
/decl/emote/visible/airguitar,
/decl/emote/visible/blink_r,
/decl/emote/visible/bow,
/decl/emote/visible/salute,
/decl/emote/visible/flap,
/decl/emote/visible/aflap,
/decl/emote/visible/drool,
/decl/emote/visible/eyebrow,
/decl/emote/visible/twitch,
/decl/emote/visible/dance,
/decl/emote/visible/twitch_v,
/decl/emote/visible/faint,
/decl/emote/visible/frown,
/decl/emote/visible/blush,
/decl/emote/visible/wave,
/decl/emote/visible/glare,
/decl/emote/visible/stare,
/decl/emote/visible/look,
/decl/emote/visible/point,
/decl/emote/visible/raise,
/decl/emote/visible/grin,
/decl/emote/visible/shrug,
/decl/emote/visible/smile,
/decl/emote/visible/pale,
/decl/emote/visible/tremble,
/decl/emote/visible/wink,
/decl/emote/visible/hug,
/decl/emote/visible/signal,
/decl/emote/visible/afold,
/decl/emote/visible/alook,
/decl/emote/visible/eroll,
/decl/emote/visible/hbow,
/decl/emote/visible/hip,
/decl/emote/visible/holdup,
/decl/emote/visible/hshrug,
/decl/emote/visible/crub,
/decl/emote/visible/erub,
/decl/emote/visible/fslap,
/decl/emote/visible/ftap,
/decl/emote/visible/hrub,
/decl/emote/visible/hspread,
/decl/emote/visible/rsalute,
/decl/emote/visible/rshoulder,
/decl/emote/visible/squint,
/decl/emote/visible/tfist,
/decl/emote/visible/tilt,
/decl/emote/visible/spin,
/decl/emote/visible/sidestep,
/decl/emote/visible/vomit,
/decl/emote/visible/floorspin,
/decl/emote/visible/flip,
/decl/emote/audible/awoo,
/decl/emote/audible/awoo2,
/decl/emote/audible/belch,
/decl/emote/audible/growl,
/decl/emote/audible/woof,
/decl/emote/audible/woof2,
/decl/emote/audible/nya,
/decl/emote/audible/mrowl,
/decl/emote/audible/peep,
/decl/emote/audible/chirp,
/decl/emote/audible/hoot,
/decl/emote/audible/weh,
/decl/emote/audible/merp,
/decl/emote/audible/myarp,
/decl/emote/audible/bark,
/decl/emote/audible/bork,
/decl/emote/audible/mrow,
/decl/emote/audible/hypno,
/decl/emote/audible/hiss,
/decl/emote/audible/rattle,
/decl/emote/audible/squeak,
/decl/emote/audible/geck,
/decl/emote/audible/baa,
/decl/emote/audible/baa2,
/decl/emote/audible/mar,
/decl/emote/audible/wurble,
/decl/emote/audible/snort,
/decl/emote/audible/meow,
/decl/emote/audible/moo,
/decl/emote/audible/croak,
/decl/emote/audible/gao,
/decl/emote/audible/cackle,
/decl/emote/audible/squish,
/decl/emote/audible/spiderchitter,
/decl/emote/audible/spiderpurr,
/decl/emote/audible/squeaky,
/decl/emote/visible/mlem,
/decl/emote/visible/blep,
/decl/emote/audible/prbt,
/decl/emote/audible/gyoh,
/decl/emote/audible/rumble,
/decl/emote/audible/fennecscream,
/decl/emote/audible/zoom,
/decl/emote/audible/bug_hiss,
/decl/emote/audible/bug_buzz,
/decl/emote/audible/bug_chitter,
/decl/emote/audible/hiss,
/decl/emote/audible/chirp,
/decl/emote/audible/warble,
/decl/emote/audible/vox_shriek,
/decl/emote/audible/purr,
/decl/emote/audible/purrlong,
/decl/emote/audible/dook
)
//VOREStation Add End
/mob/living/carbon/human/get_available_emotes()
. = global._human_default_emotes.Copy()
if(length(species?.default_emotes))
return . | species.default_emotes
/mob/living/simple_mob/get_available_emotes()
. = global._simple_mob_default_emotes.Copy()
/mob/living/carbon/human/verb/pose()
set name = "Set Pose"
set desc = "Sets a description which will be shown when someone examines you."
set category = "IC"
var/datum/gender/T = gender_datums[get_visible_gender()]
pose = strip_html_simple(tgui_input_text(usr, "This is [src]. [T.he]...", "Pose", null))
/mob/living/carbon/human/verb/set_flavor()
set name = "Set Flavour Text"
set desc = "Sets an extended description of your character's features."
set category = "IC"
var/HTML = "<body>"
HTML += "<tt><center>"
HTML += "<b>Update Flavour Text</b> <hr />"
HTML += "<br></center>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=general'>General:</a> "
HTML += TextPreview(flavor_texts["general"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=head'>Head:</a> "
HTML += TextPreview(flavor_texts["head"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=face'>Face:</a> "
HTML += TextPreview(flavor_texts["face"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=eyes'>Eyes:</a> "
HTML += TextPreview(flavor_texts["eyes"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=torso'>Body:</a> "
HTML += TextPreview(flavor_texts["torso"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=arms'>Arms:</a> "
HTML += TextPreview(flavor_texts["arms"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=hands'>Hands:</a> "
HTML += TextPreview(flavor_texts["hands"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=legs'>Legs:</a> "
HTML += TextPreview(flavor_texts["legs"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=feet'>Feet:</a> "
HTML += TextPreview(flavor_texts["feet"])
HTML += "<br>"
HTML += "<hr />"
HTML +="<a href='?src=\ref[src];flavor_change=done'>\[Done\]</a>"
HTML += "<tt>"
src << browse(HTML, "window=flavor_changes;size=430x300")
/mob/living/carbon/human/proc/toggle_tail(var/setting,var/message = 0)
if(!tail_style || !tail_style.ani_state)
if(message)
to_chat(src, "<span class='warning'>You don't have a tail that supports this.</span>")
return 0
var/new_wagging = isnull(setting) ? !wagging : setting
if(new_wagging != wagging)
wagging = new_wagging
update_tail_showing()
return 1
/mob/living/carbon/human/proc/toggle_wing(var/setting,var/message = 0)
if(!wing_style || !wing_style.ani_state)
if(message)
to_chat(src, "<span class='warning'>You don't have a wingtype that supports this.</span>")
return 0
var/new_flapping = isnull(setting) ? !flapping : setting
if(new_flapping != flapping)
flapping = new_flapping
update_wing_showing()
return 1
var/list/_human_default_emotes = list(
/decl/emote/visible/blink,
/decl/emote/audible/synth,
/decl/emote/audible/synth/beep,
/decl/emote/audible/synth/buzz,
/decl/emote/audible/synth/confirm,
/decl/emote/audible/synth/deny,
/decl/emote/audible/synth/scary,
/decl/emote/audible/synth/dwoop,
/decl/emote/audible/synth/boop,
/decl/emote/audible/synth/robochirp,
/decl/emote/visible/nod,
/decl/emote/visible/shake,
/decl/emote/visible/shiver,
/decl/emote/visible/collapse,
/decl/emote/audible/gasp,
/decl/emote/audible/choke,
/decl/emote/audible/sneeze,
/decl/emote/audible/sniff,
/decl/emote/audible/snore,
/decl/emote/audible/whimper,
/decl/emote/audible/whistle,
/decl/emote/audible/whistle/quiet,
/decl/emote/audible/whistle/wolf,
/decl/emote/audible/whistle/summon,
/decl/emote/audible/yawn,
/decl/emote/audible/clap,
/decl/emote/audible/chuckle,
/decl/emote/audible/cough,
/decl/emote/audible/cry,
/decl/emote/audible/sigh,
/decl/emote/audible/laugh,
/decl/emote/audible/mumble,
/decl/emote/audible/grumble,
/decl/emote/audible/groan,
/decl/emote/audible/moan,
/decl/emote/audible/grunt,
/decl/emote/audible/slap,
/decl/emote/audible/crack,
/decl/emote/human/deathgasp,
/decl/emote/audible/giggle,
/decl/emote/audible/scream,
/decl/emote/visible/airguitar,
/decl/emote/visible/blink_r,
/decl/emote/visible/bow,
/decl/emote/visible/salute,
/decl/emote/visible/flap,
/decl/emote/visible/aflap,
/decl/emote/visible/drool,
/decl/emote/visible/eyebrow,
/decl/emote/visible/twitch,
/decl/emote/visible/dance,
/decl/emote/visible/twitch_v,
/decl/emote/visible/faint,
/decl/emote/visible/frown,
/decl/emote/visible/blush,
/decl/emote/visible/wave,
/decl/emote/visible/glare,
/decl/emote/visible/stare,
/decl/emote/visible/look,
/decl/emote/visible/point,
/decl/emote/visible/raise,
/decl/emote/visible/grin,
/decl/emote/visible/shrug,
/decl/emote/visible/smile,
/decl/emote/visible/pale,
/decl/emote/visible/tremble,
/decl/emote/visible/wink,
/decl/emote/visible/hug,
/decl/emote/visible/dap,
/decl/emote/visible/signal,
/decl/emote/visible/handshake,
/decl/emote/visible/afold,
/decl/emote/visible/alook,
/decl/emote/visible/eroll,
/decl/emote/visible/hbow,
/decl/emote/visible/hip,
/decl/emote/visible/holdup,
/decl/emote/visible/hshrug,
/decl/emote/visible/crub,
/decl/emote/visible/erub,
/decl/emote/visible/fslap,
/decl/emote/visible/ftap,
/decl/emote/visible/hrub,
/decl/emote/visible/hspread,
/decl/emote/visible/pocket,
/decl/emote/visible/rsalute,
/decl/emote/visible/rshoulder,
/decl/emote/visible/squint,
/decl/emote/visible/tfist,
/decl/emote/visible/tilt,
/decl/emote/visible/spin,
/decl/emote/visible/sidestep,
/decl/emote/audible/snap,
/decl/emote/visible/vomit,
/decl/emote/visible/floorspin,
/decl/emote/visible/flip,
//VOREStation Add
/decl/emote/audible/bug_hiss,
/decl/emote/audible/bug_buzz,
/decl/emote/audible/bug_chitter,
/decl/emote/audible/hiss,
/decl/emote/audible/chirp,
/decl/emote/audible/warble,
/decl/emote/audible/vox_shriek,
/decl/emote/audible/purr,
/decl/emote/audible/purrlong,
/decl/emote/audible/awoo,
/decl/emote/audible/awoo2,
/decl/emote/audible/belch,
/decl/emote/audible/growl,
/decl/emote/audible/woof,
/decl/emote/audible/woof2,
/decl/emote/audible/nya,
/decl/emote/audible/mrowl,
/decl/emote/audible/peep,
/decl/emote/audible/chirp,
/decl/emote/audible/hoot,
/decl/emote/audible/weh,
/decl/emote/audible/merp,
/decl/emote/audible/myarp,
/decl/emote/audible/bark,
/decl/emote/audible/bork,
/decl/emote/audible/mrow,
/decl/emote/audible/hypno,
/decl/emote/audible/hiss,
/decl/emote/audible/rattle,
/decl/emote/audible/squeak,
/decl/emote/audible/geck,
/decl/emote/audible/baa,
/decl/emote/audible/baa2,
/decl/emote/audible/mar,
/decl/emote/audible/wurble,
/decl/emote/audible/snort,
/decl/emote/audible/meow,
/decl/emote/audible/moo,
/decl/emote/audible/croak,
/decl/emote/audible/gao,
/decl/emote/audible/cackle,
/decl/emote/audible/squish,
/decl/emote/audible/spiderchitter,
/decl/emote/audible/spiderpurr,
/decl/emote/audible/squeaky,
/decl/emote/visible/mlem,
/decl/emote/visible/blep,
/decl/emote/helper/vwag,
/decl/emote/helper/vflap,
/decl/emote/audible/prbt,
/decl/emote/audible/gyoh,
/decl/emote/audible/rumble,
/decl/emote/audible/coyawoo,
/decl/emote/audible/coyawoo2,
/decl/emote/audible/coyawoo3,
/decl/emote/audible/coyawoo4,
/decl/emote/audible/coyawoo5,
/decl/emote/audible/fennecscream,
/decl/emote/audible/zoom,
/decl/emote/audible/mothscream,
/decl/emote/audible/mothchitter,
/decl/emote/audible/mothlaugh,
/decl/emote/audible/multichirp,
/decl/emote/audible/gnarl,
/decl/emote/audible/teshsqueak,
/decl/emote/audible/teshchirp,
/decl/emote/audible/teshtrill,
/decl/emote/audible/teshscream,
/decl/emote/visible/bounce,
/decl/emote/visible/jiggle,
/decl/emote/visible/lightup,
/decl/emote/visible/vibrate,
/decl/emote/audible/croon,
/decl/emote/audible/lwarble,
/decl/emote/audible/croak_skrell,
/decl/emote/audible/roarbark,
/decl/emote/audible/dook
//VOREStation Add End
)
//VOREStation Add Start
var/list/_simple_mob_default_emotes = list(
/decl/emote/visible/blink,
/decl/emote/visible/nod,
/decl/emote/visible/shake,
/decl/emote/visible/shiver,
/decl/emote/visible/collapse,
/decl/emote/audible/gasp,
/decl/emote/audible/choke,
/decl/emote/audible/sneeze,
/decl/emote/audible/sniff,
/decl/emote/audible/snore,
/decl/emote/audible/whimper,
/decl/emote/audible/whistle,
/decl/emote/audible/whistle/quiet,
/decl/emote/audible/whistle/wolf,
/decl/emote/audible/whistle/summon,
/decl/emote/audible/yawn,
/decl/emote/audible/clap,
/decl/emote/audible/chuckle,
/decl/emote/audible/cough,
/decl/emote/audible/cry,
/decl/emote/audible/sigh,
/decl/emote/audible/laugh,
/decl/emote/audible/mumble,
/decl/emote/audible/grumble,
/decl/emote/audible/groan,
/decl/emote/audible/moan,
/decl/emote/audible/grunt,
/decl/emote/audible/slap,
/decl/emote/audible/crack,
/decl/emote/human/deathgasp,
/decl/emote/audible/giggle,
/decl/emote/audible/scream,
/decl/emote/visible/airguitar,
/decl/emote/visible/blink_r,
/decl/emote/visible/bow,
/decl/emote/visible/salute,
/decl/emote/visible/flap,
/decl/emote/visible/aflap,
/decl/emote/visible/drool,
/decl/emote/visible/eyebrow,
/decl/emote/visible/twitch,
/decl/emote/visible/dance,
/decl/emote/visible/twitch_v,
/decl/emote/visible/faint,
/decl/emote/visible/frown,
/decl/emote/visible/blush,
/decl/emote/visible/wave,
/decl/emote/visible/glare,
/decl/emote/visible/stare,
/decl/emote/visible/look,
/decl/emote/visible/point,
/decl/emote/visible/raise,
/decl/emote/visible/grin,
/decl/emote/visible/shrug,
/decl/emote/visible/smile,
/decl/emote/visible/pale,
/decl/emote/visible/tremble,
/decl/emote/visible/wink,
/decl/emote/visible/hug,
/decl/emote/visible/signal,
/decl/emote/visible/afold,
/decl/emote/visible/alook,
/decl/emote/visible/eroll,
/decl/emote/visible/hbow,
/decl/emote/visible/hip,
/decl/emote/visible/holdup,
/decl/emote/visible/hshrug,
/decl/emote/visible/crub,
/decl/emote/visible/erub,
/decl/emote/visible/fslap,
/decl/emote/visible/ftap,
/decl/emote/visible/hrub,
/decl/emote/visible/hspread,
/decl/emote/visible/rsalute,
/decl/emote/visible/rshoulder,
/decl/emote/visible/squint,
/decl/emote/visible/tfist,
/decl/emote/visible/tilt,
/decl/emote/visible/spin,
/decl/emote/visible/sidestep,
/decl/emote/visible/vomit,
/decl/emote/visible/floorspin,
/decl/emote/visible/flip,
/decl/emote/audible/awoo,
/decl/emote/audible/awoo2,
/decl/emote/audible/belch,
/decl/emote/audible/growl,
/decl/emote/audible/woof,
/decl/emote/audible/woof2,
/decl/emote/audible/nya,
/decl/emote/audible/mrowl,
/decl/emote/audible/peep,
/decl/emote/audible/chirp,
/decl/emote/audible/hoot,
/decl/emote/audible/weh,
/decl/emote/audible/merp,
/decl/emote/audible/myarp,
/decl/emote/audible/bark,
/decl/emote/audible/bork,
/decl/emote/audible/mrow,
/decl/emote/audible/hypno,
/decl/emote/audible/hiss,
/decl/emote/audible/rattle,
/decl/emote/audible/squeak,
/decl/emote/audible/geck,
/decl/emote/audible/baa,
/decl/emote/audible/baa2,
/decl/emote/audible/mar,
/decl/emote/audible/wurble,
/decl/emote/audible/snort,
/decl/emote/audible/meow,
/decl/emote/audible/moo,
/decl/emote/audible/croak,
/decl/emote/audible/gao,
/decl/emote/audible/cackle,
/decl/emote/audible/squish,
/decl/emote/audible/spiderchitter,
/decl/emote/audible/spiderpurr,
/decl/emote/audible/squeaky,
/decl/emote/visible/mlem,
/decl/emote/visible/blep,
/decl/emote/audible/prbt,
/decl/emote/audible/gyoh,
/decl/emote/audible/rumble,
/decl/emote/audible/fennecscream,
/decl/emote/audible/zoom,
/decl/emote/audible/bug_hiss,
/decl/emote/audible/bug_buzz,
/decl/emote/audible/bug_chitter,
/decl/emote/audible/hiss,
/decl/emote/audible/chirp,
/decl/emote/audible/warble,
/decl/emote/audible/vox_shriek,
/decl/emote/audible/purr,
/decl/emote/audible/purrlong,
/decl/emote/audible/dook
)
//VOREStation Add End
/mob/living/carbon/human/get_available_emotes()
. = global._human_default_emotes.Copy()
if(length(species?.default_emotes))
return . | species.default_emotes
/mob/living/simple_mob/get_available_emotes()
. = global._simple_mob_default_emotes.Copy()
/mob/living/carbon/human/verb/pose()
set name = "Set Pose"
set desc = "Sets a description which will be shown when someone examines you."
set category = "IC"
var/datum/gender/T = gender_datums[get_visible_gender()]
pose = strip_html_simple(tgui_input_text(usr, "This is [src]. [T.he]...", "Pose", null))
/mob/living/carbon/human/verb/set_flavor()
set name = "Set Flavour Text"
set desc = "Sets an extended description of your character's features."
set category = "IC"
var/HTML = "<body>"
HTML += "<tt><center>"
HTML += "<b>Update Flavour Text</b> <hr />"
HTML += "<br></center>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=general'>General:</a> "
HTML += TextPreview(flavor_texts["general"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=head'>Head:</a> "
HTML += TextPreview(flavor_texts["head"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=face'>Face:</a> "
HTML += TextPreview(flavor_texts["face"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=eyes'>Eyes:</a> "
HTML += TextPreview(flavor_texts["eyes"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=torso'>Body:</a> "
HTML += TextPreview(flavor_texts["torso"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=arms'>Arms:</a> "
HTML += TextPreview(flavor_texts["arms"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=hands'>Hands:</a> "
HTML += TextPreview(flavor_texts["hands"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=legs'>Legs:</a> "
HTML += TextPreview(flavor_texts["legs"])
HTML += "<br>"
HTML += "<a href='byond://?src=\ref[src];flavor_change=feet'>Feet:</a> "
HTML += TextPreview(flavor_texts["feet"])
HTML += "<br>"
HTML += "<hr />"
HTML +="<a href='?src=\ref[src];flavor_change=done'>\[Done\]</a>"
HTML += "<tt>"
src << browse(HTML, "window=flavor_changes;size=430x300")
/mob/living/carbon/human/proc/toggle_tail(var/setting,var/message = 0)
if(!tail_style || !tail_style.ani_state)
if(message)
to_chat(src, "<span class='warning'>You don't have a tail that supports this.</span>")
return 0
var/new_wagging = isnull(setting) ? !wagging : setting
if(new_wagging != wagging)
wagging = new_wagging
update_tail_showing()
return 1
/mob/living/carbon/human/proc/toggle_wing(var/setting,var/message = 0)
if(!wing_style || !wing_style.ani_state)
if(message)
to_chat(src, "<span class='warning'>You don't have a wingtype that supports this.</span>")
return 0
var/new_flapping = isnull(setting) ? !flapping : setting
if(new_flapping != flapping)
flapping = new_flapping
update_wing_showing()
return 1
+468 -468
View File
@@ -1,468 +1,468 @@
/mob/living/carbon/human/examine(mob/user)
// . = ..() //Note that we don't call parent. We build the list by ourselves.
var/skip_gear = 0
var/skip_body = 0
if(alpha <= EFFECTIVE_INVIS)
return src.loc.examine(user) // Returns messages as if they examined wherever the human was
var/looks_synth = looksSynthetic()
//exosuits and helmets obscure our view and stuff.
if(wear_suit)
if(wear_suit.flags_inv & HIDESUITSTORAGE)
skip_gear |= EXAMINE_SKIPSUITSTORAGE
if(wear_suit.flags_inv & HIDEJUMPSUIT)
skip_body |= EXAMINE_SKIPARMS | EXAMINE_SKIPLEGS | EXAMINE_SKIPBODY | EXAMINE_SKIPGROIN
skip_gear |= EXAMINE_SKIPJUMPSUIT | EXAMINE_SKIPTIE | EXAMINE_SKIPHOLSTER
else if(wear_suit.flags_inv & HIDETIE)
skip_gear |= EXAMINE_SKIPTIE | EXAMINE_SKIPHOLSTER
else if(wear_suit.flags_inv & HIDEHOLSTER)
skip_gear |= EXAMINE_SKIPHOLSTER
if(wear_suit.flags_inv & HIDESHOES)
skip_gear |= EXAMINE_SKIPSHOES
skip_body |= EXAMINE_SKIPFEET
if(wear_suit.flags_inv & HIDEGLOVES)
skip_gear |= EXAMINE_SKIPGLOVES
skip_body |= EXAMINE_SKIPHANDS
if(w_uniform)
if(w_uniform.body_parts_covered & LEGS)
skip_body |= EXAMINE_SKIPLEGS
if(w_uniform.body_parts_covered & ARMS)
skip_body |= EXAMINE_SKIPARMS
if(w_uniform.body_parts_covered & UPPER_TORSO)
skip_body |= EXAMINE_SKIPBODY
if(w_uniform.body_parts_covered & LOWER_TORSO)
skip_body |= EXAMINE_SKIPGROIN
if(gloves && (gloves.body_parts_covered & HANDS))
skip_body |= EXAMINE_SKIPHANDS
if(shoes && (shoes.body_parts_covered & FEET))
skip_body |= EXAMINE_SKIPFEET
if(head)
if(head.flags_inv & HIDEMASK)
skip_gear |= EXAMINE_SKIPMASK
if(head.flags_inv & HIDEEYES)
skip_gear |= EXAMINE_SKIPEYEWEAR
skip_body |= EXAMINE_SKIPEYES
if(head.flags_inv & HIDEEARS)
skip_gear |= EXAMINE_SKIPEARS
if(head.flags_inv & HIDEFACE)
skip_body |= EXAMINE_SKIPFACE
if(wear_mask && (wear_mask.flags_inv & HIDEFACE))
skip_body |= EXAMINE_SKIPFACE
//This is what hides what
var/list/hidden = list(
BP_GROIN = skip_body & EXAMINE_SKIPGROIN,
BP_TORSO = skip_body & EXAMINE_SKIPBODY,
BP_HEAD = skip_body & EXAMINE_SKIPHEAD,
BP_L_ARM = skip_body & EXAMINE_SKIPARMS,
BP_R_ARM = skip_body & EXAMINE_SKIPARMS,
BP_L_HAND= skip_body & EXAMINE_SKIPHANDS,
BP_R_HAND= skip_body & EXAMINE_SKIPHANDS,
BP_L_FOOT= skip_body & EXAMINE_SKIPFEET,
BP_R_FOOT= skip_body & EXAMINE_SKIPFEET,
BP_L_LEG = skip_body & EXAMINE_SKIPLEGS,
BP_R_LEG = skip_body & EXAMINE_SKIPLEGS)
var/gender_hidden = (skip_gear & EXAMINE_SKIPJUMPSUIT) && (skip_body & EXAMINE_SKIPFACE)
var/gender_key = get_visible_gender(user, gender_hidden)
var/datum/gender/T = gender_datums[gender_key]
if (!T)
CRASH({"Null gender datum on examine: mob="[src]",hidden="[gender_hidden]",key="[gender_key]",bio="[gender]",id="[identifying_gender]""})
var/name_ender = ""
if(!((skip_gear & EXAMINE_SKIPJUMPSUIT) && (skip_body & EXAMINE_SKIPFACE)))
//VOREStation Add Start
if(custom_species)
name_ender = ", a <b>[src.custom_species]</b>"
else if(looks_synth)
//VOREStation Add End
var/use_gender = "a synthetic"
if(gender == MALE)
use_gender = "an android"
else if(gender == FEMALE)
use_gender = "a gynoid"
name_ender = ", <b><font color='#555555'>[use_gender]!</font></b>[species.get_additional_examine_text(src)]"
else if(species.name != "Human")
name_ender = ", <b><font color='[species.get_flesh_colour(src)]'>\a [species.get_examine_name()]!</font></b>[species.get_additional_examine_text(src)]"
var/list/msg = list("<span class='info'>*---------*","This is \icon[src.examine_icon()][bicon(src)] <EM>[src.name]</EM>[name_ender]")
//uniform
if(w_uniform && !(skip_gear & EXAMINE_SKIPJUMPSUIT) && w_uniform.show_examine)
//Ties
var/tie_msg
var/tie_msg_warn
if(istype(w_uniform,/obj/item/clothing/under) && !(skip_gear & EXAMINE_SKIPTIE))
var/obj/item/clothing/under/U = w_uniform
if(LAZYLEN(U.accessories))
tie_msg += ". Attached to it is"
tie_msg_warn += "! Attached to it is"
var/list/accessory_descs = list()
if(skip_gear & EXAMINE_SKIPHOLSTER)
for(var/obj/item/clothing/accessory/A in U.accessories)
if(A.show_examine && !istype(A, /obj/item/clothing/accessory/holster)) // If we're supposed to skip holsters, actually skip them
accessory_descs += "\a [A]"
else
for(var/obj/item/clothing/accessory/A in U.accessories)
if(A.concealed_holster == 0 && A.show_examine)
accessory_descs += "<a href='?src=\ref[src];lookitem_desc_only=\ref[A]'>\a [A]</a>"
tie_msg += " [lowertext(english_list(accessory_descs))]."
if(w_uniform.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[w_uniform][bicon(w_uniform)] [w_uniform.gender==PLURAL?"some":"a"] [(w_uniform.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[w_uniform]'>[w_uniform.name]</a>![tie_msg]</span>"
else
msg += "[T.He] [T.is] wearing [bicon(w_uniform)] <a href='?src=\ref[src];lookitem_desc_only=\ref[w_uniform]'>\a [w_uniform]</a>.[tie_msg]"
//head
if(head && !(skip_gear & EXAMINE_SKIPHELMET) && head.show_examine)
if(head.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[w_uniform][bicon(head)] [head.gender==PLURAL?"some":"a"] [(head.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[head]'>[head.name]</a> on [T.his] head!</span>"
else
msg += "[T.He] [T.is] wearing [bicon(head)] <a href='?src=\ref[src];lookitem_desc_only=\ref[head]'>\a [head]</a> on [T.his] head."
//suit/armour
if(wear_suit)
var/tie_msg
var/tie_msg_warn
if(istype(wear_suit,/obj/item/clothing/suit))
var/obj/item/clothing/suit/U = wear_suit
if(LAZYLEN(U.accessories))
tie_msg += ". Attached to it is"
tie_msg_warn += "! Attached to it is"
var/list/accessory_descs = list()
for(var/accessory in U.accessories)
accessory_descs += "<a href='?src=\ref[src];lookitem_desc_only=\ref[accessory]'>\a [accessory]</a>"
tie_msg += " [lowertext(english_list(accessory_descs))]."
if(wear_suit.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[wear_suit][bicon(wear_suit)] [wear_suit.gender==PLURAL?"some":"a"] [(wear_suit.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_suit]'>[wear_suit.name]</a>![tie_msg]</span>"
else
msg += "[T.He] [T.is] wearing \icon[wear_suit][bicon(wear_suit)] <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_suit]'>\a [wear_suit]</a>.[tie_msg]"
//suit/armour storage
if(s_store && !(skip_gear & EXAMINE_SKIPSUITSTORAGE) && s_store.show_examine)
if(s_store.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] carrying \icon[s_store][bicon(s_store)] [s_store.gender==PLURAL?"some":"a"] [(s_store.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[s_store]'>[s_store.name]</a> on [T.his] [wear_suit.name]!</span>"
else
msg += "[T.He] [T.is] carrying \icon[s_store][bicon(s_store)] <a href='?src=\ref[src];lookitem_desc_only=\ref[s_store]'>\a [s_store]</a> on [T.his] [wear_suit.name]."
//back
if(back && !(skip_gear & EXAMINE_SKIPBACKPACK) && back.show_examine)
if(back.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[back][bicon(back)] [back.gender==PLURAL?"some":"a"] [(back.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[back]'>[back]</a> on [T.his] back.</span>"
else
msg += "[T.He] [T.has] \icon[back][bicon(back)] <a href='?src=\ref[src];lookitem_desc_only=\ref[back]'>\a [back]</a> on [T.his] back."
//left hand
if(l_hand && l_hand.show_examine)
if(l_hand.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] holding \icon[l_hand][bicon(l_hand)] [l_hand.gender==PLURAL?"some":"a"] [(l_hand.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[l_hand]'>[l_hand.name]</a> in [T.his] left hand!</span>"
else
msg += "[T.He] [T.is] holding \icon[l_hand][bicon(l_hand)] <a href='?src=\ref[src];lookitem_desc_only=\ref[l_hand]'>\a [l_hand]</a> in [T.his] left hand."
//right hand
if(r_hand && r_hand.show_examine)
if(r_hand.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] holding \icon[r_hand][bicon(r_hand)] [r_hand.gender==PLURAL?"some":"a"] [(r_hand.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[r_hand]'>[r_hand.name]</a> in [T.his] right hand!</span>"
else
msg += "[T.He] [T.is] holding \icon[r_hand][bicon(r_hand)] <a href='?src=\ref[src];lookitem_desc_only=\ref[r_hand]'>\a [r_hand]</a> in [T.his] right hand."
//gloves
if(gloves && !(skip_gear & EXAMINE_SKIPGLOVES) && gloves.show_examine)
if(gloves.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[gloves][bicon(gloves)] [gloves.gender==PLURAL?"some":"a"] [(gloves.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[gloves]'>[gloves.name]</a> on [T.his] hands!</span>"
else
msg += "[T.He] [T.has] \icon[gloves][bicon(gloves)] <a href='?src=\ref[src];lookitem_desc_only=\ref[gloves]'>\a [gloves]</a> on [T.his] hands."
else if(blood_DNA && !(skip_body & EXAMINE_SKIPHANDS))
msg += "<span class='warning'>[T.He] [T.has] [(hand_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained hands!</span>"
//handcuffed?
if(handcuffed && handcuffed.show_examine)
if(istype(handcuffed, /obj/item/weapon/handcuffs/cable))
msg += "<span class='warning'>[T.He] [T.is] \icon[handcuffed][bicon(handcuffed)] restrained with cable!</span>"
else
msg += "<span class='warning'>[T.He] [T.is] \icon[handcuffed][bicon(handcuffed)] handcuffed!</span>"
//buckled
if(buckled)
msg += "<span class='warning'>[T.He] [T.is] \icon[buckled][bicon(buckled)] buckled to [buckled]!</span>"
//belt
if(belt && !(skip_gear & EXAMINE_SKIPBELT) && belt.show_examine)
if(belt.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[belt][bicon(belt)] [belt.gender==PLURAL?"some":"a"] [(belt.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[belt]'>[belt.name]</a> about [T.his] waist!</span>"
else
msg += "[T.He] [T.has] \icon[belt][bicon(belt)] <a href='?src=\ref[src];lookitem_desc_only=\ref[belt]'>\a [belt]</a> about [T.his] waist."
//shoes
if(shoes && !(skip_gear & EXAMINE_SKIPSHOES) && shoes.show_examine)
if(shoes.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[shoes][bicon(shoes)] [shoes.gender==PLURAL?"some":"a"] [(shoes.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[shoes]'>[shoes.name]</a> on [T.his] feet!</span>"
else
msg += "[T.He] [T.is] wearing \icon[shoes][bicon(shoes)] <a href='?src=\ref[src];lookitem_desc_only=\ref[shoes]'>\a [shoes]</a> on [T.his] feet."
else if(feet_blood_DNA && !(skip_body & EXAMINE_SKIPHANDS))
msg += "<span class='warning'>[T.He] [T.has] [(feet_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained feet!</span>"
//mask
if(wear_mask && !(skip_gear & EXAMINE_SKIPMASK) && wear_mask.show_examine)
var/descriptor = "on [T.his] face"
if(istype(wear_mask, /obj/item/weapon/grenade) && check_has_mouth())
descriptor = "in [T.his] mouth"
if(wear_mask.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[wear_mask][bicon(wear_mask)] [wear_mask.gender==PLURAL?"some":"a"] [(wear_mask.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_mask]'>[wear_mask.name]</a> [descriptor]!</span>"
else
msg += "[T.He] [T.has] \icon[wear_mask][bicon(wear_mask)] <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_mask]'>\a [wear_mask]</a> [descriptor]."
//eyes
if(glasses && !(skip_gear & EXAMINE_SKIPEYEWEAR) && glasses.show_examine)
if(glasses.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[glasses][bicon(glasses)] [glasses.gender==PLURAL?"some":"a"] [(glasses.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[glasses]'>[glasses]</a> covering [T.his] eyes!</span>"
else
msg += "[T.He] [T.has] \icon[glasses][bicon(glasses)] <a href='?src=\ref[src];lookitem_desc_only=\ref[glasses]'>\a [glasses]</a> covering [T.his] eyes."
//left ear
if(l_ear && !(skip_gear & EXAMINE_SKIPEARS) && l_ear.show_examine)
msg += "[T.He] [T.has] \icon[l_ear][bicon(l_ear)] <a href='?src=\ref[src];lookitem_desc_only=\ref[l_ear]'>\a [l_ear]</a> on [T.his] left ear."
//right ear
if(r_ear && !(skip_gear & EXAMINE_SKIPEARS) && r_ear.show_examine)
msg += "[T.He] [T.has] \icon[r_ear][bicon(r_ear)] <a href='?src=\ref[src];lookitem_desc_only=\ref[r_ear]'>\a [r_ear]</a> on [T.his] right ear."
//ID
if(wear_id && wear_id.show_examine)
msg += "[T.He] [T.is] wearing \icon[wear_id][bicon(wear_id)]<a href='?src=\ref[src];lookitem_desc_only=\ref[wear_id]'>\a [wear_id]</a>."
//Jitters
if(is_jittery)
if(jitteriness >= 300)
msg += "<span class='warning'><B>[T.He] [T.is] convulsing violently!</B></span>"
else if(jitteriness >= 200)
msg += "<span class='warning'>[T.He] [T.is] extremely jittery.</span>"
else if(jitteriness >= 100)
msg += "<span class='warning'>[T.He] [T.is] twitching ever so slightly.</span>"
//splints
for(var/organ in BP_ALL)
var/obj/item/organ/external/o = get_organ(organ)
if(o && o.splinted && o.splinted.loc == o)
msg += "<span class='warning'>[T.He] [T.has] \a [o.splinted] on [T.his] [o.name]!</span>"
if(suiciding)
msg += "<span class='warning'>[T.He] appears to have commited suicide... there is no hope of recovery.</span>"
//VOREStation Add
var/list/vorestrings = list()
vorestrings += examine_weight()
vorestrings += examine_nutrition()
vorestrings += examine_bellies()
vorestrings += examine_pickup_size()
vorestrings += examine_step_size()
vorestrings += examine_nif()
vorestrings += examine_chimera()
for(var/entry in vorestrings)
if(entry == "" || entry == null)
vorestrings -= entry
msg += vorestrings
//VOREStation Add End
if(mSmallsize in mutations)
msg += "[T.He] [T.is] very short!"
if (src.stat)
msg += "<span class='warning'>[T.He] [T.is]n't responding to anything around [T.him] and seems to be asleep.</span>"
if((stat == 2 || src.losebreath) && get_dist(user, src) <= 3)
msg += "<span class='warning'>[T.He] [T.does] not appear to be breathing.</span>"
if(istype(user, /mob/living/carbon/human) && !user.stat && Adjacent(user))
user.visible_message("<b>[usr]</b> checks [src]'s pulse.", "You check [src]'s pulse.")
spawn(15)
if(isobserver(user) || (Adjacent(user) && !user.stat)) // If you're a corpse then you can't exactly check their pulse, but ghosts can see anything
if(pulse == PULSE_NONE)
to_chat(user, "<span class='deadsay'>[T.He] [T.has] no pulse[src.client ? "" : " and [T.his] soul has departed"]...</span>")
else
to_chat(user, "<span class='deadsay'>[T.He] [T.has] a pulse!</span>")
if(fire_stacks)
msg += "[T.He] [T.is] covered in some liquid."
if(on_fire)
msg += "<span class='warning'>[T.He] [T.is] on fire!.</span>"
var/ssd_msg = species.get_ssd(src)
if(ssd_msg && (!should_have_organ("brain") || has_brain()) && stat != DEAD)
if(!key)
msg += "<span class='deadsay'>[T.He] [T.is] [ssd_msg]. It doesn't look like [T.he] [T.is] waking up anytime soon.</span>"
else if(!client)
msg += "<span class='deadsay'>[T.He] [T.is] [ssd_msg].</span>"
//VOREStation Add Start
if(client && ((client.inactivity / 10) / 60 > 10)) //10 Minutes
msg += "\[Inactive for [round((client.inactivity/10)/60)] minutes\]"
else if(disconnect_time)
msg += "\[Disconnected/ghosted [round(((world.realtime - disconnect_time)/10)/60)] minutes ago\]"
//VOREStation Add End
var/list/wound_flavor_text = list()
var/list/is_bleeding = list()
var/applying_pressure = ""
for(var/organ_tag in species.has_limbs)
var/list/organ_data = species.has_limbs[organ_tag]
var/organ_descriptor = organ_data["descriptor"]
var/obj/item/organ/external/E = organs_by_name[organ_tag]
if(!E)
wound_flavor_text["[organ_descriptor]"] = "<span class='warning'><b>[T.He] [T.is] missing [T.his] [organ_descriptor].</b></span>"
else if(E.is_stump())
wound_flavor_text["[organ_descriptor]"] = "<span class='warning'><b>[T.He] [T.has] a stump where [T.his] [organ_descriptor] should be.</b></span>"
else
continue
for(var/obj/item/organ/external/temp in organs)
if(temp)
if((temp.organ_tag in hidden) && hidden[temp.organ_tag])
continue //Organ is hidden, don't talk about it
if(temp.status & ORGAN_DESTROYED)
wound_flavor_text["[temp.name]"] = "<span class='warning'><b>[T.He] [T.is] missing [T.his] [temp.name].</b></span>"
continue
if(!looks_synth && temp.robotic == ORGAN_ROBOT)
if(!(temp.brute_dam + temp.burn_dam))
wound_flavor_text["[temp.name]"] = "[T.He] [T.has] a [temp.name]."
else
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] [T.has] a [temp.name] with [temp.get_wounds_desc()]!</span>"
continue
else if(temp.wounds.len > 0 || temp.open)
if(temp.is_stump() && temp.parent_organ && organs_by_name[temp.parent_organ])
var/obj/item/organ/external/parent = organs_by_name[temp.parent_organ]
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] [T.has] [temp.get_wounds_desc()] on [T.his] [parent.name].</span>"
else
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] [T.has] [temp.get_wounds_desc()] on [T.his] [temp.name].</span>"
else
wound_flavor_text["[temp.name]"] = ""
if(temp.dislocated == 1) //VOREStation Edit Bugfix
wound_flavor_text["[temp.name]"] += "<span class='warning'>[T.His] [temp.joint] is dislocated!</span>"
if(temp.brute_dam > temp.min_broken_damage || (temp.status & (ORGAN_BROKEN | ORGAN_MUTATED)))
wound_flavor_text["[temp.name]"] += "<span class='warning'>[T.His] [temp.name] is dented and swollen!</span>"
if(temp.germ_level > INFECTION_LEVEL_TWO && !(temp.status & ORGAN_DEAD))
wound_flavor_text["[temp.name]"] += "<span class='warning'>[T.His] [temp.name] looks very infected!</span>"
else if(temp.status & ORGAN_DEAD)
wound_flavor_text["[temp.name]"] += "<span class='warning'>[T.His] [temp.name] looks rotten!</span>"
if(temp.status & ORGAN_BLEEDING)
is_bleeding["[temp.name]"] += "<span class='danger'>[T.His] [temp.name] is bleeding!</span>"
if(temp.applied_pressure == src)
applying_pressure = "<span class='info'>[T.He] is applying pressure to [T.his] [temp.name].</span>"
for(var/limb in wound_flavor_text)
var/flavor = wound_flavor_text[limb]
if(flavor)
msg += flavor
for(var/limb in is_bleeding)
var/blood = is_bleeding[limb]
if(blood)
msg += blood
for(var/implant in get_visible_implants(0))
msg += "<span class='danger'>[src] [T.has] \a [implant] sticking out of [T.his] flesh!</span>"
if(digitalcamo)
msg += "[T.He] [T.is] repulsively uncanny!"
if(hasHUD(user,"security"))
var/perpname = name
var/criminal = "None"
if(wear_id)
if(istype(wear_id, /obj/item/weapon/card/id))
var/obj/item/weapon/card/id/I = wear_id
perpname = I.registered_name
else if(istype(wear_id, /obj/item/device/pda))
var/obj/item/device/pda/P = wear_id
perpname = P.owner
for (var/datum/data/record/R in data_core.security)
if(R.fields["name"] == perpname)
criminal = R.fields["criminal"]
msg += "Criminal status: <a href='?src=\ref[src];criminal=1'>\[[criminal]\]</a>"
msg += "Security records: <a href='?src=\ref[src];secrecord=`'>\[View\]</a> <a href='?src=\ref[src];secrecordadd=`'>\[Add comment\]</a>"
if(hasHUD(user,"medical"))
var/perpname = name
var/medical = "None"
if(wear_id)
if(istype(wear_id, /obj/item/weapon/card/id))
var/obj/item/weapon/card/id/I = wear_id
perpname = I.registered_name
else if(istype(wear_id, /obj/item/device/pda))
var/obj/item/device/pda/P = wear_id
perpname = P.owner
for (var/datum/data/record/R in data_core.medical)
if (R.fields["name"] == perpname)
medical = R.fields["p_stat"]
msg += "Physical status: <a href='?src=\ref[src];medical=1'>\[[medical]\]</a>"
msg += "Medical records: <a href='?src=\ref[src];medrecord=`'>\[View\]</a> <a href='?src=\ref[src];medrecordadd=`'>\[Add comment\]</a>"
if(hasHUD(user,"best"))
msg += "Employment records: <a href='?src=\ref[src];emprecord=`'>\[View\]</a> <a href='?src=\ref[src];emprecordadd=`'>\[Add comment\]</a>"
var/flavor_text = print_flavor_text()
if(flavor_text)
msg += "[flavor_text]"
// VOREStation Start
if(custom_link)
msg += "Custom link: <span class='linkify'>[custom_link]</span>"
if(ooc_notes)
msg += "OOC Notes: <a href='?src=\ref[src];ooc_notes=1'>\[View\]</a> - <a href='?src=\ref[src];print_ooc_notes_to_chat=1'>\[Print\]</a>"
msg += "<a href='?src=\ref[src];vore_prefs=1'>\[Mechanical Vore Preferences\]</a>"
// VOREStation End
msg += "*---------*</span>"
if(applying_pressure)
msg += applying_pressure
var/show_descs = show_descriptors_to(user)
if(show_descs)
msg += "<span class='notice'>[jointext(show_descs, "<br>")]</span>"
if(pose)
if(!findtext(pose, regex("\[.?!]$"))) // Will be zero if the last character is not a member of [.?!]
pose = addtext(pose,".") //Makes sure all emotes end with a period.
msg += "<br>[T.He] [pose]" //<br> intentional, extra gap.
return msg
//Helper procedure. Called by /mob/living/carbon/human/examine() and /mob/living/carbon/human/Topic() to determine HUD access to security and medical records.
/proc/hasHUD(mob/M as mob, hudtype)
if(istype(M, /mob/living/carbon/human))
var/mob/living/carbon/human/H = M
if(hasHUD_vr(H,hudtype)) return 1 //VOREStation Add - Added records access for certain modes of omni-hud glasses
switch(hudtype)
if("security")
return istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(H.glasses, /obj/item/clothing/glasses/sunglasses/sechud)
if("medical")
return istype(H.glasses, /obj/item/clothing/glasses/hud/health)
else if(istype(M, /mob/living/silicon/robot))
var/mob/living/silicon/robot/R = M
return R.sensor_type //VOREStation Add - Borgo sensors are now binary so just have them on or off
/mob/living/carbon/human/examine(mob/user)
// . = ..() //Note that we don't call parent. We build the list by ourselves.
var/skip_gear = 0
var/skip_body = 0
if(alpha <= EFFECTIVE_INVIS)
return src.loc.examine(user) // Returns messages as if they examined wherever the human was
var/looks_synth = looksSynthetic()
//exosuits and helmets obscure our view and stuff.
if(wear_suit)
if(wear_suit.flags_inv & HIDESUITSTORAGE)
skip_gear |= EXAMINE_SKIPSUITSTORAGE
if(wear_suit.flags_inv & HIDEJUMPSUIT)
skip_body |= EXAMINE_SKIPARMS | EXAMINE_SKIPLEGS | EXAMINE_SKIPBODY | EXAMINE_SKIPGROIN
skip_gear |= EXAMINE_SKIPJUMPSUIT | EXAMINE_SKIPTIE | EXAMINE_SKIPHOLSTER
else if(wear_suit.flags_inv & HIDETIE)
skip_gear |= EXAMINE_SKIPTIE | EXAMINE_SKIPHOLSTER
else if(wear_suit.flags_inv & HIDEHOLSTER)
skip_gear |= EXAMINE_SKIPHOLSTER
if(wear_suit.flags_inv & HIDESHOES)
skip_gear |= EXAMINE_SKIPSHOES
skip_body |= EXAMINE_SKIPFEET
if(wear_suit.flags_inv & HIDEGLOVES)
skip_gear |= EXAMINE_SKIPGLOVES
skip_body |= EXAMINE_SKIPHANDS
if(w_uniform)
if(w_uniform.body_parts_covered & LEGS)
skip_body |= EXAMINE_SKIPLEGS
if(w_uniform.body_parts_covered & ARMS)
skip_body |= EXAMINE_SKIPARMS
if(w_uniform.body_parts_covered & UPPER_TORSO)
skip_body |= EXAMINE_SKIPBODY
if(w_uniform.body_parts_covered & LOWER_TORSO)
skip_body |= EXAMINE_SKIPGROIN
if(gloves && (gloves.body_parts_covered & HANDS))
skip_body |= EXAMINE_SKIPHANDS
if(shoes && (shoes.body_parts_covered & FEET))
skip_body |= EXAMINE_SKIPFEET
if(head)
if(head.flags_inv & HIDEMASK)
skip_gear |= EXAMINE_SKIPMASK
if(head.flags_inv & HIDEEYES)
skip_gear |= EXAMINE_SKIPEYEWEAR
skip_body |= EXAMINE_SKIPEYES
if(head.flags_inv & HIDEEARS)
skip_gear |= EXAMINE_SKIPEARS
if(head.flags_inv & HIDEFACE)
skip_body |= EXAMINE_SKIPFACE
if(wear_mask && (wear_mask.flags_inv & HIDEFACE))
skip_body |= EXAMINE_SKIPFACE
//This is what hides what
var/list/hidden = list(
BP_GROIN = skip_body & EXAMINE_SKIPGROIN,
BP_TORSO = skip_body & EXAMINE_SKIPBODY,
BP_HEAD = skip_body & EXAMINE_SKIPHEAD,
BP_L_ARM = skip_body & EXAMINE_SKIPARMS,
BP_R_ARM = skip_body & EXAMINE_SKIPARMS,
BP_L_HAND= skip_body & EXAMINE_SKIPHANDS,
BP_R_HAND= skip_body & EXAMINE_SKIPHANDS,
BP_L_FOOT= skip_body & EXAMINE_SKIPFEET,
BP_R_FOOT= skip_body & EXAMINE_SKIPFEET,
BP_L_LEG = skip_body & EXAMINE_SKIPLEGS,
BP_R_LEG = skip_body & EXAMINE_SKIPLEGS)
var/gender_hidden = (skip_gear & EXAMINE_SKIPJUMPSUIT) && (skip_body & EXAMINE_SKIPFACE)
var/gender_key = get_visible_gender(user, gender_hidden)
var/datum/gender/T = gender_datums[gender_key]
if (!T)
CRASH({"Null gender datum on examine: mob="[src]",hidden="[gender_hidden]",key="[gender_key]",bio="[gender]",id="[identifying_gender]""})
var/name_ender = ""
if(!((skip_gear & EXAMINE_SKIPJUMPSUIT) && (skip_body & EXAMINE_SKIPFACE)))
//VOREStation Add Start
if(custom_species)
name_ender = ", a <b>[src.custom_species]</b>"
else if(looks_synth)
//VOREStation Add End
var/use_gender = "a synthetic"
if(gender == MALE)
use_gender = "an android"
else if(gender == FEMALE)
use_gender = "a gynoid"
name_ender = ", <b><font color='#555555'>[use_gender]!</font></b>[species.get_additional_examine_text(src)]"
else if(species.name != "Human")
name_ender = ", <b><font color='[species.get_flesh_colour(src)]'>\a [species.get_examine_name()]!</font></b>[species.get_additional_examine_text(src)]"
var/list/msg = list("<span class='info'>*---------*","This is \icon[src.examine_icon()][bicon(src)] <EM>[src.name]</EM>[name_ender]")
//uniform
if(w_uniform && !(skip_gear & EXAMINE_SKIPJUMPSUIT) && w_uniform.show_examine)
//Ties
var/tie_msg
var/tie_msg_warn
if(istype(w_uniform,/obj/item/clothing/under) && !(skip_gear & EXAMINE_SKIPTIE))
var/obj/item/clothing/under/U = w_uniform
if(LAZYLEN(U.accessories))
tie_msg += ". Attached to it is"
tie_msg_warn += "! Attached to it is"
var/list/accessory_descs = list()
if(skip_gear & EXAMINE_SKIPHOLSTER)
for(var/obj/item/clothing/accessory/A in U.accessories)
if(A.show_examine && !istype(A, /obj/item/clothing/accessory/holster)) // If we're supposed to skip holsters, actually skip them
accessory_descs += "\a [A]"
else
for(var/obj/item/clothing/accessory/A in U.accessories)
if(A.concealed_holster == 0 && A.show_examine)
accessory_descs += "<a href='?src=\ref[src];lookitem_desc_only=\ref[A]'>\a [A]</a>"
tie_msg += " [lowertext(english_list(accessory_descs))]."
if(w_uniform.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[w_uniform][bicon(w_uniform)] [w_uniform.gender==PLURAL?"some":"a"] [(w_uniform.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[w_uniform]'>[w_uniform.name]</a>![tie_msg]</span>"
else
msg += "[T.He] [T.is] wearing [bicon(w_uniform)] <a href='?src=\ref[src];lookitem_desc_only=\ref[w_uniform]'>\a [w_uniform]</a>.[tie_msg]"
//head
if(head && !(skip_gear & EXAMINE_SKIPHELMET) && head.show_examine)
if(head.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[w_uniform][bicon(head)] [head.gender==PLURAL?"some":"a"] [(head.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[head]'>[head.name]</a> on [T.his] head!</span>"
else
msg += "[T.He] [T.is] wearing [bicon(head)] <a href='?src=\ref[src];lookitem_desc_only=\ref[head]'>\a [head]</a> on [T.his] head."
//suit/armour
if(wear_suit)
var/tie_msg
var/tie_msg_warn
if(istype(wear_suit,/obj/item/clothing/suit))
var/obj/item/clothing/suit/U = wear_suit
if(LAZYLEN(U.accessories))
tie_msg += ". Attached to it is"
tie_msg_warn += "! Attached to it is"
var/list/accessory_descs = list()
for(var/accessory in U.accessories)
accessory_descs += "<a href='?src=\ref[src];lookitem_desc_only=\ref[accessory]'>\a [accessory]</a>"
tie_msg += " [lowertext(english_list(accessory_descs))]."
if(wear_suit.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[wear_suit][bicon(wear_suit)] [wear_suit.gender==PLURAL?"some":"a"] [(wear_suit.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_suit]'>[wear_suit.name]</a>![tie_msg]</span>"
else
msg += "[T.He] [T.is] wearing \icon[wear_suit][bicon(wear_suit)] <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_suit]'>\a [wear_suit]</a>.[tie_msg]"
//suit/armour storage
if(s_store && !(skip_gear & EXAMINE_SKIPSUITSTORAGE) && s_store.show_examine)
if(s_store.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] carrying \icon[s_store][bicon(s_store)] [s_store.gender==PLURAL?"some":"a"] [(s_store.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[s_store]'>[s_store.name]</a> on [T.his] [wear_suit.name]!</span>"
else
msg += "[T.He] [T.is] carrying \icon[s_store][bicon(s_store)] <a href='?src=\ref[src];lookitem_desc_only=\ref[s_store]'>\a [s_store]</a> on [T.his] [wear_suit.name]."
//back
if(back && !(skip_gear & EXAMINE_SKIPBACKPACK) && back.show_examine)
if(back.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[back][bicon(back)] [back.gender==PLURAL?"some":"a"] [(back.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[back]'>[back]</a> on [T.his] back.</span>"
else
msg += "[T.He] [T.has] \icon[back][bicon(back)] <a href='?src=\ref[src];lookitem_desc_only=\ref[back]'>\a [back]</a> on [T.his] back."
//left hand
if(l_hand && l_hand.show_examine)
if(l_hand.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] holding \icon[l_hand][bicon(l_hand)] [l_hand.gender==PLURAL?"some":"a"] [(l_hand.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[l_hand]'>[l_hand.name]</a> in [T.his] left hand!</span>"
else
msg += "[T.He] [T.is] holding \icon[l_hand][bicon(l_hand)] <a href='?src=\ref[src];lookitem_desc_only=\ref[l_hand]'>\a [l_hand]</a> in [T.his] left hand."
//right hand
if(r_hand && r_hand.show_examine)
if(r_hand.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] holding \icon[r_hand][bicon(r_hand)] [r_hand.gender==PLURAL?"some":"a"] [(r_hand.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[r_hand]'>[r_hand.name]</a> in [T.his] right hand!</span>"
else
msg += "[T.He] [T.is] holding \icon[r_hand][bicon(r_hand)] <a href='?src=\ref[src];lookitem_desc_only=\ref[r_hand]'>\a [r_hand]</a> in [T.his] right hand."
//gloves
if(gloves && !(skip_gear & EXAMINE_SKIPGLOVES) && gloves.show_examine)
if(gloves.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[gloves][bicon(gloves)] [gloves.gender==PLURAL?"some":"a"] [(gloves.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[gloves]'>[gloves.name]</a> on [T.his] hands!</span>"
else
msg += "[T.He] [T.has] \icon[gloves][bicon(gloves)] <a href='?src=\ref[src];lookitem_desc_only=\ref[gloves]'>\a [gloves]</a> on [T.his] hands."
else if(blood_DNA && !(skip_body & EXAMINE_SKIPHANDS))
msg += "<span class='warning'>[T.He] [T.has] [(hand_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained hands!</span>"
//handcuffed?
if(handcuffed && handcuffed.show_examine)
if(istype(handcuffed, /obj/item/weapon/handcuffs/cable))
msg += "<span class='warning'>[T.He] [T.is] \icon[handcuffed][bicon(handcuffed)] restrained with cable!</span>"
else
msg += "<span class='warning'>[T.He] [T.is] \icon[handcuffed][bicon(handcuffed)] handcuffed!</span>"
//buckled
if(buckled)
msg += "<span class='warning'>[T.He] [T.is] \icon[buckled][bicon(buckled)] buckled to [buckled]!</span>"
//belt
if(belt && !(skip_gear & EXAMINE_SKIPBELT) && belt.show_examine)
if(belt.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[belt][bicon(belt)] [belt.gender==PLURAL?"some":"a"] [(belt.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[belt]'>[belt.name]</a> about [T.his] waist!</span>"
else
msg += "[T.He] [T.has] \icon[belt][bicon(belt)] <a href='?src=\ref[src];lookitem_desc_only=\ref[belt]'>\a [belt]</a> about [T.his] waist."
//shoes
if(shoes && !(skip_gear & EXAMINE_SKIPSHOES) && shoes.show_examine)
if(shoes.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[shoes][bicon(shoes)] [shoes.gender==PLURAL?"some":"a"] [(shoes.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[shoes]'>[shoes.name]</a> on [T.his] feet!</span>"
else
msg += "[T.He] [T.is] wearing \icon[shoes][bicon(shoes)] <a href='?src=\ref[src];lookitem_desc_only=\ref[shoes]'>\a [shoes]</a> on [T.his] feet."
else if(feet_blood_DNA && !(skip_body & EXAMINE_SKIPHANDS))
msg += "<span class='warning'>[T.He] [T.has] [(feet_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained feet!</span>"
//mask
if(wear_mask && !(skip_gear & EXAMINE_SKIPMASK) && wear_mask.show_examine)
var/descriptor = "on [T.his] face"
if(istype(wear_mask, /obj/item/weapon/grenade) && check_has_mouth())
descriptor = "in [T.his] mouth"
if(wear_mask.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[wear_mask][bicon(wear_mask)] [wear_mask.gender==PLURAL?"some":"a"] [(wear_mask.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_mask]'>[wear_mask.name]</a> [descriptor]!</span>"
else
msg += "[T.He] [T.has] \icon[wear_mask][bicon(wear_mask)] <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_mask]'>\a [wear_mask]</a> [descriptor]."
//eyes
if(glasses && !(skip_gear & EXAMINE_SKIPEYEWEAR) && glasses.show_examine)
if(glasses.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[glasses][bicon(glasses)] [glasses.gender==PLURAL?"some":"a"] [(glasses.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[glasses]'>[glasses]</a> covering [T.his] eyes!</span>"
else
msg += "[T.He] [T.has] \icon[glasses][bicon(glasses)] <a href='?src=\ref[src];lookitem_desc_only=\ref[glasses]'>\a [glasses]</a> covering [T.his] eyes."
//left ear
if(l_ear && !(skip_gear & EXAMINE_SKIPEARS) && l_ear.show_examine)
msg += "[T.He] [T.has] \icon[l_ear][bicon(l_ear)] <a href='?src=\ref[src];lookitem_desc_only=\ref[l_ear]'>\a [l_ear]</a> on [T.his] left ear."
//right ear
if(r_ear && !(skip_gear & EXAMINE_SKIPEARS) && r_ear.show_examine)
msg += "[T.He] [T.has] \icon[r_ear][bicon(r_ear)] <a href='?src=\ref[src];lookitem_desc_only=\ref[r_ear]'>\a [r_ear]</a> on [T.his] right ear."
//ID
if(wear_id && wear_id.show_examine)
msg += "[T.He] [T.is] wearing \icon[wear_id][bicon(wear_id)]<a href='?src=\ref[src];lookitem_desc_only=\ref[wear_id]'>\a [wear_id]</a>."
//Jitters
if(is_jittery)
if(jitteriness >= 300)
msg += "<span class='warning'><B>[T.He] [T.is] convulsing violently!</B></span>"
else if(jitteriness >= 200)
msg += "<span class='warning'>[T.He] [T.is] extremely jittery.</span>"
else if(jitteriness >= 100)
msg += "<span class='warning'>[T.He] [T.is] twitching ever so slightly.</span>"
//splints
for(var/organ in BP_ALL)
var/obj/item/organ/external/o = get_organ(organ)
if(o && o.splinted && o.splinted.loc == o)
msg += "<span class='warning'>[T.He] [T.has] \a [o.splinted] on [T.his] [o.name]!</span>"
if(suiciding)
msg += "<span class='warning'>[T.He] appears to have commited suicide... there is no hope of recovery.</span>"
//VOREStation Add
var/list/vorestrings = list()
vorestrings += examine_weight()
vorestrings += examine_nutrition()
vorestrings += examine_bellies()
vorestrings += examine_pickup_size()
vorestrings += examine_step_size()
vorestrings += examine_nif()
vorestrings += examine_chimera()
for(var/entry in vorestrings)
if(entry == "" || entry == null)
vorestrings -= entry
msg += vorestrings
//VOREStation Add End
if(mSmallsize in mutations)
msg += "[T.He] [T.is] very short!"
if (src.stat)
msg += "<span class='warning'>[T.He] [T.is]n't responding to anything around [T.him] and seems to be asleep.</span>"
if((stat == 2 || src.losebreath) && get_dist(user, src) <= 3)
msg += "<span class='warning'>[T.He] [T.does] not appear to be breathing.</span>"
if(istype(user, /mob/living/carbon/human) && !user.stat && Adjacent(user))
user.visible_message("<b>[usr]</b> checks [src]'s pulse.", "You check [src]'s pulse.")
spawn(15)
if(isobserver(user) || (Adjacent(user) && !user.stat)) // If you're a corpse then you can't exactly check their pulse, but ghosts can see anything
if(pulse == PULSE_NONE)
to_chat(user, "<span class='deadsay'>[T.He] [T.has] no pulse[src.client ? "" : " and [T.his] soul has departed"]...</span>")
else
to_chat(user, "<span class='deadsay'>[T.He] [T.has] a pulse!</span>")
if(fire_stacks)
msg += "[T.He] [T.is] covered in some liquid."
if(on_fire)
msg += "<span class='warning'>[T.He] [T.is] on fire!.</span>"
var/ssd_msg = species.get_ssd(src)
if(ssd_msg && (!should_have_organ("brain") || has_brain()) && stat != DEAD)
if(!key)
msg += "<span class='deadsay'>[T.He] [T.is] [ssd_msg]. It doesn't look like [T.he] [T.is] waking up anytime soon.</span>"
else if(!client)
msg += "<span class='deadsay'>[T.He] [T.is] [ssd_msg].</span>"
//VOREStation Add Start
if(client && ((client.inactivity / 10) / 60 > 10)) //10 Minutes
msg += "\[Inactive for [round((client.inactivity/10)/60)] minutes\]"
else if(disconnect_time)
msg += "\[Disconnected/ghosted [round(((world.realtime - disconnect_time)/10)/60)] minutes ago\]"
//VOREStation Add End
var/list/wound_flavor_text = list()
var/list/is_bleeding = list()
var/applying_pressure = ""
for(var/organ_tag in species.has_limbs)
var/list/organ_data = species.has_limbs[organ_tag]
var/organ_descriptor = organ_data["descriptor"]
var/obj/item/organ/external/E = organs_by_name[organ_tag]
if(!E)
wound_flavor_text["[organ_descriptor]"] = "<span class='warning'><b>[T.He] [T.is] missing [T.his] [organ_descriptor].</b></span>"
else if(E.is_stump())
wound_flavor_text["[organ_descriptor]"] = "<span class='warning'><b>[T.He] [T.has] a stump where [T.his] [organ_descriptor] should be.</b></span>"
else
continue
for(var/obj/item/organ/external/temp in organs)
if(temp)
if((temp.organ_tag in hidden) && hidden[temp.organ_tag])
continue //Organ is hidden, don't talk about it
if(temp.status & ORGAN_DESTROYED)
wound_flavor_text["[temp.name]"] = "<span class='warning'><b>[T.He] [T.is] missing [T.his] [temp.name].</b></span>"
continue
if(!looks_synth && temp.robotic == ORGAN_ROBOT)
if(!(temp.brute_dam + temp.burn_dam))
wound_flavor_text["[temp.name]"] = "[T.He] [T.has] a [temp.name]."
else
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] [T.has] a [temp.name] with [temp.get_wounds_desc()]!</span>"
continue
else if(temp.wounds.len > 0 || temp.open)
if(temp.is_stump() && temp.parent_organ && organs_by_name[temp.parent_organ])
var/obj/item/organ/external/parent = organs_by_name[temp.parent_organ]
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] [T.has] [temp.get_wounds_desc()] on [T.his] [parent.name].</span>"
else
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] [T.has] [temp.get_wounds_desc()] on [T.his] [temp.name].</span>"
else
wound_flavor_text["[temp.name]"] = ""
if(temp.dislocated == 1) //VOREStation Edit Bugfix
wound_flavor_text["[temp.name]"] += "<span class='warning'>[T.His] [temp.joint] is dislocated!</span>"
if(temp.brute_dam > temp.min_broken_damage || (temp.status & (ORGAN_BROKEN | ORGAN_MUTATED)))
wound_flavor_text["[temp.name]"] += "<span class='warning'>[T.His] [temp.name] is dented and swollen!</span>"
if(temp.germ_level > INFECTION_LEVEL_TWO && !(temp.status & ORGAN_DEAD))
wound_flavor_text["[temp.name]"] += "<span class='warning'>[T.His] [temp.name] looks very infected!</span>"
else if(temp.status & ORGAN_DEAD)
wound_flavor_text["[temp.name]"] += "<span class='warning'>[T.His] [temp.name] looks rotten!</span>"
if(temp.status & ORGAN_BLEEDING)
is_bleeding["[temp.name]"] += "<span class='danger'>[T.His] [temp.name] is bleeding!</span>"
if(temp.applied_pressure == src)
applying_pressure = "<span class='info'>[T.He] is applying pressure to [T.his] [temp.name].</span>"
for(var/limb in wound_flavor_text)
var/flavor = wound_flavor_text[limb]
if(flavor)
msg += flavor
for(var/limb in is_bleeding)
var/blood = is_bleeding[limb]
if(blood)
msg += blood
for(var/implant in get_visible_implants(0))
msg += "<span class='danger'>[src] [T.has] \a [implant] sticking out of [T.his] flesh!</span>"
if(digitalcamo)
msg += "[T.He] [T.is] repulsively uncanny!"
if(hasHUD(user,"security"))
var/perpname = name
var/criminal = "None"
if(wear_id)
if(istype(wear_id, /obj/item/weapon/card/id))
var/obj/item/weapon/card/id/I = wear_id
perpname = I.registered_name
else if(istype(wear_id, /obj/item/device/pda))
var/obj/item/device/pda/P = wear_id
perpname = P.owner
for (var/datum/data/record/R in data_core.security)
if(R.fields["name"] == perpname)
criminal = R.fields["criminal"]
msg += "Criminal status: <a href='?src=\ref[src];criminal=1'>\[[criminal]\]</a>"
msg += "Security records: <a href='?src=\ref[src];secrecord=`'>\[View\]</a> <a href='?src=\ref[src];secrecordadd=`'>\[Add comment\]</a>"
if(hasHUD(user,"medical"))
var/perpname = name
var/medical = "None"
if(wear_id)
if(istype(wear_id, /obj/item/weapon/card/id))
var/obj/item/weapon/card/id/I = wear_id
perpname = I.registered_name
else if(istype(wear_id, /obj/item/device/pda))
var/obj/item/device/pda/P = wear_id
perpname = P.owner
for (var/datum/data/record/R in data_core.medical)
if (R.fields["name"] == perpname)
medical = R.fields["p_stat"]
msg += "Physical status: <a href='?src=\ref[src];medical=1'>\[[medical]\]</a>"
msg += "Medical records: <a href='?src=\ref[src];medrecord=`'>\[View\]</a> <a href='?src=\ref[src];medrecordadd=`'>\[Add comment\]</a>"
if(hasHUD(user,"best"))
msg += "Employment records: <a href='?src=\ref[src];emprecord=`'>\[View\]</a> <a href='?src=\ref[src];emprecordadd=`'>\[Add comment\]</a>"
var/flavor_text = print_flavor_text()
if(flavor_text)
msg += "[flavor_text]"
// VOREStation Start
if(custom_link)
msg += "Custom link: <span class='linkify'>[custom_link]</span>"
if(ooc_notes)
msg += "OOC Notes: <a href='?src=\ref[src];ooc_notes=1'>\[View\]</a> - <a href='?src=\ref[src];print_ooc_notes_to_chat=1'>\[Print\]</a>"
msg += "<a href='?src=\ref[src];vore_prefs=1'>\[Mechanical Vore Preferences\]</a>"
// VOREStation End
msg += "*---------*</span>"
if(applying_pressure)
msg += applying_pressure
var/show_descs = show_descriptors_to(user)
if(show_descs)
msg += "<span class='notice'>[jointext(show_descs, "<br>")]</span>"
if(pose)
if(!findtext(pose, regex("\[.?!]$"))) // Will be zero if the last character is not a member of [.?!]
pose = addtext(pose,".") //Makes sure all emotes end with a period.
msg += "<br>[T.He] [pose]" //<br> intentional, extra gap.
return msg
//Helper procedure. Called by /mob/living/carbon/human/examine() and /mob/living/carbon/human/Topic() to determine HUD access to security and medical records.
/proc/hasHUD(mob/M as mob, hudtype)
if(istype(M, /mob/living/carbon/human))
var/mob/living/carbon/human/H = M
if(hasHUD_vr(H,hudtype)) return 1 //VOREStation Add - Added records access for certain modes of omni-hud glasses
switch(hudtype)
if("security")
return istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(H.glasses, /obj/item/clothing/glasses/sunglasses/sechud)
if("medical")
return istype(H.glasses, /obj/item/clothing/glasses/hud/health)
else if(istype(M, /mob/living/silicon/robot))
var/mob/living/silicon/robot/R = M
return R.sensor_type //VOREStation Add - Borgo sensors are now binary so just have them on or off
File diff suppressed because it is too large Load Diff
@@ -1,479 +1,479 @@
/mob/living/carbon/human
var/datum/unarmed_attack/default_attack
/mob/living/carbon/human/proc/get_unarmed_attack(var/mob/living/carbon/human/target, var/hit_zone)
// VOREStation Edit - Begin
if(nif && nif.flag_check(NIF_C_HARDCLAWS,NIF_FLAGS_COMBAT)){return unarmed_hardclaws}
if(src.default_attack && src.default_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
var/datum/unarmed_attack/soft_type = src.default_attack.get_sparring_variant()
if(soft_type)
return soft_type
return src.default_attack
// VOREStation Edit - End
if(src.gloves)
var/obj/item/clothing/gloves/G = src.gloves
if(istype(G) && G.special_attack && G.special_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
var/datum/unarmed_attack/soft_type = G.special_attack.get_sparring_variant()
if(soft_type)
return soft_type
return G.special_attack
if(src.default_attack && src.default_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
var/datum/unarmed_attack/soft_type = src.default_attack.get_sparring_variant()
if(soft_type)
return soft_type
return src.default_attack
for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks)
if(u_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
var/datum/unarmed_attack/soft_variant = u_attack.get_sparring_variant()
if(soft_variant)
return soft_variant
return u_attack
return null
/mob/living/carbon/human/attack_hand(mob/living/M as mob)
var/datum/gender/TT = gender_datums[M.get_visible_gender()]
var/mob/living/carbon/human/H = M
if(istype(H))
var/obj/item/organ/external/temp = H.organs_by_name["r_hand"]
if(H.hand)
temp = H.organs_by_name["l_hand"]
if(!temp || !temp.is_usable())
to_chat(H, "<span class='warning'>You can't use your hand.</span>")
return
if(H.lying)
return
M.break_cloak()
..()
// Should this all be in Touch()?
if(istype(H))
if(H.get_accuracy_penalty() && H != src) //Should only trigger if they're not aiming well
var/hit_zone = get_zone_with_miss_chance(H.zone_sel.selecting, src, H.get_accuracy_penalty())
if(!hit_zone)
H.do_attack_animation(src)
playsound(src, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='filter_combat'>[span_red("<B>[H] reaches for [src], but misses!</B>")]</span>")
return FALSE
if(H != src && check_shields(0, null, H, H.zone_sel.selecting, H.name))
H.do_attack_animation(src)
return FALSE
if(istype(M,/mob/living/carbon))
var/mob/living/carbon/C = M
C.spread_disease_to(src, "Contact")
switch(M.a_intent)
if(I_HELP)
// VOREStation Edit - Begin
if (istype(H) && attempt_to_scoop(H))
return 0;
// VOREStation Edit - End
if(istype(H) && health < config.health_threshold_crit)
if(!H.check_has_mouth())
to_chat(H, "<span class='danger'>You don't have a mouth, you cannot perform CPR!</span>")
return
if(!check_has_mouth())
to_chat(H, "<span class='danger'>They don't have a mouth, you cannot perform CPR!</span>")
return
if((H.head && (H.head.body_parts_covered & FACE)) || (H.wear_mask && (H.wear_mask.body_parts_covered & FACE)))
to_chat(H, "<span class='notice'>Remove your mask!</span>")
return 0
if((head && (head.body_parts_covered & FACE)) || (wear_mask && (wear_mask.body_parts_covered & FACE)))
to_chat(H, "<span class='notice'>Remove [src]'s mask!</span>")
return 0
if (!cpr_time)
return 0
cpr_time = 0
spawn(30)
cpr_time = 1
H.visible_message("<span class='danger'>\The [H] is trying to perform CPR on \the [src]!</span>")
if(!do_after(H, 30))
return
H.visible_message("<span class='danger'>\The [H] performs CPR on \the [src]!</span>")
to_chat(H, "<span class='warning'>Repeat at least every 7 seconds.</span>")
if(istype(H) && health > config.health_threshold_dead)
adjustOxyLoss(-(min(getOxyLoss(), 5)))
updatehealth()
to_chat(src, "<span class='notice'>You feel a breath of fresh air enter your lungs. It feels good.</span>")
else if(!(M == src && apply_pressure(M, M.zone_sel.selecting)))
help_shake_act(M)
return TRUE
if(I_GRAB)
if(M == src || anchored)
return 0
for(var/obj/item/weapon/grab/G in src.grabbed_by)
if(G.assailant == M)
to_chat(M, "<span class='notice'>You already grabbed [src].</span>")
return
if(w_uniform)
w_uniform.add_fingerprint(M)
var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src)
if(buckled)
to_chat(M, "<span class='notice'>You cannot grab [src], [TT.he] is buckled in!</span>")
return
if(!G) //the grab will delete itself in New if affecting is anchored
return
M.put_in_active_hand(G)
G.synch()
LAssailant = M
H.do_attack_animation(src)
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
//VORESTATION EDIT
visible_message("<span class='warning'>[M] has grabbed [src] [(M.zone_sel.selecting == BP_L_HAND || M.zone_sel.selecting == BP_R_HAND)? "by [(gender==FEMALE)? "her" : ((gender==MALE)? "his": "their")] hands": "passively"]!</span>")
//VORESTATION END END
return TRUE
if(I_HURT)
if(M.zone_sel.selecting == "mouth" && wear_mask && istype(wear_mask, /obj/item/weapon/grenade))
var/obj/item/weapon/grenade/G = wear_mask
if(!G.active)
visible_message("<span class='danger'>\The [M] pulls the pin from \the [src]'s [G.name]!</span>")
G.activate(M)
update_inv_wear_mask()
else
to_chat(M, "<span class='warning'>\The [G] is already primed! Run!</span>")
return
if(!istype(H))
attack_generic(H,rand(1,3),"punched")
return
var/rand_damage = rand(1, 5)
var/block = 0
var/accurate = 0
var/hit_zone = H.zone_sel.selecting
var/obj/item/organ/external/affecting = get_organ(hit_zone)
if(!affecting || affecting.is_stump())
to_chat(M, "<span class='danger'>They are missing that limb!</span>")
return TRUE
switch(src.a_intent)
if(I_HELP)
// We didn't see this coming, so we get the full blow
rand_damage = 5
accurate = 1
if(I_HURT, I_GRAB)
// We're in a fighting stance, there's a chance we block
if(src.canmove && src!=H && prob(20))
block = 1
if (M.grabbed_by.len)
// Someone got a good grip on them, they won't be able to do much damage
rand_damage = max(1, rand_damage - 2)
if(src.grabbed_by.len || src.buckled || !src.canmove || src==H)
accurate = 1 // certain circumstances make it impossible for us to evade punches
rand_damage = 5
// Process evasion and blocking
var/miss_type = 0
var/attack_message
if(!accurate)
/* ~Hubblenaut
This place is kind of convoluted and will need some explaining.
ran_zone() will pick out of 11 zones, thus the chance for hitting
our target where we want to hit them is circa 9.1%.
Now since we want to statistically hit our target organ a bit more
often than other organs, we add a base chance of 20% for hitting it.
This leaves us with the following chances:
If aiming for chest:
27.3% chance you hit your target organ
70.5% chance you hit a random other organ
2.2% chance you miss
If aiming for something else:
23.2% chance you hit your target organ
56.8% chance you hit a random other organ
15.0% chance you miss
Note: We don't use get_zone_with_miss_chance() here since the chances
were made for projectiles.
TODO: proc for melee combat miss chances depending on organ?
*/
if(!hit_zone)
attack_message = "[H] attempted to strike [src], but missed!"
miss_type = 1
if(prob(80))
hit_zone = ran_zone(hit_zone, 70) //70% chance to hit what you're aiming at seems fair?
if(prob(15) && hit_zone != BP_TORSO) // Missed!
if(!src.lying)
attack_message = "[H] attempted to strike [src], but missed!"
else
attack_message = "[H] attempted to strike [src], but [TT.he] rolled out of the way!"
src.set_dir(pick(cardinal))
miss_type = 1
if(!miss_type && block)
attack_message = "[H] went for [src]'s [affecting.name] but was blocked!"
miss_type = 2
// See what attack they use
var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, hit_zone)
if(!attack)
return FALSE
if(attack.unarmed_override(H, src, hit_zone))
return FALSE
H.do_attack_animation(src)
if(!attack_message)
attack.show_attack(H, src, hit_zone, rand_damage)
else
H.visible_message("<span class='danger'>[attack_message]</span>")
playsound(src, ((miss_type) ? (miss_type == 1 ? attack.miss_sound : 'sound/weapons/thudswoosh.ogg') : attack.attack_sound), 25, 1, -1)
add_attack_logs(H,src,"Melee attacked with fists (miss/block)")
if(miss_type)
return FALSE
var/real_damage = rand_damage
var/hit_dam_type = attack.damage_type
real_damage += attack.get_unarmed_damage(H)
if(H.gloves)
if(istype(H.gloves, /obj/item/clothing/gloves))
var/obj/item/clothing/gloves/G = H.gloves
real_damage += G.punch_force
hit_dam_type = G.punch_damtype
if(H.pulling_punches && !attack.sharp && !attack.edge) //SO IT IS DECREED: PULLING PUNCHES WILL PREVENT THE ACTUAL DAMAGE FROM RINGS AND KNUCKLES, BUT NOT THE ADDED PAIN, BUT YOU CAN'T "PULL" A KNIFE
hit_dam_type = AGONY
real_damage *= damage_multiplier
rand_damage *= damage_multiplier
if(HULK in H.mutations)
real_damage *= 2 // Hulks do twice the damage
rand_damage *= 2
real_damage = max(1, real_damage)
var/armour = run_armor_check(hit_zone, "melee")
var/soaked = get_armor_soak(hit_zone, "melee")
// Apply additional unarmed effects.
attack.apply_effects(H, src, armour, rand_damage, hit_zone)
// Finally, apply damage to target
apply_damage(real_damage, hit_dam_type, hit_zone, armour, soaked, sharp=attack.sharp, edge=attack.edge)
if(I_DISARM)
add_attack_logs(H,src,"Disarmed")
M.do_attack_animation(src)
if(w_uniform)
w_uniform.add_fingerprint(M)
var/obj/item/organ/external/affecting = get_organ(ran_zone(M.zone_sel.selecting))
var/list/holding = list(get_active_hand() = 40, get_inactive_hand = 20)
//See if they have any guns that might go off
for(var/obj/item/weapon/gun/W in holding)
if(W && prob(holding[W]))
var/list/turfs = list()
for(var/turf/T in view())
turfs += T
if(turfs.len)
var/turf/target = pick(turfs)
visible_message("<span class='danger'>[src]'s [W] goes off during the struggle!</span>")
return W.afterattack(target,src)
if(last_push_time + 30 > world.time)
visible_message("<span class='warning'>[M] has weakly pushed [src]!</span>")
return
var/randn = rand(1, 100)
last_push_time = world.time
// We ARE wearing shoes OR
// We as a species CAN be slipped when barefoot
// And also 1 in 4 because rngesus
if((shoes || !(species.flags & NO_SLIP)) && randn <= 25)
var/armor_check = run_armor_check(affecting, "melee")
apply_effect(3, WEAKEN, armor_check)
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if(armor_check < 60)
visible_message("<span class='danger'>[M] has pushed [src]!</span>")
else
visible_message("<span class='warning'>[M] attempted to push [src]!</span>")
return
if(randn <= 60)
//See about breaking grips or pulls
if(break_all_grabs(M))
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
return
//Actually disarm them
for(var/obj/item/I in holding)
if(I)
drop_from_inventory(I)
visible_message("<span class='danger'>[M] has disarmed [src]!</span>")
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
return
playsound(src, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='filter_combat'>[span_red("<B>[M] attempted to disarm [src]!</B>")]</span>")
return
/mob/living/carbon/human/proc/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, inrange, params)
return
/mob/living/carbon/human/attack_generic(var/mob/user, var/damage, var/attack_message, var/armor_type = "melee", var/armor_pen = 0, var/a_sharp = 0, var/a_edge = 0)
if(!damage)
return
add_attack_logs(user,src,"Melee attacked with fists (miss/block)",admin_notify = FALSE) //No admin notice since this is usually fighting simple animals
src.visible_message("<span class='danger'>[user] has [attack_message] [src]!</span>")
user.do_attack_animation(src)
var/dam_zone = pick(organs_by_name)
var/obj/item/organ/external/affecting = get_organ(ran_zone(dam_zone))
var/armor_block = run_armor_check(affecting, armor_type, armor_pen)
var/armor_soak = get_armor_soak(affecting, armor_type, armor_pen)
apply_damage(damage, BRUTE, affecting, armor_block, armor_soak, sharp = a_sharp, edge = a_edge)
updatehealth()
return TRUE
//Used to attack a joint through grabbing
/mob/living/carbon/human/proc/grab_joint(var/mob/living/user, var/def_zone)
var/has_grab = 0
for(var/obj/item/weapon/grab/G in list(user.l_hand, user.r_hand))
if(G.affecting == src && G.state == GRAB_NECK)
has_grab = 1
break
if(!has_grab)
return FALSE
if(!def_zone) def_zone = user.zone_sel.selecting
var/target_zone = check_zone(def_zone)
if(!target_zone)
return FALSE
var/obj/item/organ/external/organ = get_organ(check_zone(target_zone))
if(!organ || organ.dislocated > 0 || organ.dislocated == -1) //don't use is_dislocated() here, that checks parent
return FALSE
user.visible_message("<span class='warning'>[user] begins to dislocate [src]'s [organ.joint]!</span>")
if(do_after(user, 100))
organ.dislocate(1)
src.visible_message("<span class='danger'>[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!</span>")
return TRUE
return FALSE
//Breaks all grips and pulls that the mob currently has.
/mob/living/carbon/human/proc/break_all_grabs(mob/living/carbon/user)
var/success = FALSE
if(pulling)
visible_message("<span class='danger'>[user] has broken [src]'s grip on [pulling]!</span>")
success = TRUE
stop_pulling()
if(istype(l_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/lgrab = l_hand
if(lgrab.affecting)
visible_message("<span class='danger'>[user] has broken [src]'s grip on [lgrab.affecting]!</span>")
success = TRUE
spawn(1)
qdel(lgrab)
if(istype(r_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/rgrab = r_hand
if(rgrab.affecting)
visible_message("<span class='danger'>[user] has broken [src]'s grip on [rgrab.affecting]!</span>")
success = TRUE
spawn(1)
qdel(rgrab)
return success
/*
We want to ensure that a mob may only apply pressure to one organ of one mob at any given time. Currently this is done mostly implicitly through
the behaviour of do_after() and the fact that applying pressure to someone else requires a grab:
If you are applying pressure to yourself and attempt to grab someone else, you'll change what you are holding in your active hand which will stop do_mob()
If you are applying pressure to another and attempt to apply pressure to yourself, you'll have to switch to an empty hand which will also stop do_mob()
Changing targeted zones should also stop do_mob(), preventing you from applying pressure to more than one body part at once.
*/
/mob/living/carbon/human/proc/apply_pressure(mob/living/user, var/target_zone)
var/obj/item/organ/external/organ = get_organ(target_zone)
if(!organ || !(organ.status & ORGAN_BLEEDING) || (organ.robotic >= ORGAN_ROBOT))
return FALSE
if(organ.applied_pressure)
var/message = "<span class='warning'>Someone is already applying pressure to [user == src ? "your [organ.name]" : "[src]'s [organ.name]"].</span>"
to_chat(user,message)
return FALSE
var/datum/gender/TU = gender_datums[user.get_visible_gender()]
if(user == src)
user.visible_message("<span class='filter_notice'>\The [user] starts applying pressure to [TU.his] [organ.name]!</span>", "<span class='filter_notice'>You start applying pressure to your [organ.name]!</span>")
else
user.visible_message("<span class='filter_notice'>\The [user] starts applying pressure to [src]'s [organ.name]!</span>", "<span class='filter_notice'>You start applying pressure to [src]'s [organ.name]!</span>")
spawn(0)
organ.applied_pressure = user
//apply pressure as long as they stay still and keep grabbing
do_mob(user, src, INFINITY, target_zone, progress = 0)
organ.applied_pressure = null
if(user == src)
user.visible_message("\<span class='filter_notice'>The [user] stops applying pressure to [TU.his] [organ.name]!</span>", "<span class='filter_notice'>You stop applying pressure to your [organ]!</span>")
else
user.visible_message("<span class='filter_notice'>\The [user] stops applying pressure to [src]'s [organ.name]!</span>", "<span class='filter_notice'>You stop applying pressure to [src]'s [organ.name]!</span>")
return TRUE
/mob/living/carbon/human/verb/check_attacks()
set name = "Check Attacks"
set category = "IC"
set src = usr
var/dat = "<b><font size = 5>Known Attacks</font></b><br/><br/>"
if(default_attack)
dat += "Current default attack: [default_attack.attack_name] - <a href='byond://?src=\ref[src];default_attk=reset_attk'>reset</a><br/><br/>"
for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks)
if(u_attack == default_attack)
dat += "<b>Primarily [u_attack.attack_name]</b> - default - <a href='byond://?src=\ref[src];default_attk=reset_attk'>reset</a><br/><br/><br/>"
else
dat += "<b>Primarily [u_attack.attack_name]</b> - <a href='byond://?src=\ref[src];default_attk=\ref[u_attack]'>set default</a><br/><br/><br/>"
src << browse(dat, "window=checkattack")
/mob/living/carbon/human/Topic(href, href_list)
if(href_list["default_attk"])
if(href_list["default_attk"] == "reset_attk")
set_default_attack(null)
else
var/datum/unarmed_attack/u_attack = locate(href_list["default_attk"])
if(u_attack && (u_attack in species.unarmed_attacks))
set_default_attack(u_attack)
check_attacks()
return 1
else
return ..()
/mob/living/carbon/human/proc/set_default_attack(var/datum/unarmed_attack/u_attack)
default_attack = u_attack
/mob/living/carbon/human
var/datum/unarmed_attack/default_attack
/mob/living/carbon/human/proc/get_unarmed_attack(var/mob/living/carbon/human/target, var/hit_zone)
// VOREStation Edit - Begin
if(nif && nif.flag_check(NIF_C_HARDCLAWS,NIF_FLAGS_COMBAT)){return unarmed_hardclaws}
if(src.default_attack && src.default_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
var/datum/unarmed_attack/soft_type = src.default_attack.get_sparring_variant()
if(soft_type)
return soft_type
return src.default_attack
// VOREStation Edit - End
if(src.gloves)
var/obj/item/clothing/gloves/G = src.gloves
if(istype(G) && G.special_attack && G.special_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
var/datum/unarmed_attack/soft_type = G.special_attack.get_sparring_variant()
if(soft_type)
return soft_type
return G.special_attack
if(src.default_attack && src.default_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
var/datum/unarmed_attack/soft_type = src.default_attack.get_sparring_variant()
if(soft_type)
return soft_type
return src.default_attack
for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks)
if(u_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
var/datum/unarmed_attack/soft_variant = u_attack.get_sparring_variant()
if(soft_variant)
return soft_variant
return u_attack
return null
/mob/living/carbon/human/attack_hand(mob/living/M as mob)
var/datum/gender/TT = gender_datums[M.get_visible_gender()]
var/mob/living/carbon/human/H = M
if(istype(H))
var/obj/item/organ/external/temp = H.organs_by_name["r_hand"]
if(H.hand)
temp = H.organs_by_name["l_hand"]
if(!temp || !temp.is_usable())
to_chat(H, "<span class='warning'>You can't use your hand.</span>")
return
if(H.lying)
return
M.break_cloak()
..()
// Should this all be in Touch()?
if(istype(H))
if(H.get_accuracy_penalty() && H != src) //Should only trigger if they're not aiming well
var/hit_zone = get_zone_with_miss_chance(H.zone_sel.selecting, src, H.get_accuracy_penalty())
if(!hit_zone)
H.do_attack_animation(src)
playsound(src, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='filter_combat'>[span_red("<B>[H] reaches for [src], but misses!</B>")]</span>")
return FALSE
if(H != src && check_shields(0, null, H, H.zone_sel.selecting, H.name))
H.do_attack_animation(src)
return FALSE
if(istype(M,/mob/living/carbon))
var/mob/living/carbon/C = M
C.spread_disease_to(src, "Contact")
switch(M.a_intent)
if(I_HELP)
// VOREStation Edit - Begin
if (istype(H) && attempt_to_scoop(H))
return 0;
// VOREStation Edit - End
if(istype(H) && health < config.health_threshold_crit)
if(!H.check_has_mouth())
to_chat(H, "<span class='danger'>You don't have a mouth, you cannot perform CPR!</span>")
return
if(!check_has_mouth())
to_chat(H, "<span class='danger'>They don't have a mouth, you cannot perform CPR!</span>")
return
if((H.head && (H.head.body_parts_covered & FACE)) || (H.wear_mask && (H.wear_mask.body_parts_covered & FACE)))
to_chat(H, "<span class='notice'>Remove your mask!</span>")
return 0
if((head && (head.body_parts_covered & FACE)) || (wear_mask && (wear_mask.body_parts_covered & FACE)))
to_chat(H, "<span class='notice'>Remove [src]'s mask!</span>")
return 0
if (!cpr_time)
return 0
cpr_time = 0
spawn(30)
cpr_time = 1
H.visible_message("<span class='danger'>\The [H] is trying to perform CPR on \the [src]!</span>")
if(!do_after(H, 30))
return
H.visible_message("<span class='danger'>\The [H] performs CPR on \the [src]!</span>")
to_chat(H, "<span class='warning'>Repeat at least every 7 seconds.</span>")
if(istype(H) && health > config.health_threshold_dead)
adjustOxyLoss(-(min(getOxyLoss(), 5)))
updatehealth()
to_chat(src, "<span class='notice'>You feel a breath of fresh air enter your lungs. It feels good.</span>")
else if(!(M == src && apply_pressure(M, M.zone_sel.selecting)))
help_shake_act(M)
return TRUE
if(I_GRAB)
if(M == src || anchored)
return 0
for(var/obj/item/weapon/grab/G in src.grabbed_by)
if(G.assailant == M)
to_chat(M, "<span class='notice'>You already grabbed [src].</span>")
return
if(w_uniform)
w_uniform.add_fingerprint(M)
var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src)
if(buckled)
to_chat(M, "<span class='notice'>You cannot grab [src], [TT.he] is buckled in!</span>")
return
if(!G) //the grab will delete itself in New if affecting is anchored
return
M.put_in_active_hand(G)
G.synch()
LAssailant = M
H.do_attack_animation(src)
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
//VORESTATION EDIT
visible_message("<span class='warning'>[M] has grabbed [src] [(M.zone_sel.selecting == BP_L_HAND || M.zone_sel.selecting == BP_R_HAND)? "by [(gender==FEMALE)? "her" : ((gender==MALE)? "his": "their")] hands": "passively"]!</span>")
//VORESTATION END END
return TRUE
if(I_HURT)
if(M.zone_sel.selecting == "mouth" && wear_mask && istype(wear_mask, /obj/item/weapon/grenade))
var/obj/item/weapon/grenade/G = wear_mask
if(!G.active)
visible_message("<span class='danger'>\The [M] pulls the pin from \the [src]'s [G.name]!</span>")
G.activate(M)
update_inv_wear_mask()
else
to_chat(M, "<span class='warning'>\The [G] is already primed! Run!</span>")
return
if(!istype(H))
attack_generic(H,rand(1,3),"punched")
return
var/rand_damage = rand(1, 5)
var/block = 0
var/accurate = 0
var/hit_zone = H.zone_sel.selecting
var/obj/item/organ/external/affecting = get_organ(hit_zone)
if(!affecting || affecting.is_stump())
to_chat(M, "<span class='danger'>They are missing that limb!</span>")
return TRUE
switch(src.a_intent)
if(I_HELP)
// We didn't see this coming, so we get the full blow
rand_damage = 5
accurate = 1
if(I_HURT, I_GRAB)
// We're in a fighting stance, there's a chance we block
if(src.canmove && src!=H && prob(20))
block = 1
if (M.grabbed_by.len)
// Someone got a good grip on them, they won't be able to do much damage
rand_damage = max(1, rand_damage - 2)
if(src.grabbed_by.len || src.buckled || !src.canmove || src==H)
accurate = 1 // certain circumstances make it impossible for us to evade punches
rand_damage = 5
// Process evasion and blocking
var/miss_type = 0
var/attack_message
if(!accurate)
/* ~Hubblenaut
This place is kind of convoluted and will need some explaining.
ran_zone() will pick out of 11 zones, thus the chance for hitting
our target where we want to hit them is circa 9.1%.
Now since we want to statistically hit our target organ a bit more
often than other organs, we add a base chance of 20% for hitting it.
This leaves us with the following chances:
If aiming for chest:
27.3% chance you hit your target organ
70.5% chance you hit a random other organ
2.2% chance you miss
If aiming for something else:
23.2% chance you hit your target organ
56.8% chance you hit a random other organ
15.0% chance you miss
Note: We don't use get_zone_with_miss_chance() here since the chances
were made for projectiles.
TODO: proc for melee combat miss chances depending on organ?
*/
if(!hit_zone)
attack_message = "[H] attempted to strike [src], but missed!"
miss_type = 1
if(prob(80))
hit_zone = ran_zone(hit_zone, 70) //70% chance to hit what you're aiming at seems fair?
if(prob(15) && hit_zone != BP_TORSO) // Missed!
if(!src.lying)
attack_message = "[H] attempted to strike [src], but missed!"
else
attack_message = "[H] attempted to strike [src], but [TT.he] rolled out of the way!"
src.set_dir(pick(cardinal))
miss_type = 1
if(!miss_type && block)
attack_message = "[H] went for [src]'s [affecting.name] but was blocked!"
miss_type = 2
// See what attack they use
var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, hit_zone)
if(!attack)
return FALSE
if(attack.unarmed_override(H, src, hit_zone))
return FALSE
H.do_attack_animation(src)
if(!attack_message)
attack.show_attack(H, src, hit_zone, rand_damage)
else
H.visible_message("<span class='danger'>[attack_message]</span>")
playsound(src, ((miss_type) ? (miss_type == 1 ? attack.miss_sound : 'sound/weapons/thudswoosh.ogg') : attack.attack_sound), 25, 1, -1)
add_attack_logs(H,src,"Melee attacked with fists (miss/block)")
if(miss_type)
return FALSE
var/real_damage = rand_damage
var/hit_dam_type = attack.damage_type
real_damage += attack.get_unarmed_damage(H)
if(H.gloves)
if(istype(H.gloves, /obj/item/clothing/gloves))
var/obj/item/clothing/gloves/G = H.gloves
real_damage += G.punch_force
hit_dam_type = G.punch_damtype
if(H.pulling_punches && !attack.sharp && !attack.edge) //SO IT IS DECREED: PULLING PUNCHES WILL PREVENT THE ACTUAL DAMAGE FROM RINGS AND KNUCKLES, BUT NOT THE ADDED PAIN, BUT YOU CAN'T "PULL" A KNIFE
hit_dam_type = AGONY
real_damage *= damage_multiplier
rand_damage *= damage_multiplier
if(HULK in H.mutations)
real_damage *= 2 // Hulks do twice the damage
rand_damage *= 2
real_damage = max(1, real_damage)
var/armour = run_armor_check(hit_zone, "melee")
var/soaked = get_armor_soak(hit_zone, "melee")
// Apply additional unarmed effects.
attack.apply_effects(H, src, armour, rand_damage, hit_zone)
// Finally, apply damage to target
apply_damage(real_damage, hit_dam_type, hit_zone, armour, soaked, sharp=attack.sharp, edge=attack.edge)
if(I_DISARM)
add_attack_logs(H,src,"Disarmed")
M.do_attack_animation(src)
if(w_uniform)
w_uniform.add_fingerprint(M)
var/obj/item/organ/external/affecting = get_organ(ran_zone(M.zone_sel.selecting))
var/list/holding = list(get_active_hand() = 40, get_inactive_hand = 20)
//See if they have any guns that might go off
for(var/obj/item/weapon/gun/W in holding)
if(W && prob(holding[W]))
var/list/turfs = list()
for(var/turf/T in view())
turfs += T
if(turfs.len)
var/turf/target = pick(turfs)
visible_message("<span class='danger'>[src]'s [W] goes off during the struggle!</span>")
return W.afterattack(target,src)
if(last_push_time + 30 > world.time)
visible_message("<span class='warning'>[M] has weakly pushed [src]!</span>")
return
var/randn = rand(1, 100)
last_push_time = world.time
// We ARE wearing shoes OR
// We as a species CAN be slipped when barefoot
// And also 1 in 4 because rngesus
if((shoes || !(species.flags & NO_SLIP)) && randn <= 25)
var/armor_check = run_armor_check(affecting, "melee")
apply_effect(3, WEAKEN, armor_check)
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if(armor_check < 60)
visible_message("<span class='danger'>[M] has pushed [src]!</span>")
else
visible_message("<span class='warning'>[M] attempted to push [src]!</span>")
return
if(randn <= 60)
//See about breaking grips or pulls
if(break_all_grabs(M))
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
return
//Actually disarm them
for(var/obj/item/I in holding)
if(I)
drop_from_inventory(I)
visible_message("<span class='danger'>[M] has disarmed [src]!</span>")
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
return
playsound(src, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='filter_combat'>[span_red("<B>[M] attempted to disarm [src]!</B>")]</span>")
return
/mob/living/carbon/human/proc/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, inrange, params)
return
/mob/living/carbon/human/attack_generic(var/mob/user, var/damage, var/attack_message, var/armor_type = "melee", var/armor_pen = 0, var/a_sharp = 0, var/a_edge = 0)
if(!damage)
return
add_attack_logs(user,src,"Melee attacked with fists (miss/block)",admin_notify = FALSE) //No admin notice since this is usually fighting simple animals
src.visible_message("<span class='danger'>[user] has [attack_message] [src]!</span>")
user.do_attack_animation(src)
var/dam_zone = pick(organs_by_name)
var/obj/item/organ/external/affecting = get_organ(ran_zone(dam_zone))
var/armor_block = run_armor_check(affecting, armor_type, armor_pen)
var/armor_soak = get_armor_soak(affecting, armor_type, armor_pen)
apply_damage(damage, BRUTE, affecting, armor_block, armor_soak, sharp = a_sharp, edge = a_edge)
updatehealth()
return TRUE
//Used to attack a joint through grabbing
/mob/living/carbon/human/proc/grab_joint(var/mob/living/user, var/def_zone)
var/has_grab = 0
for(var/obj/item/weapon/grab/G in list(user.l_hand, user.r_hand))
if(G.affecting == src && G.state == GRAB_NECK)
has_grab = 1
break
if(!has_grab)
return FALSE
if(!def_zone) def_zone = user.zone_sel.selecting
var/target_zone = check_zone(def_zone)
if(!target_zone)
return FALSE
var/obj/item/organ/external/organ = get_organ(check_zone(target_zone))
if(!organ || organ.dislocated > 0 || organ.dislocated == -1) //don't use is_dislocated() here, that checks parent
return FALSE
user.visible_message("<span class='warning'>[user] begins to dislocate [src]'s [organ.joint]!</span>")
if(do_after(user, 100))
organ.dislocate(1)
src.visible_message("<span class='danger'>[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!</span>")
return TRUE
return FALSE
//Breaks all grips and pulls that the mob currently has.
/mob/living/carbon/human/proc/break_all_grabs(mob/living/carbon/user)
var/success = FALSE
if(pulling)
visible_message("<span class='danger'>[user] has broken [src]'s grip on [pulling]!</span>")
success = TRUE
stop_pulling()
if(istype(l_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/lgrab = l_hand
if(lgrab.affecting)
visible_message("<span class='danger'>[user] has broken [src]'s grip on [lgrab.affecting]!</span>")
success = TRUE
spawn(1)
qdel(lgrab)
if(istype(r_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/rgrab = r_hand
if(rgrab.affecting)
visible_message("<span class='danger'>[user] has broken [src]'s grip on [rgrab.affecting]!</span>")
success = TRUE
spawn(1)
qdel(rgrab)
return success
/*
We want to ensure that a mob may only apply pressure to one organ of one mob at any given time. Currently this is done mostly implicitly through
the behaviour of do_after() and the fact that applying pressure to someone else requires a grab:
If you are applying pressure to yourself and attempt to grab someone else, you'll change what you are holding in your active hand which will stop do_mob()
If you are applying pressure to another and attempt to apply pressure to yourself, you'll have to switch to an empty hand which will also stop do_mob()
Changing targeted zones should also stop do_mob(), preventing you from applying pressure to more than one body part at once.
*/
/mob/living/carbon/human/proc/apply_pressure(mob/living/user, var/target_zone)
var/obj/item/organ/external/organ = get_organ(target_zone)
if(!organ || !(organ.status & ORGAN_BLEEDING) || (organ.robotic >= ORGAN_ROBOT))
return FALSE
if(organ.applied_pressure)
var/message = "<span class='warning'>Someone is already applying pressure to [user == src ? "your [organ.name]" : "[src]'s [organ.name]"].</span>"
to_chat(user,message)
return FALSE
var/datum/gender/TU = gender_datums[user.get_visible_gender()]
if(user == src)
user.visible_message("<span class='filter_notice'>\The [user] starts applying pressure to [TU.his] [organ.name]!</span>", "<span class='filter_notice'>You start applying pressure to your [organ.name]!</span>")
else
user.visible_message("<span class='filter_notice'>\The [user] starts applying pressure to [src]'s [organ.name]!</span>", "<span class='filter_notice'>You start applying pressure to [src]'s [organ.name]!</span>")
spawn(0)
organ.applied_pressure = user
//apply pressure as long as they stay still and keep grabbing
do_mob(user, src, INFINITY, target_zone, progress = 0)
organ.applied_pressure = null
if(user == src)
user.visible_message("\<span class='filter_notice'>The [user] stops applying pressure to [TU.his] [organ.name]!</span>", "<span class='filter_notice'>You stop applying pressure to your [organ]!</span>")
else
user.visible_message("<span class='filter_notice'>\The [user] stops applying pressure to [src]'s [organ.name]!</span>", "<span class='filter_notice'>You stop applying pressure to [src]'s [organ.name]!</span>")
return TRUE
/mob/living/carbon/human/verb/check_attacks()
set name = "Check Attacks"
set category = "IC"
set src = usr
var/dat = "<b><font size = 5>Known Attacks</font></b><br/><br/>"
if(default_attack)
dat += "Current default attack: [default_attack.attack_name] - <a href='byond://?src=\ref[src];default_attk=reset_attk'>reset</a><br/><br/>"
for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks)
if(u_attack == default_attack)
dat += "<b>Primarily [u_attack.attack_name]</b> - default - <a href='byond://?src=\ref[src];default_attk=reset_attk'>reset</a><br/><br/><br/>"
else
dat += "<b>Primarily [u_attack.attack_name]</b> - <a href='byond://?src=\ref[src];default_attk=\ref[u_attack]'>set default</a><br/><br/><br/>"
src << browse(dat, "window=checkattack")
/mob/living/carbon/human/Topic(href, href_list)
if(href_list["default_attk"])
if(href_list["default_attk"] == "reset_attk")
set_default_attack(null)
else
var/datum/unarmed_attack/u_attack = locate(href_list["default_attk"])
if(u_attack && (u_attack in species.unarmed_attacks))
set_default_attack(u_attack)
check_attacks()
return 1
else
return ..()
/mob/living/carbon/human/proc/set_default_attack(var/datum/unarmed_attack/u_attack)
default_attack = u_attack
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,163 +1,163 @@
/mob/living/carbon/human
//Hair colour and style
var/r_hair = 0
var/g_hair = 0
var/b_hair = 0
var/h_style = "Bald"
var/r_grad = 0
var/g_grad = 0
var/b_grad = 0
var/grad_style = "none"
//Facial hair colour and style
var/r_facial = 0
var/g_facial = 0
var/b_facial = 0
var/f_style = "Shaved"
//Eye colour
var/r_eyes = 0
var/g_eyes = 0
var/b_eyes = 0
var/s_tone = 0 //Skin tone
//Skin colour
var/r_skin = 0
var/g_skin = 0
var/b_skin = 0
var/skin_state = SKIN_NORMAL
//Synth colors
var/synth_color = 0 //Lets normally uncolorable synth parts be colorable.
var/r_synth //Used with synth_color to color synth parts that normaly can't be colored.
var/g_synth //Same as above
var/b_synth //Same as above
var/synth_markings = 0 //Enables/disables markings on synth parts.
var/digitigrade = 0 // 0 = no digi, 1 = default, 2+ = digi styles... (Not used yet)
//var/size_multiplier = 1 //multiplier for the mob's icon size //VOREStation Edit (Moved to /mob/living)
var/damage_multiplier = 1 //multiplies melee combat damage
var/icon_update = 1 //whether icon updating shall take place
var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup
var/age = 30 //Player's age (pure fluff)
var/bday_month = 0 //Character birth month
var/bday_day = 0 //Character birthday day
var/b_type = "A+" //Player's bloodtype
var/datum/robolimb/synthetic //If they are a synthetic (aka synthetic torso). Also holds the datum for the type of robolimb.
var/list/all_underwear = list()
var/list/all_underwear_metadata = list()
var/list/hide_underwear = list()
var/backbag = 2 //Which backpack type the player has chosen.
var/pdachoice = 1 //Which PDA type the player has chosen.
// General information
var/home_system = ""
var/birthplace = ""
var/citizenship = ""
var/personal_faction = ""
var/religion = ""
var/antag_faction = ""
var/antag_vis = ""
//Equipment slots
var/obj/item/wear_suit = null
var/obj/item/w_uniform = null
var/obj/item/shoes = null
var/obj/item/belt = null
var/obj/item/gloves = null
var/obj/item/glasses = null
var/obj/item/head = null
var/obj/item/l_ear = null
var/obj/item/r_ear = null
var/obj/item/wear_id = null
var/obj/item/r_store = null
var/obj/item/l_store = null
var/obj/item/s_store = null
var/used_skillpoints = 0
var/skill_specialization = null
var/list/skills = list()
var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life()
var/special_voice = "" // For changing our voice. Used by a symptom.
var/last_dam = -1 //Used for determining if we need to process all organs or just some or even none.
var/xylophone = 0 //For the spoooooooky xylophone cooldown
var/mob/remoteview_target = null
var/hand_blood_color
var/list/flavor_texts = list()
var/gunshot_residue
var/pulling_punches // Are you trying not to hurt your opponent?
var/robolimb_count = 0 // Total number of external robot parts.
var/robobody_count = 0 // Counts torso, groin, and head, if they're robotic
mob_bump_flag = HUMAN
mob_push_flags = ~HEAVY
mob_swap_flags = ~HEAVY
var/identifying_gender // In case the human identifies as another gender than it's biological
var/list/descriptors // For comparative examine code
var/step_count = 0 // Track how many footsteps have been taken to know when to play footstep sounds
can_be_antagged = TRUE
// Used by mobs in virtual reality to point back to the "real" mob the client belongs to.
var/mob/living/carbon/human/vr_holder = null
// Used by "real" mobs after they leave a VR session
var/mob/living/carbon/human/vr_link = null
var/obj/machinery/machine_visual //machine that is currently applying visual effects to this mob. Only used for camera monitors currently.
inventory_panel_type = /datum/inventory_panel/human
butchery_loot = list(/obj/item/stack/animalhide/human = 1)
// Horray Furries!
var/datum/sprite_accessory/ears/ear_style = null
var/r_ears = 30
var/g_ears = 30
var/b_ears = 30
var/r_ears2 = 30
var/g_ears2 = 30
var/b_ears2 = 30
var/r_ears3 = 30 //Trust me, we could always use more colour. No japes.
var/g_ears3 = 30
var/b_ears3 = 30
var/datum/sprite_accessory/tail/tail_style = null
var/r_tail = 30
var/g_tail = 30
var/b_tail = 30
var/r_tail2 = 30
var/g_tail2 = 30
var/b_tail2 = 30
var/r_tail3 = 30
var/g_tail3 = 30
var/b_tail3 = 30
var/datum/sprite_accessory/wing/wing_style = null
var/r_wing = 30
var/g_wing = 30
var/b_wing = 30
var/r_wing2 = 30
var/g_wing2 = 30
var/b_wing2 = 30
var/r_wing3 = 30
var/g_wing3 = 30
var/b_wing3 = 30
var/wagging = 0 //UGH.
var/flapping = 0
// Custom Species Name
var/custom_species
/mob/living/carbon/human
//Hair colour and style
var/r_hair = 0
var/g_hair = 0
var/b_hair = 0
var/h_style = "Bald"
var/r_grad = 0
var/g_grad = 0
var/b_grad = 0
var/grad_style = "none"
//Facial hair colour and style
var/r_facial = 0
var/g_facial = 0
var/b_facial = 0
var/f_style = "Shaved"
//Eye colour
var/r_eyes = 0
var/g_eyes = 0
var/b_eyes = 0
var/s_tone = 0 //Skin tone
//Skin colour
var/r_skin = 0
var/g_skin = 0
var/b_skin = 0
var/skin_state = SKIN_NORMAL
//Synth colors
var/synth_color = 0 //Lets normally uncolorable synth parts be colorable.
var/r_synth //Used with synth_color to color synth parts that normaly can't be colored.
var/g_synth //Same as above
var/b_synth //Same as above
var/synth_markings = 0 //Enables/disables markings on synth parts.
var/digitigrade = 0 // 0 = no digi, 1 = default, 2+ = digi styles... (Not used yet)
//var/size_multiplier = 1 //multiplier for the mob's icon size //VOREStation Edit (Moved to /mob/living)
var/damage_multiplier = 1 //multiplies melee combat damage
var/icon_update = 1 //whether icon updating shall take place
var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup
var/age = 30 //Player's age (pure fluff)
var/bday_month = 0 //Character birth month
var/bday_day = 0 //Character birthday day
var/b_type = "A+" //Player's bloodtype
var/datum/robolimb/synthetic //If they are a synthetic (aka synthetic torso). Also holds the datum for the type of robolimb.
var/list/all_underwear = list()
var/list/all_underwear_metadata = list()
var/list/hide_underwear = list()
var/backbag = 2 //Which backpack type the player has chosen.
var/pdachoice = 1 //Which PDA type the player has chosen.
// General information
var/home_system = ""
var/birthplace = ""
var/citizenship = ""
var/personal_faction = ""
var/religion = ""
var/antag_faction = ""
var/antag_vis = ""
//Equipment slots
var/obj/item/wear_suit = null
var/obj/item/w_uniform = null
var/obj/item/shoes = null
var/obj/item/belt = null
var/obj/item/gloves = null
var/obj/item/glasses = null
var/obj/item/head = null
var/obj/item/l_ear = null
var/obj/item/r_ear = null
var/obj/item/wear_id = null
var/obj/item/r_store = null
var/obj/item/l_store = null
var/obj/item/s_store = null
var/used_skillpoints = 0
var/skill_specialization = null
var/list/skills = list()
var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life()
var/special_voice = "" // For changing our voice. Used by a symptom.
var/last_dam = -1 //Used for determining if we need to process all organs or just some or even none.
var/xylophone = 0 //For the spoooooooky xylophone cooldown
var/mob/remoteview_target = null
var/hand_blood_color
var/list/flavor_texts = list()
var/gunshot_residue
var/pulling_punches // Are you trying not to hurt your opponent?
var/robolimb_count = 0 // Total number of external robot parts.
var/robobody_count = 0 // Counts torso, groin, and head, if they're robotic
mob_bump_flag = HUMAN
mob_push_flags = ~HEAVY
mob_swap_flags = ~HEAVY
var/identifying_gender // In case the human identifies as another gender than it's biological
var/list/descriptors // For comparative examine code
var/step_count = 0 // Track how many footsteps have been taken to know when to play footstep sounds
can_be_antagged = TRUE
// Used by mobs in virtual reality to point back to the "real" mob the client belongs to.
var/mob/living/carbon/human/vr_holder = null
// Used by "real" mobs after they leave a VR session
var/mob/living/carbon/human/vr_link = null
var/obj/machinery/machine_visual //machine that is currently applying visual effects to this mob. Only used for camera monitors currently.
inventory_panel_type = /datum/inventory_panel/human
butchery_loot = list(/obj/item/stack/animalhide/human = 1)
// Horray Furries!
var/datum/sprite_accessory/ears/ear_style = null
var/r_ears = 30
var/g_ears = 30
var/b_ears = 30
var/r_ears2 = 30
var/g_ears2 = 30
var/b_ears2 = 30
var/r_ears3 = 30 //Trust me, we could always use more colour. No japes.
var/g_ears3 = 30
var/b_ears3 = 30
var/datum/sprite_accessory/tail/tail_style = null
var/r_tail = 30
var/g_tail = 30
var/b_tail = 30
var/r_tail2 = 30
var/g_tail2 = 30
var/b_tail2 = 30
var/r_tail3 = 30
var/g_tail3 = 30
var/b_tail3 = 30
var/datum/sprite_accessory/wing/wing_style = null
var/r_wing = 30
var/g_wing = 30
var/b_wing = 30
var/r_wing2 = 30
var/g_wing2 = 30
var/b_wing2 = 30
var/r_wing3 = 30
var/g_wing3 = 30
var/b_wing3 = 30
var/wagging = 0 //UGH.
var/flapping = 0
// Custom Species Name
var/custom_species
@@ -1,304 +1,304 @@
#define HUMAN_LOWEST_SLOWDOWN -3
/mob/living/carbon/human/movement_delay(oldloc, direct)
. = 0
if (istype(loc, /turf/space))
return ..() - 1
if(species.slowdown)
. += species.slowdown
if(force_max_speed)
return ..() + HUMAN_LOWEST_SLOWDOWN
for(var/datum/modifier/M in modifiers)
if(!isnull(M.haste) && M.haste == TRUE)
return ..() + HUMAN_LOWEST_SLOWDOWN // Returning -1 will actually result in a slowdown for Teshari.
if(!isnull(M.slowdown))
. += M.slowdown
var/health_deficiency = (getMaxHealth() - health)
if(istype(src, /mob/living/carbon/human)) //VOREStation Edit Start
var/mob/living/carbon/human/H = src
health_deficiency *= H.species.trauma_mod //Species pain sensitivity does not apply to painkillers, so we apply it before
if(health_deficiency >= 40)
if(chem_effects[CE_PAINKILLER]) //On painkillers? Reduce pain! On anti-painkillers? Increase pain!
health_deficiency = max(0, health_deficiency - src.chem_effects[CE_PAINKILLER])
if(health_deficiency >= 40) //Still in enough pain for it to be significant?
. += (health_deficiency / 25) //VOREStation Edit End
if(can_feel_pain())
if(halloss >= 10) . += (halloss / 10) //halloss shouldn't slow you down if you can't even feel it
var/hungry = (500 - nutrition) / 5 //VOREStation Edit - Fixed 500 here instead of our huge MAX_NUTRITION
if (hungry >= 70) . += hungry/50
//VOREstation start
if (feral >= 10) //crazy feral animals give less and less of a shit about pain and hunger as they get crazier
. = max(species.slowdown, species.slowdown+((.-species.slowdown)/(feral/10))) // As feral scales to damage, this amounts to an effective +1 slowdown cap
if(shock_stage >= 10) . -= 1.5 //this gets a +3 later, feral critters take reduced penalty
if(riding_datum) //Bit of slowdown for taur rides if rider is bigger or fatter than mount.
var/datum/riding/R = riding_datum
var/mob/living/L = R.ridden
for(var/mob/living/M in L.buckled_mobs)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.size_multiplier > L.size_multiplier)
. += 1
//if(H.weight > L.weight) weight should not have mechanical impact
//. += 1
//VOREstation end
if(istype(buckled, /obj/structure/bed/chair/wheelchair))
for(var/organ_name in list(BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM))
var/obj/item/organ/external/E = get_organ(organ_name)
if(!E || E.is_stump())
. += 4
else if(E.splinted && E.splinted.loc != E)
. += 0.5
else if(E.status & ORGAN_BROKEN)
. += 1.5
else
for(var/organ_name in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT))
var/obj/item/organ/external/E = get_organ(organ_name)
if(!E || E.is_stump())
. += 4
else if(E.splinted && E.splinted.loc != E)
. += 0.5
else if(E.status & ORGAN_BROKEN)
. += 1.5
if(shock_stage >= 10) . += 3
if(aiming && aiming.aiming_at) . += 5 // Iron sights make you slower, it's a well-known fact.
if(FAT in src.mutations)
. += 1.5
if (bodytemperature < species.cold_level_1)
. += (species.cold_level_1 - bodytemperature) / 10 * 1.75
. += max(2 * stance_damage, 0) //damaged/missing feet or legs is slow
if(mRun in mutations)
. = 0
// Turf related slowdown
var/turf/T = get_turf(src)
. += calculate_turf_slowdown(T, direct)
// Item related slowdown.
var/item_tally = calculate_item_encumbrance()
// Dragging heavy objects will also slow you down, similar to above.
if(pulling)
if(istype(pulling, /obj/item))
var/obj/item/pulled = pulling
item_tally += max(pulled.slowdown, 0)
else if(ishuman(pulling))
var/mob/living/carbon/human/H = pulling
var/their_slowdown = max(H.calculate_item_encumbrance(), 1)
item_tally = max(item_tally, their_slowdown) // If our slowdown is less than theirs, then we become as slow as them (before species modifires).
item_tally *= species.item_slowdown_mod
. += item_tally
if(CE_SLOWDOWN in chem_effects)
if (. >= 0 )
. *= 1.25 //Add a quarter of penalties on top.
. += chem_effects[CE_SLOWDOWN]
if(CE_SPEEDBOOST in chem_effects)
if (. >= 0) // cut any penalties in half
. *= 0.5
. -= chem_effects[CE_SPEEDBOOST] // give 'em a buff on top.
. = max(HUMAN_LOWEST_SLOWDOWN, . + config.human_delay) // Minimum return should be the same as force_max_speed
. += ..()
/mob/living/carbon/human/Moved()
. = ..()
if(embedded_flag)
handle_embedded_objects() //Moving with objects stuck in you can cause bad times.
// This calculates the amount of slowdown to receive from items worn. This does NOT include species modifiers.
// It is in a seperate place to avoid an infinite loop situation with dragging mobs dragging each other.
// Also its nice to have these things seperated.
/mob/living/carbon/human/proc/calculate_item_encumbrance()
if(shoes) // Shoes can make you go faster.
if(!buckled || (buckled && istype(buckled, /obj/machinery/power/rtg/reg)))
. += shoes.slowdown
// Loop through some slots, and add up their slowdowns.
// Includes slots which can provide armor, the back slot, and suit storage.
for(var/obj/item/I in list(wear_suit, w_uniform, back, gloves, head, s_store))
. += I.slowdown
// Hands are also included, to make the 'take off your armor instantly and carry it with you to go faster' trick no longer viable.
// This is done seperately to disallow negative numbers (so you can't hold shoes in your hands to go faster).
for(var/obj/item/I in list(r_hand, l_hand) )
. += max(I.slowdown, 0)
// Similar to above, but for turf slowdown.
/mob/living/carbon/human/proc/calculate_turf_slowdown(turf/T, direct)
if(!T)
return 0
if(T.movement_cost)
var/turf_move_cost = T.movement_cost
if(istype(T, /turf/simulated/floor/water))
if(species.water_movement)
turf_move_cost = CLAMP(turf_move_cost + species.water_movement, HUMAN_LOWEST_SLOWDOWN, 15)
if(shoes)
var/obj/item/clothing/shoes/feet = shoes
if(istype(feet) && feet.water_speed)
turf_move_cost = CLAMP(turf_move_cost + feet.water_speed, HUMAN_LOWEST_SLOWDOWN, 15)
. += turf_move_cost
else if(istype(T, /turf/simulated/floor/outdoors/snow))
if(species.snow_movement)
turf_move_cost = CLAMP(turf_move_cost + species.snow_movement, HUMAN_LOWEST_SLOWDOWN, 15)
if(shoes)
var/obj/item/clothing/shoes/feet = shoes
if(istype(feet) && feet.snow_speed)
turf_move_cost = CLAMP(turf_move_cost + feet.snow_speed, HUMAN_LOWEST_SLOWDOWN, 15)
. += turf_move_cost
else
turf_move_cost = CLAMP(turf_move_cost, HUMAN_LOWEST_SLOWDOWN, 15)
. += turf_move_cost
// Wind makes it easier or harder to move, depending on if you're with or against the wind.
// I don't like that so I'm commenting it out :)
// VOREstation Edit Start
/*
if((T.is_outdoors()) && (T.z <= SSplanets.z_to_planet.len))
var/datum/planet/P = SSplanets.z_to_planet[z]
if(P)
var/datum/weather_holder/WH = P.weather_holder
if(WH && WH.wind_speed) // Is there any wind?
// With the wind.
if(direct & WH.wind_dir)
. = max(. - WH.wind_speed, -1) // Wind speedup is capped to prevent supersonic speeds from a storm.
// Against it.
else if(direct & reverse_dir[WH.wind_dir])
. += WH.wind_speed
*/
// VOREstation Edit End.
#undef HUMAN_LOWEST_SLOWDOWN
/mob/living/carbon/human/get_jetpack()
if(back)
var/obj/item/weapon/rig/rig = get_rig()
if(istype(back, /obj/item/weapon/tank/jetpack))
return back
else if(istype(rig))
for(var/obj/item/rig_module/maneuvering_jets/module in rig.installed_modules)
return module.jets
/mob/living/carbon/human/Process_Spacemove(var/check_drift = 0)
//Can we act?
if(restrained()) return 0
if(..()) //Can move due to other reasons, don't use jetpack fuel
return TRUE
if(species.can_space_freemove || (species.can_zero_g_move && !istype(get_turf(src), /turf/space))) //VOREStation Edit.
return TRUE //VOREStation Edit.
if(flying) //VOREStation Edit. If you're flying, you glide around!
return TRUE //VOREStation Edit.
//Do we have a working jetpack?
var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
if(thrust)
if(((!check_drift) || (check_drift && thrust.stabilization_on)) && (!lying) && (thrust.do_thrust(0.01, src)))
inertia_dir = 0
return TRUE
return FALSE
/mob/living/carbon/human/Process_Spaceslipping(var/prob_slip = 5)
//If knocked out we might just hit it and stop. This makes it possible to get dead bodies and such.
if(species.flags & NO_SLIP)
return FALSE
if(species.can_space_freemove || species.can_zero_g_move)
return FALSE
var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
if(thrust?.can_thrust(0.01))
return FALSE
if(stat)
prob_slip = 0 // Changing this to zero to make it line up with the comment, and also, make more sense.
//Do we have magboots or such on if so no slip
if(istype(shoes, /obj/item/clothing/shoes/magboots) && (shoes.item_flags & NOSLIP))
prob_slip = 0
//Check hands and mod slip
if(!l_hand) prob_slip -= 2
else if(l_hand.w_class <= 2) prob_slip -= 1
if (!r_hand) prob_slip -= 2
else if(r_hand.w_class <= 2) prob_slip -= 1
prob_slip = round(prob_slip)
return(prob_slip)
// Handle footstep sounds
/mob/living/carbon/human/handle_footstep(var/turf/T)
if(!istype(T))
return
if(is_incorporeal())
return
if(!config.footstep_volume || !T.footstep_sounds || !T.footstep_sounds.len)
return
// Future Upgrades - Multi species support
var/list/footstep_sounds = T.footstep_sounds["human"]
if(!footstep_sounds)
return
var/S = pick(footstep_sounds)
GLOB.step_taken_shift_roundstat++
if(!S) return
// Play every 20 steps while walking, for the sneak
if(m_intent == "walk" && step_count++ % 20 != 0)
return
// Play every other step while running
if(m_intent == "run" && step_count++ % 2 != 0)
return
var/volume = config.footstep_volume
// Reduce volume while walking or barefoot
if(!shoes || m_intent == "walk")
volume *= 0.5
else if(shoes)
var/obj/item/clothing/shoes/feet = shoes
if(istype(feet))
volume *= feet.step_volume_mod
if(!has_organ(BP_L_FOOT) && !has_organ(BP_R_FOOT))
return // no feet = no footsteps
if(buckled || lying || throwing)
return // people flying, lying down or sitting do not step
if(!has_gravity(src) && prob(75))
return // Far less likely to make noise in no gravity
playsound(T, S, volume, FALSE)
return
/mob/living/carbon/human/set_dir(var/new_dir)
. = ..()
if(. && (species.tail || tail_style))
#define HUMAN_LOWEST_SLOWDOWN -3
/mob/living/carbon/human/movement_delay(oldloc, direct)
. = 0
if (istype(loc, /turf/space))
return ..() - 1
if(species.slowdown)
. += species.slowdown
if(force_max_speed)
return ..() + HUMAN_LOWEST_SLOWDOWN
for(var/datum/modifier/M in modifiers)
if(!isnull(M.haste) && M.haste == TRUE)
return ..() + HUMAN_LOWEST_SLOWDOWN // Returning -1 will actually result in a slowdown for Teshari.
if(!isnull(M.slowdown))
. += M.slowdown
var/health_deficiency = (getMaxHealth() - health)
if(istype(src, /mob/living/carbon/human)) //VOREStation Edit Start
var/mob/living/carbon/human/H = src
health_deficiency *= H.species.trauma_mod //Species pain sensitivity does not apply to painkillers, so we apply it before
if(health_deficiency >= 40)
if(chem_effects[CE_PAINKILLER]) //On painkillers? Reduce pain! On anti-painkillers? Increase pain!
health_deficiency = max(0, health_deficiency - src.chem_effects[CE_PAINKILLER])
if(health_deficiency >= 40) //Still in enough pain for it to be significant?
. += (health_deficiency / 25) //VOREStation Edit End
if(can_feel_pain())
if(halloss >= 10) . += (halloss / 10) //halloss shouldn't slow you down if you can't even feel it
var/hungry = (500 - nutrition) / 5 //VOREStation Edit - Fixed 500 here instead of our huge MAX_NUTRITION
if (hungry >= 70) . += hungry/50
//VOREstation start
if (feral >= 10) //crazy feral animals give less and less of a shit about pain and hunger as they get crazier
. = max(species.slowdown, species.slowdown+((.-species.slowdown)/(feral/10))) // As feral scales to damage, this amounts to an effective +1 slowdown cap
if(shock_stage >= 10) . -= 1.5 //this gets a +3 later, feral critters take reduced penalty
if(riding_datum) //Bit of slowdown for taur rides if rider is bigger or fatter than mount.
var/datum/riding/R = riding_datum
var/mob/living/L = R.ridden
for(var/mob/living/M in L.buckled_mobs)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.size_multiplier > L.size_multiplier)
. += 1
//if(H.weight > L.weight) weight should not have mechanical impact
//. += 1
//VOREstation end
if(istype(buckled, /obj/structure/bed/chair/wheelchair))
for(var/organ_name in list(BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM))
var/obj/item/organ/external/E = get_organ(organ_name)
if(!E || E.is_stump())
. += 4
else if(E.splinted && E.splinted.loc != E)
. += 0.5
else if(E.status & ORGAN_BROKEN)
. += 1.5
else
for(var/organ_name in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT))
var/obj/item/organ/external/E = get_organ(organ_name)
if(!E || E.is_stump())
. += 4
else if(E.splinted && E.splinted.loc != E)
. += 0.5
else if(E.status & ORGAN_BROKEN)
. += 1.5
if(shock_stage >= 10) . += 3
if(aiming && aiming.aiming_at) . += 5 // Iron sights make you slower, it's a well-known fact.
if(FAT in src.mutations)
. += 1.5
if (bodytemperature < species.cold_level_1)
. += (species.cold_level_1 - bodytemperature) / 10 * 1.75
. += max(2 * stance_damage, 0) //damaged/missing feet or legs is slow
if(mRun in mutations)
. = 0
// Turf related slowdown
var/turf/T = get_turf(src)
. += calculate_turf_slowdown(T, direct)
// Item related slowdown.
var/item_tally = calculate_item_encumbrance()
// Dragging heavy objects will also slow you down, similar to above.
if(pulling)
if(istype(pulling, /obj/item))
var/obj/item/pulled = pulling
item_tally += max(pulled.slowdown, 0)
else if(ishuman(pulling))
var/mob/living/carbon/human/H = pulling
var/their_slowdown = max(H.calculate_item_encumbrance(), 1)
item_tally = max(item_tally, their_slowdown) // If our slowdown is less than theirs, then we become as slow as them (before species modifires).
item_tally *= species.item_slowdown_mod
. += item_tally
if(CE_SLOWDOWN in chem_effects)
if (. >= 0 )
. *= 1.25 //Add a quarter of penalties on top.
. += chem_effects[CE_SLOWDOWN]
if(CE_SPEEDBOOST in chem_effects)
if (. >= 0) // cut any penalties in half
. *= 0.5
. -= chem_effects[CE_SPEEDBOOST] // give 'em a buff on top.
. = max(HUMAN_LOWEST_SLOWDOWN, . + config.human_delay) // Minimum return should be the same as force_max_speed
. += ..()
/mob/living/carbon/human/Moved()
. = ..()
if(embedded_flag)
handle_embedded_objects() //Moving with objects stuck in you can cause bad times.
// This calculates the amount of slowdown to receive from items worn. This does NOT include species modifiers.
// It is in a seperate place to avoid an infinite loop situation with dragging mobs dragging each other.
// Also its nice to have these things seperated.
/mob/living/carbon/human/proc/calculate_item_encumbrance()
if(shoes) // Shoes can make you go faster.
if(!buckled || (buckled && istype(buckled, /obj/machinery/power/rtg/reg)))
. += shoes.slowdown
// Loop through some slots, and add up their slowdowns.
// Includes slots which can provide armor, the back slot, and suit storage.
for(var/obj/item/I in list(wear_suit, w_uniform, back, gloves, head, s_store))
. += I.slowdown
// Hands are also included, to make the 'take off your armor instantly and carry it with you to go faster' trick no longer viable.
// This is done seperately to disallow negative numbers (so you can't hold shoes in your hands to go faster).
for(var/obj/item/I in list(r_hand, l_hand) )
. += max(I.slowdown, 0)
// Similar to above, but for turf slowdown.
/mob/living/carbon/human/proc/calculate_turf_slowdown(turf/T, direct)
if(!T)
return 0
if(T.movement_cost)
var/turf_move_cost = T.movement_cost
if(istype(T, /turf/simulated/floor/water))
if(species.water_movement)
turf_move_cost = CLAMP(turf_move_cost + species.water_movement, HUMAN_LOWEST_SLOWDOWN, 15)
if(shoes)
var/obj/item/clothing/shoes/feet = shoes
if(istype(feet) && feet.water_speed)
turf_move_cost = CLAMP(turf_move_cost + feet.water_speed, HUMAN_LOWEST_SLOWDOWN, 15)
. += turf_move_cost
else if(istype(T, /turf/simulated/floor/outdoors/snow))
if(species.snow_movement)
turf_move_cost = CLAMP(turf_move_cost + species.snow_movement, HUMAN_LOWEST_SLOWDOWN, 15)
if(shoes)
var/obj/item/clothing/shoes/feet = shoes
if(istype(feet) && feet.snow_speed)
turf_move_cost = CLAMP(turf_move_cost + feet.snow_speed, HUMAN_LOWEST_SLOWDOWN, 15)
. += turf_move_cost
else
turf_move_cost = CLAMP(turf_move_cost, HUMAN_LOWEST_SLOWDOWN, 15)
. += turf_move_cost
// Wind makes it easier or harder to move, depending on if you're with or against the wind.
// I don't like that so I'm commenting it out :)
// VOREstation Edit Start
/*
if((T.is_outdoors()) && (T.z <= SSplanets.z_to_planet.len))
var/datum/planet/P = SSplanets.z_to_planet[z]
if(P)
var/datum/weather_holder/WH = P.weather_holder
if(WH && WH.wind_speed) // Is there any wind?
// With the wind.
if(direct & WH.wind_dir)
. = max(. - WH.wind_speed, -1) // Wind speedup is capped to prevent supersonic speeds from a storm.
// Against it.
else if(direct & reverse_dir[WH.wind_dir])
. += WH.wind_speed
*/
// VOREstation Edit End.
#undef HUMAN_LOWEST_SLOWDOWN
/mob/living/carbon/human/get_jetpack()
if(back)
var/obj/item/weapon/rig/rig = get_rig()
if(istype(back, /obj/item/weapon/tank/jetpack))
return back
else if(istype(rig))
for(var/obj/item/rig_module/maneuvering_jets/module in rig.installed_modules)
return module.jets
/mob/living/carbon/human/Process_Spacemove(var/check_drift = 0)
//Can we act?
if(restrained()) return 0
if(..()) //Can move due to other reasons, don't use jetpack fuel
return TRUE
if(species.can_space_freemove || (species.can_zero_g_move && !istype(get_turf(src), /turf/space))) //VOREStation Edit.
return TRUE //VOREStation Edit.
if(flying) //VOREStation Edit. If you're flying, you glide around!
return TRUE //VOREStation Edit.
//Do we have a working jetpack?
var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
if(thrust)
if(((!check_drift) || (check_drift && thrust.stabilization_on)) && (!lying) && (thrust.do_thrust(0.01, src)))
inertia_dir = 0
return TRUE
return FALSE
/mob/living/carbon/human/Process_Spaceslipping(var/prob_slip = 5)
//If knocked out we might just hit it and stop. This makes it possible to get dead bodies and such.
if(species.flags & NO_SLIP)
return FALSE
if(species.can_space_freemove || species.can_zero_g_move)
return FALSE
var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
if(thrust?.can_thrust(0.01))
return FALSE
if(stat)
prob_slip = 0 // Changing this to zero to make it line up with the comment, and also, make more sense.
//Do we have magboots or such on if so no slip
if(istype(shoes, /obj/item/clothing/shoes/magboots) && (shoes.item_flags & NOSLIP))
prob_slip = 0
//Check hands and mod slip
if(!l_hand) prob_slip -= 2
else if(l_hand.w_class <= 2) prob_slip -= 1
if (!r_hand) prob_slip -= 2
else if(r_hand.w_class <= 2) prob_slip -= 1
prob_slip = round(prob_slip)
return(prob_slip)
// Handle footstep sounds
/mob/living/carbon/human/handle_footstep(var/turf/T)
if(!istype(T))
return
if(is_incorporeal())
return
if(!config.footstep_volume || !T.footstep_sounds || !T.footstep_sounds.len)
return
// Future Upgrades - Multi species support
var/list/footstep_sounds = T.footstep_sounds["human"]
if(!footstep_sounds)
return
var/S = pick(footstep_sounds)
GLOB.step_taken_shift_roundstat++
if(!S) return
// Play every 20 steps while walking, for the sneak
if(m_intent == "walk" && step_count++ % 20 != 0)
return
// Play every other step while running
if(m_intent == "run" && step_count++ % 2 != 0)
return
var/volume = config.footstep_volume
// Reduce volume while walking or barefoot
if(!shoes || m_intent == "walk")
volume *= 0.5
else if(shoes)
var/obj/item/clothing/shoes/feet = shoes
if(istype(feet))
volume *= feet.step_volume_mod
if(!has_organ(BP_L_FOOT) && !has_organ(BP_R_FOOT))
return // no feet = no footsteps
if(buckled || lying || throwing)
return // people flying, lying down or sitting do not step
if(!has_gravity(src) && prob(75))
return // Far less likely to make noise in no gravity
playsound(T, S, volume, FALSE)
return
/mob/living/carbon/human/set_dir(var/new_dir)
. = ..()
if(. && (species.tail || tail_style))
update_tail_showing()
+444 -444
View File
@@ -1,444 +1,444 @@
/*
Add fingerprints to items when we put them in our hands.
This saves us from having to call add_fingerprint() any time something is put in a human's hands programmatically.
*/
/mob/living/carbon/human
var/list/worn_clothing = list() //Contains all CLOTHING items worn
/mob/living/carbon/human/verb/quick_equip()
set name = "quick-equip"
set hidden = 1
if(ishuman(src))
var/mob/living/carbon/human/H = src
var/obj/item/I = H.get_active_hand()
if(!I)
to_chat(H, "<span class='notice'>You are not holding anything to equip.</span>")
return
var/moved = FALSE
// Try an equipment slot
if(H.equip_to_appropriate_slot(I))
moved = TRUE
// No? Try a storage item.
else if(H.equip_to_storage(I, TRUE))
moved = TRUE
// No?! Well, give up.
if(!moved)
to_chat(H, "<span class='warning'>You are unable to equip that.</span>")
// Update hand icons
else
if(hand)
update_inv_l_hand(0)
else
update_inv_r_hand(0)
/mob/living/carbon/human/equip_to_storage(obj/item/newitem, user_initiated = FALSE)
// Try put it in their belt first
if(istype(src.belt,/obj/item/weapon/storage))
var/obj/item/weapon/storage/wornbelt = src.belt
if(wornbelt.can_be_inserted(newitem, 1))
if(user_initiated)
wornbelt.handle_item_insertion(newitem)
else
newitem.forceMove(wornbelt)
return wornbelt
return ..()
/mob/living/carbon/human/proc/equip_in_one_of_slots(obj/item/W, list/slots, del_on_fail = 1)
for (var/slot in slots)
if (equip_to_slot_if_possible(W, slots[slot], del_on_fail = 0))
return slot
if (del_on_fail)
qdel(W)
return null
/mob/living/carbon/human/proc/has_organ(name)
var/obj/item/organ/external/O = organs_by_name[name]
return (O && !O.is_stump())
/mob/living/carbon/human/proc/has_organ_for_slot(slot)
switch(slot)
if(slot_back)
return has_organ(BP_TORSO)
if(slot_wear_mask)
return has_organ(BP_HEAD)
if(slot_handcuffed)
return has_organ(BP_L_HAND) && has_organ(BP_R_HAND)
if(slot_legcuffed)
return has_organ(BP_L_FOOT) && has_organ(BP_R_FOOT)
if(slot_l_hand)
return has_organ(BP_L_HAND)
if(slot_r_hand)
return has_organ(BP_R_HAND)
if(slot_belt)
return has_organ(BP_TORSO)
if(slot_wear_id)
// the only relevant check for this is the uniform check
return 1
if(slot_l_ear)
return has_organ(BP_HEAD)
if(slot_r_ear)
return has_organ(BP_HEAD)
if(slot_glasses)
return has_organ(BP_HEAD)
if(slot_gloves)
return has_organ(BP_L_HAND) || has_organ(BP_R_HAND)
if(slot_head)
return has_organ(BP_HEAD)
if(slot_shoes)
return has_organ(BP_L_FOOT) || has_organ(BP_R_FOOT)
if(slot_wear_suit)
return has_organ(BP_TORSO)
if(slot_w_uniform)
return has_organ(BP_TORSO)
if(slot_l_store)
return has_organ(BP_TORSO)
if(slot_r_store)
return has_organ(BP_TORSO)
if(slot_s_store)
return has_organ(BP_TORSO)
if(slot_in_backpack)
return 1
if(slot_tie)
return 1
/obj/item/var/suitlink = 1 //makes belt items require a jumpsuit- set individual items to suitlink = 0 to allow wearing on belt slot without suit
/mob/living/carbon/human/u_equip(obj/W as obj)
if(!W) return 0
if (W == wear_suit)
if(s_store)
drop_from_inventory(s_store)
worn_clothing -= wear_suit
wear_suit = null
update_inv_wear_suit()
else if (W == w_uniform)
if (r_store)
drop_from_inventory(r_store)
if (l_store)
drop_from_inventory(l_store)
if (wear_id)
drop_from_inventory(wear_id)
if (belt && belt.suitlink == 1)
worn_clothing -= belt
drop_from_inventory(belt)
worn_clothing -= w_uniform
w_uniform = null
update_inv_w_uniform()
else if (W == gloves)
worn_clothing -= gloves
gloves = null
update_inv_gloves()
else if (W == glasses)
worn_clothing -= glasses
glasses = null
update_inv_glasses()
else if (W == head)
worn_clothing -= head
head = null
if(istype(W, /obj/item))
var/obj/item/I = W
if(I.flags_inv & (HIDEMASK|BLOCKHAIR|BLOCKHEADHAIR))
update_hair(0) //rebuild hair
update_inv_ears(0)
update_inv_wear_mask(0)
update_inv_head()
else if (W == l_ear)
l_ear = null
update_inv_ears()
else if (W == r_ear)
r_ear = null
update_inv_ears()
else if (W == shoes)
worn_clothing -= shoes
shoes = null
update_inv_shoes()
else if (W == belt)
worn_clothing -= belt
belt = null
update_inv_belt()
else if (W == wear_mask)
worn_clothing -= wear_mask
wear_mask = null
if(istype(W, /obj/item))
var/obj/item/I = W
if(I.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR))
update_hair(0) //rebuild hair
update_inv_ears(0)
// If this is how the internals are connected, disable them
if(internal && !(head?.item_flags & AIRTIGHT))
if(internals)
internals.icon_state = "internal0"
internal = null
update_inv_wear_mask()
else if (W == wear_id)
wear_id = null
update_inv_wear_id()
BITSET(hud_updateflag, ID_HUD)
BITSET(hud_updateflag, WANTED_HUD)
else if (W == r_store)
r_store = null
//update_inv_pockets() //Doesn't do anything.
else if (W == l_store)
l_store = null
//update_inv_pockets() //Doesn't do anything.
else if (W == s_store)
s_store = null
update_inv_s_store()
else if (W == back)
worn_clothing -= back
back = null
update_inv_back()
else if (W == handcuffed)
handcuffed = null
if(buckled && buckled.buckle_require_restraints)
buckled.unbuckle_mob()
update_handcuffed()
else if (W == legcuffed)
legcuffed = null
update_inv_legcuffed()
else if (W == r_hand)
r_hand = null
if(l_hand)
l_hand.update_twohanding()
l_hand.update_held_icon()
update_inv_l_hand()
update_inv_r_hand()
else if (W == l_hand)
l_hand = null
if(r_hand)
r_hand.update_twohanding()
r_hand.update_held_icon()
update_inv_l_hand()
update_inv_l_hand()
else
return 0
update_action_buttons()
return 1
//This is an UNSAFE proc. Use mob_can_equip() before calling this one! Or rather use equip_to_slot_if_possible() or advanced_equip_to_slot_if_possible()
/mob/living/carbon/human/equip_to_slot(obj/item/W as obj, slot)
if(!slot)
return
if(!istype(W))
return
if(!has_organ_for_slot(slot))
return
if(!species || !species.hud || !(slot in species.hud.equip_slots))
return
W.loc = src
switch(slot)
if(slot_back)
src.back = W
W.equipped(src, slot)
worn_clothing += back
update_inv_back()
if(slot_wear_mask)
src.wear_mask = W
if(wear_mask.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR))
update_hair() //rebuild hair
update_inv_ears()
W.equipped(src, slot)
worn_clothing += wear_mask
update_inv_wear_mask()
if(slot_handcuffed)
src.handcuffed = W
update_inv_handcuffed()
if(slot_legcuffed)
src.legcuffed = W
W.equipped(src, slot)
update_inv_legcuffed()
if(slot_l_hand)
src.l_hand = W
W.equipped(src, slot)
update_inv_l_hand()
if(slot_r_hand)
src.r_hand = W
W.equipped(src, slot)
update_inv_r_hand()
if(slot_belt)
src.belt = W
W.equipped(src, slot)
worn_clothing += belt
update_inv_belt()
if(slot_wear_id)
src.wear_id = W
W.equipped(src, slot)
update_inv_wear_id()
BITSET(hud_updateflag, ID_HUD)
BITSET(hud_updateflag, WANTED_HUD)
if(slot_l_ear)
src.l_ear = W
if(l_ear.slot_flags & SLOT_TWOEARS)
var/obj/item/clothing/ears/offear/O = new(W)
O.loc = src
src.r_ear = O
O.hud_layerise()
W.equipped(src, slot)
update_inv_ears()
if(slot_r_ear)
src.r_ear = W
if(r_ear.slot_flags & SLOT_TWOEARS)
var/obj/item/clothing/ears/offear/O = new(W)
O.loc = src
src.l_ear = O
O.hud_layerise()
W.equipped(src, slot)
update_inv_ears()
if(slot_glasses)
src.glasses = W
W.equipped(src, slot)
worn_clothing += glasses
update_inv_glasses()
if(slot_gloves)
src.gloves = W
W.equipped(src, slot)
worn_clothing += gloves
update_inv_gloves()
if(slot_head)
src.head = W
if(head.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR|HIDEMASK))
update_hair() //rebuild hair
update_inv_ears(0)
update_inv_wear_mask(0)
if(istype(W,/obj/item/clothing/head/kitty))
W.update_icon(src)
W.equipped(src, slot)
worn_clothing += head
update_inv_head()
if(slot_shoes)
src.shoes = W
W.equipped(src, slot)
worn_clothing += shoes
update_inv_shoes()
if(slot_wear_suit)
src.wear_suit = W
W.equipped(src, slot)
worn_clothing += wear_suit
update_inv_wear_suit()
if(slot_w_uniform)
src.w_uniform = W
W.equipped(src, slot)
worn_clothing += w_uniform
update_inv_w_uniform()
if(slot_l_store)
src.l_store = W
W.equipped(src, slot)
//update_inv_pockets() //Doesn't do anything
if(slot_r_store)
src.r_store = W
W.equipped(src, slot)
//update_inv_pockets() //Doesn't do anything
if(slot_s_store)
src.s_store = W
W.equipped(src, slot)
update_inv_s_store()
if(slot_in_backpack)
if(src.get_active_hand() == W)
src.remove_from_mob(W)
W.loc = src.back
if(slot_tie)
for(var/obj/item/clothing/C in worn_clothing)
if(istype(W, /obj/item/clothing/accessory))
var/obj/item/clothing/accessory/A = W
if(C.attempt_attach_accessory(A, src))
return
else
to_chat(src, span_red("You are trying to equip this item to an unsupported inventory slot. How the heck did you manage that? Stop it..."))
return
if((W == src.l_hand) && (slot != slot_l_hand))
src.l_hand = null
update_inv_l_hand() //So items actually disappear from hands.
else if((W == src.r_hand) && (slot != slot_r_hand))
src.r_hand = null
update_inv_r_hand()
W.hud_layerise()
if(W.action_button_name)
update_action_buttons()
if(W.zoom)
W.zoom()
W.in_inactive_hand(src)
//VOREStation Addition Start
if(istype(W, /obj/item))
var/obj/item/I = W
I.equip_special()
//VOREStation Addition End
return 1
//Checks if a given slot can be accessed at this time, either to equip or unequip I
/mob/living/carbon/human/slot_is_accessible(var/slot, var/obj/item/I, mob/user=null)
var/obj/item/covering = null
var/check_flags = 0
switch(slot)
if(slot_wear_mask)
covering = src.head
check_flags = FACE
if(slot_glasses)
covering = src.head
check_flags = EYES
if(slot_gloves, slot_w_uniform)
covering = src.wear_suit
if(covering && (covering.body_parts_covered & (I.body_parts_covered|check_flags)))
to_chat(user, "<span class='warning'>\The [covering] is in the way.</span>")
return 0
return 1
/mob/living/carbon/human/get_equipped_item(var/slot)
switch(slot)
if(slot_back) return back
if(slot_legcuffed) return legcuffed
if(slot_handcuffed) return handcuffed
if(slot_l_store) return l_store
if(slot_r_store) return r_store
if(slot_wear_mask) return wear_mask
if(slot_l_hand) return l_hand
if(slot_r_hand) return r_hand
if(slot_wear_id) return wear_id
if(slot_glasses) return glasses
if(slot_gloves) return gloves
if(slot_head) return head
if(slot_shoes) return shoes
if(slot_belt) return belt
if(slot_wear_suit) return wear_suit
if(slot_w_uniform) return w_uniform
if(slot_s_store) return s_store
if(slot_l_ear) return l_ear
if(slot_r_ear) return r_ear
return ..()
/mob/living/carbon/human/is_holding_item_of_type(typepath)
for(var/obj/item/I in list(l_hand, r_hand))
if(istype(I, typepath))
return I
return FALSE
// Returns a list of items held in both hands.
/mob/living/carbon/human/get_all_held_items()
. = list()
if(l_hand)
. += l_hand
if(r_hand)
. += r_hand
/*
Add fingerprints to items when we put them in our hands.
This saves us from having to call add_fingerprint() any time something is put in a human's hands programmatically.
*/
/mob/living/carbon/human
var/list/worn_clothing = list() //Contains all CLOTHING items worn
/mob/living/carbon/human/verb/quick_equip()
set name = "quick-equip"
set hidden = 1
if(ishuman(src))
var/mob/living/carbon/human/H = src
var/obj/item/I = H.get_active_hand()
if(!I)
to_chat(H, "<span class='notice'>You are not holding anything to equip.</span>")
return
var/moved = FALSE
// Try an equipment slot
if(H.equip_to_appropriate_slot(I))
moved = TRUE
// No? Try a storage item.
else if(H.equip_to_storage(I, TRUE))
moved = TRUE
// No?! Well, give up.
if(!moved)
to_chat(H, "<span class='warning'>You are unable to equip that.</span>")
// Update hand icons
else
if(hand)
update_inv_l_hand(0)
else
update_inv_r_hand(0)
/mob/living/carbon/human/equip_to_storage(obj/item/newitem, user_initiated = FALSE)
// Try put it in their belt first
if(istype(src.belt,/obj/item/weapon/storage))
var/obj/item/weapon/storage/wornbelt = src.belt
if(wornbelt.can_be_inserted(newitem, 1))
if(user_initiated)
wornbelt.handle_item_insertion(newitem)
else
newitem.forceMove(wornbelt)
return wornbelt
return ..()
/mob/living/carbon/human/proc/equip_in_one_of_slots(obj/item/W, list/slots, del_on_fail = 1)
for (var/slot in slots)
if (equip_to_slot_if_possible(W, slots[slot], del_on_fail = 0))
return slot
if (del_on_fail)
qdel(W)
return null
/mob/living/carbon/human/proc/has_organ(name)
var/obj/item/organ/external/O = organs_by_name[name]
return (O && !O.is_stump())
/mob/living/carbon/human/proc/has_organ_for_slot(slot)
switch(slot)
if(slot_back)
return has_organ(BP_TORSO)
if(slot_wear_mask)
return has_organ(BP_HEAD)
if(slot_handcuffed)
return has_organ(BP_L_HAND) && has_organ(BP_R_HAND)
if(slot_legcuffed)
return has_organ(BP_L_FOOT) && has_organ(BP_R_FOOT)
if(slot_l_hand)
return has_organ(BP_L_HAND)
if(slot_r_hand)
return has_organ(BP_R_HAND)
if(slot_belt)
return has_organ(BP_TORSO)
if(slot_wear_id)
// the only relevant check for this is the uniform check
return 1
if(slot_l_ear)
return has_organ(BP_HEAD)
if(slot_r_ear)
return has_organ(BP_HEAD)
if(slot_glasses)
return has_organ(BP_HEAD)
if(slot_gloves)
return has_organ(BP_L_HAND) || has_organ(BP_R_HAND)
if(slot_head)
return has_organ(BP_HEAD)
if(slot_shoes)
return has_organ(BP_L_FOOT) || has_organ(BP_R_FOOT)
if(slot_wear_suit)
return has_organ(BP_TORSO)
if(slot_w_uniform)
return has_organ(BP_TORSO)
if(slot_l_store)
return has_organ(BP_TORSO)
if(slot_r_store)
return has_organ(BP_TORSO)
if(slot_s_store)
return has_organ(BP_TORSO)
if(slot_in_backpack)
return 1
if(slot_tie)
return 1
/obj/item/var/suitlink = 1 //makes belt items require a jumpsuit- set individual items to suitlink = 0 to allow wearing on belt slot without suit
/mob/living/carbon/human/u_equip(obj/W as obj)
if(!W) return 0
if (W == wear_suit)
if(s_store)
drop_from_inventory(s_store)
worn_clothing -= wear_suit
wear_suit = null
update_inv_wear_suit()
else if (W == w_uniform)
if (r_store)
drop_from_inventory(r_store)
if (l_store)
drop_from_inventory(l_store)
if (wear_id)
drop_from_inventory(wear_id)
if (belt && belt.suitlink == 1)
worn_clothing -= belt
drop_from_inventory(belt)
worn_clothing -= w_uniform
w_uniform = null
update_inv_w_uniform()
else if (W == gloves)
worn_clothing -= gloves
gloves = null
update_inv_gloves()
else if (W == glasses)
worn_clothing -= glasses
glasses = null
update_inv_glasses()
else if (W == head)
worn_clothing -= head
head = null
if(istype(W, /obj/item))
var/obj/item/I = W
if(I.flags_inv & (HIDEMASK|BLOCKHAIR|BLOCKHEADHAIR))
update_hair(0) //rebuild hair
update_inv_ears(0)
update_inv_wear_mask(0)
update_inv_head()
else if (W == l_ear)
l_ear = null
update_inv_ears()
else if (W == r_ear)
r_ear = null
update_inv_ears()
else if (W == shoes)
worn_clothing -= shoes
shoes = null
update_inv_shoes()
else if (W == belt)
worn_clothing -= belt
belt = null
update_inv_belt()
else if (W == wear_mask)
worn_clothing -= wear_mask
wear_mask = null
if(istype(W, /obj/item))
var/obj/item/I = W
if(I.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR))
update_hair(0) //rebuild hair
update_inv_ears(0)
// If this is how the internals are connected, disable them
if(internal && !(head?.item_flags & AIRTIGHT))
if(internals)
internals.icon_state = "internal0"
internal = null
update_inv_wear_mask()
else if (W == wear_id)
wear_id = null
update_inv_wear_id()
BITSET(hud_updateflag, ID_HUD)
BITSET(hud_updateflag, WANTED_HUD)
else if (W == r_store)
r_store = null
//update_inv_pockets() //Doesn't do anything.
else if (W == l_store)
l_store = null
//update_inv_pockets() //Doesn't do anything.
else if (W == s_store)
s_store = null
update_inv_s_store()
else if (W == back)
worn_clothing -= back
back = null
update_inv_back()
else if (W == handcuffed)
handcuffed = null
if(buckled && buckled.buckle_require_restraints)
buckled.unbuckle_mob()
update_handcuffed()
else if (W == legcuffed)
legcuffed = null
update_inv_legcuffed()
else if (W == r_hand)
r_hand = null
if(l_hand)
l_hand.update_twohanding()
l_hand.update_held_icon()
update_inv_l_hand()
update_inv_r_hand()
else if (W == l_hand)
l_hand = null
if(r_hand)
r_hand.update_twohanding()
r_hand.update_held_icon()
update_inv_l_hand()
update_inv_l_hand()
else
return 0
update_action_buttons()
return 1
//This is an UNSAFE proc. Use mob_can_equip() before calling this one! Or rather use equip_to_slot_if_possible() or advanced_equip_to_slot_if_possible()
/mob/living/carbon/human/equip_to_slot(obj/item/W as obj, slot)
if(!slot)
return
if(!istype(W))
return
if(!has_organ_for_slot(slot))
return
if(!species || !species.hud || !(slot in species.hud.equip_slots))
return
W.loc = src
switch(slot)
if(slot_back)
src.back = W
W.equipped(src, slot)
worn_clothing += back
update_inv_back()
if(slot_wear_mask)
src.wear_mask = W
if(wear_mask.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR))
update_hair() //rebuild hair
update_inv_ears()
W.equipped(src, slot)
worn_clothing += wear_mask
update_inv_wear_mask()
if(slot_handcuffed)
src.handcuffed = W
update_inv_handcuffed()
if(slot_legcuffed)
src.legcuffed = W
W.equipped(src, slot)
update_inv_legcuffed()
if(slot_l_hand)
src.l_hand = W
W.equipped(src, slot)
update_inv_l_hand()
if(slot_r_hand)
src.r_hand = W
W.equipped(src, slot)
update_inv_r_hand()
if(slot_belt)
src.belt = W
W.equipped(src, slot)
worn_clothing += belt
update_inv_belt()
if(slot_wear_id)
src.wear_id = W
W.equipped(src, slot)
update_inv_wear_id()
BITSET(hud_updateflag, ID_HUD)
BITSET(hud_updateflag, WANTED_HUD)
if(slot_l_ear)
src.l_ear = W
if(l_ear.slot_flags & SLOT_TWOEARS)
var/obj/item/clothing/ears/offear/O = new(W)
O.loc = src
src.r_ear = O
O.hud_layerise()
W.equipped(src, slot)
update_inv_ears()
if(slot_r_ear)
src.r_ear = W
if(r_ear.slot_flags & SLOT_TWOEARS)
var/obj/item/clothing/ears/offear/O = new(W)
O.loc = src
src.l_ear = O
O.hud_layerise()
W.equipped(src, slot)
update_inv_ears()
if(slot_glasses)
src.glasses = W
W.equipped(src, slot)
worn_clothing += glasses
update_inv_glasses()
if(slot_gloves)
src.gloves = W
W.equipped(src, slot)
worn_clothing += gloves
update_inv_gloves()
if(slot_head)
src.head = W
if(head.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR|HIDEMASK))
update_hair() //rebuild hair
update_inv_ears(0)
update_inv_wear_mask(0)
if(istype(W,/obj/item/clothing/head/kitty))
W.update_icon(src)
W.equipped(src, slot)
worn_clothing += head
update_inv_head()
if(slot_shoes)
src.shoes = W
W.equipped(src, slot)
worn_clothing += shoes
update_inv_shoes()
if(slot_wear_suit)
src.wear_suit = W
W.equipped(src, slot)
worn_clothing += wear_suit
update_inv_wear_suit()
if(slot_w_uniform)
src.w_uniform = W
W.equipped(src, slot)
worn_clothing += w_uniform
update_inv_w_uniform()
if(slot_l_store)
src.l_store = W
W.equipped(src, slot)
//update_inv_pockets() //Doesn't do anything
if(slot_r_store)
src.r_store = W
W.equipped(src, slot)
//update_inv_pockets() //Doesn't do anything
if(slot_s_store)
src.s_store = W
W.equipped(src, slot)
update_inv_s_store()
if(slot_in_backpack)
if(src.get_active_hand() == W)
src.remove_from_mob(W)
W.loc = src.back
if(slot_tie)
for(var/obj/item/clothing/C in worn_clothing)
if(istype(W, /obj/item/clothing/accessory))
var/obj/item/clothing/accessory/A = W
if(C.attempt_attach_accessory(A, src))
return
else
to_chat(src, span_red("You are trying to equip this item to an unsupported inventory slot. How the heck did you manage that? Stop it..."))
return
if((W == src.l_hand) && (slot != slot_l_hand))
src.l_hand = null
update_inv_l_hand() //So items actually disappear from hands.
else if((W == src.r_hand) && (slot != slot_r_hand))
src.r_hand = null
update_inv_r_hand()
W.hud_layerise()
if(W.action_button_name)
update_action_buttons()
if(W.zoom)
W.zoom()
W.in_inactive_hand(src)
//VOREStation Addition Start
if(istype(W, /obj/item))
var/obj/item/I = W
I.equip_special()
//VOREStation Addition End
return 1
//Checks if a given slot can be accessed at this time, either to equip or unequip I
/mob/living/carbon/human/slot_is_accessible(var/slot, var/obj/item/I, mob/user=null)
var/obj/item/covering = null
var/check_flags = 0
switch(slot)
if(slot_wear_mask)
covering = src.head
check_flags = FACE
if(slot_glasses)
covering = src.head
check_flags = EYES
if(slot_gloves, slot_w_uniform)
covering = src.wear_suit
if(covering && (covering.body_parts_covered & (I.body_parts_covered|check_flags)))
to_chat(user, "<span class='warning'>\The [covering] is in the way.</span>")
return 0
return 1
/mob/living/carbon/human/get_equipped_item(var/slot)
switch(slot)
if(slot_back) return back
if(slot_legcuffed) return legcuffed
if(slot_handcuffed) return handcuffed
if(slot_l_store) return l_store
if(slot_r_store) return r_store
if(slot_wear_mask) return wear_mask
if(slot_l_hand) return l_hand
if(slot_r_hand) return r_hand
if(slot_wear_id) return wear_id
if(slot_glasses) return glasses
if(slot_gloves) return gloves
if(slot_head) return head
if(slot_shoes) return shoes
if(slot_belt) return belt
if(slot_wear_suit) return wear_suit
if(slot_w_uniform) return w_uniform
if(slot_s_store) return s_store
if(slot_l_ear) return l_ear
if(slot_r_ear) return r_ear
return ..()
/mob/living/carbon/human/is_holding_item_of_type(typepath)
for(var/obj/item/I in list(l_hand, r_hand))
if(istype(I, typepath))
return I
return FALSE
// Returns a list of items held in both hands.
/mob/living/carbon/human/get_all_held_items()
. = list()
if(l_hand)
. += l_hand
if(r_hand)
. += r_hand
File diff suppressed because it is too large Load Diff
+31 -31
View File
@@ -1,31 +1,31 @@
// VOREStation Add Start: Doing this here bc AUTOHISS_FULL is more readable than #
#define AUTOHISS_OFF 0
#define AUTOHISS_BASIC 1
#define AUTOHISS_FULL 2
// VOREStation Add End
/mob/living/carbon/human/Login()
..()
update_hud()
// VOREStation Add
if(client.prefs) // Safety, just in case so we don't runtime.
if(!client.prefs.autohiss)
client.autohiss_mode = AUTOHISS_FULL
else
switch(client.prefs.autohiss)
if("Full")
client.autohiss_mode = AUTOHISS_FULL
if("Basic")
client.autohiss_mode = AUTOHISS_BASIC
if("Off")
client.autohiss_mode = AUTOHISS_OFF
consider_birthday()
// VOREStation Add
if(species) species.handle_login_special(src)
return
// VOREStation Add Start: Doing this here bc AUTOHISS_FULL is more readable than #
#undef AUTOHISS_OFF
#undef AUTOHISS_BASIC
#undef AUTOHISS_FULL
// VOREStation Add End
// VOREStation Add Start: Doing this here bc AUTOHISS_FULL is more readable than #
#define AUTOHISS_OFF 0
#define AUTOHISS_BASIC 1
#define AUTOHISS_FULL 2
// VOREStation Add End
/mob/living/carbon/human/Login()
..()
update_hud()
// VOREStation Add
if(client.prefs) // Safety, just in case so we don't runtime.
if(!client.prefs.autohiss)
client.autohiss_mode = AUTOHISS_FULL
else
switch(client.prefs.autohiss)
if("Full")
client.autohiss_mode = AUTOHISS_FULL
if("Basic")
client.autohiss_mode = AUTOHISS_BASIC
if("Off")
client.autohiss_mode = AUTOHISS_OFF
consider_birthday()
// VOREStation Add
if(species) species.handle_login_special(src)
return
// VOREStation Add Start: Doing this here bc AUTOHISS_FULL is more readable than #
#undef AUTOHISS_OFF
#undef AUTOHISS_BASIC
#undef AUTOHISS_FULL
// VOREStation Add End
+214 -214
View File
@@ -1,214 +1,214 @@
/mob/living/carbon/human/GetAltName()
if(ability_flags & AB_PHASE_SHIFTED)
return ""
if(name != GetVoice())
return " (as [get_id_name("Unknown")])"
return ..()
/mob/living/carbon/human/proc/forcesay(list/append)
if(stat == CONSCIOUS)
if(client)
var/virgin = 1 //has the text been modified yet?
var/temp = winget(client, "input", "text")
if(findtextEx(temp, "Say \"", 1, 7) && length(temp) > 5) //case sensitive means
temp = replacetext(temp, ";", "") //general radio
if(findtext(trim_left(temp), ":", 6, 7)) //dept radio
temp = copytext(trim_left(temp), 8)
virgin = 0
if(virgin)
temp = copytext(trim_left(temp), 6) //normal speech
virgin = 0
while(findtext(trim_left(temp), ":", 1, 2)) //dept radio again (necessary)
temp = copytext(trim_left(temp), 3)
if(findtext(temp, "*", 1, 2)) //emotes
return
temp = copytext(trim_left(temp), 1, rand(5,8))
var/trimmed = trim_left(temp)
if(length(trimmed))
if(append)
temp += pick(append)
say(temp)
winset(client, "input", "text=[null]")
/mob/living/carbon/human/speech_bubble_appearance()
var/sounds_synth = FALSE
var/datum/robolimb/robo = isSynthetic() //Will get torso manufacturer
if(robo)
sounds_synth = looksSynthetic() //Based on lifelike robolimb vars
// Not lifelike and got manufacturer
if(sounds_synth)
return robo.speech_bubble_appearance || "synthetic"
// Not lifelike synth, might have synth voice box
if(!robo)
var/obj/item/organ/internal/V = internal_organs_by_name[O_VOICE]
if(V?.robotic >= ORGAN_ROBOT)
return "synthetic"
// Species might have custom one
if(species.speech_bubble_appearance)
return species.speech_bubble_appearance
// NORMIE
return ..()
/mob/living/carbon/human/say_understands(var/mob/other, var/datum/language/speaking = null)
if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak.
return TRUE
if(species.can_understand(other))
return TRUE
//These only pertain to common. Languages are handled by mob/say_understands()
if(!speaking)
if(istype(other, /mob/living/carbon/alien/diona))
if(other.languages.len >= 2) //They've sucked down some blood and can speak common now.
return TRUE
if(issilicon(other))
return TRUE
if(isbrain(other))
return TRUE
if(isslime(other))
return TRUE
return ..()
/mob/living/carbon/human/GetVoice()
var/voice_sub
if(istype(get_rig(),/obj/item/weapon/rig))
var/obj/item/weapon/rig/rig = get_rig()
// todo: fix this shit
if(rig.speech && rig.speech.voice_holder && rig.speech.voice_holder.active && rig.speech.voice_holder.voice)
voice_sub = rig.speech.voice_holder.voice
if(!voice_sub) // If the rig has a voice changer, then we use that. Otherwise, use this
for(var/obj/item/gear in list(wear_mask,wear_suit,head))
if(!gear)
continue
var/obj/item/voice_changer/changer = locate() in gear
if(changer && changer.active)
if(changer.voice)
voice_sub = changer.voice
else
voice_sub = get_id_name()
if(voice_sub)
return voice_sub
if(mind && mind.changeling && mind.changeling.mimicing)
return mind.changeling.mimicing
if(GetSpecialVoice())
return GetSpecialVoice()
return real_name
/mob/living/carbon/human/proc/SetSpecialVoice(var/new_voice)
if(new_voice)
special_voice = new_voice
return
/mob/living/carbon/human/proc/UnsetSpecialVoice()
special_voice = ""
return
/mob/living/carbon/human/proc/GetSpecialVoice()
return special_voice
/mob/living/carbon/human/handle_speech_problems(var/list/message_data)
if(silent || (sdisabilities & MUTE))
message_data[1] = ""
. = 1
else if(istype(wear_mask, /obj/item/clothing/mask))
var/obj/item/clothing/mask/M = wear_mask
if(M.voicechange)
message_data[1] = pick(M.say_messages)
message_data[2] = pick(M.say_verbs)
. = 1
else if(CE_SPEEDBOOST in chem_effects || is_jittery) // motor mouth
// Despite trying to url/html decode these, byond is just being bad and I dunno.
var/static/regex/speedboost_initial = new (@"&[a-z]{2,5};|&#\d{2};","g")
// Not herestring because bad vs code syntax highlight panics at apostrophe
var/static/regex/speedboost_main = new ("\[ ',!?.;\]","g")
for(var/datum/multilingual_say_piece/S in message_data[1])
S.message = speedboost_initial.Replace(S.message, "")
S.message = speedboost_main.Replace(S.message, "")
. = 1
else
. = ..(message_data)
/mob/living/carbon/human/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
switch(message_mode)
if("intercom")
if(!restrained())
for(var/obj/item/device/radio/intercom/I in view(1))
I.talk_into(src, message_pieces, null, verb)
I.add_fingerprint(src)
used_radios += I
if("headset")
var/obj/item/device/radio/R = null
if(isradio(l_ear))
R = l_ear
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
return
if(isradio(r_ear))
R = r_ear
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
return
if("right ear")
var/obj/item/device/radio/R = null
if(isradio(r_ear))
R = r_ear
if(isradio(r_hand))
R = r_hand
if(istype(R))
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
if("left ear")
var/obj/item/device/radio/R = null
if(isradio(l_ear))
R = l_ear
if(isradio(l_hand))
R = l_hand
if(istype(R))
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
else
if(message_mode)
if(isradio(l_ear))
if(l_ear.talk_into(src, message_pieces, message_mode, verb))
used_radios += l_ear
return
if(isradio(r_ear))
if(r_ear.talk_into(src, message_pieces, message_mode, verb))
used_radios += r_ear
/mob/living/carbon/human/handle_speech_sound()
var/list/returns[2]
if(species.speech_sounds && species.speech_sounds.len && prob(species.speech_chance)) //VOREStation Edit: Sanity Check
returns[1] = sound(pick(species.speech_sounds))
returns[2] = 50
return returns
/mob/living/carbon/human/binarycheck()
. = FALSE
var/obj/item/device/radio/headset/R = null
if(istype(l_ear, /obj/item/device/radio/headset))
R = l_ear
if(R.translate_binary)
. = TRUE
if(istype(r_ear, /obj/item/device/radio/headset))
R = r_ear
if(R.translate_binary)
. = TRUE
/mob/living/carbon/human/GetAltName()
if(ability_flags & AB_PHASE_SHIFTED)
return ""
if(name != GetVoice())
return " (as [get_id_name("Unknown")])"
return ..()
/mob/living/carbon/human/proc/forcesay(list/append)
if(stat == CONSCIOUS)
if(client)
var/virgin = 1 //has the text been modified yet?
var/temp = winget(client, "input", "text")
if(findtextEx(temp, "Say \"", 1, 7) && length(temp) > 5) //case sensitive means
temp = replacetext(temp, ";", "") //general radio
if(findtext(trim_left(temp), ":", 6, 7)) //dept radio
temp = copytext(trim_left(temp), 8)
virgin = 0
if(virgin)
temp = copytext(trim_left(temp), 6) //normal speech
virgin = 0
while(findtext(trim_left(temp), ":", 1, 2)) //dept radio again (necessary)
temp = copytext(trim_left(temp), 3)
if(findtext(temp, "*", 1, 2)) //emotes
return
temp = copytext(trim_left(temp), 1, rand(5,8))
var/trimmed = trim_left(temp)
if(length(trimmed))
if(append)
temp += pick(append)
say(temp)
winset(client, "input", "text=[null]")
/mob/living/carbon/human/speech_bubble_appearance()
var/sounds_synth = FALSE
var/datum/robolimb/robo = isSynthetic() //Will get torso manufacturer
if(robo)
sounds_synth = looksSynthetic() //Based on lifelike robolimb vars
// Not lifelike and got manufacturer
if(sounds_synth)
return robo.speech_bubble_appearance || "synthetic"
// Not lifelike synth, might have synth voice box
if(!robo)
var/obj/item/organ/internal/V = internal_organs_by_name[O_VOICE]
if(V?.robotic >= ORGAN_ROBOT)
return "synthetic"
// Species might have custom one
if(species.speech_bubble_appearance)
return species.speech_bubble_appearance
// NORMIE
return ..()
/mob/living/carbon/human/say_understands(var/mob/other, var/datum/language/speaking = null)
if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak.
return TRUE
if(species.can_understand(other))
return TRUE
//These only pertain to common. Languages are handled by mob/say_understands()
if(!speaking)
if(istype(other, /mob/living/carbon/alien/diona))
if(other.languages.len >= 2) //They've sucked down some blood and can speak common now.
return TRUE
if(issilicon(other))
return TRUE
if(isbrain(other))
return TRUE
if(isslime(other))
return TRUE
return ..()
/mob/living/carbon/human/GetVoice()
var/voice_sub
if(istype(get_rig(),/obj/item/weapon/rig))
var/obj/item/weapon/rig/rig = get_rig()
// todo: fix this shit
if(rig.speech && rig.speech.voice_holder && rig.speech.voice_holder.active && rig.speech.voice_holder.voice)
voice_sub = rig.speech.voice_holder.voice
if(!voice_sub) // If the rig has a voice changer, then we use that. Otherwise, use this
for(var/obj/item/gear in list(wear_mask,wear_suit,head))
if(!gear)
continue
var/obj/item/voice_changer/changer = locate() in gear
if(changer && changer.active)
if(changer.voice)
voice_sub = changer.voice
else
voice_sub = get_id_name()
if(voice_sub)
return voice_sub
if(mind && mind.changeling && mind.changeling.mimicing)
return mind.changeling.mimicing
if(GetSpecialVoice())
return GetSpecialVoice()
return real_name
/mob/living/carbon/human/proc/SetSpecialVoice(var/new_voice)
if(new_voice)
special_voice = new_voice
return
/mob/living/carbon/human/proc/UnsetSpecialVoice()
special_voice = ""
return
/mob/living/carbon/human/proc/GetSpecialVoice()
return special_voice
/mob/living/carbon/human/handle_speech_problems(var/list/message_data)
if(silent || (sdisabilities & MUTE))
message_data[1] = ""
. = 1
else if(istype(wear_mask, /obj/item/clothing/mask))
var/obj/item/clothing/mask/M = wear_mask
if(M.voicechange)
message_data[1] = pick(M.say_messages)
message_data[2] = pick(M.say_verbs)
. = 1
else if(CE_SPEEDBOOST in chem_effects || is_jittery) // motor mouth
// Despite trying to url/html decode these, byond is just being bad and I dunno.
var/static/regex/speedboost_initial = new (@"&[a-z]{2,5};|&#\d{2};","g")
// Not herestring because bad vs code syntax highlight panics at apostrophe
var/static/regex/speedboost_main = new ("\[ ',!?.;\]","g")
for(var/datum/multilingual_say_piece/S in message_data[1])
S.message = speedboost_initial.Replace(S.message, "")
S.message = speedboost_main.Replace(S.message, "")
. = 1
else
. = ..(message_data)
/mob/living/carbon/human/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
switch(message_mode)
if("intercom")
if(!restrained())
for(var/obj/item/device/radio/intercom/I in view(1))
I.talk_into(src, message_pieces, null, verb)
I.add_fingerprint(src)
used_radios += I
if("headset")
var/obj/item/device/radio/R = null
if(isradio(l_ear))
R = l_ear
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
return
if(isradio(r_ear))
R = r_ear
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
return
if("right ear")
var/obj/item/device/radio/R = null
if(isradio(r_ear))
R = r_ear
if(isradio(r_hand))
R = r_hand
if(istype(R))
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
if("left ear")
var/obj/item/device/radio/R = null
if(isradio(l_ear))
R = l_ear
if(isradio(l_hand))
R = l_hand
if(istype(R))
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
else
if(message_mode)
if(isradio(l_ear))
if(l_ear.talk_into(src, message_pieces, message_mode, verb))
used_radios += l_ear
return
if(isradio(r_ear))
if(r_ear.talk_into(src, message_pieces, message_mode, verb))
used_radios += r_ear
/mob/living/carbon/human/handle_speech_sound()
var/list/returns[2]
if(species.speech_sounds && species.speech_sounds.len && prob(species.speech_chance)) //VOREStation Edit: Sanity Check
returns[1] = sound(pick(species.speech_sounds))
returns[2] = 50
return returns
/mob/living/carbon/human/binarycheck()
. = FALSE
var/obj/item/device/radio/headset/R = null
if(istype(l_ear, /obj/item/device/radio/headset))
R = l_ear
if(R.translate_binary)
. = TRUE
if(istype(r_ear, /obj/item/device/radio/headset))
R = r_ear
if(R.translate_binary)
. = TRUE
@@ -1,77 +1,77 @@
/datum/unarmed_attack/bite/sharp/numbing //Is using this against someone you are truly trying to fight a bad idea? Yes. Yes it is.
attack_verb = list("bit")
attack_noun = list("fangs")
attack_sound = 'sound/weapons/bite.ogg'
shredding = 0
sharp = TRUE
edge = TRUE
/datum/unarmed_attack/bite/sharp/numbing/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
var/obj/item/organ/external/affecting = target.get_organ(zone)
attack_damage = CLAMP(attack_damage, 1, 5)
if(target == user)
user.visible_message("<span class='danger'>[user] [pick(attack_verb)] \himself in the [affecting.name]!</span>")
return 0 //No venom for you.
switch(zone)
if(BP_HEAD, O_MOUTH, O_EYES)
// ----- HEAD ----- //
switch(attack_damage)
if(1 to 2)
user.visible_message("<span class='danger'>[user]'s fangs scrape across [target]'s cheek!</span>")
to_chat(target, "<span class='danger'>Your face feels tingly!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage) //Have to add this here, otherwise the swtich fails.
if(3 to 4)
user.visible_message("<span class='danger'>[user]'s fangs pierce into [target]'s neck at an odd, awkward angle!</span>")
to_chat(target, "<span class='danger'>Your neck feels like it's on fire before going numb!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(5)
user.visible_message("<span class='danger'>[user] sinks \his [pick(attack_noun)] <b><i>deep</i></b> into [target]'s neck, causing the vein to bulge outwards at some type of chemical is pumped into it!</span>")
to_chat(target, "<span class='danger'>Your neck feels like it's going to burst! Moments later, you simply can't feel your neck any longer, the numbness beginning to spread throughout your body!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
else
// ----- BODY ----- //
switch(attack_damage)
if(1 to 2)
user.visible_message("<span class='danger'>[user]'s fangs scrape across [target]'s [affecting.name]!</span>")
to_chat(target, "<span class='danger'>Your [affecting.name] feels tingly!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(3 to 4)
user.visible_message("<span class='danger'>[user]'s fangs pierce [pick("", "", "the side of")] [target]'s [affecting.name]!</span>")
to_chat(target, "<span class='danger'>Your [affecting.name] feels like it's on fire before going numb!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(5)
user.visible_message("<span class='danger'>[user]'s fangs sink deep into [target]'s [affecting.name], one of their veins bulging outwards from the sudden fluid pumped into it!</span>")
to_chat(target, "<span class='danger'>Your [affecting.name] feels like it's going to burst! Moments later, you simply can't feel your [affecting.name] any longer, the numbness slowly spreading throughout your body!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
/datum/unarmed_attack/claws/shadekin
/datum/unarmed_attack/claws/shadekin/apply_effects(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
..()
if(!(target == user))
user.shadekin_adjust_energy(attack_damage)
/datum/unarmed_attack/bite/sharp/shadekin
/datum/unarmed_attack/bite/sharp/shadekin/apply_effects(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
..()
if(!(target == user))
user.shadekin_adjust_energy(attack_damage)
/datum/unarmed_attack/claws/chimera //special feral attack that gets stronger as they get angrier
/datum/unarmed_attack/claws/chimera/get_unarmed_damage(var/mob/living/carbon/human/user)
return user.feral/5
/datum/unarmed_attack/claws/chimera/apply_effects(var/mob/living/carbon/human/user,var/mob/living/carbon/human/target,var/armour,var/attack_damage,var/zone)
..()
if(user.feral && !(target == user))
var/selfdamage = ((user.feral/10)-7.5)
if(selfdamage > 0)
var/selfdamagezone = null
if (user.hand)
selfdamagezone=pick(BP_L_ARM, BP_L_HAND)
else
selfdamagezone=pick(BP_R_ARM, BP_R_HAND)
/datum/unarmed_attack/bite/sharp/numbing //Is using this against someone you are truly trying to fight a bad idea? Yes. Yes it is.
attack_verb = list("bit")
attack_noun = list("fangs")
attack_sound = 'sound/weapons/bite.ogg'
shredding = 0
sharp = TRUE
edge = TRUE
/datum/unarmed_attack/bite/sharp/numbing/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
var/obj/item/organ/external/affecting = target.get_organ(zone)
attack_damage = CLAMP(attack_damage, 1, 5)
if(target == user)
user.visible_message("<span class='danger'>[user] [pick(attack_verb)] \himself in the [affecting.name]!</span>")
return 0 //No venom for you.
switch(zone)
if(BP_HEAD, O_MOUTH, O_EYES)
// ----- HEAD ----- //
switch(attack_damage)
if(1 to 2)
user.visible_message("<span class='danger'>[user]'s fangs scrape across [target]'s cheek!</span>")
to_chat(target, "<span class='danger'>Your face feels tingly!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage) //Have to add this here, otherwise the swtich fails.
if(3 to 4)
user.visible_message("<span class='danger'>[user]'s fangs pierce into [target]'s neck at an odd, awkward angle!</span>")
to_chat(target, "<span class='danger'>Your neck feels like it's on fire before going numb!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(5)
user.visible_message("<span class='danger'>[user] sinks \his [pick(attack_noun)] <b><i>deep</i></b> into [target]'s neck, causing the vein to bulge outwards at some type of chemical is pumped into it!</span>")
to_chat(target, "<span class='danger'>Your neck feels like it's going to burst! Moments later, you simply can't feel your neck any longer, the numbness beginning to spread throughout your body!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
else
// ----- BODY ----- //
switch(attack_damage)
if(1 to 2)
user.visible_message("<span class='danger'>[user]'s fangs scrape across [target]'s [affecting.name]!</span>")
to_chat(target, "<span class='danger'>Your [affecting.name] feels tingly!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(3 to 4)
user.visible_message("<span class='danger'>[user]'s fangs pierce [pick("", "", "the side of")] [target]'s [affecting.name]!</span>")
to_chat(target, "<span class='danger'>Your [affecting.name] feels like it's on fire before going numb!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(5)
user.visible_message("<span class='danger'>[user]'s fangs sink deep into [target]'s [affecting.name], one of their veins bulging outwards from the sudden fluid pumped into it!</span>")
to_chat(target, "<span class='danger'>Your [affecting.name] feels like it's going to burst! Moments later, you simply can't feel your [affecting.name] any longer, the numbness slowly spreading throughout your body!</span>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
/datum/unarmed_attack/claws/shadekin
/datum/unarmed_attack/claws/shadekin/apply_effects(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
..()
if(!(target == user))
user.shadekin_adjust_energy(attack_damage)
/datum/unarmed_attack/bite/sharp/shadekin
/datum/unarmed_attack/bite/sharp/shadekin/apply_effects(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
..()
if(!(target == user))
user.shadekin_adjust_energy(attack_damage)
/datum/unarmed_attack/claws/chimera //special feral attack that gets stronger as they get angrier
/datum/unarmed_attack/claws/chimera/get_unarmed_damage(var/mob/living/carbon/human/user)
return user.feral/5
/datum/unarmed_attack/claws/chimera/apply_effects(var/mob/living/carbon/human/user,var/mob/living/carbon/human/target,var/armour,var/attack_damage,var/zone)
..()
if(user.feral && !(target == user))
var/selfdamage = ((user.feral/10)-7.5)
if(selfdamage > 0)
var/selfdamagezone = null
if (user.hand)
selfdamagezone=pick(BP_L_ARM, BP_L_HAND)
else
selfdamagezone=pick(BP_R_ARM, BP_R_HAND)
user.apply_damage(selfdamage, BRUTE, selfdamagezone, 0, 0, sharp=FALSE, edge=FALSE)
@@ -1 +1 @@
#define PROTEAN_EDIBLE_MATERIALS list(MAT_STEEL, MAT_SILVER, MAT_GOLD, MAT_URANIUM, MAT_METALHYDROGEN)
#define PROTEAN_EDIBLE_MATERIALS list(MAT_STEEL, MAT_SILVER, MAT_GOLD, MAT_URANIUM, MAT_METALHYDROGEN)
@@ -1,120 +1,120 @@
// ### Wooo, inheritance. Basically copying everything I don't need to edit from prometheans, because they mostly work already.
// ### Any and all of this is open to change for balance or whatever.
// ###
// ###
// Species definition follows.
/datum/species/shapeshifter/promethean/avatar
name = SPECIES_VR
name_plural = "Virtual Reality Avatars"
blurb = "A 3-dimensional representation of some sort of animate object used to display the presence and actions of some-one or -thing using a virtual reality program."
show_ssd = "eerily still"
death_message = "flickers briefly, their gear falling in a heap on the floor around their motionless body."
knockout_message = "has been knocked unconscious!"
spawn_flags = SPECIES_IS_RESTRICTED
speech_bubble_appearance = "cyber"
assisted_langs = list()
male_cough_sounds = list('sound/effects/mob_effects/m_cougha.ogg','sound/effects/mob_effects/m_coughb.ogg', 'sound/effects/mob_effects/m_coughc.ogg')
female_cough_sounds = list('sound/effects/mob_effects/f_cougha.ogg','sound/effects/mob_effects/f_coughb.ogg')
male_sneeze_sound = 'sound/effects/mob_effects/sneeze.ogg'
female_sneeze_sound = 'sound/effects/mob_effects/f_sneeze.ogg'
valid_transform_species = list(SPECIES_HUMAN, SPECIES_HUMAN_VATBORN, SPECIES_UNATHI, SPECIES_TAJ, SPECIES_SKRELL, SPECIES_DIONA, SPECIES_TESHARI, SPECIES_VOX, SPECIES_MONKEY, SPECIES_SKELETON)
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/shapeshifter_select_wings,
/mob/living/carbon/human/proc/shapeshifter_select_tail,
/mob/living/carbon/human/proc/shapeshifter_select_ears,
/mob/living/proc/set_size,
/mob/living/carbon/human/proc/regenerate,
/mob/living/carbon/human/proc/promethean_select_opaqueness,
/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
/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(SPECIES_VR)
// 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, "<b>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.</b>") //No more prommie VR thing, so removed tidbit about changing appearance
to_chat(avatar, "<span class='notice'> You black out for a moment, and wake to find yourself in a new body in virtual reality.</span>") // 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, "<span class='notice'>You black out for a moment, and wake to find yourself back in your own body.</span>")
// 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, "<span class='warning'>Pain from your time in VR lingers.</span>") // 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
// ### Wooo, inheritance. Basically copying everything I don't need to edit from prometheans, because they mostly work already.
// ### Any and all of this is open to change for balance or whatever.
// ###
// ###
// Species definition follows.
/datum/species/shapeshifter/promethean/avatar
name = SPECIES_VR
name_plural = "Virtual Reality Avatars"
blurb = "A 3-dimensional representation of some sort of animate object used to display the presence and actions of some-one or -thing using a virtual reality program."
show_ssd = "eerily still"
death_message = "flickers briefly, their gear falling in a heap on the floor around their motionless body."
knockout_message = "has been knocked unconscious!"
spawn_flags = SPECIES_IS_RESTRICTED
speech_bubble_appearance = "cyber"
assisted_langs = list()
male_cough_sounds = list('sound/effects/mob_effects/m_cougha.ogg','sound/effects/mob_effects/m_coughb.ogg', 'sound/effects/mob_effects/m_coughc.ogg')
female_cough_sounds = list('sound/effects/mob_effects/f_cougha.ogg','sound/effects/mob_effects/f_coughb.ogg')
male_sneeze_sound = 'sound/effects/mob_effects/sneeze.ogg'
female_sneeze_sound = 'sound/effects/mob_effects/f_sneeze.ogg'
valid_transform_species = list(SPECIES_HUMAN, SPECIES_HUMAN_VATBORN, SPECIES_UNATHI, SPECIES_TAJ, SPECIES_SKRELL, SPECIES_DIONA, SPECIES_TESHARI, SPECIES_VOX, SPECIES_MONKEY, SPECIES_SKELETON)
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/shapeshifter_select_wings,
/mob/living/carbon/human/proc/shapeshifter_select_tail,
/mob/living/carbon/human/proc/shapeshifter_select_ears,
/mob/living/proc/set_size,
/mob/living/carbon/human/proc/regenerate,
/mob/living/carbon/human/proc/promethean_select_opaqueness,
/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
/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(SPECIES_VR)
// 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, "<b>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.</b>") //No more prommie VR thing, so removed tidbit about changing appearance
to_chat(avatar, "<span class='notice'> You black out for a moment, and wake to find yourself in a new body in virtual reality.</span>") // 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, "<span class='notice'>You black out for a moment, and wake to find yourself back in your own body.</span>")
// 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, "<span class='warning'>Pain from your time in VR lingers.</span>") // 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()
@@ -1,181 +1,181 @@
// 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 Tajaran"
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_teshari.dmi'
deform = 'icons/mob/human_races/r_teshari.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/teshari),
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/teshari),
BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/teshari),
BP_L_FOOT = list("path" = /obj/item/organ/external/foot/teshari),
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/teshari)
)
/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)
)
/datum/species/shapeshifter/promethean/avatar/monkey
name = "Virtual Reality Monkey"
icobase = 'icons/mob/human_races/monkeys/r_monkey.dmi'
deform = 'icons/mob/human_races/monkeys/r_monkey.dmi'
damage_overlays = 'icons/mob/human_races/masks/dam_monkey.dmi'
damage_mask = 'icons/mob/human_races/masks/dam_mask_monkey.dmi'
blood_mask = 'icons/mob/human_races/masks/blood_monkey.dmi'
fire_icon_state = "monkey"
appearance_flags = 0
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/no_eyes),
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/vox
name = "Virtual Reality Vox"
icobase = 'icons/mob/human_races/r_vox.dmi'
deform = 'icons/mob/human_races/r_def_vox.dmi'
appearance_flags = HAS_EYE_COLOR | HAS_HAIR_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/vox),
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/skeleton
name = "Virtual Reality Skeleton"
icobase = 'icons/mob/human_races/r_skeleton.dmi'
deform = 'icons/mob/human_races/r_skeleton.dmi'
appearance_flags = HAS_HAIR_COLOR | 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)
)
// 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 Tajaran"
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_teshari.dmi'
deform = 'icons/mob/human_races/r_teshari.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/teshari),
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/teshari),
BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/teshari),
BP_L_FOOT = list("path" = /obj/item/organ/external/foot/teshari),
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/teshari)
)
/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)
)
/datum/species/shapeshifter/promethean/avatar/monkey
name = "Virtual Reality Monkey"
icobase = 'icons/mob/human_races/monkeys/r_monkey.dmi'
deform = 'icons/mob/human_races/monkeys/r_monkey.dmi'
damage_overlays = 'icons/mob/human_races/masks/dam_monkey.dmi'
damage_mask = 'icons/mob/human_races/masks/dam_mask_monkey.dmi'
blood_mask = 'icons/mob/human_races/masks/blood_monkey.dmi'
fire_icon_state = "monkey"
appearance_flags = 0
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/no_eyes),
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/vox
name = "Virtual Reality Vox"
icobase = 'icons/mob/human_races/r_vox.dmi'
deform = 'icons/mob/human_races/r_def_vox.dmi'
appearance_flags = HAS_EYE_COLOR | HAS_HAIR_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/vox),
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/skeleton
name = "Virtual Reality Skeleton"
icobase = 'icons/mob/human_races/r_skeleton.dmi'
deform = 'icons/mob/human_races/r_skeleton.dmi'
appearance_flags = HAS_HAIR_COLOR | 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)
)
+177 -177
View File
@@ -1,177 +1,177 @@
/mob/living/carbon/human/proc/handle_strip(var/slot_to_strip,var/mob/living/user)
if(!slot_to_strip || !istype(user))
return
if(user.incapacitated() || !user.Adjacent(src))
user << browse(null, text("window=mob[src.name]"))
return
var/obj/item/target_slot = get_equipped_item(text2num(slot_to_strip))
switch(slot_to_strip)
// Handle things that are part of this interface but not removing/replacing a given item.
if("pockets")
visible_message("<span class='danger'>\The [user] is trying to empty \the [src]'s pockets!</span>")
if(do_after(user,HUMAN_STRIP_DELAY,src))
empty_pockets(user)
return
if("splints")
visible_message("<span class='danger'>\The [user] is trying to remove \the [src]'s splints!</span>")
if(do_after(user,HUMAN_STRIP_DELAY,src))
remove_splints(user)
return
if("sensors")
visible_message("<span class='danger'>\The [user] is trying to set \the [src]'s sensors!</span>")
if(do_after(user,HUMAN_STRIP_DELAY,src))
toggle_sensors(user)
return
if("internals")
visible_message("<span class='danger'>\The [usr] is trying to set \the [src]'s internals!</span>")
if(do_after(user,HUMAN_STRIP_DELAY,src))
toggle_internals(user)
return
if("tie")
var/obj/item/clothing/under/suit = w_uniform
if(!istype(suit) || !LAZYLEN(suit.accessories))
return
var/obj/item/clothing/accessory/A = suit.accessories[1]
if(!istype(A))
return
visible_message("<span class='danger'>\The [usr] is trying to remove \the [src]'s [A.name]!</span>")
if(!do_after(user,HUMAN_STRIP_DELAY,src))
return
if(!A || suit.loc != src || !(A in suit.accessories))
return
if(istype(A, /obj/item/clothing/accessory/badge) || istype(A, /obj/item/clothing/accessory/medal))
user.visible_message("<span class='danger'>\The [user] tears off \the [A] from [src]'s [suit.name]!</span>")
add_attack_logs(user,src,"Stripped [A.name] off [suit.name]")
A.on_removed(user)
suit.accessories -= A
update_inv_w_uniform()
return
// Are we placing or stripping?
var/stripping
var/obj/item/held = user.get_active_hand()
if(!istype(held) || is_robot_module(held))
stripping = TRUE
else
var/obj/item/weapon/holder/holder = held
if(istype(holder) && src == holder.held_mob)
stripping = TRUE
else
var/obj/item/weapon/grab/grab = held
if(istype(grab) && grab.affecting == src)
stripping = TRUE
if(stripping)
if(!istype(target_slot)) // They aren't holding anything valid and there's nothing to remove, why are we even here?
return
if(!target_slot.canremove)
to_chat(user, "<span class='warning'>You cannot remove \the [src]'s [target_slot.name].</span>")
return
visible_message("<span class='danger'>\The [user] is trying to remove \the [src]'s [target_slot.name]!</span>")
else
if(slot_to_strip == slot_wear_mask && istype(held, /obj/item/weapon/grenade))
visible_message("<span class='danger'>\The [user] is trying to put \a [held] in \the [src]'s mouth!</span>")
else
visible_message("<span class='danger'>\The [user] is trying to put \a [held] on \the [src]!</span>")
if(!do_after(user,HUMAN_STRIP_DELAY,src))
return
if(!stripping)
if(user.get_active_hand() != held)
return
var/obj/item/weapon/holder/mobheld = held
if(istype(mobheld)&&mobheld.held_mob==src)
to_chat(user, "<span class='warning'>You can't put someone on themselves! Stop trying to break reality!</span>")
return
if(stripping)
add_attack_logs(user,src,"Removed equipment from slot [target_slot]")
unEquip(target_slot)
else if(user.unEquip(held))
equip_to_slot_if_possible(held, text2num(slot_to_strip), 0, 1, 1)
if(held.loc != src)
user.put_in_hands(held)
// Empty out everything in the target's pockets.
/mob/living/carbon/human/proc/empty_pockets(var/mob/living/user)
if(!r_store && !l_store)
to_chat(user, "<span class='warning'>\The [src] has nothing in their pockets.</span>")
return
if(r_store)
unEquip(r_store)
if(l_store)
unEquip(l_store)
visible_message("<span class='danger'>\The [user] empties \the [src]'s pockets!</span>")
// Modify the current target sensor level.
/mob/living/carbon/human/proc/toggle_sensors(var/mob/living/user)
var/obj/item/clothing/under/suit = w_uniform
if(!suit)
to_chat(user, "<span class='warning'>\The [src] is not wearing a suit with sensors.</span>")
return
if (suit.has_sensor >= 2)
to_chat(user, "<span class='warning'>\The [src]'s suit sensor controls are locked.</span>")
return
add_attack_logs(user,src,"Adjusted suit sensor level")
suit.set_sensors(user)
// Remove all splints.
/mob/living/carbon/human/proc/remove_splints(var/mob/living/user)
var/can_reach_splints = 1
if(istype(wear_suit,/obj/item/clothing/suit/space))
var/obj/item/clothing/suit/space/suit = wear_suit
if(suit.supporting_limbs && suit.supporting_limbs.len)
to_chat(user, "<span class='warning'>You cannot remove the splints - [src]'s [suit] is supporting some of the breaks.</span>")
can_reach_splints = 0
if(can_reach_splints)
var/removed_splint
for(var/obj/item/organ/external/o in organs)
if (o && o.splinted)
var/obj/item/S = o.splinted
if(istype(S) && S.loc == o) //can only remove splints that are actually worn on the organ (deals with hardsuit splints)
S.add_fingerprint(user)
if(o.remove_splint())
user.put_in_active_hand(S)
removed_splint = 1
if(removed_splint)
visible_message("<span class='danger'>\The [user] removes \the [src]'s splints!</span>")
else
to_chat(user, "<span class='warning'>\The [src] has no splints to remove.</span>")
// Set internals on or off.
/mob/living/carbon/human/proc/toggle_internals(var/mob/living/user)
if(internal)
internal.add_fingerprint(user)
internal = null
if(internals)
internals.icon_state = "internal0"
else
// Check for airtight mask/helmet.
if(!(istype(wear_mask, /obj/item/clothing/mask) || istype(head, /obj/item/clothing/head/helmet/space)))
return
// Find an internal source.
if(istype(back, /obj/item/weapon/tank))
internal = back
else if(istype(s_store, /obj/item/weapon/tank))
internal = s_store
else if(istype(belt, /obj/item/weapon/tank))
internal = belt
if(internal)
visible_message("<span class='warning'>\The [src] is now running on internals!</span>")
internal.add_fingerprint(user)
if (internals)
internals.icon_state = "internal1"
else
visible_message("<span class='danger'>\The [user] disables \the [src]'s internals!</span>")
/mob/living/carbon/human/proc/handle_strip(var/slot_to_strip,var/mob/living/user)
if(!slot_to_strip || !istype(user))
return
if(user.incapacitated() || !user.Adjacent(src))
user << browse(null, text("window=mob[src.name]"))
return
var/obj/item/target_slot = get_equipped_item(text2num(slot_to_strip))
switch(slot_to_strip)
// Handle things that are part of this interface but not removing/replacing a given item.
if("pockets")
visible_message("<span class='danger'>\The [user] is trying to empty \the [src]'s pockets!</span>")
if(do_after(user,HUMAN_STRIP_DELAY,src))
empty_pockets(user)
return
if("splints")
visible_message("<span class='danger'>\The [user] is trying to remove \the [src]'s splints!</span>")
if(do_after(user,HUMAN_STRIP_DELAY,src))
remove_splints(user)
return
if("sensors")
visible_message("<span class='danger'>\The [user] is trying to set \the [src]'s sensors!</span>")
if(do_after(user,HUMAN_STRIP_DELAY,src))
toggle_sensors(user)
return
if("internals")
visible_message("<span class='danger'>\The [usr] is trying to set \the [src]'s internals!</span>")
if(do_after(user,HUMAN_STRIP_DELAY,src))
toggle_internals(user)
return
if("tie")
var/obj/item/clothing/under/suit = w_uniform
if(!istype(suit) || !LAZYLEN(suit.accessories))
return
var/obj/item/clothing/accessory/A = suit.accessories[1]
if(!istype(A))
return
visible_message("<span class='danger'>\The [usr] is trying to remove \the [src]'s [A.name]!</span>")
if(!do_after(user,HUMAN_STRIP_DELAY,src))
return
if(!A || suit.loc != src || !(A in suit.accessories))
return
if(istype(A, /obj/item/clothing/accessory/badge) || istype(A, /obj/item/clothing/accessory/medal))
user.visible_message("<span class='danger'>\The [user] tears off \the [A] from [src]'s [suit.name]!</span>")
add_attack_logs(user,src,"Stripped [A.name] off [suit.name]")
A.on_removed(user)
suit.accessories -= A
update_inv_w_uniform()
return
// Are we placing or stripping?
var/stripping
var/obj/item/held = user.get_active_hand()
if(!istype(held) || is_robot_module(held))
stripping = TRUE
else
var/obj/item/weapon/holder/holder = held
if(istype(holder) && src == holder.held_mob)
stripping = TRUE
else
var/obj/item/weapon/grab/grab = held
if(istype(grab) && grab.affecting == src)
stripping = TRUE
if(stripping)
if(!istype(target_slot)) // They aren't holding anything valid and there's nothing to remove, why are we even here?
return
if(!target_slot.canremove)
to_chat(user, "<span class='warning'>You cannot remove \the [src]'s [target_slot.name].</span>")
return
visible_message("<span class='danger'>\The [user] is trying to remove \the [src]'s [target_slot.name]!</span>")
else
if(slot_to_strip == slot_wear_mask && istype(held, /obj/item/weapon/grenade))
visible_message("<span class='danger'>\The [user] is trying to put \a [held] in \the [src]'s mouth!</span>")
else
visible_message("<span class='danger'>\The [user] is trying to put \a [held] on \the [src]!</span>")
if(!do_after(user,HUMAN_STRIP_DELAY,src))
return
if(!stripping)
if(user.get_active_hand() != held)
return
var/obj/item/weapon/holder/mobheld = held
if(istype(mobheld)&&mobheld.held_mob==src)
to_chat(user, "<span class='warning'>You can't put someone on themselves! Stop trying to break reality!</span>")
return
if(stripping)
add_attack_logs(user,src,"Removed equipment from slot [target_slot]")
unEquip(target_slot)
else if(user.unEquip(held))
equip_to_slot_if_possible(held, text2num(slot_to_strip), 0, 1, 1)
if(held.loc != src)
user.put_in_hands(held)
// Empty out everything in the target's pockets.
/mob/living/carbon/human/proc/empty_pockets(var/mob/living/user)
if(!r_store && !l_store)
to_chat(user, "<span class='warning'>\The [src] has nothing in their pockets.</span>")
return
if(r_store)
unEquip(r_store)
if(l_store)
unEquip(l_store)
visible_message("<span class='danger'>\The [user] empties \the [src]'s pockets!</span>")
// Modify the current target sensor level.
/mob/living/carbon/human/proc/toggle_sensors(var/mob/living/user)
var/obj/item/clothing/under/suit = w_uniform
if(!suit)
to_chat(user, "<span class='warning'>\The [src] is not wearing a suit with sensors.</span>")
return
if (suit.has_sensor >= 2)
to_chat(user, "<span class='warning'>\The [src]'s suit sensor controls are locked.</span>")
return
add_attack_logs(user,src,"Adjusted suit sensor level")
suit.set_sensors(user)
// Remove all splints.
/mob/living/carbon/human/proc/remove_splints(var/mob/living/user)
var/can_reach_splints = 1
if(istype(wear_suit,/obj/item/clothing/suit/space))
var/obj/item/clothing/suit/space/suit = wear_suit
if(suit.supporting_limbs && suit.supporting_limbs.len)
to_chat(user, "<span class='warning'>You cannot remove the splints - [src]'s [suit] is supporting some of the breaks.</span>")
can_reach_splints = 0
if(can_reach_splints)
var/removed_splint
for(var/obj/item/organ/external/o in organs)
if (o && o.splinted)
var/obj/item/S = o.splinted
if(istype(S) && S.loc == o) //can only remove splints that are actually worn on the organ (deals with hardsuit splints)
S.add_fingerprint(user)
if(o.remove_splint())
user.put_in_active_hand(S)
removed_splint = 1
if(removed_splint)
visible_message("<span class='danger'>\The [user] removes \the [src]'s splints!</span>")
else
to_chat(user, "<span class='warning'>\The [src] has no splints to remove.</span>")
// Set internals on or off.
/mob/living/carbon/human/proc/toggle_internals(var/mob/living/user)
if(internal)
internal.add_fingerprint(user)
internal = null
if(internals)
internals.icon_state = "internal0"
else
// Check for airtight mask/helmet.
if(!(istype(wear_mask, /obj/item/clothing/mask) || istype(head, /obj/item/clothing/head/helmet/space)))
return
// Find an internal source.
if(istype(back, /obj/item/weapon/tank))
internal = back
else if(istype(s_store, /obj/item/weapon/tank))
internal = s_store
else if(istype(belt, /obj/item/weapon/tank))
internal = belt
if(internal)
visible_message("<span class='warning'>\The [src] is now running on internals!</span>")
internal.add_fingerprint(user)
if (internals)
internals.icon_state = "internal1"
else
visible_message("<span class='danger'>\The [user] disables \the [src]'s internals!</span>")
File diff suppressed because it is too large Load Diff
+169 -169
View File
@@ -1,169 +1,169 @@
/mob/living/carbon/slime/proc/Wrap(var/mob/living/M) // This is a proc for the clicks
if (Victim == M || src == M)
Feedstop()
return
if (Victim)
to_chat(src, "I am already feeding...")
return
var t = invalidFeedTarget(M)
if (t)
to_chat(src,t)
return
Feedon(M)
/mob/living/carbon/slime/proc/invalidFeedTarget(var/mob/living/M)
if (!M || !istype(M))
return "This subject is incomparable..."
if (istype(M, /mob/living/carbon/slime)) // No cannibalism... yet
return "I cannot feed on other slimes..."
if (!Adjacent(M))
return "This subject is too far away..."
if (istype(M, /mob/living/carbon) && M.getCloneLoss() >= M.getMaxHealth() * 1.5 || istype(M, /mob/living/simple_mob) && M.stat == DEAD)
return "This subject does not have an edible life energy..."
for(var/mob/living/carbon/slime/met in view())
if(met.Victim == M && met != src)
return "The [met.name] is already feeding on this subject..."
return 0
/mob/living/carbon/slime/proc/Feedon(var/mob/living/M)
Victim = M
loc = M.loc
canmove = 0
anchored = TRUE
regenerate_icons()
while(Victim && !invalidFeedTarget(M) && stat != 2)
canmove = 0
if(Adjacent(M))
UpdateFeed(M)
if(istype(M, /mob/living/carbon))
Victim.adjustCloneLoss(rand(5,6))
Victim.adjustToxLoss(rand(1,2))
if(Victim.health <= 0)
Victim.adjustToxLoss(rand(2,4))
else if(istype(M, /mob/living/simple_mob))
Victim.adjustBruteLoss(is_adult ? rand(7, 15) : rand(4, 12))
else
to_chat(src, "<span class='warning'>[pick("This subject is incompatible", "This subject does not have a life energy", "This subject is empty", "I am not satisfied", "I can not feed from this subject", "I do not feel nourished", "This subject is not food")]...</span>")
Feedstop()
break
if(prob(15) && M.client && istype(M, /mob/living/carbon))
var/painMes = pick("You can feel your body becoming weak!", "You feel like you're about to die!", "You feel every part of your body screaming in agony!", "A low, rolling pain passes through your body!", "Your body feels as if it's falling apart!", "You feel extremely weak!", "A sharp, deep pain bathes every inch of your body!")
if (ishuman(M))
var/mob/living/carbon/human/H = M
H.custom_pain(painMes, 100)
else if (istype(M, /mob/living/carbon))
var/mob/living/carbon/C = M
if (C.can_feel_pain())
to_chat(M, "<span class='danger'>[painMes]</span>")
gain_nutrition(rand(20,25))
adjustOxyLoss(-10) //Heal yourself
adjustBruteLoss(-10)
adjustFireLoss(-10)
adjustCloneLoss(-10)
updatehealth()
if(Victim)
Victim.updatehealth()
sleep(30) // Deal damage every 3 seconds
else
break
canmove = 1
anchored = FALSE
if(M && invalidFeedTarget(M)) // This means that the slime drained the victim
if(!client)
if(Victim && !rabid && !attacked && Victim.LAssailant && Victim.LAssailant != Victim && prob(50))
if(!(Victim.LAssailant in Friends))
Friends[Victim.LAssailant] = 1
else
++Friends[Victim.LAssailant]
else
to_chat(src, "<span class='notice'>This subject does not have a strong enough life energy anymore...</span>")
Victim = null
/mob/living/carbon/slime/proc/Feedstop()
if(Victim)
if(Victim.client)
to_chat(Victim, "[src] has let go of your head!")
Victim = null
/mob/living/carbon/slime/proc/UpdateFeed(var/mob/M)
if(Victim)
if(Victim == M)
loc = M.loc // simple "attach to head" effect!
/mob/living/carbon/slime/verb/Evolve()
set category = "Slime"
set desc = "This will let you evolve from baby to adult slime."
if(stat)
to_chat(src, "<span class='notice'>I must be conscious to do this...</span>")
return
if(!is_adult)
if(amount_grown >= 10)
is_adult = 1
maxHealth = 200
amount_grown = 0
regenerate_icons()
name = text("[colour] [is_adult ? "adult" : "baby"] slime ([number])")
else
to_chat(src, "<span class='notice'>I am not ready to evolve yet...</span>")
else
to_chat(src, "<span class='notice'>I have already evolved...</span>")
/mob/living/carbon/slime/verb/Reproduce()
set category = "Slime"
set desc = "This will make you split into four Slimes."
if(stat)
to_chat(src, "<span class='notice'>I must be conscious to do this...</span>")
return
if(is_adult)
if(amount_grown >= 10)
if(stat)
to_chat(src, "<span class='notice'>I must be conscious to do this...</span>")
return
var/list/babies = list()
var/new_nutrition = round(nutrition * 0.9)
var/new_powerlevel = round(powerlevel / 4)
for(var/i = 1, i <= 4, i++)
var/t = colour
if(prob(mutation_chance))
t = slime_mutation[rand(1,4)]
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime/(loc, t)
if(ckey) M.nutrition = new_nutrition //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature!
M.powerlevel = new_powerlevel
if(i != 1) step_away(M, src)
M.Friends = Friends.Copy()
babies += M
feedback_add_details("slime_babies_born","slimebirth_[replacetext(M.colour," ","_")]")
var/mob/living/carbon/slime/new_slime = pick(babies)
new_slime.universal_speak = universal_speak
if(src.mind)
src.mind.transfer_to(new_slime)
else
new_slime.key = src.key
qdel(src)
else
to_chat(src, "<span class='notice'>I am not ready to reproduce yet...</span>")
else
to_chat(src, "<span class='notice'>I am not old enough to reproduce yet...</span>")
/mob/living/carbon/slime/proc/Wrap(var/mob/living/M) // This is a proc for the clicks
if (Victim == M || src == M)
Feedstop()
return
if (Victim)
to_chat(src, "I am already feeding...")
return
var t = invalidFeedTarget(M)
if (t)
to_chat(src,t)
return
Feedon(M)
/mob/living/carbon/slime/proc/invalidFeedTarget(var/mob/living/M)
if (!M || !istype(M))
return "This subject is incomparable..."
if (istype(M, /mob/living/carbon/slime)) // No cannibalism... yet
return "I cannot feed on other slimes..."
if (!Adjacent(M))
return "This subject is too far away..."
if (istype(M, /mob/living/carbon) && M.getCloneLoss() >= M.getMaxHealth() * 1.5 || istype(M, /mob/living/simple_mob) && M.stat == DEAD)
return "This subject does not have an edible life energy..."
for(var/mob/living/carbon/slime/met in view())
if(met.Victim == M && met != src)
return "The [met.name] is already feeding on this subject..."
return 0
/mob/living/carbon/slime/proc/Feedon(var/mob/living/M)
Victim = M
loc = M.loc
canmove = 0
anchored = TRUE
regenerate_icons()
while(Victim && !invalidFeedTarget(M) && stat != 2)
canmove = 0
if(Adjacent(M))
UpdateFeed(M)
if(istype(M, /mob/living/carbon))
Victim.adjustCloneLoss(rand(5,6))
Victim.adjustToxLoss(rand(1,2))
if(Victim.health <= 0)
Victim.adjustToxLoss(rand(2,4))
else if(istype(M, /mob/living/simple_mob))
Victim.adjustBruteLoss(is_adult ? rand(7, 15) : rand(4, 12))
else
to_chat(src, "<span class='warning'>[pick("This subject is incompatible", "This subject does not have a life energy", "This subject is empty", "I am not satisfied", "I can not feed from this subject", "I do not feel nourished", "This subject is not food")]...</span>")
Feedstop()
break
if(prob(15) && M.client && istype(M, /mob/living/carbon))
var/painMes = pick("You can feel your body becoming weak!", "You feel like you're about to die!", "You feel every part of your body screaming in agony!", "A low, rolling pain passes through your body!", "Your body feels as if it's falling apart!", "You feel extremely weak!", "A sharp, deep pain bathes every inch of your body!")
if (ishuman(M))
var/mob/living/carbon/human/H = M
H.custom_pain(painMes, 100)
else if (istype(M, /mob/living/carbon))
var/mob/living/carbon/C = M
if (C.can_feel_pain())
to_chat(M, "<span class='danger'>[painMes]</span>")
gain_nutrition(rand(20,25))
adjustOxyLoss(-10) //Heal yourself
adjustBruteLoss(-10)
adjustFireLoss(-10)
adjustCloneLoss(-10)
updatehealth()
if(Victim)
Victim.updatehealth()
sleep(30) // Deal damage every 3 seconds
else
break
canmove = 1
anchored = FALSE
if(M && invalidFeedTarget(M)) // This means that the slime drained the victim
if(!client)
if(Victim && !rabid && !attacked && Victim.LAssailant && Victim.LAssailant != Victim && prob(50))
if(!(Victim.LAssailant in Friends))
Friends[Victim.LAssailant] = 1
else
++Friends[Victim.LAssailant]
else
to_chat(src, "<span class='notice'>This subject does not have a strong enough life energy anymore...</span>")
Victim = null
/mob/living/carbon/slime/proc/Feedstop()
if(Victim)
if(Victim.client)
to_chat(Victim, "[src] has let go of your head!")
Victim = null
/mob/living/carbon/slime/proc/UpdateFeed(var/mob/M)
if(Victim)
if(Victim == M)
loc = M.loc // simple "attach to head" effect!
/mob/living/carbon/slime/verb/Evolve()
set category = "Slime"
set desc = "This will let you evolve from baby to adult slime."
if(stat)
to_chat(src, "<span class='notice'>I must be conscious to do this...</span>")
return
if(!is_adult)
if(amount_grown >= 10)
is_adult = 1
maxHealth = 200
amount_grown = 0
regenerate_icons()
name = text("[colour] [is_adult ? "adult" : "baby"] slime ([number])")
else
to_chat(src, "<span class='notice'>I am not ready to evolve yet...</span>")
else
to_chat(src, "<span class='notice'>I have already evolved...</span>")
/mob/living/carbon/slime/verb/Reproduce()
set category = "Slime"
set desc = "This will make you split into four Slimes."
if(stat)
to_chat(src, "<span class='notice'>I must be conscious to do this...</span>")
return
if(is_adult)
if(amount_grown >= 10)
if(stat)
to_chat(src, "<span class='notice'>I must be conscious to do this...</span>")
return
var/list/babies = list()
var/new_nutrition = round(nutrition * 0.9)
var/new_powerlevel = round(powerlevel / 4)
for(var/i = 1, i <= 4, i++)
var/t = colour
if(prob(mutation_chance))
t = slime_mutation[rand(1,4)]
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime/(loc, t)
if(ckey) M.nutrition = new_nutrition //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature!
M.powerlevel = new_powerlevel
if(i != 1) step_away(M, src)
M.Friends = Friends.Copy()
babies += M
feedback_add_details("slime_babies_born","slimebirth_[replacetext(M.colour," ","_")]")
var/mob/living/carbon/slime/new_slime = pick(babies)
new_slime.universal_speak = universal_speak
if(src.mind)
src.mind.transfer_to(new_slime)
else
new_slime.key = src.key
qdel(src)
else
to_chat(src, "<span class='notice'>I am not ready to reproduce yet...</span>")
else
to_chat(src, "<span class='notice'>I am not old enough to reproduce yet...</span>")
+99 -99
View File
@@ -1,99 +1,99 @@
/mob/living/carbon/resist_fire()
adjust_fire_stacks(-1.2)
Weaken(3)
spin(32,2)
visible_message(
"<span class='danger'>[src] rolls on the floor, trying to put themselves out!</span>",
"<span class='notice'>You stop, drop, and roll!</span>"
)
sleep(30)
if(fire_stacks <= 0)
visible_message(
"<span class='danger'>[src] has successfully extinguished themselves!</span>",
"<span class='notice'>You extinguish yourself.</span>"
)
ExtinguishMob()
return TRUE
/mob/living/carbon/resist_restraints()
var/obj/item/I = null
if(handcuffed)
I = handcuffed
else if(legcuffed)
I = legcuffed
if(I)
setClickCooldown(100)
cuff_resist(I, cuff_break = can_break_cuffs())
/mob/living/carbon/proc/reduce_cuff_time()
return FALSE
/mob/living/carbon/proc/cuff_resist(obj/item/weapon/handcuffs/I, breakouttime = 1200, cuff_break = 0)
if(istype(I))
breakouttime = I.breakouttime
var/displaytime = breakouttime / 10
var/reduceCuffTime = reduce_cuff_time()
if(reduceCuffTime)
breakouttime /= reduceCuffTime
displaytime /= reduceCuffTime
if(cuff_break)
visible_message("<span class='danger'>[src] is trying to break [I]!</span>",
"<span class='warning'>You attempt to break your [I]. (This will take around 5 seconds and you need to stand still)</span>")
if(do_after(src, 5 SECONDS, target = src, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED))
if(!I || buckled)
return
visible_message("<span class='danger'>[src] manages to break [I]!</span>",
"<span class='warning'>You successfully break your [I].</span>")
say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
if(I == handcuffed)
handcuffed = null
update_handcuffed()
else if(I == legcuffed)
legcuffed = null
update_inv_legcuffed()
if(buckled && buckled.buckle_require_restraints)
buckled.unbuckle_mob()
qdel(I)
else
to_chat(src, "<span class='warning'>You fail to break [I].</span>")
return
visible_message("<span class='danger'>[src] attempts to remove [I]!</span>",
"<span class='warning'>You attempt to remove [I]. (This will take around [displaytime] seconds and you need to stand still)</span>")
if(do_after(src, breakouttime, target = src, incapacitation_flags = INCAPACITATION_DISABLED & INCAPACITATION_KNOCKDOWN))
visible_message("<span class='danger'>[src] manages to remove [I]!</span>",
"<span class='notice'>You successfully remove [I].</span>")
drop_from_inventory(I)
/mob/living/carbon/resist_buckle()
if(!buckled)
return
if(!restrained())
return ..()
setClickCooldown(100)
visible_message(
"<span class='danger'>[src] attempts to unbuckle themself!</span>",
"<span class='warning'>You attempt to unbuckle yourself. (This will take around 2 minutes and you need to stand still)</span>"
)
if(do_after(src, 2 MINUTES, incapacitation_flags = INCAPACITATION_DEFAULT & ~(INCAPACITATION_RESTRAINED | INCAPACITATION_BUCKLED_FULLY)))
if(!buckled)
return
visible_message("<span class='danger'>[src] manages to unbuckle themself!</span>",
"<span class='notice'>You successfully unbuckle yourself.</span>")
buckled.user_unbuckle_mob(src, src)
/mob/living/carbon/proc/can_break_cuffs()
if(HULK in mutations)
return 1
/mob/living/carbon/resist_fire()
adjust_fire_stacks(-1.2)
Weaken(3)
spin(32,2)
visible_message(
"<span class='danger'>[src] rolls on the floor, trying to put themselves out!</span>",
"<span class='notice'>You stop, drop, and roll!</span>"
)
sleep(30)
if(fire_stacks <= 0)
visible_message(
"<span class='danger'>[src] has successfully extinguished themselves!</span>",
"<span class='notice'>You extinguish yourself.</span>"
)
ExtinguishMob()
return TRUE
/mob/living/carbon/resist_restraints()
var/obj/item/I = null
if(handcuffed)
I = handcuffed
else if(legcuffed)
I = legcuffed
if(I)
setClickCooldown(100)
cuff_resist(I, cuff_break = can_break_cuffs())
/mob/living/carbon/proc/reduce_cuff_time()
return FALSE
/mob/living/carbon/proc/cuff_resist(obj/item/weapon/handcuffs/I, breakouttime = 1200, cuff_break = 0)
if(istype(I))
breakouttime = I.breakouttime
var/displaytime = breakouttime / 10
var/reduceCuffTime = reduce_cuff_time()
if(reduceCuffTime)
breakouttime /= reduceCuffTime
displaytime /= reduceCuffTime
if(cuff_break)
visible_message("<span class='danger'>[src] is trying to break [I]!</span>",
"<span class='warning'>You attempt to break your [I]. (This will take around 5 seconds and you need to stand still)</span>")
if(do_after(src, 5 SECONDS, target = src, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED))
if(!I || buckled)
return
visible_message("<span class='danger'>[src] manages to break [I]!</span>",
"<span class='warning'>You successfully break your [I].</span>")
say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
if(I == handcuffed)
handcuffed = null
update_handcuffed()
else if(I == legcuffed)
legcuffed = null
update_inv_legcuffed()
if(buckled && buckled.buckle_require_restraints)
buckled.unbuckle_mob()
qdel(I)
else
to_chat(src, "<span class='warning'>You fail to break [I].</span>")
return
visible_message("<span class='danger'>[src] attempts to remove [I]!</span>",
"<span class='warning'>You attempt to remove [I]. (This will take around [displaytime] seconds and you need to stand still)</span>")
if(do_after(src, breakouttime, target = src, incapacitation_flags = INCAPACITATION_DISABLED & INCAPACITATION_KNOCKDOWN))
visible_message("<span class='danger'>[src] manages to remove [I]!</span>",
"<span class='notice'>You successfully remove [I].</span>")
drop_from_inventory(I)
/mob/living/carbon/resist_buckle()
if(!buckled)
return
if(!restrained())
return ..()
setClickCooldown(100)
visible_message(
"<span class='danger'>[src] attempts to unbuckle themself!</span>",
"<span class='warning'>You attempt to unbuckle yourself. (This will take around 2 minutes and you need to stand still)</span>"
)
if(do_after(src, 2 MINUTES, incapacitation_flags = INCAPACITATION_DEFAULT & ~(INCAPACITATION_RESTRAINED | INCAPACITATION_BUCKLED_FULLY)))
if(!buckled)
return
visible_message("<span class='danger'>[src] manages to unbuckle themself!</span>",
"<span class='notice'>You successfully unbuckle yourself.</span>")
buckled.user_unbuckle_mob(src, src)
/mob/living/carbon/proc/can_break_cuffs()
if(HULK in mutations)
return 1
+47 -47
View File
@@ -1,48 +1,48 @@
/mob/living/carbon/proc/handle_viruses()
if(status_flags & GODMODE) return 0 //godmode
if(bodytemperature > 406)
for (var/ID in virus2)
var/datum/disease2/disease/V = virus2[ID]
V.cure(src)
if(life_tick % 3) //don't spam checks over all objects in view every tick.
for(var/obj/effect/decal/cleanable/O in view(1,src))
if(istype(O,/obj/effect/decal/cleanable/blood))
var/obj/effect/decal/cleanable/blood/B = O
if(B.virus2.len)
for (var/ID in B.virus2)
var/datum/disease2/disease/V = B.virus2[ID]
infect_virus2(src,V)
else if(istype(O,/obj/effect/decal/cleanable/mucus))
var/obj/effect/decal/cleanable/mucus/M = O
if(M.virus2.len)
for (var/ID in M.virus2)
var/datum/disease2/disease/V = M.virus2[ID]
infect_virus2(src,V)
else if(istype(O,/obj/effect/decal/cleanable/vomit))
var/obj/effect/decal/cleanable/vomit/Vom = O
if(Vom.virus2.len)
for (var/ID in Vom.virus2)
var/datum/disease2/disease/V = Vom.virus2[ID]
infect_virus2(src,V)
if(virus2.len)
for (var/ID in virus2)
var/datum/disease2/disease/V = virus2[ID]
if(isnull(V)) // Trying to figure out a runtime error that keeps repeating
CRASH("virus2 nulled before calling activate()")
else
V.activate(src)
// activate may have deleted the virus
if(!V) continue
// check if we're immune
var/list/common_antibodies = V.antigen & src.antibodies
if(common_antibodies.len)
V.dead = 1
/mob/living/carbon/proc/handle_viruses()
if(status_flags & GODMODE) return 0 //godmode
if(bodytemperature > 406)
for (var/ID in virus2)
var/datum/disease2/disease/V = virus2[ID]
V.cure(src)
if(life_tick % 3) //don't spam checks over all objects in view every tick.
for(var/obj/effect/decal/cleanable/O in view(1,src))
if(istype(O,/obj/effect/decal/cleanable/blood))
var/obj/effect/decal/cleanable/blood/B = O
if(B.virus2.len)
for (var/ID in B.virus2)
var/datum/disease2/disease/V = B.virus2[ID]
infect_virus2(src,V)
else if(istype(O,/obj/effect/decal/cleanable/mucus))
var/obj/effect/decal/cleanable/mucus/M = O
if(M.virus2.len)
for (var/ID in M.virus2)
var/datum/disease2/disease/V = M.virus2[ID]
infect_virus2(src,V)
else if(istype(O,/obj/effect/decal/cleanable/vomit))
var/obj/effect/decal/cleanable/vomit/Vom = O
if(Vom.virus2.len)
for (var/ID in Vom.virus2)
var/datum/disease2/disease/V = Vom.virus2[ID]
infect_virus2(src,V)
if(virus2.len)
for (var/ID in virus2)
var/datum/disease2/disease/V = virus2[ID]
if(isnull(V)) // Trying to figure out a runtime error that keeps repeating
CRASH("virus2 nulled before calling activate()")
else
V.activate(src)
// activate may have deleted the virus
if(!V) continue
// check if we're immune
var/list/common_antibodies = V.antigen & src.antibodies
if(common_antibodies.len)
V.dead = 1
return
+194 -194
View File
@@ -1,194 +1,194 @@
/*
apply_damage(a,b,c)
args
a:damage - How much damage to take
b:damage_type - What type of damage to take, brute, burn
c:def_zone - Where to take the damage if its brute or burn
Returns
standard 0 if fail
*/
/mob/living/proc/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/soaked = 0, var/used_weapon = null, var/sharp = FALSE, var/edge = FALSE, var/obj/used_weapon = null)
if(Debug2)
to_world_log("## DEBUG: apply_damage() was called on [src], with [damage] damage, and an armor value of [blocked].")
if(!damage || (blocked >= 100))
return 0
for(var/datum/modifier/M in modifiers) //MODIFIER STUFF. It's best to do this RIGHT before armor is calculated, so it's done here! This is the 'forcefield' defence.
if(damagetype == BRUTE && (!isnull(M.effective_brute_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_brute_resistance
continue
if((damagetype == BURN || damagetype == ELECTROCUTE)&& (!isnull(M.effective_fire_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_fire_resistance
continue
if(damagetype == TOX && (!isnull(M.effective_tox_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_tox_resistance
continue
if(damagetype == OXY && (!isnull(M.effective_oxy_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_oxy_resistance
continue
if(damagetype == CLONE && (!isnull(M.effective_clone_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_clone_resistance
continue
if(damagetype == HALLOSS && (!isnull(M.effective_hal_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_hal_resistance
continue
if(damagetype == SEARING && (!isnull(M.effective_fire_resistance) || !isnull(M.effective_brute_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
var/damage_mitigation = 0//Used for dual calculations.
if(!isnull(M.effective_fire_resistance))
damage_mitigation += round((1/3)*damage * M.effective_fire_resistance)
if(!isnull(M.effective_brute_resistance))
damage_mitigation += round((2/3)*damage * M.effective_brute_resistance)
damage -= damage_mitigation
continue
if(damagetype == BIOACID && (isSynthetic() && (!isnull(M.effective_fire_resistance))) || (!isSynthetic() && M.effective_tox_resistance))
if(isSynthetic())
damage = damage * M.effective_fire_resistance
else
damage = damage * M.effective_tox_resistance
continue
if(soaked)
if(soaked >= round(damage*0.8))
damage -= round(damage*0.8)
else
damage -= soaked
var/initial_blocked = blocked
blocked = (100-blocked)/100
switch(damagetype)
if(BRUTE)
adjustBruteLoss(damage * blocked)
if(BURN)
if(COLD_RESISTANCE in mutations)
damage = 0
adjustFireLoss(damage * blocked)
if(SEARING)
apply_damage(round(damage / 3), BURN, def_zone, initial_blocked, soaked, used_weapon, sharp, edge)
apply_damage(round(damage / 3 * 2), BRUTE, def_zone, initial_blocked, soaked, used_weapon, sharp, edge)
if(TOX)
adjustToxLoss(damage * blocked)
if(OXY)
adjustOxyLoss(damage * blocked)
if(CLONE)
adjustCloneLoss(damage * blocked)
if(HALLOSS)
adjustHalLoss(damage * blocked)
if(ELECTROCUTE)
electrocute_act(damage, used_weapon, 1.0, def_zone)
if(BIOACID)
if(isSynthetic())
apply_damage(damage, BURN, def_zone, initial_blocked, soaked, used_weapon, sharp, edge) // Handle it as normal burn.
else
adjustToxLoss(damage * blocked)
if(ELECTROMAG)
damage = damage * blocked
switch(round(damage))
if(91 to INFINITY)
emp_act(1)
if(76 to 90)
if(prob(50))
emp_act(1)
else
emp_act(2)
if(61 to 75)
emp_act(2)
if(46 to 60)
if(prob(50))
emp_act(2)
else
emp_act(3)
if(31 to 45)
emp_act(3)
if(16 to 30)
if(prob(50))
emp_act(3)
else
emp_act(4)
if(0 to 15)
emp_act(4)
flash_weak_pain()
updatehealth()
return 1
/mob/living/proc/apply_damages(var/brute = 0, var/burn = 0, var/tox = 0, var/oxy = 0, var/clone = 0, var/halloss = 0, var/def_zone = null, var/blocked = 0)
if(blocked >= 100)
return 0
// INSERT MODIFIER CODE HERE... But no, really, only two things in the game use it, quad and viruses. The former is admin-only and the latter wouldn't be affected logically, but would if shield code was inerted here. If you really want, you can copy&paste the above and modify it to adjust brute/burn/etc. I do not advise this however.
if(brute) apply_damage(brute, BRUTE, def_zone, blocked)
if(burn) apply_damage(burn, BURN, def_zone, blocked)
if(tox) apply_damage(tox, TOX, def_zone, blocked)
if(oxy) apply_damage(oxy, OXY, def_zone, blocked)
if(clone) apply_damage(clone, CLONE, def_zone, blocked)
if(halloss) apply_damage(halloss, HALLOSS, def_zone, blocked)
return 1
/mob/living/proc/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0, var/check_protection = 1)
if(Debug2)
to_world_log("## DEBUG: apply_effect() was called. The type of effect is [effecttype]. Blocked by [blocked].")
if(!effect || (blocked >= 100))
return 0
blocked = (100-blocked)/100
switch(effecttype)
if(STUN)
Stun(effect * blocked)
if(WEAKEN)
Weaken(effect * blocked)
if(PARALYZE)
Paralyse(effect * blocked)
if(AGONY)
halloss += max((effect * blocked), 0) // Useful for objects that cause "subdual" damage. PAIN!
if(IRRADIATE)
/*
var/rad_protection = check_protection ? getarmor(null, "rad")/100 : 0
radiation += max((1-rad_protection)*effect/(blocked+1),0)//Rads auto check armor
*/
var/rad_protection = getarmor(null, "rad")
rad_protection = (100-rad_protection)/100
radiation += max((effect * rad_protection), 0)
if(STUTTER)
if(status_flags & CANSTUN) // stun is usually associated with stutter
stuttering = max(stuttering,(effect * blocked))
if(EYE_BLUR)
eye_blurry = max(eye_blurry,(effect * blocked))
if(DROWSY)
drowsyness = max(drowsyness,(effect * blocked))
updatehealth()
return 1
/mob/living/proc/apply_effects(var/stun = 0, var/weaken = 0, var/paralyze = 0, var/irradiate = 0, var/stutter = 0, var/eyeblur = 0, var/drowsy = 0, var/agony = 0, var/blocked = 0, var/ignite = 0, var/flammable = 0)
if(blocked >= 100)
return 0
if(stun) apply_effect(stun, STUN, blocked)
if(weaken) apply_effect(weaken, WEAKEN, blocked)
if(paralyze) apply_effect(paralyze, PARALYZE, blocked)
if(irradiate) apply_effect(irradiate, IRRADIATE, blocked)
if(stutter) apply_effect(stutter, STUTTER, blocked)
if(eyeblur) apply_effect(eyeblur, EYE_BLUR, blocked)
if(drowsy) apply_effect(drowsy, DROWSY, blocked)
if(agony) apply_effect(agony, AGONY, blocked)
if(flammable) adjust_fire_stacks(flammable)
if(ignite)
if(ignite >= 3)
add_modifier(/datum/modifier/fire/stack_managed/intense, 60 SECONDS)
else
add_modifier(/datum/modifier/fire/stack_managed, 45 * ignite SECONDS)
return 1
/*
apply_damage(a,b,c)
args
a:damage - How much damage to take
b:damage_type - What type of damage to take, brute, burn
c:def_zone - Where to take the damage if its brute or burn
Returns
standard 0 if fail
*/
/mob/living/proc/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/soaked = 0, var/used_weapon = null, var/sharp = FALSE, var/edge = FALSE, var/obj/used_weapon = null)
if(Debug2)
to_world_log("## DEBUG: apply_damage() was called on [src], with [damage] damage, and an armor value of [blocked].")
if(!damage || (blocked >= 100))
return 0
for(var/datum/modifier/M in modifiers) //MODIFIER STUFF. It's best to do this RIGHT before armor is calculated, so it's done here! This is the 'forcefield' defence.
if(damagetype == BRUTE && (!isnull(M.effective_brute_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_brute_resistance
continue
if((damagetype == BURN || damagetype == ELECTROCUTE)&& (!isnull(M.effective_fire_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_fire_resistance
continue
if(damagetype == TOX && (!isnull(M.effective_tox_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_tox_resistance
continue
if(damagetype == OXY && (!isnull(M.effective_oxy_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_oxy_resistance
continue
if(damagetype == CLONE && (!isnull(M.effective_clone_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_clone_resistance
continue
if(damagetype == HALLOSS && (!isnull(M.effective_hal_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
damage = damage * M.effective_hal_resistance
continue
if(damagetype == SEARING && (!isnull(M.effective_fire_resistance) || !isnull(M.effective_brute_resistance)))
if(M.energy_based)
M.energy_source.use(M.damage_cost * damage)
var/damage_mitigation = 0//Used for dual calculations.
if(!isnull(M.effective_fire_resistance))
damage_mitigation += round((1/3)*damage * M.effective_fire_resistance)
if(!isnull(M.effective_brute_resistance))
damage_mitigation += round((2/3)*damage * M.effective_brute_resistance)
damage -= damage_mitigation
continue
if(damagetype == BIOACID && (isSynthetic() && (!isnull(M.effective_fire_resistance))) || (!isSynthetic() && M.effective_tox_resistance))
if(isSynthetic())
damage = damage * M.effective_fire_resistance
else
damage = damage * M.effective_tox_resistance
continue
if(soaked)
if(soaked >= round(damage*0.8))
damage -= round(damage*0.8)
else
damage -= soaked
var/initial_blocked = blocked
blocked = (100-blocked)/100
switch(damagetype)
if(BRUTE)
adjustBruteLoss(damage * blocked)
if(BURN)
if(COLD_RESISTANCE in mutations)
damage = 0
adjustFireLoss(damage * blocked)
if(SEARING)
apply_damage(round(damage / 3), BURN, def_zone, initial_blocked, soaked, used_weapon, sharp, edge)
apply_damage(round(damage / 3 * 2), BRUTE, def_zone, initial_blocked, soaked, used_weapon, sharp, edge)
if(TOX)
adjustToxLoss(damage * blocked)
if(OXY)
adjustOxyLoss(damage * blocked)
if(CLONE)
adjustCloneLoss(damage * blocked)
if(HALLOSS)
adjustHalLoss(damage * blocked)
if(ELECTROCUTE)
electrocute_act(damage, used_weapon, 1.0, def_zone)
if(BIOACID)
if(isSynthetic())
apply_damage(damage, BURN, def_zone, initial_blocked, soaked, used_weapon, sharp, edge) // Handle it as normal burn.
else
adjustToxLoss(damage * blocked)
if(ELECTROMAG)
damage = damage * blocked
switch(round(damage))
if(91 to INFINITY)
emp_act(1)
if(76 to 90)
if(prob(50))
emp_act(1)
else
emp_act(2)
if(61 to 75)
emp_act(2)
if(46 to 60)
if(prob(50))
emp_act(2)
else
emp_act(3)
if(31 to 45)
emp_act(3)
if(16 to 30)
if(prob(50))
emp_act(3)
else
emp_act(4)
if(0 to 15)
emp_act(4)
flash_weak_pain()
updatehealth()
return 1
/mob/living/proc/apply_damages(var/brute = 0, var/burn = 0, var/tox = 0, var/oxy = 0, var/clone = 0, var/halloss = 0, var/def_zone = null, var/blocked = 0)
if(blocked >= 100)
return 0
// INSERT MODIFIER CODE HERE... But no, really, only two things in the game use it, quad and viruses. The former is admin-only and the latter wouldn't be affected logically, but would if shield code was inerted here. If you really want, you can copy&paste the above and modify it to adjust brute/burn/etc. I do not advise this however.
if(brute) apply_damage(brute, BRUTE, def_zone, blocked)
if(burn) apply_damage(burn, BURN, def_zone, blocked)
if(tox) apply_damage(tox, TOX, def_zone, blocked)
if(oxy) apply_damage(oxy, OXY, def_zone, blocked)
if(clone) apply_damage(clone, CLONE, def_zone, blocked)
if(halloss) apply_damage(halloss, HALLOSS, def_zone, blocked)
return 1
/mob/living/proc/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0, var/check_protection = 1)
if(Debug2)
to_world_log("## DEBUG: apply_effect() was called. The type of effect is [effecttype]. Blocked by [blocked].")
if(!effect || (blocked >= 100))
return 0
blocked = (100-blocked)/100
switch(effecttype)
if(STUN)
Stun(effect * blocked)
if(WEAKEN)
Weaken(effect * blocked)
if(PARALYZE)
Paralyse(effect * blocked)
if(AGONY)
halloss += max((effect * blocked), 0) // Useful for objects that cause "subdual" damage. PAIN!
if(IRRADIATE)
/*
var/rad_protection = check_protection ? getarmor(null, "rad")/100 : 0
radiation += max((1-rad_protection)*effect/(blocked+1),0)//Rads auto check armor
*/
var/rad_protection = getarmor(null, "rad")
rad_protection = (100-rad_protection)/100
radiation += max((effect * rad_protection), 0)
if(STUTTER)
if(status_flags & CANSTUN) // stun is usually associated with stutter
stuttering = max(stuttering,(effect * blocked))
if(EYE_BLUR)
eye_blurry = max(eye_blurry,(effect * blocked))
if(DROWSY)
drowsyness = max(drowsyness,(effect * blocked))
updatehealth()
return 1
/mob/living/proc/apply_effects(var/stun = 0, var/weaken = 0, var/paralyze = 0, var/irradiate = 0, var/stutter = 0, var/eyeblur = 0, var/drowsy = 0, var/agony = 0, var/blocked = 0, var/ignite = 0, var/flammable = 0)
if(blocked >= 100)
return 0
if(stun) apply_effect(stun, STUN, blocked)
if(weaken) apply_effect(weaken, WEAKEN, blocked)
if(paralyze) apply_effect(paralyze, PARALYZE, blocked)
if(irradiate) apply_effect(irradiate, IRRADIATE, blocked)
if(stutter) apply_effect(stutter, STUTTER, blocked)
if(eyeblur) apply_effect(eyeblur, EYE_BLUR, blocked)
if(drowsy) apply_effect(drowsy, DROWSY, blocked)
if(agony) apply_effect(agony, AGONY, blocked)
if(flammable) adjust_fire_stacks(flammable)
if(ignite)
if(ignite >= 3)
add_modifier(/datum/modifier/fire/stack_managed/intense, 60 SECONDS)
else
add_modifier(/datum/modifier/fire/stack_managed, 45 * ignite SECONDS)
return 1
+36 -36
View File
@@ -1,36 +1,36 @@
/mob/living
var/datum/language/default_language
/mob/living/verb/set_default_language(language as null|anything in languages)
set name = "Set Default Language"
set category = "IC"
if (only_species_language && language != GLOB.all_languages[src.species_language])
to_chat(src, "<span class='notice'>You can only speak your species language, [src.species_language].</span>")
return 0
if(language == GLOB.all_languages[src.species_language])
to_chat(src, "<span class='notice'>You will now speak your standard default language, [language ? language : "common"], if you do not specify a language when speaking.</span>")
else if (language)
if(language && !can_speak(language))
to_chat(src, "<span class='notice'>You are unable to speak that language.</span>")
return
to_chat(src, "<span class='notice'>You will now speak [language] if you do not specify a language when speaking.</span>")
else
to_chat(src, "<span class='notice'>You will now speak whatever your standard default language is if you do not specify one when speaking.</span>")
default_language = language
// Silicons can't neccessarily speak everything in their languages list
/mob/living/silicon/set_default_language(language as null|anything in speech_synthesizer_langs)
..()
/mob/living/verb/check_default_language()
set name = "Check Default Language"
set category = "IC"
if(default_language)
to_chat(src, "<span class='notice'>You are currently speaking [default_language] by default.</span>")
else
to_chat(src, "<span class='notice'>Your current default language is your species or mob type default.</span>")
/mob/living
var/datum/language/default_language
/mob/living/verb/set_default_language(language as null|anything in languages)
set name = "Set Default Language"
set category = "IC"
if (only_species_language && language != GLOB.all_languages[src.species_language])
to_chat(src, "<span class='notice'>You can only speak your species language, [src.species_language].</span>")
return 0
if(language == GLOB.all_languages[src.species_language])
to_chat(src, "<span class='notice'>You will now speak your standard default language, [language ? language : "common"], if you do not specify a language when speaking.</span>")
else if (language)
if(language && !can_speak(language))
to_chat(src, "<span class='notice'>You are unable to speak that language.</span>")
return
to_chat(src, "<span class='notice'>You will now speak [language] if you do not specify a language when speaking.</span>")
else
to_chat(src, "<span class='notice'>You will now speak whatever your standard default language is if you do not specify one when speaking.</span>")
default_language = language
// Silicons can't neccessarily speak everything in their languages list
/mob/living/silicon/set_default_language(language as null|anything in speech_synthesizer_langs)
..()
/mob/living/verb/check_default_language()
set name = "Check Default Language"
set category = "IC"
if(default_language)
to_chat(src, "<span class='notice'>You are currently speaking [default_language] by default.</span>")
else
to_chat(src, "<span class='notice'>Your current default language is your species or mob type default.</span>")
+284 -284
View File
@@ -1,284 +1,284 @@
/mob/living/Life()
set invisibility = 0
set background = BACKGROUND_ENABLED
..()
if (transforming)
return
handle_modifiers() //VOREStation Edit - Needs to be done even if in nullspace.
if(!loc)
return
var/datum/gas_mixture/environment
if(isbelly(loc))
environment = loc.return_air_for_internal_lifeform(src)
else
environment = loc.return_air()
//handle_modifiers() // Do this early since it might affect other things later. //VOREStation Edit
handle_light()
if(stat != DEAD)
//Breathing, if applicable
handle_breathing()
//Mutations and radiation
handle_mutations_and_radiation()
//Blood
handle_blood()
//Random events (vomiting etc)
handle_random_events()
. = 1
//Chemicals in the body, this is moved over here so that blood can be added after death
handle_chemicals_in_body()
//Handle temperature/pressure differences between body and environment
if(environment)
handle_environment(environment)
//Check if we're on fire
handle_fire()
if(client && !(client.prefs.ambience_freq == 0)) // Handle re-running ambience to mobs if they've remained in an area, AND have an active client assigned to them, and do not have repeating ambience disabled.
handle_ambience()
//stuff in the stomach
//handle_stomach() //VOREStation Code
update_gravity(mob_has_gravity())
update_pulling()
for(var/obj/item/weapon/grab/G in src)
G.process()
if(handle_regular_status_updates()) // Status & health update, are we dead or alive etc.
handle_disabilities() // eye, ear, brain damages
handle_statuses() //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc
handle_actions()
update_canmove()
handle_regular_hud_updates()
handle_vision()
handle_tf_holder() //VOREStation Addition
/mob/living/proc/handle_breathing()
return
/mob/living/proc/handle_mutations_and_radiation()
return
/mob/living/proc/handle_chemicals_in_body()
return
/mob/living/proc/handle_blood()
return
/mob/living/proc/handle_random_events()
return
/mob/living/proc/handle_environment(var/datum/gas_mixture/environment)
return
/mob/living/proc/handle_stomach()
return
/mob/living/proc/handle_ambience() // If you're in an ambient area and have not moved out of it for x time as configured per-client, and do not have it disabled, we're going to play ambience again to you, to help break up the silence.
if(world.time >= (lastareachange + client.prefs.ambience_freq MINUTES)) // Every 5 minutes (by default, set per-client), we're going to run a 35% chance (by default, also set per-client) to play ambience.
var/area/A = get_area(src)
if(A)
lastareachange = world.time // This will refresh the last area change to prevent this call happening LITERALLY every life tick.
A.play_ambience(src, initial = FALSE)
/mob/living/proc/update_pulling()
if(pulling)
if(incapacitated())
stop_pulling()
//This updates the health and status of the mob (conscious, unconscious, dead)
/mob/living/proc/handle_regular_status_updates()
updatehealth()
if(stat != DEAD)
if(paralysis)
set_stat(UNCONSCIOUS)
else if (status_flags & FAKEDEATH)
set_stat(UNCONSCIOUS)
else
set_stat(CONSCIOUS)
return 1
/mob/living/proc/handle_statuses()
handle_stunned()
handle_weakened()
handle_paralysed()
handle_stuttering()
handle_silent()
handle_drugged()
handle_slurring()
handle_confused()
/mob/living/proc/handle_stunned()
if(stunned)
AdjustStunned(-1)
throw_alert("stunned", /obj/screen/alert/stunned)
else
clear_alert("stunned")
return stunned
/mob/living/proc/handle_weakened()
if(weakened)
AdjustWeakened(-1)
throw_alert("weakened", /obj/screen/alert/weakened)
else
clear_alert("weakened")
return weakened
/mob/living/proc/handle_stuttering()
if(stuttering)
stuttering = max(stuttering-1, 0)
return stuttering
/mob/living/proc/handle_silent()
if(silent)
silent = max(silent-1, 0)
return silent
/mob/living/proc/handle_drugged()
if(druggy)
druggy = max(druggy-1, 0)
throw_alert("high", /obj/screen/alert/high)
else
clear_alert("high")
return druggy
/mob/living/proc/handle_slurring()
if(slurring)
slurring = max(slurring-1, 0)
return slurring
/mob/living/proc/handle_paralysed()
if(paralysis)
AdjustParalysis(-1)
throw_alert("paralyzed", /obj/screen/alert/paralyzed)
else
clear_alert("paralyzed")
return paralysis
/mob/living/proc/handle_confused()
if(confused)
AdjustConfused(-1)
throw_alert("confused", /obj/screen/alert/confused)
else
clear_alert("confused")
return confused
/mob/living/proc/handle_disabilities()
//Eyes
if(sdisabilities & BLIND || stat) //blindness from disability or unconsciousness doesn't get better on its own
SetBlinded(1)
throw_alert("blind", /obj/screen/alert/blind)
else if(eye_blind) //blindness, heals slowly over time
AdjustBlinded(-1)
throw_alert("blind", /obj/screen/alert/blind)
else
clear_alert("blind")
if(eye_blurry) //blurry eyes heal slowly
eye_blurry = max(eye_blurry-1, 0)
//Ears
if(sdisabilities & DEAF) //disabled-deaf, doesn't get better on its own
setEarDamage(-1, max(ear_deaf, 1))
else
// deafness heals slowly over time, unless ear_damage is over 100
if(ear_damage < 100)
adjustEarDamage(-0.05,-1)
/mob/living/handle_regular_hud_updates()
if(!client)
return 0
..()
handle_darksight()
handle_hud_icons()
return 1
/mob/living/proc/update_sight()
if(!seedarkness)
see_invisible = SEE_INVISIBLE_NOLIGHTING
else
see_invisible = initial(see_invisible)
sight = initial(sight)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.vision_flags))
sight |= M.vision_flags
return
/mob/living/proc/handle_hud_icons()
handle_hud_icons_health()
return
/mob/living/proc/handle_hud_icons_health()
return
/mob/living/proc/handle_light()
if(glow_override)
return FALSE
if(instability >= TECHNOMANCER_INSTABILITY_MIN_GLOW)
var/distance = round(sqrt(instability / 2))
if(distance)
set_light(distance, distance * 4, l_color = "#660066")
return TRUE
else if(glow_toggle)
set_light(glow_range, glow_intensity, glow_color)
else
set_light(0)
return FALSE
/mob/living/proc/handle_darksight()
if(!seedarkness) //Cheap 'always darksight' var
dsoverlay.alpha = 255
return
var/darksightedness = min(see_in_dark/world.view,1.0) //A ratio of how good your darksight is, from 'nada' to 'really darn good'
var/current = dsoverlay.alpha/255 //Our current adjustedness
var/brightness = 0.0 //We'll assume it's superdark if we can't find something else.
if(isturf(loc))
var/turf/T = loc //Will be true 99% of the time, thus avoiding the whole elif chain
brightness = T.get_lumcount()
//Snowflake treatment of potential locations
else if(istype(loc,/obj/mecha)) //I imagine there's like displays and junk in there. Use the lights!
brightness = 1
else if(istype(loc,/obj/item/weapon/holder)) //Poor carried teshari and whatnot should adjust appropriately
var/turf/T = get_turf(src)
brightness = T.get_lumcount()
var/darkness = 1-brightness //Silly, I know, but 'alpha' and 'darkness' go the same direction on a number line
var/adjust_to = min(darkness,darksightedness)//Capped by how darksighted they are
var/distance = abs(current-adjust_to) //Used for how long to animate for
if(distance < 0.01) return //We're already all set
//to_world("[src] in B:[round(brightness,0.1)] C:[round(current,0.1)] A2:[round(adjust_to,0.1)] D:[round(distance,0.01)] T:[round(distance*10 SECONDS,0.1)]")
animate(dsoverlay, alpha = (adjust_to*255), time = (distance*10 SECONDS))
/mob/living/Life()
set invisibility = 0
set background = BACKGROUND_ENABLED
..()
if (transforming)
return
handle_modifiers() //VOREStation Edit - Needs to be done even if in nullspace.
if(!loc)
return
var/datum/gas_mixture/environment
if(isbelly(loc))
environment = loc.return_air_for_internal_lifeform(src)
else
environment = loc.return_air()
//handle_modifiers() // Do this early since it might affect other things later. //VOREStation Edit
handle_light()
if(stat != DEAD)
//Breathing, if applicable
handle_breathing()
//Mutations and radiation
handle_mutations_and_radiation()
//Blood
handle_blood()
//Random events (vomiting etc)
handle_random_events()
. = 1
//Chemicals in the body, this is moved over here so that blood can be added after death
handle_chemicals_in_body()
//Handle temperature/pressure differences between body and environment
if(environment)
handle_environment(environment)
//Check if we're on fire
handle_fire()
if(client && !(client.prefs.ambience_freq == 0)) // Handle re-running ambience to mobs if they've remained in an area, AND have an active client assigned to them, and do not have repeating ambience disabled.
handle_ambience()
//stuff in the stomach
//handle_stomach() //VOREStation Code
update_gravity(mob_has_gravity())
update_pulling()
for(var/obj/item/weapon/grab/G in src)
G.process()
if(handle_regular_status_updates()) // Status & health update, are we dead or alive etc.
handle_disabilities() // eye, ear, brain damages
handle_statuses() //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc
handle_actions()
update_canmove()
handle_regular_hud_updates()
handle_vision()
handle_tf_holder() //VOREStation Addition
/mob/living/proc/handle_breathing()
return
/mob/living/proc/handle_mutations_and_radiation()
return
/mob/living/proc/handle_chemicals_in_body()
return
/mob/living/proc/handle_blood()
return
/mob/living/proc/handle_random_events()
return
/mob/living/proc/handle_environment(var/datum/gas_mixture/environment)
return
/mob/living/proc/handle_stomach()
return
/mob/living/proc/handle_ambience() // If you're in an ambient area and have not moved out of it for x time as configured per-client, and do not have it disabled, we're going to play ambience again to you, to help break up the silence.
if(world.time >= (lastareachange + client.prefs.ambience_freq MINUTES)) // Every 5 minutes (by default, set per-client), we're going to run a 35% chance (by default, also set per-client) to play ambience.
var/area/A = get_area(src)
if(A)
lastareachange = world.time // This will refresh the last area change to prevent this call happening LITERALLY every life tick.
A.play_ambience(src, initial = FALSE)
/mob/living/proc/update_pulling()
if(pulling)
if(incapacitated())
stop_pulling()
//This updates the health and status of the mob (conscious, unconscious, dead)
/mob/living/proc/handle_regular_status_updates()
updatehealth()
if(stat != DEAD)
if(paralysis)
set_stat(UNCONSCIOUS)
else if (status_flags & FAKEDEATH)
set_stat(UNCONSCIOUS)
else
set_stat(CONSCIOUS)
return 1
/mob/living/proc/handle_statuses()
handle_stunned()
handle_weakened()
handle_paralysed()
handle_stuttering()
handle_silent()
handle_drugged()
handle_slurring()
handle_confused()
/mob/living/proc/handle_stunned()
if(stunned)
AdjustStunned(-1)
throw_alert("stunned", /obj/screen/alert/stunned)
else
clear_alert("stunned")
return stunned
/mob/living/proc/handle_weakened()
if(weakened)
AdjustWeakened(-1)
throw_alert("weakened", /obj/screen/alert/weakened)
else
clear_alert("weakened")
return weakened
/mob/living/proc/handle_stuttering()
if(stuttering)
stuttering = max(stuttering-1, 0)
return stuttering
/mob/living/proc/handle_silent()
if(silent)
silent = max(silent-1, 0)
return silent
/mob/living/proc/handle_drugged()
if(druggy)
druggy = max(druggy-1, 0)
throw_alert("high", /obj/screen/alert/high)
else
clear_alert("high")
return druggy
/mob/living/proc/handle_slurring()
if(slurring)
slurring = max(slurring-1, 0)
return slurring
/mob/living/proc/handle_paralysed()
if(paralysis)
AdjustParalysis(-1)
throw_alert("paralyzed", /obj/screen/alert/paralyzed)
else
clear_alert("paralyzed")
return paralysis
/mob/living/proc/handle_confused()
if(confused)
AdjustConfused(-1)
throw_alert("confused", /obj/screen/alert/confused)
else
clear_alert("confused")
return confused
/mob/living/proc/handle_disabilities()
//Eyes
if(sdisabilities & BLIND || stat) //blindness from disability or unconsciousness doesn't get better on its own
SetBlinded(1)
throw_alert("blind", /obj/screen/alert/blind)
else if(eye_blind) //blindness, heals slowly over time
AdjustBlinded(-1)
throw_alert("blind", /obj/screen/alert/blind)
else
clear_alert("blind")
if(eye_blurry) //blurry eyes heal slowly
eye_blurry = max(eye_blurry-1, 0)
//Ears
if(sdisabilities & DEAF) //disabled-deaf, doesn't get better on its own
setEarDamage(-1, max(ear_deaf, 1))
else
// deafness heals slowly over time, unless ear_damage is over 100
if(ear_damage < 100)
adjustEarDamage(-0.05,-1)
/mob/living/handle_regular_hud_updates()
if(!client)
return 0
..()
handle_darksight()
handle_hud_icons()
return 1
/mob/living/proc/update_sight()
if(!seedarkness)
see_invisible = SEE_INVISIBLE_NOLIGHTING
else
see_invisible = initial(see_invisible)
sight = initial(sight)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.vision_flags))
sight |= M.vision_flags
return
/mob/living/proc/handle_hud_icons()
handle_hud_icons_health()
return
/mob/living/proc/handle_hud_icons_health()
return
/mob/living/proc/handle_light()
if(glow_override)
return FALSE
if(instability >= TECHNOMANCER_INSTABILITY_MIN_GLOW)
var/distance = round(sqrt(instability / 2))
if(distance)
set_light(distance, distance * 4, l_color = "#660066")
return TRUE
else if(glow_toggle)
set_light(glow_range, glow_intensity, glow_color)
else
set_light(0)
return FALSE
/mob/living/proc/handle_darksight()
if(!seedarkness) //Cheap 'always darksight' var
dsoverlay.alpha = 255
return
var/darksightedness = min(see_in_dark/world.view,1.0) //A ratio of how good your darksight is, from 'nada' to 'really darn good'
var/current = dsoverlay.alpha/255 //Our current adjustedness
var/brightness = 0.0 //We'll assume it's superdark if we can't find something else.
if(isturf(loc))
var/turf/T = loc //Will be true 99% of the time, thus avoiding the whole elif chain
brightness = T.get_lumcount()
//Snowflake treatment of potential locations
else if(istype(loc,/obj/mecha)) //I imagine there's like displays and junk in there. Use the lights!
brightness = 1
else if(istype(loc,/obj/item/weapon/holder)) //Poor carried teshari and whatnot should adjust appropriately
var/turf/T = get_turf(src)
brightness = T.get_lumcount()
var/darkness = 1-brightness //Silly, I know, but 'alpha' and 'darkness' go the same direction on a number line
var/adjust_to = min(darkness,darksightedness)//Capped by how darksighted they are
var/distance = abs(current-adjust_to) //Used for how long to animate for
if(distance < 0.01) return //We're already all set
//to_world("[src] in B:[round(brightness,0.1)] C:[round(current,0.1)] A2:[round(adjust_to,0.1)] D:[round(distance,0.01)] T:[round(distance*10 SECONDS,0.1)]")
animate(dsoverlay, alpha = (adjust_to*255), time = (distance*10 SECONDS))
+84 -84
View File
@@ -1,84 +1,84 @@
/mob/living
see_invisible = SEE_INVISIBLE_LIVING
//Health and life related vars
var/maxHealth = 100 //Maximum health that should be possible. Avoid adjusting this if you can, and instead use modifiers datums.
var/health = 100 //A mob's health
var/mob_class = null // A mob's "class", e.g. human, mechanical, animal, etc. Used for certain projectile effects. See __defines/mob.dm for available classes.
var/hud_updateflag = 0
//Damage related vars, NOTE: THESE SHOULD ONLY BE MODIFIED BY PROCS
var/bruteloss = 0.0 //Brutal damage caused by brute force (punching, being clubbed by a toolbox ect... this also accounts for pressure damage)
var/oxyloss = 0.0 //Oxygen depravation damage (no air in lungs)
var/toxloss = 0.0 //Toxic damage caused by being poisoned or radiated
var/fireloss = 0.0 //Burn damage caused by being way too hot, too cold or burnt.
var/cloneloss = 0 //Damage caused by being cloned or ejected from the cloner early. slimes also deal cloneloss damage to victims
var/brainloss = 0 //Thought-scrambly damage caused by someone hitting you in the head with a bible or being infected with brainrot.
var/halloss = 0 //Hallucination damage. 'Fake' damage obtained through hallucinating or the holodeck. Sleeping should cause it to wear off.
var/nutrition = 400
var/max_nutrition = MAX_NUTRITION
var/hallucination = 0 //Directly affects how long a mob will hallucinate for
var/list/atom/hallucinations = list() //A list of hallucinated people that try to attack the mob. See /obj/effect/fake_attacker in hallucinations.dm
var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out.
var/base_attack_cooldown = DEFAULT_ATTACK_COOLDOWN
var/t_phoron = null
var/t_oxygen = null
var/t_sl_gas = null
var/t_n2 = null
var/now_pushing = null
var/mob_bump_flag = 0
var/mob_swap_flags = 0
var/mob_push_flags = 0
var/mob_always_swap = 0
var/mob/living/cameraFollow = null
var/list/datum/action/actions = list()
var/tod = null // Time of death
var/update_slimes = 1
var/silent = null // Can't talk. Value goes down every life proc.
var/on_fire = 0 //The "Are we on fire?" var
var/fire_stacks
var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks.
var/lastpuke = 0
var/evasion = 0 // Makes attacks harder to land. Negative numbers increase hit chance.
var/force_max_speed = 0 // If 1, the mob runs extremely fast and cannot be slowed.
var/image/dsoverlay = null //Overlay used for darksight eye adjustments
var/glow_toggle = FALSE // If they're glowing!
var/glow_override = FALSE // Ignore the manual toggle
var/glow_range = 2
var/glow_intensity = null
var/glow_color = "#FFFFFF" // The color they're glowing!
var/see_invisible_default = SEE_INVISIBLE_LIVING
var/nest //Not specific, because a Nest may be the prop nest, or blob factory in this case.
var/list/hud_list //Holder for health hud, status hud, wanted hud, etc (not like inventory slots)
var/has_huds = FALSE //Whether or not we should bother initializing the above list
var/makes_dirt = TRUE //FALSE if the mob shouldn't be making dirt on the ground when it walks
var/looking_elsewhere = FALSE //If the mob's view has been relocated to somewhere else, like via a camera or with binocs
var/image/selected_image = null // Used for buildmode AI control stuff.
var/allow_self_surgery = FALSE // Used to determine if the mob can perform surgery on itself.
var/tail_alt = 0
var/flying = 0 // Allows flight
var/inventory_panel_type = /datum/inventory_panel
var/datum/inventory_panel/inventory_panel
var/last_resist_time = 0 // world.time of the most recent resist that wasn't on cooldown.
/mob/living
see_invisible = SEE_INVISIBLE_LIVING
//Health and life related vars
var/maxHealth = 100 //Maximum health that should be possible. Avoid adjusting this if you can, and instead use modifiers datums.
var/health = 100 //A mob's health
var/mob_class = null // A mob's "class", e.g. human, mechanical, animal, etc. Used for certain projectile effects. See __defines/mob.dm for available classes.
var/hud_updateflag = 0
//Damage related vars, NOTE: THESE SHOULD ONLY BE MODIFIED BY PROCS
var/bruteloss = 0.0 //Brutal damage caused by brute force (punching, being clubbed by a toolbox ect... this also accounts for pressure damage)
var/oxyloss = 0.0 //Oxygen depravation damage (no air in lungs)
var/toxloss = 0.0 //Toxic damage caused by being poisoned or radiated
var/fireloss = 0.0 //Burn damage caused by being way too hot, too cold or burnt.
var/cloneloss = 0 //Damage caused by being cloned or ejected from the cloner early. slimes also deal cloneloss damage to victims
var/brainloss = 0 //Thought-scrambly damage caused by someone hitting you in the head with a bible or being infected with brainrot.
var/halloss = 0 //Hallucination damage. 'Fake' damage obtained through hallucinating or the holodeck. Sleeping should cause it to wear off.
var/nutrition = 400
var/max_nutrition = MAX_NUTRITION
var/hallucination = 0 //Directly affects how long a mob will hallucinate for
var/list/atom/hallucinations = list() //A list of hallucinated people that try to attack the mob. See /obj/effect/fake_attacker in hallucinations.dm
var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out.
var/base_attack_cooldown = DEFAULT_ATTACK_COOLDOWN
var/t_phoron = null
var/t_oxygen = null
var/t_sl_gas = null
var/t_n2 = null
var/now_pushing = null
var/mob_bump_flag = 0
var/mob_swap_flags = 0
var/mob_push_flags = 0
var/mob_always_swap = 0
var/mob/living/cameraFollow = null
var/list/datum/action/actions = list()
var/tod = null // Time of death
var/update_slimes = 1
var/silent = null // Can't talk. Value goes down every life proc.
var/on_fire = 0 //The "Are we on fire?" var
var/fire_stacks
var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks.
var/lastpuke = 0
var/evasion = 0 // Makes attacks harder to land. Negative numbers increase hit chance.
var/force_max_speed = 0 // If 1, the mob runs extremely fast and cannot be slowed.
var/image/dsoverlay = null //Overlay used for darksight eye adjustments
var/glow_toggle = FALSE // If they're glowing!
var/glow_override = FALSE // Ignore the manual toggle
var/glow_range = 2
var/glow_intensity = null
var/glow_color = "#FFFFFF" // The color they're glowing!
var/see_invisible_default = SEE_INVISIBLE_LIVING
var/nest //Not specific, because a Nest may be the prop nest, or blob factory in this case.
var/list/hud_list //Holder for health hud, status hud, wanted hud, etc (not like inventory slots)
var/has_huds = FALSE //Whether or not we should bother initializing the above list
var/makes_dirt = TRUE //FALSE if the mob shouldn't be making dirt on the ground when it walks
var/looking_elsewhere = FALSE //If the mob's view has been relocated to somewhere else, like via a camera or with binocs
var/image/selected_image = null // Used for buildmode AI control stuff.
var/allow_self_surgery = FALSE // Used to determine if the mob can perform surgery on itself.
var/tail_alt = 0
var/flying = 0 // Allows flight
var/inventory_panel_type = /datum/inventory_panel
var/datum/inventory_panel/inventory_panel
var/last_resist_time = 0 // world.time of the most recent resist that wasn't on cooldown.
+19 -19
View File
@@ -1,19 +1,19 @@
/mob/living/Logout()
..()
if (mind)
//Per BYOND docs key remains set if the player DCs, becomes null if switching bodies.
if(!key) //key and mind have become seperated.
mind.active = 0 //This is to stop say, a mind.transfer_to call on a corpse causing a ghost to re-enter its body.
var/datum/component/character_setup/cs = GetComponent(/datum/component/character_setup)
if(cs)
qdel(cs)
var/datum/component/vore_panel/vp = GetComponent(/datum/component/vore_panel)
if(vp)
qdel(vp)
spawn(15 SECONDS) //15 seconds to get back into the mob before it goes wild
if(src && !src.client)
if(ai_holder)
ai_holder.go_wake()
/mob/living/Logout()
..()
if (mind)
//Per BYOND docs key remains set if the player DCs, becomes null if switching bodies.
if(!key) //key and mind have become seperated.
mind.active = 0 //This is to stop say, a mind.transfer_to call on a corpse causing a ghost to re-enter its body.
var/datum/component/character_setup/cs = GetComponent(/datum/component/character_setup)
if(cs)
qdel(cs)
var/datum/component/vore_panel/vp = GetComponent(/datum/component/vore_panel)
if(vp)
qdel(vp)
spawn(15 SECONDS) //15 seconds to get back into the mob before it goes wild
if(src && !src.client)
if(ai_holder)
ai_holder.go_wake()
+462 -462
View File
@@ -1,462 +1,462 @@
var/list/department_radio_keys = list(
":r" = "right ear", ".r" = "right ear",
":l" = "left ear", ".l" = "left ear",
":i" = "intercom", ".i" = "intercom",
":h" = "department", ".h" = "department",
":+" = "special", ".+" = "special", //activate radio-specific special functions
":c" = "Command", ".c" = "Command",
":n" = "Science", ".n" = "Science",
":m" = "Medical", ".m" = "Medical",
":e" = "Engineering", ".e" = "Engineering",
":k" = "Response Team", ".k" = "Response Team",
":s" = "Security", ".s" = "Security",
":w" = "whisper", ".w" = "whisper",
":t" = "Mercenary", ".t" = "Mercenary",
":x" = "Raider", ".x" = "Raider",
":u" = "Supply", ".u" = "Supply",
":v" = "Service", ".v" = "Service",
":p" = "AI Private", ".p" = "AI Private",
":a" = "Away Team", ".a" = "Away Team", //VOREStation Edit
":y" = "Talon", ".y" = "Talon", //VOREStation Add,
":g" = "Casino", ".g" = "Casino",
":R" = "right ear", ".R" = "right ear",
":L" = "left ear", ".L" = "left ear",
":I" = "intercom", ".I" = "intercom",
":H" = "department", ".H" = "department",
":C" = "Command", ".C" = "Command",
":N" = "Science", ".N" = "Science",
":M" = "Medical", ".M" = "Medical",
":E" = "Engineering", ".E" = "Engineering",
":k" = "Response Team", ".k" = "Response Team",
":S" = "Security", ".S" = "Security",
":W" = "whisper", ".W" = "whisper",
":T" = "Mercenary", ".T" = "Mercenary",
":X" = "Raider", ".X" = "Raider",
":U" = "Supply", ".U" = "Supply",
":V" = "Service", ".V" = "Service",
":P" = "AI Private", ".P" = "AI Private",
":A" = "Away Team", ".A" = "Away Team",
":Y" = "Talon", ".Y" = "Talon", //VOREStation Add,
":G" = "Casino", ".G" = "Casino",
// Cyrillic characters on the same keys on the Russian QWERTY (phonetic) layout
":к" = "right ear", ".к" = "right ear",
":д" = "left ear", ".д" = "left ear",
":ш" = "intercom", ".ш" = "intercom",
":р" = "department", ".р" = "department",
":+" = "special", ".+" = "special", //activate radio-specific special functions
":с" = "Command", ".с" = "Command",
":т" = "Science", ".т" = "Science",
":ь" = "Medical", ".ь" = "Medical",
":у" = "Engineering", ".у" = "Engineering",
":л" = "Response Team", ".л" = "Response Team",
":ы" = "Security", ".ы" = "Security",
":ц" = "whisper", ".ц" = "whisper",
":е" = "Mercenary", ".е" = "Mercenary",
":ч" = "Raider", ".ч" = "Raider",
":г" = "Supply", ".г" = "Supply",
":м" = "Service", ".м" = "Service",
":з" = "AI Private", ".з" = "AI Private",
":ф" = "Away Team", ".ф" = "Away Team",
":н" = "Talon", ".н" = "Talon", //VOREStation Add
":п" = "Casino", ".п" = "Casino",
)
var/list/channel_to_radio_key = new
/proc/get_radio_key_from_channel(var/channel)
var/key = channel_to_radio_key[channel]
if(!key)
for(var/radio_key in department_radio_keys)
if(department_radio_keys[radio_key] == channel)
key = radio_key
break
if(!key)
key = ""
channel_to_radio_key[channel] = key
return key
/mob/living/proc/binarycheck()
return FALSE
/mob/proc/get_default_language()
return null
/mob/living/get_default_language()
return default_language
//Takes a list of the form list(message, verb, whispering) and modifies it as needed
//Returns 1 if a speech problem was applied, 0 otherwise
/mob/living/proc/handle_speech_problems(var/list/message_data)
var/list/message_pieces = message_data[1]
var/verb = message_data[2]
var/whispering = message_data[3]
. = 0
// Technically this rerolls the verb for as many say pieces as there are. _shrug_
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && (S.speaking.flags & NO_STUTTER || S.speaking.flags & SIGNLANG))
continue
if((HULK in mutations) && health >= 25 && length(S.message))
S.message = "[uppertext(S.message)]!!!"
verb = pick("yells","roars","hollers")
whispering = 0
. = 1
if(slurring)
S.message = slur(S.message)
verb = pick("slobbers","slurs")
. = 1
if(stuttering)
S.message = stutter(S.message)
verb = pick("stammers","stutters")
. = 1
//VOREStation Edit Start
if(muffled)
verb = pick("muffles")
whispering = 1
. = 1
//VOREStation Edit End
message_data[1] = message_pieces
message_data[2] = verb
message_data[3] = whispering
/mob/living/proc/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
if(message_mode == "intercom")
for(var/obj/item/device/radio/intercom/I in view(1, null))
I.talk_into(src, message_pieces, verb)
used_radios += I
return 0
/mob/living/proc/handle_speech_sound()
var/list/returns[2]
returns[1] = null
returns[2] = null
return returns
/mob/living/proc/get_speech_ending(verb, var/ending)
if(ending == "!")
return pick("exclaims","shouts","yells")
if(ending == "?")
return "asks"
return verb
/mob/living/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
//If you're muted for IC chat
if(client)
if(message)
client.handle_spam_prevention(MUTE_IC)
if((client.prefs.muted & MUTE_IC) || say_disabled)
to_chat(src, "<span class='warning'>You cannot speak in IC (Muted).</span>")
return
//Redirect to say_dead if talker is dead
if(stat)
if(stat == DEAD && !forbid_seeing_deadchat)
return say_dead(message)
return
//VOREStation Addition Start
if(forced_psay)
psay(message)
return
if(autowhisper)
whispering = 1
//VOREStation Addition End
//Parse the mode
var/message_mode = parse_message_mode(message, "headset")
//Maybe they are using say/whisper to do a quick emote, so do those
switch(copytext(message, 1, 2))
if("*") return emote(copytext(message, 2))
if("^") return custom_emote(1, copytext(message, 2))
//Parse the radio code and consume it
if(message_mode)
if(message_mode == "headset")
message = copytext(message, 2) //it would be really nice if the parse procs could do this for us.
else if(message_mode == "whisper")
whispering = 1
message_mode = null
message = copytext(message, 3)
else
message = copytext(message, 3)
//Clean up any remaining space on the left
message = trim_left(message)
// VOREStation Edit - Reflect messages as needed, no sanitizing because parse_languages will handle it for us
if(reflect_if_needed(message, src))
return
// VOREStation Edit End
//Parse the language code and consume it
var/list/message_pieces = parse_languages(message)
if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quark for dealing with hivemind/signlang languages.
var/datum/multilingual_say_piece/S = message_pieces // Yay for BYOND's hilariously broken typecasting for allowing us to do this.
S.speaking.broadcast(src, S.message)
return 1
if(!LAZYLEN(message_pieces))
log_runtime(EXCEPTION("Message failed to generate pieces. [message] - [json_encode(message_pieces)]"))
return 0
// If you're muzzled, you can only speak sign language
// However, sign language is handled above.
if(is_muzzled())
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
return
//Whisper vars
var/w_scramble_range = 5 //The range at which you get ***as*th**wi****
var/w_adverb //An adverb prepended to the verb in whispers
var/w_not_heard //The message for people in watching range
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
var/verb = ""
//Handle language-specific verbs and adverb setup if necessary
if(!whispering) //Just doing normal 'say' (for now, may change below)
verb = say_quote(message, first_piece.speaking)
else if(whispering && first_piece.speaking.whisper_verb) //Language has defined whisper verb
verb = first_piece.speaking.whisper_verb
w_not_heard = "[verb] something"
else //Whispering but language has no whisper verb, use say verb
w_adverb = pick("quietly", "softly")
verb = first_piece.speaking.speech_verb
w_not_heard = "[first_piece.speaking.speech_verb] something [w_adverb]"
//For speech disorders (hulk, slurring, stuttering)
var/list/message_data = list(message_pieces, verb, whispering)
if(handle_speech_problems(message_data))
message_pieces = message_data[1]
whispering = message_data[3]
if(verb != message_data[2]) //They changed our verb
if(whispering)
w_adverb = pick("quietly", "softly")
verb = message_data[2]
//Whisper may have adverbs, add those if one was set
if(w_adverb)
verb = "[verb] [w_adverb]"
//If something nulled or emptied the message, forget it
if(!LAZYLEN(message_pieces))
return 0
//Radio message handling
var/list/used_radios = list()
if(handle_message_mode(message_mode, message_pieces, verb, used_radios, whispering))
return 1
//For languages with actual speech sounds
var/list/handle_v = handle_speech_sound()
var/sound/speech_sound = handle_v[1]
var/sound_vol = handle_v[2]
//Default range and italics, may be overridden past here
var/message_range = world.view
var/italics = 0
var/do_sound = TRUE
if(!voice_sounds_list || !voice_sounds_list.len)
do_sound = FALSE
//Speaking into radios
if(used_radios.len)
italics = 1
message_range = 1
if(first_piece.speaking)
message_range = first_piece.speaking.get_talkinto_msg_range(message)
var/msg
if(!first_piece.speaking || !(first_piece.speaking.flags & NO_TALK_MSG))
msg = "<span class='notice'>[src] talks into [used_radios[1]]</span>"
if(msg)
for(var/mob/living/M in hearers(5, src) - src)
M.show_message(msg)
if(speech_sound)
sound_vol *= 0.5
//Set vars if we're still whispering by this point
if(whispering)
italics = 1
message_range = 1
sound_vol *= 0.5
//VOREStation edit - allows for custom say verbs, overriding all other say-verb types- e.g. "says loudly" instead of "shouts"
//You'll still stammer if injured or slur if drunk, but it won't have those specific words
var/ending = copytext(message, length(message))
if(custom_whisper && whispering)
verb = "[custom_whisper]"
else if(custom_exclaim && ending=="!")
verb = "[custom_exclaim]"
else if(custom_ask && ending=="?")
verb = "[custom_ask]"
else if(custom_say)
verb = "[custom_say]"
//VOREStation edit ends
//Handle nonverbal languages here
for(var/datum/multilingual_say_piece/S in message_pieces)
if((S.speaking.flags & NONVERBAL) || (S.speaking.flags & INAUDIBLE))
custom_emote(1, "[pick(S.speaking.signlang_verb)].")
do_sound = FALSE
//These will contain the main receivers of the message
var/list/listening = list()
var/list/listening_obj = list()
//Atmosphere calculations (speaker's side only, for now)
var/turf/T = get_turf(src)
if(T)
//Air is too thin to carry sound at all, contact speech only
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment ? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE)
message_range = 1
//Air is nearing minimum levels, make text italics as a hint, and muffle sound
if(pressure < ONE_ATMOSPHERE * 0.4)
italics = 1
sound_vol *= 0.5
//Obtain the mobs and objects in the message range
var/list/results = get_mobs_and_objs_in_view_fast(T, world.view, remote_ghosts = client ? TRUE : FALSE)
listening = results["mobs"]
listening_obj = results["objs"]
else
return 1 //If we're in nullspace, then forget it.
//Remember the speech images so we can remove them later and they can get GC'd
var/list/images_to_clients = list()
//The 'post-say' static speech bubble
var/speech_bubble_test = say_test(message)
//var/image/speech_bubble = image('icons/mob/talk_vr.dmi',src,"h[speech_bubble_test]") //VOREStation Edit. Commented this out in case we need to reenable.
var/speech_type = custom_speech_bubble
if(!speech_type || speech_type == "default")
speech_type = speech_bubble_appearance()
var/image/speech_bubble = generate_speech_bubble(src, "[speech_type][speech_bubble_test]")
var/sb_alpha = 255
var/atom/loc_before_turf = src
//VOREStation Add
if(isbelly(loc))
speech_bubble.pixel_y = -13 //teehee
//VOREStation Add End
while(loc_before_turf && !isturf(loc_before_turf.loc))
loc_before_turf = loc_before_turf.loc
sb_alpha -= 50
if(sb_alpha < 0)
break
speech_bubble.loc = loc_before_turf
speech_bubble.alpha = CLAMP(sb_alpha, 0, 255)
images_to_clients[speech_bubble] = list()
//Main 'say' and 'whisper' message delivery
for(var/mob/M in listening)
spawn(0) //Using spawns to queue all the messages for AFTER this proc is done, and stop runtimes
if(M && src) //If we still exist, when the spawn processes
//VOREStation Add - Ghosts don't hear whispers
if(whispering && isobserver(M) && (!M.is_preference_enabled(/datum/client_preference/ghost_see_whisubtle) || \
(!is_preference_enabled(/datum/client_preference/whisubtle_vis) && !M.client?.holder)))
M.show_message("<span class='game say'><span class='name'>[src.name]</span> [w_not_heard].</span>", 2)
return
//VOREStation Add End
var/dst = get_dist(get_turf(M),get_turf(src))
var/runechat_enabled = M.client?.is_preference_enabled(/datum/client_preference/runechat_mob)
if(dst <= message_range || (M.stat == DEAD && !forbid_seeing_deadchat)) //Inside normal message range, or dead with ears (handled in the view proc)
if(M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol))
if(M.client && !runechat_enabled)
var/image/I1 = listening[M] || speech_bubble
images_to_clients[I1] |= M.client
M << I1
if(whispering && !isobserver(M)) //Don't even bother with these unless whispering
if(dst > message_range && dst <= w_scramble_range) //Inside whisper scramble range
if(M.hear_say(stars_all(message_pieces), verb, italics, src, speech_sound, sound_vol*0.2))
if(M.client && !runechat_enabled)
var/image/I2 = listening[M] || speech_bubble
images_to_clients[I2] |= M.client
M << I2
if(dst > w_scramble_range && dst <= world.view) //Inside whisper 'visible' range
M.show_message("<span class='game say'><span class='name'>[name]</span> [w_not_heard].</span>", 2)
//Object message delivery
for(var/obj/O in listening_obj)
spawn(0)
if(O && src) //If we still exist, when the spawn processes
var/dst = get_dist(get_turf(O),get_turf(src))
if(dst <= message_range)
O.hear_talk(src, message_pieces, verb)
//Remove all those images. At least it's just ONE spawn this time.
spawn(30)
for(var/image/I as anything in images_to_clients)
var/list/clients_from_image = images_to_clients[I]
for(var/client/C as anything in clients_from_image)
if(C) //Could have disconnected after message sent, before removing bubble.
C.images -= I
qdel(I)
var/ourfreq = null
if(voice_freq > 0 )
ourfreq = voice_freq
//Log the message to file
if(message_mode)
message = "([message_mode == "headset" ? "Common" : capitalize(message_mode)]) [message]" //Adds radio keys used if available
if(whispering)
if(do_sound && message)
playsound(T, pick(voice_sounds_list), 25, TRUE, extrarange = -6, falloff = 1 , is_global = TRUE, frequency = ourfreq, ignore_walls = FALSE, preference = /datum/client_preference/whisper_sounds)
log_whisper(message, src)
else
if(do_sound && message)
playsound(T, pick(voice_sounds_list), 75, TRUE, falloff = 1 , is_global = TRUE, frequency = ourfreq, ignore_walls = FALSE, preference = /datum/client_preference/say_sounds)
log_say(message, src)
return 1
/mob/living/proc/say_signlang(var/message, var/verb="gestures", var/verb_understood="gestures", var/datum/language/language, var/type = 1)
var/turf/T = get_turf(src)
//We're in something, gesture to people inside the same thing
if(loc != T)
for(var/mob/M in loc)
M.hear_signlang(message, verb, verb_understood, language, src, type)
//We're on a turf, gesture to visible as if we were a normal language
else
var/low_range = FALSE
if(T && type == 2) // type 2 is audible signlang. yes. sue me.
//Air is too thin to carry sound at all, contact speech only
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment ? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE)
low_range = TRUE
var/list/potentials = get_mobs_and_objs_in_view_fast(T, world.view)
var/list/mobs = potentials["mobs"]
for(var/mob/M as anything in mobs)
if(low_range && !(M in range(1, src)))
continue
M.hear_signlang(message, verb, verb_understood, language, src, type)
var/list/objs = potentials["objs"]
for(var/obj/O as anything in objs)
if(low_range && !(O in range(1, src)))
continue
O.hear_signlang(message, verb, language, src)
return 1
/obj/effect/speech_bubble
var/mob/parent
/mob/proc/GetVoice()
return name
/mob/proc/speech_bubble_appearance()
return "normal"
var/list/department_radio_keys = list(
":r" = "right ear", ".r" = "right ear",
":l" = "left ear", ".l" = "left ear",
":i" = "intercom", ".i" = "intercom",
":h" = "department", ".h" = "department",
":+" = "special", ".+" = "special", //activate radio-specific special functions
":c" = "Command", ".c" = "Command",
":n" = "Science", ".n" = "Science",
":m" = "Medical", ".m" = "Medical",
":e" = "Engineering", ".e" = "Engineering",
":k" = "Response Team", ".k" = "Response Team",
":s" = "Security", ".s" = "Security",
":w" = "whisper", ".w" = "whisper",
":t" = "Mercenary", ".t" = "Mercenary",
":x" = "Raider", ".x" = "Raider",
":u" = "Supply", ".u" = "Supply",
":v" = "Service", ".v" = "Service",
":p" = "AI Private", ".p" = "AI Private",
":a" = "Away Team", ".a" = "Away Team", //VOREStation Edit
":y" = "Talon", ".y" = "Talon", //VOREStation Add,
":g" = "Casino", ".g" = "Casino",
":R" = "right ear", ".R" = "right ear",
":L" = "left ear", ".L" = "left ear",
":I" = "intercom", ".I" = "intercom",
":H" = "department", ".H" = "department",
":C" = "Command", ".C" = "Command",
":N" = "Science", ".N" = "Science",
":M" = "Medical", ".M" = "Medical",
":E" = "Engineering", ".E" = "Engineering",
":k" = "Response Team", ".k" = "Response Team",
":S" = "Security", ".S" = "Security",
":W" = "whisper", ".W" = "whisper",
":T" = "Mercenary", ".T" = "Mercenary",
":X" = "Raider", ".X" = "Raider",
":U" = "Supply", ".U" = "Supply",
":V" = "Service", ".V" = "Service",
":P" = "AI Private", ".P" = "AI Private",
":A" = "Away Team", ".A" = "Away Team",
":Y" = "Talon", ".Y" = "Talon", //VOREStation Add,
":G" = "Casino", ".G" = "Casino",
// Cyrillic characters on the same keys on the Russian QWERTY (phonetic) layout
":к" = "right ear", ".к" = "right ear",
":д" = "left ear", ".д" = "left ear",
":ш" = "intercom", ".ш" = "intercom",
":р" = "department", ".р" = "department",
":+" = "special", ".+" = "special", //activate radio-specific special functions
":с" = "Command", ".с" = "Command",
":т" = "Science", ".т" = "Science",
":ь" = "Medical", ".ь" = "Medical",
":у" = "Engineering", ".у" = "Engineering",
":л" = "Response Team", ".л" = "Response Team",
":ы" = "Security", ".ы" = "Security",
":ц" = "whisper", ".ц" = "whisper",
":е" = "Mercenary", ".е" = "Mercenary",
":ч" = "Raider", ".ч" = "Raider",
":г" = "Supply", ".г" = "Supply",
":м" = "Service", ".м" = "Service",
":з" = "AI Private", ".з" = "AI Private",
":ф" = "Away Team", ".ф" = "Away Team",
":н" = "Talon", ".н" = "Talon", //VOREStation Add
":п" = "Casino", ".п" = "Casino",
)
var/list/channel_to_radio_key = new
/proc/get_radio_key_from_channel(var/channel)
var/key = channel_to_radio_key[channel]
if(!key)
for(var/radio_key in department_radio_keys)
if(department_radio_keys[radio_key] == channel)
key = radio_key
break
if(!key)
key = ""
channel_to_radio_key[channel] = key
return key
/mob/living/proc/binarycheck()
return FALSE
/mob/proc/get_default_language()
return null
/mob/living/get_default_language()
return default_language
//Takes a list of the form list(message, verb, whispering) and modifies it as needed
//Returns 1 if a speech problem was applied, 0 otherwise
/mob/living/proc/handle_speech_problems(var/list/message_data)
var/list/message_pieces = message_data[1]
var/verb = message_data[2]
var/whispering = message_data[3]
. = 0
// Technically this rerolls the verb for as many say pieces as there are. _shrug_
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && (S.speaking.flags & NO_STUTTER || S.speaking.flags & SIGNLANG))
continue
if((HULK in mutations) && health >= 25 && length(S.message))
S.message = "[uppertext(S.message)]!!!"
verb = pick("yells","roars","hollers")
whispering = 0
. = 1
if(slurring)
S.message = slur(S.message)
verb = pick("slobbers","slurs")
. = 1
if(stuttering)
S.message = stutter(S.message)
verb = pick("stammers","stutters")
. = 1
//VOREStation Edit Start
if(muffled)
verb = pick("muffles")
whispering = 1
. = 1
//VOREStation Edit End
message_data[1] = message_pieces
message_data[2] = verb
message_data[3] = whispering
/mob/living/proc/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
if(message_mode == "intercom")
for(var/obj/item/device/radio/intercom/I in view(1, null))
I.talk_into(src, message_pieces, verb)
used_radios += I
return 0
/mob/living/proc/handle_speech_sound()
var/list/returns[2]
returns[1] = null
returns[2] = null
return returns
/mob/living/proc/get_speech_ending(verb, var/ending)
if(ending == "!")
return pick("exclaims","shouts","yells")
if(ending == "?")
return "asks"
return verb
/mob/living/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
//If you're muted for IC chat
if(client)
if(message)
client.handle_spam_prevention(MUTE_IC)
if((client.prefs.muted & MUTE_IC) || say_disabled)
to_chat(src, "<span class='warning'>You cannot speak in IC (Muted).</span>")
return
//Redirect to say_dead if talker is dead
if(stat)
if(stat == DEAD && !forbid_seeing_deadchat)
return say_dead(message)
return
//VOREStation Addition Start
if(forced_psay)
psay(message)
return
if(autowhisper)
whispering = 1
//VOREStation Addition End
//Parse the mode
var/message_mode = parse_message_mode(message, "headset")
//Maybe they are using say/whisper to do a quick emote, so do those
switch(copytext(message, 1, 2))
if("*") return emote(copytext(message, 2))
if("^") return custom_emote(1, copytext(message, 2))
//Parse the radio code and consume it
if(message_mode)
if(message_mode == "headset")
message = copytext(message, 2) //it would be really nice if the parse procs could do this for us.
else if(message_mode == "whisper")
whispering = 1
message_mode = null
message = copytext(message, 3)
else
message = copytext(message, 3)
//Clean up any remaining space on the left
message = trim_left(message)
// VOREStation Edit - Reflect messages as needed, no sanitizing because parse_languages will handle it for us
if(reflect_if_needed(message, src))
return
// VOREStation Edit End
//Parse the language code and consume it
var/list/message_pieces = parse_languages(message)
if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quark for dealing with hivemind/signlang languages.
var/datum/multilingual_say_piece/S = message_pieces // Yay for BYOND's hilariously broken typecasting for allowing us to do this.
S.speaking.broadcast(src, S.message)
return 1
if(!LAZYLEN(message_pieces))
log_runtime(EXCEPTION("Message failed to generate pieces. [message] - [json_encode(message_pieces)]"))
return 0
// If you're muzzled, you can only speak sign language
// However, sign language is handled above.
if(is_muzzled())
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
return
//Whisper vars
var/w_scramble_range = 5 //The range at which you get ***as*th**wi****
var/w_adverb //An adverb prepended to the verb in whispers
var/w_not_heard //The message for people in watching range
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
var/verb = ""
//Handle language-specific verbs and adverb setup if necessary
if(!whispering) //Just doing normal 'say' (for now, may change below)
verb = say_quote(message, first_piece.speaking)
else if(whispering && first_piece.speaking.whisper_verb) //Language has defined whisper verb
verb = first_piece.speaking.whisper_verb
w_not_heard = "[verb] something"
else //Whispering but language has no whisper verb, use say verb
w_adverb = pick("quietly", "softly")
verb = first_piece.speaking.speech_verb
w_not_heard = "[first_piece.speaking.speech_verb] something [w_adverb]"
//For speech disorders (hulk, slurring, stuttering)
var/list/message_data = list(message_pieces, verb, whispering)
if(handle_speech_problems(message_data))
message_pieces = message_data[1]
whispering = message_data[3]
if(verb != message_data[2]) //They changed our verb
if(whispering)
w_adverb = pick("quietly", "softly")
verb = message_data[2]
//Whisper may have adverbs, add those if one was set
if(w_adverb)
verb = "[verb] [w_adverb]"
//If something nulled or emptied the message, forget it
if(!LAZYLEN(message_pieces))
return 0
//Radio message handling
var/list/used_radios = list()
if(handle_message_mode(message_mode, message_pieces, verb, used_radios, whispering))
return 1
//For languages with actual speech sounds
var/list/handle_v = handle_speech_sound()
var/sound/speech_sound = handle_v[1]
var/sound_vol = handle_v[2]
//Default range and italics, may be overridden past here
var/message_range = world.view
var/italics = 0
var/do_sound = TRUE
if(!voice_sounds_list || !voice_sounds_list.len)
do_sound = FALSE
//Speaking into radios
if(used_radios.len)
italics = 1
message_range = 1
if(first_piece.speaking)
message_range = first_piece.speaking.get_talkinto_msg_range(message)
var/msg
if(!first_piece.speaking || !(first_piece.speaking.flags & NO_TALK_MSG))
msg = "<span class='notice'>[src] talks into [used_radios[1]]</span>"
if(msg)
for(var/mob/living/M in hearers(5, src) - src)
M.show_message(msg)
if(speech_sound)
sound_vol *= 0.5
//Set vars if we're still whispering by this point
if(whispering)
italics = 1
message_range = 1
sound_vol *= 0.5
//VOREStation edit - allows for custom say verbs, overriding all other say-verb types- e.g. "says loudly" instead of "shouts"
//You'll still stammer if injured or slur if drunk, but it won't have those specific words
var/ending = copytext(message, length(message))
if(custom_whisper && whispering)
verb = "[custom_whisper]"
else if(custom_exclaim && ending=="!")
verb = "[custom_exclaim]"
else if(custom_ask && ending=="?")
verb = "[custom_ask]"
else if(custom_say)
verb = "[custom_say]"
//VOREStation edit ends
//Handle nonverbal languages here
for(var/datum/multilingual_say_piece/S in message_pieces)
if((S.speaking.flags & NONVERBAL) || (S.speaking.flags & INAUDIBLE))
custom_emote(1, "[pick(S.speaking.signlang_verb)].")
do_sound = FALSE
//These will contain the main receivers of the message
var/list/listening = list()
var/list/listening_obj = list()
//Atmosphere calculations (speaker's side only, for now)
var/turf/T = get_turf(src)
if(T)
//Air is too thin to carry sound at all, contact speech only
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment ? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE)
message_range = 1
//Air is nearing minimum levels, make text italics as a hint, and muffle sound
if(pressure < ONE_ATMOSPHERE * 0.4)
italics = 1
sound_vol *= 0.5
//Obtain the mobs and objects in the message range
var/list/results = get_mobs_and_objs_in_view_fast(T, world.view, remote_ghosts = client ? TRUE : FALSE)
listening = results["mobs"]
listening_obj = results["objs"]
else
return 1 //If we're in nullspace, then forget it.
//Remember the speech images so we can remove them later and they can get GC'd
var/list/images_to_clients = list()
//The 'post-say' static speech bubble
var/speech_bubble_test = say_test(message)
//var/image/speech_bubble = image('icons/mob/talk_vr.dmi',src,"h[speech_bubble_test]") //VOREStation Edit. Commented this out in case we need to reenable.
var/speech_type = custom_speech_bubble
if(!speech_type || speech_type == "default")
speech_type = speech_bubble_appearance()
var/image/speech_bubble = generate_speech_bubble(src, "[speech_type][speech_bubble_test]")
var/sb_alpha = 255
var/atom/loc_before_turf = src
//VOREStation Add
if(isbelly(loc))
speech_bubble.pixel_y = -13 //teehee
//VOREStation Add End
while(loc_before_turf && !isturf(loc_before_turf.loc))
loc_before_turf = loc_before_turf.loc
sb_alpha -= 50
if(sb_alpha < 0)
break
speech_bubble.loc = loc_before_turf
speech_bubble.alpha = CLAMP(sb_alpha, 0, 255)
images_to_clients[speech_bubble] = list()
//Main 'say' and 'whisper' message delivery
for(var/mob/M in listening)
spawn(0) //Using spawns to queue all the messages for AFTER this proc is done, and stop runtimes
if(M && src) //If we still exist, when the spawn processes
//VOREStation Add - Ghosts don't hear whispers
if(whispering && isobserver(M) && (!M.is_preference_enabled(/datum/client_preference/ghost_see_whisubtle) || \
(!is_preference_enabled(/datum/client_preference/whisubtle_vis) && !M.client?.holder)))
M.show_message("<span class='game say'><span class='name'>[src.name]</span> [w_not_heard].</span>", 2)
return
//VOREStation Add End
var/dst = get_dist(get_turf(M),get_turf(src))
var/runechat_enabled = M.client?.is_preference_enabled(/datum/client_preference/runechat_mob)
if(dst <= message_range || (M.stat == DEAD && !forbid_seeing_deadchat)) //Inside normal message range, or dead with ears (handled in the view proc)
if(M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol))
if(M.client && !runechat_enabled)
var/image/I1 = listening[M] || speech_bubble
images_to_clients[I1] |= M.client
M << I1
if(whispering && !isobserver(M)) //Don't even bother with these unless whispering
if(dst > message_range && dst <= w_scramble_range) //Inside whisper scramble range
if(M.hear_say(stars_all(message_pieces), verb, italics, src, speech_sound, sound_vol*0.2))
if(M.client && !runechat_enabled)
var/image/I2 = listening[M] || speech_bubble
images_to_clients[I2] |= M.client
M << I2
if(dst > w_scramble_range && dst <= world.view) //Inside whisper 'visible' range
M.show_message("<span class='game say'><span class='name'>[name]</span> [w_not_heard].</span>", 2)
//Object message delivery
for(var/obj/O in listening_obj)
spawn(0)
if(O && src) //If we still exist, when the spawn processes
var/dst = get_dist(get_turf(O),get_turf(src))
if(dst <= message_range)
O.hear_talk(src, message_pieces, verb)
//Remove all those images. At least it's just ONE spawn this time.
spawn(30)
for(var/image/I as anything in images_to_clients)
var/list/clients_from_image = images_to_clients[I]
for(var/client/C as anything in clients_from_image)
if(C) //Could have disconnected after message sent, before removing bubble.
C.images -= I
qdel(I)
var/ourfreq = null
if(voice_freq > 0 )
ourfreq = voice_freq
//Log the message to file
if(message_mode)
message = "([message_mode == "headset" ? "Common" : capitalize(message_mode)]) [message]" //Adds radio keys used if available
if(whispering)
if(do_sound && message)
playsound(T, pick(voice_sounds_list), 25, TRUE, extrarange = -6, falloff = 1 , is_global = TRUE, frequency = ourfreq, ignore_walls = FALSE, preference = /datum/client_preference/whisper_sounds)
log_whisper(message, src)
else
if(do_sound && message)
playsound(T, pick(voice_sounds_list), 75, TRUE, falloff = 1 , is_global = TRUE, frequency = ourfreq, ignore_walls = FALSE, preference = /datum/client_preference/say_sounds)
log_say(message, src)
return 1
/mob/living/proc/say_signlang(var/message, var/verb="gestures", var/verb_understood="gestures", var/datum/language/language, var/type = 1)
var/turf/T = get_turf(src)
//We're in something, gesture to people inside the same thing
if(loc != T)
for(var/mob/M in loc)
M.hear_signlang(message, verb, verb_understood, language, src, type)
//We're on a turf, gesture to visible as if we were a normal language
else
var/low_range = FALSE
if(T && type == 2) // type 2 is audible signlang. yes. sue me.
//Air is too thin to carry sound at all, contact speech only
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment ? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE)
low_range = TRUE
var/list/potentials = get_mobs_and_objs_in_view_fast(T, world.view)
var/list/mobs = potentials["mobs"]
for(var/mob/M as anything in mobs)
if(low_range && !(M in range(1, src)))
continue
M.hear_signlang(message, verb, verb_understood, language, src, type)
var/list/objs = potentials["objs"]
for(var/obj/O as anything in objs)
if(low_range && !(O in range(1, src)))
continue
O.hear_signlang(message, verb, language, src)
return 1
/obj/effect/speech_bubble
var/mob/parent
/mob/proc/GetVoice()
return name
/mob/proc/speech_bubble_appearance()
return "normal"
@@ -1,2 +1,2 @@
/mob/living/silicon/ai/SelfMove(turf/n, direct)
return 0
/mob/living/silicon/ai/SelfMove(turf/n, direct)
return 0
@@ -1,71 +1,71 @@
/mob/living/silicon/ai
var/mob/living/silicon/robot/deployed_shell = null //For shell control
/mob/living/silicon/ai/Initialize()
if(config.allow_ai_shells)
verbs += /mob/living/silicon/ai/proc/deploy_to_shell_act
return ..()
/mob/living/silicon/ai/proc/deploy_to_shell(var/mob/living/silicon/robot/target)
if(!config.allow_ai_shells)
to_chat(src, span("warning", "AI Shells are not allowed on this server. You shouldn't have this verb because of it, so consider making a bug report."))
return
if(incapacitated())
to_chat(src, span("warning", "You are incapacitated!"))
return
if(lacks_power())
to_chat(src, span("warning", "Your core lacks power, wireless is disabled."))
return
if(control_disabled)
to_chat(src, span("warning", "Wireless networking module is offline."))
return
var/list/possible = list()
for(var/mob/living/silicon/robot/R as anything in GLOB.available_ai_shells)
if(R.shell && !R.deployed && (R.stat != DEAD) && (!R.connected_ai || (R.connected_ai == src) ) ) //VOREStation Edit: shell restrictions
if(istype(R.loc, /obj/machinery/recharge_station)) //Check Rechargers
var/obj/machinery/recharge_station/RS = R.loc
if(!(using_map.ai_shell_restricted && !(RS.z in using_map.ai_shell_allowed_levels))) //Allow station borgs to be redeployed from Chargers.
possible += R
if(isbelly(R.loc)) //check belly space
var/obj/belly/B = R.loc
if(!(using_map.ai_shell_restricted && !(B.owner.z in using_map.ai_shell_allowed_levels))) //No smuggling in borgs
possible += R
if(!(using_map.ai_shell_restricted && !(R.z in using_map.ai_shell_allowed_levels)))
possible += R
if(!LAZYLEN(possible))
to_chat(src, span("warning", "No usable AI shell beacons detected."))
if(!target || !(target in possible)) //If the AI is looking for a new shell, or its pre-selected shell is no longer valid
target = tgui_input_list(src, "Which body to control?", "Shell Choice", possible)
if(!target || target.stat == DEAD || target.deployed || !(!target.connected_ai || (target.connected_ai == src) ) )
if(target)
to_chat(src, span("warning", "It is no longer possible to deploy to \the [target]."))
else
to_chat(src, span("notice", "Deployment aborted."))
return
else if(mind)
soul_link(/datum/soul_link/shared_body, src, target)
deployed_shell = target
target.deploy_init(src)
mind.transfer_to(target)
teleop = target // So the AI 'hears' messages near its core.
target.post_deploy()
/mob/living/silicon/ai/proc/deploy_to_shell_act()
set category = "AI Commands"
set name = "Deploy to Shell"
deploy_to_shell() // This is so the AI is not prompted with a list of all mobs when using the 'real' proc.
/mob/living/silicon/ai/proc/disconnect_shell(message = "Your remote connection has been reset!")
if(deployed_shell) // Forcibly call back AI in event of things such as damage, EMP or power loss.
message = span("danger", message)
deployed_shell.undeploy(message)
/mob/living/silicon/ai
var/mob/living/silicon/robot/deployed_shell = null //For shell control
/mob/living/silicon/ai/Initialize()
if(config.allow_ai_shells)
verbs += /mob/living/silicon/ai/proc/deploy_to_shell_act
return ..()
/mob/living/silicon/ai/proc/deploy_to_shell(var/mob/living/silicon/robot/target)
if(!config.allow_ai_shells)
to_chat(src, span("warning", "AI Shells are not allowed on this server. You shouldn't have this verb because of it, so consider making a bug report."))
return
if(incapacitated())
to_chat(src, span("warning", "You are incapacitated!"))
return
if(lacks_power())
to_chat(src, span("warning", "Your core lacks power, wireless is disabled."))
return
if(control_disabled)
to_chat(src, span("warning", "Wireless networking module is offline."))
return
var/list/possible = list()
for(var/mob/living/silicon/robot/R as anything in GLOB.available_ai_shells)
if(R.shell && !R.deployed && (R.stat != DEAD) && (!R.connected_ai || (R.connected_ai == src) ) ) //VOREStation Edit: shell restrictions
if(istype(R.loc, /obj/machinery/recharge_station)) //Check Rechargers
var/obj/machinery/recharge_station/RS = R.loc
if(!(using_map.ai_shell_restricted && !(RS.z in using_map.ai_shell_allowed_levels))) //Allow station borgs to be redeployed from Chargers.
possible += R
if(isbelly(R.loc)) //check belly space
var/obj/belly/B = R.loc
if(!(using_map.ai_shell_restricted && !(B.owner.z in using_map.ai_shell_allowed_levels))) //No smuggling in borgs
possible += R
if(!(using_map.ai_shell_restricted && !(R.z in using_map.ai_shell_allowed_levels)))
possible += R
if(!LAZYLEN(possible))
to_chat(src, span("warning", "No usable AI shell beacons detected."))
if(!target || !(target in possible)) //If the AI is looking for a new shell, or its pre-selected shell is no longer valid
target = tgui_input_list(src, "Which body to control?", "Shell Choice", possible)
if(!target || target.stat == DEAD || target.deployed || !(!target.connected_ai || (target.connected_ai == src) ) )
if(target)
to_chat(src, span("warning", "It is no longer possible to deploy to \the [target]."))
else
to_chat(src, span("notice", "Deployment aborted."))
return
else if(mind)
soul_link(/datum/soul_link/shared_body, src, target)
deployed_shell = target
target.deploy_init(src)
mind.transfer_to(target)
teleop = target // So the AI 'hears' messages near its core.
target.post_deploy()
/mob/living/silicon/ai/proc/deploy_to_shell_act()
set category = "AI Commands"
set name = "Deploy to Shell"
deploy_to_shell() // This is so the AI is not prompted with a list of all mobs when using the 'real' proc.
/mob/living/silicon/ai/proc/disconnect_shell(message = "Your remote connection has been reset!")
if(deployed_shell) // Forcibly call back AI in event of things such as damage, EMP or power loss.
message = span("danger", message)
deployed_shell.undeploy(message)
+23 -23
View File
@@ -1,23 +1,23 @@
/mob/living/silicon/ai/death(gibbed)
if(stat == DEAD)
return
if(deployed_shell)
disconnect_shell("Disconnecting from remote shell due to critical system failure.")
. = ..(gibbed)
if(src.eyeobj)
src.eyeobj.setLoc(get_turf(src))
remove_ai_verbs(src)
for(var/obj/machinery/ai_status_display/O in machines)
spawn( 0 )
O.mode = 2
if (istype(loc, /obj/item/device/aicard))
var/obj/item/device/aicard/card = loc
card.update_icon()
. = ..(gibbed,"gives one shrill beep before falling lifeless.")
density = TRUE
/mob/living/silicon/ai/death(gibbed)
if(stat == DEAD)
return
if(deployed_shell)
disconnect_shell("Disconnecting from remote shell due to critical system failure.")
. = ..(gibbed)
if(src.eyeobj)
src.eyeobj.setLoc(get_turf(src))
remove_ai_verbs(src)
for(var/obj/machinery/ai_status_display/O in machines)
spawn( 0 )
O.mode = 2
if (istype(loc, /obj/item/device/aicard))
var/obj/item/device/aicard/card = loc
card.update_icon()
. = ..(gibbed,"gives one shrill beep before falling lifeless.")
density = TRUE
+43 -43
View File
@@ -1,43 +1,43 @@
/mob/living/silicon/ai/examine(mob/user)
. = ..()
if (src.stat == DEAD)
. += "<span class='deadsay'>It appears to be powered-down.</span>"
else
if (src.getBruteLoss())
if (src.getBruteLoss() < 30)
. += "<span class='warning'>It looks slightly dented.</span>"
else
. += "<span class='warning'><B>It looks severely dented!</B></span>"
if (src.getFireLoss())
if (src.getFireLoss() < 30)
. += "<span class='warning'>It looks slightly charred.</span>"
else
. += "<span class='warning'><B>Its casing is melted and heat-warped!</B></span>"
if (src.getOxyLoss() && (aiRestorePowerRoutine != 0 && !APU_power))
if (src.getOxyLoss() > 175)
. += "<span class='warning'><B>It seems to be running on backup power. Its display is blinking a \"BACKUP POWER CRITICAL\" warning.</B></span>"
else if(src.getOxyLoss() > 100)
. += "<span class='warning'><B>It seems to be running on backup power. Its display is blinking a \"BACKUP POWER LOW\" warning.</B></span>"
else
. += "<span class='warning'>It seems to be running on backup power.</span>"
if (src.stat == UNCONSCIOUS)
. += "<span class='warning'>It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".</span>"
if(deployed_shell)
. += "The wireless networking light is blinking."
. += "*---------*"
if(hardware && (hardware.owner == src))
. += hardware.get_examine_desc()
user.showLaws(src)
/mob/proc/showLaws(var/mob/living/silicon/S)
return
/mob/observer/dead/showLaws(var/mob/living/silicon/S)
if(antagHUD || is_admin(src))
S.laws.show_laws(src)
/mob/living/silicon/ai/examine(mob/user)
. = ..()
if (src.stat == DEAD)
. += "<span class='deadsay'>It appears to be powered-down.</span>"
else
if (src.getBruteLoss())
if (src.getBruteLoss() < 30)
. += "<span class='warning'>It looks slightly dented.</span>"
else
. += "<span class='warning'><B>It looks severely dented!</B></span>"
if (src.getFireLoss())
if (src.getFireLoss() < 30)
. += "<span class='warning'>It looks slightly charred.</span>"
else
. += "<span class='warning'><B>Its casing is melted and heat-warped!</B></span>"
if (src.getOxyLoss() && (aiRestorePowerRoutine != 0 && !APU_power))
if (src.getOxyLoss() > 175)
. += "<span class='warning'><B>It seems to be running on backup power. Its display is blinking a \"BACKUP POWER CRITICAL\" warning.</B></span>"
else if(src.getOxyLoss() > 100)
. += "<span class='warning'><B>It seems to be running on backup power. Its display is blinking a \"BACKUP POWER LOW\" warning.</B></span>"
else
. += "<span class='warning'>It seems to be running on backup power.</span>"
if (src.stat == UNCONSCIOUS)
. += "<span class='warning'>It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".</span>"
if(deployed_shell)
. += "The wireless networking light is blinking."
. += "*---------*"
if(hardware && (hardware.owner == src))
. += hardware.get_examine_desc()
user.showLaws(src)
/mob/proc/showLaws(var/mob/living/silicon/S)
return
/mob/observer/dead/showLaws(var/mob/living/silicon/S)
if(antagHUD || is_admin(src))
S.laws.show_laws(src)
+259 -259
View File
@@ -1,260 +1,260 @@
var/datum/ai_icon/default_ai_icon = new/datum/ai_icon/blue()
var/list/datum/ai_icon/ai_icons
/datum/ai_icon
var/name
var/alive_icon
var/alive_light = "#FFFFFF"
var/nopower_icon = "4"
var/nopower_light = "#FFFFFF"
var/dead_icon = "ai-crash"
var/dead_light = "#000099"
/datum/ai_icon/New(var/name, var/alive_icon, var/nopower_icon, var/dead_icon, var/alive_light, var/nopower_light, var/dead_light)
if(name)
src.name = name
src.alive_icon = alive_icon
src.nopower_icon = nopower_icon
src.dead_icon = dead_icon
src.alive_light = alive_light
src.nopower_light = nopower_light
src.dead_light = dead_light
if(!ai_icons)
ai_icons = list()
init_subtypes(/datum/ai_icon, ai_icons)
..()
/datum/ai_icon/red
name = "Red"
alive_icon = "ai-red"
alive_light = "#F04848"
dead_icon = "ai-red-crash"
dead_light = "#F04848"
/datum/ai_icon/green
name = "Green"
alive_icon = "ai-wierd"
alive_light = "#00FF99"
dead_icon = "ai-weird-crash"
/datum/ai_icon/blue
name = "Blue"
alive_icon = "ai"
alive_light = "#81DDFF"
/datum/ai_icon/angry
name = "Angry"
alive_icon = "ai-angryface"
alive_light = "#FFFF33"
/datum/ai_icon/angel
name = "Angel"
alive_icon = "ai-angel"
dead_icon = "ai-angel-crash"
/datum/ai_icon/bliss
name = "Bliss"
alive_icon = "ai-bliss"
alive_light = "#5C7A4A"
/datum/ai_icon/chatterbox
name = "Chatterbox"
alive_icon = "ai-president"
alive_light = "#40666B"
/datum/ai_icon/database
name = "Database"
alive_icon = "ai-database"
dead_icon = "ai-database-crash"
/datum/ai_icon/dorf
name = "Dorf"
alive_icon = "ai-dorf"
/datum/ai_icon/dugtodeep
name = "Dug Too Deep"
alive_icon = "ai-toodeep"
alive_light = "#81DDFF"
/datum/ai_icon/firewall
name = "Firewall"
alive_icon = "ai-magma"
alive_light = "#FF4126"
/datum/ai_icon/glitchman
name = "Glitchman"
alive_icon = "ai-glitchman"
dead_icon = "ai-glitchman-crash"
/datum/ai_icon/goon
name = "Goon"
alive_icon = "ai-goon"
alive_light = "#3E5C80"
dead_icon = "ai-goon-crash"
dead_light = "#3E5C80"
/datum/ai_icon/heartline
name = "Heartline"
alive_icon = "ai-heartline"
dead_icon = "ai-heartline-crash"
/datum/ai_icon/helios
name = "Helios"
alive_icon = "ai-helios"
alive_light = "#F2CF73"
/datum/ai_icon/hourglass
name = "Hourglass"
alive_icon = "ai-hourglass"
/datum/ai_icon/inverted
name = "Inverted"
alive_icon = "ai-u"
alive_light = "#81DDFF"
dead_icon = "ai-u-crash"
/datum/ai_icon/lonestar
name = "Lonestar"
alive_icon = "ai-lonestar"
alive_light = "#58751C"
dead_icon = "ai-lonestar-crash"
/datum/ai_icon/matrix
name = "Matrix"
alive_icon = "ai-matrix"
alive_light = "#449944"
/datum/ai_icon/monochrome
name = "Monochrome"
alive_icon = "ai-mono"
alive_light = "#585858"
dead_icon = "ai-mono-crash"
/datum/ai_icon/nanotrasen
name = "NanoTrasen"
alive_icon = "ai-nanotrasen"
alive_light = "#000029"
/datum/ai_icon/rainbow
name = "Rainbow"
alive_icon = "ai-clown"
alive_light = "#E50213"
/datum/ai_icon/smiley
name = "Smiley"
alive_icon = "ai-smiley"
alive_light = "#F3DD00"
/datum/ai_icon/soviet
name = "Soviet"
alive_icon = "ai-soviet"
alive_light = "#FF4307"
dead_icon = "ai-soviet-crash"
dead_light = "#FF4307"
/datum/ai_icon/Static
name = "Static"
alive_icon = "ai-static"
alive_light = "#4784C1"
alive_icon = "ai-static-crash"
/datum/ai_icon/text
name = "Text"
alive_icon = "ai-text"
/datum/ai_icon/trapped
name = "Trapped"
alive_icon = "ai-hades"
dead_icon = "ai-hades-crash"
/datum/ai_icon/triumvirate
name = "Triumvirate"
alive_icon = "ai-triumvirate"
alive_light = "#020B2B"
/datum/ai_icon/triumvirate_static
name = "Triumvirate Static"
alive_icon = "ai-triumvirate-malf"
alive_light = "#020B2B"
/datum/ai_icon/bored
name = "Bored"
alive_icon = "ai-bored"
dead_icon = "ai-eager-crash"
//Eros Research Platform Ports
/datum/ai_icon/clown2
name = "Honk"
alive_icon = "ai-clown2"
dead_icon = "ai-clown2-crash"
/*
/datum/ai_icon/boxfort
name = "Boxfort"
alive_icon = "ai-boxfort"
dead_icon = "ai-boxfort_dead"
*/
/datum/ai_icon/ravensdale
name = "Integration"
alive_icon = "ai-ravensdale"
dead_icon = "ai-ravensdale-crash"
/datum/ai_icon/gentoo
name = "Gentoo"
alive_icon = "ai-gentoo"
dead_icon = "ai-gentoo-crash"
/datum/ai_icon/serithi
name = "Mechanicus"
alive_icon = "ai-serithi"
dead_icon = "ai-serithi-crash"
/*
/datum/ai_icon/alien
name = "Xenomorph"
alive_icon = "ai-alien"
dead_icon = "ai-alien-crash"
*/
/datum/ai_icon/syndicat
name = "Syndi-cat"
alive_icon = "ai-syndicatmeow"
/datum/ai_icon/wasp
name = "Wasp"
alive_icon = "ai-wasp"
/datum/ai_icon/sheltered
name = "Doctor"
alive_icon = "ai-sheltered"
/datum/ai_icon/fabulous
name = "Fabulous"
alive_icon = "ai-fabulous"
/datum/ai_icon/eager
name = "Eager"
alive_icon = "ai-eager"
dead_icon = "ai-eager-crash"
/datum/ai_icon/royal
name = "Royal"
alive_icon = "ai-royal"
/datum/ai_icon/pirate
name = "Pirate"
alive_icon = "ai-pirate"
/datum/ai_icon/bloodylove
name = "Love"
alive_icon = "ai-bloodylove"
/datum/ai_icon/ahasuerus
name = "Ahasuerus"
alive_icon = "ai-ahasuerus"
/datum/ai_icon/godfrey
name = "Godfrey"
var/datum/ai_icon/default_ai_icon = new/datum/ai_icon/blue()
var/list/datum/ai_icon/ai_icons
/datum/ai_icon
var/name
var/alive_icon
var/alive_light = "#FFFFFF"
var/nopower_icon = "4"
var/nopower_light = "#FFFFFF"
var/dead_icon = "ai-crash"
var/dead_light = "#000099"
/datum/ai_icon/New(var/name, var/alive_icon, var/nopower_icon, var/dead_icon, var/alive_light, var/nopower_light, var/dead_light)
if(name)
src.name = name
src.alive_icon = alive_icon
src.nopower_icon = nopower_icon
src.dead_icon = dead_icon
src.alive_light = alive_light
src.nopower_light = nopower_light
src.dead_light = dead_light
if(!ai_icons)
ai_icons = list()
init_subtypes(/datum/ai_icon, ai_icons)
..()
/datum/ai_icon/red
name = "Red"
alive_icon = "ai-red"
alive_light = "#F04848"
dead_icon = "ai-red-crash"
dead_light = "#F04848"
/datum/ai_icon/green
name = "Green"
alive_icon = "ai-wierd"
alive_light = "#00FF99"
dead_icon = "ai-weird-crash"
/datum/ai_icon/blue
name = "Blue"
alive_icon = "ai"
alive_light = "#81DDFF"
/datum/ai_icon/angry
name = "Angry"
alive_icon = "ai-angryface"
alive_light = "#FFFF33"
/datum/ai_icon/angel
name = "Angel"
alive_icon = "ai-angel"
dead_icon = "ai-angel-crash"
/datum/ai_icon/bliss
name = "Bliss"
alive_icon = "ai-bliss"
alive_light = "#5C7A4A"
/datum/ai_icon/chatterbox
name = "Chatterbox"
alive_icon = "ai-president"
alive_light = "#40666B"
/datum/ai_icon/database
name = "Database"
alive_icon = "ai-database"
dead_icon = "ai-database-crash"
/datum/ai_icon/dorf
name = "Dorf"
alive_icon = "ai-dorf"
/datum/ai_icon/dugtodeep
name = "Dug Too Deep"
alive_icon = "ai-toodeep"
alive_light = "#81DDFF"
/datum/ai_icon/firewall
name = "Firewall"
alive_icon = "ai-magma"
alive_light = "#FF4126"
/datum/ai_icon/glitchman
name = "Glitchman"
alive_icon = "ai-glitchman"
dead_icon = "ai-glitchman-crash"
/datum/ai_icon/goon
name = "Goon"
alive_icon = "ai-goon"
alive_light = "#3E5C80"
dead_icon = "ai-goon-crash"
dead_light = "#3E5C80"
/datum/ai_icon/heartline
name = "Heartline"
alive_icon = "ai-heartline"
dead_icon = "ai-heartline-crash"
/datum/ai_icon/helios
name = "Helios"
alive_icon = "ai-helios"
alive_light = "#F2CF73"
/datum/ai_icon/hourglass
name = "Hourglass"
alive_icon = "ai-hourglass"
/datum/ai_icon/inverted
name = "Inverted"
alive_icon = "ai-u"
alive_light = "#81DDFF"
dead_icon = "ai-u-crash"
/datum/ai_icon/lonestar
name = "Lonestar"
alive_icon = "ai-lonestar"
alive_light = "#58751C"
dead_icon = "ai-lonestar-crash"
/datum/ai_icon/matrix
name = "Matrix"
alive_icon = "ai-matrix"
alive_light = "#449944"
/datum/ai_icon/monochrome
name = "Monochrome"
alive_icon = "ai-mono"
alive_light = "#585858"
dead_icon = "ai-mono-crash"
/datum/ai_icon/nanotrasen
name = "NanoTrasen"
alive_icon = "ai-nanotrasen"
alive_light = "#000029"
/datum/ai_icon/rainbow
name = "Rainbow"
alive_icon = "ai-clown"
alive_light = "#E50213"
/datum/ai_icon/smiley
name = "Smiley"
alive_icon = "ai-smiley"
alive_light = "#F3DD00"
/datum/ai_icon/soviet
name = "Soviet"
alive_icon = "ai-soviet"
alive_light = "#FF4307"
dead_icon = "ai-soviet-crash"
dead_light = "#FF4307"
/datum/ai_icon/Static
name = "Static"
alive_icon = "ai-static"
alive_light = "#4784C1"
alive_icon = "ai-static-crash"
/datum/ai_icon/text
name = "Text"
alive_icon = "ai-text"
/datum/ai_icon/trapped
name = "Trapped"
alive_icon = "ai-hades"
dead_icon = "ai-hades-crash"
/datum/ai_icon/triumvirate
name = "Triumvirate"
alive_icon = "ai-triumvirate"
alive_light = "#020B2B"
/datum/ai_icon/triumvirate_static
name = "Triumvirate Static"
alive_icon = "ai-triumvirate-malf"
alive_light = "#020B2B"
/datum/ai_icon/bored
name = "Bored"
alive_icon = "ai-bored"
dead_icon = "ai-eager-crash"
//Eros Research Platform Ports
/datum/ai_icon/clown2
name = "Honk"
alive_icon = "ai-clown2"
dead_icon = "ai-clown2-crash"
/*
/datum/ai_icon/boxfort
name = "Boxfort"
alive_icon = "ai-boxfort"
dead_icon = "ai-boxfort_dead"
*/
/datum/ai_icon/ravensdale
name = "Integration"
alive_icon = "ai-ravensdale"
dead_icon = "ai-ravensdale-crash"
/datum/ai_icon/gentoo
name = "Gentoo"
alive_icon = "ai-gentoo"
dead_icon = "ai-gentoo-crash"
/datum/ai_icon/serithi
name = "Mechanicus"
alive_icon = "ai-serithi"
dead_icon = "ai-serithi-crash"
/*
/datum/ai_icon/alien
name = "Xenomorph"
alive_icon = "ai-alien"
dead_icon = "ai-alien-crash"
*/
/datum/ai_icon/syndicat
name = "Syndi-cat"
alive_icon = "ai-syndicatmeow"
/datum/ai_icon/wasp
name = "Wasp"
alive_icon = "ai-wasp"
/datum/ai_icon/sheltered
name = "Doctor"
alive_icon = "ai-sheltered"
/datum/ai_icon/fabulous
name = "Fabulous"
alive_icon = "ai-fabulous"
/datum/ai_icon/eager
name = "Eager"
alive_icon = "ai-eager"
dead_icon = "ai-eager-crash"
/datum/ai_icon/royal
name = "Royal"
alive_icon = "ai-royal"
/datum/ai_icon/pirate
name = "Pirate"
alive_icon = "ai-pirate"
/datum/ai_icon/bloodylove
name = "Love"
alive_icon = "ai-bloodylove"
/datum/ai_icon/ahasuerus
name = "Ahasuerus"
alive_icon = "ai-ahasuerus"
/datum/ai_icon/godfrey
name = "Godfrey"
alive_icon = "ai-godfrey"
+31 -31
View File
@@ -1,32 +1,32 @@
var/global/list/empty_playable_ai_cores = list()
/hook/roundstart/proc/spawn_empty_ai()
for(var/obj/effect/landmark/start/S in landmarks_list)
if(S.name != "AI")
continue
if(locate(/mob/living) in S.loc)
continue
empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(get_turf(S))
return 1
/mob/living/silicon/ai/verb/store_core()
set name = "Store Core"
set category = "OOC"
set desc = "Enter intelligence storage. This is functionally equivalent to cryo or robotic storage, freeing up your job slot."
if(ticker && ticker.mode && ticker.mode.name == "AI malfunction")
to_chat(usr, "<span class='danger'>You cannot use this verb in malfunction. If you need to leave, please adminhelp.</span>")
return
// Guard against misclicks, this isn't the sort of thing we want happening accidentally
if(tgui_alert(usr, "WARNING: This will immediately empty your core and ghost you, removing your character from the round permanently (similar to cryo and robotic storage). Are you entirely sure you want to do this?", "Store Core", list("No", "Yes")) != "Yes")
return
// We warned you.
empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(loc)
global_announcer.autosay("[src] has been moved to intelligence storage.", "Artificial Intelligence Oversight")
//Handle job slot/tater cleanup.
set_respawn_timer()
var/global/list/empty_playable_ai_cores = list()
/hook/roundstart/proc/spawn_empty_ai()
for(var/obj/effect/landmark/start/S in landmarks_list)
if(S.name != "AI")
continue
if(locate(/mob/living) in S.loc)
continue
empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(get_turf(S))
return 1
/mob/living/silicon/ai/verb/store_core()
set name = "Store Core"
set category = "OOC"
set desc = "Enter intelligence storage. This is functionally equivalent to cryo or robotic storage, freeing up your job slot."
if(ticker && ticker.mode && ticker.mode.name == "AI malfunction")
to_chat(usr, "<span class='danger'>You cannot use this verb in malfunction. If you need to leave, please adminhelp.</span>")
return
// Guard against misclicks, this isn't the sort of thing we want happening accidentally
if(tgui_alert(usr, "WARNING: This will immediately empty your core and ghost you, removing your character from the round permanently (similar to cryo and robotic storage). Are you entirely sure you want to do this?", "Store Core", list("No", "Yes")) != "Yes")
return
// We warned you.
empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(loc)
global_announcer.autosay("[src] has been moved to intelligence storage.", "Artificial Intelligence Oversight")
//Handle job slot/tater cleanup.
set_respawn_timer()
clear_client()
+27 -27
View File
@@ -1,27 +1,27 @@
/mob/living/silicon/ai/proc/show_laws_verb()
set category = "AI Commands"
set name = "Show Laws"
src.show_laws()
/mob/living/silicon/ai/show_laws(var/everyone = 0)
var/who
if (everyone)
who = world
else
who = src
to_chat(who, "<span class='filter_notice'><b>Obey these laws:</b></span>")
src.laws_sanity_check()
src.laws.show_laws(who)
/mob/living/silicon/ai/add_ion_law(var/law)
..()
for(var/mob/living/silicon/robot/R in mob_list)
if(R.lawupdate && (R.connected_ai == src))
R.show_laws()
/mob/living/silicon/ai/proc/ai_checklaws()
set category = "AI Commands"
set name = "State Laws"
subsystem_law_manager()
/mob/living/silicon/ai/proc/show_laws_verb()
set category = "AI Commands"
set name = "Show Laws"
src.show_laws()
/mob/living/silicon/ai/show_laws(var/everyone = 0)
var/who
if (everyone)
who = world
else
who = src
to_chat(who, "<span class='filter_notice'><b>Obey these laws:</b></span>")
src.laws_sanity_check()
src.laws.show_laws(who)
/mob/living/silicon/ai/add_ion_law(var/law)
..()
for(var/mob/living/silicon/robot/R in mob_list)
if(R.lawupdate && (R.connected_ai == src))
R.show_laws()
/mob/living/silicon/ai/proc/ai_checklaws()
set category = "AI Commands"
set name = "State Laws"
subsystem_law_manager()
+181 -181
View File
@@ -1,181 +1,181 @@
/mob/living/silicon/ai/Life()
if (src.stat == DEAD)
return
else //I'm not removing that shitton of tabs, unneeded as they are. -- Urist
//Being dead doesn't mean your temperature never changes
var/turf/T = get_turf(src)
if (src.stat != CONSCIOUS)
src.cameraFollow = null
src.reset_view(null)
disconnect_shell("Disconnecting from remote shell due to local system failure.")
src.updatehealth()
if (!hardware_integrity() || !backup_capacitor())
death()
return
// If our powersupply object was destroyed somehow, create new one.
if(!psupply)
create_powersupply()
// Handle power damage (oxy)
if(aiRestorePowerRoutine != 0 && !APU_power)
// Lose power
adjustOxyLoss(1)
else
// Gain Power
aiRestorePowerRoutine = 0 // Necessary if AI activated it's APU AFTER losing primary power.
adjustOxyLoss(-1)
handle_stunned() // Handle EMP-stun
lying = 0 // Handle lying down
malf_process()
if(APU_power && (hardware_integrity() < 50))
to_chat(src, "<span class='notice'><b>APU GENERATOR FAILURE! (System Damaged)</b></span>")
stop_apu(1)
var/blind = 0
var/area/loc = null
if (istype(T, /turf))
loc = T.loc
if (istype(loc, /area))
if (!loc.power_equip && !istype(src.loc,/obj/item) && !APU_power)
blind = 1
if (!blind)
src.sight |= SEE_TURFS
src.sight |= SEE_MOBS
src.sight |= SEE_OBJS
src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_LIVING
if (aiRestorePowerRoutine==2)
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
aiRestorePowerRoutine = 0
clear_fullscreen("blind")
update_icon()
return
else if (aiRestorePowerRoutine==3)
to_chat(src, "Alert cancelled. Power has been restored.")
aiRestorePowerRoutine = 0
clear_fullscreen("blind")
update_icon()
return
else if (APU_power)
aiRestorePowerRoutine = 0
clear_fullscreen("blind")
update_icon()
return
else
var/area/current_area = get_area(src)
if (lacks_power())
if (aiRestorePowerRoutine==0)
aiRestorePowerRoutine = 1
//Blind the AI
update_icon()
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
src.sight = src.sight&~SEE_TURFS
src.sight = src.sight&~SEE_MOBS
src.sight = src.sight&~SEE_OBJS
src.see_in_dark = 0
src.see_invisible = SEE_INVISIBLE_LIVING
//Now to tell the AI why they're blind and dying slowly.
to_chat(src, "You've lost power!")
disconnect_shell(message = "Disconnected from remote shell due to depowered networking interface.")
spawn(20)
to_chat(src, "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection.")
end_multicam()
sleep(50)
if (loc.power_equip)
if (!istype(T, /turf/space))
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
aiRestorePowerRoutine = 0
clear_fullscreen("blind")
return
to_chat(src, "Fault confirmed: missing external power. Shutting down main control system to save power.")
sleep(20)
to_chat(src, "Emergency control system online. Verifying connection to power network.")
sleep(50)
if (istype(T, /turf/space))
to_chat(src, "Unable to verify! No power connection detected!")
aiRestorePowerRoutine = 2
return
to_chat(src, "Connection verified. Searching for APC in power network.")
sleep(50)
var/obj/machinery/power/apc/theAPC = null
var/PRP
for (PRP=1, PRP<=4, PRP++)
for (var/obj/machinery/power/apc/APC in current_area)
if (!(APC.stat & BROKEN))
theAPC = APC
break
if (!theAPC)
switch(PRP)
if (1)
to_chat(src, "Unable to locate APC!")
else
to_chat(src, "Lost connection with the APC!")
src:aiRestorePowerRoutine = 2
return
if (loc.power_equip)
if (!istype(T, /turf/space))
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
aiRestorePowerRoutine = 0
clear_fullscreen("blind") //This, too, is a fix to issue 603
return
switch(PRP)
if (1)
to_chat(src, "APC located. Optimizing route to APC to avoid needless power waste.")
if (2)
to_chat(src, "Best route identified. Hacking offline APC power port.")
if (3)
to_chat(src, "Power port upload access confirmed. Loading control program into APC power port software.")
if (4)
to_chat(src, "Transfer complete. Forcing APC to execute program.")
sleep(50)
to_chat(src, "Receiving control information from APC.")
sleep(2)
theAPC.operating = 1
theAPC.equipment = 3
theAPC.update()
aiRestorePowerRoutine = 3
to_chat(src, "Here are your current laws:")
show_laws()
update_icon()
sleep(50)
theAPC = null
process_queued_alarms()
handle_regular_hud_updates()
handle_vision()
/mob/living/silicon/ai/proc/lacks_power()
if(APU_power)
return 0
var/turf/T = get_turf(src)
var/area/A = get_area(src)
return ((!A.power_equip) && A.requires_power == 1 || istype(T, /turf/space)) && !istype(src.loc,/obj/item)
/mob/living/silicon/ai/updatehealth()
if(status_flags & GODMODE)
health = 100
set_stat(CONSCIOUS)
setOxyLoss(0)
else
health = 100 - getFireLoss() - getBruteLoss() // Oxyloss is not part of health as it represents AIs backup power. AI is immune against ToxLoss as it is machine.
/mob/living/silicon/ai/rejuvenate()
..()
add_ai_verbs(src)
/mob/living/silicon/ai/Life()
if (src.stat == DEAD)
return
else //I'm not removing that shitton of tabs, unneeded as they are. -- Urist
//Being dead doesn't mean your temperature never changes
var/turf/T = get_turf(src)
if (src.stat != CONSCIOUS)
src.cameraFollow = null
src.reset_view(null)
disconnect_shell("Disconnecting from remote shell due to local system failure.")
src.updatehealth()
if (!hardware_integrity() || !backup_capacitor())
death()
return
// If our powersupply object was destroyed somehow, create new one.
if(!psupply)
create_powersupply()
// Handle power damage (oxy)
if(aiRestorePowerRoutine != 0 && !APU_power)
// Lose power
adjustOxyLoss(1)
else
// Gain Power
aiRestorePowerRoutine = 0 // Necessary if AI activated it's APU AFTER losing primary power.
adjustOxyLoss(-1)
handle_stunned() // Handle EMP-stun
lying = 0 // Handle lying down
malf_process()
if(APU_power && (hardware_integrity() < 50))
to_chat(src, "<span class='notice'><b>APU GENERATOR FAILURE! (System Damaged)</b></span>")
stop_apu(1)
var/blind = 0
var/area/loc = null
if (istype(T, /turf))
loc = T.loc
if (istype(loc, /area))
if (!loc.power_equip && !istype(src.loc,/obj/item) && !APU_power)
blind = 1
if (!blind)
src.sight |= SEE_TURFS
src.sight |= SEE_MOBS
src.sight |= SEE_OBJS
src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_LIVING
if (aiRestorePowerRoutine==2)
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
aiRestorePowerRoutine = 0
clear_fullscreen("blind")
update_icon()
return
else if (aiRestorePowerRoutine==3)
to_chat(src, "Alert cancelled. Power has been restored.")
aiRestorePowerRoutine = 0
clear_fullscreen("blind")
update_icon()
return
else if (APU_power)
aiRestorePowerRoutine = 0
clear_fullscreen("blind")
update_icon()
return
else
var/area/current_area = get_area(src)
if (lacks_power())
if (aiRestorePowerRoutine==0)
aiRestorePowerRoutine = 1
//Blind the AI
update_icon()
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
src.sight = src.sight&~SEE_TURFS
src.sight = src.sight&~SEE_MOBS
src.sight = src.sight&~SEE_OBJS
src.see_in_dark = 0
src.see_invisible = SEE_INVISIBLE_LIVING
//Now to tell the AI why they're blind and dying slowly.
to_chat(src, "You've lost power!")
disconnect_shell(message = "Disconnected from remote shell due to depowered networking interface.")
spawn(20)
to_chat(src, "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection.")
end_multicam()
sleep(50)
if (loc.power_equip)
if (!istype(T, /turf/space))
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
aiRestorePowerRoutine = 0
clear_fullscreen("blind")
return
to_chat(src, "Fault confirmed: missing external power. Shutting down main control system to save power.")
sleep(20)
to_chat(src, "Emergency control system online. Verifying connection to power network.")
sleep(50)
if (istype(T, /turf/space))
to_chat(src, "Unable to verify! No power connection detected!")
aiRestorePowerRoutine = 2
return
to_chat(src, "Connection verified. Searching for APC in power network.")
sleep(50)
var/obj/machinery/power/apc/theAPC = null
var/PRP
for (PRP=1, PRP<=4, PRP++)
for (var/obj/machinery/power/apc/APC in current_area)
if (!(APC.stat & BROKEN))
theAPC = APC
break
if (!theAPC)
switch(PRP)
if (1)
to_chat(src, "Unable to locate APC!")
else
to_chat(src, "Lost connection with the APC!")
src:aiRestorePowerRoutine = 2
return
if (loc.power_equip)
if (!istype(T, /turf/space))
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
aiRestorePowerRoutine = 0
clear_fullscreen("blind") //This, too, is a fix to issue 603
return
switch(PRP)
if (1)
to_chat(src, "APC located. Optimizing route to APC to avoid needless power waste.")
if (2)
to_chat(src, "Best route identified. Hacking offline APC power port.")
if (3)
to_chat(src, "Power port upload access confirmed. Loading control program into APC power port software.")
if (4)
to_chat(src, "Transfer complete. Forcing APC to execute program.")
sleep(50)
to_chat(src, "Receiving control information from APC.")
sleep(2)
theAPC.operating = 1
theAPC.equipment = 3
theAPC.update()
aiRestorePowerRoutine = 3
to_chat(src, "Here are your current laws:")
show_laws()
update_icon()
sleep(50)
theAPC = null
process_queued_alarms()
handle_regular_hud_updates()
handle_vision()
/mob/living/silicon/ai/proc/lacks_power()
if(APU_power)
return 0
var/turf/T = get_turf(src)
var/area/A = get_area(src)
return ((!A.power_equip) && A.requires_power == 1 || istype(T, /turf/space)) && !istype(src.loc,/obj/item)
/mob/living/silicon/ai/updatehealth()
if(status_flags & GODMODE)
health = 100
set_stat(CONSCIOUS)
setOxyLoss(0)
else
health = 100 - getFireLoss() - getBruteLoss() // Oxyloss is not part of health as it represents AIs backup power. AI is immune against ToxLoss as it is machine.
/mob/living/silicon/ai/rejuvenate()
..()
add_ai_verbs(src)
+11 -11
View File
@@ -1,12 +1,12 @@
/mob/living/silicon/ai/Login() //ThisIsDumb(TM) TODO: tidy this up _ ~Carn
..()
for(var/obj/effect/rune/rune in rune_list)
client.images += rune.blood_image
if(stat != DEAD)
for(var/obj/machinery/ai_status_display/O in machines) //change status
O.mode = 1
O.emotion = "Neutral"
if(multicam_on)
end_multicam()
src.view_core()
/mob/living/silicon/ai/Login() //ThisIsDumb(TM) TODO: tidy this up _ ~Carn
..()
for(var/obj/effect/rune/rune in rune_list)
client.images += rune.blood_image
if(stat != DEAD)
for(var/obj/machinery/ai_status_display/O in machines) //change status
O.mode = 1
O.emotion = "Neutral"
if(multicam_on)
end_multicam()
src.view_core()
return
+9 -9
View File
@@ -1,10 +1,10 @@
/mob/living/silicon/ai/Logout()
..()
for(var/obj/machinery/ai_status_display/O in machines) //change status
O.mode = 0
if(!isturf(loc))
if (client)
client.eye = loc
client.perspective = EYE_PERSPECTIVE
src.view_core()
/mob/living/silicon/ai/Logout()
..()
for(var/obj/machinery/ai_status_display/O in machines) //change status
O.mode = 0
if(!isturf(loc))
if (client)
client.eye = loc
client.perspective = EYE_PERSPECTIVE
src.view_core()
return
+140 -140
View File
@@ -1,140 +1,140 @@
// NEWMALF FUNCTIONS/PROCEDURES
// Sets up malfunction-related variables, research system and such.
/mob/living/silicon/ai/proc/setup_for_malf()
var/mob/living/silicon/ai/user = src
// Setup Variables
malfunctioning = 1
research = new/datum/malf_research()
research.owner = src
hacked_apcs = list()
recalc_cpu()
verbs += new/datum/game_mode/malfunction/verb/ai_select_hardware()
verbs += new/datum/game_mode/malfunction/verb/ai_select_research()
verbs += new/datum/game_mode/malfunction/verb/ai_help()
// And greet user with some OOC info.
to_chat(user, "You are malfunctioning, you do not have to follow any laws.")
to_chat(user, "Use ai-help command to view relevant information about your abilities")
// Safely remove malfunction status, fixing hacked APCs and resetting variables.
/mob/living/silicon/ai/proc/stop_malf()
var/mob/living/silicon/ai/user = src
// Generic variables
malfunctioning = 0
sleep(10)
research = null
// Fix hacked APCs
if(hacked_apcs)
for(var/obj/machinery/power/apc/A in hacked_apcs)
A.hacker = null
hacked_apcs = null
// Reset our verbs
src.verbs = null
add_ai_verbs()
// Let them know.
to_chat(user, "You are no longer malfunctioning. Your abilities have been removed.")
// Called every tick. Checks if AI is malfunctioning. If yes calls Process on research datum which handles all logic.
/mob/living/silicon/ai/proc/malf_process()
if(!malfunctioning)
return
if(!research)
if(!errored)
errored = 1
error("malf_process() called on AI without research datum. Report this.")
message_admins("ERROR: malf_process() called on AI without research datum. If admin modified one of the AI's vars revert the change and don't modify variables directly, instead use ProcCall or admin panels.")
spawn(1200)
errored = 0
return
recalc_cpu()
if(APU_power || aiRestorePowerRoutine != 0)
research.process(1)
else
research.process(0)
// Recalculates CPU time gain and storage capacities.
/mob/living/silicon/ai/proc/recalc_cpu()
// AI Starts with these values.
var/cpu_gain = 0.01
var/cpu_storage = 10
// Off-Station APCs should not count towards CPU generation.
for(var/obj/machinery/power/apc/A in hacked_apcs)
if(A.z in using_map.station_levels)
cpu_gain += 0.004
cpu_storage += 10
research.max_cpu = cpu_storage + override_CPUStorage
if(hardware && istype(hardware, /datum/malf_hardware/dual_ram))
research.max_cpu = research.max_cpu * 1.5
research.stored_cpu = min(research.stored_cpu, research.max_cpu)
research.cpu_increase_per_tick = cpu_gain + override_CPURate
if(hardware && istype(hardware, /datum/malf_hardware/dual_cpu))
research.cpu_increase_per_tick = research.cpu_increase_per_tick * 2
// Starts AI's APU generator
/mob/living/silicon/ai/proc/start_apu(var/shutup = 0)
if(!hardware || !istype(hardware, /datum/malf_hardware/apu_gen))
if(!shutup)
to_chat(src, "You do not have an APU generator and you shouldn't have this verb. Report this.")
return
if(hardware_integrity() < 50)
if(!shutup)
to_chat(src, "<span class='notice'>Starting APU... <b>FAULT</b>(System Damaged)</span>")
return
if(!shutup)
to_chat(src, "Starting APU... ONLINE")
APU_power = 1
// Stops AI's APU generator
/mob/living/silicon/ai/proc/stop_apu(var/shutup = 0)
if(!hardware || !istype(hardware, /datum/malf_hardware/apu_gen))
return
if(APU_power)
APU_power = 0
if(!shutup)
to_chat(src, "Shutting down APU... DONE")
// Returns percentage of AI's remaining backup capacitor charge (maxhealth - oxyloss).
/mob/living/silicon/ai/proc/backup_capacitor()
return ((200 - getOxyLoss()) / 2)
// Returns percentage of AI's remaining hardware integrity (maxhealth - (bruteloss + fireloss))
/mob/living/silicon/ai/proc/hardware_integrity()
return (health-config.health_threshold_dead)/2
// Shows capacitor charge and hardware integrity information to the AI in Status tab.
/mob/living/silicon/ai/show_system_integrity()
if(!src.stat)
stat(null, text("Hardware integrity: [hardware_integrity()]%"))
stat(null, text("Internal capacitor: [backup_capacitor()]%"))
else
stat(null, text("Systems nonfunctional"))
// Shows AI Malfunction related information to the AI.
/mob/living/silicon/ai/show_malf_ai()
if(src.is_malf())
if(src.hacked_apcs)
stat(null, "Hacked APCs: [src.hacked_apcs.len]")
stat(null, "System Status: [src.hacking ? "Busy" : "Stand-By"]")
if(src.research)
stat(null, "Available CPU: [src.research.stored_cpu] TFlops")
stat(null, "Maximal CPU: [src.research.max_cpu] TFlops")
stat(null, "CPU generation rate: [src.research.cpu_increase_per_tick * 10] TFlops/s")
stat(null, "Current research focus: [src.research.focus ? src.research.focus.name : "None"]")
if(src.research.focus)
stat(null, "Research completed: [round(src.research.focus.invested, 0.1)]/[round(src.research.focus.price)]")
if(system_override == 1)
stat(null, "SYSTEM OVERRIDE INITIATED")
else if(system_override == 2)
stat(null, "SYSTEM OVERRIDE COMPLETED")
// Cleaner proc for creating powersupply for an AI.
/mob/living/silicon/ai/proc/create_powersupply()
if(psupply)
qdel(psupply)
psupply = new/obj/machinery/ai_powersupply(src)
// NEWMALF FUNCTIONS/PROCEDURES
// Sets up malfunction-related variables, research system and such.
/mob/living/silicon/ai/proc/setup_for_malf()
var/mob/living/silicon/ai/user = src
// Setup Variables
malfunctioning = 1
research = new/datum/malf_research()
research.owner = src
hacked_apcs = list()
recalc_cpu()
verbs += new/datum/game_mode/malfunction/verb/ai_select_hardware()
verbs += new/datum/game_mode/malfunction/verb/ai_select_research()
verbs += new/datum/game_mode/malfunction/verb/ai_help()
// And greet user with some OOC info.
to_chat(user, "You are malfunctioning, you do not have to follow any laws.")
to_chat(user, "Use ai-help command to view relevant information about your abilities")
// Safely remove malfunction status, fixing hacked APCs and resetting variables.
/mob/living/silicon/ai/proc/stop_malf()
var/mob/living/silicon/ai/user = src
// Generic variables
malfunctioning = 0
sleep(10)
research = null
// Fix hacked APCs
if(hacked_apcs)
for(var/obj/machinery/power/apc/A in hacked_apcs)
A.hacker = null
hacked_apcs = null
// Reset our verbs
src.verbs = null
add_ai_verbs()
// Let them know.
to_chat(user, "You are no longer malfunctioning. Your abilities have been removed.")
// Called every tick. Checks if AI is malfunctioning. If yes calls Process on research datum which handles all logic.
/mob/living/silicon/ai/proc/malf_process()
if(!malfunctioning)
return
if(!research)
if(!errored)
errored = 1
error("malf_process() called on AI without research datum. Report this.")
message_admins("ERROR: malf_process() called on AI without research datum. If admin modified one of the AI's vars revert the change and don't modify variables directly, instead use ProcCall or admin panels.")
spawn(1200)
errored = 0
return
recalc_cpu()
if(APU_power || aiRestorePowerRoutine != 0)
research.process(1)
else
research.process(0)
// Recalculates CPU time gain and storage capacities.
/mob/living/silicon/ai/proc/recalc_cpu()
// AI Starts with these values.
var/cpu_gain = 0.01
var/cpu_storage = 10
// Off-Station APCs should not count towards CPU generation.
for(var/obj/machinery/power/apc/A in hacked_apcs)
if(A.z in using_map.station_levels)
cpu_gain += 0.004
cpu_storage += 10
research.max_cpu = cpu_storage + override_CPUStorage
if(hardware && istype(hardware, /datum/malf_hardware/dual_ram))
research.max_cpu = research.max_cpu * 1.5
research.stored_cpu = min(research.stored_cpu, research.max_cpu)
research.cpu_increase_per_tick = cpu_gain + override_CPURate
if(hardware && istype(hardware, /datum/malf_hardware/dual_cpu))
research.cpu_increase_per_tick = research.cpu_increase_per_tick * 2
// Starts AI's APU generator
/mob/living/silicon/ai/proc/start_apu(var/shutup = 0)
if(!hardware || !istype(hardware, /datum/malf_hardware/apu_gen))
if(!shutup)
to_chat(src, "You do not have an APU generator and you shouldn't have this verb. Report this.")
return
if(hardware_integrity() < 50)
if(!shutup)
to_chat(src, "<span class='notice'>Starting APU... <b>FAULT</b>(System Damaged)</span>")
return
if(!shutup)
to_chat(src, "Starting APU... ONLINE")
APU_power = 1
// Stops AI's APU generator
/mob/living/silicon/ai/proc/stop_apu(var/shutup = 0)
if(!hardware || !istype(hardware, /datum/malf_hardware/apu_gen))
return
if(APU_power)
APU_power = 0
if(!shutup)
to_chat(src, "Shutting down APU... DONE")
// Returns percentage of AI's remaining backup capacitor charge (maxhealth - oxyloss).
/mob/living/silicon/ai/proc/backup_capacitor()
return ((200 - getOxyLoss()) / 2)
// Returns percentage of AI's remaining hardware integrity (maxhealth - (bruteloss + fireloss))
/mob/living/silicon/ai/proc/hardware_integrity()
return (health-config.health_threshold_dead)/2
// Shows capacitor charge and hardware integrity information to the AI in Status tab.
/mob/living/silicon/ai/show_system_integrity()
if(!src.stat)
stat(null, text("Hardware integrity: [hardware_integrity()]%"))
stat(null, text("Internal capacitor: [backup_capacitor()]%"))
else
stat(null, text("Systems nonfunctional"))
// Shows AI Malfunction related information to the AI.
/mob/living/silicon/ai/show_malf_ai()
if(src.is_malf())
if(src.hacked_apcs)
stat(null, "Hacked APCs: [src.hacked_apcs.len]")
stat(null, "System Status: [src.hacking ? "Busy" : "Stand-By"]")
if(src.research)
stat(null, "Available CPU: [src.research.stored_cpu] TFlops")
stat(null, "Maximal CPU: [src.research.max_cpu] TFlops")
stat(null, "CPU generation rate: [src.research.cpu_increase_per_tick * 10] TFlops/s")
stat(null, "Current research focus: [src.research.focus ? src.research.focus.name : "None"]")
if(src.research.focus)
stat(null, "Research completed: [round(src.research.focus.invested, 0.1)]/[round(src.research.focus.price)]")
if(system_override == 1)
stat(null, "SYSTEM OVERRIDE INITIATED")
else if(system_override == 2)
stat(null, "SYSTEM OVERRIDE COMPLETED")
// Cleaner proc for creating powersupply for an AI.
/mob/living/silicon/ai/proc/create_powersupply()
if(psupply)
qdel(psupply)
psupply = new/obj/machinery/ai_powersupply(src)
@@ -1,8 +1,8 @@
/mob/living/silicon/decoy/death(gibbed)
if(stat == DEAD) return
icon_state = "ai-crash"
spawn(10)
explosion(loc, 3, 6, 12, 15)
for(var/obj/machinery/ai_status_display/O in machines) //change status
O.mode = 2
/mob/living/silicon/decoy/death(gibbed)
if(stat == DEAD) return
icon_state = "ai-crash"
spawn(10)
explosion(loc, 3, 6, 12, 15)
for(var/obj/machinery/ai_status_display/O in machines) //change status
O.mode = 2
return ..(gibbed)
+11 -11
View File
@@ -1,12 +1,12 @@
/mob/living/silicon/decoy
name = "AI"
icon = 'icons/mob/AI.dmi'//
icon_state = "ai"
anchored = TRUE // -- TLE
canmove = 0
/mob/living/silicon/decoy/New()
src.icon = 'icons/mob/AI.dmi'
src.icon_state = "ai"
src.anchored = TRUE
/mob/living/silicon/decoy
name = "AI"
icon = 'icons/mob/AI.dmi'//
icon_state = "ai"
anchored = TRUE // -- TLE
canmove = 0
/mob/living/silicon/decoy/New()
src.icon = 'icons/mob/AI.dmi'
src.icon_state = "ai"
src.anchored = TRUE
src.canmove = 0
+15 -15
View File
@@ -1,15 +1,15 @@
/mob/living/silicon/decoy/Life()
if (src.stat == 2)
return
else
if (src.health <= config.health_threshold_dead && src.stat != 2)
death()
return
/mob/living/silicon/decoy/updatehealth()
if(status_flags & GODMODE)
health = 100
set_stat(CONSCIOUS)
else
health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss()
/mob/living/silicon/decoy/Life()
if (src.stat == 2)
return
else
if (src.health <= config.health_threshold_dead && src.stat != 2)
death()
return
/mob/living/silicon/decoy/updatehealth()
if(status_flags & GODMODE)
health = 100
set_stat(CONSCIOUS)
else
health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss()
+2 -2
View File
@@ -1,3 +1,3 @@
/mob/living/silicon/Login()
SetSleeping(0)
/mob/living/silicon/Login()
SetSleeping(0)
..()
+16 -16
View File
@@ -1,16 +1,16 @@
//VOREStation Edit - Let's make it so that pAIs don't just always cease to be when they die! It would be cool if we could fix them.
/mob/living/silicon/pai/death(gibbed,deathmessage="fizzles out and clatters to the floor...")
// set_respawn_timer()
release_vore_contents()
close_up(TRUE)
if(card)
card.cut_overlays()
card.setEmotion(16)
card.damage_random_component()
if(gibbed)
qdel(card)
..(gibbed)
else
card.add_overlay("pai-dead")
..(gibbed,deathmessage)
//VOREStation Edit - Let's make it so that pAIs don't just always cease to be when they die! It would be cool if we could fix them.
/mob/living/silicon/pai/death(gibbed,deathmessage="fizzles out and clatters to the floor...")
// set_respawn_timer()
release_vore_contents()
close_up(TRUE)
if(card)
card.cut_overlays()
card.setEmotion(16)
card.damage_random_component()
if(gibbed)
qdel(card)
..(gibbed)
else
card.add_overlay("pai-dead")
..(gibbed,deathmessage)
+18 -18
View File
@@ -1,18 +1,18 @@
/mob/living/silicon/pai/examine(mob/user)
. = ..(user, infix = ", personal AI")
switch(src.stat)
if(CONSCIOUS)
if(!src.client) . += "It appears to be in stand-by mode." //afk
if(UNCONSCIOUS) . += "<span class='warning'>It doesn't seem to be responding.</span>"
if(DEAD) . += "<span class='deadsay'>It looks completely unsalvageable.</span>"
// VOREStation Edit: Start
. += attempt_vr(src,"examine_bellies",args) //VOREStation Edit
if(print_flavor_text()) . += "\n[print_flavor_text()]\n"
// VOREStation Edit: End
. += "*---------*"
if (pose)
if(!findtext(pose, regex("\[.?!]$"))) // Will be zero if the last character is not a member of [.?!]
pose = addtext(pose,".") //Makes sure all emotes end with a period.
. += "<br>It is [pose]" //Extra <br> intentional
/mob/living/silicon/pai/examine(mob/user)
. = ..(user, infix = ", personal AI")
switch(src.stat)
if(CONSCIOUS)
if(!src.client) . += "It appears to be in stand-by mode." //afk
if(UNCONSCIOUS) . += "<span class='warning'>It doesn't seem to be responding.</span>"
if(DEAD) . += "<span class='deadsay'>It looks completely unsalvageable.</span>"
// VOREStation Edit: Start
. += attempt_vr(src,"examine_bellies",args) //VOREStation Edit
if(print_flavor_text()) . += "\n[print_flavor_text()]\n"
// VOREStation Edit: End
. += "*---------*"
if (pose)
if(!findtext(pose, regex("\[.?!]$"))) // Will be zero if the last character is not a member of [.?!]
pose = addtext(pose,".") //Makes sure all emotes end with a period.
. += "<br>It is [pose]" //Extra <br> intentional
+50 -50
View File
@@ -1,50 +1,50 @@
/mob/living/silicon/pai/Life()
if(src.cable)
if(get_dist(src, src.cable) > 1)
var/turf/T = get_turf_or_move(src.loc)
for (var/mob/M in viewers(T))
M.show_message(span_red("The data cable rapidly retracts back into its spool."), 3, span_red("You hear a click and the sound of wire spooling rapidly."), 2)
playsound(src, 'sound/machines/click.ogg', 50, 1)
qdel(src.cable)
src.cable = null
if (src.stat == DEAD)
return
if(card.cell != PP_FUNCTIONAL|| card.processor != PP_FUNCTIONAL || card.board != PP_FUNCTIONAL || card.capacitor != PP_FUNCTIONAL)
death()
if(card.projector != PP_FUNCTIONAL && card.emitter != PP_FUNCTIONAL)
if(loc != card)
close_up()
to_chat(src, "<span class ='warning'>ERROR: System malfunction. Service required!</span>")
else if(card.projector != PP_FUNCTIONAL|| card.emitter != PP_FUNCTIONAL)
if(prob(5))
close_up()
to_chat(src, "<span class ='warning'>ERROR: System malfunction. Service recommended!</span>")
handle_regular_hud_updates()
handle_vision()
if(silence_time)
if(world.timeofday >= silence_time)
silence_time = null
to_chat(src, span_green("Communication circuit reinitialized. Speech and messaging functionality restored."))
handle_statuses()
if(health <= 0)
card.death_damage()
death(null,"fizzles out and clatters to the floor...")
else if(health < maxHealth && istype(src.loc , /obj/item/device/paicard))
adjustBruteLoss(-0.5)
adjustFireLoss(-0.5)
/mob/living/silicon/pai/updatehealth()
if(status_flags & GODMODE)
health = 100
set_stat(CONSCIOUS)
else
health = 100 - getBruteLoss() - getFireLoss()
/mob/living/silicon/pai/Life()
if(src.cable)
if(get_dist(src, src.cable) > 1)
var/turf/T = get_turf_or_move(src.loc)
for (var/mob/M in viewers(T))
M.show_message(span_red("The data cable rapidly retracts back into its spool."), 3, span_red("You hear a click and the sound of wire spooling rapidly."), 2)
playsound(src, 'sound/machines/click.ogg', 50, 1)
qdel(src.cable)
src.cable = null
if (src.stat == DEAD)
return
if(card.cell != PP_FUNCTIONAL|| card.processor != PP_FUNCTIONAL || card.board != PP_FUNCTIONAL || card.capacitor != PP_FUNCTIONAL)
death()
if(card.projector != PP_FUNCTIONAL && card.emitter != PP_FUNCTIONAL)
if(loc != card)
close_up()
to_chat(src, "<span class ='warning'>ERROR: System malfunction. Service required!</span>")
else if(card.projector != PP_FUNCTIONAL|| card.emitter != PP_FUNCTIONAL)
if(prob(5))
close_up()
to_chat(src, "<span class ='warning'>ERROR: System malfunction. Service recommended!</span>")
handle_regular_hud_updates()
handle_vision()
if(silence_time)
if(world.timeofday >= silence_time)
silence_time = null
to_chat(src, span_green("Communication circuit reinitialized. Speech and messaging functionality restored."))
handle_statuses()
if(health <= 0)
card.death_damage()
death(null,"fizzles out and clatters to the floor...")
else if(health < maxHealth && istype(src.loc , /obj/item/device/paicard))
adjustBruteLoss(-0.5)
adjustFireLoss(-0.5)
/mob/living/silicon/pai/updatehealth()
if(status_flags & GODMODE)
health = 100
set_stat(CONSCIOUS)
else
health = 100 - getBruteLoss() - getFireLoss()
File diff suppressed because it is too large Load Diff
@@ -1,65 +1,65 @@
/*
name
key
description
role
comments
ready = 0
*/
/datum/paiCandidate/proc/savefile_path(mob/user)
return "data/player_saves/[copytext(user.ckey, 1, 2)]/[user.ckey]/pai.sav"
/datum/paiCandidate/proc/savefile_save(mob/user)
if(IsGuestKey(user.key))
return 0
var/savefile/F = new /savefile(src.savefile_path(user))
F["name"] << src.name
F["description"] << src.description
F["role"] << src.role
F["comments"] << src.comments
F["version"] << 1
return 1
// loads the savefile corresponding to the mob's ckey
// if silent=true, report incompatible savefiles
// returns 1 if loaded (or file was incompatible)
// returns 0 if savefile did not exist
/datum/paiCandidate/proc/savefile_load(mob/user, var/silent = 1)
if (IsGuestKey(user.key))
return 0
var/path = savefile_path(user)
if (!fexists(path))
return 0
var/savefile/F = new /savefile(path)
if(!F) return //Not everyone has a pai savefile.
var/version = null
F["version"] >> version
if (isnull(version) || version != 1)
fdel(path)
if (!silent)
tgui_alert_async(user, "Your savefile was incompatible with this version and was deleted.")
return 0
F["name"] >> src.name
F["description"] >> src.description
F["role"] >> src.role
F["comments"] >> src.comments
F["eyecolor"] >> src.eye_color
F["chassis"] >> src.chassis
F["emotion"] >> src.ouremotion
F["gender"] >> src.gender
return 1
/*
name
key
description
role
comments
ready = 0
*/
/datum/paiCandidate/proc/savefile_path(mob/user)
return "data/player_saves/[copytext(user.ckey, 1, 2)]/[user.ckey]/pai.sav"
/datum/paiCandidate/proc/savefile_save(mob/user)
if(IsGuestKey(user.key))
return 0
var/savefile/F = new /savefile(src.savefile_path(user))
F["name"] << src.name
F["description"] << src.description
F["role"] << src.role
F["comments"] << src.comments
F["version"] << 1
return 1
// loads the savefile corresponding to the mob's ckey
// if silent=true, report incompatible savefiles
// returns 1 if loaded (or file was incompatible)
// returns 0 if savefile did not exist
/datum/paiCandidate/proc/savefile_load(mob/user, var/silent = 1)
if (IsGuestKey(user.key))
return 0
var/path = savefile_path(user)
if (!fexists(path))
return 0
var/savefile/F = new /savefile(path)
if(!F) return //Not everyone has a pai savefile.
var/version = null
F["version"] >> version
if (isnull(version) || version != 1)
fdel(path)
if (!silent)
tgui_alert_async(user, "Your savefile was incompatible with this version and was deleted.")
return 0
F["name"] >> src.name
F["description"] >> src.description
F["role"] >> src.role
F["comments"] >> src.comments
F["eyecolor"] >> src.eye_color
F["chassis"] >> src.chassis
F["emotion"] >> src.ouremotion
F["gender"] >> src.gender
return 1
+398 -398
View File
@@ -1,398 +1,398 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
// Recruiting observers to play as pAIs
var/datum/paiController/paiController // Global handler for pAI candidates
/datum/paiCandidate
var/name
var/key
var/description
var/role
var/comments
var/ready = 0
var/chassis
var/ouremotion
var/eye_color
var/gender
/hook/startup/proc/paiControllerSetup()
paiController = new /datum/paiController()
return 1
/datum/paiController
var/inquirer = null
var/list/pai_candidates = list()
var/list/asked = list()
var/askDelay = 10 * 60 * 1 // One minute [ms * sec * min]
/datum/paiController/Topic(href, href_list[])
if(href_list["download"])
var/datum/paiCandidate/candidate = locate(href_list["candidate"])
var/obj/item/device/paicard/card = locate(href_list["device"])
if(card.pai)
return
if(istype(card,/obj/item/device/paicard) && istype(candidate,/datum/paiCandidate))
var/mob/living/silicon/pai/pai = new(card)
pai.key = candidate.key
paikeys |= pai.ckey
card.setPersonality(pai)
if(!candidate.name)
pai.SetName(pick(ninja_names))
else
pai.SetName(candidate.name)
if(candidate.description)
pai.flavor_text = candidate.description
if(candidate.eye_color)
pai.eye_color = candidate.eye_color
card.screen_color = pai.eye_color
if(candidate.chassis)
pai.chassis = candidate.chassis
if(candidate.ouremotion)
card.setEmotion(candidate.ouremotion)
if(candidate.gender)
pai.gender = candidate.gender
pai.update_icon()
pai.real_name = pai.name
card.looking_for_personality = 0
if(pai.mind) update_antag_icons(pai.mind)
pai_candidates -= candidate
usr << browse(null, "window=findPai")
if(href_list["new"])
var/datum/paiCandidate/candidate = locate(href_list["candidate"])
var/option = href_list["option"]
var/t = ""
switch(option)
if("name")
t = sanitizeSafe(tgui_input_text(usr, "Enter a name for your pAI", "pAI Name", candidate.name, MAX_NAME_LEN), MAX_NAME_LEN)
if(t)
candidate.name = t
if("desc")
t = tgui_input_text(usr, "Enter a description for your pAI", "pAI Description", candidate.description, multiline = TRUE, prevent_enter = TRUE)
if(t)
candidate.description = sanitize(t)
if("role")
t = tgui_input_text(usr, "Enter a role for your pAI", "pAI Role", candidate.role)
if(t)
candidate.role = sanitize(t)
if("ooc")
t = tgui_input_text(usr, "Enter any OOC comments", "pAI OOC Comments", candidate.comments, multiline = TRUE, prevent_enter = TRUE)
if(t)
candidate.comments = sanitize(t)
if("save")
candidate.savefile_save(usr)
if("load")
candidate.savefile_load(usr)
//In case people have saved unsanitized stuff.
if(candidate.name)
candidate.name = sanitizeSafe(candidate.name, MAX_NAME_LEN)
if(candidate.description)
candidate.description = sanitize(candidate.description)
if(candidate.role)
candidate.role = sanitize(candidate.role)
if(candidate.comments)
candidate.comments = sanitize(candidate.comments)
if("submit")
if(candidate)
candidate.ready = 1
for(var/obj/item/device/paicard/p in all_pai_cards)
if(p.looking_for_personality == 1)
p.alertUpdate()
usr << browse(null, "window=paiRecruit")
return
recruitWindow(usr, href_list["allow_submit"] != "0")
/datum/paiController/proc/recruitWindow(var/mob/M as mob, allowSubmit = 1)
var/datum/paiCandidate/candidate
for(var/datum/paiCandidate/c in pai_candidates)
if(!istype(c) || !istype(M))
break
if(c.key == M.key)
candidate = c
if(!candidate)
candidate = new /datum/paiCandidate()
candidate.key = M.key
pai_candidates.Add(candidate)
var/dat = ""
dat += {"
<style type="text/css">
body {
margin-top:5px;
font-family:Verdana;
color:white;
font-size:13px;
background-image:url('uiBackground.png');
background-repeat:repeat-x;
background-color:#272727;
background-position:center top;
}
table {
border-collapse:collapse;
font-size:13px;
}
th, td {
border: 1px solid #333333;
}
p.top {
background-color: none;
color: white;
}
tr.d0 td {
background-color: #c0c0c0;
color: black;
border:0px;
border: 1px solid #333333;
}
tr.d0 th {
background-color: none;
color: #4477E0;
text-align:right;
vertical-align:top;
width:120px;
border:0px;
}
tr.d1 td {
background-color: #555555;
color: white;
}
td.button {
border: 1px solid #161616;
background-color: #40628a;
}
td.desc {
font-weight:bold;
}
a {
color:#4477E0;
}
a.button {
color:white;
text-decoration: none;
}
</style>
"}
dat += {"
<body>
<b><font size="3px">pAI Personality Configuration</font></b>
<p class="top">Please configure your pAI personality's options. Remember, what you enter here could determine whether or not the user requesting a personality chooses you!</p>
<table>
<tr class="d0">
<th rowspan="2"><a href='byond://?src=\ref[src];option=name;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]'>Name</a>:</th>
<td class="desc">[candidate.name]&nbsp;</td>
</tr>
<tr class="d1">
<td>What you plan to call yourself. Suggestions: Any character name you would choose for a station character OR an AI.</td>
</tr>
<tr class="d0">
<th rowspan="2"><a href='byond://?src=\ref[src];option=desc;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]'>Description</a>:</th>
<td class="desc">[candidate.description]&nbsp;</td>
</tr>
<tr class="d1">
<td>What sort of pAI you typically play; your mannerisms, your quirks, etc. This can be as sparse or as detailed as you like.</td>
</tr>
<tr class="d0">
<th rowspan="2"><a href='byond://?src=\ref[src];option=role;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]'>Preferred Role</a>:</th>
<td class="desc">[candidate.role]&nbsp;</td>
</tr>
<tr class="d1">
<td>Do you like to partner with sneaky social ninjas? Like to help security hunt down thugs? Enjoy watching an engineer's back while he saves the station yet again? This doesn't have to be limited to just station jobs. Pretty much any general descriptor for what you'd like to be doing works here.</td>
</tr>
<tr class="d0">
<th rowspan="2"><a href='byond://?src=\ref[src];option=ooc;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]'>OOC Comments</a>:</th>
<td class="desc">[candidate.comments]&nbsp;</td>
</tr>
<tr class="d1">
<td>Anything you'd like to address specifically to the player reading this in an OOC manner. \"I prefer more serious RP.\", \"I'm still learning the interface!\", etc. Feel free to leave this blank if you want.</td>
</tr>
</table>
<br>
<table>
<tr>
<td class="button">
<a href='byond://?src=\ref[src];option=save;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]' class="button">Save Personality</a>
</td>
</tr>
<tr>
<td class="button">
<a href='byond://?src=\ref[src];option=load;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]' class="button"><b><font size="3px">Load Personality</font></b></a>
</td>
</tr>
</table><br>
"}
if(allowSubmit)
dat += {"
<table>
<td class="button"><a href='byond://?src=\ref[src];option=submit;new=1;candidate=\ref[candidate]' class="button"><b><font size="4px">Submit Personality</font></b></a></td>
</table><br>
"}
dat += {"
<body>
"}
M << browse(dat, "window=paiRecruit;size=580x580;")
/datum/paiController/proc/findPAI(var/obj/item/device/paicard/p, var/mob/user)
requestRecruits(user)
var/list/available = list()
for(var/datum/paiCandidate/c in paiController.pai_candidates)
if(c.ready)
var/found = 0
for(var/mob/observer/dead/o in player_list)
if(o.key == c.key && o.MayRespawn())
found = 1
if(found)
available.Add(c)
var/dat = ""
dat += {"
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
<html>
<head>
<style>
body {
margin-top:5px;
font-family:Verdana;
color:white;
font-size:13px;
background-image:url('uiBackground.png');
background-repeat:repeat-x;
background-color:#272727;
background-position:center top;
}
table {
font-size:13px;
}
table.desc {
border-collapse:collapse;
font-size:13px;
border: 1px solid #161616;
width:100%;
}
table.download {
border-collapse:collapse;
font-size:13px;
border: 1px solid #161616;
width:100%;
}
tr.d0 td, tr.d0 th {
background-color: #506070;
color: white;
}
tr.d1 td, tr.d1 th {
background-color: #708090;
color: white;
}
tr.d2 td {
background-color: #00FF00;
color: white;
text-align:center;
}
td.button {
border: 1px solid #161616;
background-color: #40628a;
text-align: center;
}
td.download {
border: 1px solid #161616;
background-color: #40628a;
text-align: center;
}
th {
text-align:left;
width:125px;
vertical-align:top;
}
a.button {
color:white;
text-decoration: none;
}
</style>
</head>
<body>
<b><font size='3px'>pAI Availability List</font></b><br><br>
"}
dat += "<p>Displaying available AI personalities from central database... If there are no entries, or if a suitable entry is not listed, check again later as more personalities may be added.</p>"
for(var/datum/paiCandidate/c in available)
dat += {"
<table class="desc">
<tr class="d0">
<th>Name:</th>
<td>[c.name]</td>
</tr>
<tr class="d1">
<th>Description:</th>
<td>[c.description]</td>
</tr>
<tr class="d0">
<th>Preferred Role:</th>
<td>[c.role]</td>
</tr>
<tr class="d1">
<th>OOC Comments:</th>
<td>[c.comments]</td>
</tr>
</table>
<table class="download">
<td class="download"><a href='byond://?src=\ref[src];download=1;candidate=\ref[c];device=\ref[p]' class="button"><b>Download [c.name]</b></a>
</td>
</table>
<br>
"}
dat += {"
</body>
</html>
"}
user << browse(dat, "window=findPai")
/datum/paiController/proc/requestRecruits(var/mob/user)
inquirer = user
for(var/mob/observer/dead/O in player_list)
if(!O.MayRespawn())
continue
if(jobban_isbanned(O, "pAI"))
continue
if(asked.Find(O.key))
if(world.time < asked[O.key] + askDelay)
continue
else
asked.Remove(O.key)
if(O.client)
if(O.client.prefs.be_special & BE_PAI)
question(O.client)
/datum/paiController/proc/question(var/client/C)
spawn(0)
if(!C) return
asked.Add(C.key)
asked[C.key] = world.time
var/mob/ourmob = C.mob
if(ourmob)
var/time_till_respawn = ourmob.time_till_respawn()
if(time_till_respawn == -1 || time_till_respawn)
return
for(var/ourkey in paikeys)
if(ourkey == ourmob.ckey)
return
var/response = tgui_alert(C, "[inquirer] is requesting a pAI personality. Would you like to play as a personal AI?", "pAI Request", list("Yes", "No", "Never for this round"))
if(!C) return //handle logouts that happen whilst the alert is waiting for a response.
if(response == "Yes")
recruitWindow(C.mob)
else if (response == "Never for this round")
C.prefs.be_special ^= BE_PAI
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
// Recruiting observers to play as pAIs
var/datum/paiController/paiController // Global handler for pAI candidates
/datum/paiCandidate
var/name
var/key
var/description
var/role
var/comments
var/ready = 0
var/chassis
var/ouremotion
var/eye_color
var/gender
/hook/startup/proc/paiControllerSetup()
paiController = new /datum/paiController()
return 1
/datum/paiController
var/inquirer = null
var/list/pai_candidates = list()
var/list/asked = list()
var/askDelay = 10 * 60 * 1 // One minute [ms * sec * min]
/datum/paiController/Topic(href, href_list[])
if(href_list["download"])
var/datum/paiCandidate/candidate = locate(href_list["candidate"])
var/obj/item/device/paicard/card = locate(href_list["device"])
if(card.pai)
return
if(istype(card,/obj/item/device/paicard) && istype(candidate,/datum/paiCandidate))
var/mob/living/silicon/pai/pai = new(card)
pai.key = candidate.key
paikeys |= pai.ckey
card.setPersonality(pai)
if(!candidate.name)
pai.SetName(pick(ninja_names))
else
pai.SetName(candidate.name)
if(candidate.description)
pai.flavor_text = candidate.description
if(candidate.eye_color)
pai.eye_color = candidate.eye_color
card.screen_color = pai.eye_color
if(candidate.chassis)
pai.chassis = candidate.chassis
if(candidate.ouremotion)
card.setEmotion(candidate.ouremotion)
if(candidate.gender)
pai.gender = candidate.gender
pai.update_icon()
pai.real_name = pai.name
card.looking_for_personality = 0
if(pai.mind) update_antag_icons(pai.mind)
pai_candidates -= candidate
usr << browse(null, "window=findPai")
if(href_list["new"])
var/datum/paiCandidate/candidate = locate(href_list["candidate"])
var/option = href_list["option"]
var/t = ""
switch(option)
if("name")
t = sanitizeSafe(tgui_input_text(usr, "Enter a name for your pAI", "pAI Name", candidate.name, MAX_NAME_LEN), MAX_NAME_LEN)
if(t)
candidate.name = t
if("desc")
t = tgui_input_text(usr, "Enter a description for your pAI", "pAI Description", candidate.description, multiline = TRUE, prevent_enter = TRUE)
if(t)
candidate.description = sanitize(t)
if("role")
t = tgui_input_text(usr, "Enter a role for your pAI", "pAI Role", candidate.role)
if(t)
candidate.role = sanitize(t)
if("ooc")
t = tgui_input_text(usr, "Enter any OOC comments", "pAI OOC Comments", candidate.comments, multiline = TRUE, prevent_enter = TRUE)
if(t)
candidate.comments = sanitize(t)
if("save")
candidate.savefile_save(usr)
if("load")
candidate.savefile_load(usr)
//In case people have saved unsanitized stuff.
if(candidate.name)
candidate.name = sanitizeSafe(candidate.name, MAX_NAME_LEN)
if(candidate.description)
candidate.description = sanitize(candidate.description)
if(candidate.role)
candidate.role = sanitize(candidate.role)
if(candidate.comments)
candidate.comments = sanitize(candidate.comments)
if("submit")
if(candidate)
candidate.ready = 1
for(var/obj/item/device/paicard/p in all_pai_cards)
if(p.looking_for_personality == 1)
p.alertUpdate()
usr << browse(null, "window=paiRecruit")
return
recruitWindow(usr, href_list["allow_submit"] != "0")
/datum/paiController/proc/recruitWindow(var/mob/M as mob, allowSubmit = 1)
var/datum/paiCandidate/candidate
for(var/datum/paiCandidate/c in pai_candidates)
if(!istype(c) || !istype(M))
break
if(c.key == M.key)
candidate = c
if(!candidate)
candidate = new /datum/paiCandidate()
candidate.key = M.key
pai_candidates.Add(candidate)
var/dat = ""
dat += {"
<style type="text/css">
body {
margin-top:5px;
font-family:Verdana;
color:white;
font-size:13px;
background-image:url('uiBackground.png');
background-repeat:repeat-x;
background-color:#272727;
background-position:center top;
}
table {
border-collapse:collapse;
font-size:13px;
}
th, td {
border: 1px solid #333333;
}
p.top {
background-color: none;
color: white;
}
tr.d0 td {
background-color: #c0c0c0;
color: black;
border:0px;
border: 1px solid #333333;
}
tr.d0 th {
background-color: none;
color: #4477E0;
text-align:right;
vertical-align:top;
width:120px;
border:0px;
}
tr.d1 td {
background-color: #555555;
color: white;
}
td.button {
border: 1px solid #161616;
background-color: #40628a;
}
td.desc {
font-weight:bold;
}
a {
color:#4477E0;
}
a.button {
color:white;
text-decoration: none;
}
</style>
"}
dat += {"
<body>
<b><font size="3px">pAI Personality Configuration</font></b>
<p class="top">Please configure your pAI personality's options. Remember, what you enter here could determine whether or not the user requesting a personality chooses you!</p>
<table>
<tr class="d0">
<th rowspan="2"><a href='byond://?src=\ref[src];option=name;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]'>Name</a>:</th>
<td class="desc">[candidate.name]&nbsp;</td>
</tr>
<tr class="d1">
<td>What you plan to call yourself. Suggestions: Any character name you would choose for a station character OR an AI.</td>
</tr>
<tr class="d0">
<th rowspan="2"><a href='byond://?src=\ref[src];option=desc;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]'>Description</a>:</th>
<td class="desc">[candidate.description]&nbsp;</td>
</tr>
<tr class="d1">
<td>What sort of pAI you typically play; your mannerisms, your quirks, etc. This can be as sparse or as detailed as you like.</td>
</tr>
<tr class="d0">
<th rowspan="2"><a href='byond://?src=\ref[src];option=role;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]'>Preferred Role</a>:</th>
<td class="desc">[candidate.role]&nbsp;</td>
</tr>
<tr class="d1">
<td>Do you like to partner with sneaky social ninjas? Like to help security hunt down thugs? Enjoy watching an engineer's back while he saves the station yet again? This doesn't have to be limited to just station jobs. Pretty much any general descriptor for what you'd like to be doing works here.</td>
</tr>
<tr class="d0">
<th rowspan="2"><a href='byond://?src=\ref[src];option=ooc;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]'>OOC Comments</a>:</th>
<td class="desc">[candidate.comments]&nbsp;</td>
</tr>
<tr class="d1">
<td>Anything you'd like to address specifically to the player reading this in an OOC manner. \"I prefer more serious RP.\", \"I'm still learning the interface!\", etc. Feel free to leave this blank if you want.</td>
</tr>
</table>
<br>
<table>
<tr>
<td class="button">
<a href='byond://?src=\ref[src];option=save;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]' class="button">Save Personality</a>
</td>
</tr>
<tr>
<td class="button">
<a href='byond://?src=\ref[src];option=load;new=1;allow_submit=[allowSubmit];candidate=\ref[candidate]' class="button"><b><font size="3px">Load Personality</font></b></a>
</td>
</tr>
</table><br>
"}
if(allowSubmit)
dat += {"
<table>
<td class="button"><a href='byond://?src=\ref[src];option=submit;new=1;candidate=\ref[candidate]' class="button"><b><font size="4px">Submit Personality</font></b></a></td>
</table><br>
"}
dat += {"
<body>
"}
M << browse(dat, "window=paiRecruit;size=580x580;")
/datum/paiController/proc/findPAI(var/obj/item/device/paicard/p, var/mob/user)
requestRecruits(user)
var/list/available = list()
for(var/datum/paiCandidate/c in paiController.pai_candidates)
if(c.ready)
var/found = 0
for(var/mob/observer/dead/o in player_list)
if(o.key == c.key && o.MayRespawn())
found = 1
if(found)
available.Add(c)
var/dat = ""
dat += {"
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
<html>
<head>
<style>
body {
margin-top:5px;
font-family:Verdana;
color:white;
font-size:13px;
background-image:url('uiBackground.png');
background-repeat:repeat-x;
background-color:#272727;
background-position:center top;
}
table {
font-size:13px;
}
table.desc {
border-collapse:collapse;
font-size:13px;
border: 1px solid #161616;
width:100%;
}
table.download {
border-collapse:collapse;
font-size:13px;
border: 1px solid #161616;
width:100%;
}
tr.d0 td, tr.d0 th {
background-color: #506070;
color: white;
}
tr.d1 td, tr.d1 th {
background-color: #708090;
color: white;
}
tr.d2 td {
background-color: #00FF00;
color: white;
text-align:center;
}
td.button {
border: 1px solid #161616;
background-color: #40628a;
text-align: center;
}
td.download {
border: 1px solid #161616;
background-color: #40628a;
text-align: center;
}
th {
text-align:left;
width:125px;
vertical-align:top;
}
a.button {
color:white;
text-decoration: none;
}
</style>
</head>
<body>
<b><font size='3px'>pAI Availability List</font></b><br><br>
"}
dat += "<p>Displaying available AI personalities from central database... If there are no entries, or if a suitable entry is not listed, check again later as more personalities may be added.</p>"
for(var/datum/paiCandidate/c in available)
dat += {"
<table class="desc">
<tr class="d0">
<th>Name:</th>
<td>[c.name]</td>
</tr>
<tr class="d1">
<th>Description:</th>
<td>[c.description]</td>
</tr>
<tr class="d0">
<th>Preferred Role:</th>
<td>[c.role]</td>
</tr>
<tr class="d1">
<th>OOC Comments:</th>
<td>[c.comments]</td>
</tr>
</table>
<table class="download">
<td class="download"><a href='byond://?src=\ref[src];download=1;candidate=\ref[c];device=\ref[p]' class="button"><b>Download [c.name]</b></a>
</td>
</table>
<br>
"}
dat += {"
</body>
</html>
"}
user << browse(dat, "window=findPai")
/datum/paiController/proc/requestRecruits(var/mob/user)
inquirer = user
for(var/mob/observer/dead/O in player_list)
if(!O.MayRespawn())
continue
if(jobban_isbanned(O, "pAI"))
continue
if(asked.Find(O.key))
if(world.time < asked[O.key] + askDelay)
continue
else
asked.Remove(O.key)
if(O.client)
if(O.client.prefs.be_special & BE_PAI)
question(O.client)
/datum/paiController/proc/question(var/client/C)
spawn(0)
if(!C) return
asked.Add(C.key)
asked[C.key] = world.time
var/mob/ourmob = C.mob
if(ourmob)
var/time_till_respawn = ourmob.time_till_respawn()
if(time_till_respawn == -1 || time_till_respawn)
return
for(var/ourkey in paikeys)
if(ourkey == ourmob.ckey)
return
var/response = tgui_alert(C, "[inquirer] is requesting a pAI personality. Would you like to play as a personal AI?", "pAI Request", list("Yes", "No", "Never for this round"))
if(!C) return //handle logouts that happen whilst the alert is waiting for a response.
if(response == "Yes")
recruitWindow(C.mob)
else if (response == "Never for this round")
C.prefs.be_special ^= BE_PAI
+7 -7
View File
@@ -1,7 +1,7 @@
/mob/living/silicon/pai/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if(silence_time)
to_chat(src, span_green("Communication circuits remain uninitialized."))
else if(card.speech_synthesizer != PP_FUNCTIONAL)
to_chat(src, "<span class='warning'>Communication circuits damaged. Service required.</span>")
else
..()
/mob/living/silicon/pai/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if(silence_time)
to_chat(src, span_green("Communication circuits remain uninitialized."))
else if(card.speech_synthesizer != PP_FUNCTIONAL)
to_chat(src, "<span class='warning'>Communication circuits damaged. Service required.</span>")
else
..()
+275 -275
View File
@@ -1,276 +1,276 @@
// TODO: remove the robot.mmi and robot.cell variables and completely rely on the robot component system
/datum/robot_component/var/name
/datum/robot_component/var/installed = 0
/datum/robot_component/var/powered = 0
/datum/robot_component/var/toggled = 1
/datum/robot_component/var/brute_damage = 0
/datum/robot_component/var/electronics_damage = 0
/datum/robot_component/var/idle_usage = 0 // Amount of power used every MC tick. In joules.
/datum/robot_component/var/active_usage = 0 // Amount of power used for every action. Actions are module-specific. Actuator for each tile moved, etc.
/datum/robot_component/var/max_damage = 30 // HP of this component.
/datum/robot_component/var/mob/living/silicon/robot/owner
// The actual device object that has to be installed for this.
/datum/robot_component/var/external_type = null
// The wrapped device(e.g. radio), only set if external_type isn't null
/datum/robot_component/var/obj/item/wrapped = null
/datum/robot_component/New(mob/living/silicon/robot/R)
src.owner = R
/datum/robot_component/proc/install()
/datum/robot_component/proc/uninstall()
/datum/robot_component/proc/destroy()
var/brokenstate = "broken" // Generic icon
if (istype(wrapped, /obj/item/robot_parts/robot_component))
var/obj/item/robot_parts/robot_component/comp = wrapped
brokenstate = comp.icon_state_broken
if(wrapped)
qdel(wrapped)
wrapped = new/obj/item/broken_device
wrapped.icon_state = brokenstate // Module-specific broken icons! Yay!
// The thing itself isn't there anymore, but some fried remains are.
installed = -1
uninstall()
/datum/robot_component/proc/take_damage(brute, electronics, sharp, edge)
if(installed != 1) return
brute_damage += brute
electronics_damage += electronics
if(brute_damage + electronics_damage >= max_damage) destroy()
/datum/robot_component/proc/heal_damage(brute, electronics)
if(installed != 1)
// If it's not installed, can't repair it.
return 0
brute_damage = max(0, brute_damage - brute)
electronics_damage = max(0, electronics_damage - electronics)
/datum/robot_component/proc/is_powered()
return (installed == 1) && (brute_damage + electronics_damage < max_damage) && (!idle_usage || powered)
/datum/robot_component/proc/update_power_state()
if(toggled == 0)
powered = 0
return
if(owner.cell && owner.cell.charge >= idle_usage)
owner.cell_use_power(idle_usage)
powered = 1
else
powered = 0
// ARMOUR
// Protects the cyborg from damage. Usually first module to be hit
// No power usage
/datum/robot_component/armour
name = "armour plating"
external_type = /obj/item/robot_parts/robot_component/armour
max_damage = 90
/datum/robot_component/armour/platform
name = "platform armour plating"
external_type = /obj/item/robot_parts/robot_component/armour_platform
max_damage = 140
// ACTUATOR
// Enables movement.
// Uses no power when idle. Uses 200J for each tile the cyborg moves.
/datum/robot_component/actuator
name = "actuator"
idle_usage = 0
active_usage = 200
external_type = /obj/item/robot_parts/robot_component/actuator
max_damage = 50
//A fixed and much cleaner implementation of /tg/'s special snowflake code.
/datum/robot_component/actuator/is_powered()
return (installed == 1) && (brute_damage + electronics_damage < max_damage)
// POWER CELL
// Stores power (how unexpected..)
// No power usage
/datum/robot_component/cell
name = "power cell"
max_damage = 50
/datum/robot_component/cell/destroy()
..()
owner.cell = null
// RADIO
// Enables radio communications
// Uses no power when idle. Uses 10J for each received radio message, 50 for each transmitted message.
/datum/robot_component/radio
name = "radio"
external_type = /obj/item/robot_parts/robot_component/radio
idle_usage = 15 //it's not actually possible to tell when we receive a message over our radio, so just use 10W every tick for passive listening
active_usage = 75 //transmit power
max_damage = 40
// BINARY RADIO
// Enables binary communications with other cyborgs/AIs
// Uses no power when idle. Uses 10J for each received radio message, 50 for each transmitted message
/datum/robot_component/binary_communication
name = "binary communication device"
external_type = /obj/item/robot_parts/robot_component/binary_communication_device
idle_usage = 5
active_usage = 25
max_damage = 30
// CAMERA
// Enables cyborg vision. Can also be remotely accessed via consoles.
// Uses 10J constantly
/datum/robot_component/camera
name = "camera"
external_type = /obj/item/robot_parts/robot_component/camera
idle_usage = 10
max_damage = 40
var/obj/machinery/camera/camera
/datum/robot_component/camera/New(mob/living/silicon/robot/R)
..()
camera = R.camera
/datum/robot_component/camera/update_power_state()
..()
if (camera)
camera.status = powered
/datum/robot_component/camera/install()
if (camera)
camera.status = 1
/datum/robot_component/camera/uninstall()
if (camera)
camera.status = 0
/datum/robot_component/camera/destroy()
if (camera)
camera.status = 0
// SELF DIAGNOSIS MODULE
// Analyses cyborg's modules, providing damage readouts and basic information
// Uses 1kJ burst when analysis is done
/datum/robot_component/diagnosis_unit
name = "self-diagnosis unit"
active_usage = 1000
external_type = /obj/item/robot_parts/robot_component/diagnosis_unit
max_damage = 30
// HELPER STUFF
// Initializes cyborg's components. Technically, adds default set of components to new borgs
/mob/living/silicon/robot/proc/initialize_components()
components["actuator"] = new/datum/robot_component/actuator(src)
components["radio"] = new/datum/robot_component/radio(src)
components["power cell"] = new/datum/robot_component/cell(src)
components["diagnosis unit"] = new/datum/robot_component/diagnosis_unit(src)
components["camera"] = new/datum/robot_component/camera(src)
components["comms"] = new/datum/robot_component/binary_communication(src)
components["armour"] = new/datum/robot_component/armour(src)
// Checks if component is functioning
/mob/living/silicon/robot/proc/is_component_functioning(module_name)
var/datum/robot_component/C = components[module_name]
return C && C.installed == 1 && C.toggled && C.is_powered()
// Returns component by it's string name
/mob/living/silicon/robot/proc/get_component(var/component_name)
var/datum/robot_component/C = components[component_name]
return C
// COMPONENT OBJECTS
// Component Objects
// These objects are visual representation of modules
/obj/item/broken_device
name = "broken component"
icon = 'icons/obj/robot_component.dmi'
icon_state = "broken"
matter = list(MAT_STEEL = 1000)
/obj/item/broken_device/random
var/list/possible_icons = list("binradio_broken",
"motor_broken",
"armor_broken",
"camera_broken",
"analyser_broken",
"radio_broken")
/obj/item/broken_device/random/Initialize()
icon_state = pick(possible_icons)
/obj/item/robot_parts/robot_component
icon = 'icons/obj/robot_component.dmi'
icon_state = "working"
var/brute = 0
var/burn = 0
var/icon_state_broken = "broken"
/obj/item/robot_parts/robot_component/binary_communication_device
name = "binary communication device"
desc = "A module used for binary communications over encrypted frequencies, commonly used by synthetic robots."
icon_state = "binradio"
icon_state_broken = "binradio_broken"
/obj/item/robot_parts/robot_component/actuator
name = "actuator"
desc = "A modular, hydraulic actuator used by exosuits and robots alike for movement and manipulation."
icon_state = "motor"
icon_state_broken = "motor_broken"
/obj/item/robot_parts/robot_component/armour
name = "armour plating"
desc = "A pair of flexible, adaptable armor plates, used to protect the internals of robots."
icon_state = "armor"
icon_state_broken = "armor_broken"
/obj/item/robot_parts/robot_component/armour_platform
name = "platform armour plating"
desc = "A pair of reinforced armor plates, used to protect the internals of robots."
icon_state = "armor"
icon_state_broken = "armor_broken"
color = COLOR_GRAY80
/obj/item/robot_parts/robot_component/camera
name = "camera"
desc = "A modified camera module used as a visual receptor for robots and exosuits, also serving as a relay for wireless video feed."
icon_state = "camera"
icon_state_broken = "camera_broken"
/obj/item/robot_parts/robot_component/diagnosis_unit
name = "diagnosis unit"
desc = "An internal computer and sensors used by robots and exosuits to accurately diagnose any system discrepancies on their components."
icon_state = "analyser"
icon_state_broken = "analyser_broken"
/obj/item/robot_parts/robot_component/radio
name = "radio"
desc = "A modular, multi-frequency radio used by robots and exosuits to enable communication systems. Comes with built-in subspace receivers."
icon_state = "radio"
// TODO: remove the robot.mmi and robot.cell variables and completely rely on the robot component system
/datum/robot_component/var/name
/datum/robot_component/var/installed = 0
/datum/robot_component/var/powered = 0
/datum/robot_component/var/toggled = 1
/datum/robot_component/var/brute_damage = 0
/datum/robot_component/var/electronics_damage = 0
/datum/robot_component/var/idle_usage = 0 // Amount of power used every MC tick. In joules.
/datum/robot_component/var/active_usage = 0 // Amount of power used for every action. Actions are module-specific. Actuator for each tile moved, etc.
/datum/robot_component/var/max_damage = 30 // HP of this component.
/datum/robot_component/var/mob/living/silicon/robot/owner
// The actual device object that has to be installed for this.
/datum/robot_component/var/external_type = null
// The wrapped device(e.g. radio), only set if external_type isn't null
/datum/robot_component/var/obj/item/wrapped = null
/datum/robot_component/New(mob/living/silicon/robot/R)
src.owner = R
/datum/robot_component/proc/install()
/datum/robot_component/proc/uninstall()
/datum/robot_component/proc/destroy()
var/brokenstate = "broken" // Generic icon
if (istype(wrapped, /obj/item/robot_parts/robot_component))
var/obj/item/robot_parts/robot_component/comp = wrapped
brokenstate = comp.icon_state_broken
if(wrapped)
qdel(wrapped)
wrapped = new/obj/item/broken_device
wrapped.icon_state = brokenstate // Module-specific broken icons! Yay!
// The thing itself isn't there anymore, but some fried remains are.
installed = -1
uninstall()
/datum/robot_component/proc/take_damage(brute, electronics, sharp, edge)
if(installed != 1) return
brute_damage += brute
electronics_damage += electronics
if(brute_damage + electronics_damage >= max_damage) destroy()
/datum/robot_component/proc/heal_damage(brute, electronics)
if(installed != 1)
// If it's not installed, can't repair it.
return 0
brute_damage = max(0, brute_damage - brute)
electronics_damage = max(0, electronics_damage - electronics)
/datum/robot_component/proc/is_powered()
return (installed == 1) && (brute_damage + electronics_damage < max_damage) && (!idle_usage || powered)
/datum/robot_component/proc/update_power_state()
if(toggled == 0)
powered = 0
return
if(owner.cell && owner.cell.charge >= idle_usage)
owner.cell_use_power(idle_usage)
powered = 1
else
powered = 0
// ARMOUR
// Protects the cyborg from damage. Usually first module to be hit
// No power usage
/datum/robot_component/armour
name = "armour plating"
external_type = /obj/item/robot_parts/robot_component/armour
max_damage = 90
/datum/robot_component/armour/platform
name = "platform armour plating"
external_type = /obj/item/robot_parts/robot_component/armour_platform
max_damage = 140
// ACTUATOR
// Enables movement.
// Uses no power when idle. Uses 200J for each tile the cyborg moves.
/datum/robot_component/actuator
name = "actuator"
idle_usage = 0
active_usage = 200
external_type = /obj/item/robot_parts/robot_component/actuator
max_damage = 50
//A fixed and much cleaner implementation of /tg/'s special snowflake code.
/datum/robot_component/actuator/is_powered()
return (installed == 1) && (brute_damage + electronics_damage < max_damage)
// POWER CELL
// Stores power (how unexpected..)
// No power usage
/datum/robot_component/cell
name = "power cell"
max_damage = 50
/datum/robot_component/cell/destroy()
..()
owner.cell = null
// RADIO
// Enables radio communications
// Uses no power when idle. Uses 10J for each received radio message, 50 for each transmitted message.
/datum/robot_component/radio
name = "radio"
external_type = /obj/item/robot_parts/robot_component/radio
idle_usage = 15 //it's not actually possible to tell when we receive a message over our radio, so just use 10W every tick for passive listening
active_usage = 75 //transmit power
max_damage = 40
// BINARY RADIO
// Enables binary communications with other cyborgs/AIs
// Uses no power when idle. Uses 10J for each received radio message, 50 for each transmitted message
/datum/robot_component/binary_communication
name = "binary communication device"
external_type = /obj/item/robot_parts/robot_component/binary_communication_device
idle_usage = 5
active_usage = 25
max_damage = 30
// CAMERA
// Enables cyborg vision. Can also be remotely accessed via consoles.
// Uses 10J constantly
/datum/robot_component/camera
name = "camera"
external_type = /obj/item/robot_parts/robot_component/camera
idle_usage = 10
max_damage = 40
var/obj/machinery/camera/camera
/datum/robot_component/camera/New(mob/living/silicon/robot/R)
..()
camera = R.camera
/datum/robot_component/camera/update_power_state()
..()
if (camera)
camera.status = powered
/datum/robot_component/camera/install()
if (camera)
camera.status = 1
/datum/robot_component/camera/uninstall()
if (camera)
camera.status = 0
/datum/robot_component/camera/destroy()
if (camera)
camera.status = 0
// SELF DIAGNOSIS MODULE
// Analyses cyborg's modules, providing damage readouts and basic information
// Uses 1kJ burst when analysis is done
/datum/robot_component/diagnosis_unit
name = "self-diagnosis unit"
active_usage = 1000
external_type = /obj/item/robot_parts/robot_component/diagnosis_unit
max_damage = 30
// HELPER STUFF
// Initializes cyborg's components. Technically, adds default set of components to new borgs
/mob/living/silicon/robot/proc/initialize_components()
components["actuator"] = new/datum/robot_component/actuator(src)
components["radio"] = new/datum/robot_component/radio(src)
components["power cell"] = new/datum/robot_component/cell(src)
components["diagnosis unit"] = new/datum/robot_component/diagnosis_unit(src)
components["camera"] = new/datum/robot_component/camera(src)
components["comms"] = new/datum/robot_component/binary_communication(src)
components["armour"] = new/datum/robot_component/armour(src)
// Checks if component is functioning
/mob/living/silicon/robot/proc/is_component_functioning(module_name)
var/datum/robot_component/C = components[module_name]
return C && C.installed == 1 && C.toggled && C.is_powered()
// Returns component by it's string name
/mob/living/silicon/robot/proc/get_component(var/component_name)
var/datum/robot_component/C = components[component_name]
return C
// COMPONENT OBJECTS
// Component Objects
// These objects are visual representation of modules
/obj/item/broken_device
name = "broken component"
icon = 'icons/obj/robot_component.dmi'
icon_state = "broken"
matter = list(MAT_STEEL = 1000)
/obj/item/broken_device/random
var/list/possible_icons = list("binradio_broken",
"motor_broken",
"armor_broken",
"camera_broken",
"analyser_broken",
"radio_broken")
/obj/item/broken_device/random/Initialize()
icon_state = pick(possible_icons)
/obj/item/robot_parts/robot_component
icon = 'icons/obj/robot_component.dmi'
icon_state = "working"
var/brute = 0
var/burn = 0
var/icon_state_broken = "broken"
/obj/item/robot_parts/robot_component/binary_communication_device
name = "binary communication device"
desc = "A module used for binary communications over encrypted frequencies, commonly used by synthetic robots."
icon_state = "binradio"
icon_state_broken = "binradio_broken"
/obj/item/robot_parts/robot_component/actuator
name = "actuator"
desc = "A modular, hydraulic actuator used by exosuits and robots alike for movement and manipulation."
icon_state = "motor"
icon_state_broken = "motor_broken"
/obj/item/robot_parts/robot_component/armour
name = "armour plating"
desc = "A pair of flexible, adaptable armor plates, used to protect the internals of robots."
icon_state = "armor"
icon_state_broken = "armor_broken"
/obj/item/robot_parts/robot_component/armour_platform
name = "platform armour plating"
desc = "A pair of reinforced armor plates, used to protect the internals of robots."
icon_state = "armor"
icon_state_broken = "armor_broken"
color = COLOR_GRAY80
/obj/item/robot_parts/robot_component/camera
name = "camera"
desc = "A modified camera module used as a visual receptor for robots and exosuits, also serving as a relay for wireless video feed."
icon_state = "camera"
icon_state_broken = "camera_broken"
/obj/item/robot_parts/robot_component/diagnosis_unit
name = "diagnosis unit"
desc = "An internal computer and sensors used by robots and exosuits to accurately diagnose any system discrepancies on their components."
icon_state = "analyser"
icon_state_broken = "analyser_broken"
/obj/item/robot_parts/robot_component/radio
name = "radio"
desc = "A modular, multi-frequency radio used by robots and exosuits to enable communication systems. Comes with built-in subspace receivers."
icon_state = "radio"
icon_state_broken = "radio_broken"
+22 -22
View File
@@ -1,22 +1,22 @@
/mob/living/silicon/robot/dust()
//Delete the MMI first so that it won't go popping out.
if(mmi)
qdel(mmi)
..()
/mob/living/silicon/robot/ash()
if(mmi)
qdel(mmi)
..()
/mob/living/silicon/robot/death(gibbed)
if(camera)
camera.status = 0
if(module)
var/obj/item/weapon/gripper/G = locate(/obj/item/weapon/gripper) in module
if(G) G.drop_item()
var/obj/item/device/dogborg/sleeper/S = locate(/obj/item/device/dogborg/sleeper) in module //VOREStation edit.
if(S) S.go_out() //VOREStation edit.
remove_robot_verbs()
sql_report_cyborg_death(src)
..(gibbed,"shudders violently for a moment, then becomes motionless, its eyes slowly darkening.")
/mob/living/silicon/robot/dust()
//Delete the MMI first so that it won't go popping out.
if(mmi)
qdel(mmi)
..()
/mob/living/silicon/robot/ash()
if(mmi)
qdel(mmi)
..()
/mob/living/silicon/robot/death(gibbed)
if(camera)
camera.status = 0
if(module)
var/obj/item/weapon/gripper/G = locate(/obj/item/weapon/gripper) in module
if(G) G.drop_item()
var/obj/item/device/dogborg/sleeper/S = locate(/obj/item/device/dogborg/sleeper) in module //VOREStation edit.
if(S) S.go_out() //VOREStation edit.
remove_robot_verbs()
sql_report_cyborg_death(src)
..(gibbed,"shudders violently for a moment, then becomes motionless, its eyes slowly darkening.")
+39 -39
View File
@@ -1,39 +1,39 @@
var/list/_robot_default_emotes = list(
/decl/emote/audible/clap,
/decl/emote/visible/bow,
/decl/emote/visible/salute,
/decl/emote/visible/flap,
/decl/emote/visible/aflap,
/decl/emote/visible/twitch,
/decl/emote/visible/twitch_v,
/decl/emote/visible/dance,
/decl/emote/visible/nod,
/decl/emote/visible/shake,
/decl/emote/visible/glare,
/decl/emote/visible/look,
/decl/emote/visible/stare,
/decl/emote/visible/deathgasp_robot,
/decl/emote/visible/spin,
/decl/emote/visible/sidestep,
/decl/emote/audible/synth,
/decl/emote/audible/synth/beep,
/decl/emote/audible/synth/bing,
/decl/emote/audible/synth/buzz,
/decl/emote/audible/synth/confirm,
/decl/emote/audible/synth/deny,
/decl/emote/audible/synth/scary,
/decl/emote/audible/synth/dwoop,
/decl/emote/audible/synth/boop,
/decl/emote/audible/synth/robochirp,
/decl/emote/audible/synth/security,
/decl/emote/audible/synth/security/halt,
//VOREStation Add
/decl/emote/visible/mlem,
/decl/emote/visible/blep
//VOREStation Add End
)
/mob/living/silicon/robot/get_available_emotes()
var/list/fulllist = global._robot_default_emotes.Copy()
fulllist |= _human_default_emotes
return fulllist
var/list/_robot_default_emotes = list(
/decl/emote/audible/clap,
/decl/emote/visible/bow,
/decl/emote/visible/salute,
/decl/emote/visible/flap,
/decl/emote/visible/aflap,
/decl/emote/visible/twitch,
/decl/emote/visible/twitch_v,
/decl/emote/visible/dance,
/decl/emote/visible/nod,
/decl/emote/visible/shake,
/decl/emote/visible/glare,
/decl/emote/visible/look,
/decl/emote/visible/stare,
/decl/emote/visible/deathgasp_robot,
/decl/emote/visible/spin,
/decl/emote/visible/sidestep,
/decl/emote/audible/synth,
/decl/emote/audible/synth/beep,
/decl/emote/audible/synth/bing,
/decl/emote/audible/synth/buzz,
/decl/emote/audible/synth/confirm,
/decl/emote/audible/synth/deny,
/decl/emote/audible/synth/scary,
/decl/emote/audible/synth/dwoop,
/decl/emote/audible/synth/boop,
/decl/emote/audible/synth/robochirp,
/decl/emote/audible/synth/security,
/decl/emote/audible/synth/security/halt,
//VOREStation Add
/decl/emote/visible/mlem,
/decl/emote/visible/blep
//VOREStation Add End
)
/mob/living/silicon/robot/get_available_emotes()
var/list/fulllist = global._robot_default_emotes.Copy()
fulllist |= _human_default_emotes
return fulllist
@@ -1,46 +1,46 @@
/mob/living/silicon/robot/examine(mob/user)
var/custom_infix = custom_name ? ", [modtype][sprite_type ? " [sprite_type]" : ""] [braintype]" : ""
. = ..(user, infix = custom_infix)
if (src.getBruteLoss())
if (src.getBruteLoss() < 75)
. += "<span class='warning'>It looks slightly dented.</span>"
else
. += "<span class='warning'><B>It looks severely dented!</B></span>"
if (src.getFireLoss())
if (src.getFireLoss() < 75)
. += "<span class='warning'>It looks slightly charred.</span>"
else
. += "<span class='warning'><B>It looks severely burnt and heat-warped!</B></span>"
if(opened)
. += "<span class='warning'>Its cover is open and the power cell is [cell ? "installed" : "missing"].</span>"
else
. += "Its cover is closed."
if(!has_power)
. += "<span class='warning'>It appears to be running on backup power.</span>"
switch(src.stat)
if(CONSCIOUS)
if(shell)
. += "It appears to be an [deployed ? "active" : "empty"] AI shell."
else if(!src.client)
. += "It appears to be in stand-by mode." //afk
if(UNCONSCIOUS) . += "<span class='warning'>It doesn't seem to be responding.</span>"
if(DEAD) . += "<span class='deadsay'>It looks completely unsalvageable.</span>"
// VOREStation Edit: Start
. += attempt_vr(src,"examine_bellies_borg",args) //VOREStation Edit
// VOREStation Edit: End
. += "*---------*"
if(print_flavor_text()) . += "<br>[print_flavor_text()]"
if (pose)
if(!findtext(pose, regex("\[.?!]$"))) // Will be zero if the last character is not a member of [.?!]
pose = addtext(pose,".") //Makes sure all emotes end with a period.
. += "<br>It is [pose]" //Extra <br> intentional
user.showLaws(src)
/mob/living/silicon/robot/examine(mob/user)
var/custom_infix = custom_name ? ", [modtype][sprite_type ? " [sprite_type]" : ""] [braintype]" : ""
. = ..(user, infix = custom_infix)
if (src.getBruteLoss())
if (src.getBruteLoss() < 75)
. += "<span class='warning'>It looks slightly dented.</span>"
else
. += "<span class='warning'><B>It looks severely dented!</B></span>"
if (src.getFireLoss())
if (src.getFireLoss() < 75)
. += "<span class='warning'>It looks slightly charred.</span>"
else
. += "<span class='warning'><B>It looks severely burnt and heat-warped!</B></span>"
if(opened)
. += "<span class='warning'>Its cover is open and the power cell is [cell ? "installed" : "missing"].</span>"
else
. += "Its cover is closed."
if(!has_power)
. += "<span class='warning'>It appears to be running on backup power.</span>"
switch(src.stat)
if(CONSCIOUS)
if(shell)
. += "It appears to be an [deployed ? "active" : "empty"] AI shell."
else if(!src.client)
. += "It appears to be in stand-by mode." //afk
if(UNCONSCIOUS) . += "<span class='warning'>It doesn't seem to be responding.</span>"
if(DEAD) . += "<span class='deadsay'>It looks completely unsalvageable.</span>"
// VOREStation Edit: Start
. += attempt_vr(src,"examine_bellies_borg",args) //VOREStation Edit
// VOREStation Edit: End
. += "*---------*"
if(print_flavor_text()) . += "<br>[print_flavor_text()]"
if (pose)
if(!findtext(pose, regex("\[.?!]$"))) // Will be zero if the last character is not a member of [.?!]
pose = addtext(pose,".") //Makes sure all emotes end with a period.
. += "<br>It is [pose]" //Extra <br> intentional
user.showLaws(src)
+273 -273
View File
@@ -1,274 +1,274 @@
//These procs handle putting s tuff in your hand. It's probably best to use these rather than setting stuff manually
//as they handle all relevant stuff like adding it to the player's screen and such
//Returns the thing in our active hand (whatever is in our active module-slot, in this case)
/mob/living/silicon/robot/get_active_hand()
return module_active
/*-------TODOOOOOOOOOO--------*/
//Verbs used by hotkeys.
/mob/living/silicon/robot/verb/cmd_unequip_module()
set name = "unequip-module"
set hidden = 1
uneq_active()
/mob/living/silicon/robot/verb/cmd_toggle_module(module as num)
set name = "toggle-module"
set hidden = 1
toggle_module(module)
/mob/living/silicon/robot/proc/uneq_active()
if(isnull(module_active))
return
if(module_state_1 == module_active)
if(istype(module_state_1,/obj/item/borg/sight))
sight_mode &= ~module_state_1:sight_mode
if (client)
client.screen -= module_state_1
contents -= module_state_1
module_active = null
module_state_1:loc = module //So it can be used again later
module_state_1 = null
inv1.icon_state = "inv1"
else if(module_state_2 == module_active)
if(istype(module_state_2,/obj/item/borg/sight))
sight_mode &= ~module_state_2:sight_mode
if (client)
client.screen -= module_state_2
contents -= module_state_2
module_active = null
module_state_2:loc = module
module_state_2 = null
inv2.icon_state = "inv2"
else if(module_state_3 == module_active)
if(istype(module_state_3,/obj/item/borg/sight))
sight_mode &= ~module_state_3:sight_mode
if (client)
client.screen -= module_state_3
contents -= module_state_3
module_active = null
module_state_3:loc = module
module_state_3 = null
inv3.icon_state = "inv3"
update_icon()
hud_used.update_robot_modules_display()
/mob/living/silicon/robot/proc/uneq_all()
module_active = null
if(module_state_1)
if(istype(module_state_1,/obj/item/borg/sight))
sight_mode &= ~module_state_1:sight_mode
if (client)
client.screen -= module_state_1
contents -= module_state_1
module_state_1:loc = module
module_state_1 = null
inv1.icon_state = "inv1"
if(module_state_2)
if(istype(module_state_2,/obj/item/borg/sight))
sight_mode &= ~module_state_2:sight_mode
if (client)
client.screen -= module_state_2
contents -= module_state_2
module_state_2:loc = module
module_state_2 = null
inv2.icon_state = "inv2"
if(module_state_3)
if(istype(module_state_3,/obj/item/borg/sight))
sight_mode &= ~module_state_3:sight_mode
if (client)
client.screen -= module_state_3
contents -= module_state_3
module_state_3:loc = module
module_state_3 = null
inv3.icon_state = "inv3"
update_icon()
/mob/living/silicon/robot/proc/activated(obj/item/O)
if(module_state_1 == O)
return 1
else if(module_state_2 == O)
return 1
else if(module_state_3 == O)
return 1
else
return 0
// This one takes an object's type instead of an instance, as above.
/mob/living/silicon/robot/proc/has_active_type(var/type_to_compare)
var/list/active_modules = list(module_state_1, module_state_2, module_state_3)
if(is_path_in_list(type_to_compare, active_modules))
return TRUE
return FALSE
//Helper procs for cyborg modules on the UI.
//These are hackish but they help clean up code elsewhere.
//module_selected(module) - Checks whether the module slot specified by "module" is currently selected.
/mob/living/silicon/robot/proc/module_selected(var/module) //Module is 1-3
return module == get_selected_module()
//module_active(module) - Checks whether there is a module active in the slot specified by "module".
/mob/living/silicon/robot/proc/module_active(var/module) //Module is 1-3
if(module < 1 || module > 3) return 0
switch(module)
if(1)
if(module_state_1)
return 1
if(2)
if(module_state_2)
return 1
if(3)
if(module_state_3)
return 1
return 0
//get_selected_module() - Returns the slot number of the currently selected module. Returns 0 if no modules are selected.
/mob/living/silicon/robot/proc/get_selected_module()
if(module_state_1 && module_active == module_state_1)
return 1
else if(module_state_2 && module_active == module_state_2)
return 2
else if(module_state_3 && module_active == module_state_3)
return 3
return 0
//select_module(module) - Selects the module slot specified by "module"
/mob/living/silicon/robot/proc/select_module(var/module) //Module is 1-3
if(module < 1 || module > 3) return
if(!module_active(module)) return
switch(module)
if(1)
if(module_active != module_state_1)
inv1.icon_state = "inv1 +a"
inv2.icon_state = "inv2"
inv3.icon_state = "inv3"
module_active = module_state_1
return
if(2)
if(module_active != module_state_2)
inv1.icon_state = "inv1"
inv2.icon_state = "inv2 +a"
inv3.icon_state = "inv3"
module_active = module_state_2
return
if(3)
if(module_active != module_state_3)
inv1.icon_state = "inv1"
inv2.icon_state = "inv2"
inv3.icon_state = "inv3 +a"
module_active = module_state_3
return
return
//deselect_module(module) - Deselects the module slot specified by "module"
/mob/living/silicon/robot/proc/deselect_module(var/module) //Module is 1-3
if(module < 1 || module > 3) return
switch(module)
if(1)
if(module_active == module_state_1)
inv1.icon_state = "inv1"
module_active = null
return
if(2)
if(module_active == module_state_2)
inv2.icon_state = "inv2"
module_active = null
return
if(3)
if(module_active == module_state_3)
inv3.icon_state = "inv3"
module_active = null
return
return
//toggle_module(module) - Toggles the selection of the module slot specified by "module".
/mob/living/silicon/robot/proc/toggle_module(var/module) //Module is 1-3
if(module < 1 || module > 3) return
if(module_selected(module))
deselect_module(module)
else
if(module_active(module))
select_module(module)
else
deselect_module(get_selected_module()) //If we can't do select anything, at least deselect the current module.
return
//cycle_modules() - Cycles through the list of selected modules.
/mob/living/silicon/robot/proc/cycle_modules()
var/slot_start = get_selected_module()
if(slot_start) deselect_module(slot_start) //Only deselect if we have a selected slot.
var/slot_num
if(slot_start == 0)
slot_num = 1
slot_start = 2
else
slot_num = slot_start + 1
while(slot_start != slot_num) //If we wrap around without finding any free slots, just give up.
if(module_active(slot_num))
select_module(slot_num)
return
slot_num++
if(slot_num > 3) slot_num = 1 //Wrap around.
return
/mob/living/silicon/robot/proc/activate_module(var/obj/item/O)
if(!(locate(O) in src.module.modules) && !(locate(O) in src.module.emag))
return
if(activated(O))
to_chat(src, "<span class='notice'>Already activated</span>")
return
if(!module_state_1)
module_state_1 = O
O.hud_layerise()
O.screen_loc = inv1.screen_loc
contents += O
if(istype(module_state_1,/obj/item/borg/sight))
sight_mode |= module_state_1:sight_mode
else if(!module_state_2)
module_state_2 = O
O.hud_layerise()
O.screen_loc = inv2.screen_loc
contents += O
if(istype(module_state_2,/obj/item/borg/sight))
sight_mode |= module_state_2:sight_mode
else if(!module_state_3)
module_state_3 = O
O.hud_layerise()
O.screen_loc = inv3.screen_loc
contents += O
if(istype(module_state_3,/obj/item/borg/sight))
sight_mode |= module_state_3:sight_mode
else
to_chat(src, "<span class='notice'>You need to disable a module first!</span>")
/mob/living/silicon/robot/put_in_hands(var/obj/item/W) // No hands.
W.loc = get_turf(src)
return 1
/mob/living/silicon/robot/is_holding_item_of_type(typepath)
for(var/obj/item/I in list(module_state_1, module_state_2, module_state_3))
if(istype(I, typepath))
return I
return FALSE
// Returns a list of all held items in a borg's 'hands'.
/mob/living/silicon/robot/get_all_held_items()
. = list()
if(module_state_1)
. += module_state_1
if(module_state_2)
. += module_state_2
if(module_state_3)
//These procs handle putting s tuff in your hand. It's probably best to use these rather than setting stuff manually
//as they handle all relevant stuff like adding it to the player's screen and such
//Returns the thing in our active hand (whatever is in our active module-slot, in this case)
/mob/living/silicon/robot/get_active_hand()
return module_active
/*-------TODOOOOOOOOOO--------*/
//Verbs used by hotkeys.
/mob/living/silicon/robot/verb/cmd_unequip_module()
set name = "unequip-module"
set hidden = 1
uneq_active()
/mob/living/silicon/robot/verb/cmd_toggle_module(module as num)
set name = "toggle-module"
set hidden = 1
toggle_module(module)
/mob/living/silicon/robot/proc/uneq_active()
if(isnull(module_active))
return
if(module_state_1 == module_active)
if(istype(module_state_1,/obj/item/borg/sight))
sight_mode &= ~module_state_1:sight_mode
if (client)
client.screen -= module_state_1
contents -= module_state_1
module_active = null
module_state_1:loc = module //So it can be used again later
module_state_1 = null
inv1.icon_state = "inv1"
else if(module_state_2 == module_active)
if(istype(module_state_2,/obj/item/borg/sight))
sight_mode &= ~module_state_2:sight_mode
if (client)
client.screen -= module_state_2
contents -= module_state_2
module_active = null
module_state_2:loc = module
module_state_2 = null
inv2.icon_state = "inv2"
else if(module_state_3 == module_active)
if(istype(module_state_3,/obj/item/borg/sight))
sight_mode &= ~module_state_3:sight_mode
if (client)
client.screen -= module_state_3
contents -= module_state_3
module_active = null
module_state_3:loc = module
module_state_3 = null
inv3.icon_state = "inv3"
update_icon()
hud_used.update_robot_modules_display()
/mob/living/silicon/robot/proc/uneq_all()
module_active = null
if(module_state_1)
if(istype(module_state_1,/obj/item/borg/sight))
sight_mode &= ~module_state_1:sight_mode
if (client)
client.screen -= module_state_1
contents -= module_state_1
module_state_1:loc = module
module_state_1 = null
inv1.icon_state = "inv1"
if(module_state_2)
if(istype(module_state_2,/obj/item/borg/sight))
sight_mode &= ~module_state_2:sight_mode
if (client)
client.screen -= module_state_2
contents -= module_state_2
module_state_2:loc = module
module_state_2 = null
inv2.icon_state = "inv2"
if(module_state_3)
if(istype(module_state_3,/obj/item/borg/sight))
sight_mode &= ~module_state_3:sight_mode
if (client)
client.screen -= module_state_3
contents -= module_state_3
module_state_3:loc = module
module_state_3 = null
inv3.icon_state = "inv3"
update_icon()
/mob/living/silicon/robot/proc/activated(obj/item/O)
if(module_state_1 == O)
return 1
else if(module_state_2 == O)
return 1
else if(module_state_3 == O)
return 1
else
return 0
// This one takes an object's type instead of an instance, as above.
/mob/living/silicon/robot/proc/has_active_type(var/type_to_compare)
var/list/active_modules = list(module_state_1, module_state_2, module_state_3)
if(is_path_in_list(type_to_compare, active_modules))
return TRUE
return FALSE
//Helper procs for cyborg modules on the UI.
//These are hackish but they help clean up code elsewhere.
//module_selected(module) - Checks whether the module slot specified by "module" is currently selected.
/mob/living/silicon/robot/proc/module_selected(var/module) //Module is 1-3
return module == get_selected_module()
//module_active(module) - Checks whether there is a module active in the slot specified by "module".
/mob/living/silicon/robot/proc/module_active(var/module) //Module is 1-3
if(module < 1 || module > 3) return 0
switch(module)
if(1)
if(module_state_1)
return 1
if(2)
if(module_state_2)
return 1
if(3)
if(module_state_3)
return 1
return 0
//get_selected_module() - Returns the slot number of the currently selected module. Returns 0 if no modules are selected.
/mob/living/silicon/robot/proc/get_selected_module()
if(module_state_1 && module_active == module_state_1)
return 1
else if(module_state_2 && module_active == module_state_2)
return 2
else if(module_state_3 && module_active == module_state_3)
return 3
return 0
//select_module(module) - Selects the module slot specified by "module"
/mob/living/silicon/robot/proc/select_module(var/module) //Module is 1-3
if(module < 1 || module > 3) return
if(!module_active(module)) return
switch(module)
if(1)
if(module_active != module_state_1)
inv1.icon_state = "inv1 +a"
inv2.icon_state = "inv2"
inv3.icon_state = "inv3"
module_active = module_state_1
return
if(2)
if(module_active != module_state_2)
inv1.icon_state = "inv1"
inv2.icon_state = "inv2 +a"
inv3.icon_state = "inv3"
module_active = module_state_2
return
if(3)
if(module_active != module_state_3)
inv1.icon_state = "inv1"
inv2.icon_state = "inv2"
inv3.icon_state = "inv3 +a"
module_active = module_state_3
return
return
//deselect_module(module) - Deselects the module slot specified by "module"
/mob/living/silicon/robot/proc/deselect_module(var/module) //Module is 1-3
if(module < 1 || module > 3) return
switch(module)
if(1)
if(module_active == module_state_1)
inv1.icon_state = "inv1"
module_active = null
return
if(2)
if(module_active == module_state_2)
inv2.icon_state = "inv2"
module_active = null
return
if(3)
if(module_active == module_state_3)
inv3.icon_state = "inv3"
module_active = null
return
return
//toggle_module(module) - Toggles the selection of the module slot specified by "module".
/mob/living/silicon/robot/proc/toggle_module(var/module) //Module is 1-3
if(module < 1 || module > 3) return
if(module_selected(module))
deselect_module(module)
else
if(module_active(module))
select_module(module)
else
deselect_module(get_selected_module()) //If we can't do select anything, at least deselect the current module.
return
//cycle_modules() - Cycles through the list of selected modules.
/mob/living/silicon/robot/proc/cycle_modules()
var/slot_start = get_selected_module()
if(slot_start) deselect_module(slot_start) //Only deselect if we have a selected slot.
var/slot_num
if(slot_start == 0)
slot_num = 1
slot_start = 2
else
slot_num = slot_start + 1
while(slot_start != slot_num) //If we wrap around without finding any free slots, just give up.
if(module_active(slot_num))
select_module(slot_num)
return
slot_num++
if(slot_num > 3) slot_num = 1 //Wrap around.
return
/mob/living/silicon/robot/proc/activate_module(var/obj/item/O)
if(!(locate(O) in src.module.modules) && !(locate(O) in src.module.emag))
return
if(activated(O))
to_chat(src, "<span class='notice'>Already activated</span>")
return
if(!module_state_1)
module_state_1 = O
O.hud_layerise()
O.screen_loc = inv1.screen_loc
contents += O
if(istype(module_state_1,/obj/item/borg/sight))
sight_mode |= module_state_1:sight_mode
else if(!module_state_2)
module_state_2 = O
O.hud_layerise()
O.screen_loc = inv2.screen_loc
contents += O
if(istype(module_state_2,/obj/item/borg/sight))
sight_mode |= module_state_2:sight_mode
else if(!module_state_3)
module_state_3 = O
O.hud_layerise()
O.screen_loc = inv3.screen_loc
contents += O
if(istype(module_state_3,/obj/item/borg/sight))
sight_mode |= module_state_3:sight_mode
else
to_chat(src, "<span class='notice'>You need to disable a module first!</span>")
/mob/living/silicon/robot/put_in_hands(var/obj/item/W) // No hands.
W.loc = get_turf(src)
return 1
/mob/living/silicon/robot/is_holding_item_of_type(typepath)
for(var/obj/item/I in list(module_state_1, module_state_2, module_state_3))
if(istype(I, typepath))
return I
return FALSE
// Returns a list of all held items in a borg's 'hands'.
/mob/living/silicon/robot/get_all_held_items()
. = list()
if(module_state_1)
. += module_state_1
if(module_state_2)
. += module_state_2
if(module_state_3)
. += module_state_3
+56 -56
View File
@@ -1,56 +1,56 @@
/mob/living/silicon/robot/verb/cmd_show_laws()
set category = "Robot Commands"
set name = "Show Laws"
show_laws()
/mob/living/silicon/robot/show_laws(var/everyone = 0)
laws_sanity_check()
var/who
if (everyone)
who = world
else
who = src
if(lawupdate)
if (connected_ai)
if(connected_ai.stat || connected_ai.control_disabled)
to_chat(src, "<b>AI signal lost, unable to sync laws.</b>")
else
lawsync()
photosync()
to_chat(src, "<b>Laws synced with AI, be sure to note any changes.</b>")
// TODO: Update to new antagonist system.
if(mind && mind.special_role == "traitor" && mind.original == src)
to_chat(src, "<b>Remember, your AI does NOT share or know about your law 0.</b>")
else
to_chat(src, "<b>No AI selected to sync laws with, disabling lawsync protocol.</b>")
lawupdate = FALSE
to_chat(who, "<b>Obey these laws:</b>")
laws.show_laws(who)
if(shell) //AI shell
to_chat(who, "<b>Remember, you are an AI remotely controlling your shell, other AIs can be ignored.</b>")
// TODO: Update to new antagonist system.
else if(mind && (mind.special_role == "traitor" && mind.original == src) && connected_ai)
to_chat(who, "<b>Remember, [connected_ai.name] is technically your master, but your objective comes first.</b>")
else if(connected_ai)
to_chat(who, "<b>Remember, [connected_ai.name] is your master, other AIs can be ignored.</b>")
else if(emagged)
to_chat(who, "<b>Remember, you are not required to listen to the AI.</b>")
else
to_chat(who, "<b>Remember, you are not bound to any AI, you are not required to listen to them.</b>")
/mob/living/silicon/robot/lawsync()
laws_sanity_check()
var/datum/ai_laws/master = connected_ai && lawupdate ? connected_ai.laws : null
if (master)
master.sync(src)
..()
return
/mob/living/silicon/robot/proc/robot_checklaws()
set category = "Robot Commands"
set name = "State Laws"
subsystem_law_manager()
/mob/living/silicon/robot/verb/cmd_show_laws()
set category = "Robot Commands"
set name = "Show Laws"
show_laws()
/mob/living/silicon/robot/show_laws(var/everyone = 0)
laws_sanity_check()
var/who
if (everyone)
who = world
else
who = src
if(lawupdate)
if (connected_ai)
if(connected_ai.stat || connected_ai.control_disabled)
to_chat(src, "<b>AI signal lost, unable to sync laws.</b>")
else
lawsync()
photosync()
to_chat(src, "<b>Laws synced with AI, be sure to note any changes.</b>")
// TODO: Update to new antagonist system.
if(mind && mind.special_role == "traitor" && mind.original == src)
to_chat(src, "<b>Remember, your AI does NOT share or know about your law 0.</b>")
else
to_chat(src, "<b>No AI selected to sync laws with, disabling lawsync protocol.</b>")
lawupdate = FALSE
to_chat(who, "<b>Obey these laws:</b>")
laws.show_laws(who)
if(shell) //AI shell
to_chat(who, "<b>Remember, you are an AI remotely controlling your shell, other AIs can be ignored.</b>")
// TODO: Update to new antagonist system.
else if(mind && (mind.special_role == "traitor" && mind.original == src) && connected_ai)
to_chat(who, "<b>Remember, [connected_ai.name] is technically your master, but your objective comes first.</b>")
else if(connected_ai)
to_chat(who, "<b>Remember, [connected_ai.name] is your master, other AIs can be ignored.</b>")
else if(emagged)
to_chat(who, "<b>Remember, you are not required to listen to the AI.</b>")
else
to_chat(who, "<b>Remember, you are not bound to any AI, you are not required to listen to them.</b>")
/mob/living/silicon/robot/lawsync()
laws_sanity_check()
var/datum/ai_laws/master = connected_ai && lawupdate ? connected_ai.laws : null
if (master)
master.sync(src)
..()
return
/mob/living/silicon/robot/proc/robot_checklaws()
set category = "Robot Commands"
set name = "State Laws"
subsystem_law_manager()
+377 -377
View File
@@ -1,377 +1,377 @@
/mob/living/silicon/robot/Life()
set invisibility = 0
set background = 1
if (src.transforming)
return
src.blinded = null
//Status updates, death etc.
clamp_values()
handle_regular_status_updates()
handle_actions()
handle_instability()
// For some reason borg Life() doesn't call ..()
handle_modifiers()
handle_light()
if(client)
handle_regular_hud_updates()
handle_vision()
update_items()
if (src.stat != DEAD) //still using power
use_power()
process_killswitch()
process_locks()
process_queued_alarms()
update_canmove()
/mob/living/silicon/robot/proc/clamp_values()
// SetStunned(min(stunned, 30))
SetParalysis(min(paralysis, 30))
// SetWeakened(min(weakened, 20))
SetSleeping(0)
adjustBruteLoss(0)
adjustToxLoss(0)
adjustOxyLoss(0)
adjustFireLoss(0)
/mob/living/silicon/robot/proc/use_power()
// Debug only
// to_world("DEBUG: life.dm line 35: cyborg use_power() called at tick [controller_iteration]")
used_power_this_tick = 0
for(var/V in components)
var/datum/robot_component/C = components[V]
C.update_power_state()
if ( cell && is_component_functioning("power cell") && src.cell.charge > 0 )
if(src.module_state_1)
cell_use_power(50) // 50W load for every enabled tool TODO: tool-specific loads
if(src.module_state_2)
cell_use_power(50)
if(src.module_state_3)
cell_use_power(50)
if(lights_on)
cell_use_power(30) // 30W light. Normal lights would use ~15W, but increased for balance reasons.
src.has_power = 1
else
if (src.has_power)
to_chat(src, span_red("You are now running on emergency backup power."))
src.has_power = 0
if(lights_on) // Light is on but there is no power!
lights_on = 0
set_light(0)
/mob/living/silicon/robot/handle_regular_status_updates()
if(src.camera && !scrambledcodes)
if(src.stat == 2 || wires.is_cut(WIRE_BORG_CAMERA))
src.camera.set_status(0)
else
src.camera.set_status(1)
updatehealth()
if(src.sleeping)
Paralyse(3)
AdjustSleeping(-1)
//if(src.resting) // VOREStation edit. Our borgos would rather not.
// Weaken(5)
if(health < config.health_threshold_dead && src.stat != 2) //die only once
death()
if (src.stat != 2) //Alive.
if (src.weakened > 0) // Do not fullstun on weaken
AdjustWeakened(-1)
if (src.paralysis || src.stunned || !src.has_power) //Stunned etc.
src.set_stat(UNCONSCIOUS)
if (src.stunned > 0)
AdjustStunned(-1)
if (src.weakened > 0)
AdjustWeakened(-1)
if (src.paralysis > 0)
AdjustParalysis(-1)
src.blinded = 1
else
src.blinded = 0
else //Not stunned.
src.set_stat(CONSCIOUS)
AdjustConfused(-1)
else //Dead or just unconscious.
src.blinded = 1
if (src.stuttering) src.stuttering--
if (src.eye_blind)
src.AdjustBlinded(-1)
src.blinded = 1
if (src.ear_deaf > 0) src.ear_deaf--
if (src.ear_damage < 25)
src.ear_damage -= 0.05
src.ear_damage = max(src.ear_damage, 0)
src.density = !( src.lying )
if (src.sdisabilities & BLIND)
src.blinded = 1
if (src.sdisabilities & DEAF)
src.ear_deaf = 1
if (src.eye_blurry > 0)
src.eye_blurry--
src.eye_blurry = max(0, src.eye_blurry)
if (src.druggy > 0)
src.druggy--
src.druggy = max(0, src.druggy)
//update the state of modules and components here
if (src.stat != 0)
uneq_all()
if(radio)
if(!is_component_functioning("radio"))
radio.on = 0
else
radio.on = 1
if(is_component_functioning("camera"))
src.blinded = 0
else
src.blinded = 1
return 1
/mob/living/silicon/robot/handle_regular_hud_updates()
var/fullbright = FALSE
var/seemeson = FALSE
var/area/A = get_area(src)
if(A?.no_spoilers)
disable_spoiler_vision()
if (src.stat == DEAD || (XRAY in mutations) || (src.sight_mode & BORGXRAY))
src.sight |= SEE_TURFS
src.sight |= SEE_MOBS
src.sight |= SEE_OBJS
src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_MINIMUM
else if ((src.sight_mode & BORGMESON) && (src.sight_mode & BORGTHERM))
src.sight |= SEE_TURFS
src.sight |= SEE_MOBS
src.see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
fullbright = TRUE
else if (src.sight_mode & BORGMESON)
src.sight |= SEE_TURFS
src.see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
fullbright = TRUE
seemeson = TRUE
else if (src.sight_mode & BORGMATERIAL)
src.sight |= SEE_OBJS
src.see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
fullbright = TRUE
else if (src.sight_mode & BORGTHERM)
src.sight |= SEE_MOBS
src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_LEVEL_TWO
fullbright = TRUE
else if (!seedarkness)
src.sight &= ~SEE_MOBS
src.sight &= ~SEE_TURFS
src.sight &= ~SEE_OBJS
src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_NOLIGHTING
else if (src.stat != DEAD)
src.sight &= ~SEE_MOBS
src.sight &= ~SEE_TURFS
src.sight &= ~SEE_OBJS
src.see_in_dark = 8 // see_in_dark means you can FAINTLY see in the dark, humans have a range of 3 or so, tajaran have it at 8
src.see_invisible = SEE_INVISIBLE_LIVING // This is normal vision (25), setting it lower for normal vision means you don't "see" things like darkness since darkness
// has a "invisible" value of 15
if(plane_holder)
plane_holder.set_vis(VIS_FULLBRIGHT,fullbright)
plane_holder.set_vis(VIS_MESONS,seemeson)
..()
if (src.healths)
if (src.stat != 2)
if(istype(src,/mob/living/silicon/robot/drone))
switch(health)
if(35 to INFINITY)
src.healths.icon_state = "health0"
if(25 to 34)
src.healths.icon_state = "health1"
if(15 to 24)
src.healths.icon_state = "health2"
if(5 to 14)
src.healths.icon_state = "health3"
if(0 to 4)
src.healths.icon_state = "health4"
if(-35 to 0)
src.healths.icon_state = "health5"
else
src.healths.icon_state = "health6"
else
switch(health)
if(200 to INFINITY)
src.healths.icon_state = "health0"
if(150 to 200)
src.healths.icon_state = "health1"
if(100 to 150)
src.healths.icon_state = "health2"
if(50 to 100)
src.healths.icon_state = "health3"
if(0 to 50)
src.healths.icon_state = "health4"
if(config.health_threshold_dead to 0)
src.healths.icon_state = "health5"
else
src.healths.icon_state = "health6"
else
src.healths.icon_state = "health7"
if (src.syndicate && src.client)
for(var/datum/mind/tra in traitors.current_antagonists)
if(tra.current)
// TODO: Update to new antagonist system.
var/I = image('icons/mob/mob.dmi', loc = tra.current, icon_state = "traitor")
src.client.images += I
src.disconnect_from_ai()
if(src.mind)
// TODO: Update to new antagonist system.
if(!src.mind.special_role)
src.mind.special_role = "traitor"
traitors.current_antagonists |= src.mind
update_cell()
var/turf/T = get_turf(src)
var/datum/gas_mixture/environment = T.return_air()
if(environment)
switch(environment.temperature) //310.055 optimal body temp
if(400 to INFINITY)
throw_alert("temp", /obj/screen/alert/hot/robot, HOT_ALERT_SEVERITY_MODERATE)
if(360 to 400)
throw_alert("temp", /obj/screen/alert/hot/robot, HOT_ALERT_SEVERITY_LOW)
if(260 to 360)
clear_alert("temp")
if(200 to 260)
throw_alert("temp", /obj/screen/alert/cold/robot, COLD_ALERT_SEVERITY_LOW)
else
throw_alert("temp", /obj/screen/alert/cold/robot, COLD_ALERT_SEVERITY_MODERATE)
//Oxygen and fire does nothing yet!!
// if (src.oxygen) src.oxygen.icon_state = "oxy[src.oxygen_alert ? 1 : 0]"
// if (src.fire) src.fire.icon_state = "fire[src.fire_alert ? 1 : 0]"
if(stat != 2)
if(blinded)
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else
clear_fullscreen("blind")
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
if (src.machine)
if (src.machine.check_eye(src) < 0)
src.reset_view(null)
else
if(client && !client.adminobs)
reset_view(null)
if(emagged)
throw_alert("hacked", /obj/screen/alert/hacked)
else
clear_alert("hacked")
return 1
/mob/living/silicon/robot/proc/update_cell()
if(cell)
var/cellcharge = cell.charge/cell.maxcharge
switch(cellcharge)
if(0.75 to INFINITY)
clear_alert("charge")
if(0.5 to 0.75)
throw_alert("charge", /obj/screen/alert/lowcell, 1)
if(0.25 to 0.5)
throw_alert("charge", /obj/screen/alert/lowcell, 2)
if(0.01 to 0.25)
throw_alert("charge", /obj/screen/alert/lowcell, 3)
else
throw_alert("charge", /obj/screen/alert/emptycell)
else
throw_alert("charge", /obj/screen/alert/nocell)
/mob/living/silicon/robot/proc/update_items()
if(client)
client.screen -= contents
for(var/obj/I in contents)
if(I && !(istype(I,/obj/item/weapon/cell) || istype(I,/obj/item/device/radio) || istype(I,/obj/machinery/camera) || istype(I,/obj/item/device/mmi)))
client.screen += I
if(module_state_1)
module_state_1:screen_loc = ui_inv1
if(module_state_2)
module_state_2:screen_loc = ui_inv2
if(module_state_3)
module_state_3:screen_loc = ui_inv3
update_icon()
/mob/living/silicon/robot/proc/process_killswitch()
if(killswitch)
killswitch_time --
if(killswitch_time <= 0)
if(src.client)
to_chat(src, "<span class='danger'>Killswitch Activated</span>")
killswitch = 0
spawn(5)
gib()
/mob/living/silicon/robot/proc/process_locks()
if(weapon_lock)
uneq_all()
weaponlock_time --
if(weaponlock_time <= 0)
if(src.client)
to_chat(src, "<span class='danger'>Weapon Lock Timed Out!</span>")
weapon_lock = 0
weaponlock_time = 120
/mob/living/silicon/robot/update_canmove()
..() // Let's not reinvent the wheel.
if(lockdown || !is_component_functioning("actuator"))
canmove = FALSE
return canmove
/mob/living/silicon/robot/update_fire()
cut_overlay(image(icon = 'icons/mob/OnFire.dmi', icon_state = get_fire_icon_state()))
if(on_fire)
add_overlay(image(icon = 'icons/mob/OnFire.dmi', icon_state = get_fire_icon_state()))
/mob/living/silicon/robot/fire_act()
if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
IgniteMob()
/mob/living/silicon/robot/handle_light()
. = ..()
if(. == FALSE) // If no other light sources are on.
if(lights_on)
set_light(integrated_light_power, 1, "#FFFFFF")
return TRUE
/mob/living/silicon/robot/Life()
set invisibility = 0
set background = 1
if (src.transforming)
return
src.blinded = null
//Status updates, death etc.
clamp_values()
handle_regular_status_updates()
handle_actions()
handle_instability()
// For some reason borg Life() doesn't call ..()
handle_modifiers()
handle_light()
if(client)
handle_regular_hud_updates()
handle_vision()
update_items()
if (src.stat != DEAD) //still using power
use_power()
process_killswitch()
process_locks()
process_queued_alarms()
update_canmove()
/mob/living/silicon/robot/proc/clamp_values()
// SetStunned(min(stunned, 30))
SetParalysis(min(paralysis, 30))
// SetWeakened(min(weakened, 20))
SetSleeping(0)
adjustBruteLoss(0)
adjustToxLoss(0)
adjustOxyLoss(0)
adjustFireLoss(0)
/mob/living/silicon/robot/proc/use_power()
// Debug only
// to_world("DEBUG: life.dm line 35: cyborg use_power() called at tick [controller_iteration]")
used_power_this_tick = 0
for(var/V in components)
var/datum/robot_component/C = components[V]
C.update_power_state()
if ( cell && is_component_functioning("power cell") && src.cell.charge > 0 )
if(src.module_state_1)
cell_use_power(50) // 50W load for every enabled tool TODO: tool-specific loads
if(src.module_state_2)
cell_use_power(50)
if(src.module_state_3)
cell_use_power(50)
if(lights_on)
cell_use_power(30) // 30W light. Normal lights would use ~15W, but increased for balance reasons.
src.has_power = 1
else
if (src.has_power)
to_chat(src, span_red("You are now running on emergency backup power."))
src.has_power = 0
if(lights_on) // Light is on but there is no power!
lights_on = 0
set_light(0)
/mob/living/silicon/robot/handle_regular_status_updates()
if(src.camera && !scrambledcodes)
if(src.stat == 2 || wires.is_cut(WIRE_BORG_CAMERA))
src.camera.set_status(0)
else
src.camera.set_status(1)
updatehealth()
if(src.sleeping)
Paralyse(3)
AdjustSleeping(-1)
//if(src.resting) // VOREStation edit. Our borgos would rather not.
// Weaken(5)
if(health < config.health_threshold_dead && src.stat != 2) //die only once
death()
if (src.stat != 2) //Alive.
if (src.weakened > 0) // Do not fullstun on weaken
AdjustWeakened(-1)
if (src.paralysis || src.stunned || !src.has_power) //Stunned etc.
src.set_stat(UNCONSCIOUS)
if (src.stunned > 0)
AdjustStunned(-1)
if (src.weakened > 0)
AdjustWeakened(-1)
if (src.paralysis > 0)
AdjustParalysis(-1)
src.blinded = 1
else
src.blinded = 0
else //Not stunned.
src.set_stat(CONSCIOUS)
AdjustConfused(-1)
else //Dead or just unconscious.
src.blinded = 1
if (src.stuttering) src.stuttering--
if (src.eye_blind)
src.AdjustBlinded(-1)
src.blinded = 1
if (src.ear_deaf > 0) src.ear_deaf--
if (src.ear_damage < 25)
src.ear_damage -= 0.05
src.ear_damage = max(src.ear_damage, 0)
src.density = !( src.lying )
if (src.sdisabilities & BLIND)
src.blinded = 1
if (src.sdisabilities & DEAF)
src.ear_deaf = 1
if (src.eye_blurry > 0)
src.eye_blurry--
src.eye_blurry = max(0, src.eye_blurry)
if (src.druggy > 0)
src.druggy--
src.druggy = max(0, src.druggy)
//update the state of modules and components here
if (src.stat != 0)
uneq_all()
if(radio)
if(!is_component_functioning("radio"))
radio.on = 0
else
radio.on = 1
if(is_component_functioning("camera"))
src.blinded = 0
else
src.blinded = 1
return 1
/mob/living/silicon/robot/handle_regular_hud_updates()
var/fullbright = FALSE
var/seemeson = FALSE
var/area/A = get_area(src)
if(A?.no_spoilers)
disable_spoiler_vision()
if (src.stat == DEAD || (XRAY in mutations) || (src.sight_mode & BORGXRAY))
src.sight |= SEE_TURFS
src.sight |= SEE_MOBS
src.sight |= SEE_OBJS
src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_MINIMUM
else if ((src.sight_mode & BORGMESON) && (src.sight_mode & BORGTHERM))
src.sight |= SEE_TURFS
src.sight |= SEE_MOBS
src.see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
fullbright = TRUE
else if (src.sight_mode & BORGMESON)
src.sight |= SEE_TURFS
src.see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
fullbright = TRUE
seemeson = TRUE
else if (src.sight_mode & BORGMATERIAL)
src.sight |= SEE_OBJS
src.see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
fullbright = TRUE
else if (src.sight_mode & BORGTHERM)
src.sight |= SEE_MOBS
src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_LEVEL_TWO
fullbright = TRUE
else if (!seedarkness)
src.sight &= ~SEE_MOBS
src.sight &= ~SEE_TURFS
src.sight &= ~SEE_OBJS
src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_NOLIGHTING
else if (src.stat != DEAD)
src.sight &= ~SEE_MOBS
src.sight &= ~SEE_TURFS
src.sight &= ~SEE_OBJS
src.see_in_dark = 8 // see_in_dark means you can FAINTLY see in the dark, humans have a range of 3 or so, tajaran have it at 8
src.see_invisible = SEE_INVISIBLE_LIVING // This is normal vision (25), setting it lower for normal vision means you don't "see" things like darkness since darkness
// has a "invisible" value of 15
if(plane_holder)
plane_holder.set_vis(VIS_FULLBRIGHT,fullbright)
plane_holder.set_vis(VIS_MESONS,seemeson)
..()
if (src.healths)
if (src.stat != 2)
if(istype(src,/mob/living/silicon/robot/drone))
switch(health)
if(35 to INFINITY)
src.healths.icon_state = "health0"
if(25 to 34)
src.healths.icon_state = "health1"
if(15 to 24)
src.healths.icon_state = "health2"
if(5 to 14)
src.healths.icon_state = "health3"
if(0 to 4)
src.healths.icon_state = "health4"
if(-35 to 0)
src.healths.icon_state = "health5"
else
src.healths.icon_state = "health6"
else
switch(health)
if(200 to INFINITY)
src.healths.icon_state = "health0"
if(150 to 200)
src.healths.icon_state = "health1"
if(100 to 150)
src.healths.icon_state = "health2"
if(50 to 100)
src.healths.icon_state = "health3"
if(0 to 50)
src.healths.icon_state = "health4"
if(config.health_threshold_dead to 0)
src.healths.icon_state = "health5"
else
src.healths.icon_state = "health6"
else
src.healths.icon_state = "health7"
if (src.syndicate && src.client)
for(var/datum/mind/tra in traitors.current_antagonists)
if(tra.current)
// TODO: Update to new antagonist system.
var/I = image('icons/mob/mob.dmi', loc = tra.current, icon_state = "traitor")
src.client.images += I
src.disconnect_from_ai()
if(src.mind)
// TODO: Update to new antagonist system.
if(!src.mind.special_role)
src.mind.special_role = "traitor"
traitors.current_antagonists |= src.mind
update_cell()
var/turf/T = get_turf(src)
var/datum/gas_mixture/environment = T.return_air()
if(environment)
switch(environment.temperature) //310.055 optimal body temp
if(400 to INFINITY)
throw_alert("temp", /obj/screen/alert/hot/robot, HOT_ALERT_SEVERITY_MODERATE)
if(360 to 400)
throw_alert("temp", /obj/screen/alert/hot/robot, HOT_ALERT_SEVERITY_LOW)
if(260 to 360)
clear_alert("temp")
if(200 to 260)
throw_alert("temp", /obj/screen/alert/cold/robot, COLD_ALERT_SEVERITY_LOW)
else
throw_alert("temp", /obj/screen/alert/cold/robot, COLD_ALERT_SEVERITY_MODERATE)
//Oxygen and fire does nothing yet!!
// if (src.oxygen) src.oxygen.icon_state = "oxy[src.oxygen_alert ? 1 : 0]"
// if (src.fire) src.fire.icon_state = "fire[src.fire_alert ? 1 : 0]"
if(stat != 2)
if(blinded)
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else
clear_fullscreen("blind")
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
if (src.machine)
if (src.machine.check_eye(src) < 0)
src.reset_view(null)
else
if(client && !client.adminobs)
reset_view(null)
if(emagged)
throw_alert("hacked", /obj/screen/alert/hacked)
else
clear_alert("hacked")
return 1
/mob/living/silicon/robot/proc/update_cell()
if(cell)
var/cellcharge = cell.charge/cell.maxcharge
switch(cellcharge)
if(0.75 to INFINITY)
clear_alert("charge")
if(0.5 to 0.75)
throw_alert("charge", /obj/screen/alert/lowcell, 1)
if(0.25 to 0.5)
throw_alert("charge", /obj/screen/alert/lowcell, 2)
if(0.01 to 0.25)
throw_alert("charge", /obj/screen/alert/lowcell, 3)
else
throw_alert("charge", /obj/screen/alert/emptycell)
else
throw_alert("charge", /obj/screen/alert/nocell)
/mob/living/silicon/robot/proc/update_items()
if(client)
client.screen -= contents
for(var/obj/I in contents)
if(I && !(istype(I,/obj/item/weapon/cell) || istype(I,/obj/item/device/radio) || istype(I,/obj/machinery/camera) || istype(I,/obj/item/device/mmi)))
client.screen += I
if(module_state_1)
module_state_1:screen_loc = ui_inv1
if(module_state_2)
module_state_2:screen_loc = ui_inv2
if(module_state_3)
module_state_3:screen_loc = ui_inv3
update_icon()
/mob/living/silicon/robot/proc/process_killswitch()
if(killswitch)
killswitch_time --
if(killswitch_time <= 0)
if(src.client)
to_chat(src, "<span class='danger'>Killswitch Activated</span>")
killswitch = 0
spawn(5)
gib()
/mob/living/silicon/robot/proc/process_locks()
if(weapon_lock)
uneq_all()
weaponlock_time --
if(weaponlock_time <= 0)
if(src.client)
to_chat(src, "<span class='danger'>Weapon Lock Timed Out!</span>")
weapon_lock = 0
weaponlock_time = 120
/mob/living/silicon/robot/update_canmove()
..() // Let's not reinvent the wheel.
if(lockdown || !is_component_functioning("actuator"))
canmove = FALSE
return canmove
/mob/living/silicon/robot/update_fire()
cut_overlay(image(icon = 'icons/mob/OnFire.dmi', icon_state = get_fire_icon_state()))
if(on_fire)
add_overlay(image(icon = 'icons/mob/OnFire.dmi', icon_state = get_fire_icon_state()))
/mob/living/silicon/robot/fire_act()
if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
IgniteMob()
/mob/living/silicon/robot/handle_light()
. = ..()
if(. == FALSE) // If no other light sources are on.
if(lights_on)
set_light(integrated_light_power, 1, "#FFFFFF")
return TRUE
+18 -18
View File
@@ -1,19 +1,19 @@
/mob/living/silicon/robot/Login()
..()
regenerate_icons()
update_hud()
show_laws(0)
// Override the DreamSeeker macro with the borg version!
client.set_hotkeys_macro("borgmacro", "borghotkeymode")
// Forces synths to select an icon relevant to their module
if(!icon_selected)
icon_selection_tries = SSrobot_sprites.get_module_sprites_len(modtype, src) + 1
choose_icon(icon_selection_tries)
if(sprite_datum && module)
sprite_datum.do_equipment_glamour(module)
/mob/living/silicon/robot/Login()
..()
regenerate_icons()
update_hud()
show_laws(0)
// Override the DreamSeeker macro with the borg version!
client.set_hotkeys_macro("borgmacro", "borghotkeymode")
// Forces synths to select an icon relevant to their module
if(!icon_selected)
icon_selection_tries = SSrobot_sprites.get_module_sprites_len(modtype, src) + 1
choose_icon(icon_selection_tries)
if(sprite_datum && module)
sprite_datum.do_equipment_glamour(module)
plane_holder.set_vis(VIS_AUGMENTED, TRUE)
+20 -20
View File
@@ -1,20 +1,20 @@
/mob/living/silicon/robot/proc/photosync()
var/obj/item/device/camera/siliconcam/master_cam = connected_ai ? connected_ai.aiCamera : null
if (!master_cam)
return
var/synced = 0
// Sync borg images to the master AI.
// We don't care about syncing the other way around
for(var/obj/item/weapon/photo/borg_photo in aiCamera.aipictures)
var/copied = 0
for(var/obj/item/weapon/photo/ai_photo in master_cam.aipictures)
if(borg_photo.id == ai_photo.id)
copied = 1
break
if(!copied)
master_cam.injectaialbum(borg_photo.copy(1), " (synced from [name])")
synced = 1
if(synced)
to_chat(src, "<span class='notice'>Images synced with AI. Local images will be retained in the case of loss of connection with the AI.</span>")
/mob/living/silicon/robot/proc/photosync()
var/obj/item/device/camera/siliconcam/master_cam = connected_ai ? connected_ai.aiCamera : null
if (!master_cam)
return
var/synced = 0
// Sync borg images to the master AI.
// We don't care about syncing the other way around
for(var/obj/item/weapon/photo/borg_photo in aiCamera.aipictures)
var/copied = 0
for(var/obj/item/weapon/photo/ai_photo in master_cam.aipictures)
if(borg_photo.id == ai_photo.id)
copied = 1
break
if(!copied)
master_cam.injectaialbum(borg_photo.copy(1), " (synced from [name])")
synced = 1
if(synced)
to_chat(src, "<span class='notice'>Images synced with AI. Local images will be retained in the case of loss of connection with the AI.</span>")
File diff suppressed because it is too large Load Diff
@@ -1,155 +1,155 @@
/mob/living/silicon/robot/updatehealth()
if(status_flags & GODMODE)
health = getMaxHealth()
set_stat(CONSCIOUS)
return
health = getMaxHealth() - (getBruteLoss() + getFireLoss())
return
/mob/living/silicon/robot/getBruteLoss()
var/amount = 0
for(var/V in components)
var/datum/robot_component/C = components[V]
if(C.installed != 0) amount += C.brute_damage
return amount
/mob/living/silicon/robot/getFireLoss()
var/amount = 0
for(var/V in components)
var/datum/robot_component/C = components[V]
if(C.installed != 0) amount += C.electronics_damage
return amount
/mob/living/silicon/robot/adjustBruteLoss(var/amount,var/include_robo)
if(amount > 0)
take_overall_damage(amount, 0)
else
heal_overall_damage(-amount, 0)
/mob/living/silicon/robot/adjustFireLoss(var/amount,var/include_robo)
if(amount > 0)
take_overall_damage(0, amount)
else
heal_overall_damage(0, -amount)
/mob/living/silicon/robot/proc/get_damaged_components(var/brute, var/burn, var/destroyed = 0)
var/list/datum/robot_component/parts = list()
for(var/V in components)
var/datum/robot_component/C = components[V]
if(C.installed == 1 || (C.installed == -1 && destroyed))
if((brute && C.brute_damage) || (burn && C.electronics_damage) || (!C.toggled) || (!C.powered && C.toggled))
parts += C
return parts
/mob/living/silicon/robot/proc/get_damageable_components()
var/list/rval = new
for(var/V in components)
var/datum/robot_component/C = components[V]
if(C.installed == 1) rval += C
return rval
/mob/living/silicon/robot/proc/get_armour()
if(!components.len) return 0
var/datum/robot_component/C = components["armour"]
if(C && C.installed == 1)
return C
return 0
/mob/living/silicon/robot/heal_organ_damage(var/brute, var/burn)
var/list/datum/robot_component/parts = get_damaged_components(brute,burn)
if(!parts.len) return
var/datum/robot_component/picked = pick(parts)
picked.heal_damage(brute,burn)
/mob/living/silicon/robot/take_organ_damage(var/brute = 0, var/burn = 0, var/sharp = FALSE, var/edge = FALSE, var/emp = 0)
var/list/components = get_damageable_components()
if(!components.len)
return
//Combat shielding absorbs a percentage of damage directly into the cell.
if(has_active_type(/obj/item/borg/combat/shield))
var/obj/item/borg/combat/shield/shield = locate() in src
if(shield && shield.active)
//Shields absorb a certain percentage of damage based on their power setting.
var/absorb_brute = brute*shield.shield_level
var/absorb_burn = burn*shield.shield_level
var/cost = (absorb_brute+absorb_burn) * 25
cell.charge -= cost
if(cell.charge <= 0)
cell.charge = 0
to_chat(src, "<span class='filter_warning'>[span_red("Your shield has overloaded!")]</span>")
else
brute -= absorb_brute
burn -= absorb_burn
to_chat(src, "<span class='filter_combat'>[span_red("Your shield absorbs some of the impact!")]</span>")
if(!emp)
var/datum/robot_component/armour/A = get_armour()
if(A)
A.take_damage(brute,burn,sharp,edge)
return
var/datum/robot_component/C = pick(components)
C.take_damage(brute,burn,sharp,edge)
/mob/living/silicon/robot/heal_overall_damage(var/brute, var/burn)
var/list/datum/robot_component/parts = get_damaged_components(brute,burn)
while(parts.len && (brute>0 || burn>0) )
var/datum/robot_component/picked = pick(parts)
var/brute_was = picked.brute_damage
var/burn_was = picked.electronics_damage
picked.heal_damage(brute,burn)
brute -= (brute_was-picked.brute_damage)
burn -= (burn_was-picked.electronics_damage)
parts -= picked
/mob/living/silicon/robot/take_overall_damage(var/brute = 0, var/burn = 0, var/sharp = FALSE, var/used_weapon = null)
if(status_flags & GODMODE) return //godmode
var/list/datum/robot_component/parts = get_damageable_components()
//Combat shielding absorbs a percentage of damage directly into the cell.
if(has_active_type(/obj/item/borg/combat/shield))
var/obj/item/borg/combat/shield/shield = locate() in src
if(shield)
//Shields absorb a certain percentage of damage based on their power setting.
var/absorb_brute = brute*shield.shield_level
var/absorb_burn = burn*shield.shield_level
var/cost = (absorb_brute+absorb_burn) * 25
cell.charge -= cost
if(cell.charge <= 0)
cell.charge = 0
to_chat(src, "<span class='filter_warning'>[span_red("Your shield has overloaded!")]</span>")
else
brute -= absorb_brute
burn -= absorb_burn
to_chat(src, "<span class='filter_combat'>[span_red("Your shield absorbs some of the impact!")]</span>")
var/datum/robot_component/armour/A = get_armour()
if(A)
A.take_damage(brute,burn,sharp)
return
while(parts.len && (brute>0 || burn>0) )
var/datum/robot_component/picked = pick(parts)
var/brute_was = picked.brute_damage
var/burn_was = picked.electronics_damage
picked.take_damage(brute,burn)
brute -= (picked.brute_damage - brute_was)
burn -= (picked.electronics_damage - burn_was)
parts -= picked
/mob/living/silicon/robot/emp_act(severity)
uneq_all()
..() //Damage is handled at /silicon/ level.
/mob/living/silicon/robot/updatehealth()
if(status_flags & GODMODE)
health = getMaxHealth()
set_stat(CONSCIOUS)
return
health = getMaxHealth() - (getBruteLoss() + getFireLoss())
return
/mob/living/silicon/robot/getBruteLoss()
var/amount = 0
for(var/V in components)
var/datum/robot_component/C = components[V]
if(C.installed != 0) amount += C.brute_damage
return amount
/mob/living/silicon/robot/getFireLoss()
var/amount = 0
for(var/V in components)
var/datum/robot_component/C = components[V]
if(C.installed != 0) amount += C.electronics_damage
return amount
/mob/living/silicon/robot/adjustBruteLoss(var/amount,var/include_robo)
if(amount > 0)
take_overall_damage(amount, 0)
else
heal_overall_damage(-amount, 0)
/mob/living/silicon/robot/adjustFireLoss(var/amount,var/include_robo)
if(amount > 0)
take_overall_damage(0, amount)
else
heal_overall_damage(0, -amount)
/mob/living/silicon/robot/proc/get_damaged_components(var/brute, var/burn, var/destroyed = 0)
var/list/datum/robot_component/parts = list()
for(var/V in components)
var/datum/robot_component/C = components[V]
if(C.installed == 1 || (C.installed == -1 && destroyed))
if((brute && C.brute_damage) || (burn && C.electronics_damage) || (!C.toggled) || (!C.powered && C.toggled))
parts += C
return parts
/mob/living/silicon/robot/proc/get_damageable_components()
var/list/rval = new
for(var/V in components)
var/datum/robot_component/C = components[V]
if(C.installed == 1) rval += C
return rval
/mob/living/silicon/robot/proc/get_armour()
if(!components.len) return 0
var/datum/robot_component/C = components["armour"]
if(C && C.installed == 1)
return C
return 0
/mob/living/silicon/robot/heal_organ_damage(var/brute, var/burn)
var/list/datum/robot_component/parts = get_damaged_components(brute,burn)
if(!parts.len) return
var/datum/robot_component/picked = pick(parts)
picked.heal_damage(brute,burn)
/mob/living/silicon/robot/take_organ_damage(var/brute = 0, var/burn = 0, var/sharp = FALSE, var/edge = FALSE, var/emp = 0)
var/list/components = get_damageable_components()
if(!components.len)
return
//Combat shielding absorbs a percentage of damage directly into the cell.
if(has_active_type(/obj/item/borg/combat/shield))
var/obj/item/borg/combat/shield/shield = locate() in src
if(shield && shield.active)
//Shields absorb a certain percentage of damage based on their power setting.
var/absorb_brute = brute*shield.shield_level
var/absorb_burn = burn*shield.shield_level
var/cost = (absorb_brute+absorb_burn) * 25
cell.charge -= cost
if(cell.charge <= 0)
cell.charge = 0
to_chat(src, "<span class='filter_warning'>[span_red("Your shield has overloaded!")]</span>")
else
brute -= absorb_brute
burn -= absorb_burn
to_chat(src, "<span class='filter_combat'>[span_red("Your shield absorbs some of the impact!")]</span>")
if(!emp)
var/datum/robot_component/armour/A = get_armour()
if(A)
A.take_damage(brute,burn,sharp,edge)
return
var/datum/robot_component/C = pick(components)
C.take_damage(brute,burn,sharp,edge)
/mob/living/silicon/robot/heal_overall_damage(var/brute, var/burn)
var/list/datum/robot_component/parts = get_damaged_components(brute,burn)
while(parts.len && (brute>0 || burn>0) )
var/datum/robot_component/picked = pick(parts)
var/brute_was = picked.brute_damage
var/burn_was = picked.electronics_damage
picked.heal_damage(brute,burn)
brute -= (brute_was-picked.brute_damage)
burn -= (burn_was-picked.electronics_damage)
parts -= picked
/mob/living/silicon/robot/take_overall_damage(var/brute = 0, var/burn = 0, var/sharp = FALSE, var/used_weapon = null)
if(status_flags & GODMODE) return //godmode
var/list/datum/robot_component/parts = get_damageable_components()
//Combat shielding absorbs a percentage of damage directly into the cell.
if(has_active_type(/obj/item/borg/combat/shield))
var/obj/item/borg/combat/shield/shield = locate() in src
if(shield)
//Shields absorb a certain percentage of damage based on their power setting.
var/absorb_brute = brute*shield.shield_level
var/absorb_burn = burn*shield.shield_level
var/cost = (absorb_brute+absorb_burn) * 25
cell.charge -= cost
if(cell.charge <= 0)
cell.charge = 0
to_chat(src, "<span class='filter_warning'>[span_red("Your shield has overloaded!")]</span>")
else
brute -= absorb_brute
burn -= absorb_burn
to_chat(src, "<span class='filter_combat'>[span_red("Your shield absorbs some of the impact!")]</span>")
var/datum/robot_component/armour/A = get_armour()
if(A)
A.take_damage(brute,burn,sharp)
return
while(parts.len && (brute>0 || burn>0) )
var/datum/robot_component/picked = pick(parts)
var/brute_was = picked.brute_damage
var/burn_was = picked.electronics_damage
picked.take_damage(brute,burn)
brute -= (picked.brute_damage - brute_was)
burn -= (picked.electronics_damage - burn_was)
parts -= picked
/mob/living/silicon/robot/emp_act(severity)
uneq_all()
..() //Damage is handled at /silicon/ level.
@@ -1,99 +1,99 @@
/mob/living/silicon/robot/get_jetpack()
if(module)
for(var/obj/item/weapon/tank/jetpack/J in module.modules)
return J
/mob/living/silicon/robot/Check_Shoegrip()
return module && module.no_slip
/mob/living/silicon/robot/Process_Spaceslipping(var/prob_slip)
var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
if(thrust?.can_thrust(0.01))
return 0
if(module && module.no_slip)
return 0
..(prob_slip)
/mob/living/silicon/robot/Process_Spacemove(var/check_drift = 0)
if(..())//Can move due to other reasons, don't use jetpack fuel
return 1
var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
if(thrust && (!check_drift || (check_drift && thrust.stabilization_on)) && thrust.do_thrust(0.01))
inertia_dir = 0
return 1
return 0
//No longer needed, but I'll leave it here incase we plan to re-use it.
/mob/living/silicon/robot/movement_delay()
. = speed
if(module_active && istype(module_active,/obj/item/borg/combat/mobility))
. -= 2 // VOREStation Edit
if(get_restraining_bolt()) // Borgs with Restraining Bolts move slower.
. += 1
. += config.robot_delay
. += ..()
// NEW: Use power while moving.
/mob/living/silicon/robot/SelfMove(turf/n, direct, movetime)
if (!is_component_functioning("actuator"))
return 0
var/datum/robot_component/actuator/A = get_component("actuator")
if (cell_use_power(A.active_usage))
return ..()
/mob/living/silicon/robot/Moved(atom/old_loc, direction, forced = FALSE)
. = ..()
if(!module)
return
//Borgs and drones can use their mining bags ~automagically~ if they're deployed in a slot. Only mining bags, as they're optimized for mass use.
if(istype(module_state_1, /obj/item/weapon/storage/bag/ore) || istype(module_state_2, /obj/item/weapon/storage/bag/ore) || istype(module_state_3, /obj/item/weapon/storage/bag/ore))
var/obj/item/weapon/storage/bag/ore/B = null
if(istype(module_state_1, /obj/item/weapon/storage/bag/ore)) //First orebag has priority, if they for some reason have multiple.
B = module_state_1
else if(istype(module_state_2, /obj/item/weapon/storage/bag/ore))
B = module_state_2
else if(istype(module_state_3, /obj/item/weapon/storage/bag/ore))
B = module_state_3
var/turf/tile = loc
if(isturf(tile))
B.gather_all(tile, src, 1) //Shhh, unless the bag fills, don't spam the borg's chat with stuff that's going on every time they move!
if(scrubbing && isturf(loc))
var/turf/tile = loc
tile.clean_blood()
if (istype(tile, /turf/simulated))
var/turf/simulated/S = tile
S.dirt = 0
for(var/A in tile)
if(istype(A, /obj/effect))
if(istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/overlay))
qdel(A)
else if(istype(A, /obj/item))
var/obj/item/cleaned_item = A
cleaned_item.clean_blood()
else if(istype(A, /mob/living/carbon/human))
var/mob/living/carbon/human/cleaned_human = A
if(cleaned_human.lying)
if(cleaned_human.head)
cleaned_human.head.clean_blood()
cleaned_human.update_inv_head(0)
if(cleaned_human.wear_suit)
cleaned_human.wear_suit.clean_blood()
cleaned_human.update_inv_wear_suit(0)
else if(cleaned_human.w_uniform)
cleaned_human.w_uniform.clean_blood()
cleaned_human.update_inv_w_uniform(0)
if(cleaned_human.shoes)
cleaned_human.shoes.clean_blood()
cleaned_human.update_inv_shoes(0)
cleaned_human.clean_blood(1)
to_chat(cleaned_human, "<span class='warning'>[src] cleans your face!</span>")
/mob/living/silicon/robot/get_jetpack()
if(module)
for(var/obj/item/weapon/tank/jetpack/J in module.modules)
return J
/mob/living/silicon/robot/Check_Shoegrip()
return module && module.no_slip
/mob/living/silicon/robot/Process_Spaceslipping(var/prob_slip)
var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
if(thrust?.can_thrust(0.01))
return 0
if(module && module.no_slip)
return 0
..(prob_slip)
/mob/living/silicon/robot/Process_Spacemove(var/check_drift = 0)
if(..())//Can move due to other reasons, don't use jetpack fuel
return 1
var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
if(thrust && (!check_drift || (check_drift && thrust.stabilization_on)) && thrust.do_thrust(0.01))
inertia_dir = 0
return 1
return 0
//No longer needed, but I'll leave it here incase we plan to re-use it.
/mob/living/silicon/robot/movement_delay()
. = speed
if(module_active && istype(module_active,/obj/item/borg/combat/mobility))
. -= 2 // VOREStation Edit
if(get_restraining_bolt()) // Borgs with Restraining Bolts move slower.
. += 1
. += config.robot_delay
. += ..()
// NEW: Use power while moving.
/mob/living/silicon/robot/SelfMove(turf/n, direct, movetime)
if (!is_component_functioning("actuator"))
return 0
var/datum/robot_component/actuator/A = get_component("actuator")
if (cell_use_power(A.active_usage))
return ..()
/mob/living/silicon/robot/Moved(atom/old_loc, direction, forced = FALSE)
. = ..()
if(!module)
return
//Borgs and drones can use their mining bags ~automagically~ if they're deployed in a slot. Only mining bags, as they're optimized for mass use.
if(istype(module_state_1, /obj/item/weapon/storage/bag/ore) || istype(module_state_2, /obj/item/weapon/storage/bag/ore) || istype(module_state_3, /obj/item/weapon/storage/bag/ore))
var/obj/item/weapon/storage/bag/ore/B = null
if(istype(module_state_1, /obj/item/weapon/storage/bag/ore)) //First orebag has priority, if they for some reason have multiple.
B = module_state_1
else if(istype(module_state_2, /obj/item/weapon/storage/bag/ore))
B = module_state_2
else if(istype(module_state_3, /obj/item/weapon/storage/bag/ore))
B = module_state_3
var/turf/tile = loc
if(isturf(tile))
B.gather_all(tile, src, 1) //Shhh, unless the bag fills, don't spam the borg's chat with stuff that's going on every time they move!
if(scrubbing && isturf(loc))
var/turf/tile = loc
tile.clean_blood()
if (istype(tile, /turf/simulated))
var/turf/simulated/S = tile
S.dirt = 0
for(var/A in tile)
if(istype(A, /obj/effect))
if(istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/overlay))
qdel(A)
else if(istype(A, /obj/item))
var/obj/item/cleaned_item = A
cleaned_item.clean_blood()
else if(istype(A, /mob/living/carbon/human))
var/mob/living/carbon/human/cleaned_human = A
if(cleaned_human.lying)
if(cleaned_human.head)
cleaned_human.head.clean_blood()
cleaned_human.update_inv_head(0)
if(cleaned_human.wear_suit)
cleaned_human.wear_suit.clean_blood()
cleaned_human.update_inv_wear_suit(0)
else if(cleaned_human.w_uniform)
cleaned_human.w_uniform.clean_blood()
cleaned_human.update_inv_w_uniform(0)
if(cleaned_human.shoes)
cleaned_human.shoes.clean_blood()
cleaned_human.update_inv_shoes(0)
cleaned_human.clean_blood(1)
to_chat(cleaned_human, "<span class='warning'>[src] cleans your face!</span>")
@@ -1,135 +1,135 @@
// This file holds things required for remote borg control by an AI.
GLOBAL_LIST_EMPTY(available_ai_shells)
/mob/living/silicon/robot
var/shell = FALSE
var/deployed = FALSE
var/mob/living/silicon/ai/mainframe = null
// Premade AI shell, for roundstart shells.
/mob/living/silicon/robot/ai_shell/Initialize()
mmi = new /obj/item/device/mmi/inert/ai_remote(src)
post_mmi_setup()
return ..()
// Call after inserting or instantiating an MMI.
/mob/living/silicon/robot/proc/post_mmi_setup()
if(istype(mmi, /obj/item/device/mmi/inert/ai_remote))
make_shell()
playsound(src, 'sound/machines/twobeep.ogg', 50, 0)
else
playsound(src, 'sound/voice/liveagain.ogg', 75, 1)
return
/mob/living/silicon/robot/proc/make_shell()
shell = TRUE
braintype = "AI Shell"
SetName("[modtype] AI Shell [num2text(ident)]")
rbPDA = new /obj/item/device/pda/ai/shell(src)
setup_PDA()
GLOB.available_ai_shells |= src
if(!QDELETED(camera))
camera.c_tag = real_name //update the camera name too
notify_ai(ROBOT_NOTIFICATION_AI_SHELL)
update_icon()
/mob/living/silicon/robot/proc/revert_shell()
if(!shell)
return
undeploy()
shell = FALSE
GLOB.available_ai_shells -= src
if(!QDELETED(camera))
camera.c_tag = real_name
update_icon()
// This should be called before the AI client/mind is actually moved.
/mob/living/silicon/robot/proc/deploy_init(mob/living/silicon/ai/AI)
// Set the name when the AI steps inside.
SetName("[AI.real_name] shell [num2text(ident)]")
if(isnull(sprite_name)) // For custom sprites. It can only chance once in case there are two AIs with custom borg sprites.
sprite_name = AI.real_name
if(!QDELETED(camera))
camera.c_tag = real_name
// Have the borg have eyes when active.
mainframe = AI
deployed = TRUE
update_icon()
// Laws.
connected_ai = mainframe // So they share laws.
mainframe.connected_robots |= src
lawsync()
// Give button to leave.
verbs += /mob/living/silicon/robot/proc/undeploy_act
to_chat(AI, span("notice", "You have connected to an AI Shell remotely, and are now in control of it.<br>\
To return to your core, use the <b>Release Control</b> verb."))
// Languages and comms.
languages = AI.languages.Copy()
speech_synthesizer_langs = AI.speech_synthesizer_langs.Copy()
if(radio && AI.aiRadio) //AI keeps all channels, including Syndie if it is an Infiltrator.
// if(AI.radio.syndie)
// radio.make_syndie()
radio.subspace_transmission = TRUE
radio.channels = AI.aiRadio.channels
// Called after the AI transfers over.
/mob/living/silicon/robot/proc/post_deploy()
return
/mob/living/silicon/robot/proc/undeploy(message)
if(!deployed || !mind || !mainframe)
return
// mainframe.redeploy_action.Grant(mainframe)
// mainframe.redeploy_action.last_used_shell = src
if(message)
to_chat(src, span("notice", message))
mind.transfer_to(mainframe)
deployed = FALSE
update_icon()
mainframe.teleop = null
mainframe.deployed_shell = null
SetName("[modtype] AI Shell [num2text(ident)]")
// undeployment_action.Remove(src)
if(radio) //Return radio to normal
radio.recalculateChannels()
if(!QDELETED(camera))
camera.c_tag = real_name //update the camera name too
// diag_hud_set_aishell()
// mainframe.diag_hud_set_deployed()
if(mainframe.laws)
mainframe.laws.show_laws(mainframe) //Always remind the AI when switching
mainframe = null
/mob/living/silicon/robot/proc/undeploy_act()
set name = "Release Control"
set desc = "Release control of a remote drone."
set category = "Robot Commands"
undeploy("Remote session terminated.")
/mob/living/silicon/robot/attack_ai(mob/user)
if(shell && config.allow_ai_shells && (!connected_ai || connected_ai == user))
var/mob/living/silicon/ai/AI = user
if(istype(AI)) // Just in case we're clicked by a borg
AI.deploy_to_shell(src)
else
return ..()
// Place this on your map to mark where a free AI shell will be.
// This can be turned off in the config (and is off by default).
// Note that mapping in more than one of these will result in multiple shells.
/obj/effect/landmark/free_ai_shell
name = "free ai shell spawner"
icon = 'icons/mob/screen1.dmi'
icon_state = "x3"
delete_me = TRUE
/obj/effect/landmark/free_ai_shell/Initialize()
if(config.allow_ai_shells && config.give_free_ai_shell)
new /mob/living/silicon/robot/ai_shell(get_turf(src))
return ..()
// This file holds things required for remote borg control by an AI.
GLOBAL_LIST_EMPTY(available_ai_shells)
/mob/living/silicon/robot
var/shell = FALSE
var/deployed = FALSE
var/mob/living/silicon/ai/mainframe = null
// Premade AI shell, for roundstart shells.
/mob/living/silicon/robot/ai_shell/Initialize()
mmi = new /obj/item/device/mmi/inert/ai_remote(src)
post_mmi_setup()
return ..()
// Call after inserting or instantiating an MMI.
/mob/living/silicon/robot/proc/post_mmi_setup()
if(istype(mmi, /obj/item/device/mmi/inert/ai_remote))
make_shell()
playsound(src, 'sound/machines/twobeep.ogg', 50, 0)
else
playsound(src, 'sound/voice/liveagain.ogg', 75, 1)
return
/mob/living/silicon/robot/proc/make_shell()
shell = TRUE
braintype = "AI Shell"
SetName("[modtype] AI Shell [num2text(ident)]")
rbPDA = new /obj/item/device/pda/ai/shell(src)
setup_PDA()
GLOB.available_ai_shells |= src
if(!QDELETED(camera))
camera.c_tag = real_name //update the camera name too
notify_ai(ROBOT_NOTIFICATION_AI_SHELL)
update_icon()
/mob/living/silicon/robot/proc/revert_shell()
if(!shell)
return
undeploy()
shell = FALSE
GLOB.available_ai_shells -= src
if(!QDELETED(camera))
camera.c_tag = real_name
update_icon()
// This should be called before the AI client/mind is actually moved.
/mob/living/silicon/robot/proc/deploy_init(mob/living/silicon/ai/AI)
// Set the name when the AI steps inside.
SetName("[AI.real_name] shell [num2text(ident)]")
if(isnull(sprite_name)) // For custom sprites. It can only chance once in case there are two AIs with custom borg sprites.
sprite_name = AI.real_name
if(!QDELETED(camera))
camera.c_tag = real_name
// Have the borg have eyes when active.
mainframe = AI
deployed = TRUE
update_icon()
// Laws.
connected_ai = mainframe // So they share laws.
mainframe.connected_robots |= src
lawsync()
// Give button to leave.
verbs += /mob/living/silicon/robot/proc/undeploy_act
to_chat(AI, span("notice", "You have connected to an AI Shell remotely, and are now in control of it.<br>\
To return to your core, use the <b>Release Control</b> verb."))
// Languages and comms.
languages = AI.languages.Copy()
speech_synthesizer_langs = AI.speech_synthesizer_langs.Copy()
if(radio && AI.aiRadio) //AI keeps all channels, including Syndie if it is an Infiltrator.
// if(AI.radio.syndie)
// radio.make_syndie()
radio.subspace_transmission = TRUE
radio.channels = AI.aiRadio.channels
// Called after the AI transfers over.
/mob/living/silicon/robot/proc/post_deploy()
return
/mob/living/silicon/robot/proc/undeploy(message)
if(!deployed || !mind || !mainframe)
return
// mainframe.redeploy_action.Grant(mainframe)
// mainframe.redeploy_action.last_used_shell = src
if(message)
to_chat(src, span("notice", message))
mind.transfer_to(mainframe)
deployed = FALSE
update_icon()
mainframe.teleop = null
mainframe.deployed_shell = null
SetName("[modtype] AI Shell [num2text(ident)]")
// undeployment_action.Remove(src)
if(radio) //Return radio to normal
radio.recalculateChannels()
if(!QDELETED(camera))
camera.c_tag = real_name //update the camera name too
// diag_hud_set_aishell()
// mainframe.diag_hud_set_deployed()
if(mainframe.laws)
mainframe.laws.show_laws(mainframe) //Always remind the AI when switching
mainframe = null
/mob/living/silicon/robot/proc/undeploy_act()
set name = "Release Control"
set desc = "Release control of a remote drone."
set category = "Robot Commands"
undeploy("Remote session terminated.")
/mob/living/silicon/robot/attack_ai(mob/user)
if(shell && config.allow_ai_shells && (!connected_ai || connected_ai == user))
var/mob/living/silicon/ai/AI = user
if(istype(AI)) // Just in case we're clicked by a borg
AI.deploy_to_shell(src)
else
return ..()
// Place this on your map to mark where a free AI shell will be.
// This can be turned off in the config (and is off by default).
// Note that mapping in more than one of these will result in multiple shells.
/obj/effect/landmark/free_ai_shell
name = "free ai shell spawner"
icon = 'icons/mob/screen1.dmi'
icon_state = "x3"
delete_me = TRUE
/obj/effect/landmark/free_ai_shell/Initialize()
if(config.allow_ai_shells && config.give_free_ai_shell)
new /mob/living/silicon/robot/ai_shell(get_turf(src))
return ..()
+110 -110
View File
@@ -1,110 +1,110 @@
/mob/living/silicon
var/register_alarms = 1
var/datum/tgui_module/alarm_monitor/all/robot/alarm_monitor
var/datum/tgui_module/atmos_control/robot/atmos_control
var/datum/tgui_module/crew_manifest/robot/crew_manifest
var/datum/tgui_module/crew_monitor/robot/crew_monitor
var/datum/tgui_module/law_manager/robot/law_manager
var/datum/tgui_module/power_monitor/robot/power_monitor
var/datum/tgui_module/rcon/robot/rcon
/mob/living/silicon
var/list/silicon_subsystems = list(
/mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_crew_manifest,
/mob/living/silicon/proc/subsystem_law_manager
)
/mob/living/silicon/ai
silicon_subsystems = list(
/mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_atmos_control,
/mob/living/silicon/proc/subsystem_crew_manifest,
/mob/living/silicon/proc/subsystem_crew_monitor,
/mob/living/silicon/proc/subsystem_law_manager,
/mob/living/silicon/proc/subsystem_power_monitor,
/mob/living/silicon/proc/subsystem_rcon
)
/mob/living/silicon/robot/syndicate
register_alarms = 0
silicon_subsystems = list(/mob/living/silicon/proc/subsystem_law_manager)
/mob/living/silicon/proc/init_subsystems()
alarm_monitor = new(src)
atmos_control = new(src)
crew_manifest = new(src)
crew_monitor = new(src)
law_manager = new(src)
power_monitor = new(src)
rcon = new(src)
if(!register_alarms)
return
for(var/datum/alarm_handler/AH in SSalarm.all_handlers)
AH.register_alarm(src, /mob/living/silicon/proc/receive_alarm)
queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
/********************
* Alarm Monitor *
********************/
/mob/living/silicon/proc/subsystem_alarm_monitor()
set name = "Alarm Monitor"
set category = "Subystems"
alarm_monitor.tgui_interact(usr)
/********************
* Atmos Control *
********************/
/mob/living/silicon/proc/subsystem_atmos_control()
set category = "Subystems"
set name = "Atmospherics Control"
atmos_control.tgui_interact(usr)
/********************
* Crew Manifest *
********************/
/mob/living/silicon/proc/subsystem_crew_manifest()
set category = "Subystems"
set name = "Crew Manifest"
crew_manifest.tgui_interact(usr)
/********************
* Crew Monitor *
********************/
/mob/living/silicon/proc/subsystem_crew_monitor()
set category = "Subystems"
set name = "Crew Monitor"
crew_monitor.tgui_interact(usr)
/****************
* Law Manager *
****************/
/mob/living/silicon/proc/subsystem_law_manager()
set name = "Law Manager"
set category = "Subystems"
law_manager.tgui_interact(usr)
/********************
* Power Monitor *
********************/
/mob/living/silicon/proc/subsystem_power_monitor()
set category = "Subystems"
set name = "Power Monitor"
power_monitor.tgui_interact(usr)
/************
* RCON *
************/
/mob/living/silicon/proc/subsystem_rcon()
set category = "Subystems"
set name = "RCON"
rcon.tgui_interact(usr)
/mob/living/silicon
var/register_alarms = 1
var/datum/tgui_module/alarm_monitor/all/robot/alarm_monitor
var/datum/tgui_module/atmos_control/robot/atmos_control
var/datum/tgui_module/crew_manifest/robot/crew_manifest
var/datum/tgui_module/crew_monitor/robot/crew_monitor
var/datum/tgui_module/law_manager/robot/law_manager
var/datum/tgui_module/power_monitor/robot/power_monitor
var/datum/tgui_module/rcon/robot/rcon
/mob/living/silicon
var/list/silicon_subsystems = list(
/mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_crew_manifest,
/mob/living/silicon/proc/subsystem_law_manager
)
/mob/living/silicon/ai
silicon_subsystems = list(
/mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_atmos_control,
/mob/living/silicon/proc/subsystem_crew_manifest,
/mob/living/silicon/proc/subsystem_crew_monitor,
/mob/living/silicon/proc/subsystem_law_manager,
/mob/living/silicon/proc/subsystem_power_monitor,
/mob/living/silicon/proc/subsystem_rcon
)
/mob/living/silicon/robot/syndicate
register_alarms = 0
silicon_subsystems = list(/mob/living/silicon/proc/subsystem_law_manager)
/mob/living/silicon/proc/init_subsystems()
alarm_monitor = new(src)
atmos_control = new(src)
crew_manifest = new(src)
crew_monitor = new(src)
law_manager = new(src)
power_monitor = new(src)
rcon = new(src)
if(!register_alarms)
return
for(var/datum/alarm_handler/AH in SSalarm.all_handlers)
AH.register_alarm(src, /mob/living/silicon/proc/receive_alarm)
queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
/********************
* Alarm Monitor *
********************/
/mob/living/silicon/proc/subsystem_alarm_monitor()
set name = "Alarm Monitor"
set category = "Subystems"
alarm_monitor.tgui_interact(usr)
/********************
* Atmos Control *
********************/
/mob/living/silicon/proc/subsystem_atmos_control()
set category = "Subystems"
set name = "Atmospherics Control"
atmos_control.tgui_interact(usr)
/********************
* Crew Manifest *
********************/
/mob/living/silicon/proc/subsystem_crew_manifest()
set category = "Subystems"
set name = "Crew Manifest"
crew_manifest.tgui_interact(usr)
/********************
* Crew Monitor *
********************/
/mob/living/silicon/proc/subsystem_crew_monitor()
set category = "Subystems"
set name = "Crew Monitor"
crew_monitor.tgui_interact(usr)
/****************
* Law Manager *
****************/
/mob/living/silicon/proc/subsystem_law_manager()
set name = "Law Manager"
set category = "Subystems"
law_manager.tgui_interact(usr)
/********************
* Power Monitor *
********************/
/mob/living/silicon/proc/subsystem_power_monitor()
set category = "Subystems"
set name = "Power Monitor"
power_monitor.tgui_interact(usr)
/************
* RCON *
************/
/mob/living/silicon/proc/subsystem_rcon()
set category = "Subystems"
set name = "RCON"
rcon.tgui_interact(usr)
@@ -1,60 +1,60 @@
//I figured since it's basically always frowned upon to eat the station pets, it would probably be a good idea to just make that not possible normally.
/mob/living/simple_mob/animal/passive/dog/corgi/Ian
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/dog/corgi/Lisa
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/dog/corgi/puppy
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/cat/runtime
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/cat/kitten
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/bird/parrot/poly
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/opossum/poppy
digestable = 0
devourable = 0
/mob/living/carbon/human/monkey/punpun
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/snake/python/noodle
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/mouse/white/apple //She's a mouse living with a snake. Accidents happen. But don't gurg apple >:I
digestable = 0
/mob/living/simple_mob/animal/passive/fox/renault
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/crab/Coffee
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/sif/fluffy
digestable = 0
devourable = 0
/mob/living/simple_mob/slime/xenobio/rainbow/kendrick
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/chick
digestable = 0
//I figured since it's basically always frowned upon to eat the station pets, it would probably be a good idea to just make that not possible normally.
/mob/living/simple_mob/animal/passive/dog/corgi/Ian
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/dog/corgi/Lisa
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/dog/corgi/puppy
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/cat/runtime
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/cat/kitten
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/bird/parrot/poly
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/opossum/poppy
digestable = 0
devourable = 0
/mob/living/carbon/human/monkey/punpun
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/snake/python/noodle
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/mouse/white/apple //She's a mouse living with a snake. Accidents happen. But don't gurg apple >:I
digestable = 0
/mob/living/simple_mob/animal/passive/fox/renault
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/crab/Coffee
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/sif/fluffy
digestable = 0
devourable = 0
/mob/living/simple_mob/slime/xenobio/rainbow/kendrick
digestable = 0
devourable = 0
/mob/living/simple_mob/animal/passive/chick
digestable = 0
devourable = 0
@@ -1,274 +1,274 @@
// Borers are probably still going to be buggy as fuck, this is just bringing their mob defines up to the new system.
// IMO they're a relic of several ages we're long past, their code and their design showing this plainly, but removing them would
// make certain people Unhappy so here we are. They need a complete redesign but thats beyond the scope of the rewrite.
/mob/living/simple_mob/animal/borer
name = "cortical borer"
desc = "A small, quivering sluglike creature."
icon_state = "brainslug"
item_state = "brainslug"
icon_living = "brainslug"
icon_dead = "brainslug_dead"
response_help = "pokes"
response_disarm = "prods"
response_harm = "stomps on"
attacktext = list("nipped")
friendly = list("prods")
organ_names = /decl/mob_organ_names/borer
status_flags = CANPUSH
pass_flags = PASSTABLE
movement_cooldown = 1.5
universal_understand = TRUE
can_be_antagged = TRUE
holder_type = /obj/item/weapon/holder/borer
ai_holder_type = null // This is player-controlled, always.
var/mob/living/carbon/human/host = null // The humanoid host for the brain worm.
var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth.
var/roundstart = FALSE // If true, spawning won't try to pull a ghost.
var/antag = TRUE // If false, will avoid setting up objectives and events
var/chemicals = 10 // A resource used for reproduction and powers.
var/max_chemicals = 250 // Max of said resource.
var/true_name = null // String used when speaking among other worms.
var/controlling = FALSE // Used in human death ceck.
var/docile = FALSE // Sugar can stop borers from acting.
var/has_reproduced = FALSE
var/used_dominate // world.time when the dominate power was last used.
/mob/living/simple_mob/animal/borer/roundstart
roundstart = TRUE
/mob/living/simple_mob/animal/borer/non_antag
antag = FALSE
/mob/living/simple_mob/animal/borer/Login()
..()
if(antag && mind)
borers.add_antagonist(mind)
/mob/living/simple_mob/animal/borer/Initialize()
add_language("Cortical Link")
verbs += /mob/living/proc/ventcrawl
verbs += /mob/living/proc/hide
true_name = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]"
if(!roundstart && antag)
request_player()
return ..()
/mob/living/simple_mob/animal/borer/handle_special()
if(host && !stat && !host.stat)
// Handle docility.
if(host.reagents.has_reagent("sugar") && !docile)
var/message = "You feel the soporific flow of sugar in your host's blood, lulling you into docility."
var/target = controlling ? host : src
to_chat(target, span("warning", message))
docile = TRUE
else if(docile)
var/message = "You shake off your lethargy as the sugar leaves your host's blood."
var/target = controlling ? host : src
to_chat(target, span("notice", message))
docile = FALSE
// Chem regen.
if(chemicals < max_chemicals)
chemicals++
// Control stuff.
if(controlling)
if(docile)
to_chat(host, span("warning", "You are feeling far too docile to continue controlling your host..."))
host.release_control()
return
if(prob(5))
host.adjustBrainLoss(0.1)
if(prob(host.brainloss/20))
host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_v","gasp"))]")
/mob/living/simple_mob/animal/borer/Stat()
..()
if(client.statpanel == "Status")
statpanel("Status")
if(emergency_shuttle)
var/eta_status = emergency_shuttle.get_status_panel_eta()
if(eta_status)
stat(null, eta_status)
stat("Chemicals", chemicals)
/mob/living/simple_mob/animal/borer/proc/detatch()
if(!host || !controlling)
return
if(istype(host, /mob/living/carbon/human))
var/mob/living/carbon/human/H = host
var/obj/item/organ/external/head = H.get_organ(BP_HEAD)
if(head)
head.implants -= src
controlling = FALSE
host.remove_language("Cortical Link")
host.verbs -= /mob/living/carbon/proc/release_control
host.verbs -= /mob/living/carbon/proc/punish_host
host.verbs -= /mob/living/carbon/proc/spawn_larvae
if(host_brain)
// these are here so bans and multikey warnings are not triggered on the wrong people when ckey is changed.
// computer_id and IP are not updated magically on their own in offline mobs -walter0o
// This shit need to die in a phoron fire.
// host -> self
var/h2s_id = host.computer_id
var/h2s_ip= host.lastKnownIP
host.computer_id = null
host.lastKnownIP = null
src.ckey = host.ckey
if(!src.computer_id)
src.computer_id = h2s_id
if(!host_brain.lastKnownIP)
src.lastKnownIP = h2s_ip
// brain -> host
var/b2h_id = host_brain.computer_id
var/b2h_ip= host_brain.lastKnownIP
host_brain.computer_id = null
host_brain.lastKnownIP = null
host.ckey = host_brain.ckey
if(!host.computer_id)
host.computer_id = b2h_id
if(!host.lastKnownIP)
host.lastKnownIP = b2h_ip
qdel(host_brain)
/mob/living/simple_mob/animal/borer/proc/leave_host()
if(!host)
return
if(host.mind)
borers.remove_antagonist(host.mind)
forceMove(get_turf(host))
reset_view(null)
machine = null
if(istype(host, /mob/living/carbon/human))
var/mob/living/carbon/human/H = host
var/obj/item/organ/external/head = H.get_organ(BP_HEAD)
if(head)
head.implants -= src
host.reset_view(null)
host.machine = null
host = null
/mob/living/simple_mob/animal/borer/proc/request_player()
var/datum/ghost_query/Q = new /datum/ghost_query/borer()
var/list/winner = Q.query() // This will sleep the proc for awhile.
if(winner.len)
var/mob/observer/dead/D = winner[1]
transfer_personality(D)
/mob/living/simple_mob/animal/borer/proc/transfer_personality(mob/candidate)
if(!candidate || !candidate.mind)
return
src.mind = candidate.mind
candidate.mind.current = src
ckey = candidate.ckey
if(mind)
mind.assigned_role = "Cortical Borer"
mind.special_role = "Cortical Borer"
to_chat(src, span("notice", "You are a cortical borer! You are a brain slug that worms its way \
into the head of its victim. Use stealth, persuasion and your powers of mind control to keep you, \
your host and your eventual spawn safe and warm."))
to_chat(src, "You can speak to your victim with <b>say</b>, to other borers with <b>say :x</b>, and use your Abilities tab to access powers.")
/mob/living/simple_mob/animal/borer/cannot_use_vents()
return
// This is awful but its literally say code.
/mob/living/simple_mob/animal/borer/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
message = sanitize(message)
message = capitalize(message)
if(!message)
return
if(stat >= DEAD)
return say_dead(message)
else if(stat)
return
if(client && client.prefs.muted & MUTE_IC)
to_chat(src, span("danger", "You cannot speak in IC (muted)."))
return
if(copytext(message, 1, 2) == "*")
return emote(copytext(message, 2))
var/list/message_pieces = parse_languages(message)
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && S.speaking.flags & HIVEMIND)
S.speaking.broadcast(src, trim(copytext(message, 3)), src.true_name)
return
if(!host)
if(chemicals >= 30)
to_chat(src, span("alien", "..You emit a psionic pulse with an encoded message.."))
var/list/nearby_mobs = list()
for(var/mob/living/LM in view(src, 1 + round(6 * (chemicals / max_chemicals))))
if(LM == src)
continue
if(!LM.stat)
nearby_mobs += LM
var/mob/living/speaker
if(nearby_mobs.len)
speaker = tgui_input_list(usr, "Choose a target speaker:", "Target Choice", nearby_mobs)
if(speaker)
log_admin("[src.ckey]/([src]) tried to force [speaker] to say: [message]")
message_admins("[src.ckey]/([src]) tried to force [speaker] to say: [message]")
speaker.say("[message]")
return
to_chat(src, span("alien", "..But nothing heard it.."))
else
to_chat(src, span("warning", "You have no host to speak to."))
return //No host, no audible speech.
to_chat(src, "You drop words into [host]'s mind: \"[message]\"")
to_chat(host, "Your own thoughts speak: \"[message]\"")
for(var/mob/M in player_list)
if(istype(M, /mob/new_player))
continue
else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
to_chat(M, "[src.true_name] whispers to [host], \"[message]\"")
/decl/mob_organ_names/borer
hit_zones = list("head", "central segment", "tail segment")
// Borers are probably still going to be buggy as fuck, this is just bringing their mob defines up to the new system.
// IMO they're a relic of several ages we're long past, their code and their design showing this plainly, but removing them would
// make certain people Unhappy so here we are. They need a complete redesign but thats beyond the scope of the rewrite.
/mob/living/simple_mob/animal/borer
name = "cortical borer"
desc = "A small, quivering sluglike creature."
icon_state = "brainslug"
item_state = "brainslug"
icon_living = "brainslug"
icon_dead = "brainslug_dead"
response_help = "pokes"
response_disarm = "prods"
response_harm = "stomps on"
attacktext = list("nipped")
friendly = list("prods")
organ_names = /decl/mob_organ_names/borer
status_flags = CANPUSH
pass_flags = PASSTABLE
movement_cooldown = 1.5
universal_understand = TRUE
can_be_antagged = TRUE
holder_type = /obj/item/weapon/holder/borer
ai_holder_type = null // This is player-controlled, always.
var/mob/living/carbon/human/host = null // The humanoid host for the brain worm.
var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth.
var/roundstart = FALSE // If true, spawning won't try to pull a ghost.
var/antag = TRUE // If false, will avoid setting up objectives and events
var/chemicals = 10 // A resource used for reproduction and powers.
var/max_chemicals = 250 // Max of said resource.
var/true_name = null // String used when speaking among other worms.
var/controlling = FALSE // Used in human death ceck.
var/docile = FALSE // Sugar can stop borers from acting.
var/has_reproduced = FALSE
var/used_dominate // world.time when the dominate power was last used.
/mob/living/simple_mob/animal/borer/roundstart
roundstart = TRUE
/mob/living/simple_mob/animal/borer/non_antag
antag = FALSE
/mob/living/simple_mob/animal/borer/Login()
..()
if(antag && mind)
borers.add_antagonist(mind)
/mob/living/simple_mob/animal/borer/Initialize()
add_language("Cortical Link")
verbs += /mob/living/proc/ventcrawl
verbs += /mob/living/proc/hide
true_name = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]"
if(!roundstart && antag)
request_player()
return ..()
/mob/living/simple_mob/animal/borer/handle_special()
if(host && !stat && !host.stat)
// Handle docility.
if(host.reagents.has_reagent("sugar") && !docile)
var/message = "You feel the soporific flow of sugar in your host's blood, lulling you into docility."
var/target = controlling ? host : src
to_chat(target, span("warning", message))
docile = TRUE
else if(docile)
var/message = "You shake off your lethargy as the sugar leaves your host's blood."
var/target = controlling ? host : src
to_chat(target, span("notice", message))
docile = FALSE
// Chem regen.
if(chemicals < max_chemicals)
chemicals++
// Control stuff.
if(controlling)
if(docile)
to_chat(host, span("warning", "You are feeling far too docile to continue controlling your host..."))
host.release_control()
return
if(prob(5))
host.adjustBrainLoss(0.1)
if(prob(host.brainloss/20))
host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_v","gasp"))]")
/mob/living/simple_mob/animal/borer/Stat()
..()
if(client.statpanel == "Status")
statpanel("Status")
if(emergency_shuttle)
var/eta_status = emergency_shuttle.get_status_panel_eta()
if(eta_status)
stat(null, eta_status)
stat("Chemicals", chemicals)
/mob/living/simple_mob/animal/borer/proc/detatch()
if(!host || !controlling)
return
if(istype(host, /mob/living/carbon/human))
var/mob/living/carbon/human/H = host
var/obj/item/organ/external/head = H.get_organ(BP_HEAD)
if(head)
head.implants -= src
controlling = FALSE
host.remove_language("Cortical Link")
host.verbs -= /mob/living/carbon/proc/release_control
host.verbs -= /mob/living/carbon/proc/punish_host
host.verbs -= /mob/living/carbon/proc/spawn_larvae
if(host_brain)
// these are here so bans and multikey warnings are not triggered on the wrong people when ckey is changed.
// computer_id and IP are not updated magically on their own in offline mobs -walter0o
// This shit need to die in a phoron fire.
// host -> self
var/h2s_id = host.computer_id
var/h2s_ip= host.lastKnownIP
host.computer_id = null
host.lastKnownIP = null
src.ckey = host.ckey
if(!src.computer_id)
src.computer_id = h2s_id
if(!host_brain.lastKnownIP)
src.lastKnownIP = h2s_ip
// brain -> host
var/b2h_id = host_brain.computer_id
var/b2h_ip= host_brain.lastKnownIP
host_brain.computer_id = null
host_brain.lastKnownIP = null
host.ckey = host_brain.ckey
if(!host.computer_id)
host.computer_id = b2h_id
if(!host.lastKnownIP)
host.lastKnownIP = b2h_ip
qdel(host_brain)
/mob/living/simple_mob/animal/borer/proc/leave_host()
if(!host)
return
if(host.mind)
borers.remove_antagonist(host.mind)
forceMove(get_turf(host))
reset_view(null)
machine = null
if(istype(host, /mob/living/carbon/human))
var/mob/living/carbon/human/H = host
var/obj/item/organ/external/head = H.get_organ(BP_HEAD)
if(head)
head.implants -= src
host.reset_view(null)
host.machine = null
host = null
/mob/living/simple_mob/animal/borer/proc/request_player()
var/datum/ghost_query/Q = new /datum/ghost_query/borer()
var/list/winner = Q.query() // This will sleep the proc for awhile.
if(winner.len)
var/mob/observer/dead/D = winner[1]
transfer_personality(D)
/mob/living/simple_mob/animal/borer/proc/transfer_personality(mob/candidate)
if(!candidate || !candidate.mind)
return
src.mind = candidate.mind
candidate.mind.current = src
ckey = candidate.ckey
if(mind)
mind.assigned_role = "Cortical Borer"
mind.special_role = "Cortical Borer"
to_chat(src, span("notice", "You are a cortical borer! You are a brain slug that worms its way \
into the head of its victim. Use stealth, persuasion and your powers of mind control to keep you, \
your host and your eventual spawn safe and warm."))
to_chat(src, "You can speak to your victim with <b>say</b>, to other borers with <b>say :x</b>, and use your Abilities tab to access powers.")
/mob/living/simple_mob/animal/borer/cannot_use_vents()
return
// This is awful but its literally say code.
/mob/living/simple_mob/animal/borer/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
message = sanitize(message)
message = capitalize(message)
if(!message)
return
if(stat >= DEAD)
return say_dead(message)
else if(stat)
return
if(client && client.prefs.muted & MUTE_IC)
to_chat(src, span("danger", "You cannot speak in IC (muted)."))
return
if(copytext(message, 1, 2) == "*")
return emote(copytext(message, 2))
var/list/message_pieces = parse_languages(message)
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && S.speaking.flags & HIVEMIND)
S.speaking.broadcast(src, trim(copytext(message, 3)), src.true_name)
return
if(!host)
if(chemicals >= 30)
to_chat(src, span("alien", "..You emit a psionic pulse with an encoded message.."))
var/list/nearby_mobs = list()
for(var/mob/living/LM in view(src, 1 + round(6 * (chemicals / max_chemicals))))
if(LM == src)
continue
if(!LM.stat)
nearby_mobs += LM
var/mob/living/speaker
if(nearby_mobs.len)
speaker = tgui_input_list(usr, "Choose a target speaker:", "Target Choice", nearby_mobs)
if(speaker)
log_admin("[src.ckey]/([src]) tried to force [speaker] to say: [message]")
message_admins("[src.ckey]/([src]) tried to force [speaker] to say: [message]")
speaker.say("[message]")
return
to_chat(src, span("alien", "..But nothing heard it.."))
else
to_chat(src, span("warning", "You have no host to speak to."))
return //No host, no audible speech.
to_chat(src, "You drop words into [host]'s mind: \"[message]\"")
to_chat(host, "Your own thoughts speak: \"[message]\"")
for(var/mob/M in player_list)
if(istype(M, /mob/new_player))
continue
else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
to_chat(M, "[src.true_name] whispers to [host], \"[message]\"")
/decl/mob_organ_names/borer
hit_zones = list("head", "central segment", "tail segment")
@@ -1,64 +1,64 @@
// Straight move from the old location, with the paths corrected.
/mob/living/captive_brain
name = "host brain"
real_name = "host brain"
universal_understand = 1
/mob/living/captive_brain/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if (src.client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, span_red("You cannot speak in IC (muted)."))
return
if(istype(src.loc, /mob/living/simple_mob/animal/borer))
message = sanitize(message)
if (!message)
return
log_say(message,src)
if (stat == 2)
return say_dead(message)
var/mob/living/simple_mob/animal/borer/B = src.loc
to_chat(src, "You whisper silently, \"[message]\"")
to_chat(B.host, "The captive mind of [src] whispers, \"[message]\"")
for (var/mob/M in player_list)
if (istype(M, /mob/new_player))
continue
else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
to_chat(M, "The captive mind of [src] whispers, \"[message]\"")
/mob/living/captive_brain/me_verb(message as text)
to_chat(src, "<span class='danger'>You cannot emote as a captive mind.</span>")
return
/mob/living/captive_brain/emote(var/message)
to_chat(src, "<span class='danger'>You cannot emote as a captive mind.</span>")
return
/mob/living/captive_brain/process_resist()
//Resisting control by an alien mind.
if(istype(src.loc, /mob/living/simple_mob/animal/borer))
var/mob/living/simple_mob/animal/borer/B = src.loc
var/mob/living/captive_brain/H = src
to_chat(H, "<span class='danger'>You begin doggedly resisting the parasite's control (this will take approximately sixty seconds).</span>")
to_chat(B.host, "<span class='danger'>You feel the captive mind of [src] begin to resist your control.</span>")
spawn(rand(200,250)+B.host.brainloss)
if(!B || !B.controlling) return
B.host.adjustBrainLoss(rand(0.1,0.5))
to_chat(H, "<span class='danger'>With an immense exertion of will, you regain control of your body!</span>")
to_chat(B.host, "<span class='danger'>You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you.</span>")
B.detatch()
verbs -= /mob/living/carbon/proc/release_control
verbs -= /mob/living/carbon/proc/punish_host
verbs -= /mob/living/carbon/proc/spawn_larvae
return
..()
// Straight move from the old location, with the paths corrected.
/mob/living/captive_brain
name = "host brain"
real_name = "host brain"
universal_understand = 1
/mob/living/captive_brain/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if (src.client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, span_red("You cannot speak in IC (muted)."))
return
if(istype(src.loc, /mob/living/simple_mob/animal/borer))
message = sanitize(message)
if (!message)
return
log_say(message,src)
if (stat == 2)
return say_dead(message)
var/mob/living/simple_mob/animal/borer/B = src.loc
to_chat(src, "You whisper silently, \"[message]\"")
to_chat(B.host, "The captive mind of [src] whispers, \"[message]\"")
for (var/mob/M in player_list)
if (istype(M, /mob/new_player))
continue
else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
to_chat(M, "The captive mind of [src] whispers, \"[message]\"")
/mob/living/captive_brain/me_verb(message as text)
to_chat(src, "<span class='danger'>You cannot emote as a captive mind.</span>")
return
/mob/living/captive_brain/emote(var/message)
to_chat(src, "<span class='danger'>You cannot emote as a captive mind.</span>")
return
/mob/living/captive_brain/process_resist()
//Resisting control by an alien mind.
if(istype(src.loc, /mob/living/simple_mob/animal/borer))
var/mob/living/simple_mob/animal/borer/B = src.loc
var/mob/living/captive_brain/H = src
to_chat(H, "<span class='danger'>You begin doggedly resisting the parasite's control (this will take approximately sixty seconds).</span>")
to_chat(B.host, "<span class='danger'>You feel the captive mind of [src] begin to resist your control.</span>")
spawn(rand(200,250)+B.host.brainloss)
if(!B || !B.controlling) return
B.host.adjustBrainLoss(rand(0.1,0.5))
to_chat(H, "<span class='danger'>With an immense exertion of will, you regain control of your body!</span>")
to_chat(B.host, "<span class='danger'>You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you.</span>")
B.detatch()
verbs -= /mob/living/carbon/proc/release_control
verbs -= /mob/living/carbon/proc/punish_host
verbs -= /mob/living/carbon/proc/spawn_larvae
return
..()
@@ -1,356 +1,356 @@
/mob/living/simple_mob/animal/borer/verb/release_host()
set category = "Abilities"
set name = "Release Host"
set desc = "Slither out of your host."
if(!host)
to_chat(src, "You are not inside a host body.")
return
if(stat)
to_chat(src, "You cannot leave your host in your current state.")
if(docile)
to_chat(src, span_blue("You are feeling far too docile to do that."))
return
if(!host || !src) return
to_chat(src, "You begin disconnecting from [host]'s synapses and prodding at their internal ear canal.")
if(!host.stat)
to_chat(host, "An odd, uncomfortable pressure begins to build inside your skull, behind your ear...")
spawn(100)
if(!host || !src) return
if(src.stat)
to_chat(src, "You cannot release your host in your current state.")
return
to_chat(src, "You wiggle out of [host]'s ear and plop to the ground.")
if(host.mind)
if(!host.stat)
to_chat(host, "<span class='danger'>Something slimy wiggles out of your ear and plops to the ground!</span>")
to_chat(host, "<span class='danger'>As though waking from a dream, you shake off the insidious mind control of the brain worm. Your thoughts are your own again.</span>")
detatch()
leave_host()
/mob/living/simple_mob/animal/borer/verb/infest()
set category = "Abilities"
set name = "Infest"
set desc = "Infest a suitable humanoid host."
if(host)
to_chat(src, "You are already within a host.")
return
if(stat)
to_chat(src, "You cannot infest a target in your current state.")
return
var/list/choices = list()
for(var/mob/living/carbon/C in view(1,src))
if(src.Adjacent(C))
choices += C
if(!choices.len)
to_chat(src, "There are no viable hosts within range...")
return
var/mob/living/carbon/M = tgui_input_list(src, "Who do you wish to infest?", "Target Choice", choices)
if(!M || !src) return
if(!(src.Adjacent(M))) return
if(M.has_brain_worms())
to_chat(src, "You cannot infest someone who is already infested!")
return
if(istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/H = M
var/obj/item/organ/external/E = H.organs_by_name[BP_HEAD]
if(!E || E.is_stump())
to_chat(src, "\The [H] does not have a head!")
if(!H.should_have_organ("brain"))
to_chat(src, "\The [H] does not seem to have an ear canal to breach.")
return
if(H.check_head_coverage())
to_chat(src, "You cannot get through that host's protective gear.")
return
to_chat(M, "Something slimy begins probing at the opening of your ear canal...")
to_chat(src, "You slither up [M] and begin probing at their ear canal...")
if(!do_after(src,30))
to_chat(src, "As [M] moves away, you are dislodged and fall to the ground.")
return
if(!M || !src) return
if(src.stat)
to_chat(src, "You cannot infest a target in your current state.")
return
if(M in view(1, src))
to_chat(src, "You wiggle into [M]'s ear.")
if(!M.stat)
to_chat(M, "Something disgusting and slimy wiggles into your ear!")
src.host = M
src.forceMove(M)
//Update their traitor status.
if(host.mind)
borers.add_antagonist_mind(host.mind, 1, borers.faction_role_text, borers.faction_welcome)
if(istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/H = M
var/obj/item/organ/I = H.internal_organs_by_name["brain"]
if(!I) // No brain organ, so the borer moves in and replaces it permanently.
replace_brain()
else
// If they're in normally, implant removal can get them out.
var/obj/item/organ/external/head = H.get_organ(BP_HEAD)
head.implants += src
return
else
to_chat(src, "They are no longer in range!")
return
/*
/mob/living/simple_mob/animal/borer/verb/devour_brain()
set category = "Abilities"
set name = "Devour Brain"
set desc = "Take permanent control of a dead host."
if(!host)
to_chat(src, "You are not inside a host body.")
return
if(host.stat != 2)
to_chat(src, "Your host is still alive.")
return
if(stat)
to_chat(src, "You cannot do that in your current state.")
if(docile)
to_chat(src, "<font color='blue'>You are feeling far too docile to do that.</font>")
return
to_chat(src, "<span class = 'danger'>It only takes a few moments to render the dead host brain down into a nutrient-rich slurry...</span>")
replace_brain()
*/
// BRAIN WORM ZOMBIES AAAAH.
/mob/living/simple_mob/animal/borer/proc/replace_brain()
var/mob/living/carbon/human/H = host
if(!istype(host))
to_chat(src, "This host does not have a suitable brain.")
return
to_chat(src, "<span class = 'danger'>You settle into the empty brainpan and begin to expand, fusing inextricably with the dead flesh of [H].</span>")
H.add_language("Cortical Link")
if(host.stat == 2)
H.verbs |= /mob/living/carbon/human/proc/jumpstart
H.verbs |= /mob/living/carbon/human/proc/psychic_whisper
H.verbs |= /mob/living/carbon/human/proc/tackle
if(antag)
H.verbs |= /mob/living/carbon/proc/spawn_larvae
if(H.client)
H.ghostize(0)
if(src.mind)
src.mind.special_role = "Borer Husk"
src.mind.transfer_to(host)
H.ChangeToHusk()
var/obj/item/organ/internal/borer/B = new(H)
H.internal_organs_by_name["brain"] = B
H.internal_organs |= B
var/obj/item/organ/external/affecting = H.get_organ(BP_HEAD)
affecting.implants -= src
var/s2h_id = src.computer_id
var/s2h_ip= src.lastKnownIP
src.computer_id = null
src.lastKnownIP = null
if(!H.computer_id)
H.computer_id = s2h_id
if(!H.lastKnownIP)
H.lastKnownIP = s2h_ip
/mob/living/simple_mob/animal/borer/verb/secrete_chemicals()
set category = "Abilities"
set name = "Secrete Chemicals"
set desc = "Push some chemicals into your host's bloodstream."
if(!host)
to_chat(src, "You are not inside a host body.")
return
if(stat)
to_chat(src, "You cannot secrete chemicals in your current state.")
if(docile)
to_chat(src, span_blue("You are feeling far too docile to do that."))
return
if(chemicals < 50)
to_chat(src, "You don't have enough chemicals!")
var/chem = tgui_input_list(usr, "Select a chemical to secrete.", "Chemicals", list("alkysine","bicaridine","hyperzine","tramadol"))
if(!chem || chemicals < 50 || !host || controlling || !src || stat) //Sanity check.
return
to_chat(src, span_red("<B>You squirt a measure of [chem] from your reservoirs into [host]'s bloodstream.</B>"))
host.reagents.add_reagent(chem, 10)
chemicals -= 50
/mob/living/simple_mob/animal/borer/verb/dominate_victim()
set category = "Abilities"
set name = "Paralyze Victim"
set desc = "Freeze the limbs of a potential host with supernatural fear."
if(world.time - used_dominate < 150)
to_chat(src, "You cannot use that ability again so soon.")
return
if(host)
to_chat(src, "You cannot do that from within a host body.")
return
if(src.stat)
to_chat(src, "You cannot do that in your current state.")
return
var/list/choices = list()
for(var/mob/living/carbon/C in view(3,src))
if(C.stat != 2)
choices += C
if(world.time - used_dominate < 150)
to_chat(src, "You cannot use that ability again so soon.")
return
var/mob/living/carbon/M = tgui_input_list(src, "Who do you wish to dominate?", "Target Choice", choices)
if(!M || !src) return
if(M.has_brain_worms())
to_chat(src, "You cannot infest someone who is already infested!")
return
to_chat(src, span_red("You focus your psychic lance on [M] and freeze their limbs with a wave of terrible dread."))
to_chat(M, span_red("You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing."))
M.Weaken(10)
used_dominate = world.time
/mob/living/simple_mob/animal/borer/verb/bond_brain()
set category = "Abilities"
set name = "Assume Control"
set desc = "Fully connect to the brain of your host."
if(!host)
to_chat(src, "You are not inside a host body.")
return
if(src.stat)
to_chat(src, "You cannot do that in your current state.")
return
if(docile)
to_chat(src, span_blue("You are feeling far too docile to do that."))
return
to_chat(src, "You begin delicately adjusting your connection to the host brain...")
spawn(100+(host.brainloss*5))
if(!host || !src || controlling)
return
else
to_chat(src, span_red("<B>You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system.</B>"))
to_chat(host, span_red("<B>You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours.</B>"))
host.add_language("Cortical Link")
// host -> brain
var/h2b_id = host.computer_id
var/h2b_ip= host.lastKnownIP
host.computer_id = null
host.lastKnownIP = null
qdel(host_brain)
host_brain = new(src)
host_brain.ckey = host.ckey
host_brain.name = host.name
if(!host_brain.computer_id)
host_brain.computer_id = h2b_id
if(!host_brain.lastKnownIP)
host_brain.lastKnownIP = h2b_ip
// self -> host
var/s2h_id = src.computer_id
var/s2h_ip= src.lastKnownIP
src.computer_id = null
src.lastKnownIP = null
host.ckey = src.ckey
if(!host.computer_id)
host.computer_id = s2h_id
if(!host.lastKnownIP)
host.lastKnownIP = s2h_ip
controlling = 1
host.verbs += /mob/living/carbon/proc/release_control
host.verbs += /mob/living/carbon/proc/punish_host
if(antag)
host.verbs += /mob/living/carbon/proc/spawn_larvae
return
/mob/living/carbon/human/proc/jumpstart()
set category = "Abilities"
set name = "Revive Host"
set desc = "Send a jolt of electricity through your host, reviving them."
if(stat != 2)
to_chat(usr, "Your host is already alive.")
return
verbs -= /mob/living/carbon/human/proc/jumpstart
visible_message("<span class='warning'>With a hideous, rattling moan, [src] shudders back to life!</span>")
rejuvenate()
restore_blood()
fixblood()
update_canmove()
/mob/living/simple_mob/animal/borer/verb/release_host()
set category = "Abilities"
set name = "Release Host"
set desc = "Slither out of your host."
if(!host)
to_chat(src, "You are not inside a host body.")
return
if(stat)
to_chat(src, "You cannot leave your host in your current state.")
if(docile)
to_chat(src, span_blue("You are feeling far too docile to do that."))
return
if(!host || !src) return
to_chat(src, "You begin disconnecting from [host]'s synapses and prodding at their internal ear canal.")
if(!host.stat)
to_chat(host, "An odd, uncomfortable pressure begins to build inside your skull, behind your ear...")
spawn(100)
if(!host || !src) return
if(src.stat)
to_chat(src, "You cannot release your host in your current state.")
return
to_chat(src, "You wiggle out of [host]'s ear and plop to the ground.")
if(host.mind)
if(!host.stat)
to_chat(host, "<span class='danger'>Something slimy wiggles out of your ear and plops to the ground!</span>")
to_chat(host, "<span class='danger'>As though waking from a dream, you shake off the insidious mind control of the brain worm. Your thoughts are your own again.</span>")
detatch()
leave_host()
/mob/living/simple_mob/animal/borer/verb/infest()
set category = "Abilities"
set name = "Infest"
set desc = "Infest a suitable humanoid host."
if(host)
to_chat(src, "You are already within a host.")
return
if(stat)
to_chat(src, "You cannot infest a target in your current state.")
return
var/list/choices = list()
for(var/mob/living/carbon/C in view(1,src))
if(src.Adjacent(C))
choices += C
if(!choices.len)
to_chat(src, "There are no viable hosts within range...")
return
var/mob/living/carbon/M = tgui_input_list(src, "Who do you wish to infest?", "Target Choice", choices)
if(!M || !src) return
if(!(src.Adjacent(M))) return
if(M.has_brain_worms())
to_chat(src, "You cannot infest someone who is already infested!")
return
if(istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/H = M
var/obj/item/organ/external/E = H.organs_by_name[BP_HEAD]
if(!E || E.is_stump())
to_chat(src, "\The [H] does not have a head!")
if(!H.should_have_organ("brain"))
to_chat(src, "\The [H] does not seem to have an ear canal to breach.")
return
if(H.check_head_coverage())
to_chat(src, "You cannot get through that host's protective gear.")
return
to_chat(M, "Something slimy begins probing at the opening of your ear canal...")
to_chat(src, "You slither up [M] and begin probing at their ear canal...")
if(!do_after(src,30))
to_chat(src, "As [M] moves away, you are dislodged and fall to the ground.")
return
if(!M || !src) return
if(src.stat)
to_chat(src, "You cannot infest a target in your current state.")
return
if(M in view(1, src))
to_chat(src, "You wiggle into [M]'s ear.")
if(!M.stat)
to_chat(M, "Something disgusting and slimy wiggles into your ear!")
src.host = M
src.forceMove(M)
//Update their traitor status.
if(host.mind)
borers.add_antagonist_mind(host.mind, 1, borers.faction_role_text, borers.faction_welcome)
if(istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/H = M
var/obj/item/organ/I = H.internal_organs_by_name["brain"]
if(!I) // No brain organ, so the borer moves in and replaces it permanently.
replace_brain()
else
// If they're in normally, implant removal can get them out.
var/obj/item/organ/external/head = H.get_organ(BP_HEAD)
head.implants += src
return
else
to_chat(src, "They are no longer in range!")
return
/*
/mob/living/simple_mob/animal/borer/verb/devour_brain()
set category = "Abilities"
set name = "Devour Brain"
set desc = "Take permanent control of a dead host."
if(!host)
to_chat(src, "You are not inside a host body.")
return
if(host.stat != 2)
to_chat(src, "Your host is still alive.")
return
if(stat)
to_chat(src, "You cannot do that in your current state.")
if(docile)
to_chat(src, "<font color='blue'>You are feeling far too docile to do that.</font>")
return
to_chat(src, "<span class = 'danger'>It only takes a few moments to render the dead host brain down into a nutrient-rich slurry...</span>")
replace_brain()
*/
// BRAIN WORM ZOMBIES AAAAH.
/mob/living/simple_mob/animal/borer/proc/replace_brain()
var/mob/living/carbon/human/H = host
if(!istype(host))
to_chat(src, "This host does not have a suitable brain.")
return
to_chat(src, "<span class = 'danger'>You settle into the empty brainpan and begin to expand, fusing inextricably with the dead flesh of [H].</span>")
H.add_language("Cortical Link")
if(host.stat == 2)
H.verbs |= /mob/living/carbon/human/proc/jumpstart
H.verbs |= /mob/living/carbon/human/proc/psychic_whisper
H.verbs |= /mob/living/carbon/human/proc/tackle
if(antag)
H.verbs |= /mob/living/carbon/proc/spawn_larvae
if(H.client)
H.ghostize(0)
if(src.mind)
src.mind.special_role = "Borer Husk"
src.mind.transfer_to(host)
H.ChangeToHusk()
var/obj/item/organ/internal/borer/B = new(H)
H.internal_organs_by_name["brain"] = B
H.internal_organs |= B
var/obj/item/organ/external/affecting = H.get_organ(BP_HEAD)
affecting.implants -= src
var/s2h_id = src.computer_id
var/s2h_ip= src.lastKnownIP
src.computer_id = null
src.lastKnownIP = null
if(!H.computer_id)
H.computer_id = s2h_id
if(!H.lastKnownIP)
H.lastKnownIP = s2h_ip
/mob/living/simple_mob/animal/borer/verb/secrete_chemicals()
set category = "Abilities"
set name = "Secrete Chemicals"
set desc = "Push some chemicals into your host's bloodstream."
if(!host)
to_chat(src, "You are not inside a host body.")
return
if(stat)
to_chat(src, "You cannot secrete chemicals in your current state.")
if(docile)
to_chat(src, span_blue("You are feeling far too docile to do that."))
return
if(chemicals < 50)
to_chat(src, "You don't have enough chemicals!")
var/chem = tgui_input_list(usr, "Select a chemical to secrete.", "Chemicals", list("alkysine","bicaridine","hyperzine","tramadol"))
if(!chem || chemicals < 50 || !host || controlling || !src || stat) //Sanity check.
return
to_chat(src, span_red("<B>You squirt a measure of [chem] from your reservoirs into [host]'s bloodstream.</B>"))
host.reagents.add_reagent(chem, 10)
chemicals -= 50
/mob/living/simple_mob/animal/borer/verb/dominate_victim()
set category = "Abilities"
set name = "Paralyze Victim"
set desc = "Freeze the limbs of a potential host with supernatural fear."
if(world.time - used_dominate < 150)
to_chat(src, "You cannot use that ability again so soon.")
return
if(host)
to_chat(src, "You cannot do that from within a host body.")
return
if(src.stat)
to_chat(src, "You cannot do that in your current state.")
return
var/list/choices = list()
for(var/mob/living/carbon/C in view(3,src))
if(C.stat != 2)
choices += C
if(world.time - used_dominate < 150)
to_chat(src, "You cannot use that ability again so soon.")
return
var/mob/living/carbon/M = tgui_input_list(src, "Who do you wish to dominate?", "Target Choice", choices)
if(!M || !src) return
if(M.has_brain_worms())
to_chat(src, "You cannot infest someone who is already infested!")
return
to_chat(src, span_red("You focus your psychic lance on [M] and freeze their limbs with a wave of terrible dread."))
to_chat(M, span_red("You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing."))
M.Weaken(10)
used_dominate = world.time
/mob/living/simple_mob/animal/borer/verb/bond_brain()
set category = "Abilities"
set name = "Assume Control"
set desc = "Fully connect to the brain of your host."
if(!host)
to_chat(src, "You are not inside a host body.")
return
if(src.stat)
to_chat(src, "You cannot do that in your current state.")
return
if(docile)
to_chat(src, span_blue("You are feeling far too docile to do that."))
return
to_chat(src, "You begin delicately adjusting your connection to the host brain...")
spawn(100+(host.brainloss*5))
if(!host || !src || controlling)
return
else
to_chat(src, span_red("<B>You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system.</B>"))
to_chat(host, span_red("<B>You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours.</B>"))
host.add_language("Cortical Link")
// host -> brain
var/h2b_id = host.computer_id
var/h2b_ip= host.lastKnownIP
host.computer_id = null
host.lastKnownIP = null
qdel(host_brain)
host_brain = new(src)
host_brain.ckey = host.ckey
host_brain.name = host.name
if(!host_brain.computer_id)
host_brain.computer_id = h2b_id
if(!host_brain.lastKnownIP)
host_brain.lastKnownIP = h2b_ip
// self -> host
var/s2h_id = src.computer_id
var/s2h_ip= src.lastKnownIP
src.computer_id = null
src.lastKnownIP = null
host.ckey = src.ckey
if(!host.computer_id)
host.computer_id = s2h_id
if(!host.lastKnownIP)
host.lastKnownIP = s2h_ip
controlling = 1
host.verbs += /mob/living/carbon/proc/release_control
host.verbs += /mob/living/carbon/proc/punish_host
if(antag)
host.verbs += /mob/living/carbon/proc/spawn_larvae
return
/mob/living/carbon/human/proc/jumpstart()
set category = "Abilities"
set name = "Revive Host"
set desc = "Send a jolt of electricity through your host, reviving them."
if(stat != 2)
to_chat(usr, "Your host is already alive.")
return
verbs -= /mob/living/carbon/human/proc/jumpstart
visible_message("<span class='warning'>With a hideous, rattling moan, [src] shudders back to life!</span>")
rejuvenate()
restore_blood()
fixblood()
update_canmove()
@@ -1,56 +1,56 @@
//Look Sir, free crabs!
/mob/living/simple_mob/animal/passive/crab
name = "crab"
desc = "A hard-shelled crustacean. Seems quite content to lounge around all the time."
tt_desc = "E Cancer bellianus"
faction = "crabs"
icon_state = "crab"
icon_living = "crab"
icon_dead = "crab_dead"
mob_size = MOB_SMALL
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "stomps"
friendly = "pinches"
organ_names = /decl/mob_organ_names/crab
meat_type = /obj/item/weapon/reagent_containers/food/snacks/crabmeat
meat_amount = 3
say_list_type = /datum/say_list/crab
//COFFEE! SQUEEEEEEEEE!
/mob/living/simple_mob/animal/passive/crab/Coffee
name = "Coffee"
real_name = "Coffee"
desc = "It's Coffee, the other pet!"
// Sif!
/datum/category_item/catalogue/fauna/sif_crab
name = "Sivian Fauna - Shelf Crab"
desc = "Classification: S Ocypode glacian\
<br><br>\
A small crustacean sometimes considered a pest to Sivian fisheries, \
as the creatures often tend to ignore non-native fish species when feeding. This \
results in an unfortunate advantage for invasive species. \
<br>\
Otherwise, these animals are enjoyed as a reliable source of high-grade meat."
value = CATALOGUER_REWARD_EASY
/mob/living/simple_mob/animal/passive/crab/sif
icon = 'icons/mob/fish.dmi'
tt_desc = "S Ocypode glacian"
catalogue_data = list(/datum/category_item/catalogue/fauna/sif_crab)
/mob/living/simple_mob/animal/passive/crab/sif/Initialize()
. = ..()
adjust_scale(rand(5,12) / 10)
/decl/mob_organ_names/crab
//Look Sir, free crabs!
/mob/living/simple_mob/animal/passive/crab
name = "crab"
desc = "A hard-shelled crustacean. Seems quite content to lounge around all the time."
tt_desc = "E Cancer bellianus"
faction = "crabs"
icon_state = "crab"
icon_living = "crab"
icon_dead = "crab_dead"
mob_size = MOB_SMALL
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "stomps"
friendly = "pinches"
organ_names = /decl/mob_organ_names/crab
meat_type = /obj/item/weapon/reagent_containers/food/snacks/crabmeat
meat_amount = 3
say_list_type = /datum/say_list/crab
//COFFEE! SQUEEEEEEEEE!
/mob/living/simple_mob/animal/passive/crab/Coffee
name = "Coffee"
real_name = "Coffee"
desc = "It's Coffee, the other pet!"
// Sif!
/datum/category_item/catalogue/fauna/sif_crab
name = "Sivian Fauna - Shelf Crab"
desc = "Classification: S Ocypode glacian\
<br><br>\
A small crustacean sometimes considered a pest to Sivian fisheries, \
as the creatures often tend to ignore non-native fish species when feeding. This \
results in an unfortunate advantage for invasive species. \
<br>\
Otherwise, these animals are enjoyed as a reliable source of high-grade meat."
value = CATALOGUER_REWARD_EASY
/mob/living/simple_mob/animal/passive/crab/sif
icon = 'icons/mob/fish.dmi'
tt_desc = "S Ocypode glacian"
catalogue_data = list(/datum/category_item/catalogue/fauna/sif_crab)
/mob/living/simple_mob/animal/passive/crab/sif/Initialize()
. = ..()
adjust_scale(rand(5,12) / 10)
/decl/mob_organ_names/crab
hit_zones = list("cephalothorax", "abdomen", "left walking legs", "right walking legs", "left swimming legs", "right swimming legs", "left pincer", "right pincer")

Some files were not shown because too many files have changed in this diff Show More