mirror of
https://github.com/Yawn-Wider/YWPolarisVore.git
synced 2026-08-26 22:46:47 +01:00
Merge branch 'release' of https://github.com/VOREStation/VOREStation into upstream-update
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)
|
||||
*/
|
||||
|
||||
@@ -38,9 +38,6 @@
|
||||
|
||||
raw_msg += (piece + " ")
|
||||
|
||||
if(!speaker.client)
|
||||
piece = "<span class='npcsay'>[piece]</span>"
|
||||
|
||||
//HTML formatting
|
||||
if(!SP.speaking) // Catch the most generic case first
|
||||
piece = "<span class='message body'>[piece]</span>"
|
||||
@@ -125,7 +122,7 @@
|
||||
if(check_mentioned(multilingual_to_message(message_pieces)) && is_preference_enabled(/datum/client_preference/check_mention))
|
||||
message_to_send = "<font size='3'><b>[message_to_send]</b></font>"
|
||||
|
||||
on_hear_say(message_to_send)
|
||||
on_hear_say(message_to_send, speaker)
|
||||
create_chat_message(speaker, combined["raw"], italics, list())
|
||||
|
||||
if(speech_sound && (get_dist(speaker, src) <= world.view && z == speaker.z))
|
||||
@@ -140,25 +137,29 @@
|
||||
if(has_AI()) // Won't happen if no ai_holder exists or there's a player inside w/o autopilot active.
|
||||
ai_holder.on_hear_say(speaker, multilingual_to_message(message_pieces))
|
||||
|
||||
/mob/proc/on_hear_say(var/message)
|
||||
/mob/proc/on_hear_say(var/message, var/mob/speaker = null)
|
||||
var/time = say_timestamp()
|
||||
if(client)
|
||||
if(client.prefs.chat_timestamp)
|
||||
to_chat(src, "<span class='game say'>[time] [message]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='game say'>[message]</span>")
|
||||
message = "[time] [message]"
|
||||
message = "<span class='game say'>[message]</span>"
|
||||
if(speaker && !speaker.client)
|
||||
message = "<span class='npcsay'>[message]</span>"
|
||||
to_chat(src, message)
|
||||
else if(teleop)
|
||||
to_chat(teleop, "<span class='game say'>[create_text_tag("body", "BODY:", teleop.client)][message]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='game say'>[message]</span>")
|
||||
|
||||
/mob/living/silicon/on_hear_say(var/message)
|
||||
/mob/living/silicon/on_hear_say(var/message, var/mob/speaker = null)
|
||||
var/time = say_timestamp()
|
||||
if(client)
|
||||
if(client.prefs.chat_timestamp)
|
||||
to_chat(src, "<span class='game say'>[time] [message]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='game say'>[message]</span>")
|
||||
message = "[time] [message]"
|
||||
message = "<span class='game say'>[message]</span>"
|
||||
if(speaker && !speaker.client)
|
||||
message = "<span class='npcsay'>[message]</span>"
|
||||
to_chat(src, message)
|
||||
else if(teleop)
|
||||
to_chat(teleop, "<span class='game say'>[create_text_tag("body", "BODY:", teleop.client)][message]</span>")
|
||||
else
|
||||
@@ -330,4 +331,6 @@
|
||||
name = speaker.voice_name
|
||||
|
||||
var/rendered = "<span class='game say'><span class='name'>[name]</span> [message]</span>"
|
||||
if(!speaker.client)
|
||||
rendered = "<span class='npcsay'>[rendered]</span>"
|
||||
to_chat(src, rendered)
|
||||
|
||||
+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)
|
||||
|
||||
@@ -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,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
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,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,176 +1,176 @@
|
||||
/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()
|
||||
|
||||
@@ -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,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")
|
||||
@@ -1,328 +1,328 @@
|
||||
// Different types of fish! They are all subtypes of this tho
|
||||
/datum/category_item/catalogue/fauna/invasive_fish
|
||||
name = "Invasive Fauna - Fish"
|
||||
desc = "This fish is considered an invasive species according \
|
||||
to Sivian wildlife regulations. Removal or relocation is advised."
|
||||
value = CATALOGUER_REWARD_TRIVIAL
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish
|
||||
name = "fish"
|
||||
desc = "Its a fishy. No touchy fishy."
|
||||
icon = 'icons/mob/fish.dmi'
|
||||
item_state = "fish"
|
||||
|
||||
//catalogue_data = list(/datum/category_item/catalogue/fauna/invasive_fish) //TODO: write non-sif lore
|
||||
|
||||
mob_size = MOB_SMALL
|
||||
// So fish are actually underwater.
|
||||
plane = TURF_PLANE
|
||||
layer = UNDERWATER_LAYER
|
||||
|
||||
organ_names = /decl/mob_organ_names/fish
|
||||
|
||||
holder_type = /obj/item/weapon/holder/fish
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/fish
|
||||
meat_amount = 3
|
||||
|
||||
// By default they can be in any water turf. Subtypes might restrict to deep/shallow etc
|
||||
var/global/list/suitable_turf_types = list(
|
||||
/turf/simulated/floor/beach/water,
|
||||
/turf/simulated/floor/beach/coastline,
|
||||
/turf/simulated/floor/holofloor/beach/water,
|
||||
/turf/simulated/floor/holofloor/beach/coastline,
|
||||
/turf/simulated/floor/water
|
||||
)
|
||||
|
||||
var/randomize_location = TRUE
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/Initialize()
|
||||
. = ..()
|
||||
|
||||
if(!default_pixel_x && randomize_location)
|
||||
default_pixel_x = rand(-12, 12)
|
||||
|
||||
if(!default_pixel_y && randomize_location)
|
||||
default_pixel_y = rand(-6, 10)
|
||||
|
||||
// Makes the AI unable to willingly go on land.
|
||||
/mob/living/simple_mob/animal/passive/fish/IMove(turf/newloc, safety = TRUE)
|
||||
if(is_type_in_list(newloc, suitable_turf_types))
|
||||
return ..() // Procede as normal.
|
||||
return MOVEMENT_FAILED // Don't leave the water!
|
||||
|
||||
// Take damage if we are not in water
|
||||
/mob/living/simple_mob/animal/passive/fish/handle_breathing()
|
||||
if(istype(loc, /obj/item/glass_jar/fish))
|
||||
var/obj/item/glass_jar/fish/F = loc
|
||||
if(F.filled)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && !is_type_in_list(T, suitable_turf_types))
|
||||
if(prob(50))
|
||||
say(pick("Blub", "Glub", "Burble"))
|
||||
adjustBruteLoss(unsuitable_atoms_damage)
|
||||
|
||||
// Subtypes.
|
||||
/mob/living/simple_mob/animal/passive/fish/bass
|
||||
name = "bass"
|
||||
tt_desc = "E Micropterus notius"
|
||||
icon_state = "bass-swim"
|
||||
icon_living = "bass-swim"
|
||||
icon_dead = "bass-dead"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/trout
|
||||
name = "trout"
|
||||
tt_desc = "E Salmo trutta"
|
||||
icon_state = "trout-swim"
|
||||
icon_living = "trout-swim"
|
||||
icon_dead = "trout-dead"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/salmon
|
||||
name = "salmon"
|
||||
tt_desc = "E Oncorhynchus nerka"
|
||||
icon_state = "salmon-swim"
|
||||
icon_living = "salmon-swim"
|
||||
icon_dead = "salmon-dead"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/perch
|
||||
name = "perch"
|
||||
tt_desc = "E Perca flavescens"
|
||||
icon_state = "perch-swim"
|
||||
icon_living = "perch-swim"
|
||||
icon_dead = "perch-dead"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/pike
|
||||
name = "pike"
|
||||
tt_desc = "E Esox aquitanicus"
|
||||
icon_state = "pike-swim"
|
||||
icon_living = "pike-swim"
|
||||
icon_dead = "pike-dead"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/koi
|
||||
name = "koi"
|
||||
tt_desc = "E Cyprinus rubrofuscus"
|
||||
icon_state = "koi-swim"
|
||||
icon_living = "koi-swim"
|
||||
icon_dead = "koi-dead"
|
||||
|
||||
/datum/category_item/catalogue/fauna/javelin
|
||||
name = "Sivian Fauna - Javelin Shark"
|
||||
desc = "Classification: S Cetusan minimalix\
|
||||
<br><br>\
|
||||
A small breed of fatty shark native to the waters near the Ullran Expanse.\
|
||||
The creatures are not known to attack humans or larger animals, possibly \
|
||||
due to their size. It is speculated that they are actually scavengers, \
|
||||
as they are most commonly found near the gulf floor. \
|
||||
<br>\
|
||||
The Javelin's reproductive cycle only recurs between three and four \
|
||||
Sivian years. \
|
||||
<br>\
|
||||
These creatures are considered a protected species, and thus require an \
|
||||
up-to-date license to be hunted."
|
||||
value = CATALOGUER_REWARD_EASY
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/javelin
|
||||
name = "javelin"
|
||||
tt_desc = "S Cetusan minimalix"
|
||||
icon_state = "javelin-swim"
|
||||
icon_living = "javelin-swim"
|
||||
icon_dead = "javelin-dead"
|
||||
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/javelin)
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/fish/sif
|
||||
|
||||
/datum/category_item/catalogue/fauna/icebass
|
||||
name = "Sivian Fauna - Glitter Bass"
|
||||
desc = "Classification: X Micropterus notius crotux\
|
||||
<br><br>\
|
||||
Initially a genetically engineered hybrid of the common Earth bass and \
|
||||
the Sivian Rock-Fish. These were designed to deal with the invasive \
|
||||
fish species, however to their creators' dismay, they instead \
|
||||
began to form their own passive niche. \
|
||||
<br>\
|
||||
Due to the brilliant reflective scales earning them their name, the \
|
||||
animals pose a specific issue for Sivian animals relying on \
|
||||
bioluminesence to aid in their hunt. \
|
||||
<br>\
|
||||
Despite their beauty, they are considered an invasive species."
|
||||
value = CATALOGUER_REWARD_EASY
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/icebass
|
||||
name = "glitter bass"
|
||||
tt_desc = "X Micropterus notius crotux"
|
||||
icon_state = "sifbass-swim"
|
||||
icon_living = "sifbass-swim"
|
||||
icon_dead = "sifbass-dead"
|
||||
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/icebass)
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/fish/sif
|
||||
|
||||
var/max_red = 150
|
||||
var/min_red = 50
|
||||
|
||||
var/max_blue = 255
|
||||
var/min_blue = 50
|
||||
|
||||
var/max_green = 150
|
||||
var/min_green = 50
|
||||
|
||||
var/dorsal_color = "#FFFFFF"
|
||||
var/belly_color = "#FFFFFF"
|
||||
|
||||
var/image/dorsal_image
|
||||
var/image/belly_image
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/icebass/Initialize()
|
||||
. = ..()
|
||||
dorsal_color = rgb(rand(min_red,max_red), rand(min_green,max_green), rand(min_blue,max_blue))
|
||||
belly_color = rgb(rand(min_red,max_red), rand(min_green,max_green), rand(min_blue,max_blue))
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/icebass/update_icon()
|
||||
cut_overlays()
|
||||
..()
|
||||
|
||||
if(!dorsal_image)
|
||||
dorsal_image = image(icon, "[icon_state]_mask-body")
|
||||
if(!belly_image)
|
||||
belly_image = image(icon, "[icon_state]_mask-belly")
|
||||
|
||||
dorsal_image.icon_state = "[icon_state]_mask-body"
|
||||
belly_image.icon_state = "[icon_state]_mask-belly"
|
||||
|
||||
dorsal_image.color = dorsal_color
|
||||
belly_image.color = belly_color
|
||||
|
||||
add_overlay(dorsal_image)
|
||||
add_overlay(belly_image)
|
||||
|
||||
/datum/category_item/catalogue/fauna/rockfish
|
||||
name = "Sivian Fauna - Rock Puffer"
|
||||
desc = "Classification: S Tetraodontidae scopulix\
|
||||
<br><br>\
|
||||
A species strangely resembling the puffer-fish of Earth. These \
|
||||
creatures do not use toxic spines to protect themselves, instead \
|
||||
utilizing an incredibly durable exoskeleton that is molded by the \
|
||||
expansion of its ventral fluid bladders. \
|
||||
<br>\
|
||||
Rock Puffers or 'Rock-fish' are often host to smaller creatures which \
|
||||
maneuver their way into the gap between the fish's body and shell. \
|
||||
<br>\
|
||||
The species is also capable of pulling its vibrantly colored head into \
|
||||
the safer confines of its shell, the action being utilized in their \
|
||||
attempts to find a mate."
|
||||
value = CATALOGUER_REWARD_EASY
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/rockfish
|
||||
name = "rock-fish"
|
||||
tt_desc = "S Tetraodontidae scopulix"
|
||||
icon_state = "rockfish-swim"
|
||||
icon_living = "rockfish-swim"
|
||||
icon_dead = "rockfish-dead"
|
||||
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/rockfish)
|
||||
|
||||
armor = list(
|
||||
"melee" = 90,
|
||||
"bullet" = 50,
|
||||
"laser" = -15,
|
||||
"energy" = 30,
|
||||
"bomb" = 30,
|
||||
"bio" = 100,
|
||||
"rad" = 100)
|
||||
|
||||
var/max_red = 255
|
||||
var/min_red = 50
|
||||
|
||||
var/max_blue = 255
|
||||
var/min_blue = 50
|
||||
|
||||
var/max_green = 255
|
||||
var/min_green = 50
|
||||
|
||||
var/head_color = "#FFFFFF"
|
||||
|
||||
var/image/head_image
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/fish/sif
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/rockfish/Initialize()
|
||||
. = ..()
|
||||
head_color = rgb(rand(min_red,max_red), rand(min_green,max_green), rand(min_blue,max_blue))
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/rockfish/update_icon()
|
||||
cut_overlays()
|
||||
..()
|
||||
if(!head_image)
|
||||
head_image = image(icon, "[icon_state]_mask")
|
||||
|
||||
head_image.icon_state = "[icon_state]_mask"
|
||||
|
||||
head_image.color = head_color
|
||||
|
||||
add_overlay(head_image)
|
||||
|
||||
/datum/category_item/catalogue/fauna/solarfish
|
||||
name = "Sivian Fauna - Solar Fin"
|
||||
desc = "Classification: S Exocoetidae solarin\
|
||||
<br><br>\
|
||||
An incredibly rare species of Sivian fish.\
|
||||
The solar-fin missile fish is a specialized omnivore capable of \
|
||||
catching insects or small birds venturing too close to the water's \
|
||||
surface. \
|
||||
<br>\
|
||||
The glimmering fins of the solar-fin are actually biofluorescent, \
|
||||
'charged' by the creature basking at the surface of the water, most \
|
||||
commonly by the edge of an ice-shelf, as a rapid means of cover. \
|
||||
<br>\
|
||||
These creatures are considered a protected species, and thus require an \
|
||||
up-to-date license to be hunted."
|
||||
value = CATALOGUER_REWARD_HARD
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/solarfish
|
||||
name = "sun-fin"
|
||||
tt_desc = "S Exocoetidae solarin"
|
||||
icon_state = "solarfin-swim"
|
||||
icon_living = "solarfin-swim"
|
||||
icon_dead = "solarfin-dead"
|
||||
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/solarfish)
|
||||
|
||||
has_eye_glow = TRUE
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/fish/sif
|
||||
|
||||
/datum/category_item/catalogue/fauna/murkin
|
||||
name = "Sivian Fauna - Murkfish"
|
||||
desc = "Classification: S Perca lutux\
|
||||
<br><br>\
|
||||
A small, Sivian fish most known for its bland-ness.\
|
||||
<br>\
|
||||
The species is incredibly close in appearance to the Earth \
|
||||
perch, aside from its incredibly tall dorsal fin. The animals use \
|
||||
the fin to assess the wind direction while near the surface. \
|
||||
<br>\
|
||||
The murkfish earns its name from the fact its dense meat tastes like mud \
|
||||
thanks to a specially formed protein, most likely an adaptation to \
|
||||
protect the species from predation."
|
||||
value = CATALOGUER_REWARD_TRIVIAL
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/murkin
|
||||
name = "murkin"
|
||||
tt_desc = "S Perca lutux"
|
||||
|
||||
icon_state = "murkin-swim"
|
||||
icon_living = "murkin-swim"
|
||||
icon_dead = "murkin-dead"
|
||||
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/murkin)
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/sif/murkfish
|
||||
|
||||
/decl/mob_organ_names/fish
|
||||
// Different types of fish! They are all subtypes of this tho
|
||||
/datum/category_item/catalogue/fauna/invasive_fish
|
||||
name = "Invasive Fauna - Fish"
|
||||
desc = "This fish is considered an invasive species according \
|
||||
to Sivian wildlife regulations. Removal or relocation is advised."
|
||||
value = CATALOGUER_REWARD_TRIVIAL
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish
|
||||
name = "fish"
|
||||
desc = "Its a fishy. No touchy fishy."
|
||||
icon = 'icons/mob/fish.dmi'
|
||||
item_state = "fish"
|
||||
|
||||
//catalogue_data = list(/datum/category_item/catalogue/fauna/invasive_fish) //TODO: write non-sif lore
|
||||
|
||||
mob_size = MOB_SMALL
|
||||
// So fish are actually underwater.
|
||||
plane = TURF_PLANE
|
||||
layer = UNDERWATER_LAYER
|
||||
|
||||
organ_names = /decl/mob_organ_names/fish
|
||||
|
||||
holder_type = /obj/item/weapon/holder/fish
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/fish
|
||||
meat_amount = 3
|
||||
|
||||
// By default they can be in any water turf. Subtypes might restrict to deep/shallow etc
|
||||
var/global/list/suitable_turf_types = list(
|
||||
/turf/simulated/floor/beach/water,
|
||||
/turf/simulated/floor/beach/coastline,
|
||||
/turf/simulated/floor/holofloor/beach/water,
|
||||
/turf/simulated/floor/holofloor/beach/coastline,
|
||||
/turf/simulated/floor/water
|
||||
)
|
||||
|
||||
var/randomize_location = TRUE
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/Initialize()
|
||||
. = ..()
|
||||
|
||||
if(!default_pixel_x && randomize_location)
|
||||
default_pixel_x = rand(-12, 12)
|
||||
|
||||
if(!default_pixel_y && randomize_location)
|
||||
default_pixel_y = rand(-6, 10)
|
||||
|
||||
// Makes the AI unable to willingly go on land.
|
||||
/mob/living/simple_mob/animal/passive/fish/IMove(turf/newloc, safety = TRUE)
|
||||
if(is_type_in_list(newloc, suitable_turf_types))
|
||||
return ..() // Procede as normal.
|
||||
return MOVEMENT_FAILED // Don't leave the water!
|
||||
|
||||
// Take damage if we are not in water
|
||||
/mob/living/simple_mob/animal/passive/fish/handle_breathing()
|
||||
if(istype(loc, /obj/item/glass_jar/fish))
|
||||
var/obj/item/glass_jar/fish/F = loc
|
||||
if(F.filled)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && !is_type_in_list(T, suitable_turf_types))
|
||||
if(prob(50))
|
||||
say(pick("Blub", "Glub", "Burble"))
|
||||
adjustBruteLoss(unsuitable_atoms_damage)
|
||||
|
||||
// Subtypes.
|
||||
/mob/living/simple_mob/animal/passive/fish/bass
|
||||
name = "bass"
|
||||
tt_desc = "E Micropterus notius"
|
||||
icon_state = "bass-swim"
|
||||
icon_living = "bass-swim"
|
||||
icon_dead = "bass-dead"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/trout
|
||||
name = "trout"
|
||||
tt_desc = "E Salmo trutta"
|
||||
icon_state = "trout-swim"
|
||||
icon_living = "trout-swim"
|
||||
icon_dead = "trout-dead"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/salmon
|
||||
name = "salmon"
|
||||
tt_desc = "E Oncorhynchus nerka"
|
||||
icon_state = "salmon-swim"
|
||||
icon_living = "salmon-swim"
|
||||
icon_dead = "salmon-dead"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/perch
|
||||
name = "perch"
|
||||
tt_desc = "E Perca flavescens"
|
||||
icon_state = "perch-swim"
|
||||
icon_living = "perch-swim"
|
||||
icon_dead = "perch-dead"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/pike
|
||||
name = "pike"
|
||||
tt_desc = "E Esox aquitanicus"
|
||||
icon_state = "pike-swim"
|
||||
icon_living = "pike-swim"
|
||||
icon_dead = "pike-dead"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/koi
|
||||
name = "koi"
|
||||
tt_desc = "E Cyprinus rubrofuscus"
|
||||
icon_state = "koi-swim"
|
||||
icon_living = "koi-swim"
|
||||
icon_dead = "koi-dead"
|
||||
|
||||
/datum/category_item/catalogue/fauna/javelin
|
||||
name = "Sivian Fauna - Javelin Shark"
|
||||
desc = "Classification: S Cetusan minimalix\
|
||||
<br><br>\
|
||||
A small breed of fatty shark native to the waters near the Ullran Expanse.\
|
||||
The creatures are not known to attack humans or larger animals, possibly \
|
||||
due to their size. It is speculated that they are actually scavengers, \
|
||||
as they are most commonly found near the gulf floor. \
|
||||
<br>\
|
||||
The Javelin's reproductive cycle only recurs between three and four \
|
||||
Sivian years. \
|
||||
<br>\
|
||||
These creatures are considered a protected species, and thus require an \
|
||||
up-to-date license to be hunted."
|
||||
value = CATALOGUER_REWARD_EASY
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/javelin
|
||||
name = "javelin"
|
||||
tt_desc = "S Cetusan minimalix"
|
||||
icon_state = "javelin-swim"
|
||||
icon_living = "javelin-swim"
|
||||
icon_dead = "javelin-dead"
|
||||
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/javelin)
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/fish/sif
|
||||
|
||||
/datum/category_item/catalogue/fauna/icebass
|
||||
name = "Sivian Fauna - Glitter Bass"
|
||||
desc = "Classification: X Micropterus notius crotux\
|
||||
<br><br>\
|
||||
Initially a genetically engineered hybrid of the common Earth bass and \
|
||||
the Sivian Rock-Fish. These were designed to deal with the invasive \
|
||||
fish species, however to their creators' dismay, they instead \
|
||||
began to form their own passive niche. \
|
||||
<br>\
|
||||
Due to the brilliant reflective scales earning them their name, the \
|
||||
animals pose a specific issue for Sivian animals relying on \
|
||||
bioluminesence to aid in their hunt. \
|
||||
<br>\
|
||||
Despite their beauty, they are considered an invasive species."
|
||||
value = CATALOGUER_REWARD_EASY
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/icebass
|
||||
name = "glitter bass"
|
||||
tt_desc = "X Micropterus notius crotux"
|
||||
icon_state = "sifbass-swim"
|
||||
icon_living = "sifbass-swim"
|
||||
icon_dead = "sifbass-dead"
|
||||
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/icebass)
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/fish/sif
|
||||
|
||||
var/max_red = 150
|
||||
var/min_red = 50
|
||||
|
||||
var/max_blue = 255
|
||||
var/min_blue = 50
|
||||
|
||||
var/max_green = 150
|
||||
var/min_green = 50
|
||||
|
||||
var/dorsal_color = "#FFFFFF"
|
||||
var/belly_color = "#FFFFFF"
|
||||
|
||||
var/image/dorsal_image
|
||||
var/image/belly_image
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/icebass/Initialize()
|
||||
. = ..()
|
||||
dorsal_color = rgb(rand(min_red,max_red), rand(min_green,max_green), rand(min_blue,max_blue))
|
||||
belly_color = rgb(rand(min_red,max_red), rand(min_green,max_green), rand(min_blue,max_blue))
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/icebass/update_icon()
|
||||
cut_overlays()
|
||||
..()
|
||||
|
||||
if(!dorsal_image)
|
||||
dorsal_image = image(icon, "[icon_state]_mask-body")
|
||||
if(!belly_image)
|
||||
belly_image = image(icon, "[icon_state]_mask-belly")
|
||||
|
||||
dorsal_image.icon_state = "[icon_state]_mask-body"
|
||||
belly_image.icon_state = "[icon_state]_mask-belly"
|
||||
|
||||
dorsal_image.color = dorsal_color
|
||||
belly_image.color = belly_color
|
||||
|
||||
add_overlay(dorsal_image)
|
||||
add_overlay(belly_image)
|
||||
|
||||
/datum/category_item/catalogue/fauna/rockfish
|
||||
name = "Sivian Fauna - Rock Puffer"
|
||||
desc = "Classification: S Tetraodontidae scopulix\
|
||||
<br><br>\
|
||||
A species strangely resembling the puffer-fish of Earth. These \
|
||||
creatures do not use toxic spines to protect themselves, instead \
|
||||
utilizing an incredibly durable exoskeleton that is molded by the \
|
||||
expansion of its ventral fluid bladders. \
|
||||
<br>\
|
||||
Rock Puffers or 'Rock-fish' are often host to smaller creatures which \
|
||||
maneuver their way into the gap between the fish's body and shell. \
|
||||
<br>\
|
||||
The species is also capable of pulling its vibrantly colored head into \
|
||||
the safer confines of its shell, the action being utilized in their \
|
||||
attempts to find a mate."
|
||||
value = CATALOGUER_REWARD_EASY
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/rockfish
|
||||
name = "rock-fish"
|
||||
tt_desc = "S Tetraodontidae scopulix"
|
||||
icon_state = "rockfish-swim"
|
||||
icon_living = "rockfish-swim"
|
||||
icon_dead = "rockfish-dead"
|
||||
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/rockfish)
|
||||
|
||||
armor = list(
|
||||
"melee" = 90,
|
||||
"bullet" = 50,
|
||||
"laser" = -15,
|
||||
"energy" = 30,
|
||||
"bomb" = 30,
|
||||
"bio" = 100,
|
||||
"rad" = 100)
|
||||
|
||||
var/max_red = 255
|
||||
var/min_red = 50
|
||||
|
||||
var/max_blue = 255
|
||||
var/min_blue = 50
|
||||
|
||||
var/max_green = 255
|
||||
var/min_green = 50
|
||||
|
||||
var/head_color = "#FFFFFF"
|
||||
|
||||
var/image/head_image
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/fish/sif
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/rockfish/Initialize()
|
||||
. = ..()
|
||||
head_color = rgb(rand(min_red,max_red), rand(min_green,max_green), rand(min_blue,max_blue))
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/rockfish/update_icon()
|
||||
cut_overlays()
|
||||
..()
|
||||
if(!head_image)
|
||||
head_image = image(icon, "[icon_state]_mask")
|
||||
|
||||
head_image.icon_state = "[icon_state]_mask"
|
||||
|
||||
head_image.color = head_color
|
||||
|
||||
add_overlay(head_image)
|
||||
|
||||
/datum/category_item/catalogue/fauna/solarfish
|
||||
name = "Sivian Fauna - Solar Fin"
|
||||
desc = "Classification: S Exocoetidae solarin\
|
||||
<br><br>\
|
||||
An incredibly rare species of Sivian fish.\
|
||||
The solar-fin missile fish is a specialized omnivore capable of \
|
||||
catching insects or small birds venturing too close to the water's \
|
||||
surface. \
|
||||
<br>\
|
||||
The glimmering fins of the solar-fin are actually biofluorescent, \
|
||||
'charged' by the creature basking at the surface of the water, most \
|
||||
commonly by the edge of an ice-shelf, as a rapid means of cover. \
|
||||
<br>\
|
||||
These creatures are considered a protected species, and thus require an \
|
||||
up-to-date license to be hunted."
|
||||
value = CATALOGUER_REWARD_HARD
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/solarfish
|
||||
name = "sun-fin"
|
||||
tt_desc = "S Exocoetidae solarin"
|
||||
icon_state = "solarfin-swim"
|
||||
icon_living = "solarfin-swim"
|
||||
icon_dead = "solarfin-dead"
|
||||
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/solarfish)
|
||||
|
||||
has_eye_glow = TRUE
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/fish/sif
|
||||
|
||||
/datum/category_item/catalogue/fauna/murkin
|
||||
name = "Sivian Fauna - Murkfish"
|
||||
desc = "Classification: S Perca lutux\
|
||||
<br><br>\
|
||||
A small, Sivian fish most known for its bland-ness.\
|
||||
<br>\
|
||||
The species is incredibly close in appearance to the Earth \
|
||||
perch, aside from its incredibly tall dorsal fin. The animals use \
|
||||
the fin to assess the wind direction while near the surface. \
|
||||
<br>\
|
||||
The murkfish earns its name from the fact its dense meat tastes like mud \
|
||||
thanks to a specially formed protein, most likely an adaptation to \
|
||||
protect the species from predation."
|
||||
value = CATALOGUER_REWARD_TRIVIAL
|
||||
|
||||
/mob/living/simple_mob/animal/passive/fish/murkin
|
||||
name = "murkin"
|
||||
tt_desc = "S Perca lutux"
|
||||
|
||||
icon_state = "murkin-swim"
|
||||
icon_living = "murkin-swim"
|
||||
icon_dead = "murkin-dead"
|
||||
|
||||
catalogue_data = list(/datum/category_item/catalogue/fauna/murkin)
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat/sif/murkfish
|
||||
|
||||
/decl/mob_organ_names/fish
|
||||
hit_zones = list("head", "body", "dorsal fin", "left pectoral fin", "right pectoral fin", "tail fin")
|
||||
@@ -1,15 +1,15 @@
|
||||
/mob/living/simple_mob/animal/passive/mouse/jerboa
|
||||
name = "jerboa"
|
||||
real_name = "jerboa"
|
||||
desc = "It's a jerboa, a particularly fast desert mouse"
|
||||
tt_desc = "E Dipodidae musculus"
|
||||
icon = 'icons/mob/animal_vr.dmi'
|
||||
icon_state = "mouse_brown"
|
||||
item_state = "mouse_brown"
|
||||
icon_living = "mouse_brown"
|
||||
icon_dead = "mouse_brown_dead"
|
||||
kitchen_tag = "rodent"
|
||||
|
||||
movement_cooldown = -2
|
||||
|
||||
body_color = "brown"
|
||||
/mob/living/simple_mob/animal/passive/mouse/jerboa
|
||||
name = "jerboa"
|
||||
real_name = "jerboa"
|
||||
desc = "It's a jerboa, a particularly fast desert mouse"
|
||||
tt_desc = "E Dipodidae musculus"
|
||||
icon = 'icons/mob/animal_vr.dmi'
|
||||
icon_state = "mouse_brown"
|
||||
item_state = "mouse_brown"
|
||||
icon_living = "mouse_brown"
|
||||
icon_dead = "mouse_brown_dead"
|
||||
kitchen_tag = "rodent"
|
||||
|
||||
movement_cooldown = -2
|
||||
|
||||
body_color = "brown"
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
/mob/living/simple_mob/animal/passive/lizard
|
||||
name = "lizard"
|
||||
desc = "A cute, tiny lizard."
|
||||
tt_desc = "E Anolis cuvieri"
|
||||
|
||||
icon_state = "lizard_green"
|
||||
icon_living = "lizard_green"
|
||||
icon_dead = "lizard_green_dead"
|
||||
|
||||
health = 5
|
||||
maxHealth = 5
|
||||
mob_size = MOB_MINISCULE
|
||||
|
||||
response_help = "pets"
|
||||
response_disarm = "shoos"
|
||||
response_harm = "stomps on"
|
||||
|
||||
attacktext = list("bitten")
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 2
|
||||
|
||||
speak_emote = list("hisses")
|
||||
|
||||
say_list_type = /datum/say_list/lizard
|
||||
|
||||
meat_amount = 1
|
||||
|
||||
var/body_color // Green, red, orange, yellow or cyan. Keep blank for random (including rare redblue)
|
||||
|
||||
/mob/living/simple_mob/animal/passive/lizard/Initialize()
|
||||
.=..()
|
||||
|
||||
if(!body_color)
|
||||
if(rand(1,1000) == 1)
|
||||
body_color = "redblue"
|
||||
else
|
||||
body_color = pick(list("green","red","orange","yellow","cyan"))
|
||||
icon_state = "lizard_[body_color]"
|
||||
item_state = "lizard_[body_color]"
|
||||
icon_living = "lizard_[body_color]"
|
||||
icon_dead = "lizard_[body_color]_dead"
|
||||
if(body_color == "redblue")
|
||||
desc = "A cute, tiny, red lizard with distinctive blueish markings on its tiny limbs. Seems rare!"
|
||||
else
|
||||
desc = "A cute, tiny, [body_color] lizard."
|
||||
|
||||
/mob/living/simple_mob/animal/passive/lizard/large
|
||||
desc = "A cute, big lizard."
|
||||
maxHealth = 20
|
||||
health = 20
|
||||
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 15
|
||||
|
||||
attack_sharp = TRUE
|
||||
|
||||
/mob/living/simple_mob/animal/passive/lizard/large/Initialize()
|
||||
. = ..()
|
||||
adjust_scale(rand(12, 20) / 10)
|
||||
/mob/living/simple_mob/animal/passive/lizard/large/defensive
|
||||
maxHealth = 30
|
||||
health = 30
|
||||
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
|
||||
/mob/living/simple_mob/animal/passive/lizard
|
||||
name = "lizard"
|
||||
desc = "A cute, tiny lizard."
|
||||
tt_desc = "E Anolis cuvieri"
|
||||
|
||||
icon_state = "lizard_green"
|
||||
icon_living = "lizard_green"
|
||||
icon_dead = "lizard_green_dead"
|
||||
|
||||
health = 5
|
||||
maxHealth = 5
|
||||
mob_size = MOB_MINISCULE
|
||||
|
||||
response_help = "pets"
|
||||
response_disarm = "shoos"
|
||||
response_harm = "stomps on"
|
||||
|
||||
attacktext = list("bitten")
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 2
|
||||
|
||||
speak_emote = list("hisses")
|
||||
|
||||
say_list_type = /datum/say_list/lizard
|
||||
|
||||
meat_amount = 1
|
||||
|
||||
var/body_color // Green, red, orange, yellow or cyan. Keep blank for random (including rare redblue)
|
||||
|
||||
/mob/living/simple_mob/animal/passive/lizard/Initialize()
|
||||
.=..()
|
||||
|
||||
if(!body_color)
|
||||
if(rand(1,1000) == 1)
|
||||
body_color = "redblue"
|
||||
else
|
||||
body_color = pick(list("green","red","orange","yellow","cyan"))
|
||||
icon_state = "lizard_[body_color]"
|
||||
item_state = "lizard_[body_color]"
|
||||
icon_living = "lizard_[body_color]"
|
||||
icon_dead = "lizard_[body_color]_dead"
|
||||
if(body_color == "redblue")
|
||||
desc = "A cute, tiny, red lizard with distinctive blueish markings on its tiny limbs. Seems rare!"
|
||||
else
|
||||
desc = "A cute, tiny, [body_color] lizard."
|
||||
|
||||
/mob/living/simple_mob/animal/passive/lizard/large
|
||||
desc = "A cute, big lizard."
|
||||
maxHealth = 20
|
||||
health = 20
|
||||
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 15
|
||||
|
||||
attack_sharp = TRUE
|
||||
|
||||
/mob/living/simple_mob/animal/passive/lizard/large/Initialize()
|
||||
. = ..()
|
||||
adjust_scale(rand(12, 20) / 10)
|
||||
/mob/living/simple_mob/animal/passive/lizard/large/defensive
|
||||
maxHealth = 30
|
||||
health = 30
|
||||
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
/mob/living/simple_mob/animal/passive/yithian
|
||||
name = "yithian"
|
||||
desc = "A friendly creature vaguely resembling an oversized snail without a shell."
|
||||
tt_desc = "J Escargot escargot" // a product of Jade, which is a planet that totally exists
|
||||
|
||||
icon_state = "yithian"
|
||||
icon_living = "yithian"
|
||||
icon_dead = "yithian_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
|
||||
organ_names = /decl/mob_organ_names/yithian
|
||||
|
||||
// Same stats as lizards.
|
||||
health = 5
|
||||
maxHealth = 5
|
||||
mob_size = MOB_MINISCULE
|
||||
|
||||
/mob/living/simple_mob/animal/passive/tindalos
|
||||
name = "tindalos"
|
||||
desc = "It looks like a large, flightless grasshopper."
|
||||
tt_desc = "J Locusta bruchus"
|
||||
|
||||
icon_state = "tindalos"
|
||||
icon_living = "tindalos"
|
||||
icon_dead = "tindalos_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
|
||||
organ_names = /decl/mob_organ_names/tindalos
|
||||
|
||||
// Same stats as lizards.
|
||||
health = 5
|
||||
maxHealth = 5
|
||||
mob_size = MOB_MINISCULE
|
||||
|
||||
/decl/mob_organ_names/yithian
|
||||
hit_zones = list("head", "abdomen", "left foreleg", "right foreleg", "left hind leg", "right hind leg")
|
||||
|
||||
/decl/mob_organ_names/tindalos
|
||||
/mob/living/simple_mob/animal/passive/yithian
|
||||
name = "yithian"
|
||||
desc = "A friendly creature vaguely resembling an oversized snail without a shell."
|
||||
tt_desc = "J Escargot escargot" // a product of Jade, which is a planet that totally exists
|
||||
|
||||
icon_state = "yithian"
|
||||
icon_living = "yithian"
|
||||
icon_dead = "yithian_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
|
||||
organ_names = /decl/mob_organ_names/yithian
|
||||
|
||||
// Same stats as lizards.
|
||||
health = 5
|
||||
maxHealth = 5
|
||||
mob_size = MOB_MINISCULE
|
||||
|
||||
/mob/living/simple_mob/animal/passive/tindalos
|
||||
name = "tindalos"
|
||||
desc = "It looks like a large, flightless grasshopper."
|
||||
tt_desc = "J Locusta bruchus"
|
||||
|
||||
icon_state = "tindalos"
|
||||
icon_living = "tindalos"
|
||||
icon_dead = "tindalos_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
|
||||
organ_names = /decl/mob_organ_names/tindalos
|
||||
|
||||
// Same stats as lizards.
|
||||
health = 5
|
||||
maxHealth = 5
|
||||
mob_size = MOB_MINISCULE
|
||||
|
||||
/decl/mob_organ_names/yithian
|
||||
hit_zones = list("head", "abdomen", "left foreleg", "right foreleg", "left hind leg", "right hind leg")
|
||||
|
||||
/decl/mob_organ_names/tindalos
|
||||
hit_zones = list("head", "thorax", "abdomen", "left foreleg", "right foreleg", "left hind leg", "right hind leg", "left middle leg", "right middle leg")
|
||||
@@ -1,5 +1,5 @@
|
||||
// Passive mobs can't attack things, and will run away instead.
|
||||
// They can also be displaced by all mobs.
|
||||
/mob/living/simple_mob/animal/passive
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/passive
|
||||
// Passive mobs can't attack things, and will run away instead.
|
||||
// They can also be displaced by all mobs.
|
||||
/mob/living/simple_mob/animal/passive
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/passive
|
||||
mob_bump_flag = 0
|
||||
@@ -1,35 +1,35 @@
|
||||
/mob/living/simple_mob/animal/passive/penguin
|
||||
name = "penguin"
|
||||
desc = "An ungainly, waddling, cute, and VERY well-dressed bird."
|
||||
tt_desc = "Aptenodytes forsteri"
|
||||
icon_state = "penguin"
|
||||
icon_living = "penguin"
|
||||
icon_dead = "penguin_dead"
|
||||
|
||||
maxHealth = 20
|
||||
health = 20
|
||||
minbodytemp = 175 // Same as Sif mobs.
|
||||
|
||||
response_help = "pets"
|
||||
response_disarm = "pushes aside"
|
||||
response_harm = "hits"
|
||||
|
||||
organ_names = /decl/mob_organ_names/penguin
|
||||
|
||||
meat_amount = 3
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/chicken
|
||||
|
||||
harm_intent_damage = 5
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 15
|
||||
attacktext = list("pecked")
|
||||
|
||||
has_langs = list(LANGUAGE_ANIMAL)
|
||||
|
||||
/mob/living/simple_mob/animal/passive/penguin/tux
|
||||
name = "Tux"
|
||||
desc = "A penguin that has been known to associate with gnus."
|
||||
speak_emote = list("interjects")
|
||||
|
||||
/decl/mob_organ_names/penguin
|
||||
/mob/living/simple_mob/animal/passive/penguin
|
||||
name = "penguin"
|
||||
desc = "An ungainly, waddling, cute, and VERY well-dressed bird."
|
||||
tt_desc = "Aptenodytes forsteri"
|
||||
icon_state = "penguin"
|
||||
icon_living = "penguin"
|
||||
icon_dead = "penguin_dead"
|
||||
|
||||
maxHealth = 20
|
||||
health = 20
|
||||
minbodytemp = 175 // Same as Sif mobs.
|
||||
|
||||
response_help = "pets"
|
||||
response_disarm = "pushes aside"
|
||||
response_harm = "hits"
|
||||
|
||||
organ_names = /decl/mob_organ_names/penguin
|
||||
|
||||
meat_amount = 3
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/chicken
|
||||
|
||||
harm_intent_damage = 5
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 15
|
||||
attacktext = list("pecked")
|
||||
|
||||
has_langs = list(LANGUAGE_ANIMAL)
|
||||
|
||||
/mob/living/simple_mob/animal/passive/penguin/tux
|
||||
name = "Tux"
|
||||
desc = "A penguin that has been known to associate with gnus."
|
||||
speak_emote = list("interjects")
|
||||
|
||||
/decl/mob_organ_names/penguin
|
||||
hit_zones = list("chest", "left leg", "right leg", "left flipper", "right flipper", "head")
|
||||
@@ -1,93 +1,93 @@
|
||||
// Base bird type.
|
||||
|
||||
/mob/living/simple_mob/animal/passive/bird
|
||||
name = "bird"
|
||||
desc = "A domesticated bird. Tweet tweet!"
|
||||
player_msg = "You are able to fly."
|
||||
|
||||
icon = 'icons/mob/birds.dmi'
|
||||
icon_state = "parrot"
|
||||
item_state = null
|
||||
icon_rest = "parrot-held"
|
||||
icon_dead = "parrot-dead"
|
||||
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
health = 30
|
||||
maxHealth = 30
|
||||
melee_damage_lower = 3
|
||||
melee_damage_upper = 3
|
||||
|
||||
movement_cooldown = -1
|
||||
hovering = TRUE // Birds can fly.
|
||||
softfall = TRUE
|
||||
parachuting = TRUE
|
||||
|
||||
meat_amount = 1
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/chicken
|
||||
|
||||
attacktext = list("clawed", "pecked")
|
||||
speak_emote = list("chirps", "caws")
|
||||
has_langs = list(LANGUAGE_ANIMAL)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently moves aside"
|
||||
response_harm = "swats"
|
||||
organ_names = /decl/mob_organ_names/bird
|
||||
|
||||
say_list_type = /datum/say_list/bird
|
||||
holder_type = /obj/item/weapon/holder/bird
|
||||
|
||||
/datum/say_list/bird
|
||||
speak = list("Chirp!","Caw!","Screech!","Squawk!")
|
||||
emote_hear = list("chirps","caws")
|
||||
emote_see = list("shakes their head", "ruffles their feathers")
|
||||
|
||||
// Subtypes for birbs.
|
||||
/mob/living/simple_mob/animal/passive/bird/black_bird
|
||||
name = "common blackbird"
|
||||
desc = "A species of bird, both the males and females are known to be territorial on their breeding grounds."
|
||||
icon_state = "commonblackbird"
|
||||
icon_dead = "commonblackbird-dead"
|
||||
tt_desc = "E Turdus merula"
|
||||
icon_scale_x = 0.5
|
||||
icon_scale_y = 0.5
|
||||
|
||||
/mob/living/simple_mob/animal/passive/bird/azure_tit
|
||||
name = "azure tit"
|
||||
desc = "A species of bird, colored blue and white."
|
||||
icon_state = "azuretit"
|
||||
icon_dead = "azuretit-dead"
|
||||
tt_desc = "E Cyanistes cyanus"
|
||||
icon_scale_x = 0.5
|
||||
icon_scale_y = 0.5
|
||||
|
||||
/mob/living/simple_mob/animal/passive/bird/european_robin
|
||||
name = "european robin"
|
||||
desc = "A species of bird, they have been studied for their sense of magnetoreception."
|
||||
icon_state = "europeanrobin"
|
||||
icon_dead = "europeanrobin-dead"
|
||||
tt_desc = "E Erithacus rubecula"
|
||||
icon_scale_x = 0.5
|
||||
icon_scale_y = 0.5
|
||||
|
||||
/mob/living/simple_mob/animal/passive/bird/goldcrest
|
||||
name = "goldcrest"
|
||||
desc = "A species of bird, they were once called 'king of the birds' in ancient human folklore, for their golden crest. \
|
||||
Today, their scientific name still elude towards this, with <i>regulus</i>, meaning petty king."
|
||||
icon_state = "goldcrest"
|
||||
icon_dead = "goldcrest-dead"
|
||||
tt_desc = "E Regulus regulus"
|
||||
icon_scale_x = 0.5
|
||||
icon_scale_y = 0.5
|
||||
|
||||
/mob/living/simple_mob/animal/passive/bird/ringneck_dove
|
||||
name = "ringneck dove"
|
||||
desc = "A species of bird. They are also known as the barbary dove, and have a distinct ring-like shape around the back of their neck."
|
||||
icon_state = "ringneckdove"
|
||||
icon_dead = "ringneckdove-dead"
|
||||
tt_desc = "E Streptopelia risoria" // This is actually disputed IRL but since we can't tell the future it'll stay the same for 500+ years.
|
||||
icon_scale_x = 0.5
|
||||
icon_scale_y = 0.5
|
||||
|
||||
/decl/mob_organ_names/bird
|
||||
hit_zones = list("head", "chest", "left leg", "right leg", "left wing", "right wing")
|
||||
// Base bird type.
|
||||
|
||||
/mob/living/simple_mob/animal/passive/bird
|
||||
name = "bird"
|
||||
desc = "A domesticated bird. Tweet tweet!"
|
||||
player_msg = "You are able to fly."
|
||||
|
||||
icon = 'icons/mob/birds.dmi'
|
||||
icon_state = "parrot"
|
||||
item_state = null
|
||||
icon_rest = "parrot-held"
|
||||
icon_dead = "parrot-dead"
|
||||
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
health = 30
|
||||
maxHealth = 30
|
||||
melee_damage_lower = 3
|
||||
melee_damage_upper = 3
|
||||
|
||||
movement_cooldown = -1
|
||||
hovering = TRUE // Birds can fly.
|
||||
softfall = TRUE
|
||||
parachuting = TRUE
|
||||
|
||||
meat_amount = 1
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/chicken
|
||||
|
||||
attacktext = list("clawed", "pecked")
|
||||
speak_emote = list("chirps", "caws")
|
||||
has_langs = list(LANGUAGE_ANIMAL)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently moves aside"
|
||||
response_harm = "swats"
|
||||
organ_names = /decl/mob_organ_names/bird
|
||||
|
||||
say_list_type = /datum/say_list/bird
|
||||
holder_type = /obj/item/weapon/holder/bird
|
||||
|
||||
/datum/say_list/bird
|
||||
speak = list("Chirp!","Caw!","Screech!","Squawk!")
|
||||
emote_hear = list("chirps","caws")
|
||||
emote_see = list("shakes their head", "ruffles their feathers")
|
||||
|
||||
// Subtypes for birbs.
|
||||
/mob/living/simple_mob/animal/passive/bird/black_bird
|
||||
name = "common blackbird"
|
||||
desc = "A species of bird, both the males and females are known to be territorial on their breeding grounds."
|
||||
icon_state = "commonblackbird"
|
||||
icon_dead = "commonblackbird-dead"
|
||||
tt_desc = "E Turdus merula"
|
||||
icon_scale_x = 0.5
|
||||
icon_scale_y = 0.5
|
||||
|
||||
/mob/living/simple_mob/animal/passive/bird/azure_tit
|
||||
name = "azure tit"
|
||||
desc = "A species of bird, colored blue and white."
|
||||
icon_state = "azuretit"
|
||||
icon_dead = "azuretit-dead"
|
||||
tt_desc = "E Cyanistes cyanus"
|
||||
icon_scale_x = 0.5
|
||||
icon_scale_y = 0.5
|
||||
|
||||
/mob/living/simple_mob/animal/passive/bird/european_robin
|
||||
name = "european robin"
|
||||
desc = "A species of bird, they have been studied for their sense of magnetoreception."
|
||||
icon_state = "europeanrobin"
|
||||
icon_dead = "europeanrobin-dead"
|
||||
tt_desc = "E Erithacus rubecula"
|
||||
icon_scale_x = 0.5
|
||||
icon_scale_y = 0.5
|
||||
|
||||
/mob/living/simple_mob/animal/passive/bird/goldcrest
|
||||
name = "goldcrest"
|
||||
desc = "A species of bird, they were once called 'king of the birds' in ancient human folklore, for their golden crest. \
|
||||
Today, their scientific name still elude towards this, with <i>regulus</i>, meaning petty king."
|
||||
icon_state = "goldcrest"
|
||||
icon_dead = "goldcrest-dead"
|
||||
tt_desc = "E Regulus regulus"
|
||||
icon_scale_x = 0.5
|
||||
icon_scale_y = 0.5
|
||||
|
||||
/mob/living/simple_mob/animal/passive/bird/ringneck_dove
|
||||
name = "ringneck dove"
|
||||
desc = "A species of bird. They are also known as the barbary dove, and have a distinct ring-like shape around the back of their neck."
|
||||
icon_state = "ringneckdove"
|
||||
icon_dead = "ringneckdove-dead"
|
||||
tt_desc = "E Streptopelia risoria" // This is actually disputed IRL but since we can't tell the future it'll stay the same for 500+ years.
|
||||
icon_scale_x = 0.5
|
||||
icon_scale_y = 0.5
|
||||
|
||||
/decl/mob_organ_names/bird
|
||||
hit_zones = list("head", "chest", "left leg", "right leg", "left wing", "right wing")
|
||||
|
||||
@@ -1,285 +1,285 @@
|
||||
var/list/_cat_default_emotes = list(
|
||||
/decl/emote/visible,
|
||||
/decl/emote/visible/scratch,
|
||||
/decl/emote/visible/drool,
|
||||
/decl/emote/visible/nod,
|
||||
/decl/emote/visible/sway,
|
||||
/decl/emote/visible/sulk,
|
||||
/decl/emote/visible/twitch,
|
||||
/decl/emote/visible/twitch_v,
|
||||
/decl/emote/visible/dance,
|
||||
/decl/emote/visible/roll,
|
||||
/decl/emote/visible/shake,
|
||||
/decl/emote/visible/jump,
|
||||
/decl/emote/visible/shiver,
|
||||
/decl/emote/visible/collapse,
|
||||
/decl/emote/visible/spin,
|
||||
/decl/emote/visible/sidestep,
|
||||
/decl/emote/audible,
|
||||
/decl/emote/audible/hiss,
|
||||
/decl/emote/audible/whimper,
|
||||
/decl/emote/audible/gasp,
|
||||
/decl/emote/audible/scretch,
|
||||
/decl/emote/audible/choke,
|
||||
/decl/emote/audible/moan,
|
||||
/decl/emote/audible/gnarl,
|
||||
/decl/emote/audible/purr,
|
||||
/decl/emote/audible/purrlong
|
||||
)
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat
|
||||
name = "cat"
|
||||
desc = "A domesticated, feline pet. Has a tendency to adopt crewmembers."
|
||||
tt_desc = "E Felis silvestris catus"
|
||||
icon = 'icons/mob/pets.dmi'
|
||||
icon_state = "cat2"
|
||||
item_state = "cat2"
|
||||
|
||||
movement_cooldown = -1
|
||||
|
||||
meat_amount = 1
|
||||
see_in_dark = 6 // Not sure if this actually works.
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
|
||||
holder_type = /obj/item/weapon/holder/cat
|
||||
mob_size = MOB_SMALL
|
||||
|
||||
has_langs = list(LANGUAGE_ANIMAL)
|
||||
|
||||
var/mob/living/friend = null // Our best pal, who we'll follow. Meow.
|
||||
var/named = FALSE //have I been named yet?
|
||||
var/friend_name = null //VOREStation Edit - Lock befriending to this character
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/Initialize()
|
||||
icon_living = "[initial(icon_state)]"
|
||||
icon_dead = "[initial(icon_state)]_dead"
|
||||
icon_rest = "[initial(icon_state)]_rest"
|
||||
update_icon()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/get_available_emotes()
|
||||
return global._cat_default_emotes.Copy()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/handle_special()
|
||||
if(!stat && prob(2)) // spooky
|
||||
var/mob/observer/dead/spook = locate() in range(src, 5)
|
||||
if(spook)
|
||||
var/turf/T = get_turf(spook)
|
||||
var/list/visible = list()
|
||||
for(var/obj/O in T.contents)
|
||||
if(!O.invisibility && O.name)
|
||||
visible += O
|
||||
if(visible.len)
|
||||
var/atom/A = pick(visible)
|
||||
visible_emote("suddenly stops and stares at something unseen[istype(A) ? " near [A]":""].")
|
||||
|
||||
// Instakills mice.
|
||||
/mob/living/simple_mob/animal/passive/cat/apply_melee_effects(var/atom/A)
|
||||
if(ismouse(A))
|
||||
var/mob/living/simple_mob/animal/passive/mouse/mouse = A
|
||||
if(mouse.getMaxHealth() < 20) // In case a badmin makes giant mice or something.
|
||||
mouse.splat()
|
||||
visible_emote(pick("bites \the [mouse]!", "toys with \the [mouse].", "chomps on \the [mouse]!"))
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/IIsAlly(mob/living/L)
|
||||
if(L == friend) // Always be pals with our special friend.
|
||||
return TRUE
|
||||
|
||||
. = ..()
|
||||
|
||||
if(.) // We're pals, but they might be a dirty mouse...
|
||||
if(ismouse(L))
|
||||
return FALSE // Cats and mice can never get along.
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/verb/become_friends()
|
||||
set name = "Become Friends"
|
||||
set category = "IC"
|
||||
set src in view(1)
|
||||
|
||||
var/mob/living/L = usr
|
||||
if(!istype(L))
|
||||
return // Fuck off ghosts.
|
||||
|
||||
if(friend)
|
||||
if(friend == usr)
|
||||
to_chat(L, span("notice", "\The [src] is already your friend! Meow!"))
|
||||
return
|
||||
else
|
||||
to_chat(L, span("warning", "\The [src] ignores you."))
|
||||
return
|
||||
|
||||
//VOREStation Edit Start - Adds friend_name var checks
|
||||
if(!friend_name || L.real_name == friend_name)
|
||||
friend = L
|
||||
face_atom(L)
|
||||
to_chat(L, span("notice", "\The [src] is now your friend! Meow."))
|
||||
visible_emote(pick("nuzzles [friend].", "brushes against [friend].", "rubs against [friend].", "purrs."))
|
||||
|
||||
if(has_AI())
|
||||
var/datum/ai_holder/AI = ai_holder
|
||||
AI.set_follow(friend)
|
||||
else
|
||||
to_chat(L, span("notice", "[src] ignores you."))
|
||||
//VOREStation Edit End
|
||||
|
||||
|
||||
//RUNTIME IS ALIVE! SQUEEEEEEEE~
|
||||
/mob/living/simple_mob/animal/passive/cat/runtime
|
||||
name = "Runtime"
|
||||
desc = "Her fur has the look and feel of velvet, and her tail quivers occasionally."
|
||||
tt_desc = "E Felis silvestris medicalis" // a hypoallergenic breed produced by NT for... medical purposes? Sure.
|
||||
gender = FEMALE
|
||||
icon_state = "cat"
|
||||
item_state = "cat"
|
||||
named = TRUE
|
||||
holder_type = /obj/item/weapon/holder/cat/runtime
|
||||
makes_dirt = 0 //Vorestation Edit
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/kitten
|
||||
name = "kitten"
|
||||
desc = "D'aaawwww!"
|
||||
icon_state = "kitten"
|
||||
item_state = "kitten"
|
||||
gender = NEUTER
|
||||
holder_type = /obj/item/weapon/holder/cat/kitten //VOREStation Edit
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/kitten/Initialize()
|
||||
if(gender == NEUTER)
|
||||
gender = pick(MALE, FEMALE)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/black
|
||||
icon_state = "cat3"
|
||||
item_state = "cat3"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/bones
|
||||
name = "Bones"
|
||||
desc = "That's Bones the cat. He's a laid back, black cat. Meow."
|
||||
gender = MALE
|
||||
icon_state = "cat3"
|
||||
item_state = "cat3"
|
||||
named = TRUE
|
||||
holder_type = /obj/item/weapon/holder/cat/fluff/bones
|
||||
|
||||
// SPARKLY
|
||||
/mob/living/simple_mob/animal/passive/cat/bluespace
|
||||
name = "bluespace cat"
|
||||
desc = "Shiny cat, shiny cat, it's not your fault."
|
||||
tt_desc = "E Felis silvestris argentum"
|
||||
icon_state = "bscat"
|
||||
icon_living = "bscat"
|
||||
icon_rest = null
|
||||
icon_dead = null
|
||||
makes_dirt = 0
|
||||
holder_type = /obj/item/weapon/holder/cat/bluespace
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/bluespace/death()
|
||||
animate(src, alpha = 0, color = "#0000FF", time = 0.5 SECOND)
|
||||
spawn(0.5 SECOND)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/bread
|
||||
name = "bread cat"
|
||||
desc = "Brought lunch to work."
|
||||
tt_desc = "E Felis silvestris breadinum"
|
||||
icon_state = "breadcat"
|
||||
icon_living = "breadcat"
|
||||
icon_rest = "breadcat_rest"
|
||||
icon_dead = "breadcat_dead"
|
||||
//icon_sit = "breadcat_sit"
|
||||
makes_dirt = 0
|
||||
holder_type = /obj/item/weapon/holder/cat/breadcat
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/original
|
||||
name = "original cat"
|
||||
desc = "Donut steal."
|
||||
tt_desc = "E Felis silvestris originalis"
|
||||
icon_state = "original"
|
||||
icon_living = "original"
|
||||
icon_rest = "original_rest"
|
||||
icon_dead = "original_dead"
|
||||
//icon_sit = "original_sit"
|
||||
makes_dirt = 0
|
||||
holder_type = /obj/item/weapon/holder/cat/original
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/cak
|
||||
name = "cak"
|
||||
desc = "Optimal combination of things?"
|
||||
tt_desc = "E Felis silvestris dessertus"
|
||||
icon_state = "cak"
|
||||
icon_living = "cak"
|
||||
icon_rest = "cak_rest"
|
||||
icon_dead = "cak_dead"
|
||||
//icon_sit = "cak_sit"
|
||||
makes_dirt = 0
|
||||
holder_type = /obj/item/weapon/holder/cat/cak
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/space
|
||||
name = "space cat"
|
||||
desc = "Did someone write a song about this cat?"
|
||||
tt_desc = "E Felis silvestris stellaris"
|
||||
icon_state = "spacecat"
|
||||
icon_living = "spacecat"
|
||||
icon_rest = "spacecat_rest"
|
||||
icon_dead = "spacecat_dead"
|
||||
//icon_sit = "spacecat_sit"
|
||||
holder_type = /obj/item/weapon/holder/cat/spacecat
|
||||
makes_dirt = 0
|
||||
|
||||
minbodytemp = 0 // Minimum "okay" temperature in kelvin
|
||||
maxbodytemp = 900 // Maximum of above
|
||||
heat_damage_per_tick = 3 // Amount of damage applied if animal's body temperature is higher than maxbodytemp
|
||||
cold_damage_per_tick = 2 // Same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp
|
||||
|
||||
min_oxy = 0 // Oxygen in moles, minimum, 0 is 'no minimum'
|
||||
max_oxy = 0 // Oxygen in moles, maximum, 0 is 'no maximum'
|
||||
min_tox = 0 // Phoron min
|
||||
max_tox = 0 // Phoron max
|
||||
min_co2 = 0 // CO2 min
|
||||
max_co2 = 0 // CO2 max
|
||||
min_n2 = 0 // N2 min
|
||||
max_n2 = 0 // N2 max
|
||||
unsuitable_atoms_damage = 2 // This damage is taken when atmos doesn't fit all the requirements above
|
||||
|
||||
/datum/say_list/cat
|
||||
speak = list("Meow!","Esp!","Purr!","HSSSSS")
|
||||
emote_hear = list("meows","mews")
|
||||
emote_see = list("shakes their head", "shivers")
|
||||
say_maybe_target = list("Meow?","Mew?","Mao?")
|
||||
say_got_target = list("MEOW!","HSSSS!","REEER!")
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W, /obj/item/weapon/pen) || istype(W, /obj/item/device/flashlight/pen))
|
||||
if(named)
|
||||
to_chat(user, "<span class='notice'>\The [name] already has a name!</span>")
|
||||
else
|
||||
var/tmp_name = sanitizeSafe(tgui_input_text(user, "Give \the [name] a name", "Name", null, MAX_NAME_LEN), MAX_NAME_LEN)
|
||||
if(length(tmp_name) > 50)
|
||||
to_chat(user, "<span class='notice'>The name can be at most 50 characters long.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You name \the [name]. Meow!</span>")
|
||||
name = tmp_name
|
||||
named = TRUE
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/weapon/cat_box
|
||||
name = "faintly purring box"
|
||||
desc = "This box is purring faintly. You're pretty sure there's a cat inside it."
|
||||
icon = 'icons/obj/storage.dmi'
|
||||
icon_state = "box"
|
||||
var/cattype = /mob/living/simple_mob/animal/passive/cat
|
||||
|
||||
/obj/item/weapon/cat_box/attack_self(var/mob/user)
|
||||
var/turf/catturf = get_turf(src)
|
||||
to_chat(user, "<span class='notice'>You peek into \the [name]-- and a cat jumps out!</span>")
|
||||
new cattype(catturf)
|
||||
new /obj/item/stack/material/cardboard(catturf) //if i fits i sits
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/cat_box/black
|
||||
cattype = /mob/living/simple_mob/animal/passive/cat/black
|
||||
var/list/_cat_default_emotes = list(
|
||||
/decl/emote/visible,
|
||||
/decl/emote/visible/scratch,
|
||||
/decl/emote/visible/drool,
|
||||
/decl/emote/visible/nod,
|
||||
/decl/emote/visible/sway,
|
||||
/decl/emote/visible/sulk,
|
||||
/decl/emote/visible/twitch,
|
||||
/decl/emote/visible/twitch_v,
|
||||
/decl/emote/visible/dance,
|
||||
/decl/emote/visible/roll,
|
||||
/decl/emote/visible/shake,
|
||||
/decl/emote/visible/jump,
|
||||
/decl/emote/visible/shiver,
|
||||
/decl/emote/visible/collapse,
|
||||
/decl/emote/visible/spin,
|
||||
/decl/emote/visible/sidestep,
|
||||
/decl/emote/audible,
|
||||
/decl/emote/audible/hiss,
|
||||
/decl/emote/audible/whimper,
|
||||
/decl/emote/audible/gasp,
|
||||
/decl/emote/audible/scretch,
|
||||
/decl/emote/audible/choke,
|
||||
/decl/emote/audible/moan,
|
||||
/decl/emote/audible/gnarl,
|
||||
/decl/emote/audible/purr,
|
||||
/decl/emote/audible/purrlong
|
||||
)
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat
|
||||
name = "cat"
|
||||
desc = "A domesticated, feline pet. Has a tendency to adopt crewmembers."
|
||||
tt_desc = "E Felis silvestris catus"
|
||||
icon = 'icons/mob/pets.dmi'
|
||||
icon_state = "cat2"
|
||||
item_state = "cat2"
|
||||
|
||||
movement_cooldown = -1
|
||||
|
||||
meat_amount = 1
|
||||
see_in_dark = 6 // Not sure if this actually works.
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
|
||||
holder_type = /obj/item/weapon/holder/cat
|
||||
mob_size = MOB_SMALL
|
||||
|
||||
has_langs = list(LANGUAGE_ANIMAL)
|
||||
|
||||
var/mob/living/friend = null // Our best pal, who we'll follow. Meow.
|
||||
var/named = FALSE //have I been named yet?
|
||||
var/friend_name = null //VOREStation Edit - Lock befriending to this character
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/Initialize()
|
||||
icon_living = "[initial(icon_state)]"
|
||||
icon_dead = "[initial(icon_state)]_dead"
|
||||
icon_rest = "[initial(icon_state)]_rest"
|
||||
update_icon()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/get_available_emotes()
|
||||
return global._cat_default_emotes.Copy()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/handle_special()
|
||||
if(!stat && prob(2)) // spooky
|
||||
var/mob/observer/dead/spook = locate() in range(src, 5)
|
||||
if(spook)
|
||||
var/turf/T = get_turf(spook)
|
||||
var/list/visible = list()
|
||||
for(var/obj/O in T.contents)
|
||||
if(!O.invisibility && O.name)
|
||||
visible += O
|
||||
if(visible.len)
|
||||
var/atom/A = pick(visible)
|
||||
visible_emote("suddenly stops and stares at something unseen[istype(A) ? " near [A]":""].")
|
||||
|
||||
// Instakills mice.
|
||||
/mob/living/simple_mob/animal/passive/cat/apply_melee_effects(var/atom/A)
|
||||
if(ismouse(A))
|
||||
var/mob/living/simple_mob/animal/passive/mouse/mouse = A
|
||||
if(mouse.getMaxHealth() < 20) // In case a badmin makes giant mice or something.
|
||||
mouse.splat()
|
||||
visible_emote(pick("bites \the [mouse]!", "toys with \the [mouse].", "chomps on \the [mouse]!"))
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/IIsAlly(mob/living/L)
|
||||
if(L == friend) // Always be pals with our special friend.
|
||||
return TRUE
|
||||
|
||||
. = ..()
|
||||
|
||||
if(.) // We're pals, but they might be a dirty mouse...
|
||||
if(ismouse(L))
|
||||
return FALSE // Cats and mice can never get along.
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/verb/become_friends()
|
||||
set name = "Become Friends"
|
||||
set category = "IC"
|
||||
set src in view(1)
|
||||
|
||||
var/mob/living/L = usr
|
||||
if(!istype(L))
|
||||
return // Fuck off ghosts.
|
||||
|
||||
if(friend)
|
||||
if(friend == usr)
|
||||
to_chat(L, span("notice", "\The [src] is already your friend! Meow!"))
|
||||
return
|
||||
else
|
||||
to_chat(L, span("warning", "\The [src] ignores you."))
|
||||
return
|
||||
|
||||
//VOREStation Edit Start - Adds friend_name var checks
|
||||
if(!friend_name || L.real_name == friend_name)
|
||||
friend = L
|
||||
face_atom(L)
|
||||
to_chat(L, span("notice", "\The [src] is now your friend! Meow."))
|
||||
visible_emote(pick("nuzzles [friend].", "brushes against [friend].", "rubs against [friend].", "purrs."))
|
||||
|
||||
if(has_AI())
|
||||
var/datum/ai_holder/AI = ai_holder
|
||||
AI.set_follow(friend)
|
||||
else
|
||||
to_chat(L, span("notice", "[src] ignores you."))
|
||||
//VOREStation Edit End
|
||||
|
||||
|
||||
//RUNTIME IS ALIVE! SQUEEEEEEEE~
|
||||
/mob/living/simple_mob/animal/passive/cat/runtime
|
||||
name = "Runtime"
|
||||
desc = "Her fur has the look and feel of velvet, and her tail quivers occasionally."
|
||||
tt_desc = "E Felis silvestris medicalis" // a hypoallergenic breed produced by NT for... medical purposes? Sure.
|
||||
gender = FEMALE
|
||||
icon_state = "cat"
|
||||
item_state = "cat"
|
||||
named = TRUE
|
||||
holder_type = /obj/item/weapon/holder/cat/runtime
|
||||
makes_dirt = 0 //Vorestation Edit
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/kitten
|
||||
name = "kitten"
|
||||
desc = "D'aaawwww!"
|
||||
icon_state = "kitten"
|
||||
item_state = "kitten"
|
||||
gender = NEUTER
|
||||
holder_type = /obj/item/weapon/holder/cat/kitten //VOREStation Edit
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/kitten/Initialize()
|
||||
if(gender == NEUTER)
|
||||
gender = pick(MALE, FEMALE)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/black
|
||||
icon_state = "cat3"
|
||||
item_state = "cat3"
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/bones
|
||||
name = "Bones"
|
||||
desc = "That's Bones the cat. He's a laid back, black cat. Meow."
|
||||
gender = MALE
|
||||
icon_state = "cat3"
|
||||
item_state = "cat3"
|
||||
named = TRUE
|
||||
holder_type = /obj/item/weapon/holder/cat/fluff/bones
|
||||
|
||||
// SPARKLY
|
||||
/mob/living/simple_mob/animal/passive/cat/bluespace
|
||||
name = "bluespace cat"
|
||||
desc = "Shiny cat, shiny cat, it's not your fault."
|
||||
tt_desc = "E Felis silvestris argentum"
|
||||
icon_state = "bscat"
|
||||
icon_living = "bscat"
|
||||
icon_rest = null
|
||||
icon_dead = null
|
||||
makes_dirt = 0
|
||||
holder_type = /obj/item/weapon/holder/cat/bluespace
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/bluespace/death()
|
||||
animate(src, alpha = 0, color = "#0000FF", time = 0.5 SECOND)
|
||||
spawn(0.5 SECOND)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/bread
|
||||
name = "bread cat"
|
||||
desc = "Brought lunch to work."
|
||||
tt_desc = "E Felis silvestris breadinum"
|
||||
icon_state = "breadcat"
|
||||
icon_living = "breadcat"
|
||||
icon_rest = "breadcat_rest"
|
||||
icon_dead = "breadcat_dead"
|
||||
//icon_sit = "breadcat_sit"
|
||||
makes_dirt = 0
|
||||
holder_type = /obj/item/weapon/holder/cat/breadcat
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/original
|
||||
name = "original cat"
|
||||
desc = "Donut steal."
|
||||
tt_desc = "E Felis silvestris originalis"
|
||||
icon_state = "original"
|
||||
icon_living = "original"
|
||||
icon_rest = "original_rest"
|
||||
icon_dead = "original_dead"
|
||||
//icon_sit = "original_sit"
|
||||
makes_dirt = 0
|
||||
holder_type = /obj/item/weapon/holder/cat/original
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/cak
|
||||
name = "cak"
|
||||
desc = "Optimal combination of things?"
|
||||
tt_desc = "E Felis silvestris dessertus"
|
||||
icon_state = "cak"
|
||||
icon_living = "cak"
|
||||
icon_rest = "cak_rest"
|
||||
icon_dead = "cak_dead"
|
||||
//icon_sit = "cak_sit"
|
||||
makes_dirt = 0
|
||||
holder_type = /obj/item/weapon/holder/cat/cak
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/space
|
||||
name = "space cat"
|
||||
desc = "Did someone write a song about this cat?"
|
||||
tt_desc = "E Felis silvestris stellaris"
|
||||
icon_state = "spacecat"
|
||||
icon_living = "spacecat"
|
||||
icon_rest = "spacecat_rest"
|
||||
icon_dead = "spacecat_dead"
|
||||
//icon_sit = "spacecat_sit"
|
||||
holder_type = /obj/item/weapon/holder/cat/spacecat
|
||||
makes_dirt = 0
|
||||
|
||||
minbodytemp = 0 // Minimum "okay" temperature in kelvin
|
||||
maxbodytemp = 900 // Maximum of above
|
||||
heat_damage_per_tick = 3 // Amount of damage applied if animal's body temperature is higher than maxbodytemp
|
||||
cold_damage_per_tick = 2 // Same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp
|
||||
|
||||
min_oxy = 0 // Oxygen in moles, minimum, 0 is 'no minimum'
|
||||
max_oxy = 0 // Oxygen in moles, maximum, 0 is 'no maximum'
|
||||
min_tox = 0 // Phoron min
|
||||
max_tox = 0 // Phoron max
|
||||
min_co2 = 0 // CO2 min
|
||||
max_co2 = 0 // CO2 max
|
||||
min_n2 = 0 // N2 min
|
||||
max_n2 = 0 // N2 max
|
||||
unsuitable_atoms_damage = 2 // This damage is taken when atmos doesn't fit all the requirements above
|
||||
|
||||
/datum/say_list/cat
|
||||
speak = list("Meow!","Esp!","Purr!","HSSSSS")
|
||||
emote_hear = list("meows","mews")
|
||||
emote_see = list("shakes their head", "shivers")
|
||||
say_maybe_target = list("Meow?","Mew?","Mao?")
|
||||
say_got_target = list("MEOW!","HSSSS!","REEER!")
|
||||
|
||||
/mob/living/simple_mob/animal/passive/cat/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W, /obj/item/weapon/pen) || istype(W, /obj/item/device/flashlight/pen))
|
||||
if(named)
|
||||
to_chat(user, "<span class='notice'>\The [name] already has a name!</span>")
|
||||
else
|
||||
var/tmp_name = sanitizeSafe(tgui_input_text(user, "Give \the [name] a name", "Name", null, MAX_NAME_LEN), MAX_NAME_LEN)
|
||||
if(length(tmp_name) > 50)
|
||||
to_chat(user, "<span class='notice'>The name can be at most 50 characters long.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You name \the [name]. Meow!</span>")
|
||||
name = tmp_name
|
||||
named = TRUE
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/weapon/cat_box
|
||||
name = "faintly purring box"
|
||||
desc = "This box is purring faintly. You're pretty sure there's a cat inside it."
|
||||
icon = 'icons/obj/storage.dmi'
|
||||
icon_state = "box"
|
||||
var/cattype = /mob/living/simple_mob/animal/passive/cat
|
||||
|
||||
/obj/item/weapon/cat_box/attack_self(var/mob/user)
|
||||
var/turf/catturf = get_turf(src)
|
||||
to_chat(user, "<span class='notice'>You peek into \the [name]-- and a cat jumps out!</span>")
|
||||
new cattype(catturf)
|
||||
new /obj/item/stack/material/cardboard(catturf) //if i fits i sits
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/cat_box/black
|
||||
cattype = /mob/living/simple_mob/animal/passive/cat/black
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user