mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-17 10:05:27 +01:00
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 commitafbdd1d844. * 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 commitde22ad375d. * Attempt to normalize example.yml (and another file I guess) * Try again
This commit is contained in:
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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"].")
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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()*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
*/
|
||||
@@ -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)
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
@@ -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 = ""
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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
@@ -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>")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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))
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
/mob/living/silicon/Login()
|
||||
SetSleeping(0)
|
||||
/mob/living/silicon/Login()
|
||||
SetSleeping(0)
|
||||
..()
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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] </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] </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] </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] </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] </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] </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] </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] </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
|
||||
|
||||
@@ -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
|
||||
..()
|
||||
|
||||
@@ -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"
|
||||
@@ -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.")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user