mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-13 08:03:43 +01:00
File standardisation (#13131)
* Adds the check components * Adds in trailing newlines * Converts all CRLF to LF * Post merge EOF * Post merge line endings * Final commit
This commit is contained in:
@@ -2,4 +2,4 @@
|
||||
Creature-level abilities.
|
||||
*/
|
||||
|
||||
/var/global/list/ability_verbs = list( )
|
||||
/var/global/list/ability_verbs = list( )
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
SSmobs.dead_players_by_zlevel[new_z] += src
|
||||
registered_z = new_z
|
||||
else
|
||||
registered_z = null
|
||||
registered_z = null
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
return
|
||||
|
||||
/mob/dead
|
||||
move_resist = INFINITY
|
||||
move_resist = INFINITY
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/mob/dead/observer/Login()
|
||||
..()
|
||||
if(ghostimage)
|
||||
ghostimage.icon_state = src.icon_state
|
||||
updateghostimages()
|
||||
|
||||
if(GLOB.non_respawnable_keys[ckey])
|
||||
can_reenter_corpse = 0
|
||||
GLOB.respawnable_list -= src
|
||||
/mob/dead/observer/Login()
|
||||
..()
|
||||
if(ghostimage)
|
||||
ghostimage.icon_state = src.icon_state
|
||||
updateghostimages()
|
||||
|
||||
if(GLOB.non_respawnable_keys[ckey])
|
||||
can_reenter_corpse = 0
|
||||
GLOB.respawnable_list -= src
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/mob/dead/observer/Logout()
|
||||
if(client)
|
||||
client.images -= ghost_images
|
||||
..()
|
||||
spawn(0)
|
||||
if(src && !key) //we've transferred to another mob. This ghost should be deleted.
|
||||
qdel(src)
|
||||
/mob/dead/observer/Logout()
|
||||
if(client)
|
||||
client.images -= ghost_images
|
||||
..()
|
||||
spawn(0)
|
||||
if(src && !key) //we've transferred to another mob. This ghost should be deleted.
|
||||
qdel(src)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,48 +1,48 @@
|
||||
/mob/dead/observer/say(var/message)
|
||||
message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN))
|
||||
|
||||
if(!message)
|
||||
return
|
||||
|
||||
log_ghostsay(message, src)
|
||||
|
||||
if(src.client)
|
||||
if(src.client.prefs.muted & MUTE_DEADCHAT)
|
||||
to_chat(src, "<span class='warning'>You cannot talk in deadchat (muted).</span>")
|
||||
return
|
||||
|
||||
if(src.client.handle_spam_prevention(message,MUTE_DEADCHAT))
|
||||
return
|
||||
|
||||
. = src.say_dead(message)
|
||||
|
||||
|
||||
/mob/dead/observer/emote(act, type, message, force)
|
||||
message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN))
|
||||
|
||||
if(!message)
|
||||
return
|
||||
|
||||
if(act != "me")
|
||||
return
|
||||
|
||||
log_ghostemote(message, src)
|
||||
|
||||
if(src.client)
|
||||
if(src.client.prefs.muted & MUTE_DEADCHAT)
|
||||
to_chat(src, "<span class='warning'>You cannot emote in deadchat (muted).</span>")
|
||||
return
|
||||
|
||||
if(src.client.handle_spam_prevention(message, MUTE_DEADCHAT))
|
||||
return
|
||||
|
||||
. = src.emote_dead(message)
|
||||
|
||||
/mob/dead/observer/handle_track(var/message, var/verb = "says", var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear)
|
||||
return "[speaker_name] ([ghost_follow_link(follow_target, ghost=src)])"
|
||||
|
||||
/mob/dead/observer/handle_speaker_name(var/mob/speaker = null, var/vname, var/hard_to_hear)
|
||||
var/speaker_name = ..()
|
||||
if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs.
|
||||
speaker_name = "[speaker.real_name] ([speaker_name])"
|
||||
return speaker_name
|
||||
/mob/dead/observer/say(var/message)
|
||||
message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN))
|
||||
|
||||
if(!message)
|
||||
return
|
||||
|
||||
log_ghostsay(message, src)
|
||||
|
||||
if(src.client)
|
||||
if(src.client.prefs.muted & MUTE_DEADCHAT)
|
||||
to_chat(src, "<span class='warning'>You cannot talk in deadchat (muted).</span>")
|
||||
return
|
||||
|
||||
if(src.client.handle_spam_prevention(message,MUTE_DEADCHAT))
|
||||
return
|
||||
|
||||
. = src.say_dead(message)
|
||||
|
||||
|
||||
/mob/dead/observer/emote(act, type, message, force)
|
||||
message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN))
|
||||
|
||||
if(!message)
|
||||
return
|
||||
|
||||
if(act != "me")
|
||||
return
|
||||
|
||||
log_ghostemote(message, src)
|
||||
|
||||
if(src.client)
|
||||
if(src.client.prefs.muted & MUTE_DEADCHAT)
|
||||
to_chat(src, "<span class='warning'>You cannot emote in deadchat (muted).</span>")
|
||||
return
|
||||
|
||||
if(src.client.handle_spam_prevention(message, MUTE_DEADCHAT))
|
||||
return
|
||||
|
||||
. = src.emote_dead(message)
|
||||
|
||||
/mob/dead/observer/handle_track(var/message, var/verb = "says", var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear)
|
||||
return "[speaker_name] ([ghost_follow_link(follow_target, ghost=src)])"
|
||||
|
||||
/mob/dead/observer/handle_speaker_name(var/mob/speaker = null, var/vname, var/hard_to_hear)
|
||||
var/speaker_name = ..()
|
||||
if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs.
|
||||
speaker_name = "[speaker.real_name] ([speaker_name])"
|
||||
return speaker_name
|
||||
|
||||
@@ -179,4 +179,4 @@
|
||||
name = speaker.voice_name
|
||||
|
||||
var/rendered = "<span class='game say'><span class='name'>[name]</span> [message]</span>"
|
||||
to_chat(src, rendered)
|
||||
to_chat(src, rendered)
|
||||
|
||||
+265
-265
@@ -1,265 +1,265 @@
|
||||
//These procs handle putting s tuff in your hand. It's probably best to use these rather than setting l_hand = ...etc
|
||||
//as they handle all relevant stuff like adding it to the player's screen and updating their overlays.
|
||||
|
||||
//Returns the thing in our active hand
|
||||
/mob/proc/get_active_hand()
|
||||
if(hand) return l_hand
|
||||
else return r_hand
|
||||
|
||||
/mob/verb/quick_equip()
|
||||
set name = "quick-equip"
|
||||
set hidden = 1
|
||||
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(I)
|
||||
I.equip_to_best_slot(src)
|
||||
|
||||
/mob/proc/is_in_active_hand(obj/item/I)
|
||||
var/obj/item/item_to_test = get_active_hand()
|
||||
|
||||
return item_to_test && item_to_test.is_equivalent(I)
|
||||
|
||||
|
||||
//Returns the thing in our inactive hand
|
||||
/mob/proc/get_inactive_hand()
|
||||
if(hand) return r_hand
|
||||
else return l_hand
|
||||
|
||||
/mob/proc/is_in_inactive_hand(obj/item/I)
|
||||
var/obj/item/item_to_test = get_inactive_hand()
|
||||
|
||||
return item_to_test && item_to_test.is_equivalent(I)
|
||||
|
||||
//Returns if a certain item can be equipped to a certain slot.
|
||||
// Currently invalid for two-handed items - call obj/item/mob_can_equip() instead.
|
||||
/mob/proc/can_equip(obj/item/I, slot, disable_warning = 0)
|
||||
return 0
|
||||
|
||||
// Because there's several different places it's stored.
|
||||
/mob/proc/get_multitool(var/if_active=0)
|
||||
return null
|
||||
|
||||
//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(!put_in_hand_check(W))
|
||||
return 0
|
||||
if(!l_hand && has_left_hand())
|
||||
W.forceMove(src) //TODO: move to equipped?
|
||||
l_hand = W
|
||||
W.layer = ABOVE_HUD_LAYER //TODO: move to equipped?
|
||||
W.plane = ABOVE_HUD_PLANE //TODO: move to equipped?
|
||||
W.equipped(src,slot_l_hand)
|
||||
if(pulling == W)
|
||||
stop_pulling()
|
||||
update_inv_l_hand()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//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(!put_in_hand_check(W))
|
||||
return 0
|
||||
if(!r_hand && has_right_hand())
|
||||
W.forceMove(src)
|
||||
r_hand = W
|
||||
W.layer = ABOVE_HUD_LAYER
|
||||
W.plane = ABOVE_HUD_PLANE
|
||||
W.equipped(src,slot_r_hand)
|
||||
if(pulling == W)
|
||||
stop_pulling()
|
||||
update_inv_r_hand()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/proc/put_in_hand_check(var/obj/item/W)
|
||||
if(lying && !(W.flags & ABSTRACT)) return 0
|
||||
if(!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)
|
||||
if(hand) return put_in_l_hand(W)
|
||||
else return put_in_r_hand(W)
|
||||
|
||||
//Puts the item into our inactive hand if possible. returns 1 on success.
|
||||
/mob/proc/put_in_inactive_hand(var/obj/item/W)
|
||||
if(hand) return put_in_r_hand(W)
|
||||
else return put_in_l_hand(W)
|
||||
|
||||
//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 :)
|
||||
//Just puts stuff on the floor for most mobs, since all mobs have hands but putting stuff in the AI/corgi/ghost hand is VERY BAD.
|
||||
/mob/proc/put_in_hands(obj/item/W)
|
||||
W.forceMove(drop_location())
|
||||
W.layer = initial(W.layer)
|
||||
W.plane = initial(W.plane)
|
||||
W.dropped()
|
||||
|
||||
/mob/proc/drop_item_v() //this is dumb.
|
||||
if(stat == CONSCIOUS && isturf(loc))
|
||||
return drop_item()
|
||||
return 0
|
||||
|
||||
//Drops the item in our left hand
|
||||
/mob/proc/drop_l_hand()
|
||||
return unEquip(l_hand) //All needed checks are in unEquip
|
||||
|
||||
//Drops the item in our right hand
|
||||
/mob/proc/drop_r_hand()
|
||||
return unEquip(r_hand) //Why was this not calling unEquip in the first place jesus fuck.
|
||||
|
||||
//Drops the item in our active hand.
|
||||
/mob/proc/drop_item() //THIS. DOES. NOT. NEED. AN. ARGUMENT.
|
||||
if(hand)
|
||||
return drop_l_hand()
|
||||
else
|
||||
return drop_r_hand()
|
||||
|
||||
//Here lie unEquip and before_item_take, already forgotten and not missed.
|
||||
|
||||
/mob/proc/canUnEquip(obj/item/I, force)
|
||||
if(!I)
|
||||
return 1
|
||||
if((I.flags & NODROP) && !force)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/proc/unEquip(obj/item/I, force) //Force overrides NODROP for things like wizarditis and admin undress.
|
||||
if(!I) //If there's nothing to drop, the drop is automatically succesfull. If(unEquip) should generally be used to check for NODROP.
|
||||
return 1
|
||||
|
||||
if(!canUnEquip(I, force))
|
||||
return 0
|
||||
|
||||
if(I == r_hand)
|
||||
r_hand = null
|
||||
update_inv_r_hand()
|
||||
else if(I == l_hand)
|
||||
l_hand = null
|
||||
update_inv_l_hand()
|
||||
else if(I in tkgrabbed_objects)
|
||||
var/obj/item/tk_grab/tkgrab = tkgrabbed_objects[I]
|
||||
unEquip(tkgrab, force)
|
||||
|
||||
if(I)
|
||||
if(client)
|
||||
client.screen -= I
|
||||
I.forceMove(drop_location())
|
||||
I.dropped(src)
|
||||
if(I)
|
||||
I.layer = initial(I.layer)
|
||||
I.plane = initial(I.plane)
|
||||
return 1
|
||||
|
||||
|
||||
//Attemps to remove an object on a mob. Will not move it to another area or such, just removes from the mob.
|
||||
/mob/proc/remove_from_mob(var/obj/O)
|
||||
unEquip(O)
|
||||
O.screen_loc = null
|
||||
return 1
|
||||
|
||||
|
||||
//Outdated but still in use apparently. This should at least be a human proc.
|
||||
//Daily reminder to murder this - Remie.
|
||||
/mob/proc/get_equipped_items(include_pockets = FALSE)
|
||||
var/list/items = list()
|
||||
if(back)
|
||||
items += back
|
||||
if(wear_mask)
|
||||
items += wear_mask
|
||||
return items
|
||||
|
||||
/mob/living/carbon/get_equipped_items(include_pockets = FALSE)
|
||||
var/list/items = ..()
|
||||
if(wear_suit)
|
||||
items += wear_suit
|
||||
if(head)
|
||||
items += head
|
||||
return items
|
||||
|
||||
/mob/living/carbon/human/get_equipped_items(include_pockets = FALSE)
|
||||
var/list/items = ..()
|
||||
if(belt)
|
||||
items += belt
|
||||
if(l_ear)
|
||||
items += l_ear
|
||||
if(r_ear)
|
||||
items += r_ear
|
||||
if(glasses)
|
||||
items += glasses
|
||||
if(gloves)
|
||||
items += gloves
|
||||
if(shoes)
|
||||
items += shoes
|
||||
if(wear_id)
|
||||
items += wear_id
|
||||
if(wear_pda)
|
||||
items += wear_pda
|
||||
if(w_uniform)
|
||||
items += w_uniform
|
||||
if(include_pockets)
|
||||
if(l_store)
|
||||
items += l_store
|
||||
if(r_store)
|
||||
items += r_store
|
||||
if(s_store)
|
||||
items += s_store
|
||||
return items
|
||||
|
||||
/obj/item/proc/equip_to_best_slot(mob/M)
|
||||
if(src != M.get_active_hand())
|
||||
to_chat(M, "<span class='warning'>You are not holding anything to equip!</span>")
|
||||
return 0
|
||||
|
||||
if(M.equip_to_appropriate_slot(src))
|
||||
if(M.hand)
|
||||
M.update_inv_l_hand(0)
|
||||
else
|
||||
M.update_inv_r_hand(0)
|
||||
return 1
|
||||
|
||||
if(M.s_active && M.s_active.can_be_inserted(src, 1)) //if storage active insert there
|
||||
M.s_active.handle_item_insertion(src)
|
||||
return 1
|
||||
|
||||
var/obj/item/storage/S = M.get_inactive_hand()
|
||||
if(istype(S) && S.can_be_inserted(src, 1)) //see if we have box in other hand
|
||||
S.handle_item_insertion(src)
|
||||
return 1
|
||||
|
||||
S = M.get_item_by_slot(slot_belt)
|
||||
if(istype(S) && S.can_be_inserted(src, 1)) //else we put in belt
|
||||
S.handle_item_insertion(src)
|
||||
return 1
|
||||
|
||||
S = M.get_item_by_slot(slot_back) //else we put in backpack
|
||||
if(istype(S) && S.can_be_inserted(src, 1))
|
||||
S.handle_item_insertion(src)
|
||||
playsound(loc, "rustle", 50, 1, -5)
|
||||
return 1
|
||||
|
||||
to_chat(M, "<span class='warning'>You are unable to equip that!</span>")
|
||||
return 0
|
||||
|
||||
/mob/proc/get_all_slots()
|
||||
return list(wear_mask, back, l_hand, r_hand)
|
||||
|
||||
/mob/proc/get_id_card()
|
||||
for(var/obj/item/I in get_all_slots())
|
||||
. = I.GetID()
|
||||
if(.)
|
||||
break
|
||||
|
||||
/mob/proc/get_item_by_slot(slot_id)
|
||||
switch(slot_id)
|
||||
if(slot_wear_mask)
|
||||
return wear_mask
|
||||
if(slot_back)
|
||||
return back
|
||||
if(slot_l_hand)
|
||||
return l_hand
|
||||
if(slot_r_hand)
|
||||
return r_hand
|
||||
return null
|
||||
|
||||
//These procs handle putting s tuff in your hand. It's probably best to use these rather than setting l_hand = ...etc
|
||||
//as they handle all relevant stuff like adding it to the player's screen and updating their overlays.
|
||||
|
||||
//Returns the thing in our active hand
|
||||
/mob/proc/get_active_hand()
|
||||
if(hand) return l_hand
|
||||
else return r_hand
|
||||
|
||||
/mob/verb/quick_equip()
|
||||
set name = "quick-equip"
|
||||
set hidden = 1
|
||||
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(I)
|
||||
I.equip_to_best_slot(src)
|
||||
|
||||
/mob/proc/is_in_active_hand(obj/item/I)
|
||||
var/obj/item/item_to_test = get_active_hand()
|
||||
|
||||
return item_to_test && item_to_test.is_equivalent(I)
|
||||
|
||||
|
||||
//Returns the thing in our inactive hand
|
||||
/mob/proc/get_inactive_hand()
|
||||
if(hand) return r_hand
|
||||
else return l_hand
|
||||
|
||||
/mob/proc/is_in_inactive_hand(obj/item/I)
|
||||
var/obj/item/item_to_test = get_inactive_hand()
|
||||
|
||||
return item_to_test && item_to_test.is_equivalent(I)
|
||||
|
||||
//Returns if a certain item can be equipped to a certain slot.
|
||||
// Currently invalid for two-handed items - call obj/item/mob_can_equip() instead.
|
||||
/mob/proc/can_equip(obj/item/I, slot, disable_warning = 0)
|
||||
return 0
|
||||
|
||||
// Because there's several different places it's stored.
|
||||
/mob/proc/get_multitool(var/if_active=0)
|
||||
return null
|
||||
|
||||
//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(!put_in_hand_check(W))
|
||||
return 0
|
||||
if(!l_hand && has_left_hand())
|
||||
W.forceMove(src) //TODO: move to equipped?
|
||||
l_hand = W
|
||||
W.layer = ABOVE_HUD_LAYER //TODO: move to equipped?
|
||||
W.plane = ABOVE_HUD_PLANE //TODO: move to equipped?
|
||||
W.equipped(src,slot_l_hand)
|
||||
if(pulling == W)
|
||||
stop_pulling()
|
||||
update_inv_l_hand()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//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(!put_in_hand_check(W))
|
||||
return 0
|
||||
if(!r_hand && has_right_hand())
|
||||
W.forceMove(src)
|
||||
r_hand = W
|
||||
W.layer = ABOVE_HUD_LAYER
|
||||
W.plane = ABOVE_HUD_PLANE
|
||||
W.equipped(src,slot_r_hand)
|
||||
if(pulling == W)
|
||||
stop_pulling()
|
||||
update_inv_r_hand()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/proc/put_in_hand_check(var/obj/item/W)
|
||||
if(lying && !(W.flags & ABSTRACT)) return 0
|
||||
if(!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)
|
||||
if(hand) return put_in_l_hand(W)
|
||||
else return put_in_r_hand(W)
|
||||
|
||||
//Puts the item into our inactive hand if possible. returns 1 on success.
|
||||
/mob/proc/put_in_inactive_hand(var/obj/item/W)
|
||||
if(hand) return put_in_r_hand(W)
|
||||
else return put_in_l_hand(W)
|
||||
|
||||
//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 :)
|
||||
//Just puts stuff on the floor for most mobs, since all mobs have hands but putting stuff in the AI/corgi/ghost hand is VERY BAD.
|
||||
/mob/proc/put_in_hands(obj/item/W)
|
||||
W.forceMove(drop_location())
|
||||
W.layer = initial(W.layer)
|
||||
W.plane = initial(W.plane)
|
||||
W.dropped()
|
||||
|
||||
/mob/proc/drop_item_v() //this is dumb.
|
||||
if(stat == CONSCIOUS && isturf(loc))
|
||||
return drop_item()
|
||||
return 0
|
||||
|
||||
//Drops the item in our left hand
|
||||
/mob/proc/drop_l_hand()
|
||||
return unEquip(l_hand) //All needed checks are in unEquip
|
||||
|
||||
//Drops the item in our right hand
|
||||
/mob/proc/drop_r_hand()
|
||||
return unEquip(r_hand) //Why was this not calling unEquip in the first place jesus fuck.
|
||||
|
||||
//Drops the item in our active hand.
|
||||
/mob/proc/drop_item() //THIS. DOES. NOT. NEED. AN. ARGUMENT.
|
||||
if(hand)
|
||||
return drop_l_hand()
|
||||
else
|
||||
return drop_r_hand()
|
||||
|
||||
//Here lie unEquip and before_item_take, already forgotten and not missed.
|
||||
|
||||
/mob/proc/canUnEquip(obj/item/I, force)
|
||||
if(!I)
|
||||
return 1
|
||||
if((I.flags & NODROP) && !force)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/proc/unEquip(obj/item/I, force) //Force overrides NODROP for things like wizarditis and admin undress.
|
||||
if(!I) //If there's nothing to drop, the drop is automatically succesfull. If(unEquip) should generally be used to check for NODROP.
|
||||
return 1
|
||||
|
||||
if(!canUnEquip(I, force))
|
||||
return 0
|
||||
|
||||
if(I == r_hand)
|
||||
r_hand = null
|
||||
update_inv_r_hand()
|
||||
else if(I == l_hand)
|
||||
l_hand = null
|
||||
update_inv_l_hand()
|
||||
else if(I in tkgrabbed_objects)
|
||||
var/obj/item/tk_grab/tkgrab = tkgrabbed_objects[I]
|
||||
unEquip(tkgrab, force)
|
||||
|
||||
if(I)
|
||||
if(client)
|
||||
client.screen -= I
|
||||
I.forceMove(drop_location())
|
||||
I.dropped(src)
|
||||
if(I)
|
||||
I.layer = initial(I.layer)
|
||||
I.plane = initial(I.plane)
|
||||
return 1
|
||||
|
||||
|
||||
//Attemps to remove an object on a mob. Will not move it to another area or such, just removes from the mob.
|
||||
/mob/proc/remove_from_mob(var/obj/O)
|
||||
unEquip(O)
|
||||
O.screen_loc = null
|
||||
return 1
|
||||
|
||||
|
||||
//Outdated but still in use apparently. This should at least be a human proc.
|
||||
//Daily reminder to murder this - Remie.
|
||||
/mob/proc/get_equipped_items(include_pockets = FALSE)
|
||||
var/list/items = list()
|
||||
if(back)
|
||||
items += back
|
||||
if(wear_mask)
|
||||
items += wear_mask
|
||||
return items
|
||||
|
||||
/mob/living/carbon/get_equipped_items(include_pockets = FALSE)
|
||||
var/list/items = ..()
|
||||
if(wear_suit)
|
||||
items += wear_suit
|
||||
if(head)
|
||||
items += head
|
||||
return items
|
||||
|
||||
/mob/living/carbon/human/get_equipped_items(include_pockets = FALSE)
|
||||
var/list/items = ..()
|
||||
if(belt)
|
||||
items += belt
|
||||
if(l_ear)
|
||||
items += l_ear
|
||||
if(r_ear)
|
||||
items += r_ear
|
||||
if(glasses)
|
||||
items += glasses
|
||||
if(gloves)
|
||||
items += gloves
|
||||
if(shoes)
|
||||
items += shoes
|
||||
if(wear_id)
|
||||
items += wear_id
|
||||
if(wear_pda)
|
||||
items += wear_pda
|
||||
if(w_uniform)
|
||||
items += w_uniform
|
||||
if(include_pockets)
|
||||
if(l_store)
|
||||
items += l_store
|
||||
if(r_store)
|
||||
items += r_store
|
||||
if(s_store)
|
||||
items += s_store
|
||||
return items
|
||||
|
||||
/obj/item/proc/equip_to_best_slot(mob/M)
|
||||
if(src != M.get_active_hand())
|
||||
to_chat(M, "<span class='warning'>You are not holding anything to equip!</span>")
|
||||
return 0
|
||||
|
||||
if(M.equip_to_appropriate_slot(src))
|
||||
if(M.hand)
|
||||
M.update_inv_l_hand(0)
|
||||
else
|
||||
M.update_inv_r_hand(0)
|
||||
return 1
|
||||
|
||||
if(M.s_active && M.s_active.can_be_inserted(src, 1)) //if storage active insert there
|
||||
M.s_active.handle_item_insertion(src)
|
||||
return 1
|
||||
|
||||
var/obj/item/storage/S = M.get_inactive_hand()
|
||||
if(istype(S) && S.can_be_inserted(src, 1)) //see if we have box in other hand
|
||||
S.handle_item_insertion(src)
|
||||
return 1
|
||||
|
||||
S = M.get_item_by_slot(slot_belt)
|
||||
if(istype(S) && S.can_be_inserted(src, 1)) //else we put in belt
|
||||
S.handle_item_insertion(src)
|
||||
return 1
|
||||
|
||||
S = M.get_item_by_slot(slot_back) //else we put in backpack
|
||||
if(istype(S) && S.can_be_inserted(src, 1))
|
||||
S.handle_item_insertion(src)
|
||||
playsound(loc, "rustle", 50, 1, -5)
|
||||
return 1
|
||||
|
||||
to_chat(M, "<span class='warning'>You are unable to equip that!</span>")
|
||||
return 0
|
||||
|
||||
/mob/proc/get_all_slots()
|
||||
return list(wear_mask, back, l_hand, r_hand)
|
||||
|
||||
/mob/proc/get_id_card()
|
||||
for(var/obj/item/I in get_all_slots())
|
||||
. = I.GetID()
|
||||
if(.)
|
||||
break
|
||||
|
||||
/mob/proc/get_item_by_slot(slot_id)
|
||||
switch(slot_id)
|
||||
if(slot_wear_mask)
|
||||
return wear_mask
|
||||
if(slot_back)
|
||||
return back
|
||||
if(slot_l_hand)
|
||||
return l_hand
|
||||
if(slot_r_hand)
|
||||
return r_hand
|
||||
return null
|
||||
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
|
||||
#define COLD_GAS_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when the current breath's temperature just passes the 260.15k safety point
|
||||
#define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point
|
||||
#define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point
|
||||
#define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point
|
||||
|
||||
@@ -1,308 +1,308 @@
|
||||
/mob/living/carbon/alien
|
||||
name = "alien"
|
||||
voice_name = "alien"
|
||||
speak_emote = list("hisses")
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
gender = NEUTER
|
||||
dna = null
|
||||
alien_talk_understand = TRUE
|
||||
|
||||
var/nightvision = FALSE
|
||||
see_in_dark = 4
|
||||
|
||||
var/obj/item/card/id/wear_id = null // Fix for station bounced radios -- Skie
|
||||
var/has_fine_manipulation = FALSE
|
||||
var/move_delay_add = FALSE // movement delay to add
|
||||
|
||||
status_flags = CANPARALYSE|CANPUSH
|
||||
var/heal_rate = 5
|
||||
|
||||
var/large = FALSE
|
||||
var/heat_protection = 0.5
|
||||
var/leaping = FALSE
|
||||
ventcrawler = 2
|
||||
var/list/alien_organs = list()
|
||||
var/death_message = "lets out a waning guttural screech, green blood bubbling from its maw..."
|
||||
var/death_sound = 'sound/voice/hiss6.ogg'
|
||||
|
||||
/mob/living/carbon/alien/New()
|
||||
verbs += /mob/living/verb/mob_sleep
|
||||
verbs += /mob/living/verb/lay_down
|
||||
alien_organs += new /obj/item/organ/internal/brain/xeno
|
||||
alien_organs += new /obj/item/organ/internal/xenos/hivenode
|
||||
alien_organs += new /obj/item/organ/internal/ears
|
||||
for(var/obj/item/organ/internal/I in alien_organs)
|
||||
I.insert(src)
|
||||
..()
|
||||
|
||||
/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/adjustToxLoss(amount)
|
||||
return STATUS_UPDATE_NONE
|
||||
|
||||
/mob/living/carbon/alien/adjustFireLoss(amount) // Weak to Fire
|
||||
if(amount > 0)
|
||||
return ..(amount * 2)
|
||||
else
|
||||
return ..(amount)
|
||||
|
||||
|
||||
/mob/living/carbon/alien/check_eye_prot()
|
||||
return 2
|
||||
|
||||
/mob/living/carbon/alien/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = maxHealth
|
||||
stat = CONSCIOUS
|
||||
return
|
||||
health = maxHealth - getOxyLoss() - getFireLoss() - getBruteLoss() - getCloneLoss()
|
||||
|
||||
update_stat("updatehealth([reason])")
|
||||
med_hud_set_health()
|
||||
med_hud_set_status()
|
||||
handle_hud_icons_health()
|
||||
|
||||
/mob/living/carbon/alien/handle_environment(var/datum/gas_mixture/environment)
|
||||
|
||||
if(!environment)
|
||||
return
|
||||
|
||||
var/loc_temp = get_temperature(environment)
|
||||
|
||||
// to_chat(world, "Loc temp: [loc_temp] - Body temp: [bodytemperature] - Fireloss: [getFireLoss()] - Fire protection: [heat_protection] - Location: [loc] - src: [src]")
|
||||
|
||||
// Aliens are now weak to fire.
|
||||
|
||||
//After then, it reacts to the surrounding atmosphere based on your thermal protection
|
||||
if(!on_fire) // If you're on fire, ignore local air temperature
|
||||
if(loc_temp > bodytemperature)
|
||||
//Place is hotter than we are
|
||||
var/thermal_protection = heat_protection //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
|
||||
if(thermal_protection < 1)
|
||||
bodytemperature += (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR)
|
||||
else
|
||||
bodytemperature += 1 * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR)
|
||||
// bodytemperature -= max((loc_temp - bodytemperature / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM)
|
||||
|
||||
// +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt.
|
||||
if(bodytemperature > 360.15)
|
||||
//Body temperature is too hot.
|
||||
throw_alert("alien_fire", /obj/screen/alert/alien_fire)
|
||||
switch(bodytemperature)
|
||||
if(360 to 400)
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_1, BURN)
|
||||
if(400 to 460)
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_2, BURN)
|
||||
if(460 to INFINITY)
|
||||
if(on_fire)
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_3, BURN)
|
||||
else
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_2, BURN)
|
||||
else
|
||||
clear_alert("alien_fire")
|
||||
|
||||
/mob/living/carbon/alien/handle_fire()//Aliens on fire code
|
||||
if(..())
|
||||
return
|
||||
bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up!
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/IsAdvancedToolUser()
|
||||
return has_fine_manipulation
|
||||
|
||||
/mob/living/carbon/alien/Stat()
|
||||
..()
|
||||
statpanel("Status")
|
||||
stat(null, "Intent: [a_intent]")
|
||||
stat(null, "Move Mode: [m_intent]")
|
||||
show_stat_emergency_shuttle_eta()
|
||||
|
||||
/mob/living/carbon/alien/SetStunned(amount, updating = 1, force = 0)
|
||||
..()
|
||||
if(!(status_flags & CANSTUN) && amount)
|
||||
// add some movement delay
|
||||
move_delay_add = min(move_delay_add + round(amount / 2), 10) // a maximum delay of 10
|
||||
|
||||
/mob/living/carbon/alien/movement_delay()
|
||||
. = ..()
|
||||
. += move_delay_add + config.alien_delay //move_delay_add is used to slow aliens with stuns
|
||||
|
||||
/mob/living/carbon/alien/getDNA()
|
||||
return null
|
||||
|
||||
/mob/living/carbon/alien/setDNA()
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/verb/nightvisiontoggle()
|
||||
set name = "Toggle Night Vision"
|
||||
set category = "Alien"
|
||||
|
||||
if(!nightvision)
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
nightvision = TRUE
|
||||
usr.hud_used.nightvisionicon.icon_state = "nightvision1"
|
||||
else if(nightvision)
|
||||
see_in_dark = initial(see_in_dark)
|
||||
lighting_alpha = initial(lighting_alpha)
|
||||
nightvision = FALSE
|
||||
usr.hud_used.nightvisionicon.icon_state = "nightvision0"
|
||||
|
||||
update_sight()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/assess_threat(var/mob/living/simple_animal/bot/secbot/judgebot, var/lasercolor)
|
||||
if(judgebot.emagged == 2)
|
||||
return 10 //Everyone is a criminal!
|
||||
var/threatcount = 0
|
||||
|
||||
//Securitrons can't identify aliens
|
||||
if(!lasercolor && judgebot.idcheck)
|
||||
threatcount += 4
|
||||
|
||||
//Lasertag bullshit
|
||||
if(lasercolor)
|
||||
if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve
|
||||
if((istype(r_hand,/obj/item/gun/energy/laser/tag/red)) || (istype(l_hand,/obj/item/gun/energy/laser/tag/red)))
|
||||
threatcount += 4
|
||||
|
||||
if(lasercolor == "r")
|
||||
if((istype(r_hand,/obj/item/gun/energy/laser/tag/blue)) || (istype(l_hand,/obj/item/gun/energy/laser/tag/blue)))
|
||||
threatcount += 4
|
||||
|
||||
return threatcount
|
||||
|
||||
//Check for weapons
|
||||
if(judgebot.weaponscheck)
|
||||
if(judgebot.check_for_weapons(l_hand))
|
||||
threatcount += 4
|
||||
if(judgebot.check_for_weapons(r_hand))
|
||||
threatcount += 4
|
||||
|
||||
//Mindshield implants imply trustworthyness
|
||||
if(ismindshielded(src))
|
||||
threatcount -= 1
|
||||
|
||||
return threatcount
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: AddInfectionImages()
|
||||
Des: Gives the client of the alien an image on each infected mob.
|
||||
----------------------------------------*/
|
||||
/mob/living/carbon/alien/proc/AddInfectionImages()
|
||||
if(client)
|
||||
for(var/mob/living/C in GLOB.mob_list)
|
||||
if(C.status_flags & XENO_HOST)
|
||||
var/obj/item/organ/internal/body_egg/alien_embryo/A = C.get_int_organ(/obj/item/organ/internal/body_egg/alien_embryo)
|
||||
if(A)
|
||||
var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[A.stage]")
|
||||
client.images += I
|
||||
return
|
||||
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: RemoveInfectionImages()
|
||||
Des: Removes all infected images from the alien.
|
||||
----------------------------------------*/
|
||||
/mob/living/carbon/alien/proc/RemoveInfectionImages()
|
||||
if(client)
|
||||
for(var/image/I in client.images)
|
||||
if(dd_hasprefix_case(I.icon_state, "infected"))
|
||||
qdel(I)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/canBeHandcuffed()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/alien/proc/updatePlasmaDisplay()
|
||||
if(hud_used) //clientless aliens
|
||||
hud_used.alien_plasma_display.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'> <font color='magenta'>[getPlasma()]</font></div>"
|
||||
|
||||
/mob/living/carbon/alien/larva/updatePlasmaDisplay()
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/can_use_vents()
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/handle_footstep(turf/T)
|
||||
if(..())
|
||||
if(T.footstep_sounds["xeno"])
|
||||
var/S = pick(T.footstep_sounds["xeno"])
|
||||
if(S)
|
||||
if(m_intent == MOVE_INTENT_RUN)
|
||||
if(!(step_count % 2)) //every other turf makes a sound
|
||||
return 0
|
||||
|
||||
var/range = -(world.view - 2)
|
||||
range -= 0.666 //-(7 - 2) = (-5) = -5 | -5 - (0.666) = -5.666 | (7 + -5.666) = 1.334 | 1.334 * 3 = 4.002 | range(4.002) = range(4)
|
||||
var/volume = 5
|
||||
|
||||
if(m_intent == MOVE_INTENT_WALK)
|
||||
return 0 //silent when walking
|
||||
|
||||
if(buckled || lying || throwing)
|
||||
return 0 //people flying, lying down or sitting do not step
|
||||
|
||||
if(!has_gravity(src))
|
||||
if(step_count % 3) //this basically says, every three moves make a noise
|
||||
return 0 //1st - none, 1%3==1, 2nd - none, 2%3==2, 3rd - noise, 3%3==0
|
||||
|
||||
playsound(T, S, volume, 1, range)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/alien/getTrail()
|
||||
if(getBruteLoss() < 200)
|
||||
return pick("xltrails_1", "xltrails_2")
|
||||
else
|
||||
return pick("xttrails_1", "xttrails_2")
|
||||
|
||||
/mob/living/carbon/alien/update_sight()
|
||||
if(!client)
|
||||
return
|
||||
if(stat == DEAD)
|
||||
grant_death_vision()
|
||||
return
|
||||
|
||||
see_invisible = initial(see_invisible)
|
||||
sight = SEE_MOBS
|
||||
if(nightvision)
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
else
|
||||
see_in_dark = initial(see_in_dark)
|
||||
lighting_alpha = initial(lighting_alpha)
|
||||
|
||||
if(client.eye != src)
|
||||
var/atom/A = client.eye
|
||||
if(A.update_remote_sight(src)) //returns 1 if we override all other sight updates.
|
||||
return
|
||||
|
||||
for(var/obj/item/organ/internal/cyberimp/eyes/E in internal_organs)
|
||||
sight |= E.vision_flags
|
||||
if(E.see_in_dark)
|
||||
see_in_dark = max(see_in_dark, E.see_in_dark)
|
||||
if(E.see_invisible)
|
||||
see_invisible = min(see_invisible, E.see_invisible)
|
||||
if(!isnull(E.lighting_alpha))
|
||||
lighting_alpha = min(lighting_alpha, E.lighting_alpha)
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT)
|
||||
sync_lighting_plane_alpha()
|
||||
/mob/living/carbon/alien
|
||||
name = "alien"
|
||||
voice_name = "alien"
|
||||
speak_emote = list("hisses")
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
gender = NEUTER
|
||||
dna = null
|
||||
alien_talk_understand = TRUE
|
||||
|
||||
var/nightvision = FALSE
|
||||
see_in_dark = 4
|
||||
|
||||
var/obj/item/card/id/wear_id = null // Fix for station bounced radios -- Skie
|
||||
var/has_fine_manipulation = FALSE
|
||||
var/move_delay_add = FALSE // movement delay to add
|
||||
|
||||
status_flags = CANPARALYSE|CANPUSH
|
||||
var/heal_rate = 5
|
||||
|
||||
var/large = FALSE
|
||||
var/heat_protection = 0.5
|
||||
var/leaping = FALSE
|
||||
ventcrawler = 2
|
||||
var/list/alien_organs = list()
|
||||
var/death_message = "lets out a waning guttural screech, green blood bubbling from its maw..."
|
||||
var/death_sound = 'sound/voice/hiss6.ogg'
|
||||
|
||||
/mob/living/carbon/alien/New()
|
||||
verbs += /mob/living/verb/mob_sleep
|
||||
verbs += /mob/living/verb/lay_down
|
||||
alien_organs += new /obj/item/organ/internal/brain/xeno
|
||||
alien_organs += new /obj/item/organ/internal/xenos/hivenode
|
||||
alien_organs += new /obj/item/organ/internal/ears
|
||||
for(var/obj/item/organ/internal/I in alien_organs)
|
||||
I.insert(src)
|
||||
..()
|
||||
|
||||
/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/adjustToxLoss(amount)
|
||||
return STATUS_UPDATE_NONE
|
||||
|
||||
/mob/living/carbon/alien/adjustFireLoss(amount) // Weak to Fire
|
||||
if(amount > 0)
|
||||
return ..(amount * 2)
|
||||
else
|
||||
return ..(amount)
|
||||
|
||||
|
||||
/mob/living/carbon/alien/check_eye_prot()
|
||||
return 2
|
||||
|
||||
/mob/living/carbon/alien/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = maxHealth
|
||||
stat = CONSCIOUS
|
||||
return
|
||||
health = maxHealth - getOxyLoss() - getFireLoss() - getBruteLoss() - getCloneLoss()
|
||||
|
||||
update_stat("updatehealth([reason])")
|
||||
med_hud_set_health()
|
||||
med_hud_set_status()
|
||||
handle_hud_icons_health()
|
||||
|
||||
/mob/living/carbon/alien/handle_environment(var/datum/gas_mixture/environment)
|
||||
|
||||
if(!environment)
|
||||
return
|
||||
|
||||
var/loc_temp = get_temperature(environment)
|
||||
|
||||
// to_chat(world, "Loc temp: [loc_temp] - Body temp: [bodytemperature] - Fireloss: [getFireLoss()] - Fire protection: [heat_protection] - Location: [loc] - src: [src]")
|
||||
|
||||
// Aliens are now weak to fire.
|
||||
|
||||
//After then, it reacts to the surrounding atmosphere based on your thermal protection
|
||||
if(!on_fire) // If you're on fire, ignore local air temperature
|
||||
if(loc_temp > bodytemperature)
|
||||
//Place is hotter than we are
|
||||
var/thermal_protection = heat_protection //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
|
||||
if(thermal_protection < 1)
|
||||
bodytemperature += (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR)
|
||||
else
|
||||
bodytemperature += 1 * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR)
|
||||
// bodytemperature -= max((loc_temp - bodytemperature / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM)
|
||||
|
||||
// +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt.
|
||||
if(bodytemperature > 360.15)
|
||||
//Body temperature is too hot.
|
||||
throw_alert("alien_fire", /obj/screen/alert/alien_fire)
|
||||
switch(bodytemperature)
|
||||
if(360 to 400)
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_1, BURN)
|
||||
if(400 to 460)
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_2, BURN)
|
||||
if(460 to INFINITY)
|
||||
if(on_fire)
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_3, BURN)
|
||||
else
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_2, BURN)
|
||||
else
|
||||
clear_alert("alien_fire")
|
||||
|
||||
/mob/living/carbon/alien/handle_fire()//Aliens on fire code
|
||||
if(..())
|
||||
return
|
||||
bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up!
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/IsAdvancedToolUser()
|
||||
return has_fine_manipulation
|
||||
|
||||
/mob/living/carbon/alien/Stat()
|
||||
..()
|
||||
statpanel("Status")
|
||||
stat(null, "Intent: [a_intent]")
|
||||
stat(null, "Move Mode: [m_intent]")
|
||||
show_stat_emergency_shuttle_eta()
|
||||
|
||||
/mob/living/carbon/alien/SetStunned(amount, updating = 1, force = 0)
|
||||
..()
|
||||
if(!(status_flags & CANSTUN) && amount)
|
||||
// add some movement delay
|
||||
move_delay_add = min(move_delay_add + round(amount / 2), 10) // a maximum delay of 10
|
||||
|
||||
/mob/living/carbon/alien/movement_delay()
|
||||
. = ..()
|
||||
. += move_delay_add + config.alien_delay //move_delay_add is used to slow aliens with stuns
|
||||
|
||||
/mob/living/carbon/alien/getDNA()
|
||||
return null
|
||||
|
||||
/mob/living/carbon/alien/setDNA()
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/verb/nightvisiontoggle()
|
||||
set name = "Toggle Night Vision"
|
||||
set category = "Alien"
|
||||
|
||||
if(!nightvision)
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
nightvision = TRUE
|
||||
usr.hud_used.nightvisionicon.icon_state = "nightvision1"
|
||||
else if(nightvision)
|
||||
see_in_dark = initial(see_in_dark)
|
||||
lighting_alpha = initial(lighting_alpha)
|
||||
nightvision = FALSE
|
||||
usr.hud_used.nightvisionicon.icon_state = "nightvision0"
|
||||
|
||||
update_sight()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/assess_threat(var/mob/living/simple_animal/bot/secbot/judgebot, var/lasercolor)
|
||||
if(judgebot.emagged == 2)
|
||||
return 10 //Everyone is a criminal!
|
||||
var/threatcount = 0
|
||||
|
||||
//Securitrons can't identify aliens
|
||||
if(!lasercolor && judgebot.idcheck)
|
||||
threatcount += 4
|
||||
|
||||
//Lasertag bullshit
|
||||
if(lasercolor)
|
||||
if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve
|
||||
if((istype(r_hand,/obj/item/gun/energy/laser/tag/red)) || (istype(l_hand,/obj/item/gun/energy/laser/tag/red)))
|
||||
threatcount += 4
|
||||
|
||||
if(lasercolor == "r")
|
||||
if((istype(r_hand,/obj/item/gun/energy/laser/tag/blue)) || (istype(l_hand,/obj/item/gun/energy/laser/tag/blue)))
|
||||
threatcount += 4
|
||||
|
||||
return threatcount
|
||||
|
||||
//Check for weapons
|
||||
if(judgebot.weaponscheck)
|
||||
if(judgebot.check_for_weapons(l_hand))
|
||||
threatcount += 4
|
||||
if(judgebot.check_for_weapons(r_hand))
|
||||
threatcount += 4
|
||||
|
||||
//Mindshield implants imply trustworthyness
|
||||
if(ismindshielded(src))
|
||||
threatcount -= 1
|
||||
|
||||
return threatcount
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: AddInfectionImages()
|
||||
Des: Gives the client of the alien an image on each infected mob.
|
||||
----------------------------------------*/
|
||||
/mob/living/carbon/alien/proc/AddInfectionImages()
|
||||
if(client)
|
||||
for(var/mob/living/C in GLOB.mob_list)
|
||||
if(C.status_flags & XENO_HOST)
|
||||
var/obj/item/organ/internal/body_egg/alien_embryo/A = C.get_int_organ(/obj/item/organ/internal/body_egg/alien_embryo)
|
||||
if(A)
|
||||
var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[A.stage]")
|
||||
client.images += I
|
||||
return
|
||||
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: RemoveInfectionImages()
|
||||
Des: Removes all infected images from the alien.
|
||||
----------------------------------------*/
|
||||
/mob/living/carbon/alien/proc/RemoveInfectionImages()
|
||||
if(client)
|
||||
for(var/image/I in client.images)
|
||||
if(dd_hasprefix_case(I.icon_state, "infected"))
|
||||
qdel(I)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/canBeHandcuffed()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/alien/proc/updatePlasmaDisplay()
|
||||
if(hud_used) //clientless aliens
|
||||
hud_used.alien_plasma_display.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'> <font color='magenta'>[getPlasma()]</font></div>"
|
||||
|
||||
/mob/living/carbon/alien/larva/updatePlasmaDisplay()
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/can_use_vents()
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/handle_footstep(turf/T)
|
||||
if(..())
|
||||
if(T.footstep_sounds["xeno"])
|
||||
var/S = pick(T.footstep_sounds["xeno"])
|
||||
if(S)
|
||||
if(m_intent == MOVE_INTENT_RUN)
|
||||
if(!(step_count % 2)) //every other turf makes a sound
|
||||
return 0
|
||||
|
||||
var/range = -(world.view - 2)
|
||||
range -= 0.666 //-(7 - 2) = (-5) = -5 | -5 - (0.666) = -5.666 | (7 + -5.666) = 1.334 | 1.334 * 3 = 4.002 | range(4.002) = range(4)
|
||||
var/volume = 5
|
||||
|
||||
if(m_intent == MOVE_INTENT_WALK)
|
||||
return 0 //silent when walking
|
||||
|
||||
if(buckled || lying || throwing)
|
||||
return 0 //people flying, lying down or sitting do not step
|
||||
|
||||
if(!has_gravity(src))
|
||||
if(step_count % 3) //this basically says, every three moves make a noise
|
||||
return 0 //1st - none, 1%3==1, 2nd - none, 2%3==2, 3rd - noise, 3%3==0
|
||||
|
||||
playsound(T, S, volume, 1, range)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/alien/getTrail()
|
||||
if(getBruteLoss() < 200)
|
||||
return pick("xltrails_1", "xltrails_2")
|
||||
else
|
||||
return pick("xttrails_1", "xttrails_2")
|
||||
|
||||
/mob/living/carbon/alien/update_sight()
|
||||
if(!client)
|
||||
return
|
||||
if(stat == DEAD)
|
||||
grant_death_vision()
|
||||
return
|
||||
|
||||
see_invisible = initial(see_invisible)
|
||||
sight = SEE_MOBS
|
||||
if(nightvision)
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
else
|
||||
see_in_dark = initial(see_in_dark)
|
||||
lighting_alpha = initial(lighting_alpha)
|
||||
|
||||
if(client.eye != src)
|
||||
var/atom/A = client.eye
|
||||
if(A.update_remote_sight(src)) //returns 1 if we override all other sight updates.
|
||||
return
|
||||
|
||||
for(var/obj/item/organ/internal/cyberimp/eyes/E in internal_organs)
|
||||
sight |= E.vision_flags
|
||||
if(E.see_in_dark)
|
||||
see_in_dark = max(see_in_dark, E.see_in_dark)
|
||||
if(E.see_invisible)
|
||||
see_invisible = min(see_invisible, E.see_invisible)
|
||||
if(!isnull(E.lighting_alpha))
|
||||
lighting_alpha = min(lighting_alpha, E.lighting_alpha)
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT)
|
||||
sync_lighting_plane_alpha()
|
||||
|
||||
@@ -80,4 +80,4 @@ In all, this is a lot like the monkey code. /N
|
||||
damage = rand(10, 40)
|
||||
adjustBruteLoss(damage)
|
||||
add_attack_logs(M, src, "Slime'd for [damage] damage")
|
||||
updatehealth("slime attack")
|
||||
updatehealth("slime attack")
|
||||
|
||||
@@ -1,170 +1,170 @@
|
||||
/*NOTES:
|
||||
These are general powers. Specific powers are stored under the appropriate alien creature type.
|
||||
*/
|
||||
|
||||
/*Alien spit now works like a taser shot. It won't home in on the target but will act the same once it does hit.
|
||||
Doesn't work on other aliens/AI.*/
|
||||
|
||||
|
||||
/mob/living/carbon/proc/powerc(X, Y)//Y is optional, checks for weed planting. X can be null.
|
||||
if(stat)
|
||||
to_chat(src, "<span class='noticealien'>You must be conscious to do this.</span>")
|
||||
return 0
|
||||
else if(X && getPlasma() < X)
|
||||
to_chat(src, "<span class='noticealien'>Not enough plasma stored.</span>")
|
||||
return 0
|
||||
else if(Y && (!isturf(src.loc) || istype(src.loc, /turf/space)))
|
||||
to_chat(src, "<span class='noticealien'>You can't place that here!</span>")
|
||||
return 0
|
||||
else return 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/verb/plant()
|
||||
set name = "Plant Weeds (50)"
|
||||
set desc = "Plants some alien weeds"
|
||||
set category = "Alien"
|
||||
|
||||
if(locate(/obj/structure/alien/weeds/node) in get_turf(src))
|
||||
to_chat(src, "<span class='noticealien'>There's already a weed node here.</span>")
|
||||
return
|
||||
|
||||
if(powerc(50,1))
|
||||
adjustPlasma(-50)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span class='alertalien'>[src] has planted some alien weeds!</span>"), 1)
|
||||
new /obj/structure/alien/weeds/node(loc)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/humanoid/verb/whisp(mob/M as mob in oview())
|
||||
set name = "Whisper (10)"
|
||||
set desc = "Whisper to someone"
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(10))
|
||||
adjustPlasma(-10)
|
||||
var/msg = sanitize(input("Message:", "Alien Whisper") as text|null)
|
||||
if(msg)
|
||||
log_say("(AWHISPER to [key_name(M)]) [msg]", src)
|
||||
to_chat(M, "<span class='noticealien'>You hear a strange, alien voice in your head...<span class='noticealien'>[msg]")
|
||||
to_chat(src, "<span class='noticealien'>You said: [msg] to [M]</span>")
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
G.show_message("<i>Alien message from <b>[src]</b> ([ghost_follow_link(src, ghost=G)]) to <b>[M]</b> ([ghost_follow_link(M, ghost=G)]): [msg]</i>")
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/humanoid/verb/transfer_plasma(mob/living/carbon/alien/M as mob in oview())
|
||||
set name = "Transfer Plasma"
|
||||
set desc = "Transfer Plasma to another alien"
|
||||
set category = "Alien"
|
||||
|
||||
if(isalien(M))
|
||||
var/amount = input("Amount:", "Transfer Plasma to [M]") as num
|
||||
if(amount)
|
||||
amount = abs(round(amount))
|
||||
if(powerc(amount))
|
||||
if(get_dist(src,M) <= 1)
|
||||
M.adjustPlasma(amount)
|
||||
adjustPlasma(-amount)
|
||||
to_chat(M, "<span class='noticealien'>[src] has transfered [amount] plasma to you.</span>")
|
||||
to_chat(src, {"<span class='noticealien'>You have trasferred [amount] plasma to [M]</span>"})
|
||||
else
|
||||
to_chat(src, "<span class='noticealien'>You need to be closer.</span>")
|
||||
return
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/proc/corrosive_acid(atom/target) //If they right click to corrode, an error will flash if its an invalid target./N
|
||||
set name = "Corrossive Acid (200)"
|
||||
set desc = "Drench an object in acid, destroying it over time."
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(200))
|
||||
if(target in oview(1))
|
||||
if(target.acid_act(200, 100))
|
||||
visible_message("<span class='alertalien'>[src] vomits globs of vile stuff all over [target]. It begins to sizzle and melt under the bubbling mess of acid!</span>")
|
||||
adjustPlasma(-200)
|
||||
else
|
||||
to_chat(src, "<span class='noticealien'>You cannot dissolve this object.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='noticealien'>[target] is too far away.</span>")
|
||||
|
||||
/mob/living/carbon/alien/humanoid/proc/neurotoxin() // ok
|
||||
set name = "Spit Neurotoxin (50)"
|
||||
set desc = "Spits neurotoxin at someone, paralyzing them for a short time."
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(50))
|
||||
adjustPlasma(-50)
|
||||
src.visible_message("<span class='danger'>[src] spits neurotoxin!", "<span class='alertalien'>You spit neurotoxin.</span>")
|
||||
|
||||
var/turf/T = loc
|
||||
var/turf/U = get_step(src, dir) // Get the tile infront of the move, based on their direction
|
||||
if(!isturf(U) || !isturf(T))
|
||||
return
|
||||
|
||||
var/obj/item/projectile/bullet/neurotoxin/A = new /obj/item/projectile/bullet/neurotoxin(usr.loc)
|
||||
A.current = U
|
||||
A.firer = src
|
||||
A.yo = U.y - T.y
|
||||
A.xo = U.x - T.x
|
||||
A.fire()
|
||||
A.newtonian_move(get_dir(U, T))
|
||||
newtonian_move(get_dir(U, T))
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/humanoid/proc/resin() // -- TLE
|
||||
set name = "Secrete Resin (55)"
|
||||
set desc = "Secrete tough malleable resin."
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(55))
|
||||
var/choice = input("Choose what you wish to shape.","Resin building") as null|anything in list("resin wall","resin membrane","resin nest") //would do it through typesof but then the player choice would have the type path and we don't want the internal workings to be exposed ICly - Urist
|
||||
|
||||
if(!choice || !powerc(55)) return
|
||||
adjustPlasma(-55)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span class='alertalien'>[src] vomits up a thick purple substance and shapes it!</span>"), 1)
|
||||
switch(choice)
|
||||
if("resin wall")
|
||||
new /obj/structure/alien/resin/wall(loc)
|
||||
if("resin membrane")
|
||||
new /obj/structure/alien/resin/membrane(loc)
|
||||
if("resin nest")
|
||||
new /obj/structure/bed/nest(loc)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/humanoid/verb/regurgitate()
|
||||
set name = "Regurgitate"
|
||||
set desc = "Empties the contents of your stomach"
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc())
|
||||
if(stomach_contents.len)
|
||||
for(var/mob/M in src)
|
||||
if(M in stomach_contents)
|
||||
stomach_contents.Remove(M)
|
||||
M.forceMove(loc)
|
||||
//Paralyse(10)
|
||||
src.visible_message("<span class='alertalien'><B>[src] hurls out the contents of [p_their()] stomach!</span>")
|
||||
return
|
||||
|
||||
/mob/living/carbon/proc/getPlasma()
|
||||
var/obj/item/organ/internal/xenos/plasmavessel/vessel = get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)
|
||||
if(!vessel) return 0
|
||||
return vessel.stored_plasma
|
||||
|
||||
|
||||
/mob/living/carbon/proc/adjustPlasma(amount)
|
||||
var/obj/item/organ/internal/xenos/plasmavessel/vessel = get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)
|
||||
if(!vessel) return
|
||||
vessel.stored_plasma = max(vessel.stored_plasma + amount,0)
|
||||
vessel.stored_plasma = min(vessel.stored_plasma, vessel.max_plasma) //upper limit of max_plasma, lower limit of 0
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/alien/adjustPlasma(amount)
|
||||
. = ..()
|
||||
updatePlasmaDisplay()
|
||||
|
||||
/mob/living/carbon/proc/usePlasma(amount)
|
||||
if(getPlasma() >= amount)
|
||||
adjustPlasma(-amount)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
/*NOTES:
|
||||
These are general powers. Specific powers are stored under the appropriate alien creature type.
|
||||
*/
|
||||
|
||||
/*Alien spit now works like a taser shot. It won't home in on the target but will act the same once it does hit.
|
||||
Doesn't work on other aliens/AI.*/
|
||||
|
||||
|
||||
/mob/living/carbon/proc/powerc(X, Y)//Y is optional, checks for weed planting. X can be null.
|
||||
if(stat)
|
||||
to_chat(src, "<span class='noticealien'>You must be conscious to do this.</span>")
|
||||
return 0
|
||||
else if(X && getPlasma() < X)
|
||||
to_chat(src, "<span class='noticealien'>Not enough plasma stored.</span>")
|
||||
return 0
|
||||
else if(Y && (!isturf(src.loc) || istype(src.loc, /turf/space)))
|
||||
to_chat(src, "<span class='noticealien'>You can't place that here!</span>")
|
||||
return 0
|
||||
else return 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/verb/plant()
|
||||
set name = "Plant Weeds (50)"
|
||||
set desc = "Plants some alien weeds"
|
||||
set category = "Alien"
|
||||
|
||||
if(locate(/obj/structure/alien/weeds/node) in get_turf(src))
|
||||
to_chat(src, "<span class='noticealien'>There's already a weed node here.</span>")
|
||||
return
|
||||
|
||||
if(powerc(50,1))
|
||||
adjustPlasma(-50)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span class='alertalien'>[src] has planted some alien weeds!</span>"), 1)
|
||||
new /obj/structure/alien/weeds/node(loc)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/humanoid/verb/whisp(mob/M as mob in oview())
|
||||
set name = "Whisper (10)"
|
||||
set desc = "Whisper to someone"
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(10))
|
||||
adjustPlasma(-10)
|
||||
var/msg = sanitize(input("Message:", "Alien Whisper") as text|null)
|
||||
if(msg)
|
||||
log_say("(AWHISPER to [key_name(M)]) [msg]", src)
|
||||
to_chat(M, "<span class='noticealien'>You hear a strange, alien voice in your head...<span class='noticealien'>[msg]")
|
||||
to_chat(src, "<span class='noticealien'>You said: [msg] to [M]</span>")
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
G.show_message("<i>Alien message from <b>[src]</b> ([ghost_follow_link(src, ghost=G)]) to <b>[M]</b> ([ghost_follow_link(M, ghost=G)]): [msg]</i>")
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/humanoid/verb/transfer_plasma(mob/living/carbon/alien/M as mob in oview())
|
||||
set name = "Transfer Plasma"
|
||||
set desc = "Transfer Plasma to another alien"
|
||||
set category = "Alien"
|
||||
|
||||
if(isalien(M))
|
||||
var/amount = input("Amount:", "Transfer Plasma to [M]") as num
|
||||
if(amount)
|
||||
amount = abs(round(amount))
|
||||
if(powerc(amount))
|
||||
if(get_dist(src,M) <= 1)
|
||||
M.adjustPlasma(amount)
|
||||
adjustPlasma(-amount)
|
||||
to_chat(M, "<span class='noticealien'>[src] has transfered [amount] plasma to you.</span>")
|
||||
to_chat(src, {"<span class='noticealien'>You have trasferred [amount] plasma to [M]</span>"})
|
||||
else
|
||||
to_chat(src, "<span class='noticealien'>You need to be closer.</span>")
|
||||
return
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/proc/corrosive_acid(atom/target) //If they right click to corrode, an error will flash if its an invalid target./N
|
||||
set name = "Corrossive Acid (200)"
|
||||
set desc = "Drench an object in acid, destroying it over time."
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(200))
|
||||
if(target in oview(1))
|
||||
if(target.acid_act(200, 100))
|
||||
visible_message("<span class='alertalien'>[src] vomits globs of vile stuff all over [target]. It begins to sizzle and melt under the bubbling mess of acid!</span>")
|
||||
adjustPlasma(-200)
|
||||
else
|
||||
to_chat(src, "<span class='noticealien'>You cannot dissolve this object.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='noticealien'>[target] is too far away.</span>")
|
||||
|
||||
/mob/living/carbon/alien/humanoid/proc/neurotoxin() // ok
|
||||
set name = "Spit Neurotoxin (50)"
|
||||
set desc = "Spits neurotoxin at someone, paralyzing them for a short time."
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(50))
|
||||
adjustPlasma(-50)
|
||||
src.visible_message("<span class='danger'>[src] spits neurotoxin!", "<span class='alertalien'>You spit neurotoxin.</span>")
|
||||
|
||||
var/turf/T = loc
|
||||
var/turf/U = get_step(src, dir) // Get the tile infront of the move, based on their direction
|
||||
if(!isturf(U) || !isturf(T))
|
||||
return
|
||||
|
||||
var/obj/item/projectile/bullet/neurotoxin/A = new /obj/item/projectile/bullet/neurotoxin(usr.loc)
|
||||
A.current = U
|
||||
A.firer = src
|
||||
A.yo = U.y - T.y
|
||||
A.xo = U.x - T.x
|
||||
A.fire()
|
||||
A.newtonian_move(get_dir(U, T))
|
||||
newtonian_move(get_dir(U, T))
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/humanoid/proc/resin() // -- TLE
|
||||
set name = "Secrete Resin (55)"
|
||||
set desc = "Secrete tough malleable resin."
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(55))
|
||||
var/choice = input("Choose what you wish to shape.","Resin building") as null|anything in list("resin wall","resin membrane","resin nest") //would do it through typesof but then the player choice would have the type path and we don't want the internal workings to be exposed ICly - Urist
|
||||
|
||||
if(!choice || !powerc(55)) return
|
||||
adjustPlasma(-55)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span class='alertalien'>[src] vomits up a thick purple substance and shapes it!</span>"), 1)
|
||||
switch(choice)
|
||||
if("resin wall")
|
||||
new /obj/structure/alien/resin/wall(loc)
|
||||
if("resin membrane")
|
||||
new /obj/structure/alien/resin/membrane(loc)
|
||||
if("resin nest")
|
||||
new /obj/structure/bed/nest(loc)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/humanoid/verb/regurgitate()
|
||||
set name = "Regurgitate"
|
||||
set desc = "Empties the contents of your stomach"
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc())
|
||||
if(stomach_contents.len)
|
||||
for(var/mob/M in src)
|
||||
if(M in stomach_contents)
|
||||
stomach_contents.Remove(M)
|
||||
M.forceMove(loc)
|
||||
//Paralyse(10)
|
||||
src.visible_message("<span class='alertalien'><B>[src] hurls out the contents of [p_their()] stomach!</span>")
|
||||
return
|
||||
|
||||
/mob/living/carbon/proc/getPlasma()
|
||||
var/obj/item/organ/internal/xenos/plasmavessel/vessel = get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)
|
||||
if(!vessel) return 0
|
||||
return vessel.stored_plasma
|
||||
|
||||
|
||||
/mob/living/carbon/proc/adjustPlasma(amount)
|
||||
var/obj/item/organ/internal/xenos/plasmavessel/vessel = get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)
|
||||
if(!vessel) return
|
||||
vessel.stored_plasma = max(vessel.stored_plasma + amount,0)
|
||||
vessel.stored_plasma = min(vessel.stored_plasma, vessel.max_plasma) //upper limit of max_plasma, lower limit of 0
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/alien/adjustPlasma(amount)
|
||||
. = ..()
|
||||
updatePlasmaDisplay()
|
||||
|
||||
/mob/living/carbon/proc/usePlasma(amount)
|
||||
if(getPlasma() >= amount)
|
||||
adjustPlasma(-amount)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
/mob/living/carbon/alien/humanoid/drone
|
||||
name = "alien drone"
|
||||
caste = "d"
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
icon_state = "aliend_s"
|
||||
|
||||
/mob/living/carbon/alien/humanoid/drone/New()
|
||||
create_reagents(100)
|
||||
if(src.name == "alien drone")
|
||||
src.name = text("alien drone ([rand(1, 1000)])")
|
||||
src.real_name = src.name
|
||||
alien_organs += new /obj/item/organ/internal/xenos/plasmavessel/drone
|
||||
alien_organs += new /obj/item/organ/internal/xenos/acidgland
|
||||
alien_organs += new /obj/item/organ/internal/xenos/resinspinner
|
||||
..()
|
||||
|
||||
//Drones use the same base as generic humanoids.
|
||||
//Drone verbs
|
||||
|
||||
/mob/living/carbon/alien/humanoid/drone/verb/evolve() // -- TLE
|
||||
set name = "Evolve (500)"
|
||||
set desc = "Produce an interal egg sac capable of spawning children. Only one queen can exist at a time."
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(500))
|
||||
// Queen check
|
||||
var/no_queen = 1
|
||||
for(var/mob/living/carbon/alien/humanoid/queen/Q in GLOB.living_mob_list)
|
||||
if(!Q.key && Q.get_int_organ(/obj/item/organ/internal/brain/))
|
||||
continue
|
||||
no_queen = 0
|
||||
|
||||
if(src.has_brain_worms())
|
||||
to_chat(src, "<span class='warning'>We cannot perform this ability at the present time!</span>")
|
||||
return
|
||||
if(no_queen)
|
||||
adjustPlasma(-500)
|
||||
to_chat(src, "<span class='noticealien'>You begin to evolve!</span>")
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span class='alertalien'>[src] begins to twist and contort!</span>"), 1)
|
||||
var/mob/living/carbon/alien/humanoid/queen/new_xeno = new(loc)
|
||||
mind.transfer_to(new_xeno)
|
||||
new_xeno.mind.name = new_xeno.name
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(src, "<span class='notice'>We already have an alive queen.</span>")
|
||||
return
|
||||
/mob/living/carbon/alien/humanoid/drone
|
||||
name = "alien drone"
|
||||
caste = "d"
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
icon_state = "aliend_s"
|
||||
|
||||
/mob/living/carbon/alien/humanoid/drone/New()
|
||||
create_reagents(100)
|
||||
if(src.name == "alien drone")
|
||||
src.name = text("alien drone ([rand(1, 1000)])")
|
||||
src.real_name = src.name
|
||||
alien_organs += new /obj/item/organ/internal/xenos/plasmavessel/drone
|
||||
alien_organs += new /obj/item/organ/internal/xenos/acidgland
|
||||
alien_organs += new /obj/item/organ/internal/xenos/resinspinner
|
||||
..()
|
||||
|
||||
//Drones use the same base as generic humanoids.
|
||||
//Drone verbs
|
||||
|
||||
/mob/living/carbon/alien/humanoid/drone/verb/evolve() // -- TLE
|
||||
set name = "Evolve (500)"
|
||||
set desc = "Produce an interal egg sac capable of spawning children. Only one queen can exist at a time."
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(500))
|
||||
// Queen check
|
||||
var/no_queen = 1
|
||||
for(var/mob/living/carbon/alien/humanoid/queen/Q in GLOB.living_mob_list)
|
||||
if(!Q.key && Q.get_int_organ(/obj/item/organ/internal/brain/))
|
||||
continue
|
||||
no_queen = 0
|
||||
|
||||
if(src.has_brain_worms())
|
||||
to_chat(src, "<span class='warning'>We cannot perform this ability at the present time!</span>")
|
||||
return
|
||||
if(no_queen)
|
||||
adjustPlasma(-500)
|
||||
to_chat(src, "<span class='noticealien'>You begin to evolve!</span>")
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span class='alertalien'>[src] begins to twist and contort!</span>"), 1)
|
||||
var/mob/living/carbon/alien/humanoid/queen/new_xeno = new(loc)
|
||||
mind.transfer_to(new_xeno)
|
||||
new_xeno.mind.name = new_xeno.name
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(src, "<span class='notice'>We already have an alive queen.</span>")
|
||||
return
|
||||
|
||||
@@ -1,131 +1,131 @@
|
||||
/mob/living/carbon/alien/humanoid/hunter
|
||||
name = "alien hunter"
|
||||
caste = "h"
|
||||
maxHealth = 125
|
||||
health = 125
|
||||
icon_state = "alienh_s"
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/New()
|
||||
create_reagents(100)
|
||||
if(name == "alien hunter")
|
||||
name = text("alien hunter ([rand(1, 1000)])")
|
||||
real_name = name
|
||||
alien_organs += new /obj/item/organ/internal/xenos/plasmavessel/hunter
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/movement_delay()
|
||||
. = -1 //hunters are sanic
|
||||
. += ..() //but they still need to slow down on stun
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/handle_hud_icons_health()
|
||||
..() //-Yvarov
|
||||
|
||||
if(healths)
|
||||
if(stat != 2)
|
||||
switch(health)
|
||||
if(125 to INFINITY)
|
||||
healths.icon_state = "health0"
|
||||
if(100 to 125)
|
||||
healths.icon_state = "health1"
|
||||
if(50 to 100)
|
||||
healths.icon_state = "health2"
|
||||
if(25 to 50)
|
||||
healths.icon_state = "health3"
|
||||
if(0 to 25)
|
||||
healths.icon_state = "health4"
|
||||
else
|
||||
healths.icon_state = "health5"
|
||||
else
|
||||
healths.icon_state = "health6"
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/handle_environment()
|
||||
if(m_intent == MOVE_INTENT_RUN || resting)
|
||||
..()
|
||||
else
|
||||
adjustPlasma(-heal_rate)
|
||||
|
||||
|
||||
//Hunter verbs
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/proc/toggle_leap(var/message = 1)
|
||||
leap_on_click = !leap_on_click
|
||||
leap_icon.icon_state = "leap_[leap_on_click ? "on":"off"]"
|
||||
if(message)
|
||||
to_chat(src, "<span class='noticealien'>You will now [leap_on_click ? "leap at":"slash at"] enemies!</span>")
|
||||
else
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/ClickOn(var/atom/A, var/params)
|
||||
face_atom(A)
|
||||
if(leap_on_click)
|
||||
leap_at(A)
|
||||
else
|
||||
..()
|
||||
|
||||
#define MAX_ALIEN_LEAP_DIST 7
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/proc/leap_at(var/atom/A)
|
||||
if(pounce_cooldown > world.time)
|
||||
to_chat(src, "<span class='alertalien'>You are too fatigued to pounce right now!</span>")
|
||||
return
|
||||
|
||||
if(leaping) //Leap while you leap, so you can leap while you leap
|
||||
return
|
||||
|
||||
if(!has_gravity(src) || !has_gravity(A))
|
||||
to_chat(src, "<span class='alertalien'>It is unsafe to leap without gravity!</span>")
|
||||
//It's also extremely buggy visually, so it's balance+bugfix
|
||||
return
|
||||
if(lying)
|
||||
return
|
||||
|
||||
else //Maybe uses plasma in the future, although that wouldn't make any sense...
|
||||
leaping = 1
|
||||
update_icons()
|
||||
throw_at(A, MAX_ALIEN_LEAP_DIST, 1, spin = 0, diagonals_first = 1, callback = CALLBACK(src, .leap_end))
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/proc/leap_end()
|
||||
leaping = 0
|
||||
update_icons()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/throw_impact(atom/A)
|
||||
if(!leaping)
|
||||
return ..()
|
||||
|
||||
if(A)
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
var/blocked = 0
|
||||
if(ishuman(A))
|
||||
var/mob/living/carbon/human/H = A
|
||||
if(H.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
|
||||
blocked = 1
|
||||
if(!blocked)
|
||||
L.visible_message("<span class ='danger'>[src] pounces on [L]!</span>", "<span class ='userdanger'>[src] pounces on you!</span>")
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
H.apply_effect(5, WEAKEN, H.run_armor_check(null, "melee"))
|
||||
else
|
||||
L.Weaken(5)
|
||||
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
|
||||
step_towards(src,L)
|
||||
else
|
||||
Weaken(2, 1, 1)
|
||||
|
||||
toggle_leap(0)
|
||||
pounce_cooldown = world.time + pounce_cooldown_time
|
||||
else if(A.density && !A.CanPass(src))
|
||||
visible_message("<span class ='danger'>[src] smashes into [A]!</span>", "<span class ='alertalien'>[src] smashes into [A]!</span>")
|
||||
Weaken(2, 1, 1)
|
||||
|
||||
if(leaping)
|
||||
leaping = 0
|
||||
update_icons()
|
||||
update_canmove()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/float(on)
|
||||
if(leaping)
|
||||
return
|
||||
..()
|
||||
/mob/living/carbon/alien/humanoid/hunter
|
||||
name = "alien hunter"
|
||||
caste = "h"
|
||||
maxHealth = 125
|
||||
health = 125
|
||||
icon_state = "alienh_s"
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/New()
|
||||
create_reagents(100)
|
||||
if(name == "alien hunter")
|
||||
name = text("alien hunter ([rand(1, 1000)])")
|
||||
real_name = name
|
||||
alien_organs += new /obj/item/organ/internal/xenos/plasmavessel/hunter
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/movement_delay()
|
||||
. = -1 //hunters are sanic
|
||||
. += ..() //but they still need to slow down on stun
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/handle_hud_icons_health()
|
||||
..() //-Yvarov
|
||||
|
||||
if(healths)
|
||||
if(stat != 2)
|
||||
switch(health)
|
||||
if(125 to INFINITY)
|
||||
healths.icon_state = "health0"
|
||||
if(100 to 125)
|
||||
healths.icon_state = "health1"
|
||||
if(50 to 100)
|
||||
healths.icon_state = "health2"
|
||||
if(25 to 50)
|
||||
healths.icon_state = "health3"
|
||||
if(0 to 25)
|
||||
healths.icon_state = "health4"
|
||||
else
|
||||
healths.icon_state = "health5"
|
||||
else
|
||||
healths.icon_state = "health6"
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/handle_environment()
|
||||
if(m_intent == MOVE_INTENT_RUN || resting)
|
||||
..()
|
||||
else
|
||||
adjustPlasma(-heal_rate)
|
||||
|
||||
|
||||
//Hunter verbs
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/proc/toggle_leap(var/message = 1)
|
||||
leap_on_click = !leap_on_click
|
||||
leap_icon.icon_state = "leap_[leap_on_click ? "on":"off"]"
|
||||
if(message)
|
||||
to_chat(src, "<span class='noticealien'>You will now [leap_on_click ? "leap at":"slash at"] enemies!</span>")
|
||||
else
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/ClickOn(var/atom/A, var/params)
|
||||
face_atom(A)
|
||||
if(leap_on_click)
|
||||
leap_at(A)
|
||||
else
|
||||
..()
|
||||
|
||||
#define MAX_ALIEN_LEAP_DIST 7
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/proc/leap_at(var/atom/A)
|
||||
if(pounce_cooldown > world.time)
|
||||
to_chat(src, "<span class='alertalien'>You are too fatigued to pounce right now!</span>")
|
||||
return
|
||||
|
||||
if(leaping) //Leap while you leap, so you can leap while you leap
|
||||
return
|
||||
|
||||
if(!has_gravity(src) || !has_gravity(A))
|
||||
to_chat(src, "<span class='alertalien'>It is unsafe to leap without gravity!</span>")
|
||||
//It's also extremely buggy visually, so it's balance+bugfix
|
||||
return
|
||||
if(lying)
|
||||
return
|
||||
|
||||
else //Maybe uses plasma in the future, although that wouldn't make any sense...
|
||||
leaping = 1
|
||||
update_icons()
|
||||
throw_at(A, MAX_ALIEN_LEAP_DIST, 1, spin = 0, diagonals_first = 1, callback = CALLBACK(src, .leap_end))
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/proc/leap_end()
|
||||
leaping = 0
|
||||
update_icons()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/throw_impact(atom/A)
|
||||
if(!leaping)
|
||||
return ..()
|
||||
|
||||
if(A)
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
var/blocked = 0
|
||||
if(ishuman(A))
|
||||
var/mob/living/carbon/human/H = A
|
||||
if(H.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
|
||||
blocked = 1
|
||||
if(!blocked)
|
||||
L.visible_message("<span class ='danger'>[src] pounces on [L]!</span>", "<span class ='userdanger'>[src] pounces on you!</span>")
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
H.apply_effect(5, WEAKEN, H.run_armor_check(null, "melee"))
|
||||
else
|
||||
L.Weaken(5)
|
||||
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
|
||||
step_towards(src,L)
|
||||
else
|
||||
Weaken(2, 1, 1)
|
||||
|
||||
toggle_leap(0)
|
||||
pounce_cooldown = world.time + pounce_cooldown_time
|
||||
else if(A.density && !A.CanPass(src))
|
||||
visible_message("<span class ='danger'>[src] smashes into [A]!</span>", "<span class ='alertalien'>[src] smashes into [A]!</span>")
|
||||
Weaken(2, 1, 1)
|
||||
|
||||
if(leaping)
|
||||
leaping = 0
|
||||
update_icons()
|
||||
update_canmove()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/float(on)
|
||||
if(leaping)
|
||||
return
|
||||
..()
|
||||
|
||||
@@ -1,85 +1,85 @@
|
||||
/mob/living/carbon/alien/humanoid/sentinel
|
||||
name = "alien sentinel"
|
||||
caste = "s"
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
icon_state = "aliens_s"
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/large
|
||||
name = "alien praetorian"
|
||||
icon = 'icons/mob/alienlarge.dmi'
|
||||
icon_state = "prat_s"
|
||||
pixel_x = -16
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
large = 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/praetorian
|
||||
name = "alien praetorian"
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
large = 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/large/update_icons()
|
||||
overlays.Cut()
|
||||
if(stat == DEAD)
|
||||
icon_state = "prat_dead"
|
||||
else if(stat == UNCONSCIOUS || lying || resting)
|
||||
icon_state = "prat_sleep"
|
||||
else
|
||||
icon_state = "prat_s"
|
||||
|
||||
for(var/image/I in overlays_standing)
|
||||
overlays += I
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/New()
|
||||
create_reagents(100)
|
||||
if(name == "alien sentinel")
|
||||
name = text("alien sentinel ([rand(1, 1000)])")
|
||||
real_name = name
|
||||
alien_organs += new /obj/item/organ/internal/xenos/plasmavessel
|
||||
alien_organs += new /obj/item/organ/internal/xenos/acidgland
|
||||
alien_organs += new /obj/item/organ/internal/xenos/neurotoxin
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/handle_hud_icons_health()
|
||||
..() //-Yvarov
|
||||
|
||||
if(healths)
|
||||
if(stat != 2)
|
||||
switch(health)
|
||||
if(150 to INFINITY)
|
||||
healths.icon_state = "health0"
|
||||
if(100 to 150)
|
||||
healths.icon_state = "health1"
|
||||
if(75 to 100)
|
||||
healths.icon_state = "health2"
|
||||
if(25 to 75)
|
||||
healths.icon_state = "health3"
|
||||
if(0 to 25)
|
||||
healths.icon_state = "health4"
|
||||
else
|
||||
healths.icon_state = "health5"
|
||||
else
|
||||
healths.icon_state = "health6"
|
||||
|
||||
/*
|
||||
/mob/living/carbon/alien/humanoid/sentinel/verb/evolve() // -- TLE
|
||||
set name = "Evolve (250)"
|
||||
set desc = "Become a Praetorian, Royal Guard to the Queen."
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(250))
|
||||
adjustToxLoss(-250)
|
||||
to_chat(src, "<span class=notice'>You begin to evolve!</span>")
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span class='alertalien'>[src] begins to twist and contort!</span>"), 1)
|
||||
var/mob/living/carbon/alien/humanoid/sentinel/praetorian/new_xeno = new(loc)
|
||||
if(mind)
|
||||
mind.transfer_to(new_xeno)
|
||||
else
|
||||
new_xeno.key = key
|
||||
new_xeno.mind.name = new_xeno.name
|
||||
qdel(src)
|
||||
return
|
||||
*/
|
||||
/mob/living/carbon/alien/humanoid/sentinel
|
||||
name = "alien sentinel"
|
||||
caste = "s"
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
icon_state = "aliens_s"
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/large
|
||||
name = "alien praetorian"
|
||||
icon = 'icons/mob/alienlarge.dmi'
|
||||
icon_state = "prat_s"
|
||||
pixel_x = -16
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
large = 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/praetorian
|
||||
name = "alien praetorian"
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
large = 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/large/update_icons()
|
||||
overlays.Cut()
|
||||
if(stat == DEAD)
|
||||
icon_state = "prat_dead"
|
||||
else if(stat == UNCONSCIOUS || lying || resting)
|
||||
icon_state = "prat_sleep"
|
||||
else
|
||||
icon_state = "prat_s"
|
||||
|
||||
for(var/image/I in overlays_standing)
|
||||
overlays += I
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/New()
|
||||
create_reagents(100)
|
||||
if(name == "alien sentinel")
|
||||
name = text("alien sentinel ([rand(1, 1000)])")
|
||||
real_name = name
|
||||
alien_organs += new /obj/item/organ/internal/xenos/plasmavessel
|
||||
alien_organs += new /obj/item/organ/internal/xenos/acidgland
|
||||
alien_organs += new /obj/item/organ/internal/xenos/neurotoxin
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/handle_hud_icons_health()
|
||||
..() //-Yvarov
|
||||
|
||||
if(healths)
|
||||
if(stat != 2)
|
||||
switch(health)
|
||||
if(150 to INFINITY)
|
||||
healths.icon_state = "health0"
|
||||
if(100 to 150)
|
||||
healths.icon_state = "health1"
|
||||
if(75 to 100)
|
||||
healths.icon_state = "health2"
|
||||
if(25 to 75)
|
||||
healths.icon_state = "health3"
|
||||
if(0 to 25)
|
||||
healths.icon_state = "health4"
|
||||
else
|
||||
healths.icon_state = "health5"
|
||||
else
|
||||
healths.icon_state = "health6"
|
||||
|
||||
/*
|
||||
/mob/living/carbon/alien/humanoid/sentinel/verb/evolve() // -- TLE
|
||||
set name = "Evolve (250)"
|
||||
set desc = "Become a Praetorian, Royal Guard to the Queen."
|
||||
set category = "Alien"
|
||||
|
||||
if(powerc(250))
|
||||
adjustToxLoss(-250)
|
||||
to_chat(src, "<span class=notice'>You begin to evolve!</span>")
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span class='alertalien'>[src] begins to twist and contort!</span>"), 1)
|
||||
var/mob/living/carbon/alien/humanoid/sentinel/praetorian/new_xeno = new(loc)
|
||||
if(mind)
|
||||
mind.transfer_to(new_xeno)
|
||||
else
|
||||
new_xeno.key = key
|
||||
new_xeno.mind.name = new_xeno.name
|
||||
qdel(src)
|
||||
return
|
||||
*/
|
||||
|
||||
@@ -138,4 +138,4 @@
|
||||
playsound(src.loc, 'sound/voice/hiss1.ogg', 30, 1, 1)
|
||||
if(act == "gnarl")
|
||||
playsound(src.loc, 'sound/voice/hiss4.ogg', 30, 1, 1)
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -1,123 +1,123 @@
|
||||
/mob/living/carbon/alien/humanoid
|
||||
name = "alien"
|
||||
icon_state = "alien_s"
|
||||
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/xenomeat = 5, /obj/item/stack/sheet/animalhide/xeno = 1)
|
||||
var/obj/item/r_store = null
|
||||
var/obj/item/l_store = null
|
||||
var/caste = ""
|
||||
var/alt_icon = 'icons/mob/alienleap.dmi' //used to switch between the two alien icon files.
|
||||
var/next_attack = 0
|
||||
var/pounce_cooldown = 0
|
||||
var/pounce_cooldown_time = 30
|
||||
var/leap_on_click = 0
|
||||
var/custom_pixel_x_offset = 0 //for admin fuckery.
|
||||
var/custom_pixel_y_offset = 0
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
//This is fine right now, if we're adding organ specific damage this needs to be updated
|
||||
/mob/living/carbon/alien/humanoid/New()
|
||||
create_reagents(1000)
|
||||
if(name == "alien")
|
||||
name = text("alien ([rand(1, 1000)])")
|
||||
real_name = name
|
||||
add_language("Xenomorph")
|
||||
add_language("Hivemind")
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/Process_Spacemove(var/check_drift = 0)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
///mob/living/carbon/alien/humanoid/bullet_act(var/obj/item/projectile/Proj) taken care of in living
|
||||
|
||||
/mob/living/carbon/alien/humanoid/emp_act(severity)
|
||||
if(r_store) r_store.emp_act(severity)
|
||||
if(l_store) l_store.emp_act(severity)
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/ex_act(severity)
|
||||
..()
|
||||
|
||||
var/shielded = 0
|
||||
|
||||
var/b_loss = null
|
||||
var/f_loss = null
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
gib()
|
||||
return
|
||||
|
||||
if(2.0)
|
||||
if(!shielded)
|
||||
b_loss += 60
|
||||
|
||||
f_loss += 60
|
||||
|
||||
AdjustEarDamage(30, 120)
|
||||
if(3.0)
|
||||
b_loss += 30
|
||||
if(prob(50) && !shielded)
|
||||
Paralyse(1)
|
||||
AdjustEarDamage(15, 60)
|
||||
|
||||
take_overall_damage(b_loss, f_loss)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/restrained()
|
||||
if(handcuffed)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/var/temperature_resistance = T0C+75
|
||||
|
||||
/mob/living/carbon/alien/humanoid/show_inv(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
|
||||
var/dat = {"<table>
|
||||
<tr><td><B>Left Hand:</B></td><td><A href='?src=[UID()];item=[slot_l_hand]'>[(l_hand && !(l_hand.flags&ABSTRACT)) ? l_hand : "<font color=grey>Empty</font>"]</A></td></tr>
|
||||
<tr><td><B>Right Hand:</B></td><td><A href='?src=[UID()];item=[slot_r_hand]'>[(r_hand && !(r_hand.flags&ABSTRACT)) ? r_hand : "<font color=grey>Empty</font>"]</A></td></tr>
|
||||
<tr><td> </td></tr>"}
|
||||
|
||||
dat += "<tr><td><B>Head:</B></td><td><A href='?src=[UID()];item=[slot_head]'>[(head && !(head.flags&ABSTRACT)) ? head : "<font color=grey>Empty</font>"]</A></td></tr>"
|
||||
|
||||
dat += "<tr><td> </td></tr>"
|
||||
|
||||
dat += "<tr><td><B>Exosuit:</B></td><td><A href='?src=[UID()];item=[slot_wear_suit]'>[(wear_suit && !(wear_suit.flags&ABSTRACT)) ? wear_suit : "<font color=grey>Empty</font>"]</A></td></tr>"
|
||||
dat += "<tr><td><B>Pouches:</B></td><td><A href='?src=[UID()];item=pockets'>[((l_store && !(l_store.flags&ABSTRACT)) || (r_store && !(r_store.flags&ABSTRACT))) ? "Full" : "<font color=grey>Empty</font>"]</A>"
|
||||
|
||||
dat += {"</table>
|
||||
<A href='?src=[user.UID()];mach_close=mob\ref[src]'>Close</A>
|
||||
"}
|
||||
|
||||
var/datum/browser/popup = new(user, "mob\ref[src]", "[src]", 440, 500)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/canBeHandcuffed()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/cuff_resist(obj/item/I)
|
||||
playsound(src, 'sound/voice/hiss5.ogg', 40, 1, 1) //Alien roars when starting to break free
|
||||
..(I, cuff_break = 1)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/get_standard_pixel_y_offset(lying = 0)
|
||||
if(leaping)
|
||||
return -32
|
||||
else if(custom_pixel_y_offset)
|
||||
return custom_pixel_y_offset
|
||||
else
|
||||
return initial(pixel_y)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/get_standard_pixel_x_offset(lying = 0)
|
||||
if(leaping)
|
||||
return -32
|
||||
else if(custom_pixel_x_offset)
|
||||
return custom_pixel_x_offset
|
||||
else
|
||||
return initial(pixel_x)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/get_permeability_protection()
|
||||
return 0.8
|
||||
/mob/living/carbon/alien/humanoid
|
||||
name = "alien"
|
||||
icon_state = "alien_s"
|
||||
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/xenomeat = 5, /obj/item/stack/sheet/animalhide/xeno = 1)
|
||||
var/obj/item/r_store = null
|
||||
var/obj/item/l_store = null
|
||||
var/caste = ""
|
||||
var/alt_icon = 'icons/mob/alienleap.dmi' //used to switch between the two alien icon files.
|
||||
var/next_attack = 0
|
||||
var/pounce_cooldown = 0
|
||||
var/pounce_cooldown_time = 30
|
||||
var/leap_on_click = 0
|
||||
var/custom_pixel_x_offset = 0 //for admin fuckery.
|
||||
var/custom_pixel_y_offset = 0
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
//This is fine right now, if we're adding organ specific damage this needs to be updated
|
||||
/mob/living/carbon/alien/humanoid/New()
|
||||
create_reagents(1000)
|
||||
if(name == "alien")
|
||||
name = text("alien ([rand(1, 1000)])")
|
||||
real_name = name
|
||||
add_language("Xenomorph")
|
||||
add_language("Hivemind")
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/Process_Spacemove(var/check_drift = 0)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
///mob/living/carbon/alien/humanoid/bullet_act(var/obj/item/projectile/Proj) taken care of in living
|
||||
|
||||
/mob/living/carbon/alien/humanoid/emp_act(severity)
|
||||
if(r_store) r_store.emp_act(severity)
|
||||
if(l_store) l_store.emp_act(severity)
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/ex_act(severity)
|
||||
..()
|
||||
|
||||
var/shielded = 0
|
||||
|
||||
var/b_loss = null
|
||||
var/f_loss = null
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
gib()
|
||||
return
|
||||
|
||||
if(2.0)
|
||||
if(!shielded)
|
||||
b_loss += 60
|
||||
|
||||
f_loss += 60
|
||||
|
||||
AdjustEarDamage(30, 120)
|
||||
if(3.0)
|
||||
b_loss += 30
|
||||
if(prob(50) && !shielded)
|
||||
Paralyse(1)
|
||||
AdjustEarDamage(15, 60)
|
||||
|
||||
take_overall_damage(b_loss, f_loss)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/restrained()
|
||||
if(handcuffed)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/var/temperature_resistance = T0C+75
|
||||
|
||||
/mob/living/carbon/alien/humanoid/show_inv(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
|
||||
var/dat = {"<table>
|
||||
<tr><td><B>Left Hand:</B></td><td><A href='?src=[UID()];item=[slot_l_hand]'>[(l_hand && !(l_hand.flags&ABSTRACT)) ? l_hand : "<font color=grey>Empty</font>"]</A></td></tr>
|
||||
<tr><td><B>Right Hand:</B></td><td><A href='?src=[UID()];item=[slot_r_hand]'>[(r_hand && !(r_hand.flags&ABSTRACT)) ? r_hand : "<font color=grey>Empty</font>"]</A></td></tr>
|
||||
<tr><td> </td></tr>"}
|
||||
|
||||
dat += "<tr><td><B>Head:</B></td><td><A href='?src=[UID()];item=[slot_head]'>[(head && !(head.flags&ABSTRACT)) ? head : "<font color=grey>Empty</font>"]</A></td></tr>"
|
||||
|
||||
dat += "<tr><td> </td></tr>"
|
||||
|
||||
dat += "<tr><td><B>Exosuit:</B></td><td><A href='?src=[UID()];item=[slot_wear_suit]'>[(wear_suit && !(wear_suit.flags&ABSTRACT)) ? wear_suit : "<font color=grey>Empty</font>"]</A></td></tr>"
|
||||
dat += "<tr><td><B>Pouches:</B></td><td><A href='?src=[UID()];item=pockets'>[((l_store && !(l_store.flags&ABSTRACT)) || (r_store && !(r_store.flags&ABSTRACT))) ? "Full" : "<font color=grey>Empty</font>"]</A>"
|
||||
|
||||
dat += {"</table>
|
||||
<A href='?src=[user.UID()];mach_close=mob\ref[src]'>Close</A>
|
||||
"}
|
||||
|
||||
var/datum/browser/popup = new(user, "mob\ref[src]", "[src]", 440, 500)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/canBeHandcuffed()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/cuff_resist(obj/item/I)
|
||||
playsound(src, 'sound/voice/hiss5.ogg', 40, 1, 1) //Alien roars when starting to break free
|
||||
..(I, cuff_break = 1)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/get_standard_pixel_y_offset(lying = 0)
|
||||
if(leaping)
|
||||
return -32
|
||||
else if(custom_pixel_y_offset)
|
||||
return custom_pixel_y_offset
|
||||
else
|
||||
return initial(pixel_y)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/get_standard_pixel_x_offset(lying = 0)
|
||||
if(leaping)
|
||||
return -32
|
||||
else if(custom_pixel_x_offset)
|
||||
return custom_pixel_x_offset
|
||||
else
|
||||
return initial(pixel_x)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/get_permeability_protection()
|
||||
return 0.8
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
//unequip
|
||||
/mob/living/carbon/alien/humanoid/unEquip(var/obj/item/I, var/force)
|
||||
. = ..(I, force)
|
||||
if(!. || !I)
|
||||
return
|
||||
|
||||
if(I == r_store)
|
||||
r_store = null
|
||||
update_inv_pockets()
|
||||
|
||||
else if(I == l_store)
|
||||
l_store = null
|
||||
update_inv_pockets()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/attack_ui(slot_id)
|
||||
var/obj/item/W = get_active_hand()
|
||||
if(W)
|
||||
if(!istype(W)) return
|
||||
switch(slot_id)
|
||||
// if("o_clothing")
|
||||
// if("head")
|
||||
if(slot_l_store)
|
||||
if(l_store)
|
||||
return
|
||||
if(W.w_class > WEIGHT_CLASS_NORMAL)
|
||||
return
|
||||
unEquip(W)
|
||||
l_store = W
|
||||
update_inv_pockets()
|
||||
if(slot_r_store)
|
||||
if(r_store)
|
||||
return
|
||||
if(W.w_class > WEIGHT_CLASS_NORMAL)
|
||||
return
|
||||
unEquip(W)
|
||||
r_store = W
|
||||
update_inv_pockets()
|
||||
else
|
||||
switch(slot_id)
|
||||
if(slot_wear_suit)
|
||||
if(wear_suit) wear_suit.attack_alien(src)
|
||||
if(slot_head)
|
||||
if(head) head.attack_alien(src)
|
||||
if(slot_l_store)
|
||||
if(l_store) l_store.attack_alien(src)
|
||||
if(slot_r_store)
|
||||
if(r_store) r_store.attack_alien(src)
|
||||
//unequip
|
||||
/mob/living/carbon/alien/humanoid/unEquip(var/obj/item/I, var/force)
|
||||
. = ..(I, force)
|
||||
if(!. || !I)
|
||||
return
|
||||
|
||||
if(I == r_store)
|
||||
r_store = null
|
||||
update_inv_pockets()
|
||||
|
||||
else if(I == l_store)
|
||||
l_store = null
|
||||
update_inv_pockets()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/attack_ui(slot_id)
|
||||
var/obj/item/W = get_active_hand()
|
||||
if(W)
|
||||
if(!istype(W)) return
|
||||
switch(slot_id)
|
||||
// if("o_clothing")
|
||||
// if("head")
|
||||
if(slot_l_store)
|
||||
if(l_store)
|
||||
return
|
||||
if(W.w_class > WEIGHT_CLASS_NORMAL)
|
||||
return
|
||||
unEquip(W)
|
||||
l_store = W
|
||||
update_inv_pockets()
|
||||
if(slot_r_store)
|
||||
if(r_store)
|
||||
return
|
||||
if(W.w_class > WEIGHT_CLASS_NORMAL)
|
||||
return
|
||||
unEquip(W)
|
||||
r_store = W
|
||||
update_inv_pockets()
|
||||
else
|
||||
switch(slot_id)
|
||||
if(slot_wear_suit)
|
||||
if(wear_suit) wear_suit.attack_alien(src)
|
||||
if(slot_head)
|
||||
if(head) head.attack_alien(src)
|
||||
if(slot_l_store)
|
||||
if(l_store) l_store.attack_alien(src)
|
||||
if(slot_r_store)
|
||||
if(r_store) r_store.attack_alien(src)
|
||||
|
||||
@@ -1,89 +1,89 @@
|
||||
/mob/living/carbon/alien/humanoid/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
update_icons()
|
||||
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/handle_disabilities()
|
||||
if(disabilities & EPILEPSY)
|
||||
if((prob(1) && paralysis < 10))
|
||||
to_chat(src, "<span class='danger'>You have a seizure!</span>")
|
||||
Paralyse(10)
|
||||
if(disabilities & COUGHING)
|
||||
if((prob(5) && paralysis <= 1))
|
||||
drop_item()
|
||||
emote("cough")
|
||||
return
|
||||
if(disabilities & TOURETTES)
|
||||
if((prob(10) && paralysis <= 1))
|
||||
Stun(10)
|
||||
emote("twitch")
|
||||
return
|
||||
if(disabilities & NERVOUS)
|
||||
if(prob(10))
|
||||
stuttering = max(10, stuttering)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/proc/adjust_body_temperature(current, loc_temp, boost)
|
||||
var/temperature = current
|
||||
var/difference = abs(current-loc_temp) //get difference
|
||||
var/increments// = difference/10 //find how many increments apart they are
|
||||
if(difference > 50)
|
||||
increments = difference/5
|
||||
else
|
||||
increments = difference/10
|
||||
var/change = increments*boost // Get the amount to change by (x per increment)
|
||||
var/temp_change
|
||||
if(current < loc_temp)
|
||||
temperature = min(loc_temp, temperature+change)
|
||||
else if(current > loc_temp)
|
||||
temperature = max(loc_temp, temperature-change)
|
||||
temp_change = (temperature - current)
|
||||
return temp_change
|
||||
|
||||
/mob/living/carbon/alien/humanoid/handle_regular_status_updates()
|
||||
updatehealth()
|
||||
|
||||
if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP
|
||||
SetSilence(0)
|
||||
else //ALIVE. LIGHTS ARE ON
|
||||
if(health < HEALTH_THRESHOLD_DEAD && check_death_method() || !get_int_organ(/obj/item/organ/internal/brain))
|
||||
death()
|
||||
SetSilence(0)
|
||||
return 1
|
||||
|
||||
//UNCONSCIOUS. NO-ONE IS HOME
|
||||
if((getOxyLoss() > 50) || (HEALTH_THRESHOLD_CRIT >= health && check_death_method()))
|
||||
if(health <= 20 && prob(1))
|
||||
emote("gasp")
|
||||
if(!reagents.has_reagent("epinephrine"))
|
||||
adjustOxyLoss(1)
|
||||
Paralyse(3)
|
||||
|
||||
if(paralysis)
|
||||
stat = UNCONSCIOUS
|
||||
else if(sleeping)
|
||||
stat = UNCONSCIOUS
|
||||
if(prob(10) && health)
|
||||
emote("hiss")
|
||||
//CONSCIOUS
|
||||
else
|
||||
stat = CONSCIOUS
|
||||
|
||||
/* What in the living hell is this?*/
|
||||
if(move_delay_add > 0)
|
||||
move_delay_add = max(0, move_delay_add - rand(1, 2))
|
||||
|
||||
if(eye_blind) //blindness, heals slowly over time
|
||||
AdjustEyeBlind(-1)
|
||||
else if(eye_blurry) //blurry eyes heal slowly
|
||||
AdjustEyeBlurry(-1)
|
||||
|
||||
if(stuttering)
|
||||
AdjustStuttering(-1)
|
||||
|
||||
if(silent)
|
||||
AdjustSilence(-1)
|
||||
|
||||
if(druggy)
|
||||
AdjustDruggy(-1)
|
||||
return 1
|
||||
/mob/living/carbon/alien/humanoid/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
update_icons()
|
||||
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/handle_disabilities()
|
||||
if(disabilities & EPILEPSY)
|
||||
if((prob(1) && paralysis < 10))
|
||||
to_chat(src, "<span class='danger'>You have a seizure!</span>")
|
||||
Paralyse(10)
|
||||
if(disabilities & COUGHING)
|
||||
if((prob(5) && paralysis <= 1))
|
||||
drop_item()
|
||||
emote("cough")
|
||||
return
|
||||
if(disabilities & TOURETTES)
|
||||
if((prob(10) && paralysis <= 1))
|
||||
Stun(10)
|
||||
emote("twitch")
|
||||
return
|
||||
if(disabilities & NERVOUS)
|
||||
if(prob(10))
|
||||
stuttering = max(10, stuttering)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/proc/adjust_body_temperature(current, loc_temp, boost)
|
||||
var/temperature = current
|
||||
var/difference = abs(current-loc_temp) //get difference
|
||||
var/increments// = difference/10 //find how many increments apart they are
|
||||
if(difference > 50)
|
||||
increments = difference/5
|
||||
else
|
||||
increments = difference/10
|
||||
var/change = increments*boost // Get the amount to change by (x per increment)
|
||||
var/temp_change
|
||||
if(current < loc_temp)
|
||||
temperature = min(loc_temp, temperature+change)
|
||||
else if(current > loc_temp)
|
||||
temperature = max(loc_temp, temperature-change)
|
||||
temp_change = (temperature - current)
|
||||
return temp_change
|
||||
|
||||
/mob/living/carbon/alien/humanoid/handle_regular_status_updates()
|
||||
updatehealth()
|
||||
|
||||
if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP
|
||||
SetSilence(0)
|
||||
else //ALIVE. LIGHTS ARE ON
|
||||
if(health < HEALTH_THRESHOLD_DEAD && check_death_method() || !get_int_organ(/obj/item/organ/internal/brain))
|
||||
death()
|
||||
SetSilence(0)
|
||||
return 1
|
||||
|
||||
//UNCONSCIOUS. NO-ONE IS HOME
|
||||
if((getOxyLoss() > 50) || (HEALTH_THRESHOLD_CRIT >= health && check_death_method()))
|
||||
if(health <= 20 && prob(1))
|
||||
emote("gasp")
|
||||
if(!reagents.has_reagent("epinephrine"))
|
||||
adjustOxyLoss(1)
|
||||
Paralyse(3)
|
||||
|
||||
if(paralysis)
|
||||
stat = UNCONSCIOUS
|
||||
else if(sleeping)
|
||||
stat = UNCONSCIOUS
|
||||
if(prob(10) && health)
|
||||
emote("hiss")
|
||||
//CONSCIOUS
|
||||
else
|
||||
stat = CONSCIOUS
|
||||
|
||||
/* What in the living hell is this?*/
|
||||
if(move_delay_add > 0)
|
||||
move_delay_add = max(0, move_delay_add - rand(1, 2))
|
||||
|
||||
if(eye_blind) //blindness, heals slowly over time
|
||||
AdjustEyeBlind(-1)
|
||||
else if(eye_blurry) //blurry eyes heal slowly
|
||||
AdjustEyeBlurry(-1)
|
||||
|
||||
if(stuttering)
|
||||
AdjustStuttering(-1)
|
||||
|
||||
if(silent)
|
||||
AdjustSilence(-1)
|
||||
|
||||
if(druggy)
|
||||
AdjustDruggy(-1)
|
||||
return 1
|
||||
|
||||
@@ -1,95 +1,95 @@
|
||||
/mob/living/carbon/alien/humanoid/queen
|
||||
name = "alien queen"
|
||||
caste = "q"
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
icon_state = "alienq_s"
|
||||
status_flags = CANPARALYSE
|
||||
heal_rate = 5
|
||||
large = 1
|
||||
ventcrawler = 0
|
||||
pressure_resistance = 200 //Because big, stompy xenos should not be blown around like paper.
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/New()
|
||||
create_reagents(100)
|
||||
|
||||
//there should only be one queen
|
||||
for(var/mob/living/carbon/alien/humanoid/queen/Q in GLOB.living_mob_list)
|
||||
if(Q == src) continue
|
||||
if(Q.stat == DEAD) continue
|
||||
if(Q.client)
|
||||
name = "alien princess ([rand(1, 999)])" //if this is too cutesy feel free to change it/remove it.
|
||||
break
|
||||
|
||||
real_name = src.name
|
||||
alien_organs += new /obj/item/organ/internal/xenos/plasmavessel/queen
|
||||
alien_organs += new /obj/item/organ/internal/xenos/acidgland
|
||||
alien_organs += new /obj/item/organ/internal/xenos/eggsac
|
||||
alien_organs += new /obj/item/organ/internal/xenos/resinspinner
|
||||
alien_organs += new /obj/item/organ/internal/xenos/neurotoxin
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/movement_delay()
|
||||
. = ..()
|
||||
. += 3
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/handle_hud_icons_health()
|
||||
..() //-Yvarov
|
||||
|
||||
if(healths)
|
||||
if(stat != DEAD)
|
||||
switch(health)
|
||||
if(250 to INFINITY)
|
||||
healths.icon_state = "health0"
|
||||
if(175 to 250)
|
||||
healths.icon_state = "health1"
|
||||
if(100 to 175)
|
||||
healths.icon_state = "health2"
|
||||
if(50 to 100)
|
||||
healths.icon_state = "health3"
|
||||
if(0 to 50)
|
||||
healths.icon_state = "health4"
|
||||
else
|
||||
healths.icon_state = "health5"
|
||||
else
|
||||
healths.icon_state = "health6"
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/can_inject()
|
||||
return FALSE
|
||||
|
||||
//Queen verbs
|
||||
/mob/living/carbon/alien/humanoid/queen/verb/lay_egg()
|
||||
|
||||
set name = "Lay Egg (75)"
|
||||
set desc = "Lay an egg to produce huggers to impregnate prey with."
|
||||
set category = "Alien"
|
||||
if(locate(/obj/structure/alien/egg) in get_turf(src))
|
||||
to_chat(src, "<span class='noticealien'>There's already an egg here.</span>")
|
||||
return
|
||||
|
||||
if(powerc(75,1))//Can't plant eggs on spess tiles. That's silly.
|
||||
adjustPlasma(-75)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span class='alertalien'>[src] has laid an egg!</span>"), 1)
|
||||
new /obj/structure/alien/egg(loc)
|
||||
return
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/large
|
||||
icon = 'icons/mob/alienlarge.dmi'
|
||||
icon_state = "queen_s"
|
||||
pixel_x = -16
|
||||
large = 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/large/update_icons()
|
||||
overlays.Cut()
|
||||
|
||||
if(stat == DEAD)
|
||||
icon_state = "queen_dead"
|
||||
else if(stat == UNCONSCIOUS || lying || resting)
|
||||
icon_state = "queen_sleep"
|
||||
else
|
||||
icon_state = "queen_s"
|
||||
|
||||
for(var/image/I in overlays_standing)
|
||||
overlays += I
|
||||
/mob/living/carbon/alien/humanoid/queen
|
||||
name = "alien queen"
|
||||
caste = "q"
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
icon_state = "alienq_s"
|
||||
status_flags = CANPARALYSE
|
||||
heal_rate = 5
|
||||
large = 1
|
||||
ventcrawler = 0
|
||||
pressure_resistance = 200 //Because big, stompy xenos should not be blown around like paper.
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/New()
|
||||
create_reagents(100)
|
||||
|
||||
//there should only be one queen
|
||||
for(var/mob/living/carbon/alien/humanoid/queen/Q in GLOB.living_mob_list)
|
||||
if(Q == src) continue
|
||||
if(Q.stat == DEAD) continue
|
||||
if(Q.client)
|
||||
name = "alien princess ([rand(1, 999)])" //if this is too cutesy feel free to change it/remove it.
|
||||
break
|
||||
|
||||
real_name = src.name
|
||||
alien_organs += new /obj/item/organ/internal/xenos/plasmavessel/queen
|
||||
alien_organs += new /obj/item/organ/internal/xenos/acidgland
|
||||
alien_organs += new /obj/item/organ/internal/xenos/eggsac
|
||||
alien_organs += new /obj/item/organ/internal/xenos/resinspinner
|
||||
alien_organs += new /obj/item/organ/internal/xenos/neurotoxin
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/movement_delay()
|
||||
. = ..()
|
||||
. += 3
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/handle_hud_icons_health()
|
||||
..() //-Yvarov
|
||||
|
||||
if(healths)
|
||||
if(stat != DEAD)
|
||||
switch(health)
|
||||
if(250 to INFINITY)
|
||||
healths.icon_state = "health0"
|
||||
if(175 to 250)
|
||||
healths.icon_state = "health1"
|
||||
if(100 to 175)
|
||||
healths.icon_state = "health2"
|
||||
if(50 to 100)
|
||||
healths.icon_state = "health3"
|
||||
if(0 to 50)
|
||||
healths.icon_state = "health4"
|
||||
else
|
||||
healths.icon_state = "health5"
|
||||
else
|
||||
healths.icon_state = "health6"
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/can_inject()
|
||||
return FALSE
|
||||
|
||||
//Queen verbs
|
||||
/mob/living/carbon/alien/humanoid/queen/verb/lay_egg()
|
||||
|
||||
set name = "Lay Egg (75)"
|
||||
set desc = "Lay an egg to produce huggers to impregnate prey with."
|
||||
set category = "Alien"
|
||||
if(locate(/obj/structure/alien/egg) in get_turf(src))
|
||||
to_chat(src, "<span class='noticealien'>There's already an egg here.</span>")
|
||||
return
|
||||
|
||||
if(powerc(75,1))//Can't plant eggs on spess tiles. That's silly.
|
||||
adjustPlasma(-75)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span class='alertalien'>[src] has laid an egg!</span>"), 1)
|
||||
new /obj/structure/alien/egg(loc)
|
||||
return
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/large
|
||||
icon = 'icons/mob/alienlarge.dmi'
|
||||
icon_state = "queen_s"
|
||||
pixel_x = -16
|
||||
large = 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/large/update_icons()
|
||||
overlays.Cut()
|
||||
|
||||
if(stat == DEAD)
|
||||
icon_state = "queen_dead"
|
||||
else if(stat == UNCONSCIOUS || lying || resting)
|
||||
icon_state = "queen_sleep"
|
||||
else
|
||||
icon_state = "queen_s"
|
||||
|
||||
for(var/image/I in overlays_standing)
|
||||
overlays += I
|
||||
|
||||
@@ -1,166 +1,166 @@
|
||||
//Xeno Overlays Indexes//////////
|
||||
#define X_HEAD_LAYER 1
|
||||
#define X_SUIT_LAYER 2
|
||||
#define X_L_HAND_LAYER 3
|
||||
#define X_R_HAND_LAYER 4
|
||||
#define X_TARGETED_LAYER 5
|
||||
#define X_FIRE_LAYER 6
|
||||
#define X_TOTAL_LAYERS 6
|
||||
/////////////////////////////////
|
||||
|
||||
/mob/living/carbon/alien/humanoid
|
||||
var/list/overlays_standing[X_TOTAL_LAYERS]
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_icons()
|
||||
overlays.Cut()
|
||||
for(var/image/I in overlays_standing)
|
||||
overlays += I
|
||||
|
||||
if(stat == DEAD)
|
||||
//If we mostly took damage from fire
|
||||
if(getFireLoss() > 125)
|
||||
icon_state = "alien[caste]_husked"
|
||||
pixel_y = 0
|
||||
else
|
||||
icon_state = "alien[caste]_dead"
|
||||
pixel_y = 0
|
||||
|
||||
else if(stat == UNCONSCIOUS || IsWeakened())
|
||||
icon_state = "alien[caste]_unconscious"
|
||||
pixel_y = 0
|
||||
else if(leap_on_click)
|
||||
icon_state = "alien[caste]_pounce"
|
||||
|
||||
else if(lying || resting)
|
||||
icon_state = "alien[caste]_sleep"
|
||||
else if(m_intent == MOVE_INTENT_RUN)
|
||||
icon_state = "alien[caste]_running"
|
||||
else
|
||||
icon_state = "alien[caste]_s"
|
||||
|
||||
if(leaping)
|
||||
if(alt_icon == initial(alt_icon))
|
||||
var/old_icon = icon
|
||||
icon = alt_icon
|
||||
alt_icon = old_icon
|
||||
icon_state = "alien[caste]_leap"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
else
|
||||
if(alt_icon != initial(alt_icon))
|
||||
var/old_icon = icon
|
||||
icon = alt_icon
|
||||
alt_icon = old_icon
|
||||
pixel_x = get_standard_pixel_x_offset(lying)
|
||||
pixel_y = get_standard_pixel_y_offset(lying)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/regenerate_icons()
|
||||
..()
|
||||
if(notransform) return
|
||||
|
||||
update_inv_head(0,0)
|
||||
update_inv_wear_suit(0,0)
|
||||
update_inv_r_hand(0)
|
||||
update_inv_l_hand(0)
|
||||
update_inv_pockets(0)
|
||||
update_icons()
|
||||
update_fire()
|
||||
update_transform()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_transform() //The old method of updating lying/standing was update_icons(). Aliens still expect that.
|
||||
if(lying > 0)
|
||||
lying = 90 //Anything else looks retarded
|
||||
..()
|
||||
update_icons()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_fire()
|
||||
overlays -= overlays_standing[X_FIRE_LAYER]
|
||||
if(on_fire)
|
||||
overlays_standing[X_FIRE_LAYER] = image("icon"='icons/mob/OnFire.dmi', "icon_state"="Generic_mob_burning", "layer"= -X_FIRE_LAYER)
|
||||
overlays += overlays_standing[X_FIRE_LAYER]
|
||||
return
|
||||
else
|
||||
overlays_standing[X_FIRE_LAYER] = null
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_inv_wear_suit(var/update_icons=1)
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[slot_wear_suit]
|
||||
inv.update_icon()
|
||||
|
||||
if(wear_suit)
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown) //if the inventory is open ...
|
||||
wear_suit.screen_loc = ui_oclothing //TODO //...draw the item in the inventory screen
|
||||
client.screen += wear_suit //Either way, add the item to the HUD
|
||||
|
||||
var/t_state = wear_suit.item_state
|
||||
if(!t_state) t_state = wear_suit.icon_state
|
||||
var/image/standing = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "[t_state]")
|
||||
|
||||
if(wear_suit.blood_DNA)
|
||||
var/t_suit = "suit"
|
||||
if( istype(wear_suit, /obj/item/clothing/suit/armor) )
|
||||
t_suit = "armor"
|
||||
standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "[t_suit]blood")
|
||||
|
||||
if(wear_suit.breakouttime)
|
||||
drop_r_hand()
|
||||
drop_l_hand()
|
||||
|
||||
overlays_standing[X_SUIT_LAYER] = standing
|
||||
else
|
||||
overlays_standing[X_SUIT_LAYER] = null
|
||||
if(update_icons) update_icons()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_inv_head(var/update_icons=1)
|
||||
if(head)
|
||||
var/t_state = head.item_state
|
||||
if(!t_state) t_state = head.icon_state
|
||||
var/image/standing = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "[t_state]")
|
||||
if(head.blood_DNA)
|
||||
standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "helmetblood")
|
||||
head.screen_loc = ui_alien_head
|
||||
overlays_standing[X_HEAD_LAYER] = standing
|
||||
else
|
||||
overlays_standing[X_HEAD_LAYER] = null
|
||||
if(update_icons) update_icons()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_inv_pockets(var/update_icons=1)
|
||||
if(l_store) l_store.screen_loc = ui_storage1
|
||||
if(r_store) r_store.screen_loc = ui_storage2
|
||||
if(update_icons) update_icons()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_inv_r_hand(var/update_icons=1)
|
||||
..(1)
|
||||
if(r_hand)
|
||||
var/t_state = r_hand.item_state
|
||||
if(!t_state) t_state = r_hand.icon_state
|
||||
r_hand.screen_loc = ui_rhand
|
||||
overlays_standing[X_R_HAND_LAYER] = image("icon" = r_hand.righthand_file, "icon_state" = t_state)
|
||||
else
|
||||
overlays_standing[X_R_HAND_LAYER] = null
|
||||
if(update_icons) update_icons()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_inv_l_hand(var/update_icons=1)
|
||||
..(1)
|
||||
if(l_hand)
|
||||
var/t_state = l_hand.item_state
|
||||
if(!t_state) t_state = l_hand.icon_state
|
||||
l_hand.screen_loc = ui_lhand
|
||||
overlays_standing[X_L_HAND_LAYER] = image("icon" = l_hand.lefthand_file, "icon_state" = t_state)
|
||||
else
|
||||
overlays_standing[X_L_HAND_LAYER] = null
|
||||
if(update_icons) update_icons()
|
||||
|
||||
|
||||
//Xeno Overlays Indexes//////////
|
||||
#undef X_HEAD_LAYER
|
||||
#undef X_SUIT_LAYER
|
||||
#undef X_L_HAND_LAYER
|
||||
#undef X_R_HAND_LAYER
|
||||
#undef X_TARGETED_LAYER
|
||||
#undef X_FIRE_LAYER
|
||||
#undef X_TOTAL_LAYERS
|
||||
//Xeno Overlays Indexes//////////
|
||||
#define X_HEAD_LAYER 1
|
||||
#define X_SUIT_LAYER 2
|
||||
#define X_L_HAND_LAYER 3
|
||||
#define X_R_HAND_LAYER 4
|
||||
#define X_TARGETED_LAYER 5
|
||||
#define X_FIRE_LAYER 6
|
||||
#define X_TOTAL_LAYERS 6
|
||||
/////////////////////////////////
|
||||
|
||||
/mob/living/carbon/alien/humanoid
|
||||
var/list/overlays_standing[X_TOTAL_LAYERS]
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_icons()
|
||||
overlays.Cut()
|
||||
for(var/image/I in overlays_standing)
|
||||
overlays += I
|
||||
|
||||
if(stat == DEAD)
|
||||
//If we mostly took damage from fire
|
||||
if(getFireLoss() > 125)
|
||||
icon_state = "alien[caste]_husked"
|
||||
pixel_y = 0
|
||||
else
|
||||
icon_state = "alien[caste]_dead"
|
||||
pixel_y = 0
|
||||
|
||||
else if(stat == UNCONSCIOUS || IsWeakened())
|
||||
icon_state = "alien[caste]_unconscious"
|
||||
pixel_y = 0
|
||||
else if(leap_on_click)
|
||||
icon_state = "alien[caste]_pounce"
|
||||
|
||||
else if(lying || resting)
|
||||
icon_state = "alien[caste]_sleep"
|
||||
else if(m_intent == MOVE_INTENT_RUN)
|
||||
icon_state = "alien[caste]_running"
|
||||
else
|
||||
icon_state = "alien[caste]_s"
|
||||
|
||||
if(leaping)
|
||||
if(alt_icon == initial(alt_icon))
|
||||
var/old_icon = icon
|
||||
icon = alt_icon
|
||||
alt_icon = old_icon
|
||||
icon_state = "alien[caste]_leap"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
else
|
||||
if(alt_icon != initial(alt_icon))
|
||||
var/old_icon = icon
|
||||
icon = alt_icon
|
||||
alt_icon = old_icon
|
||||
pixel_x = get_standard_pixel_x_offset(lying)
|
||||
pixel_y = get_standard_pixel_y_offset(lying)
|
||||
|
||||
/mob/living/carbon/alien/humanoid/regenerate_icons()
|
||||
..()
|
||||
if(notransform) return
|
||||
|
||||
update_inv_head(0,0)
|
||||
update_inv_wear_suit(0,0)
|
||||
update_inv_r_hand(0)
|
||||
update_inv_l_hand(0)
|
||||
update_inv_pockets(0)
|
||||
update_icons()
|
||||
update_fire()
|
||||
update_transform()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_transform() //The old method of updating lying/standing was update_icons(). Aliens still expect that.
|
||||
if(lying > 0)
|
||||
lying = 90 //Anything else looks retarded
|
||||
..()
|
||||
update_icons()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_fire()
|
||||
overlays -= overlays_standing[X_FIRE_LAYER]
|
||||
if(on_fire)
|
||||
overlays_standing[X_FIRE_LAYER] = image("icon"='icons/mob/OnFire.dmi', "icon_state"="Generic_mob_burning", "layer"= -X_FIRE_LAYER)
|
||||
overlays += overlays_standing[X_FIRE_LAYER]
|
||||
return
|
||||
else
|
||||
overlays_standing[X_FIRE_LAYER] = null
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_inv_wear_suit(var/update_icons=1)
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[slot_wear_suit]
|
||||
inv.update_icon()
|
||||
|
||||
if(wear_suit)
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown) //if the inventory is open ...
|
||||
wear_suit.screen_loc = ui_oclothing //TODO //...draw the item in the inventory screen
|
||||
client.screen += wear_suit //Either way, add the item to the HUD
|
||||
|
||||
var/t_state = wear_suit.item_state
|
||||
if(!t_state) t_state = wear_suit.icon_state
|
||||
var/image/standing = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "[t_state]")
|
||||
|
||||
if(wear_suit.blood_DNA)
|
||||
var/t_suit = "suit"
|
||||
if( istype(wear_suit, /obj/item/clothing/suit/armor) )
|
||||
t_suit = "armor"
|
||||
standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "[t_suit]blood")
|
||||
|
||||
if(wear_suit.breakouttime)
|
||||
drop_r_hand()
|
||||
drop_l_hand()
|
||||
|
||||
overlays_standing[X_SUIT_LAYER] = standing
|
||||
else
|
||||
overlays_standing[X_SUIT_LAYER] = null
|
||||
if(update_icons) update_icons()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_inv_head(var/update_icons=1)
|
||||
if(head)
|
||||
var/t_state = head.item_state
|
||||
if(!t_state) t_state = head.icon_state
|
||||
var/image/standing = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "[t_state]")
|
||||
if(head.blood_DNA)
|
||||
standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "helmetblood")
|
||||
head.screen_loc = ui_alien_head
|
||||
overlays_standing[X_HEAD_LAYER] = standing
|
||||
else
|
||||
overlays_standing[X_HEAD_LAYER] = null
|
||||
if(update_icons) update_icons()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_inv_pockets(var/update_icons=1)
|
||||
if(l_store) l_store.screen_loc = ui_storage1
|
||||
if(r_store) r_store.screen_loc = ui_storage2
|
||||
if(update_icons) update_icons()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_inv_r_hand(var/update_icons=1)
|
||||
..(1)
|
||||
if(r_hand)
|
||||
var/t_state = r_hand.item_state
|
||||
if(!t_state) t_state = r_hand.icon_state
|
||||
r_hand.screen_loc = ui_rhand
|
||||
overlays_standing[X_R_HAND_LAYER] = image("icon" = r_hand.righthand_file, "icon_state" = t_state)
|
||||
else
|
||||
overlays_standing[X_R_HAND_LAYER] = null
|
||||
if(update_icons) update_icons()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/update_inv_l_hand(var/update_icons=1)
|
||||
..(1)
|
||||
if(l_hand)
|
||||
var/t_state = l_hand.item_state
|
||||
if(!t_state) t_state = l_hand.icon_state
|
||||
l_hand.screen_loc = ui_lhand
|
||||
overlays_standing[X_L_HAND_LAYER] = image("icon" = l_hand.lefthand_file, "icon_state" = t_state)
|
||||
else
|
||||
overlays_standing[X_L_HAND_LAYER] = null
|
||||
if(update_icons) update_icons()
|
||||
|
||||
|
||||
//Xeno Overlays Indexes//////////
|
||||
#undef X_HEAD_LAYER
|
||||
#undef X_SUIT_LAYER
|
||||
#undef X_L_HAND_LAYER
|
||||
#undef X_R_HAND_LAYER
|
||||
#undef X_TARGETED_LAYER
|
||||
#undef X_FIRE_LAYER
|
||||
#undef X_TOTAL_LAYERS
|
||||
|
||||
@@ -123,4 +123,4 @@
|
||||
for(var/mob/O in hearers(src, null))
|
||||
O.show_message(message, m_type)
|
||||
//Foreach goto(746)
|
||||
return
|
||||
return
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
//can't unequip since it can't equip anything
|
||||
/mob/living/carbon/alien/larva/unEquip(obj/item/W as obj, force)
|
||||
return
|
||||
//can't unequip since it can't equip anything
|
||||
/mob/living/carbon/alien/larva/unEquip(obj/item/W as obj, force)
|
||||
return
|
||||
|
||||
@@ -1,96 +1,96 @@
|
||||
/mob/living/carbon/alien/larva
|
||||
name = "alien larva"
|
||||
real_name = "alien larva"
|
||||
icon_state = "larva0"
|
||||
pass_flags = PASSTABLE | PASSMOB
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
|
||||
maxHealth = 30
|
||||
health = 30
|
||||
density = 0
|
||||
|
||||
var/amount_grown = 0
|
||||
var/max_grown = 200
|
||||
var/time_of_birth
|
||||
death_message = "lets out a waning high-pitched cry."
|
||||
death_sound = null
|
||||
|
||||
//This is fine right now, if we're adding organ specific damage this needs to be updated
|
||||
/mob/living/carbon/alien/larva/New()
|
||||
create_reagents(100)
|
||||
if(name == "alien larva")
|
||||
name = "alien larva ([rand(1, 1000)])"
|
||||
real_name = name
|
||||
regenerate_icons()
|
||||
add_language("Xenomorph")
|
||||
add_language("Hivemind")
|
||||
alien_organs += new /obj/item/organ/internal/xenos/plasmavessel/larva
|
||||
|
||||
..()
|
||||
|
||||
//This needs to be fixed
|
||||
/mob/living/carbon/alien/larva/Stat()
|
||||
..()
|
||||
stat(null, "Progress: [amount_grown]/[max_grown]")
|
||||
|
||||
/mob/living/carbon/alien/larva/adjustPlasma(amount)
|
||||
if(stat != DEAD && amount > 0)
|
||||
amount_grown = min(amount_grown + 1, max_grown)
|
||||
..(amount)
|
||||
|
||||
/mob/living/carbon/alien/larva/ex_act(severity)
|
||||
..()
|
||||
|
||||
var/b_loss = null
|
||||
var/f_loss = null
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
gib()
|
||||
return
|
||||
|
||||
if(2.0)
|
||||
|
||||
b_loss += 60
|
||||
|
||||
f_loss += 60
|
||||
|
||||
AdjustEarDamage(30, 120)
|
||||
|
||||
if(3.0)
|
||||
b_loss += 30
|
||||
if(prob(50))
|
||||
Paralyse(1)
|
||||
AdjustEarDamage(15, 60)
|
||||
|
||||
adjustBruteLoss(b_loss)
|
||||
adjustFireLoss(f_loss)
|
||||
|
||||
updatehealth()
|
||||
|
||||
//can't equip anything
|
||||
/mob/living/carbon/alien/larva/attack_ui(slot_id)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/larva/restrained()
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/alien/larva/var/temperature_resistance = T0C+75
|
||||
|
||||
// new damage icon system
|
||||
// now constructs damage icon for each organ from mask * damage field
|
||||
|
||||
|
||||
/mob/living/carbon/alien/larva/show_inv(mob/user as mob)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/larva/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
|
||||
return FALSE
|
||||
|
||||
/* Commented out because it's duplicated in life.dm
|
||||
/mob/living/carbon/alien/larva/proc/grow() // Larvae can grow into full fledged Xenos if they survive long enough -- TLE
|
||||
if(icon_state == "larva_l" && !canmove) // This is a shit death check. It is made of shit and death. Fix later.
|
||||
return
|
||||
else
|
||||
var/mob/living/carbon/alien/humanoid/A = new(loc)
|
||||
A.key = key
|
||||
qdel(src) */
|
||||
/mob/living/carbon/alien/larva
|
||||
name = "alien larva"
|
||||
real_name = "alien larva"
|
||||
icon_state = "larva0"
|
||||
pass_flags = PASSTABLE | PASSMOB
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
|
||||
maxHealth = 30
|
||||
health = 30
|
||||
density = 0
|
||||
|
||||
var/amount_grown = 0
|
||||
var/max_grown = 200
|
||||
var/time_of_birth
|
||||
death_message = "lets out a waning high-pitched cry."
|
||||
death_sound = null
|
||||
|
||||
//This is fine right now, if we're adding organ specific damage this needs to be updated
|
||||
/mob/living/carbon/alien/larva/New()
|
||||
create_reagents(100)
|
||||
if(name == "alien larva")
|
||||
name = "alien larva ([rand(1, 1000)])"
|
||||
real_name = name
|
||||
regenerate_icons()
|
||||
add_language("Xenomorph")
|
||||
add_language("Hivemind")
|
||||
alien_organs += new /obj/item/organ/internal/xenos/plasmavessel/larva
|
||||
|
||||
..()
|
||||
|
||||
//This needs to be fixed
|
||||
/mob/living/carbon/alien/larva/Stat()
|
||||
..()
|
||||
stat(null, "Progress: [amount_grown]/[max_grown]")
|
||||
|
||||
/mob/living/carbon/alien/larva/adjustPlasma(amount)
|
||||
if(stat != DEAD && amount > 0)
|
||||
amount_grown = min(amount_grown + 1, max_grown)
|
||||
..(amount)
|
||||
|
||||
/mob/living/carbon/alien/larva/ex_act(severity)
|
||||
..()
|
||||
|
||||
var/b_loss = null
|
||||
var/f_loss = null
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
gib()
|
||||
return
|
||||
|
||||
if(2.0)
|
||||
|
||||
b_loss += 60
|
||||
|
||||
f_loss += 60
|
||||
|
||||
AdjustEarDamage(30, 120)
|
||||
|
||||
if(3.0)
|
||||
b_loss += 30
|
||||
if(prob(50))
|
||||
Paralyse(1)
|
||||
AdjustEarDamage(15, 60)
|
||||
|
||||
adjustBruteLoss(b_loss)
|
||||
adjustFireLoss(f_loss)
|
||||
|
||||
updatehealth()
|
||||
|
||||
//can't equip anything
|
||||
/mob/living/carbon/alien/larva/attack_ui(slot_id)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/larva/restrained()
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/alien/larva/var/temperature_resistance = T0C+75
|
||||
|
||||
// new damage icon system
|
||||
// now constructs damage icon for each organ from mask * damage field
|
||||
|
||||
|
||||
/mob/living/carbon/alien/larva/show_inv(mob/user as mob)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/larva/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
|
||||
return FALSE
|
||||
|
||||
/* Commented out because it's duplicated in life.dm
|
||||
/mob/living/carbon/alien/larva/proc/grow() // Larvae can grow into full fledged Xenos if they survive long enough -- TLE
|
||||
if(icon_state == "larva_l" && !canmove) // This is a shit death check. It is made of shit and death. Fix later.
|
||||
return
|
||||
else
|
||||
var/mob/living/carbon/alien/humanoid/A = new(loc)
|
||||
A.key = key
|
||||
qdel(src) */
|
||||
|
||||
@@ -34,4 +34,4 @@
|
||||
/mob/living/carbon/alien/larva/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
|
||||
if(!no_effect && !visual_effect_icon)
|
||||
visual_effect_icon = ATTACK_EFFECT_BITE
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -1,57 +1,57 @@
|
||||
/mob/living/carbon/alien/larva/Life(seconds, times_fired)
|
||||
if(..()) //still breathing
|
||||
// GROW!
|
||||
if(amount_grown < max_grown)
|
||||
amount_grown++
|
||||
|
||||
//some kind of bug in canmove() isn't properly calling update_icons, so this is here as a placeholder
|
||||
update_icons()
|
||||
|
||||
/mob/living/carbon/alien/larva/handle_regular_status_updates()
|
||||
updatehealth()
|
||||
|
||||
if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP
|
||||
SetSilence(0)
|
||||
else //ALIVE. LIGHTS ARE ON
|
||||
if(health < -25 || !get_int_organ(/obj/item/organ/internal/brain))
|
||||
death()
|
||||
SetSilence(0)
|
||||
return 1
|
||||
|
||||
//UNCONSCIOUS. NO-ONE IS HOME
|
||||
if((getOxyLoss() > 25) || (HEALTH_THRESHOLD_CRIT >= health && check_death_method()))
|
||||
//if( health <= 20 && prob(1) )
|
||||
// spawn(0)
|
||||
// emote("gasp")
|
||||
if(!reagents.has_reagent("epinephrine"))
|
||||
adjustOxyLoss(1)
|
||||
Paralyse(3)
|
||||
|
||||
if(paralysis)
|
||||
stat = UNCONSCIOUS
|
||||
else if(sleeping)
|
||||
stat = UNCONSCIOUS
|
||||
if(prob(10) && health)
|
||||
emote("hiss_")
|
||||
//CONSCIOUS
|
||||
else
|
||||
stat = CONSCIOUS
|
||||
|
||||
/* What in the living hell is this?*/
|
||||
if(move_delay_add > 0)
|
||||
move_delay_add = max(0, move_delay_add - rand(1, 2))
|
||||
|
||||
if(eye_blind) //blindness, heals slowly over time
|
||||
AdjustEyeBlind(-1)
|
||||
else if(eye_blurry) //blurry eyes heal slowly
|
||||
AdjustEyeBlurry(-1)
|
||||
|
||||
if(stuttering)
|
||||
AdjustStuttering(-1)
|
||||
|
||||
if(silent)
|
||||
AdjustSilence(-1)
|
||||
|
||||
if(druggy)
|
||||
AdjustDruggy(-1)
|
||||
return 1
|
||||
/mob/living/carbon/alien/larva/Life(seconds, times_fired)
|
||||
if(..()) //still breathing
|
||||
// GROW!
|
||||
if(amount_grown < max_grown)
|
||||
amount_grown++
|
||||
|
||||
//some kind of bug in canmove() isn't properly calling update_icons, so this is here as a placeholder
|
||||
update_icons()
|
||||
|
||||
/mob/living/carbon/alien/larva/handle_regular_status_updates()
|
||||
updatehealth()
|
||||
|
||||
if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP
|
||||
SetSilence(0)
|
||||
else //ALIVE. LIGHTS ARE ON
|
||||
if(health < -25 || !get_int_organ(/obj/item/organ/internal/brain))
|
||||
death()
|
||||
SetSilence(0)
|
||||
return 1
|
||||
|
||||
//UNCONSCIOUS. NO-ONE IS HOME
|
||||
if((getOxyLoss() > 25) || (HEALTH_THRESHOLD_CRIT >= health && check_death_method()))
|
||||
//if( health <= 20 && prob(1) )
|
||||
// spawn(0)
|
||||
// emote("gasp")
|
||||
if(!reagents.has_reagent("epinephrine"))
|
||||
adjustOxyLoss(1)
|
||||
Paralyse(3)
|
||||
|
||||
if(paralysis)
|
||||
stat = UNCONSCIOUS
|
||||
else if(sleeping)
|
||||
stat = UNCONSCIOUS
|
||||
if(prob(10) && health)
|
||||
emote("hiss_")
|
||||
//CONSCIOUS
|
||||
else
|
||||
stat = CONSCIOUS
|
||||
|
||||
/* What in the living hell is this?*/
|
||||
if(move_delay_add > 0)
|
||||
move_delay_add = max(0, move_delay_add - rand(1, 2))
|
||||
|
||||
if(eye_blind) //blindness, heals slowly over time
|
||||
AdjustEyeBlind(-1)
|
||||
else if(eye_blurry) //blurry eyes heal slowly
|
||||
AdjustEyeBlurry(-1)
|
||||
|
||||
if(stuttering)
|
||||
AdjustStuttering(-1)
|
||||
|
||||
if(silent)
|
||||
AdjustSilence(-1)
|
||||
|
||||
if(druggy)
|
||||
AdjustDruggy(-1)
|
||||
return 1
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
|
||||
/mob/living/carbon/alien/larva/verb/hide()
|
||||
set name = "Hide"
|
||||
set desc = "Allows to hide beneath tables or certain items. Toggled on or off."
|
||||
set category = "Alien"
|
||||
|
||||
if(stat != CONSCIOUS)
|
||||
return
|
||||
|
||||
if(layer != ABOVE_NORMAL_TURF_LAYER)
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
visible_message("<B>[src] scurries to the ground!</B>", "<span class='noticealien'>You are now hiding.</span>")
|
||||
else
|
||||
layer = MOB_LAYER
|
||||
visible_message("[src] slowly peeks up from the ground...", "<span class=notice'>You have stopped hiding.</span>")
|
||||
|
||||
/mob/living/carbon/alien/larva/verb/evolve()
|
||||
set name = "Evolve"
|
||||
set desc = "Evolve into a fully grown Alien."
|
||||
set category = "Alien"
|
||||
|
||||
if(stat != CONSCIOUS)
|
||||
return
|
||||
|
||||
if(handcuffed || legcuffed)
|
||||
to_chat(src, "<span class='warning'>You cannot evolve when you are cuffed.</span>")
|
||||
|
||||
if(amount_grown >= max_grown) //TODO ~Carn
|
||||
//green is impossible to read, so i made these blue and changed the formatting slightly
|
||||
to_chat(src, "<span class='boldnotice'>You are growing into a beautiful alien! It is time to choose a caste.</span>")
|
||||
to_chat(src, "<span class='notice'>There are three to choose from:</span>")
|
||||
to_chat(src, "<B>Hunters</B> <span class='notice'>are strong and agile, able to hunt away from the hive and rapidly move through ventilation shafts. Hunters generate plasma slowly and have low reserves.</span>")
|
||||
to_chat(src, "<B>Sentinels</B> <span class='notice'>are tasked with protecting the hive and are deadly up close and at a range. They are not as physically imposing nor fast as the hunters.</span>")
|
||||
to_chat(src, "<B>Drones</B> <span class='notice'>are the working class, offering the largest plasma storage and generation. They are the only caste which may evolve again, turning into the dreaded alien queen.</span>")
|
||||
var/alien_caste = alert(src, "Please choose which alien caste you shall belong to.",,"Hunter","Sentinel","Drone")
|
||||
|
||||
var/mob/living/carbon/alien/humanoid/new_xeno
|
||||
switch(alien_caste)
|
||||
if("Hunter")
|
||||
new_xeno = new /mob/living/carbon/alien/humanoid/hunter(loc)
|
||||
if("Sentinel")
|
||||
new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(loc)
|
||||
if("Drone")
|
||||
new_xeno = new /mob/living/carbon/alien/humanoid/drone(loc)
|
||||
if(mind)
|
||||
mind.transfer_to(new_xeno)
|
||||
else
|
||||
new_xeno.key = key
|
||||
new_xeno.mind.name = new_xeno.name
|
||||
qdel(src)
|
||||
return
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You are not fully grown.</span>")
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/larva/verb/hide()
|
||||
set name = "Hide"
|
||||
set desc = "Allows to hide beneath tables or certain items. Toggled on or off."
|
||||
set category = "Alien"
|
||||
|
||||
if(stat != CONSCIOUS)
|
||||
return
|
||||
|
||||
if(layer != ABOVE_NORMAL_TURF_LAYER)
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
visible_message("<B>[src] scurries to the ground!</B>", "<span class='noticealien'>You are now hiding.</span>")
|
||||
else
|
||||
layer = MOB_LAYER
|
||||
visible_message("[src] slowly peeks up from the ground...", "<span class=notice'>You have stopped hiding.</span>")
|
||||
|
||||
/mob/living/carbon/alien/larva/verb/evolve()
|
||||
set name = "Evolve"
|
||||
set desc = "Evolve into a fully grown Alien."
|
||||
set category = "Alien"
|
||||
|
||||
if(stat != CONSCIOUS)
|
||||
return
|
||||
|
||||
if(handcuffed || legcuffed)
|
||||
to_chat(src, "<span class='warning'>You cannot evolve when you are cuffed.</span>")
|
||||
|
||||
if(amount_grown >= max_grown) //TODO ~Carn
|
||||
//green is impossible to read, so i made these blue and changed the formatting slightly
|
||||
to_chat(src, "<span class='boldnotice'>You are growing into a beautiful alien! It is time to choose a caste.</span>")
|
||||
to_chat(src, "<span class='notice'>There are three to choose from:</span>")
|
||||
to_chat(src, "<B>Hunters</B> <span class='notice'>are strong and agile, able to hunt away from the hive and rapidly move through ventilation shafts. Hunters generate plasma slowly and have low reserves.</span>")
|
||||
to_chat(src, "<B>Sentinels</B> <span class='notice'>are tasked with protecting the hive and are deadly up close and at a range. They are not as physically imposing nor fast as the hunters.</span>")
|
||||
to_chat(src, "<B>Drones</B> <span class='notice'>are the working class, offering the largest plasma storage and generation. They are the only caste which may evolve again, turning into the dreaded alien queen.</span>")
|
||||
var/alien_caste = alert(src, "Please choose which alien caste you shall belong to.",,"Hunter","Sentinel","Drone")
|
||||
|
||||
var/mob/living/carbon/alien/humanoid/new_xeno
|
||||
switch(alien_caste)
|
||||
if("Hunter")
|
||||
new_xeno = new /mob/living/carbon/alien/humanoid/hunter(loc)
|
||||
if("Sentinel")
|
||||
new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(loc)
|
||||
if("Drone")
|
||||
new_xeno = new /mob/living/carbon/alien/humanoid/drone(loc)
|
||||
if(mind)
|
||||
mind.transfer_to(new_xeno)
|
||||
else
|
||||
new_xeno.key = key
|
||||
new_xeno.mind.name = new_xeno.name
|
||||
qdel(src)
|
||||
return
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You are not fully grown.</span>")
|
||||
return
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
|
||||
/mob/living/carbon/alien/larva/regenerate_icons()
|
||||
overlays = list()
|
||||
update_icons()
|
||||
|
||||
/mob/living/carbon/alien/larva/update_icons()
|
||||
var/state = 0
|
||||
if(amount_grown > 150)
|
||||
state = 2
|
||||
else if(amount_grown > 50)
|
||||
state = 1
|
||||
|
||||
if(stat == DEAD)
|
||||
icon_state = "larva[state]_dead"
|
||||
else if(handcuffed || legcuffed) //This should be an overlay. Who made this an icon_state?
|
||||
icon_state = "larva[state]_cuff"
|
||||
else if(stat == UNCONSCIOUS || lying || resting)
|
||||
icon_state = "larva[state]_sleep"
|
||||
else if(stunned)
|
||||
icon_state = "larva[state]_stun"
|
||||
else
|
||||
icon_state = "larva[state]"
|
||||
|
||||
/mob/living/carbon/alien/larva/update_transform() //All this is handled in update_icons()
|
||||
return update_icons()
|
||||
|
||||
/mob/living/carbon/alien/larva/regenerate_icons()
|
||||
overlays = list()
|
||||
update_icons()
|
||||
|
||||
/mob/living/carbon/alien/larva/update_icons()
|
||||
var/state = 0
|
||||
if(amount_grown > 150)
|
||||
state = 2
|
||||
else if(amount_grown > 50)
|
||||
state = 1
|
||||
|
||||
if(stat == DEAD)
|
||||
icon_state = "larva[state]_dead"
|
||||
else if(handcuffed || legcuffed) //This should be an overlay. Who made this an icon_state?
|
||||
icon_state = "larva[state]_cuff"
|
||||
else if(stat == UNCONSCIOUS || lying || resting)
|
||||
icon_state = "larva[state]_sleep"
|
||||
else if(stunned)
|
||||
icon_state = "larva[state]_stun"
|
||||
else
|
||||
icon_state = "larva[state]"
|
||||
|
||||
/mob/living/carbon/alien/larva/update_transform() //All this is handled in update_icons()
|
||||
return update_icons()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/mob/living/carbon/alien/Login()
|
||||
..()
|
||||
AddInfectionImages()
|
||||
return
|
||||
/mob/living/carbon/alien/Login()
|
||||
..()
|
||||
AddInfectionImages()
|
||||
return
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/mob/living/carbon/alien/Logout()
|
||||
..()
|
||||
RemoveInfectionImages()
|
||||
return
|
||||
/mob/living/carbon/alien/Logout()
|
||||
..()
|
||||
RemoveInfectionImages()
|
||||
return
|
||||
|
||||
@@ -1,129 +1,129 @@
|
||||
// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability
|
||||
// It functions almost identically (see code/datums/diseases/alien_embryo.dm)
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo
|
||||
name = "alien embryo"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "larva0_dead"
|
||||
var/stage = 0
|
||||
var/polling = 0
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/on_find(mob/living/finder)
|
||||
..()
|
||||
if(stage < 4)
|
||||
to_chat(finder, "It's small and weak, barely the size of a fetus.")
|
||||
else
|
||||
to_chat(finder, "It's grown quite large, and writhes slightly as you look at it.")
|
||||
if(prob(10))
|
||||
AttemptGrow(0)
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.reagents.add_reagent("sacid", 10)
|
||||
return S
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/on_life()
|
||||
switch(stage)
|
||||
if(2, 3)
|
||||
if(prob(2))
|
||||
owner.emote("sneeze")
|
||||
if(prob(2))
|
||||
owner.emote("cough")
|
||||
if(prob(2))
|
||||
to_chat(owner, "<span class='danger'>Your throat feels sore.</span>")
|
||||
if(prob(2))
|
||||
to_chat(owner, "<span class='danger'>Mucous runs down the back of your throat.</span>")
|
||||
if(4)
|
||||
if(prob(2))
|
||||
owner.emote("sneeze")
|
||||
if(prob(2))
|
||||
owner.emote("cough")
|
||||
if(prob(4))
|
||||
to_chat(owner, "<span class='danger'>Your muscles ache.</span>")
|
||||
if(prob(20))
|
||||
owner.take_organ_damage(1)
|
||||
if(prob(4))
|
||||
to_chat(owner, "<span class='danger'>Your stomach hurts.</span>")
|
||||
if(prob(20))
|
||||
owner.adjustToxLoss(1)
|
||||
if(5)
|
||||
to_chat(owner, "<span class='danger'>You feel something tearing its way out of your stomach...</span>")
|
||||
owner.adjustToxLoss(10)
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/egg_process()
|
||||
if(stage < 5 && prob(3))
|
||||
stage++
|
||||
spawn(0)
|
||||
RefreshInfectionImage()
|
||||
|
||||
if(stage == 5 && prob(50))
|
||||
for(var/datum/surgery/S in owner.surgeries)
|
||||
if(S.location == "chest" && istype(S.get_surgery_step(), /datum/surgery_step/internal/manipulate_organs))
|
||||
AttemptGrow(0)
|
||||
return
|
||||
AttemptGrow()
|
||||
|
||||
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/proc/AttemptGrow(var/gib_on_success = 1)
|
||||
if(!owner || polling)
|
||||
return
|
||||
polling = 1
|
||||
spawn()
|
||||
var/list/candidates = pollCandidates("Do you want to play as an alien?", ROLE_ALIEN, 0)
|
||||
var/mob/C = null
|
||||
|
||||
// To stop clientless larva, we will check that our host has a client
|
||||
// if we find no ghosts to become the alien. If the host has a client
|
||||
// he will become the alien but if he doesn't then we will set the stage
|
||||
// to 2, so we don't do a process heavy check everytime.
|
||||
|
||||
if(candidates.len)
|
||||
C = pick(candidates)
|
||||
else if(owner.client)
|
||||
C = owner.client
|
||||
else
|
||||
stage = 2 // Let's try again later.
|
||||
polling = 0
|
||||
return
|
||||
|
||||
var/overlay = image('icons/mob/alien.dmi', loc = owner, icon_state = "burst_lie")
|
||||
owner.overlays += overlay
|
||||
|
||||
spawn(6)
|
||||
var/mob/living/carbon/alien/larva/new_xeno = new(owner.drop_location())
|
||||
new_xeno.key = C.key
|
||||
if(SSticker && SSticker.mode)
|
||||
SSticker.mode.xenos += new_xeno.mind
|
||||
new_xeno.mind.name = new_xeno.name
|
||||
new_xeno.mind.assigned_role = SPECIAL_ROLE_XENOMORPH
|
||||
new_xeno.mind.special_role = SPECIAL_ROLE_XENOMORPH
|
||||
new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100)//To get the player's attention
|
||||
|
||||
if(gib_on_success)
|
||||
owner.gib()
|
||||
else
|
||||
owner.adjustBruteLoss(40)
|
||||
owner.overlays -= overlay
|
||||
qdel(src)
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: AddInfectionImages(C)
|
||||
Des: Adds the infection image to all aliens for this embryo
|
||||
----------------------------------------*/
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/AddInfectionImages()
|
||||
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
|
||||
if(alien.client)
|
||||
var/I = image('icons/mob/alien.dmi', loc = owner, icon_state = "infected[stage]")
|
||||
alien.client.images += I
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: RemoveInfectionImage(C)
|
||||
Des: Removes all images from the mob infected by this embryo
|
||||
----------------------------------------*/
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/RemoveInfectionImages()
|
||||
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
|
||||
if(alien.client)
|
||||
for(var/image/I in alien.client.images)
|
||||
if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == owner)
|
||||
qdel(I)
|
||||
// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability
|
||||
// It functions almost identically (see code/datums/diseases/alien_embryo.dm)
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo
|
||||
name = "alien embryo"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "larva0_dead"
|
||||
var/stage = 0
|
||||
var/polling = 0
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/on_find(mob/living/finder)
|
||||
..()
|
||||
if(stage < 4)
|
||||
to_chat(finder, "It's small and weak, barely the size of a fetus.")
|
||||
else
|
||||
to_chat(finder, "It's grown quite large, and writhes slightly as you look at it.")
|
||||
if(prob(10))
|
||||
AttemptGrow(0)
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.reagents.add_reagent("sacid", 10)
|
||||
return S
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/on_life()
|
||||
switch(stage)
|
||||
if(2, 3)
|
||||
if(prob(2))
|
||||
owner.emote("sneeze")
|
||||
if(prob(2))
|
||||
owner.emote("cough")
|
||||
if(prob(2))
|
||||
to_chat(owner, "<span class='danger'>Your throat feels sore.</span>")
|
||||
if(prob(2))
|
||||
to_chat(owner, "<span class='danger'>Mucous runs down the back of your throat.</span>")
|
||||
if(4)
|
||||
if(prob(2))
|
||||
owner.emote("sneeze")
|
||||
if(prob(2))
|
||||
owner.emote("cough")
|
||||
if(prob(4))
|
||||
to_chat(owner, "<span class='danger'>Your muscles ache.</span>")
|
||||
if(prob(20))
|
||||
owner.take_organ_damage(1)
|
||||
if(prob(4))
|
||||
to_chat(owner, "<span class='danger'>Your stomach hurts.</span>")
|
||||
if(prob(20))
|
||||
owner.adjustToxLoss(1)
|
||||
if(5)
|
||||
to_chat(owner, "<span class='danger'>You feel something tearing its way out of your stomach...</span>")
|
||||
owner.adjustToxLoss(10)
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/egg_process()
|
||||
if(stage < 5 && prob(3))
|
||||
stage++
|
||||
spawn(0)
|
||||
RefreshInfectionImage()
|
||||
|
||||
if(stage == 5 && prob(50))
|
||||
for(var/datum/surgery/S in owner.surgeries)
|
||||
if(S.location == "chest" && istype(S.get_surgery_step(), /datum/surgery_step/internal/manipulate_organs))
|
||||
AttemptGrow(0)
|
||||
return
|
||||
AttemptGrow()
|
||||
|
||||
|
||||
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/proc/AttemptGrow(var/gib_on_success = 1)
|
||||
if(!owner || polling)
|
||||
return
|
||||
polling = 1
|
||||
spawn()
|
||||
var/list/candidates = pollCandidates("Do you want to play as an alien?", ROLE_ALIEN, 0)
|
||||
var/mob/C = null
|
||||
|
||||
// To stop clientless larva, we will check that our host has a client
|
||||
// if we find no ghosts to become the alien. If the host has a client
|
||||
// he will become the alien but if he doesn't then we will set the stage
|
||||
// to 2, so we don't do a process heavy check everytime.
|
||||
|
||||
if(candidates.len)
|
||||
C = pick(candidates)
|
||||
else if(owner.client)
|
||||
C = owner.client
|
||||
else
|
||||
stage = 2 // Let's try again later.
|
||||
polling = 0
|
||||
return
|
||||
|
||||
var/overlay = image('icons/mob/alien.dmi', loc = owner, icon_state = "burst_lie")
|
||||
owner.overlays += overlay
|
||||
|
||||
spawn(6)
|
||||
var/mob/living/carbon/alien/larva/new_xeno = new(owner.drop_location())
|
||||
new_xeno.key = C.key
|
||||
if(SSticker && SSticker.mode)
|
||||
SSticker.mode.xenos += new_xeno.mind
|
||||
new_xeno.mind.name = new_xeno.name
|
||||
new_xeno.mind.assigned_role = SPECIAL_ROLE_XENOMORPH
|
||||
new_xeno.mind.special_role = SPECIAL_ROLE_XENOMORPH
|
||||
new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100)//To get the player's attention
|
||||
|
||||
if(gib_on_success)
|
||||
owner.gib()
|
||||
else
|
||||
owner.adjustBruteLoss(40)
|
||||
owner.overlays -= overlay
|
||||
qdel(src)
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: AddInfectionImages(C)
|
||||
Des: Adds the infection image to all aliens for this embryo
|
||||
----------------------------------------*/
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/AddInfectionImages()
|
||||
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
|
||||
if(alien.client)
|
||||
var/I = image('icons/mob/alien.dmi', loc = owner, icon_state = "infected[stage]")
|
||||
alien.client.images += I
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: RemoveInfectionImage(C)
|
||||
Des: Removes all images from the mob infected by this embryo
|
||||
----------------------------------------*/
|
||||
/obj/item/organ/internal/body_egg/alien_embryo/RemoveInfectionImages()
|
||||
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
|
||||
if(alien.client)
|
||||
for(var/image/I in alien.client.images)
|
||||
if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == owner)
|
||||
qdel(I)
|
||||
|
||||
@@ -1,239 +1,239 @@
|
||||
//TODO: Make these simple_animals
|
||||
|
||||
#define MIN_IMPREGNATION_TIME 100 //time it takes to impregnate someone
|
||||
#define MAX_IMPREGNATION_TIME 150
|
||||
|
||||
#define MIN_ACTIVE_TIME 200 //time between being dropped and going idle
|
||||
#define MAX_ACTIVE_TIME 400
|
||||
|
||||
/obj/item/clothing/mask/facehugger
|
||||
name = "alien"
|
||||
desc = "It has some sort of a tube at the end of its tail."
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "facehugger"
|
||||
item_state = "facehugger"
|
||||
w_class = WEIGHT_CLASS_TINY //note: can be picked up by aliens unlike most other items of w_class below 4
|
||||
throw_range = 5
|
||||
tint = 3
|
||||
flags = AIRTIGHT
|
||||
flags_cover = MASKCOVERSMOUTH | MASKCOVERSEYES
|
||||
layer = MOB_LAYER
|
||||
max_integrity = 100
|
||||
|
||||
var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case
|
||||
|
||||
var/sterile = FALSE
|
||||
var/real = TRUE //0 for the toy, 1 for real. Sure I could istype, but fuck that.
|
||||
var/strength = 5
|
||||
|
||||
var/attached = 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
..()
|
||||
if(obj_integrity < 90)
|
||||
Die()
|
||||
|
||||
/obj/item/clothing/mask/facehugger/attackby(obj/item/O, mob/user, params)
|
||||
return O.attack_obj(src, user)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/attack_alien(mob/user) //can be picked up by aliens
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/attack_hand(mob/user)
|
||||
if((stat == CONSCIOUS && !sterile) && !isalien(user))
|
||||
if(Attach(user))
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/clothing/mask/facehugger/attack(mob/living/M, mob/user)
|
||||
..()
|
||||
user.unEquip(src)
|
||||
Attach(M)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/examine(mob/user)
|
||||
. = ..()
|
||||
if(real)//So that giant red text about probisci doesn't show up for fake ones
|
||||
switch(stat)
|
||||
if(DEAD,UNCONSCIOUS)
|
||||
. += "<span class='boldannounce'>[src] is not moving.</span>"
|
||||
if(CONSCIOUS)
|
||||
. += "<span class='boldannounce'>[src] seems to be active!</span>"
|
||||
if(sterile)
|
||||
. += "<span class='boldannounce'>It looks like the proboscis has been removed.</span>"
|
||||
|
||||
/obj/item/clothing/mask/facehugger/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
..()
|
||||
if(exposed_temperature > 300)
|
||||
Die()
|
||||
|
||||
/obj/item/clothing/mask/facehugger/equipped(mob/M)
|
||||
Attach(M)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/Crossed(atom/target, oldloc)
|
||||
HasProximity(target)
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/facehugger/on_found(mob/finder)
|
||||
if(stat == CONSCIOUS)
|
||||
return HasProximity(finder)
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM as mob|obj)
|
||||
if(CanHug(AM) && Adjacent(AM))
|
||||
return Attach(AM)
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed)
|
||||
if(!..())
|
||||
return
|
||||
if(stat == CONSCIOUS)
|
||||
icon_state = "[initial(icon_state)]_thrown"
|
||||
spawn(15)
|
||||
if(icon_state == "[initial(icon_state)]_thrown")
|
||||
icon_state = "[initial(icon_state)]"
|
||||
|
||||
/obj/item/clothing/mask/facehugger/throw_impact(atom/hit_atom)
|
||||
..()
|
||||
if(stat == CONSCIOUS)
|
||||
icon_state = "[initial(icon_state)]"
|
||||
Attach(hit_atom)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/proc/Attach(mob/living/M)
|
||||
if(!isliving(M))
|
||||
return 0
|
||||
if((!iscorgi(M) && !iscarbon(M)) || isalien(M))
|
||||
return 0
|
||||
if(attached)
|
||||
return 0
|
||||
else
|
||||
attached++
|
||||
spawn(MAX_IMPREGNATION_TIME)
|
||||
attached = 0
|
||||
if(M.get_int_organ(/obj/item/organ/internal/xenos/hivenode))
|
||||
return 0
|
||||
if(M.get_int_organ(/obj/item/organ/internal/body_egg/alien_embryo))
|
||||
return 0
|
||||
if(loc == M)
|
||||
return 0
|
||||
if(stat != CONSCIOUS)
|
||||
return 0
|
||||
if(!sterile) M.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage
|
||||
M.visible_message("<span class='danger'>[src] leaps at [M]'s face!</span>", \
|
||||
"<span class='userdanger'>[src] leaps at [M]'s face!</span>")
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.head && H.head.flags_cover & HEADCOVERSMOUTH)
|
||||
H.visible_message("<span class='danger'>[src] smashes against [H]'s [H.head]!</span>", \
|
||||
"<span class='userdanger'>[src] smashes against [H]'s [H.head]!</span>")
|
||||
Die()
|
||||
return 0
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/target = M
|
||||
if(target.wear_mask)
|
||||
if(prob(20))
|
||||
return 0
|
||||
if(istype(target.wear_mask, /obj/item/clothing/mask/muzzle))
|
||||
var/obj/item/clothing/mask/muzzle/S = target.wear_mask
|
||||
if(S.do_break())
|
||||
target.visible_message("<span class='danger'>[src] spits acid onto [S] melting the lock!</span>", \
|
||||
"<span class='userdanger'>[src] spits acid onto [S] melting the lock!</span>")
|
||||
var/obj/item/clothing/W = target.wear_mask
|
||||
if(W.flags & NODROP)
|
||||
return 0
|
||||
target.unEquip(W)
|
||||
|
||||
target.visible_message("<span class='danger'>[src] tears [W] off of [target]'s face!</span>", \
|
||||
"<span class='userdanger'>[src] tears [W] off of [target]'s face!</span>")
|
||||
|
||||
src.loc = target
|
||||
target.equip_to_slot(src, slot_wear_mask,,0)
|
||||
if(!sterile)
|
||||
M.Paralyse(MAX_IMPREGNATION_TIME/6) //something like 25 ticks = 20 seconds with the default settings
|
||||
|
||||
GoIdle() //so it doesn't jump the people that tear it off
|
||||
|
||||
spawn(rand(MIN_IMPREGNATION_TIME,MAX_IMPREGNATION_TIME))
|
||||
Impregnate(M)
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/mask/facehugger/proc/Impregnate(mob/living/target as mob)
|
||||
if(!target || target.stat == DEAD || loc != target) //was taken off or something
|
||||
return
|
||||
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(C.wear_mask != src)
|
||||
return
|
||||
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(!H.check_has_mouth())
|
||||
return
|
||||
|
||||
if(!sterile)
|
||||
//target.contract_disease(new /datum/disease/alien_embryo(0)) //so infection chance is same as virus infection chance
|
||||
target.visible_message("<span class='danger'>[src] falls limp after violating [target]'s face!</span>", \
|
||||
"<span class='userdanger'>[src] falls limp after violating [target]'s face!</span>")
|
||||
|
||||
Die()
|
||||
icon_state = "[initial(icon_state)]_impregnated"
|
||||
|
||||
if(!target.get_int_organ(/obj/item/organ/internal/body_egg/alien_embryo))
|
||||
new /obj/item/organ/internal/body_egg/alien_embryo(target)
|
||||
else
|
||||
target.visible_message("<span class='danger'>[src] violates [target]'s face!</span>", \
|
||||
"<span class='userdanger'>[src] violates [target]'s face!</span>")
|
||||
|
||||
/obj/item/clothing/mask/facehugger/proc/GoActive()
|
||||
if(stat == DEAD || stat == CONSCIOUS)
|
||||
return
|
||||
|
||||
stat = CONSCIOUS
|
||||
icon_state = "[initial(icon_state)]"
|
||||
|
||||
/obj/item/clothing/mask/facehugger/proc/GoIdle()
|
||||
if(stat == DEAD || stat == UNCONSCIOUS)
|
||||
return
|
||||
|
||||
stat = UNCONSCIOUS
|
||||
icon_state = "[initial(icon_state)]_inactive"
|
||||
|
||||
spawn(rand(MIN_ACTIVE_TIME,MAX_ACTIVE_TIME))
|
||||
GoActive()
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/facehugger/proc/Die()
|
||||
if(stat == DEAD)
|
||||
return
|
||||
|
||||
icon_state = "[initial(icon_state)]_dead"
|
||||
item_state = "facehugger_inactive"
|
||||
stat = DEAD
|
||||
|
||||
visible_message("<span class='danger'>[src] curls up into a ball!</span>")
|
||||
|
||||
/proc/CanHug(mob/living/M)
|
||||
if(!istype(M))
|
||||
return 0
|
||||
if(M.stat == DEAD)
|
||||
return 0
|
||||
if(M.get_int_organ(/obj/item/organ/internal/xenos/hivenode))
|
||||
return 0
|
||||
|
||||
if(iscorgi(M))
|
||||
return 1
|
||||
|
||||
var/mob/living/carbon/C = M
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.head && H.head.flags_cover & HEADCOVERSMOUTH)
|
||||
return 0
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/lamarr
|
||||
name = "Lamarr"
|
||||
desc = "The worst she might do is attempt to... couple with your head." //hope we don't get sued over a harmless reference, rite?
|
||||
sterile = 1
|
||||
gender = FEMALE
|
||||
//TODO: Make these simple_animals
|
||||
|
||||
#define MIN_IMPREGNATION_TIME 100 //time it takes to impregnate someone
|
||||
#define MAX_IMPREGNATION_TIME 150
|
||||
|
||||
#define MIN_ACTIVE_TIME 200 //time between being dropped and going idle
|
||||
#define MAX_ACTIVE_TIME 400
|
||||
|
||||
/obj/item/clothing/mask/facehugger
|
||||
name = "alien"
|
||||
desc = "It has some sort of a tube at the end of its tail."
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "facehugger"
|
||||
item_state = "facehugger"
|
||||
w_class = WEIGHT_CLASS_TINY //note: can be picked up by aliens unlike most other items of w_class below 4
|
||||
throw_range = 5
|
||||
tint = 3
|
||||
flags = AIRTIGHT
|
||||
flags_cover = MASKCOVERSMOUTH | MASKCOVERSEYES
|
||||
layer = MOB_LAYER
|
||||
max_integrity = 100
|
||||
|
||||
var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case
|
||||
|
||||
var/sterile = FALSE
|
||||
var/real = TRUE //0 for the toy, 1 for real. Sure I could istype, but fuck that.
|
||||
var/strength = 5
|
||||
|
||||
var/attached = 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
..()
|
||||
if(obj_integrity < 90)
|
||||
Die()
|
||||
|
||||
/obj/item/clothing/mask/facehugger/attackby(obj/item/O, mob/user, params)
|
||||
return O.attack_obj(src, user)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/attack_alien(mob/user) //can be picked up by aliens
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/attack_hand(mob/user)
|
||||
if((stat == CONSCIOUS && !sterile) && !isalien(user))
|
||||
if(Attach(user))
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/clothing/mask/facehugger/attack(mob/living/M, mob/user)
|
||||
..()
|
||||
user.unEquip(src)
|
||||
Attach(M)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/examine(mob/user)
|
||||
. = ..()
|
||||
if(real)//So that giant red text about probisci doesn't show up for fake ones
|
||||
switch(stat)
|
||||
if(DEAD,UNCONSCIOUS)
|
||||
. += "<span class='boldannounce'>[src] is not moving.</span>"
|
||||
if(CONSCIOUS)
|
||||
. += "<span class='boldannounce'>[src] seems to be active!</span>"
|
||||
if(sterile)
|
||||
. += "<span class='boldannounce'>It looks like the proboscis has been removed.</span>"
|
||||
|
||||
/obj/item/clothing/mask/facehugger/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
..()
|
||||
if(exposed_temperature > 300)
|
||||
Die()
|
||||
|
||||
/obj/item/clothing/mask/facehugger/equipped(mob/M)
|
||||
Attach(M)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/Crossed(atom/target, oldloc)
|
||||
HasProximity(target)
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/facehugger/on_found(mob/finder)
|
||||
if(stat == CONSCIOUS)
|
||||
return HasProximity(finder)
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM as mob|obj)
|
||||
if(CanHug(AM) && Adjacent(AM))
|
||||
return Attach(AM)
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed)
|
||||
if(!..())
|
||||
return
|
||||
if(stat == CONSCIOUS)
|
||||
icon_state = "[initial(icon_state)]_thrown"
|
||||
spawn(15)
|
||||
if(icon_state == "[initial(icon_state)]_thrown")
|
||||
icon_state = "[initial(icon_state)]"
|
||||
|
||||
/obj/item/clothing/mask/facehugger/throw_impact(atom/hit_atom)
|
||||
..()
|
||||
if(stat == CONSCIOUS)
|
||||
icon_state = "[initial(icon_state)]"
|
||||
Attach(hit_atom)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/proc/Attach(mob/living/M)
|
||||
if(!isliving(M))
|
||||
return 0
|
||||
if((!iscorgi(M) && !iscarbon(M)) || isalien(M))
|
||||
return 0
|
||||
if(attached)
|
||||
return 0
|
||||
else
|
||||
attached++
|
||||
spawn(MAX_IMPREGNATION_TIME)
|
||||
attached = 0
|
||||
if(M.get_int_organ(/obj/item/organ/internal/xenos/hivenode))
|
||||
return 0
|
||||
if(M.get_int_organ(/obj/item/organ/internal/body_egg/alien_embryo))
|
||||
return 0
|
||||
if(loc == M)
|
||||
return 0
|
||||
if(stat != CONSCIOUS)
|
||||
return 0
|
||||
if(!sterile) M.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage
|
||||
M.visible_message("<span class='danger'>[src] leaps at [M]'s face!</span>", \
|
||||
"<span class='userdanger'>[src] leaps at [M]'s face!</span>")
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.head && H.head.flags_cover & HEADCOVERSMOUTH)
|
||||
H.visible_message("<span class='danger'>[src] smashes against [H]'s [H.head]!</span>", \
|
||||
"<span class='userdanger'>[src] smashes against [H]'s [H.head]!</span>")
|
||||
Die()
|
||||
return 0
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/target = M
|
||||
if(target.wear_mask)
|
||||
if(prob(20))
|
||||
return 0
|
||||
if(istype(target.wear_mask, /obj/item/clothing/mask/muzzle))
|
||||
var/obj/item/clothing/mask/muzzle/S = target.wear_mask
|
||||
if(S.do_break())
|
||||
target.visible_message("<span class='danger'>[src] spits acid onto [S] melting the lock!</span>", \
|
||||
"<span class='userdanger'>[src] spits acid onto [S] melting the lock!</span>")
|
||||
var/obj/item/clothing/W = target.wear_mask
|
||||
if(W.flags & NODROP)
|
||||
return 0
|
||||
target.unEquip(W)
|
||||
|
||||
target.visible_message("<span class='danger'>[src] tears [W] off of [target]'s face!</span>", \
|
||||
"<span class='userdanger'>[src] tears [W] off of [target]'s face!</span>")
|
||||
|
||||
src.loc = target
|
||||
target.equip_to_slot(src, slot_wear_mask,,0)
|
||||
if(!sterile)
|
||||
M.Paralyse(MAX_IMPREGNATION_TIME/6) //something like 25 ticks = 20 seconds with the default settings
|
||||
|
||||
GoIdle() //so it doesn't jump the people that tear it off
|
||||
|
||||
spawn(rand(MIN_IMPREGNATION_TIME,MAX_IMPREGNATION_TIME))
|
||||
Impregnate(M)
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/mask/facehugger/proc/Impregnate(mob/living/target as mob)
|
||||
if(!target || target.stat == DEAD || loc != target) //was taken off or something
|
||||
return
|
||||
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(C.wear_mask != src)
|
||||
return
|
||||
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(!H.check_has_mouth())
|
||||
return
|
||||
|
||||
if(!sterile)
|
||||
//target.contract_disease(new /datum/disease/alien_embryo(0)) //so infection chance is same as virus infection chance
|
||||
target.visible_message("<span class='danger'>[src] falls limp after violating [target]'s face!</span>", \
|
||||
"<span class='userdanger'>[src] falls limp after violating [target]'s face!</span>")
|
||||
|
||||
Die()
|
||||
icon_state = "[initial(icon_state)]_impregnated"
|
||||
|
||||
if(!target.get_int_organ(/obj/item/organ/internal/body_egg/alien_embryo))
|
||||
new /obj/item/organ/internal/body_egg/alien_embryo(target)
|
||||
else
|
||||
target.visible_message("<span class='danger'>[src] violates [target]'s face!</span>", \
|
||||
"<span class='userdanger'>[src] violates [target]'s face!</span>")
|
||||
|
||||
/obj/item/clothing/mask/facehugger/proc/GoActive()
|
||||
if(stat == DEAD || stat == CONSCIOUS)
|
||||
return
|
||||
|
||||
stat = CONSCIOUS
|
||||
icon_state = "[initial(icon_state)]"
|
||||
|
||||
/obj/item/clothing/mask/facehugger/proc/GoIdle()
|
||||
if(stat == DEAD || stat == UNCONSCIOUS)
|
||||
return
|
||||
|
||||
stat = UNCONSCIOUS
|
||||
icon_state = "[initial(icon_state)]_inactive"
|
||||
|
||||
spawn(rand(MIN_ACTIVE_TIME,MAX_ACTIVE_TIME))
|
||||
GoActive()
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/facehugger/proc/Die()
|
||||
if(stat == DEAD)
|
||||
return
|
||||
|
||||
icon_state = "[initial(icon_state)]_dead"
|
||||
item_state = "facehugger_inactive"
|
||||
stat = DEAD
|
||||
|
||||
visible_message("<span class='danger'>[src] curls up into a ball!</span>")
|
||||
|
||||
/proc/CanHug(mob/living/M)
|
||||
if(!istype(M))
|
||||
return 0
|
||||
if(M.stat == DEAD)
|
||||
return 0
|
||||
if(M.get_int_organ(/obj/item/organ/internal/xenos/hivenode))
|
||||
return 0
|
||||
|
||||
if(iscorgi(M))
|
||||
return 1
|
||||
|
||||
var/mob/living/carbon/C = M
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.head && H.head.flags_cover & HEADCOVERSMOUTH)
|
||||
return 0
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/mask/facehugger/lamarr
|
||||
name = "Lamarr"
|
||||
desc = "The worst she might do is attempt to... couple with your head." //hope we don't get sued over a harmless reference, rite?
|
||||
sterile = 1
|
||||
gender = FEMALE
|
||||
|
||||
@@ -1,299 +1,299 @@
|
||||
/obj/item/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 = WEIGHT_CLASS_NORMAL
|
||||
origin_tech = "biotech=3"
|
||||
origin_tech = "biotech=2;programming=3;engineering=2"
|
||||
|
||||
//Revised. Brainmob is now contained directly within object of transfer. MMI in this case.
|
||||
var/alien = 0
|
||||
var/syndiemmi = 0 //Whether or not this is a Syndicate MMI
|
||||
var/mob/living/carbon/brain/brainmob = null//The current occupant.
|
||||
var/obj/item/organ/internal/brain/held_brain = null // This is so MMI's aren't brainscrubber 9000's
|
||||
var/mob/living/silicon/robot/robot = null//Appears unused.
|
||||
var/obj/mecha/mecha = null//This does not appear to be used outside of reference in mecha.dm.
|
||||
// I'm using this for mechs giving MMIs HUDs now
|
||||
|
||||
var/obj/item/radio/radio = null // For use with the radio MMI upgrade
|
||||
var/datum/action/generic/configure_mmi_radio/radio_action = null
|
||||
|
||||
// Used for cases when mmi or one of it's children commits suicide.
|
||||
// Needed to fix a rather insane bug when a posibrain/robotic brain commits suicide
|
||||
var/dead_icon = "mmi_dead"
|
||||
|
||||
/obj/item/mmi/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
|
||||
if(istype(O, /obj/item/organ/internal/brain/crystal))
|
||||
to_chat(user, "<span class='warning'> This brain is too malformed to be able to use with the [src].</span>")
|
||||
return
|
||||
if(istype(O, /obj/item/organ/internal/brain/golem))
|
||||
to_chat(user, "<span class='warning'>You can't find a way to plug [O] into [src].</span>")
|
||||
return
|
||||
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.brainmob)
|
||||
to_chat(user, "<span class='warning'>You aren't sure where this brain came from, but you're pretty sure it's a useless brain.</span>")
|
||||
return
|
||||
if(held_brain)
|
||||
to_chat(user, "<span class='userdanger'>Somehow, this MMI still has a brain in it. Report this to the bug tracker.</span>")
|
||||
log_runtime(EXCEPTION("[user] tried to stick a [O] into [src] in [get_area(src)], but the held brain variable wasn't cleared"), src)
|
||||
return
|
||||
if(user.drop_item())
|
||||
B.forceMove(src)
|
||||
visible_message("<span class='notice'>[user] sticks \a [O] into \the [src].</span>")
|
||||
brainmob = B.brainmob
|
||||
B.brainmob = null
|
||||
brainmob.forceMove(src)
|
||||
brainmob.container = src
|
||||
brainmob.stat = CONSCIOUS
|
||||
GLOB.respawnable_list -= brainmob
|
||||
GLOB.dead_mob_list -= brainmob//Update dem lists
|
||||
GLOB.living_mob_list += brainmob
|
||||
|
||||
held_brain = B
|
||||
if(istype(O,/obj/item/organ/internal/brain/xeno)) // kept the type check, as it still does other weird stuff
|
||||
name = "Man-Machine Interface: Alien - [brainmob.real_name]"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
become_occupied("AlienMMI")
|
||||
alien = 1
|
||||
else
|
||||
name = "Man-Machine Interface: [brainmob.real_name]"
|
||||
icon = B.mmi_icon
|
||||
become_occupied("[B.mmi_icon_state]")
|
||||
alien = 0
|
||||
|
||||
if(radio_action)
|
||||
radio_action.UpdateButtonIcon()
|
||||
feedback_inc("cyborg_mmis_filled",1)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't drop [B]!</span>")
|
||||
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/mmi_radio_upgrade))
|
||||
if(radio)
|
||||
to_chat(user, "<span class='warning'>[src] already has a radio installed.</span>")
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] begins to install the [O] into [src]...</span>", \
|
||||
"<span class='notice'>You start to install the [O] into [src]...</span>")
|
||||
if(do_after(user, 20, target=src))
|
||||
if(user.drop_item())
|
||||
user.visible_message("<span class='notice'>[user] installs [O] in [src].</span>", \
|
||||
"<span class='notice'>You install [O] in [src].</span>")
|
||||
if(brainmob)
|
||||
to_chat(brainmob, "<span class='notice'>MMI radio capability installed.</span>")
|
||||
install_radio()
|
||||
qdel(O)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't drop [O]!</span>")
|
||||
return
|
||||
|
||||
// Maybe later add encryption key support, but that's a pain in the neck atm
|
||||
|
||||
if(brainmob)
|
||||
O.attack(brainmob, user)//Oh noooeeeee
|
||||
// Brainmobs can take damage, but they can't actually die. Maybe should fix.
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/mmi/screwdriver_act(mob/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(!I.tool_use_check(user, 0))
|
||||
return
|
||||
if(!radio)
|
||||
to_chat(user, "<span class='warning'>There is no radio in [src]!</span>")
|
||||
return
|
||||
user.visible_message("<span class='warning'>[user] begins to uninstall the radio from [src]...</span>", \
|
||||
"<span class='notice'>You start to uninstall the radio from [src]...</span>")
|
||||
if(!I.use_tool(src, user, 40, volume = I.tool_volume) || !radio)
|
||||
return
|
||||
uninstall_radio()
|
||||
new /obj/item/mmi_radio_upgrade(get_turf(src))
|
||||
user.visible_message("<span class='warning'>[user] uninstalls the radio from [src].</span>", \
|
||||
"<span class='notice'>You uninstall the radio from [src].</span>")
|
||||
|
||||
|
||||
/obj/item/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
|
||||
to_chat(user, "<span class='notice'>You unlock and upend the MMI, spilling the brain onto the floor.</span>")
|
||||
dropbrain(get_turf(user))
|
||||
icon = 'icons/obj/assemblies.dmi'
|
||||
icon_state = "mmi_empty"
|
||||
name = "Man-Machine Interface"
|
||||
|
||||
/obj/item/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.Clone()
|
||||
brainmob.container = src
|
||||
|
||||
if(!istype(H.dna.species) || isnull(H.dna.species.return_organ("brain"))) // Diona/buggy people
|
||||
held_brain = new(src)
|
||||
else // We have a species, and it has a brain
|
||||
var/brain_path = H.dna.species.return_organ("brain")
|
||||
if(!ispath(brain_path, /obj/item/organ/internal/brain))
|
||||
brain_path = /obj/item/organ/internal/brain
|
||||
held_brain = new brain_path(src) // Slime people will keep their slimy brains this way
|
||||
held_brain.dna = brainmob.dna.Clone()
|
||||
held_brain.name = "\the [brainmob.name]'s [initial(held_brain.name)]"
|
||||
|
||||
name = "Man-Machine Interface: [brainmob.real_name]"
|
||||
become_occupied("mmi_full")
|
||||
|
||||
//I made this proc as a way to have a brainmob be transferred to any created brain, and to solve the
|
||||
//problem i was having with alien/nonalien brain drops.
|
||||
/obj/item/mmi/proc/dropbrain(var/turf/dropspot)
|
||||
if(isnull(held_brain))
|
||||
log_runtime(EXCEPTION("[src] at [loc] attempted to drop brain without a contained brain in [get_area(src)]."), src)
|
||||
to_chat(brainmob, "<span class='userdanger'>Your MMI did not contain a brain! We'll make a new one for you, but you'd best report this to the bugtracker!</span>")
|
||||
held_brain = new(dropspot) // Let's not ruin someone's round because of something dumb -- Crazylemon
|
||||
held_brain.dna = brainmob.dna.Clone()
|
||||
held_brain.name = "\the [brainmob.name]'s [initial(held_brain.name)]"
|
||||
|
||||
brainmob.container = null//Reset brainmob mmi var.
|
||||
brainmob.forceMove(held_brain) //Throw mob into brain.
|
||||
GLOB.respawnable_list += brainmob
|
||||
GLOB.living_mob_list -= brainmob//Get outta here
|
||||
held_brain.brainmob = brainmob//Set the brain to use the brainmob
|
||||
held_brain.brainmob.cancel_camera()
|
||||
brainmob = null//Set mmi brainmob var to null
|
||||
held_brain.forceMove(dropspot)
|
||||
held_brain = null
|
||||
|
||||
/obj/item/mmi/proc/become_occupied(var/new_icon)
|
||||
icon_state = new_icon
|
||||
if(radio)
|
||||
radio_action.ApplyIcon()
|
||||
|
||||
/obj/item/mmi/examine(mob/user)
|
||||
. = ..()
|
||||
if(radio)
|
||||
. += "<span class='notice'>A radio is installed on [src].</span>"
|
||||
|
||||
/obj/item/mmi/proc/install_radio()
|
||||
radio = new(src)
|
||||
radio.broadcasting = TRUE
|
||||
radio_action = new(radio, src)
|
||||
if(brainmob && brainmob.loc == src)
|
||||
radio_action.Grant(brainmob)
|
||||
|
||||
/obj/item/mmi/proc/uninstall_radio()
|
||||
QDEL_NULL(radio)
|
||||
QDEL_NULL(radio_action)
|
||||
|
||||
/datum/action/generic/configure_mmi_radio
|
||||
name = "Configure MMI Radio"
|
||||
desc = "Configure the radio installed in your MMI."
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
procname = "ui_interact"
|
||||
var/obj/item/mmi = null
|
||||
|
||||
/datum/action/generic/configure_mmi_radio/New(var/Target, var/obj/item/mmi/M)
|
||||
. = ..()
|
||||
mmi = M
|
||||
|
||||
/datum/action/generic/configure_mmi_radio/Destroy()
|
||||
mmi = null
|
||||
return ..()
|
||||
|
||||
/datum/action/generic/configure_mmi_radio/ApplyIcon(obj/screen/movable/action_button/current_button)
|
||||
// A copy/paste of the item action icon code
|
||||
current_button.overlays.Cut()
|
||||
if(target)
|
||||
var/obj/item/I = mmi
|
||||
var/old_layer = I.layer
|
||||
var/old_plane = I.plane
|
||||
I.layer = 21
|
||||
I.plane = HUD_PLANE
|
||||
current_button.overlays += I
|
||||
I.layer = old_layer
|
||||
I.plane = old_plane
|
||||
|
||||
/obj/item/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(0,10)
|
||||
..()
|
||||
|
||||
/obj/item/mmi/relaymove(var/mob/user, var/direction)
|
||||
if(user.stat || user.stunned)
|
||||
return
|
||||
var/obj/item/rig/rig = src.get_rig()
|
||||
if(rig)
|
||||
rig.forced_move(direction, user)
|
||||
|
||||
/obj/item/mmi/Destroy()
|
||||
if(isrobot(loc))
|
||||
var/mob/living/silicon/robot/borg = loc
|
||||
borg.mmi = null
|
||||
QDEL_NULL(brainmob)
|
||||
QDEL_NULL(held_brain)
|
||||
QDEL_NULL(radio)
|
||||
QDEL_NULL(radio_action)
|
||||
return ..()
|
||||
|
||||
// These two procs are important for when an MMI pilots a mech
|
||||
// (Brainmob "enters/leaves" the MMI when piloting)
|
||||
// Also neatly handles basically every case where a brain
|
||||
// is inserted or removed from an MMI
|
||||
/obj/item/mmi/Entered(atom/movable/A)
|
||||
if(radio && istype(A, /mob/living/carbon/brain))
|
||||
radio_action.Grant(A)
|
||||
|
||||
/obj/item/mmi/Exited(atom/movable/A)
|
||||
if(radio && istype(A, /mob/living/carbon/brain))
|
||||
radio_action.Remove(A)
|
||||
|
||||
/obj/item/mmi/syndie
|
||||
name = "Syndicate Man-Machine Interface"
|
||||
desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs created with it, but doesn't fit in Nanotrasen AI cores."
|
||||
origin_tech = "biotech=4;programming=4;syndicate=2"
|
||||
syndiemmi = 1
|
||||
|
||||
/obj/item/mmi/attempt_become_organ(obj/item/organ/external/parent,mob/living/carbon/human/H)
|
||||
if(!brainmob)
|
||||
return 0
|
||||
if(!parent)
|
||||
log_debug("Attempting to insert into a null parent!")
|
||||
return 0
|
||||
if(H.get_int_organ(/obj/item/organ/internal/brain))
|
||||
// one brain at a time
|
||||
return 0
|
||||
var/obj/item/organ/internal/brain/mmi_holder/holder = new()
|
||||
holder.parent_organ = parent.limb_name
|
||||
forceMove(holder)
|
||||
holder.stored_mmi = src
|
||||
holder.update_from_mmi()
|
||||
if(brainmob && brainmob.mind)
|
||||
brainmob.mind.transfer_to(H)
|
||||
holder.insert(H)
|
||||
|
||||
return 1
|
||||
|
||||
// As a synthetic, the only limit on visibility is view range
|
||||
/obj/item/mmi/contents_nano_distance(var/src_object, var/mob/living/user)
|
||||
if((src_object in view(src)) && get_dist(src_object, src) <= user.client.view)
|
||||
return STATUS_INTERACTIVE // interactive (green visibility)
|
||||
return user.shared_living_nano_distance(src_object)
|
||||
|
||||
// For now the only thing that is helped by this is radio access
|
||||
// Later a more intricate system for MMI UI interaction can be established
|
||||
/obj/item/mmi/contents_nano_interact(var/src_object, var/mob/living/user)
|
||||
if(!istype(user, /mob/living/carbon/brain))
|
||||
log_runtime(EXCEPTION("Somehow a non-brain mob is inside an MMI!"), user)
|
||||
return ..()
|
||||
var/mob/living/carbon/brain/BM = user
|
||||
if(BM.container == src && src_object == radio)
|
||||
return STATUS_INTERACTIVE
|
||||
return ..()
|
||||
/obj/item/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 = WEIGHT_CLASS_NORMAL
|
||||
origin_tech = "biotech=3"
|
||||
origin_tech = "biotech=2;programming=3;engineering=2"
|
||||
|
||||
//Revised. Brainmob is now contained directly within object of transfer. MMI in this case.
|
||||
var/alien = 0
|
||||
var/syndiemmi = 0 //Whether or not this is a Syndicate MMI
|
||||
var/mob/living/carbon/brain/brainmob = null//The current occupant.
|
||||
var/obj/item/organ/internal/brain/held_brain = null // This is so MMI's aren't brainscrubber 9000's
|
||||
var/mob/living/silicon/robot/robot = null//Appears unused.
|
||||
var/obj/mecha/mecha = null//This does not appear to be used outside of reference in mecha.dm.
|
||||
// I'm using this for mechs giving MMIs HUDs now
|
||||
|
||||
var/obj/item/radio/radio = null // For use with the radio MMI upgrade
|
||||
var/datum/action/generic/configure_mmi_radio/radio_action = null
|
||||
|
||||
// Used for cases when mmi or one of it's children commits suicide.
|
||||
// Needed to fix a rather insane bug when a posibrain/robotic brain commits suicide
|
||||
var/dead_icon = "mmi_dead"
|
||||
|
||||
/obj/item/mmi/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
|
||||
if(istype(O, /obj/item/organ/internal/brain/crystal))
|
||||
to_chat(user, "<span class='warning'> This brain is too malformed to be able to use with the [src].</span>")
|
||||
return
|
||||
if(istype(O, /obj/item/organ/internal/brain/golem))
|
||||
to_chat(user, "<span class='warning'>You can't find a way to plug [O] into [src].</span>")
|
||||
return
|
||||
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.brainmob)
|
||||
to_chat(user, "<span class='warning'>You aren't sure where this brain came from, but you're pretty sure it's a useless brain.</span>")
|
||||
return
|
||||
if(held_brain)
|
||||
to_chat(user, "<span class='userdanger'>Somehow, this MMI still has a brain in it. Report this to the bug tracker.</span>")
|
||||
log_runtime(EXCEPTION("[user] tried to stick a [O] into [src] in [get_area(src)], but the held brain variable wasn't cleared"), src)
|
||||
return
|
||||
if(user.drop_item())
|
||||
B.forceMove(src)
|
||||
visible_message("<span class='notice'>[user] sticks \a [O] into \the [src].</span>")
|
||||
brainmob = B.brainmob
|
||||
B.brainmob = null
|
||||
brainmob.forceMove(src)
|
||||
brainmob.container = src
|
||||
brainmob.stat = CONSCIOUS
|
||||
GLOB.respawnable_list -= brainmob
|
||||
GLOB.dead_mob_list -= brainmob//Update dem lists
|
||||
GLOB.living_mob_list += brainmob
|
||||
|
||||
held_brain = B
|
||||
if(istype(O,/obj/item/organ/internal/brain/xeno)) // kept the type check, as it still does other weird stuff
|
||||
name = "Man-Machine Interface: Alien - [brainmob.real_name]"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
become_occupied("AlienMMI")
|
||||
alien = 1
|
||||
else
|
||||
name = "Man-Machine Interface: [brainmob.real_name]"
|
||||
icon = B.mmi_icon
|
||||
become_occupied("[B.mmi_icon_state]")
|
||||
alien = 0
|
||||
|
||||
if(radio_action)
|
||||
radio_action.UpdateButtonIcon()
|
||||
feedback_inc("cyborg_mmis_filled",1)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't drop [B]!</span>")
|
||||
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/mmi_radio_upgrade))
|
||||
if(radio)
|
||||
to_chat(user, "<span class='warning'>[src] already has a radio installed.</span>")
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] begins to install the [O] into [src]...</span>", \
|
||||
"<span class='notice'>You start to install the [O] into [src]...</span>")
|
||||
if(do_after(user, 20, target=src))
|
||||
if(user.drop_item())
|
||||
user.visible_message("<span class='notice'>[user] installs [O] in [src].</span>", \
|
||||
"<span class='notice'>You install [O] in [src].</span>")
|
||||
if(brainmob)
|
||||
to_chat(brainmob, "<span class='notice'>MMI radio capability installed.</span>")
|
||||
install_radio()
|
||||
qdel(O)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't drop [O]!</span>")
|
||||
return
|
||||
|
||||
// Maybe later add encryption key support, but that's a pain in the neck atm
|
||||
|
||||
if(brainmob)
|
||||
O.attack(brainmob, user)//Oh noooeeeee
|
||||
// Brainmobs can take damage, but they can't actually die. Maybe should fix.
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/mmi/screwdriver_act(mob/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(!I.tool_use_check(user, 0))
|
||||
return
|
||||
if(!radio)
|
||||
to_chat(user, "<span class='warning'>There is no radio in [src]!</span>")
|
||||
return
|
||||
user.visible_message("<span class='warning'>[user] begins to uninstall the radio from [src]...</span>", \
|
||||
"<span class='notice'>You start to uninstall the radio from [src]...</span>")
|
||||
if(!I.use_tool(src, user, 40, volume = I.tool_volume) || !radio)
|
||||
return
|
||||
uninstall_radio()
|
||||
new /obj/item/mmi_radio_upgrade(get_turf(src))
|
||||
user.visible_message("<span class='warning'>[user] uninstalls the radio from [src].</span>", \
|
||||
"<span class='notice'>You uninstall the radio from [src].</span>")
|
||||
|
||||
|
||||
/obj/item/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
|
||||
to_chat(user, "<span class='notice'>You unlock and upend the MMI, spilling the brain onto the floor.</span>")
|
||||
dropbrain(get_turf(user))
|
||||
icon = 'icons/obj/assemblies.dmi'
|
||||
icon_state = "mmi_empty"
|
||||
name = "Man-Machine Interface"
|
||||
|
||||
/obj/item/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.Clone()
|
||||
brainmob.container = src
|
||||
|
||||
if(!istype(H.dna.species) || isnull(H.dna.species.return_organ("brain"))) // Diona/buggy people
|
||||
held_brain = new(src)
|
||||
else // We have a species, and it has a brain
|
||||
var/brain_path = H.dna.species.return_organ("brain")
|
||||
if(!ispath(brain_path, /obj/item/organ/internal/brain))
|
||||
brain_path = /obj/item/organ/internal/brain
|
||||
held_brain = new brain_path(src) // Slime people will keep their slimy brains this way
|
||||
held_brain.dna = brainmob.dna.Clone()
|
||||
held_brain.name = "\the [brainmob.name]'s [initial(held_brain.name)]"
|
||||
|
||||
name = "Man-Machine Interface: [brainmob.real_name]"
|
||||
become_occupied("mmi_full")
|
||||
|
||||
//I made this proc as a way to have a brainmob be transferred to any created brain, and to solve the
|
||||
//problem i was having with alien/nonalien brain drops.
|
||||
/obj/item/mmi/proc/dropbrain(var/turf/dropspot)
|
||||
if(isnull(held_brain))
|
||||
log_runtime(EXCEPTION("[src] at [loc] attempted to drop brain without a contained brain in [get_area(src)]."), src)
|
||||
to_chat(brainmob, "<span class='userdanger'>Your MMI did not contain a brain! We'll make a new one for you, but you'd best report this to the bugtracker!</span>")
|
||||
held_brain = new(dropspot) // Let's not ruin someone's round because of something dumb -- Crazylemon
|
||||
held_brain.dna = brainmob.dna.Clone()
|
||||
held_brain.name = "\the [brainmob.name]'s [initial(held_brain.name)]"
|
||||
|
||||
brainmob.container = null//Reset brainmob mmi var.
|
||||
brainmob.forceMove(held_brain) //Throw mob into brain.
|
||||
GLOB.respawnable_list += brainmob
|
||||
GLOB.living_mob_list -= brainmob//Get outta here
|
||||
held_brain.brainmob = brainmob//Set the brain to use the brainmob
|
||||
held_brain.brainmob.cancel_camera()
|
||||
brainmob = null//Set mmi brainmob var to null
|
||||
held_brain.forceMove(dropspot)
|
||||
held_brain = null
|
||||
|
||||
/obj/item/mmi/proc/become_occupied(var/new_icon)
|
||||
icon_state = new_icon
|
||||
if(radio)
|
||||
radio_action.ApplyIcon()
|
||||
|
||||
/obj/item/mmi/examine(mob/user)
|
||||
. = ..()
|
||||
if(radio)
|
||||
. += "<span class='notice'>A radio is installed on [src].</span>"
|
||||
|
||||
/obj/item/mmi/proc/install_radio()
|
||||
radio = new(src)
|
||||
radio.broadcasting = TRUE
|
||||
radio_action = new(radio, src)
|
||||
if(brainmob && brainmob.loc == src)
|
||||
radio_action.Grant(brainmob)
|
||||
|
||||
/obj/item/mmi/proc/uninstall_radio()
|
||||
QDEL_NULL(radio)
|
||||
QDEL_NULL(radio_action)
|
||||
|
||||
/datum/action/generic/configure_mmi_radio
|
||||
name = "Configure MMI Radio"
|
||||
desc = "Configure the radio installed in your MMI."
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
procname = "ui_interact"
|
||||
var/obj/item/mmi = null
|
||||
|
||||
/datum/action/generic/configure_mmi_radio/New(var/Target, var/obj/item/mmi/M)
|
||||
. = ..()
|
||||
mmi = M
|
||||
|
||||
/datum/action/generic/configure_mmi_radio/Destroy()
|
||||
mmi = null
|
||||
return ..()
|
||||
|
||||
/datum/action/generic/configure_mmi_radio/ApplyIcon(obj/screen/movable/action_button/current_button)
|
||||
// A copy/paste of the item action icon code
|
||||
current_button.overlays.Cut()
|
||||
if(target)
|
||||
var/obj/item/I = mmi
|
||||
var/old_layer = I.layer
|
||||
var/old_plane = I.plane
|
||||
I.layer = 21
|
||||
I.plane = HUD_PLANE
|
||||
current_button.overlays += I
|
||||
I.layer = old_layer
|
||||
I.plane = old_plane
|
||||
|
||||
/obj/item/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(0,10)
|
||||
..()
|
||||
|
||||
/obj/item/mmi/relaymove(var/mob/user, var/direction)
|
||||
if(user.stat || user.stunned)
|
||||
return
|
||||
var/obj/item/rig/rig = src.get_rig()
|
||||
if(rig)
|
||||
rig.forced_move(direction, user)
|
||||
|
||||
/obj/item/mmi/Destroy()
|
||||
if(isrobot(loc))
|
||||
var/mob/living/silicon/robot/borg = loc
|
||||
borg.mmi = null
|
||||
QDEL_NULL(brainmob)
|
||||
QDEL_NULL(held_brain)
|
||||
QDEL_NULL(radio)
|
||||
QDEL_NULL(radio_action)
|
||||
return ..()
|
||||
|
||||
// These two procs are important for when an MMI pilots a mech
|
||||
// (Brainmob "enters/leaves" the MMI when piloting)
|
||||
// Also neatly handles basically every case where a brain
|
||||
// is inserted or removed from an MMI
|
||||
/obj/item/mmi/Entered(atom/movable/A)
|
||||
if(radio && istype(A, /mob/living/carbon/brain))
|
||||
radio_action.Grant(A)
|
||||
|
||||
/obj/item/mmi/Exited(atom/movable/A)
|
||||
if(radio && istype(A, /mob/living/carbon/brain))
|
||||
radio_action.Remove(A)
|
||||
|
||||
/obj/item/mmi/syndie
|
||||
name = "Syndicate Man-Machine Interface"
|
||||
desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs created with it, but doesn't fit in Nanotrasen AI cores."
|
||||
origin_tech = "biotech=4;programming=4;syndicate=2"
|
||||
syndiemmi = 1
|
||||
|
||||
/obj/item/mmi/attempt_become_organ(obj/item/organ/external/parent,mob/living/carbon/human/H)
|
||||
if(!brainmob)
|
||||
return 0
|
||||
if(!parent)
|
||||
log_debug("Attempting to insert into a null parent!")
|
||||
return 0
|
||||
if(H.get_int_organ(/obj/item/organ/internal/brain))
|
||||
// one brain at a time
|
||||
return 0
|
||||
var/obj/item/organ/internal/brain/mmi_holder/holder = new()
|
||||
holder.parent_organ = parent.limb_name
|
||||
forceMove(holder)
|
||||
holder.stored_mmi = src
|
||||
holder.update_from_mmi()
|
||||
if(brainmob && brainmob.mind)
|
||||
brainmob.mind.transfer_to(H)
|
||||
holder.insert(H)
|
||||
|
||||
return 1
|
||||
|
||||
// As a synthetic, the only limit on visibility is view range
|
||||
/obj/item/mmi/contents_nano_distance(var/src_object, var/mob/living/user)
|
||||
if((src_object in view(src)) && get_dist(src_object, src) <= user.client.view)
|
||||
return STATUS_INTERACTIVE // interactive (green visibility)
|
||||
return user.shared_living_nano_distance(src_object)
|
||||
|
||||
// For now the only thing that is helped by this is radio access
|
||||
// Later a more intricate system for MMI UI interaction can be established
|
||||
/obj/item/mmi/contents_nano_interact(var/src_object, var/mob/living/user)
|
||||
if(!istype(user, /mob/living/carbon/brain))
|
||||
log_runtime(EXCEPTION("Somehow a non-brain mob is inside an MMI!"), user)
|
||||
return ..()
|
||||
var/mob/living/carbon/brain/BM = user
|
||||
if(BM.container == src && src_object == radio)
|
||||
return STATUS_INTERACTIVE
|
||||
return ..()
|
||||
|
||||
@@ -1,111 +1,111 @@
|
||||
/mob/living/carbon/brain
|
||||
var/obj/item/container = null
|
||||
var/timeofhostdeath = 0
|
||||
var/emp_damage = 0//Handles a type of MMI damage
|
||||
use_me = 0 //Can't use the me verb, it's a freaking immobile brain
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "brain1"
|
||||
|
||||
/mob/living/carbon/brain/New()
|
||||
create_reagents(330)
|
||||
add_language("Galactic Common")
|
||||
..()
|
||||
|
||||
/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(other)//Goddamn is this hackish, but this say code is so odd
|
||||
if(istype(other, /mob/living/silicon/ai))
|
||||
if(!(container && istype(container, /obj/item/mmi)))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
if(istype(other, /mob/living/silicon/decoy))
|
||||
if(!(container && istype(container, /obj/item/mmi)))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
if(istype(other, /mob/living/silicon/pai))
|
||||
if(!(container && istype(container, /obj/item/mmi)))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
if(istype(other, /mob/living/silicon/robot))
|
||||
if(!(container && istype(container, /obj/item/mmi)))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
if(istype(other, /mob/living/carbon/human))
|
||||
return 1
|
||||
if(istype(other, /mob/living/simple_animal/slime))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
|
||||
/mob/living/carbon/brain/update_canmove(delay_action_updates = 0)
|
||||
if(in_contents_of(/obj/mecha))
|
||||
canmove = 1
|
||||
use_me = 1 //If it can move, let it emote
|
||||
else if(istype(loc, /obj/item/mmi))
|
||||
canmove = 1 //mmi won't move anyways so whatever
|
||||
else
|
||||
canmove = 0
|
||||
|
||||
if(!delay_action_updates)
|
||||
update_action_buttons_icon()
|
||||
return canmove
|
||||
|
||||
/mob/living/carbon/brain/ex_act() //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up.
|
||||
return
|
||||
|
||||
/mob/living/carbon/brain/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
/mob/living/carbon/brain/on_forcemove(atom/newloc)
|
||||
if(container)
|
||||
container.forceMove(newloc)
|
||||
else //something went very wrong.
|
||||
CRASH("Brainmob without container.")
|
||||
forceMove(container)
|
||||
|
||||
/*
|
||||
This will return true if the brain has a container that leaves it less helpless than a naked brain
|
||||
|
||||
I'm using this for Stat to give it a more nifty interface to work with
|
||||
*/
|
||||
/mob/living/carbon/brain/proc/has_synthetic_assistance()
|
||||
return (container && istype(container, /obj/item/mmi)) || in_contents_of(/obj/mecha)
|
||||
|
||||
/mob/living/carbon/brain/proc/get_race()
|
||||
if(container)
|
||||
var/obj/item/mmi/M = container
|
||||
if(istype(M) && M.held_brain)
|
||||
return M.held_brain.dna.species.name
|
||||
else
|
||||
return "Artificial Life"
|
||||
if(istype(loc, /obj/item/organ/internal/brain))
|
||||
var/obj/item/organ/internal/brain/B = loc
|
||||
return B.dna.species.name
|
||||
|
||||
/mob/living/carbon/brain/Stat()
|
||||
..()
|
||||
if(has_synthetic_assistance())
|
||||
statpanel("Status")
|
||||
show_stat_emergency_shuttle_eta()
|
||||
|
||||
if(client.statpanel == "Status")
|
||||
//Knowing how well-off your mech is doing is really important as an MMI
|
||||
if(istype(src.loc, /obj/mecha))
|
||||
var/obj/mecha/M = src.loc
|
||||
stat("Exosuit Charge:", "[istype(M.cell) ? "[M.cell.charge] / [M.cell.maxcharge]" : "No cell detected"]")
|
||||
stat("Exosuit Integrity", "[!M.obj_integrity ? "0" : "[(M.obj_integrity / M.max_integrity) * 100]"]%")
|
||||
|
||||
/mob/living/carbon/brain/can_safely_leave_loc()
|
||||
return 0 //You're not supposed to be ethereal jaunting, brains
|
||||
|
||||
/mob/living/carbon/brain/can_hear()
|
||||
. = TRUE
|
||||
/mob/living/carbon/brain
|
||||
var/obj/item/container = null
|
||||
var/timeofhostdeath = 0
|
||||
var/emp_damage = 0//Handles a type of MMI damage
|
||||
use_me = 0 //Can't use the me verb, it's a freaking immobile brain
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "brain1"
|
||||
|
||||
/mob/living/carbon/brain/New()
|
||||
create_reagents(330)
|
||||
add_language("Galactic Common")
|
||||
..()
|
||||
|
||||
/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(other)//Goddamn is this hackish, but this say code is so odd
|
||||
if(istype(other, /mob/living/silicon/ai))
|
||||
if(!(container && istype(container, /obj/item/mmi)))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
if(istype(other, /mob/living/silicon/decoy))
|
||||
if(!(container && istype(container, /obj/item/mmi)))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
if(istype(other, /mob/living/silicon/pai))
|
||||
if(!(container && istype(container, /obj/item/mmi)))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
if(istype(other, /mob/living/silicon/robot))
|
||||
if(!(container && istype(container, /obj/item/mmi)))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
if(istype(other, /mob/living/carbon/human))
|
||||
return 1
|
||||
if(istype(other, /mob/living/simple_animal/slime))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
|
||||
/mob/living/carbon/brain/update_canmove(delay_action_updates = 0)
|
||||
if(in_contents_of(/obj/mecha))
|
||||
canmove = 1
|
||||
use_me = 1 //If it can move, let it emote
|
||||
else if(istype(loc, /obj/item/mmi))
|
||||
canmove = 1 //mmi won't move anyways so whatever
|
||||
else
|
||||
canmove = 0
|
||||
|
||||
if(!delay_action_updates)
|
||||
update_action_buttons_icon()
|
||||
return canmove
|
||||
|
||||
/mob/living/carbon/brain/ex_act() //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up.
|
||||
return
|
||||
|
||||
/mob/living/carbon/brain/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
/mob/living/carbon/brain/on_forcemove(atom/newloc)
|
||||
if(container)
|
||||
container.forceMove(newloc)
|
||||
else //something went very wrong.
|
||||
CRASH("Brainmob without container.")
|
||||
forceMove(container)
|
||||
|
||||
/*
|
||||
This will return true if the brain has a container that leaves it less helpless than a naked brain
|
||||
|
||||
I'm using this for Stat to give it a more nifty interface to work with
|
||||
*/
|
||||
/mob/living/carbon/brain/proc/has_synthetic_assistance()
|
||||
return (container && istype(container, /obj/item/mmi)) || in_contents_of(/obj/mecha)
|
||||
|
||||
/mob/living/carbon/brain/proc/get_race()
|
||||
if(container)
|
||||
var/obj/item/mmi/M = container
|
||||
if(istype(M) && M.held_brain)
|
||||
return M.held_brain.dna.species.name
|
||||
else
|
||||
return "Artificial Life"
|
||||
if(istype(loc, /obj/item/organ/internal/brain))
|
||||
var/obj/item/organ/internal/brain/B = loc
|
||||
return B.dna.species.name
|
||||
|
||||
/mob/living/carbon/brain/Stat()
|
||||
..()
|
||||
if(has_synthetic_assistance())
|
||||
statpanel("Status")
|
||||
show_stat_emergency_shuttle_eta()
|
||||
|
||||
if(client.statpanel == "Status")
|
||||
//Knowing how well-off your mech is doing is really important as an MMI
|
||||
if(istype(src.loc, /obj/mecha))
|
||||
var/obj/mecha/M = src.loc
|
||||
stat("Exosuit Charge:", "[istype(M.cell) ? "[M.cell.charge] / [M.cell.maxcharge]" : "No cell detected"]")
|
||||
stat("Exosuit Integrity", "[!M.obj_integrity ? "0" : "[(M.obj_integrity / M.max_integrity) * 100]"]%")
|
||||
|
||||
/mob/living/carbon/brain/can_safely_leave_loc()
|
||||
return 0 //You're not supposed to be ethereal jaunting, brains
|
||||
|
||||
/mob/living/carbon/brain/can_hear()
|
||||
. = TRUE
|
||||
|
||||
@@ -1,141 +1,141 @@
|
||||
/obj/item/organ/internal/brain
|
||||
name = "brain"
|
||||
max_damage = 120
|
||||
icon_state = "brain2"
|
||||
force = 1.0
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throwforce = 1.0
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
origin_tech = "biotech=5"
|
||||
attack_verb = list("attacked", "slapped", "whacked")
|
||||
var/mob/living/carbon/brain/brainmob = null
|
||||
organ_tag = "brain"
|
||||
parent_organ = "head"
|
||||
slot = "brain"
|
||||
vital = TRUE
|
||||
hidden_pain = TRUE //the brain has no pain receptors, and brain damage is meant to be a stealthy damage type.
|
||||
var/mmi_icon = 'icons/obj/assemblies.dmi'
|
||||
var/mmi_icon_state = "mmi_full"
|
||||
|
||||
/obj/item/organ/internal/brain/xeno
|
||||
name = "xenomorph brain"
|
||||
desc = "We barely understand the brains of terrestial animals. Who knows what we may find in the brain of such an advanced species?"
|
||||
icon_state = "brain-x"
|
||||
origin_tech = "biotech=6"
|
||||
mmi_icon = 'icons/mob/alien.dmi'
|
||||
mmi_icon_state = "AlienMMI"
|
||||
|
||||
/obj/item/organ/internal/brain/New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(brainmob && brainmob.client)
|
||||
brainmob.client.screen.len = null //clear the hud
|
||||
|
||||
/obj/item/organ/internal/brain/proc/transfer_identity(var/mob/living/carbon/H)
|
||||
brainmob = new(src)
|
||||
if(isnull(dna)) // someone didn't set this right...
|
||||
log_runtime(EXCEPTION("[src] at [loc] did not contain a dna datum at time of removal."), src)
|
||||
dna = H.dna.Clone()
|
||||
name = "\the [dna.real_name]'s [initial(src.name)]"
|
||||
brainmob.dna = dna.Clone() // Silly baycode, what you do
|
||||
// brainmob.dna = H.dna.Clone() Putting in and taking out a brain doesn't make it a carbon copy of the original brain of the body you put it in
|
||||
brainmob.name = dna.real_name
|
||||
brainmob.real_name = dna.real_name
|
||||
brainmob.timeofhostdeath = H.timeofdeath
|
||||
if(H.mind)
|
||||
H.mind.transfer_to(brainmob)
|
||||
|
||||
to_chat(brainmob, "<span class='notice'>You feel slightly disoriented. That's normal when you're just a [initial(src.name)].</span>")
|
||||
|
||||
/obj/item/organ/internal/brain/examine(mob/user) // -- TLE
|
||||
. = ..()
|
||||
if(brainmob && brainmob.client)//if thar be a brain inside... the brain.
|
||||
. += "You can feel the small spark of life still left in this one."
|
||||
else
|
||||
. += "This one seems particularly lifeless. Perhaps it will regain some of its luster later.."
|
||||
|
||||
/obj/item/organ/internal/brain/remove(var/mob/living/user,special = 0)
|
||||
if(dna)
|
||||
name = "[dna.real_name]'s [initial(name)]"
|
||||
|
||||
if(!owner) return ..() // Probably a redundant removal; just bail
|
||||
|
||||
var/obj/item/organ/internal/brain/B = src
|
||||
if(!special)
|
||||
var/mob/living/simple_animal/borer/borer = owner.has_brain_worms()
|
||||
if(borer)
|
||||
borer.leave_host() //Should remove borer if the brain is removed - RR
|
||||
|
||||
if(owner.mind && !non_primary)//don't transfer if the owner does not have a mind.
|
||||
B.transfer_identity(user)
|
||||
|
||||
if(istype(owner,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.update_hair(1)
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/brain/insert(var/mob/living/target,special = 0)
|
||||
|
||||
name = "[initial(name)]"
|
||||
var/brain_already_exists = 0
|
||||
if(istype(target,/mob/living/carbon/human)) // No more IPC multibrain shenanigans
|
||||
if(target.get_int_organ(/obj/item/organ/internal/brain))
|
||||
brain_already_exists = 1
|
||||
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.update_hair(1)
|
||||
|
||||
if(!brain_already_exists)
|
||||
if(brainmob)
|
||||
if(target.key)
|
||||
target.ghostize()
|
||||
if(brainmob.mind)
|
||||
brainmob.mind.transfer_to(target)
|
||||
else
|
||||
target.key = brainmob.key
|
||||
else
|
||||
log_debug("Multibrain shenanigans at ([target.x],[target.y],[target.z]), mob '[target]'")
|
||||
..(target, special = special)
|
||||
|
||||
/obj/item/organ/internal/brain/receive_damage(amount, silent = 0) //brains are special; if they receive damage by other means, we really just want the damage to be passed ot the owner and back onto the brain.
|
||||
if(owner)
|
||||
owner.adjustBrainLoss(amount)
|
||||
|
||||
/obj/item/organ/internal/brain/necrotize(update_sprite = TRUE) //Brain also has special handling for when it necrotizes
|
||||
damage = max_damage
|
||||
status |= ORGAN_DEAD
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(dead_icon && !is_robotic())
|
||||
icon_state = dead_icon
|
||||
if(owner && vital)
|
||||
owner.setBrainLoss(120)
|
||||
|
||||
/obj/item/organ/internal/brain/prepare_eat()
|
||||
return // Too important to eat.
|
||||
|
||||
/obj/item/organ/internal/brain/slime
|
||||
name = "slime core"
|
||||
desc = "A complex, organic knot of jelly and crystalline particles."
|
||||
icon = 'icons/mob/slimes.dmi'
|
||||
icon_state = "green slime extract"
|
||||
mmi_icon_state = "slime_mmi"
|
||||
// parent_organ = "chest" Hello I am from the ministry of rubber forehead aliens how are you
|
||||
|
||||
/obj/item/organ/internal/brain/golem
|
||||
name = "Runic mind"
|
||||
desc = "A tightly furled roll of paper, covered with indecipherable runes."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "scroll"
|
||||
|
||||
/obj/item/organ/internal/brain/Destroy() //copypasted from MMIs.
|
||||
QDEL_NULL(brainmob)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/internal/brain/cluwne
|
||||
|
||||
/obj/item/organ/internal/brain/cluwne/insert(mob/living/target, special = 0, make_cluwne = 1)
|
||||
..(target, special = special)
|
||||
if(ishuman(target) && make_cluwne)
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.makeCluwne() //No matter where you go, no matter what you do, you cannot escape
|
||||
/obj/item/organ/internal/brain
|
||||
name = "brain"
|
||||
max_damage = 120
|
||||
icon_state = "brain2"
|
||||
force = 1.0
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throwforce = 1.0
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
origin_tech = "biotech=5"
|
||||
attack_verb = list("attacked", "slapped", "whacked")
|
||||
var/mob/living/carbon/brain/brainmob = null
|
||||
organ_tag = "brain"
|
||||
parent_organ = "head"
|
||||
slot = "brain"
|
||||
vital = TRUE
|
||||
hidden_pain = TRUE //the brain has no pain receptors, and brain damage is meant to be a stealthy damage type.
|
||||
var/mmi_icon = 'icons/obj/assemblies.dmi'
|
||||
var/mmi_icon_state = "mmi_full"
|
||||
|
||||
/obj/item/organ/internal/brain/xeno
|
||||
name = "xenomorph brain"
|
||||
desc = "We barely understand the brains of terrestial animals. Who knows what we may find in the brain of such an advanced species?"
|
||||
icon_state = "brain-x"
|
||||
origin_tech = "biotech=6"
|
||||
mmi_icon = 'icons/mob/alien.dmi'
|
||||
mmi_icon_state = "AlienMMI"
|
||||
|
||||
/obj/item/organ/internal/brain/New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(brainmob && brainmob.client)
|
||||
brainmob.client.screen.len = null //clear the hud
|
||||
|
||||
/obj/item/organ/internal/brain/proc/transfer_identity(var/mob/living/carbon/H)
|
||||
brainmob = new(src)
|
||||
if(isnull(dna)) // someone didn't set this right...
|
||||
log_runtime(EXCEPTION("[src] at [loc] did not contain a dna datum at time of removal."), src)
|
||||
dna = H.dna.Clone()
|
||||
name = "\the [dna.real_name]'s [initial(src.name)]"
|
||||
brainmob.dna = dna.Clone() // Silly baycode, what you do
|
||||
// brainmob.dna = H.dna.Clone() Putting in and taking out a brain doesn't make it a carbon copy of the original brain of the body you put it in
|
||||
brainmob.name = dna.real_name
|
||||
brainmob.real_name = dna.real_name
|
||||
brainmob.timeofhostdeath = H.timeofdeath
|
||||
if(H.mind)
|
||||
H.mind.transfer_to(brainmob)
|
||||
|
||||
to_chat(brainmob, "<span class='notice'>You feel slightly disoriented. That's normal when you're just a [initial(src.name)].</span>")
|
||||
|
||||
/obj/item/organ/internal/brain/examine(mob/user) // -- TLE
|
||||
. = ..()
|
||||
if(brainmob && brainmob.client)//if thar be a brain inside... the brain.
|
||||
. += "You can feel the small spark of life still left in this one."
|
||||
else
|
||||
. += "This one seems particularly lifeless. Perhaps it will regain some of its luster later.."
|
||||
|
||||
/obj/item/organ/internal/brain/remove(var/mob/living/user,special = 0)
|
||||
if(dna)
|
||||
name = "[dna.real_name]'s [initial(name)]"
|
||||
|
||||
if(!owner) return ..() // Probably a redundant removal; just bail
|
||||
|
||||
var/obj/item/organ/internal/brain/B = src
|
||||
if(!special)
|
||||
var/mob/living/simple_animal/borer/borer = owner.has_brain_worms()
|
||||
if(borer)
|
||||
borer.leave_host() //Should remove borer if the brain is removed - RR
|
||||
|
||||
if(owner.mind && !non_primary)//don't transfer if the owner does not have a mind.
|
||||
B.transfer_identity(user)
|
||||
|
||||
if(istype(owner,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.update_hair(1)
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/brain/insert(var/mob/living/target,special = 0)
|
||||
|
||||
name = "[initial(name)]"
|
||||
var/brain_already_exists = 0
|
||||
if(istype(target,/mob/living/carbon/human)) // No more IPC multibrain shenanigans
|
||||
if(target.get_int_organ(/obj/item/organ/internal/brain))
|
||||
brain_already_exists = 1
|
||||
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.update_hair(1)
|
||||
|
||||
if(!brain_already_exists)
|
||||
if(brainmob)
|
||||
if(target.key)
|
||||
target.ghostize()
|
||||
if(brainmob.mind)
|
||||
brainmob.mind.transfer_to(target)
|
||||
else
|
||||
target.key = brainmob.key
|
||||
else
|
||||
log_debug("Multibrain shenanigans at ([target.x],[target.y],[target.z]), mob '[target]'")
|
||||
..(target, special = special)
|
||||
|
||||
/obj/item/organ/internal/brain/receive_damage(amount, silent = 0) //brains are special; if they receive damage by other means, we really just want the damage to be passed ot the owner and back onto the brain.
|
||||
if(owner)
|
||||
owner.adjustBrainLoss(amount)
|
||||
|
||||
/obj/item/organ/internal/brain/necrotize(update_sprite = TRUE) //Brain also has special handling for when it necrotizes
|
||||
damage = max_damage
|
||||
status |= ORGAN_DEAD
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(dead_icon && !is_robotic())
|
||||
icon_state = dead_icon
|
||||
if(owner && vital)
|
||||
owner.setBrainLoss(120)
|
||||
|
||||
/obj/item/organ/internal/brain/prepare_eat()
|
||||
return // Too important to eat.
|
||||
|
||||
/obj/item/organ/internal/brain/slime
|
||||
name = "slime core"
|
||||
desc = "A complex, organic knot of jelly and crystalline particles."
|
||||
icon = 'icons/mob/slimes.dmi'
|
||||
icon_state = "green slime extract"
|
||||
mmi_icon_state = "slime_mmi"
|
||||
// parent_organ = "chest" Hello I am from the ministry of rubber forehead aliens how are you
|
||||
|
||||
/obj/item/organ/internal/brain/golem
|
||||
name = "Runic mind"
|
||||
desc = "A tightly furled roll of paper, covered with indecipherable runes."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "scroll"
|
||||
|
||||
/obj/item/organ/internal/brain/Destroy() //copypasted from MMIs.
|
||||
QDEL_NULL(brainmob)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/internal/brain/cluwne
|
||||
|
||||
/obj/item/organ/internal/brain/cluwne/insert(mob/living/target, special = 0, make_cluwne = 1)
|
||||
..(target, special = special)
|
||||
if(ishuman(target) && make_cluwne)
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.makeCluwne() //No matter where you go, no matter what you do, you cannot escape
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
/mob/living/carbon/brain/death(gibbed)
|
||||
// Only execute the below if we successfully died
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!gibbed && container && istype(container, /obj/item/mmi))//If not gibbed but in a container.
|
||||
var/obj/item/mmi/mmi = container
|
||||
visible_message("<span class='danger'>[src]'s MMI flatlines!</span>", "<span class='warning'>You hear something flatline.</span>")
|
||||
mmi.icon_state = mmi.dead_icon
|
||||
|
||||
/mob/living/carbon/brain/gib()
|
||||
// can we muster a parent call here?
|
||||
if(!death(TRUE) && stat != DEAD)
|
||||
return FALSE
|
||||
notransform = 1
|
||||
canmove = 0
|
||||
icon = null
|
||||
invisibility = 101
|
||||
|
||||
gibs(loc, dna)
|
||||
|
||||
if(container && istype(container, /obj/item/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
|
||||
QDEL_IN(src, 0)
|
||||
/mob/living/carbon/brain/death(gibbed)
|
||||
// Only execute the below if we successfully died
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!gibbed && container && istype(container, /obj/item/mmi))//If not gibbed but in a container.
|
||||
var/obj/item/mmi/mmi = container
|
||||
visible_message("<span class='danger'>[src]'s MMI flatlines!</span>", "<span class='warning'>You hear something flatline.</span>")
|
||||
mmi.icon_state = mmi.dead_icon
|
||||
|
||||
/mob/living/carbon/brain/gib()
|
||||
// can we muster a parent call here?
|
||||
if(!death(TRUE) && stat != DEAD)
|
||||
return FALSE
|
||||
notransform = 1
|
||||
canmove = 0
|
||||
icon = null
|
||||
invisibility = 101
|
||||
|
||||
gibs(loc, dna)
|
||||
|
||||
if(container && istype(container, /obj/item/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
|
||||
QDEL_IN(src, 0)
|
||||
|
||||
@@ -48,4 +48,4 @@
|
||||
to_chat(src, "alarm, alert, notice, flash,blink, whistle, beep, boop")
|
||||
|
||||
if(message && !stat)
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
/mob/living/carbon/brain/handle_mutations_and_radiation()
|
||||
if(radiation)
|
||||
if(radiation > 100)
|
||||
if(!container)
|
||||
to_chat(src, "<span class='danger'>You feel weak.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='danger'>STATUS: CRITICAL AMOUNTS OF RADIATION DETECTED.</span>")
|
||||
|
||||
switch(radiation)
|
||||
|
||||
if(50 to 75)
|
||||
if(prob(5))
|
||||
if(!container)
|
||||
to_chat(src, "<span class='danger'>You feel weak.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='danger'>STATUS: DANGEROUS AMOUNTS OF RADIATION DETECTED.</span>")
|
||||
..()
|
||||
|
||||
/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(20.0*discomfort)
|
||||
|
||||
else
|
||||
var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0)
|
||||
adjustFireLoss(5.0*discomfort)
|
||||
|
||||
/mob/living/carbon/brain/handle_regular_status_updates()
|
||||
. = ..()
|
||||
|
||||
if(.)
|
||||
if(!container && (health < HEALTH_THRESHOLD_DEAD && check_death_method() || ((world.time - timeofhostdeath) > config.revival_brain_life)))
|
||||
death()
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/brain/breathe()
|
||||
return
|
||||
/mob/living/carbon/brain/handle_mutations_and_radiation()
|
||||
if(radiation)
|
||||
if(radiation > 100)
|
||||
if(!container)
|
||||
to_chat(src, "<span class='danger'>You feel weak.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='danger'>STATUS: CRITICAL AMOUNTS OF RADIATION DETECTED.</span>")
|
||||
|
||||
switch(radiation)
|
||||
|
||||
if(50 to 75)
|
||||
if(prob(5))
|
||||
if(!container)
|
||||
to_chat(src, "<span class='danger'>You feel weak.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='danger'>STATUS: DANGEROUS AMOUNTS OF RADIATION DETECTED.</span>")
|
||||
..()
|
||||
|
||||
/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(20.0*discomfort)
|
||||
|
||||
else
|
||||
var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0)
|
||||
adjustFireLoss(5.0*discomfort)
|
||||
|
||||
/mob/living/carbon/brain/handle_regular_status_updates()
|
||||
. = ..()
|
||||
|
||||
if(.)
|
||||
if(!container && (health < HEALTH_THRESHOLD_DEAD && check_death_method() || ((world.time - timeofhostdeath) > config.revival_brain_life)))
|
||||
death()
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/brain/breathe()
|
||||
return
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
/mob/living/carbon/brain/Login()
|
||||
..()
|
||||
SetSleeping(0)
|
||||
/mob/living/carbon/brain/Login()
|
||||
..()
|
||||
SetSleeping(0)
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
//TODO: Convert this over for languages.
|
||||
/mob/living/carbon/brain/say(var/message, var/datum/language/speaking = null)
|
||||
if(!can_speak(warning = TRUE))
|
||||
return
|
||||
|
||||
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
|
||||
|
||||
..(message)
|
||||
|
||||
/mob/living/carbon/brain/whisper(message as text)
|
||||
if(!can_speak(warning = TRUE))
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/carbon/brain/can_speak(var/warning = FALSE)
|
||||
. = ..()
|
||||
|
||||
if(!istype(container, /obj/item/mmi))
|
||||
. = FALSE
|
||||
else if(istype(container, /obj/item/mmi/robotic_brain))
|
||||
var/obj/item/mmi/robotic_brain/R = container
|
||||
if(R && R.silenced)
|
||||
if(warning)
|
||||
to_chat(usr, "<span class='warning'>You cannot speak, as your internal speaker is turned off.</span>")
|
||||
. = FALSE
|
||||
|
||||
/mob/living/carbon/brain/handle_message_mode(var/message_mode, list/message_pieces, var/verb, var/used_radios)
|
||||
switch(message_mode)
|
||||
if("headset")
|
||||
var/radio_worked = 0 // If any of the radios our brainmob could use functioned, this is set true so that we don't use any others
|
||||
// I'm doing it this way so that if the mecha radio fails for some reason, a radio MMI still has the built-in fallback
|
||||
if(container && istype(container,/obj/item/mmi))
|
||||
var/obj/item/mmi/c = container
|
||||
if(!radio_worked && c.mecha)
|
||||
var/obj/mecha/metalgear = c.mecha
|
||||
if(metalgear.radio)
|
||||
radio_worked = metalgear.radio.talk_into(src, message_pieces, message_mode, verb)
|
||||
|
||||
else if(!radio_worked && c.radio)
|
||||
radio_worked = c.radio.talk_into(src, message_pieces, message_mode, verb)
|
||||
return radio_worked
|
||||
if("whisper")
|
||||
whisper_say(message_pieces)
|
||||
return 1
|
||||
else return 0
|
||||
//TODO: Convert this over for languages.
|
||||
/mob/living/carbon/brain/say(var/message, var/datum/language/speaking = null)
|
||||
if(!can_speak(warning = TRUE))
|
||||
return
|
||||
|
||||
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
|
||||
|
||||
..(message)
|
||||
|
||||
/mob/living/carbon/brain/whisper(message as text)
|
||||
if(!can_speak(warning = TRUE))
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/carbon/brain/can_speak(var/warning = FALSE)
|
||||
. = ..()
|
||||
|
||||
if(!istype(container, /obj/item/mmi))
|
||||
. = FALSE
|
||||
else if(istype(container, /obj/item/mmi/robotic_brain))
|
||||
var/obj/item/mmi/robotic_brain/R = container
|
||||
if(R && R.silenced)
|
||||
if(warning)
|
||||
to_chat(usr, "<span class='warning'>You cannot speak, as your internal speaker is turned off.</span>")
|
||||
. = FALSE
|
||||
|
||||
/mob/living/carbon/brain/handle_message_mode(var/message_mode, list/message_pieces, var/verb, var/used_radios)
|
||||
switch(message_mode)
|
||||
if("headset")
|
||||
var/radio_worked = 0 // If any of the radios our brainmob could use functioned, this is set true so that we don't use any others
|
||||
// I'm doing it this way so that if the mecha radio fails for some reason, a radio MMI still has the built-in fallback
|
||||
if(container && istype(container,/obj/item/mmi))
|
||||
var/obj/item/mmi/c = container
|
||||
if(!radio_worked && c.mecha)
|
||||
var/obj/mecha/metalgear = c.mecha
|
||||
if(metalgear.radio)
|
||||
radio_worked = metalgear.radio.talk_into(src, message_pieces, message_mode, verb)
|
||||
|
||||
else if(!radio_worked && c.radio)
|
||||
radio_worked = c.radio.talk_into(src, message_pieces, message_mode, verb)
|
||||
return radio_worked
|
||||
if("whisper")
|
||||
whisper_say(message_pieces)
|
||||
return 1
|
||||
else return 0
|
||||
|
||||
@@ -1192,4 +1192,4 @@ so that different stomachs can handle things in different ways VB*/
|
||||
var/obj/item/I = X
|
||||
I.acid_level = 0 //washes off the acid on our clothes
|
||||
I.extinguish() //extinguishes our clothes
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
/mob/living/carbon
|
||||
gender = MALE
|
||||
pressure_resistance = 15
|
||||
var/list/stomach_contents = list()
|
||||
var/list/internal_organs = list()
|
||||
var/list/internal_organs_slot = list() //Same as above, but stores "slot ID" - "organ" pairs for easy access.
|
||||
var/antibodies = 0
|
||||
|
||||
var/life_tick = 0 // The amount of life ticks that have processed on this mob.
|
||||
|
||||
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.
|
||||
|
||||
var/obj/item/head = null
|
||||
var/obj/item/clothing/suit/wear_suit = null //TODO: necessary? Are they even used? ~Carn
|
||||
|
||||
var/mob/living/simple_animal/borer/borer = null
|
||||
|
||||
//Active emote/pose
|
||||
var/pose = null
|
||||
|
||||
var/pulse = PULSE_NORM //current pulse level
|
||||
|
||||
var/wetlevel = 0 //how wet the mob is
|
||||
|
||||
var/co2overloadtime = null
|
||||
var/dreaming = 0 //How many dream images we have left to send
|
||||
var/nightmare = 0
|
||||
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
/mob/living/carbon
|
||||
gender = MALE
|
||||
pressure_resistance = 15
|
||||
var/list/stomach_contents = list()
|
||||
var/list/internal_organs = list()
|
||||
var/list/internal_organs_slot = list() //Same as above, but stores "slot ID" - "organ" pairs for easy access.
|
||||
var/antibodies = 0
|
||||
|
||||
var/life_tick = 0 // The amount of life ticks that have processed on this mob.
|
||||
|
||||
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.
|
||||
|
||||
var/obj/item/head = null
|
||||
var/obj/item/clothing/suit/wear_suit = null //TODO: necessary? Are they even used? ~Carn
|
||||
|
||||
var/mob/living/simple_animal/borer/borer = null
|
||||
|
||||
//Active emote/pose
|
||||
var/pose = null
|
||||
|
||||
var/pulse = PULSE_NORM //current pulse level
|
||||
|
||||
var/wetlevel = 0 //how wet the mob is
|
||||
|
||||
var/co2overloadtime = null
|
||||
var/dreaming = 0 //How many dream images we have left to send
|
||||
var/nightmare = 0
|
||||
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
|
||||
@@ -1,195 +1,195 @@
|
||||
/mob/living/carbon/human/gib()
|
||||
if(!death(TRUE) && stat != DEAD)
|
||||
return FALSE
|
||||
var/atom/movable/overlay/animation = null
|
||||
notransform = 1
|
||||
canmove = 0
|
||||
icon = null
|
||||
invisibility = 101
|
||||
if(!isSynthetic())
|
||||
animation = new(loc)
|
||||
animation.icon_state = "blank"
|
||||
animation.icon = 'icons/mob/mob.dmi'
|
||||
animation.master = src
|
||||
|
||||
playsound(src.loc, 'sound/goonstation/effects/gib.ogg', 50, 1)
|
||||
else
|
||||
playsound(src.loc, 'sound/goonstation/effects/robogib.ogg', 50, 1)
|
||||
|
||||
for(var/obj/item/organ/internal/I in internal_organs)
|
||||
if(isturf(loc))
|
||||
var/atom/movable/thing = I.remove(src)
|
||||
if(thing)
|
||||
thing.forceMove(get_turf(src))
|
||||
thing.throw_at(get_edge_target_turf(src, pick(alldirs)), rand(1,3), 5)
|
||||
|
||||
for(var/obj/item/organ/external/E in bodyparts)
|
||||
if(istype(E, /obj/item/organ/external/chest))
|
||||
continue
|
||||
// Only make the limb drop if it's not too damaged
|
||||
if(prob(100 - E.get_damage()))
|
||||
// Override the current limb status and don't cause an explosion
|
||||
E.droplimb(DROPLIMB_SHARP)
|
||||
|
||||
for(var/mob/M in src)
|
||||
if(M in stomach_contents)
|
||||
stomach_contents.Remove(M)
|
||||
M.forceMove(get_turf(src))
|
||||
visible_message("<span class='danger'>[M] bursts out of [src]!</span>")
|
||||
|
||||
if(!isSynthetic())
|
||||
flick("gibbed-h", animation)
|
||||
hgibs(loc, dna)
|
||||
else
|
||||
new /obj/effect/decal/cleanable/blood/gibs/robot(loc)
|
||||
do_sparks(3, 1, src)
|
||||
QDEL_IN(animation, 15)
|
||||
QDEL_IN(src, 0)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/dust()
|
||||
if(!death(TRUE) && stat != DEAD)
|
||||
return FALSE
|
||||
notransform = 1
|
||||
canmove = 0
|
||||
icon = null
|
||||
invisibility = 101
|
||||
dust_animation()
|
||||
QDEL_IN(src, 15)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/dust_animation()
|
||||
var/atom/movable/overlay/animation = null
|
||||
|
||||
animation = new(loc)
|
||||
animation.icon_state = "blank"
|
||||
animation.icon = 'icons/mob/mob.dmi'
|
||||
animation.master = src
|
||||
|
||||
flick("dust-h", animation)
|
||||
new dna.species.remains_type(get_turf(src))
|
||||
QDEL_IN(animation, 15)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/melt()
|
||||
if(!death(TRUE) && stat != DEAD)
|
||||
return FALSE
|
||||
var/atom/movable/overlay/animation = null
|
||||
notransform = 1
|
||||
canmove = 0
|
||||
icon = null
|
||||
invisibility = 101
|
||||
|
||||
animation = new(loc)
|
||||
animation.icon_state = "blank"
|
||||
animation.icon = 'icons/mob/mob.dmi'
|
||||
animation.master = src
|
||||
|
||||
flick("liquify", animation)
|
||||
QDEL_IN(src, 0)
|
||||
QDEL_IN(animation, 15)
|
||||
//new /obj/effect/decal/remains/human(loc)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/death(gibbed)
|
||||
if(can_die() && !gibbed && deathgasp_on_death)
|
||||
emote("deathgasp", force = TRUE) //let the world KNOW WE ARE DEAD
|
||||
|
||||
// Only execute the below if we successfully died
|
||||
. = ..(gibbed)
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
set_heartattack(FALSE)
|
||||
SSmobs.cubemonkeys -= src
|
||||
if(dna.species)
|
||||
dna.species.handle_hud_icons(src)
|
||||
//Handle species-specific deaths.
|
||||
dna.species.handle_death(gibbed, src)
|
||||
|
||||
if(ishuman(LAssailant))
|
||||
var/mob/living/carbon/human/H=LAssailant
|
||||
if(H.mind)
|
||||
H.mind.kills += "[key_name(src)]"
|
||||
|
||||
if(SSticker && SSticker.mode)
|
||||
// log_world("k")
|
||||
sql_report_death(src)
|
||||
|
||||
if(wearing_rig)
|
||||
wearing_rig.notify_ai("<span class='danger'>Warning: user death event. Mobility control passed to integrated intelligence system.</span>")
|
||||
|
||||
/mob/living/carbon/human/update_revive()
|
||||
. = ..()
|
||||
if(. && healthdoll)
|
||||
// We're alive again, so re-build the entire healthdoll
|
||||
healthdoll.cached_healthdoll_overlays.Cut()
|
||||
// Update healthdoll
|
||||
if(dna.species)
|
||||
dna.species.update_sight(src)
|
||||
dna.species.handle_hud_icons(src)
|
||||
|
||||
/mob/living/carbon/human/proc/makeSkeleton()
|
||||
var/obj/item/organ/external/head/H = get_organ("head")
|
||||
if(SKELETON in src.mutations)
|
||||
return
|
||||
|
||||
if(istype(H))
|
||||
H.disfigured = TRUE
|
||||
if(H.f_style)
|
||||
H.f_style = initial(H.f_style)
|
||||
if(H.h_style)
|
||||
H.h_style = initial(H.h_style)
|
||||
if(H.ha_style)
|
||||
H.ha_style = initial(H.ha_style)
|
||||
if(H.alt_head)
|
||||
H.alt_head = initial(H.alt_head)
|
||||
H.handle_alt_icon()
|
||||
m_styles = DEFAULT_MARKING_STYLES
|
||||
update_fhair(0)
|
||||
update_hair(0)
|
||||
update_head_accessory(0)
|
||||
update_markings(0)
|
||||
|
||||
mutations.Add(SKELETON)
|
||||
mutations.Add(NOCLONE)
|
||||
update_body(0)
|
||||
update_mutantrace()
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/ChangeToHusk()
|
||||
|
||||
// If the target has no DNA to begin with, its DNA can't be damaged beyond repair.
|
||||
if(NO_DNA in dna.species.species_traits)
|
||||
return
|
||||
if(HUSK in mutations)
|
||||
return
|
||||
|
||||
var/obj/item/organ/external/head/H = bodyparts_by_name["head"]
|
||||
if(istype(H))
|
||||
H.disfigured = TRUE //makes them unknown without fucking up other stuff like admintools
|
||||
if(H.f_style)
|
||||
H.f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE
|
||||
if(H.h_style)
|
||||
H.h_style = "Bald"
|
||||
update_fhair(0)
|
||||
update_hair(0)
|
||||
|
||||
mutations.Add(HUSK)
|
||||
update_body(0)
|
||||
update_mutantrace()
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/Drain()
|
||||
ChangeToHusk()
|
||||
mutations |= NOCLONE
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/cure_husk()
|
||||
mutations.Remove(HUSK)
|
||||
var/obj/item/organ/external/head/H = bodyparts_by_name["head"]
|
||||
if(istype(H))
|
||||
H.disfigured = FALSE
|
||||
update_body(0)
|
||||
update_mutantrace(0)
|
||||
UpdateAppearance() // reset hair from DNA
|
||||
/mob/living/carbon/human/gib()
|
||||
if(!death(TRUE) && stat != DEAD)
|
||||
return FALSE
|
||||
var/atom/movable/overlay/animation = null
|
||||
notransform = 1
|
||||
canmove = 0
|
||||
icon = null
|
||||
invisibility = 101
|
||||
if(!isSynthetic())
|
||||
animation = new(loc)
|
||||
animation.icon_state = "blank"
|
||||
animation.icon = 'icons/mob/mob.dmi'
|
||||
animation.master = src
|
||||
|
||||
playsound(src.loc, 'sound/goonstation/effects/gib.ogg', 50, 1)
|
||||
else
|
||||
playsound(src.loc, 'sound/goonstation/effects/robogib.ogg', 50, 1)
|
||||
|
||||
for(var/obj/item/organ/internal/I in internal_organs)
|
||||
if(isturf(loc))
|
||||
var/atom/movable/thing = I.remove(src)
|
||||
if(thing)
|
||||
thing.forceMove(get_turf(src))
|
||||
thing.throw_at(get_edge_target_turf(src, pick(alldirs)), rand(1,3), 5)
|
||||
|
||||
for(var/obj/item/organ/external/E in bodyparts)
|
||||
if(istype(E, /obj/item/organ/external/chest))
|
||||
continue
|
||||
// Only make the limb drop if it's not too damaged
|
||||
if(prob(100 - E.get_damage()))
|
||||
// Override the current limb status and don't cause an explosion
|
||||
E.droplimb(DROPLIMB_SHARP)
|
||||
|
||||
for(var/mob/M in src)
|
||||
if(M in stomach_contents)
|
||||
stomach_contents.Remove(M)
|
||||
M.forceMove(get_turf(src))
|
||||
visible_message("<span class='danger'>[M] bursts out of [src]!</span>")
|
||||
|
||||
if(!isSynthetic())
|
||||
flick("gibbed-h", animation)
|
||||
hgibs(loc, dna)
|
||||
else
|
||||
new /obj/effect/decal/cleanable/blood/gibs/robot(loc)
|
||||
do_sparks(3, 1, src)
|
||||
QDEL_IN(animation, 15)
|
||||
QDEL_IN(src, 0)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/dust()
|
||||
if(!death(TRUE) && stat != DEAD)
|
||||
return FALSE
|
||||
notransform = 1
|
||||
canmove = 0
|
||||
icon = null
|
||||
invisibility = 101
|
||||
dust_animation()
|
||||
QDEL_IN(src, 15)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/dust_animation()
|
||||
var/atom/movable/overlay/animation = null
|
||||
|
||||
animation = new(loc)
|
||||
animation.icon_state = "blank"
|
||||
animation.icon = 'icons/mob/mob.dmi'
|
||||
animation.master = src
|
||||
|
||||
flick("dust-h", animation)
|
||||
new dna.species.remains_type(get_turf(src))
|
||||
QDEL_IN(animation, 15)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/melt()
|
||||
if(!death(TRUE) && stat != DEAD)
|
||||
return FALSE
|
||||
var/atom/movable/overlay/animation = null
|
||||
notransform = 1
|
||||
canmove = 0
|
||||
icon = null
|
||||
invisibility = 101
|
||||
|
||||
animation = new(loc)
|
||||
animation.icon_state = "blank"
|
||||
animation.icon = 'icons/mob/mob.dmi'
|
||||
animation.master = src
|
||||
|
||||
flick("liquify", animation)
|
||||
QDEL_IN(src, 0)
|
||||
QDEL_IN(animation, 15)
|
||||
//new /obj/effect/decal/remains/human(loc)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/death(gibbed)
|
||||
if(can_die() && !gibbed && deathgasp_on_death)
|
||||
emote("deathgasp", force = TRUE) //let the world KNOW WE ARE DEAD
|
||||
|
||||
// Only execute the below if we successfully died
|
||||
. = ..(gibbed)
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
set_heartattack(FALSE)
|
||||
SSmobs.cubemonkeys -= src
|
||||
if(dna.species)
|
||||
dna.species.handle_hud_icons(src)
|
||||
//Handle species-specific deaths.
|
||||
dna.species.handle_death(gibbed, src)
|
||||
|
||||
if(ishuman(LAssailant))
|
||||
var/mob/living/carbon/human/H=LAssailant
|
||||
if(H.mind)
|
||||
H.mind.kills += "[key_name(src)]"
|
||||
|
||||
if(SSticker && SSticker.mode)
|
||||
// log_world("k")
|
||||
sql_report_death(src)
|
||||
|
||||
if(wearing_rig)
|
||||
wearing_rig.notify_ai("<span class='danger'>Warning: user death event. Mobility control passed to integrated intelligence system.</span>")
|
||||
|
||||
/mob/living/carbon/human/update_revive()
|
||||
. = ..()
|
||||
if(. && healthdoll)
|
||||
// We're alive again, so re-build the entire healthdoll
|
||||
healthdoll.cached_healthdoll_overlays.Cut()
|
||||
// Update healthdoll
|
||||
if(dna.species)
|
||||
dna.species.update_sight(src)
|
||||
dna.species.handle_hud_icons(src)
|
||||
|
||||
/mob/living/carbon/human/proc/makeSkeleton()
|
||||
var/obj/item/organ/external/head/H = get_organ("head")
|
||||
if(SKELETON in src.mutations)
|
||||
return
|
||||
|
||||
if(istype(H))
|
||||
H.disfigured = TRUE
|
||||
if(H.f_style)
|
||||
H.f_style = initial(H.f_style)
|
||||
if(H.h_style)
|
||||
H.h_style = initial(H.h_style)
|
||||
if(H.ha_style)
|
||||
H.ha_style = initial(H.ha_style)
|
||||
if(H.alt_head)
|
||||
H.alt_head = initial(H.alt_head)
|
||||
H.handle_alt_icon()
|
||||
m_styles = DEFAULT_MARKING_STYLES
|
||||
update_fhair(0)
|
||||
update_hair(0)
|
||||
update_head_accessory(0)
|
||||
update_markings(0)
|
||||
|
||||
mutations.Add(SKELETON)
|
||||
mutations.Add(NOCLONE)
|
||||
update_body(0)
|
||||
update_mutantrace()
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/ChangeToHusk()
|
||||
|
||||
// If the target has no DNA to begin with, its DNA can't be damaged beyond repair.
|
||||
if(NO_DNA in dna.species.species_traits)
|
||||
return
|
||||
if(HUSK in mutations)
|
||||
return
|
||||
|
||||
var/obj/item/organ/external/head/H = bodyparts_by_name["head"]
|
||||
if(istype(H))
|
||||
H.disfigured = TRUE //makes them unknown without fucking up other stuff like admintools
|
||||
if(H.f_style)
|
||||
H.f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE
|
||||
if(H.h_style)
|
||||
H.h_style = "Bald"
|
||||
update_fhair(0)
|
||||
update_hair(0)
|
||||
|
||||
mutations.Add(HUSK)
|
||||
update_body(0)
|
||||
update_mutantrace()
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/Drain()
|
||||
ChangeToHusk()
|
||||
mutations |= NOCLONE
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/cure_husk()
|
||||
mutations.Remove(HUSK)
|
||||
var/obj/item/organ/external/head/H = bodyparts_by_name["head"]
|
||||
if(istype(H))
|
||||
H.disfigured = FALSE
|
||||
update_body(0)
|
||||
update_mutantrace(0)
|
||||
UpdateAppearance() // reset hair from DNA
|
||||
|
||||
@@ -1,434 +1,434 @@
|
||||
/mob/living/carbon/human/examine(mob/user)
|
||||
var/skipgloves = 0
|
||||
var/skipsuitstorage = 0
|
||||
var/skipjumpsuit = 0
|
||||
var/skipshoes = 0
|
||||
var/skipmask = 0
|
||||
var/skipears = 0
|
||||
var/skipeyes = 0
|
||||
var/skipface = 0
|
||||
|
||||
//exosuits and helmets obscure our view and stuff.
|
||||
if(wear_suit)
|
||||
skipgloves = wear_suit.flags_inv & HIDEGLOVES
|
||||
skipsuitstorage = wear_suit.flags_inv & HIDESUITSTORAGE
|
||||
skipjumpsuit = wear_suit.flags_inv & HIDEJUMPSUIT
|
||||
skipshoes = wear_suit.flags_inv & HIDESHOES
|
||||
|
||||
if(head)
|
||||
skipmask = head.flags_inv & HIDEMASK
|
||||
skipeyes = head.flags_inv & HIDEEYES
|
||||
skipears = head.flags_inv & HIDEEARS
|
||||
skipface = head.flags_inv & HIDEFACE
|
||||
|
||||
if(wear_mask)
|
||||
skipface |= wear_mask.flags_inv & HIDEFACE
|
||||
var/msg = "<span class='info'>*---------*\nThis is "
|
||||
|
||||
if(!(skipjumpsuit && skipface) && icon) //big suits/masks/helmets make it hard to tell their gender
|
||||
msg += "[bicon(icon(icon, dir=SOUTH))] " //fucking BYOND: this should stop dreamseeker crashing if we -somehow- examine somebody before their icon is generated
|
||||
msg += "<EM>[name]</EM>"
|
||||
|
||||
var/displayed_species = dna.species.name
|
||||
var/examine_color = dna.species.flesh_color
|
||||
for(var/obj/item/clothing/C in src) //Disguise checks
|
||||
if(C == src.head || C == src.wear_suit || C == src.wear_mask || C == src.w_uniform || C == src.belt || C == src.back)
|
||||
if(C.species_disguise)
|
||||
displayed_species = C.species_disguise
|
||||
if(skipjumpsuit && skipface || (NO_EXAMINE in dna.species.species_traits)) //either obscured or on the nospecies list
|
||||
msg += "!\n" //omit the species when examining
|
||||
else if(displayed_species == "Slime People") //snowflakey because Slime People are defined as a plural
|
||||
msg += ", a<b><font color='[examine_color]'> slime person</font></b>!\n"
|
||||
else if(displayed_species == "Unathi") //DAMN YOU, VOWELS
|
||||
msg += ", a<b><font color='[examine_color]'> unathi</font></b>!\n"
|
||||
else
|
||||
msg += ", a<b><font color='[examine_color]'> [lowertext(displayed_species)]</font></b>!\n"
|
||||
|
||||
//uniform
|
||||
if(w_uniform && !skipjumpsuit && !(w_uniform.flags & ABSTRACT))
|
||||
//Ties
|
||||
var/tie_msg
|
||||
if(istype(w_uniform,/obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/U = w_uniform
|
||||
if(U.accessories.len)
|
||||
tie_msg += " with [english_accessory_list(U)]"
|
||||
|
||||
if(w_uniform.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] wearing [bicon(w_uniform)] [w_uniform.gender==PLURAL?"some":"a"] [w_uniform.blood_color != "#030303" ? "blood-stained":"oil-stained"] [w_uniform.name][tie_msg]!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] wearing [bicon(w_uniform)] \a [w_uniform][tie_msg].\n"
|
||||
|
||||
//head
|
||||
if(head && !(head.flags & ABSTRACT))
|
||||
if(head.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] wearing [bicon(head)] [head.gender==PLURAL?"some":"a"] [head.blood_color != "#030303" ? "blood-stained":"oil-stained"] [head.name] on [p_their()] head!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] wearing [bicon(head)] \a [head] on [p_their()] head.\n"
|
||||
|
||||
//suit/armour
|
||||
if(wear_suit && !(wear_suit.flags & ABSTRACT))
|
||||
if(wear_suit.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] wearing [bicon(wear_suit)] [wear_suit.gender==PLURAL?"some":"a"] [wear_suit.blood_color != "#030303" ? "blood-stained":"oil-stained"] [wear_suit.name]!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] wearing [bicon(wear_suit)] \a [wear_suit].\n"
|
||||
|
||||
//suit/armour storage
|
||||
if(s_store && !skipsuitstorage)
|
||||
if(s_store.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] carrying [bicon(s_store)] [s_store.gender==PLURAL?"some":"a"] [s_store.blood_color != "#030303" ? "blood-stained":"oil-stained"] [s_store.name] on [p_their()] [wear_suit.name]!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] carrying [bicon(s_store)] \a [s_store] on [p_their()] [wear_suit.name].\n"
|
||||
|
||||
//back
|
||||
if(back && !(back.flags & ABSTRACT))
|
||||
if(back.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [bicon(back)] [back.gender==PLURAL?"some":"a"] [back.blood_color != "#030303" ? "blood-stained":"oil-stained"] [back] on [p_their()] back.</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(back)] \a [back] on [p_their()] back.\n"
|
||||
|
||||
//left hand
|
||||
if(l_hand && !(l_hand.flags & ABSTRACT))
|
||||
if(l_hand.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] holding [bicon(l_hand)] [l_hand.gender==PLURAL?"some":"a"] [l_hand.blood_color != "#030303" ? "blood-stained":"oil-stained"] [l_hand.name] in [p_their()] left hand!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] holding [bicon(l_hand)] \a [l_hand] in [p_their()] left hand.\n"
|
||||
|
||||
//right hand
|
||||
if(r_hand && !(r_hand.flags & ABSTRACT))
|
||||
if(r_hand.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] holding [bicon(r_hand)] [r_hand.gender==PLURAL?"some":"a"] [r_hand.blood_color != "#030303" ? "blood-stained":"oil-stained"] [r_hand.name] in [p_their()] right hand!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] holding [bicon(r_hand)] \a [r_hand] in [p_their()] right hand.\n"
|
||||
|
||||
//gloves
|
||||
if(gloves && !skipgloves && !(gloves.flags & ABSTRACT))
|
||||
if(gloves.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [bicon(gloves)] [gloves.gender==PLURAL?"some":"a"] [gloves.blood_color != "#030303" ? "blood-stained":"oil-stained"] [gloves.name] on [p_their()] hands!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(gloves)] \a [gloves] on [p_their()] hands.\n"
|
||||
else if(blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [hand_blood_color != "#030303" ? "blood-stained":"oil-stained"] hands!</span>\n"
|
||||
|
||||
//handcuffed?
|
||||
if(handcuffed)
|
||||
if(istype(handcuffed, /obj/item/restraints/handcuffs/cable/zipties))
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] [bicon(handcuffed)] restrained with zipties!</span>\n"
|
||||
else if(istype(handcuffed, /obj/item/restraints/handcuffs/cable))
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] [bicon(handcuffed)] restrained with cable!</span>\n"
|
||||
else
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] [bicon(handcuffed)] handcuffed!</span>\n"
|
||||
|
||||
//belt
|
||||
if(belt)
|
||||
if(belt.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [bicon(belt)] [belt.gender==PLURAL?"some":"a"] [belt.blood_color != "#030303" ? "blood-stained":"oil-stained"] [belt.name] about [p_their()] waist!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(belt)] \a [belt] about [p_their()] waist.\n"
|
||||
|
||||
//shoes
|
||||
if(shoes && !skipshoes && !(shoes.flags & ABSTRACT))
|
||||
if(shoes.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] wearing [bicon(shoes)] [shoes.gender==PLURAL?"some":"a"] [shoes.blood_color != "#030303" ? "blood-stained":"oil-stained"] [shoes.name] on [p_their()] feet!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] wearing [bicon(shoes)] \a [shoes] on [p_their()] feet.\n"
|
||||
else if(blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [feet_blood_color != "#030303" ? "blood-stained":"oil-stained"] feet!</span>\n"
|
||||
|
||||
|
||||
//mask
|
||||
if(wear_mask && !skipmask && !(wear_mask.flags & ABSTRACT))
|
||||
if(wear_mask.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [bicon(wear_mask)] [wear_mask.gender==PLURAL?"some":"a"] [wear_mask.blood_color != "#030303" ? "blood-stained":"oil-stained"] [wear_mask.name] on [p_their()] face!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(wear_mask)] \a [wear_mask] on [p_their()] face.\n"
|
||||
|
||||
//eyes
|
||||
if(glasses && !skipeyes && !(glasses.flags & ABSTRACT))
|
||||
if(glasses.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [bicon(glasses)] [glasses.gender==PLURAL?"some":"a"] [glasses.blood_color != "#030303" ? "blood-stained":"oil-stained"] [glasses] covering [p_their()] eyes!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(glasses)] \a [glasses] covering [p_their()] eyes.\n"
|
||||
|
||||
//left ear
|
||||
if(l_ear && !skipears)
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(l_ear)] \a [l_ear] on [p_their()] left ear.\n"
|
||||
|
||||
//right ear
|
||||
if(r_ear && !skipears)
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(r_ear)] \a [r_ear] on [p_their()] right ear.\n"
|
||||
|
||||
//ID
|
||||
if(wear_id)
|
||||
msg += "[p_they(TRUE)] [p_are()] wearing [bicon(wear_id)] \a [wear_id].\n"
|
||||
|
||||
//Jitters
|
||||
switch(jitteriness)
|
||||
if(300 to INFINITY)
|
||||
msg += "<span class='warning'><B>[p_they(TRUE)] [p_are()] convulsing violently!</B></span>\n"
|
||||
if(200 to 300)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] extremely jittery.</span>\n"
|
||||
if(100 to 200)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] twitching ever so slightly.</span>\n"
|
||||
|
||||
|
||||
var/appears_dead = FALSE
|
||||
if(stat == DEAD || (status_flags & FAKEDEATH))
|
||||
appears_dead = TRUE
|
||||
if(suiciding)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] appear[p_s()] to have committed suicide... there is no hope of recovery.</span>\n"
|
||||
msg += "<span class='deadsay'>[p_they(TRUE)] [p_are()] limp and unresponsive; there are no signs of life"
|
||||
if(get_int_organ(/obj/item/organ/internal/brain))
|
||||
if(!key)
|
||||
var/foundghost = FALSE
|
||||
if(mind)
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
if(G.mind == mind)
|
||||
foundghost = TRUE
|
||||
if(G.can_reenter_corpse == 0)
|
||||
foundghost = FALSE
|
||||
break
|
||||
if(!foundghost)
|
||||
msg += " and [p_their()] soul has departed"
|
||||
msg += "...</span>\n"
|
||||
|
||||
if(!get_int_organ(/obj/item/organ/internal/brain))
|
||||
msg += "<span class='deadsay'>It appears that [p_their()] brain is missing...</span>\n"
|
||||
|
||||
msg += "<span class='warning'>"
|
||||
|
||||
var/list/wound_flavor_text = list()
|
||||
var/list/is_destroyed = list()
|
||||
for(var/organ_tag in dna.species.has_limbs)
|
||||
|
||||
var/list/organ_data = dna.species.has_limbs[organ_tag]
|
||||
var/organ_descriptor = organ_data["descriptor"]
|
||||
is_destroyed["[organ_data["descriptor"]]"] = 1
|
||||
|
||||
var/obj/item/organ/external/E = bodyparts_by_name[organ_tag]
|
||||
if(!E)
|
||||
wound_flavor_text["[organ_tag]"] = "<B>[p_they(TRUE)] [p_are()] missing [p_their()] [organ_descriptor].</B>\n"
|
||||
else
|
||||
if(!isSynthetic())
|
||||
if(E.is_robotic())
|
||||
wound_flavor_text["[E.limb_name]"] = "[p_they(TRUE)] [p_have()] a robotic [E.name]!\n"
|
||||
|
||||
else if(E.status & ORGAN_SPLINTED)
|
||||
wound_flavor_text["[E.limb_name]"] = "[p_they(TRUE)] [p_have()] a splint on [p_their()] [E.name]!\n"
|
||||
|
||||
if(E.open)
|
||||
if(E.is_robotic())
|
||||
msg += "<b>The maintenance hatch on [p_their()] [ignore_limb_branding(E.limb_name)] is open!</b>\n"
|
||||
else
|
||||
msg += "<b>[p_their(TRUE)] [ignore_limb_branding(E.limb_name)] has an open incision!</b>\n"
|
||||
|
||||
for(var/obj/item/I in E.embedded_objects)
|
||||
msg += "<B>[p_they(TRUE)] [p_have()] \a [bicon(I)] [I] embedded in [p_their()] [E.name]!</B>\n"
|
||||
|
||||
//Handles the text strings being added to the actual description.
|
||||
//If they have something that covers the limb, and it is not missing, put flavortext. If it is covered but bleeding, add other flavortext.
|
||||
if(wound_flavor_text["head"] && (is_destroyed["head"] || (!skipmask && !(wear_mask && istype(wear_mask, /obj/item/clothing/mask/gas)))))
|
||||
msg += wound_flavor_text["head"]
|
||||
if(wound_flavor_text["chest"] && !w_uniform && !skipjumpsuit) //No need. A missing chest gibs you.
|
||||
msg += wound_flavor_text["chest"]
|
||||
if(wound_flavor_text["l_arm"] && (is_destroyed["left arm"] || (!w_uniform && !skipjumpsuit)))
|
||||
msg += wound_flavor_text["l_arm"]
|
||||
if(wound_flavor_text["l_hand"] && (is_destroyed["left hand"] || (!gloves && !skipgloves)))
|
||||
msg += wound_flavor_text["l_hand"]
|
||||
if(wound_flavor_text["r_arm"] && (is_destroyed["right arm"] || (!w_uniform && !skipjumpsuit)))
|
||||
msg += wound_flavor_text["r_arm"]
|
||||
if(wound_flavor_text["r_hand"] && (is_destroyed["right hand"] || (!gloves && !skipgloves)))
|
||||
msg += wound_flavor_text["r_hand"]
|
||||
if(wound_flavor_text["groin"] && (is_destroyed["groin"] || (!w_uniform && !skipjumpsuit)))
|
||||
msg += wound_flavor_text["groin"]
|
||||
if(wound_flavor_text["l_leg"] && (is_destroyed["left leg"] || (!w_uniform && !skipjumpsuit)))
|
||||
msg += wound_flavor_text["l_leg"]
|
||||
if(wound_flavor_text["l_foot"]&& (is_destroyed["left foot"] || (!shoes && !skipshoes)))
|
||||
msg += wound_flavor_text["l_foot"]
|
||||
if(wound_flavor_text["r_leg"] && (is_destroyed["right leg"] || (!w_uniform && !skipjumpsuit)))
|
||||
msg += wound_flavor_text["r_leg"]
|
||||
if(wound_flavor_text["r_foot"]&& (is_destroyed["right foot"] || (!shoes && !skipshoes)))
|
||||
msg += wound_flavor_text["r_foot"]
|
||||
|
||||
var/temp = getBruteLoss() //no need to calculate each of these twice
|
||||
|
||||
if(temp)
|
||||
var/brute_message = !isSynthetic() ? "bruising" : "denting"
|
||||
if(temp < 30)
|
||||
msg += "[p_they(TRUE)] [p_have()] minor [brute_message ].\n"
|
||||
else
|
||||
msg += "<B>[p_they(TRUE)] [p_have()] severe [brute_message ]!</B>\n"
|
||||
|
||||
temp = getFireLoss()
|
||||
if(temp)
|
||||
if(temp < 30)
|
||||
msg += "[p_they(TRUE)] [p_have()] minor burns.\n"
|
||||
else
|
||||
msg += "<B>[p_they(TRUE)] [p_have()] severe burns!</B>\n"
|
||||
|
||||
temp = getCloneLoss()
|
||||
if(temp)
|
||||
if(temp < 30)
|
||||
msg += "[p_they(TRUE)] [p_have()] minor cellular damage.\n"
|
||||
else
|
||||
msg += "<B>[p_they(TRUE)] [p_have()] severe cellular damage.</B>\n"
|
||||
|
||||
|
||||
if(fire_stacks > 0)
|
||||
msg += "[p_they(TRUE)] [p_are()] covered in something flammable.\n"
|
||||
if(fire_stacks < 0)
|
||||
msg += "[p_they(TRUE)] looks a little soaked.\n"
|
||||
|
||||
switch(wetlevel)
|
||||
if(1)
|
||||
msg += "[p_they(TRUE)] looks a bit damp.\n"
|
||||
if(2)
|
||||
msg += "[p_they(TRUE)] looks a little bit wet.\n"
|
||||
if(3)
|
||||
msg += "[p_they(TRUE)] looks wet.\n"
|
||||
if(4)
|
||||
msg += "[p_they(TRUE)] looks very wet.\n"
|
||||
if(5)
|
||||
msg += "[p_they(TRUE)] looks absolutely soaked.\n"
|
||||
|
||||
if(nutrition < NUTRITION_LEVEL_STARVING - 50)
|
||||
msg += "[p_they(TRUE)] [p_are()] severely malnourished.\n"
|
||||
else if(nutrition >= NUTRITION_LEVEL_FAT)
|
||||
if(user.nutrition < NUTRITION_LEVEL_STARVING - 50)
|
||||
msg += "[p_they(TRUE)] [p_are()] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] quite chubby.\n"
|
||||
|
||||
if(!isSynthetic() && blood_volume < BLOOD_VOLUME_SAFE)
|
||||
msg += "[p_they(TRUE)] [p_have()] pale skin.\n"
|
||||
|
||||
if(bleedsuppress)
|
||||
msg += "[p_they(TRUE)] [p_are()] bandaged with something.\n"
|
||||
else if(bleed_rate)
|
||||
var/bleed_message = !isSynthetic() ? "bleeding" : "leaking"
|
||||
msg += "<B>[p_they(TRUE)] [p_are()] [bleed_message]!</B>\n"
|
||||
|
||||
if(reagents.has_reagent("teslium"))
|
||||
msg += "[p_they(TRUE)] [p_are()] emitting a gentle blue glow!\n"
|
||||
|
||||
msg += "</span>"
|
||||
|
||||
if(!appears_dead)
|
||||
if(stat == UNCONSCIOUS)
|
||||
msg += "[p_they(TRUE)] [p_are()]n't responding to anything around [p_them()] and seems to be asleep.\n"
|
||||
else if(getBrainLoss() >= 60)
|
||||
msg += "[p_they(TRUE)] [p_have()] a stupid expression on [p_their()] face.\n"
|
||||
|
||||
if(get_int_organ(/obj/item/organ/internal/brain))
|
||||
if(dna.species.show_ssd)
|
||||
if(!key)
|
||||
msg += "<span class='deadsay'>[p_they(TRUE)] [p_are()] totally catatonic. The stresses of life in deep-space must have been too much for [p_them()]. Any recovery is unlikely.</span>\n"
|
||||
else if(!client)
|
||||
msg += "[p_they(TRUE)] [p_have()] suddenly fallen asleep, suffering from Space Sleep Disorder. [p_they(TRUE)] may wake up soon.\n"
|
||||
|
||||
if(digitalcamo)
|
||||
msg += "[p_they(TRUE)] [p_are()] moving [p_their()] body in an unnatural and blatantly inhuman manner.\n"
|
||||
|
||||
if(!(skipface || ( wear_mask && ( wear_mask.flags_inv & HIDEFACE || wear_mask.flags_cover & MASKCOVERSMOUTH) ) ) && is_thrall(src) && in_range(user,src))
|
||||
msg += "Their features seem unnaturally tight and drawn.\n"
|
||||
|
||||
if(decaylevel == 1)
|
||||
msg += "[p_they(TRUE)] [p_are()] starting to smell.\n"
|
||||
if(decaylevel == 2)
|
||||
msg += "[p_they(TRUE)] [p_are()] bloated and smells disgusting.\n"
|
||||
if(decaylevel == 3)
|
||||
msg += "[p_they(TRUE)] [p_are()] rotting and blackened, the skin sloughing off. The smell is indescribably foul.\n"
|
||||
if(decaylevel == 4)
|
||||
msg += "[p_they(TRUE)] [p_are()] mostly dessicated now, with only bones remaining of what used to be a person.\n"
|
||||
|
||||
if(hasHUD(user,"security"))
|
||||
var/perpname = get_visible_name(TRUE)
|
||||
var/criminal = "None"
|
||||
|
||||
if(perpname)
|
||||
for(var/datum/data/record/E in data_core.general)
|
||||
if(E.fields["name"] == perpname)
|
||||
for(var/datum/data/record/R in data_core.security)
|
||||
if(R.fields["id"] == E.fields["id"])
|
||||
criminal = R.fields["criminal"]
|
||||
var/criminal_status = hasHUD(user, "read_only_security") ? "\[[criminal]\]" : "<a href='?src=[UID()];criminal=1'>\[[criminal]\]</a>"
|
||||
msg += "<span class = 'deptradio'>Criminal status:</span> [criminal_status]\n"
|
||||
msg += "<span class = 'deptradio'>Security records:</span> <a href='?src=[UID()];secrecord=`'>\[View\]</a> <a href='?src=[UID()];secrecordadd=`'>\[Add comment\]</a>\n"
|
||||
|
||||
if(hasHUD(user,"medical"))
|
||||
var/perpname = get_visible_name(TRUE)
|
||||
var/medical = "None"
|
||||
|
||||
for(var/datum/data/record/E in data_core.general)
|
||||
if(E.fields["name"] == perpname)
|
||||
for(var/datum/data/record/R in data_core.general)
|
||||
if(R.fields["id"] == E.fields["id"])
|
||||
medical = R.fields["p_stat"]
|
||||
|
||||
msg += "<span class = 'deptradio'>Physical status:</span> <a href='?src=[UID()];medical=1'>\[[medical]\]</a>\n"
|
||||
msg += "<span class = 'deptradio'>Medical records:</span> <a href='?src=[UID()];medrecord=`'>\[View\]</a> <a href='?src=[UID()];medrecordadd=`'>\[Add comment\]</a>\n"
|
||||
|
||||
|
||||
if(print_flavor_text() && !skipface)
|
||||
msg += "[print_flavor_text()]\n"
|
||||
|
||||
msg += "*---------*</span>"
|
||||
if(pose)
|
||||
if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 )
|
||||
pose = addtext(pose,".") //Makes sure all emotes end with a period.
|
||||
msg += "\n[p_they(TRUE)] [p_are()] [pose]"
|
||||
|
||||
. = list(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
|
||||
var/obj/item/organ/internal/cyberimp/eyes/hud/CIH = H.get_int_organ(/obj/item/organ/internal/cyberimp/eyes/hud)
|
||||
switch(hudtype)
|
||||
if("security")
|
||||
return istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/security)
|
||||
if("read_only_security")
|
||||
var/obj/item/clothing/glasses/hud/security/S
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud/security))
|
||||
S = H.glasses
|
||||
return !istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/security) && S && S.read_only
|
||||
if("medical")
|
||||
return istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/medical)
|
||||
else
|
||||
return 0
|
||||
else if(isrobot(M) || isAI(M)) //Stand-in/Stopgap to prevent pAIs from freely altering records, pending a more advanced Records system
|
||||
switch(hudtype)
|
||||
if("security")
|
||||
return 1
|
||||
if("medical")
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
else
|
||||
return 0
|
||||
|
||||
// Ignores robotic limb branding prefixes like "Morpheus Cybernetics"
|
||||
/proc/ignore_limb_branding(limb_name)
|
||||
switch(limb_name)
|
||||
if("chest")
|
||||
. = "upper body"
|
||||
if("groin")
|
||||
. = "lower body"
|
||||
if("head")
|
||||
. = "head"
|
||||
if("l_arm")
|
||||
. = "left arm"
|
||||
if("r_arm")
|
||||
. = "right arm"
|
||||
if("l_leg")
|
||||
. = "left leg"
|
||||
if("r_leg")
|
||||
. = "right leg"
|
||||
if("l_foot")
|
||||
. = "left foot"
|
||||
if("r_foot")
|
||||
. = "right foot"
|
||||
if("l_hand")
|
||||
. = "left hand"
|
||||
if("r_hand")
|
||||
. = "right hand"
|
||||
/mob/living/carbon/human/examine(mob/user)
|
||||
var/skipgloves = 0
|
||||
var/skipsuitstorage = 0
|
||||
var/skipjumpsuit = 0
|
||||
var/skipshoes = 0
|
||||
var/skipmask = 0
|
||||
var/skipears = 0
|
||||
var/skipeyes = 0
|
||||
var/skipface = 0
|
||||
|
||||
//exosuits and helmets obscure our view and stuff.
|
||||
if(wear_suit)
|
||||
skipgloves = wear_suit.flags_inv & HIDEGLOVES
|
||||
skipsuitstorage = wear_suit.flags_inv & HIDESUITSTORAGE
|
||||
skipjumpsuit = wear_suit.flags_inv & HIDEJUMPSUIT
|
||||
skipshoes = wear_suit.flags_inv & HIDESHOES
|
||||
|
||||
if(head)
|
||||
skipmask = head.flags_inv & HIDEMASK
|
||||
skipeyes = head.flags_inv & HIDEEYES
|
||||
skipears = head.flags_inv & HIDEEARS
|
||||
skipface = head.flags_inv & HIDEFACE
|
||||
|
||||
if(wear_mask)
|
||||
skipface |= wear_mask.flags_inv & HIDEFACE
|
||||
var/msg = "<span class='info'>*---------*\nThis is "
|
||||
|
||||
if(!(skipjumpsuit && skipface) && icon) //big suits/masks/helmets make it hard to tell their gender
|
||||
msg += "[bicon(icon(icon, dir=SOUTH))] " //fucking BYOND: this should stop dreamseeker crashing if we -somehow- examine somebody before their icon is generated
|
||||
msg += "<EM>[name]</EM>"
|
||||
|
||||
var/displayed_species = dna.species.name
|
||||
var/examine_color = dna.species.flesh_color
|
||||
for(var/obj/item/clothing/C in src) //Disguise checks
|
||||
if(C == src.head || C == src.wear_suit || C == src.wear_mask || C == src.w_uniform || C == src.belt || C == src.back)
|
||||
if(C.species_disguise)
|
||||
displayed_species = C.species_disguise
|
||||
if(skipjumpsuit && skipface || (NO_EXAMINE in dna.species.species_traits)) //either obscured or on the nospecies list
|
||||
msg += "!\n" //omit the species when examining
|
||||
else if(displayed_species == "Slime People") //snowflakey because Slime People are defined as a plural
|
||||
msg += ", a<b><font color='[examine_color]'> slime person</font></b>!\n"
|
||||
else if(displayed_species == "Unathi") //DAMN YOU, VOWELS
|
||||
msg += ", a<b><font color='[examine_color]'> unathi</font></b>!\n"
|
||||
else
|
||||
msg += ", a<b><font color='[examine_color]'> [lowertext(displayed_species)]</font></b>!\n"
|
||||
|
||||
//uniform
|
||||
if(w_uniform && !skipjumpsuit && !(w_uniform.flags & ABSTRACT))
|
||||
//Ties
|
||||
var/tie_msg
|
||||
if(istype(w_uniform,/obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/U = w_uniform
|
||||
if(U.accessories.len)
|
||||
tie_msg += " with [english_accessory_list(U)]"
|
||||
|
||||
if(w_uniform.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] wearing [bicon(w_uniform)] [w_uniform.gender==PLURAL?"some":"a"] [w_uniform.blood_color != "#030303" ? "blood-stained":"oil-stained"] [w_uniform.name][tie_msg]!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] wearing [bicon(w_uniform)] \a [w_uniform][tie_msg].\n"
|
||||
|
||||
//head
|
||||
if(head && !(head.flags & ABSTRACT))
|
||||
if(head.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] wearing [bicon(head)] [head.gender==PLURAL?"some":"a"] [head.blood_color != "#030303" ? "blood-stained":"oil-stained"] [head.name] on [p_their()] head!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] wearing [bicon(head)] \a [head] on [p_their()] head.\n"
|
||||
|
||||
//suit/armour
|
||||
if(wear_suit && !(wear_suit.flags & ABSTRACT))
|
||||
if(wear_suit.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] wearing [bicon(wear_suit)] [wear_suit.gender==PLURAL?"some":"a"] [wear_suit.blood_color != "#030303" ? "blood-stained":"oil-stained"] [wear_suit.name]!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] wearing [bicon(wear_suit)] \a [wear_suit].\n"
|
||||
|
||||
//suit/armour storage
|
||||
if(s_store && !skipsuitstorage)
|
||||
if(s_store.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] carrying [bicon(s_store)] [s_store.gender==PLURAL?"some":"a"] [s_store.blood_color != "#030303" ? "blood-stained":"oil-stained"] [s_store.name] on [p_their()] [wear_suit.name]!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] carrying [bicon(s_store)] \a [s_store] on [p_their()] [wear_suit.name].\n"
|
||||
|
||||
//back
|
||||
if(back && !(back.flags & ABSTRACT))
|
||||
if(back.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [bicon(back)] [back.gender==PLURAL?"some":"a"] [back.blood_color != "#030303" ? "blood-stained":"oil-stained"] [back] on [p_their()] back.</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(back)] \a [back] on [p_their()] back.\n"
|
||||
|
||||
//left hand
|
||||
if(l_hand && !(l_hand.flags & ABSTRACT))
|
||||
if(l_hand.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] holding [bicon(l_hand)] [l_hand.gender==PLURAL?"some":"a"] [l_hand.blood_color != "#030303" ? "blood-stained":"oil-stained"] [l_hand.name] in [p_their()] left hand!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] holding [bicon(l_hand)] \a [l_hand] in [p_their()] left hand.\n"
|
||||
|
||||
//right hand
|
||||
if(r_hand && !(r_hand.flags & ABSTRACT))
|
||||
if(r_hand.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] holding [bicon(r_hand)] [r_hand.gender==PLURAL?"some":"a"] [r_hand.blood_color != "#030303" ? "blood-stained":"oil-stained"] [r_hand.name] in [p_their()] right hand!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] holding [bicon(r_hand)] \a [r_hand] in [p_their()] right hand.\n"
|
||||
|
||||
//gloves
|
||||
if(gloves && !skipgloves && !(gloves.flags & ABSTRACT))
|
||||
if(gloves.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [bicon(gloves)] [gloves.gender==PLURAL?"some":"a"] [gloves.blood_color != "#030303" ? "blood-stained":"oil-stained"] [gloves.name] on [p_their()] hands!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(gloves)] \a [gloves] on [p_their()] hands.\n"
|
||||
else if(blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [hand_blood_color != "#030303" ? "blood-stained":"oil-stained"] hands!</span>\n"
|
||||
|
||||
//handcuffed?
|
||||
if(handcuffed)
|
||||
if(istype(handcuffed, /obj/item/restraints/handcuffs/cable/zipties))
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] [bicon(handcuffed)] restrained with zipties!</span>\n"
|
||||
else if(istype(handcuffed, /obj/item/restraints/handcuffs/cable))
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] [bicon(handcuffed)] restrained with cable!</span>\n"
|
||||
else
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] [bicon(handcuffed)] handcuffed!</span>\n"
|
||||
|
||||
//belt
|
||||
if(belt)
|
||||
if(belt.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [bicon(belt)] [belt.gender==PLURAL?"some":"a"] [belt.blood_color != "#030303" ? "blood-stained":"oil-stained"] [belt.name] about [p_their()] waist!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(belt)] \a [belt] about [p_their()] waist.\n"
|
||||
|
||||
//shoes
|
||||
if(shoes && !skipshoes && !(shoes.flags & ABSTRACT))
|
||||
if(shoes.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] wearing [bicon(shoes)] [shoes.gender==PLURAL?"some":"a"] [shoes.blood_color != "#030303" ? "blood-stained":"oil-stained"] [shoes.name] on [p_their()] feet!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] wearing [bicon(shoes)] \a [shoes] on [p_their()] feet.\n"
|
||||
else if(blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [feet_blood_color != "#030303" ? "blood-stained":"oil-stained"] feet!</span>\n"
|
||||
|
||||
|
||||
//mask
|
||||
if(wear_mask && !skipmask && !(wear_mask.flags & ABSTRACT))
|
||||
if(wear_mask.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [bicon(wear_mask)] [wear_mask.gender==PLURAL?"some":"a"] [wear_mask.blood_color != "#030303" ? "blood-stained":"oil-stained"] [wear_mask.name] on [p_their()] face!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(wear_mask)] \a [wear_mask] on [p_their()] face.\n"
|
||||
|
||||
//eyes
|
||||
if(glasses && !skipeyes && !(glasses.flags & ABSTRACT))
|
||||
if(glasses.blood_DNA)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_have()] [bicon(glasses)] [glasses.gender==PLURAL?"some":"a"] [glasses.blood_color != "#030303" ? "blood-stained":"oil-stained"] [glasses] covering [p_their()] eyes!</span>\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(glasses)] \a [glasses] covering [p_their()] eyes.\n"
|
||||
|
||||
//left ear
|
||||
if(l_ear && !skipears)
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(l_ear)] \a [l_ear] on [p_their()] left ear.\n"
|
||||
|
||||
//right ear
|
||||
if(r_ear && !skipears)
|
||||
msg += "[p_they(TRUE)] [p_have()] [bicon(r_ear)] \a [r_ear] on [p_their()] right ear.\n"
|
||||
|
||||
//ID
|
||||
if(wear_id)
|
||||
msg += "[p_they(TRUE)] [p_are()] wearing [bicon(wear_id)] \a [wear_id].\n"
|
||||
|
||||
//Jitters
|
||||
switch(jitteriness)
|
||||
if(300 to INFINITY)
|
||||
msg += "<span class='warning'><B>[p_they(TRUE)] [p_are()] convulsing violently!</B></span>\n"
|
||||
if(200 to 300)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] extremely jittery.</span>\n"
|
||||
if(100 to 200)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] [p_are()] twitching ever so slightly.</span>\n"
|
||||
|
||||
|
||||
var/appears_dead = FALSE
|
||||
if(stat == DEAD || (status_flags & FAKEDEATH))
|
||||
appears_dead = TRUE
|
||||
if(suiciding)
|
||||
msg += "<span class='warning'>[p_they(TRUE)] appear[p_s()] to have committed suicide... there is no hope of recovery.</span>\n"
|
||||
msg += "<span class='deadsay'>[p_they(TRUE)] [p_are()] limp and unresponsive; there are no signs of life"
|
||||
if(get_int_organ(/obj/item/organ/internal/brain))
|
||||
if(!key)
|
||||
var/foundghost = FALSE
|
||||
if(mind)
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
if(G.mind == mind)
|
||||
foundghost = TRUE
|
||||
if(G.can_reenter_corpse == 0)
|
||||
foundghost = FALSE
|
||||
break
|
||||
if(!foundghost)
|
||||
msg += " and [p_their()] soul has departed"
|
||||
msg += "...</span>\n"
|
||||
|
||||
if(!get_int_organ(/obj/item/organ/internal/brain))
|
||||
msg += "<span class='deadsay'>It appears that [p_their()] brain is missing...</span>\n"
|
||||
|
||||
msg += "<span class='warning'>"
|
||||
|
||||
var/list/wound_flavor_text = list()
|
||||
var/list/is_destroyed = list()
|
||||
for(var/organ_tag in dna.species.has_limbs)
|
||||
|
||||
var/list/organ_data = dna.species.has_limbs[organ_tag]
|
||||
var/organ_descriptor = organ_data["descriptor"]
|
||||
is_destroyed["[organ_data["descriptor"]]"] = 1
|
||||
|
||||
var/obj/item/organ/external/E = bodyparts_by_name[organ_tag]
|
||||
if(!E)
|
||||
wound_flavor_text["[organ_tag]"] = "<B>[p_they(TRUE)] [p_are()] missing [p_their()] [organ_descriptor].</B>\n"
|
||||
else
|
||||
if(!isSynthetic())
|
||||
if(E.is_robotic())
|
||||
wound_flavor_text["[E.limb_name]"] = "[p_they(TRUE)] [p_have()] a robotic [E.name]!\n"
|
||||
|
||||
else if(E.status & ORGAN_SPLINTED)
|
||||
wound_flavor_text["[E.limb_name]"] = "[p_they(TRUE)] [p_have()] a splint on [p_their()] [E.name]!\n"
|
||||
|
||||
if(E.open)
|
||||
if(E.is_robotic())
|
||||
msg += "<b>The maintenance hatch on [p_their()] [ignore_limb_branding(E.limb_name)] is open!</b>\n"
|
||||
else
|
||||
msg += "<b>[p_their(TRUE)] [ignore_limb_branding(E.limb_name)] has an open incision!</b>\n"
|
||||
|
||||
for(var/obj/item/I in E.embedded_objects)
|
||||
msg += "<B>[p_they(TRUE)] [p_have()] \a [bicon(I)] [I] embedded in [p_their()] [E.name]!</B>\n"
|
||||
|
||||
//Handles the text strings being added to the actual description.
|
||||
//If they have something that covers the limb, and it is not missing, put flavortext. If it is covered but bleeding, add other flavortext.
|
||||
if(wound_flavor_text["head"] && (is_destroyed["head"] || (!skipmask && !(wear_mask && istype(wear_mask, /obj/item/clothing/mask/gas)))))
|
||||
msg += wound_flavor_text["head"]
|
||||
if(wound_flavor_text["chest"] && !w_uniform && !skipjumpsuit) //No need. A missing chest gibs you.
|
||||
msg += wound_flavor_text["chest"]
|
||||
if(wound_flavor_text["l_arm"] && (is_destroyed["left arm"] || (!w_uniform && !skipjumpsuit)))
|
||||
msg += wound_flavor_text["l_arm"]
|
||||
if(wound_flavor_text["l_hand"] && (is_destroyed["left hand"] || (!gloves && !skipgloves)))
|
||||
msg += wound_flavor_text["l_hand"]
|
||||
if(wound_flavor_text["r_arm"] && (is_destroyed["right arm"] || (!w_uniform && !skipjumpsuit)))
|
||||
msg += wound_flavor_text["r_arm"]
|
||||
if(wound_flavor_text["r_hand"] && (is_destroyed["right hand"] || (!gloves && !skipgloves)))
|
||||
msg += wound_flavor_text["r_hand"]
|
||||
if(wound_flavor_text["groin"] && (is_destroyed["groin"] || (!w_uniform && !skipjumpsuit)))
|
||||
msg += wound_flavor_text["groin"]
|
||||
if(wound_flavor_text["l_leg"] && (is_destroyed["left leg"] || (!w_uniform && !skipjumpsuit)))
|
||||
msg += wound_flavor_text["l_leg"]
|
||||
if(wound_flavor_text["l_foot"]&& (is_destroyed["left foot"] || (!shoes && !skipshoes)))
|
||||
msg += wound_flavor_text["l_foot"]
|
||||
if(wound_flavor_text["r_leg"] && (is_destroyed["right leg"] || (!w_uniform && !skipjumpsuit)))
|
||||
msg += wound_flavor_text["r_leg"]
|
||||
if(wound_flavor_text["r_foot"]&& (is_destroyed["right foot"] || (!shoes && !skipshoes)))
|
||||
msg += wound_flavor_text["r_foot"]
|
||||
|
||||
var/temp = getBruteLoss() //no need to calculate each of these twice
|
||||
|
||||
if(temp)
|
||||
var/brute_message = !isSynthetic() ? "bruising" : "denting"
|
||||
if(temp < 30)
|
||||
msg += "[p_they(TRUE)] [p_have()] minor [brute_message ].\n"
|
||||
else
|
||||
msg += "<B>[p_they(TRUE)] [p_have()] severe [brute_message ]!</B>\n"
|
||||
|
||||
temp = getFireLoss()
|
||||
if(temp)
|
||||
if(temp < 30)
|
||||
msg += "[p_they(TRUE)] [p_have()] minor burns.\n"
|
||||
else
|
||||
msg += "<B>[p_they(TRUE)] [p_have()] severe burns!</B>\n"
|
||||
|
||||
temp = getCloneLoss()
|
||||
if(temp)
|
||||
if(temp < 30)
|
||||
msg += "[p_they(TRUE)] [p_have()] minor cellular damage.\n"
|
||||
else
|
||||
msg += "<B>[p_they(TRUE)] [p_have()] severe cellular damage.</B>\n"
|
||||
|
||||
|
||||
if(fire_stacks > 0)
|
||||
msg += "[p_they(TRUE)] [p_are()] covered in something flammable.\n"
|
||||
if(fire_stacks < 0)
|
||||
msg += "[p_they(TRUE)] looks a little soaked.\n"
|
||||
|
||||
switch(wetlevel)
|
||||
if(1)
|
||||
msg += "[p_they(TRUE)] looks a bit damp.\n"
|
||||
if(2)
|
||||
msg += "[p_they(TRUE)] looks a little bit wet.\n"
|
||||
if(3)
|
||||
msg += "[p_they(TRUE)] looks wet.\n"
|
||||
if(4)
|
||||
msg += "[p_they(TRUE)] looks very wet.\n"
|
||||
if(5)
|
||||
msg += "[p_they(TRUE)] looks absolutely soaked.\n"
|
||||
|
||||
if(nutrition < NUTRITION_LEVEL_STARVING - 50)
|
||||
msg += "[p_they(TRUE)] [p_are()] severely malnourished.\n"
|
||||
else if(nutrition >= NUTRITION_LEVEL_FAT)
|
||||
if(user.nutrition < NUTRITION_LEVEL_STARVING - 50)
|
||||
msg += "[p_they(TRUE)] [p_are()] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n"
|
||||
else
|
||||
msg += "[p_they(TRUE)] [p_are()] quite chubby.\n"
|
||||
|
||||
if(!isSynthetic() && blood_volume < BLOOD_VOLUME_SAFE)
|
||||
msg += "[p_they(TRUE)] [p_have()] pale skin.\n"
|
||||
|
||||
if(bleedsuppress)
|
||||
msg += "[p_they(TRUE)] [p_are()] bandaged with something.\n"
|
||||
else if(bleed_rate)
|
||||
var/bleed_message = !isSynthetic() ? "bleeding" : "leaking"
|
||||
msg += "<B>[p_they(TRUE)] [p_are()] [bleed_message]!</B>\n"
|
||||
|
||||
if(reagents.has_reagent("teslium"))
|
||||
msg += "[p_they(TRUE)] [p_are()] emitting a gentle blue glow!\n"
|
||||
|
||||
msg += "</span>"
|
||||
|
||||
if(!appears_dead)
|
||||
if(stat == UNCONSCIOUS)
|
||||
msg += "[p_they(TRUE)] [p_are()]n't responding to anything around [p_them()] and seems to be asleep.\n"
|
||||
else if(getBrainLoss() >= 60)
|
||||
msg += "[p_they(TRUE)] [p_have()] a stupid expression on [p_their()] face.\n"
|
||||
|
||||
if(get_int_organ(/obj/item/organ/internal/brain))
|
||||
if(dna.species.show_ssd)
|
||||
if(!key)
|
||||
msg += "<span class='deadsay'>[p_they(TRUE)] [p_are()] totally catatonic. The stresses of life in deep-space must have been too much for [p_them()]. Any recovery is unlikely.</span>\n"
|
||||
else if(!client)
|
||||
msg += "[p_they(TRUE)] [p_have()] suddenly fallen asleep, suffering from Space Sleep Disorder. [p_they(TRUE)] may wake up soon.\n"
|
||||
|
||||
if(digitalcamo)
|
||||
msg += "[p_they(TRUE)] [p_are()] moving [p_their()] body in an unnatural and blatantly inhuman manner.\n"
|
||||
|
||||
if(!(skipface || ( wear_mask && ( wear_mask.flags_inv & HIDEFACE || wear_mask.flags_cover & MASKCOVERSMOUTH) ) ) && is_thrall(src) && in_range(user,src))
|
||||
msg += "Their features seem unnaturally tight and drawn.\n"
|
||||
|
||||
if(decaylevel == 1)
|
||||
msg += "[p_they(TRUE)] [p_are()] starting to smell.\n"
|
||||
if(decaylevel == 2)
|
||||
msg += "[p_they(TRUE)] [p_are()] bloated and smells disgusting.\n"
|
||||
if(decaylevel == 3)
|
||||
msg += "[p_they(TRUE)] [p_are()] rotting and blackened, the skin sloughing off. The smell is indescribably foul.\n"
|
||||
if(decaylevel == 4)
|
||||
msg += "[p_they(TRUE)] [p_are()] mostly dessicated now, with only bones remaining of what used to be a person.\n"
|
||||
|
||||
if(hasHUD(user,"security"))
|
||||
var/perpname = get_visible_name(TRUE)
|
||||
var/criminal = "None"
|
||||
|
||||
if(perpname)
|
||||
for(var/datum/data/record/E in data_core.general)
|
||||
if(E.fields["name"] == perpname)
|
||||
for(var/datum/data/record/R in data_core.security)
|
||||
if(R.fields["id"] == E.fields["id"])
|
||||
criminal = R.fields["criminal"]
|
||||
var/criminal_status = hasHUD(user, "read_only_security") ? "\[[criminal]\]" : "<a href='?src=[UID()];criminal=1'>\[[criminal]\]</a>"
|
||||
msg += "<span class = 'deptradio'>Criminal status:</span> [criminal_status]\n"
|
||||
msg += "<span class = 'deptradio'>Security records:</span> <a href='?src=[UID()];secrecord=`'>\[View\]</a> <a href='?src=[UID()];secrecordadd=`'>\[Add comment\]</a>\n"
|
||||
|
||||
if(hasHUD(user,"medical"))
|
||||
var/perpname = get_visible_name(TRUE)
|
||||
var/medical = "None"
|
||||
|
||||
for(var/datum/data/record/E in data_core.general)
|
||||
if(E.fields["name"] == perpname)
|
||||
for(var/datum/data/record/R in data_core.general)
|
||||
if(R.fields["id"] == E.fields["id"])
|
||||
medical = R.fields["p_stat"]
|
||||
|
||||
msg += "<span class = 'deptradio'>Physical status:</span> <a href='?src=[UID()];medical=1'>\[[medical]\]</a>\n"
|
||||
msg += "<span class = 'deptradio'>Medical records:</span> <a href='?src=[UID()];medrecord=`'>\[View\]</a> <a href='?src=[UID()];medrecordadd=`'>\[Add comment\]</a>\n"
|
||||
|
||||
|
||||
if(print_flavor_text() && !skipface)
|
||||
msg += "[print_flavor_text()]\n"
|
||||
|
||||
msg += "*---------*</span>"
|
||||
if(pose)
|
||||
if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 )
|
||||
pose = addtext(pose,".") //Makes sure all emotes end with a period.
|
||||
msg += "\n[p_they(TRUE)] [p_are()] [pose]"
|
||||
|
||||
. = list(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
|
||||
var/obj/item/organ/internal/cyberimp/eyes/hud/CIH = H.get_int_organ(/obj/item/organ/internal/cyberimp/eyes/hud)
|
||||
switch(hudtype)
|
||||
if("security")
|
||||
return istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/security)
|
||||
if("read_only_security")
|
||||
var/obj/item/clothing/glasses/hud/security/S
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud/security))
|
||||
S = H.glasses
|
||||
return !istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/security) && S && S.read_only
|
||||
if("medical")
|
||||
return istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/medical)
|
||||
else
|
||||
return 0
|
||||
else if(isrobot(M) || isAI(M)) //Stand-in/Stopgap to prevent pAIs from freely altering records, pending a more advanced Records system
|
||||
switch(hudtype)
|
||||
if("security")
|
||||
return 1
|
||||
if("medical")
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
else
|
||||
return 0
|
||||
|
||||
// Ignores robotic limb branding prefixes like "Morpheus Cybernetics"
|
||||
/proc/ignore_limb_branding(limb_name)
|
||||
switch(limb_name)
|
||||
if("chest")
|
||||
. = "upper body"
|
||||
if("groin")
|
||||
. = "lower body"
|
||||
if("head")
|
||||
. = "head"
|
||||
if("l_arm")
|
||||
. = "left arm"
|
||||
if("r_arm")
|
||||
. = "right arm"
|
||||
if("l_leg")
|
||||
. = "left leg"
|
||||
if("r_leg")
|
||||
. = "right leg"
|
||||
if("l_foot")
|
||||
. = "left foot"
|
||||
if("r_foot")
|
||||
. = "right foot"
|
||||
if("l_hand")
|
||||
. = "left hand"
|
||||
if("r_hand")
|
||||
. = "right hand"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,350 +1,350 @@
|
||||
//Updates the mob's health from organs and mob damage variables
|
||||
/mob/living/carbon/human/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = maxHealth
|
||||
stat = CONSCIOUS
|
||||
return
|
||||
|
||||
var/total_burn = 0
|
||||
var/total_brute = 0
|
||||
|
||||
for(var/obj/item/organ/external/O in bodyparts) //hardcoded to streamline things a bit
|
||||
total_brute += O.brute_dam //calculates health based on organ brute and burn
|
||||
total_burn += O.burn_dam
|
||||
|
||||
health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
|
||||
|
||||
//TODO: fix husking
|
||||
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD)
|
||||
ChangeToHusk()
|
||||
update_stat("updatehealth([reason])")
|
||||
med_hud_set_health()
|
||||
med_hud_set_status()
|
||||
handle_hud_icons_health()
|
||||
|
||||
/mob/living/carbon/human/adjustBrainLoss(amount, updating = TRUE, use_brain_mod = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return STATUS_UPDATE_NONE //godmode
|
||||
|
||||
if(dna.species && dna.species.has_organ["brain"])
|
||||
var/obj/item/organ/internal/brain/sponge = get_int_organ(/obj/item/organ/internal/brain)
|
||||
if(sponge)
|
||||
if(dna.species && amount > 0)
|
||||
if(use_brain_mod)
|
||||
amount = amount * dna.species.brain_mod
|
||||
sponge.damage = Clamp(sponge.damage + amount, 0, 120)
|
||||
if(sponge.damage >= 120)
|
||||
visible_message("<span class='alert'><B>[src]</B> goes limp, [p_their()] facial expression utterly blank.</span>")
|
||||
death()
|
||||
if(updating)
|
||||
update_stat("adjustBrainLoss")
|
||||
return STATUS_UPDATE_STAT
|
||||
|
||||
/mob/living/carbon/human/setBrainLoss(amount, updating = TRUE, use_brain_mod = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return STATUS_UPDATE_NONE //godmode
|
||||
|
||||
if(dna.species && dna.species.has_organ["brain"])
|
||||
var/obj/item/organ/internal/brain/sponge = get_int_organ(/obj/item/organ/internal/brain)
|
||||
if(sponge)
|
||||
if(dna.species && amount > 0)
|
||||
if(use_brain_mod)
|
||||
amount = amount * dna.species.brain_mod
|
||||
sponge.damage = Clamp(amount, 0, 120)
|
||||
if(sponge.damage >= 120)
|
||||
visible_message("<span class='alert'><B>[src]</B> goes limp, [p_their()] facial expression utterly blank.</span>")
|
||||
death()
|
||||
if(updating)
|
||||
update_stat("setBrainLoss")
|
||||
return STATUS_UPDATE_STAT
|
||||
|
||||
/mob/living/carbon/human/getBrainLoss()
|
||||
if(status_flags & GODMODE)
|
||||
return 0 //godmode
|
||||
|
||||
if(dna.species && dna.species.has_organ["brain"])
|
||||
var/obj/item/organ/internal/brain/sponge = get_int_organ(/obj/item/organ/internal/brain)
|
||||
if(sponge)
|
||||
return min(sponge.damage,maxHealth*2)
|
||||
else
|
||||
return 200
|
||||
else
|
||||
return 0
|
||||
|
||||
//These procs fetch a cumulative total damage from all organs
|
||||
/mob/living/carbon/human/getBruteLoss()
|
||||
var/amount = 0
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
amount += O.brute_dam
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/human/getFireLoss()
|
||||
var/amount = 0
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
amount += O.burn_dam
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/human/adjustBruteLoss(amount, updating_health = TRUE, damage_source = null, robotic = FALSE)
|
||||
if(amount > 0)
|
||||
if(dna.species)
|
||||
amount = amount * dna.species.brute_mod
|
||||
take_overall_damage(amount, 0, updating_health, used_weapon = damage_source)
|
||||
else
|
||||
heal_overall_damage(-amount, 0, updating_health, FALSE, robotic)
|
||||
// brainless default for now
|
||||
return STATUS_UPDATE_HEALTH
|
||||
|
||||
/mob/living/carbon/human/adjustFireLoss(amount, updating_health = TRUE, damage_source = null, robotic = FALSE)
|
||||
if(amount > 0)
|
||||
if(dna.species)
|
||||
amount = amount * dna.species.burn_mod
|
||||
take_overall_damage(0, amount, updating_health, used_weapon = damage_source)
|
||||
else
|
||||
heal_overall_damage(0, -amount, updating_health, FALSE, robotic)
|
||||
// brainless default for now
|
||||
return STATUS_UPDATE_HEALTH
|
||||
|
||||
/mob/living/carbon/human/proc/adjustBruteLossByPart(amount, organ_name, obj/damage_source = null, updating_health = TRUE)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.brute_mod
|
||||
if(organ_name in bodyparts_by_name)
|
||||
var/obj/item/organ/external/O = get_organ(organ_name)
|
||||
|
||||
if(amount > 0)
|
||||
O.receive_damage(amount, 0, sharp=is_sharp(damage_source), used_weapon=damage_source, list(), FALSE, updating_health)
|
||||
else
|
||||
//if you don't want to heal robot organs, they you will have to check that yourself before using this proc.
|
||||
O.heal_damage(-amount, 0, internal = 0, robo_repair = O.is_robotic(), updating_health = updating_health)
|
||||
return STATUS_UPDATE_HEALTH
|
||||
|
||||
/mob/living/carbon/human/proc/adjustFireLossByPart(amount, organ_name, obj/damage_source = null, updating_health = TRUE)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.burn_mod
|
||||
|
||||
if(organ_name in bodyparts_by_name)
|
||||
var/obj/item/organ/external/O = get_organ(organ_name)
|
||||
|
||||
if(amount > 0)
|
||||
O.receive_damage(0, amount, sharp=is_sharp(damage_source), used_weapon=damage_source, forbidden_limbs = list(), ignore_resists = FALSE, updating_health = updating_health)
|
||||
else
|
||||
//if you don't want to heal robot organs, they you will have to check that yourself before using this proc.
|
||||
O.heal_damage(0, -amount, internal = 0, robo_repair = O.is_robotic(), updating_health = updating_health)
|
||||
return STATUS_UPDATE_HEALTH
|
||||
|
||||
|
||||
/mob/living/carbon/human/Paralyse(amount)
|
||||
// Notify our AI if they can now control the suit.
|
||||
if(wearing_rig && !stat && paralysis < amount) //We are passing out right this second.
|
||||
wearing_rig.notify_ai("<span class='danger'>Warning: user consciousness failure. Mobility control passed to integrated intelligence system.</span>")
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/adjustCloneLoss(amount)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.clone_mod
|
||||
. = ..()
|
||||
|
||||
var/heal_prob = max(0, 80 - getCloneLoss())
|
||||
var/mut_prob = min(80, getCloneLoss() + 10)
|
||||
if(amount > 0) //cloneloss is being added
|
||||
if(prob(mut_prob))
|
||||
var/list/obj/item/organ/external/candidates = list() //TYPECASTED LISTS ARE NOT A FUCKING THING WHAT THE FUCK
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
if(O.is_robotic())
|
||||
continue
|
||||
if(!(O.status & ORGAN_MUTATED))
|
||||
candidates |= O
|
||||
|
||||
if(candidates.len)
|
||||
var/obj/item/organ/external/O = pick(candidates)
|
||||
O.mutate()
|
||||
to_chat(src, "<span class='notice'>Something is not right with your [O.name]...</span>")
|
||||
O.add_autopsy_data("Mutation", amount)
|
||||
return
|
||||
|
||||
else //cloneloss is being subtracted
|
||||
if(prob(heal_prob))
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
if(O.status & ORGAN_MUTATED)
|
||||
O.unmutate()
|
||||
to_chat(src, "<span class='notice'>Your [O.name] is shaped normally again.</span>")
|
||||
return
|
||||
|
||||
|
||||
if(getCloneLoss() < 1) //no cloneloss, fixes organs
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
if(O.status & ORGAN_MUTATED)
|
||||
O.unmutate()
|
||||
to_chat(src, "<span class='notice'>Your [O.name] is shaped normally again.</span>")
|
||||
|
||||
|
||||
// Defined here solely to take species flags into account without having to recast at mob/living level.
|
||||
/mob/living/carbon/human/adjustOxyLoss(amount)
|
||||
if(NO_BREATHE in dna.species.species_traits)
|
||||
oxyloss = 0
|
||||
return FALSE
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.oxy_mod
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/setOxyLoss(amount)
|
||||
if(NO_BREATHE in dna.species.species_traits)
|
||||
oxyloss = 0
|
||||
return FALSE
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.oxy_mod
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/adjustToxLoss(amount)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.tox_mod
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/setToxLoss(amount)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.tox_mod
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/adjustStaminaLoss(amount, updating = TRUE)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.stamina_mod
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/setStaminaLoss(amount, updating = TRUE)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.stamina_mod
|
||||
. = ..()
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
//Returns a list of damaged organs
|
||||
/mob/living/carbon/human/proc/get_damaged_organs(brute, burn, flags = AFFECT_ALL_ORGANS)
|
||||
var/list/obj/item/organ/external/parts = list()
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
if((brute && O.brute_dam) || (burn && O.burn_dam))
|
||||
if(!(flags & AFFECT_ROBOTIC_ORGAN) && O.is_robotic())
|
||||
continue
|
||||
if(!(flags & AFFECT_ORGANIC_ORGAN) && !O.is_robotic())
|
||||
continue
|
||||
parts += O
|
||||
return parts
|
||||
|
||||
//Returns a list of damageable organs
|
||||
/mob/living/carbon/human/proc/get_damageable_organs()
|
||||
var/list/obj/item/organ/external/parts = list()
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
if(O.brute_dam + O.burn_dam < O.max_damage)
|
||||
parts += O
|
||||
return parts
|
||||
|
||||
//Heals ONE external organ, organ gets randomly selected from damaged ones.
|
||||
//It automatically updates damage overlays if necesary
|
||||
//It automatically updates health status
|
||||
/mob/living/carbon/human/heal_organ_damage(brute, burn, updating_health = TRUE)
|
||||
var/list/obj/item/organ/external/parts = get_damaged_organs(brute,burn)
|
||||
if(!parts.len)
|
||||
return
|
||||
var/obj/item/organ/external/picked = pick(parts)
|
||||
if(picked.heal_damage(brute,burn, updating_health))
|
||||
UpdateDamageIcon()
|
||||
|
||||
//Damages ONE external organ, organ gets randomly selected from damagable ones.
|
||||
//It automatically updates damage overlays if necesary
|
||||
//It automatically updates health status
|
||||
/mob/living/carbon/human/take_organ_damage(brute, burn, updating_health = TRUE, sharp = 0, edge = 0)
|
||||
var/list/obj/item/organ/external/parts = get_damageable_organs()
|
||||
if(!parts.len)
|
||||
return
|
||||
var/obj/item/organ/external/picked = pick(parts)
|
||||
if(picked.receive_damage(brute, burn, sharp, updating_health))
|
||||
UpdateDamageIcon()
|
||||
|
||||
|
||||
//Heal MANY external organs, in random order
|
||||
/mob/living/carbon/human/heal_overall_damage(brute, burn, updating_health = TRUE, internal=0, robotic=0)
|
||||
var/list/obj/item/organ/external/parts = get_damaged_organs(brute,burn)
|
||||
|
||||
var/update = 0
|
||||
while(parts.len && ( brute > 0 || burn > 0) )
|
||||
var/obj/item/organ/external/picked = pick(parts)
|
||||
|
||||
var/brute_was = picked.brute_dam
|
||||
var/burn_was = picked.burn_dam
|
||||
|
||||
update |= picked.heal_damage(brute,burn, internal, robotic, updating_health = FALSE)
|
||||
|
||||
brute -= (brute_was-picked.brute_dam)
|
||||
burn -= (burn_was-picked.burn_dam)
|
||||
|
||||
parts -= picked
|
||||
|
||||
if(updating_health)
|
||||
updatehealth("heal overall damage")
|
||||
if(update)
|
||||
UpdateDamageIcon()
|
||||
|
||||
// damage MANY external organs, in random order
|
||||
/mob/living/carbon/human/take_overall_damage(brute, burn, updating_health = TRUE, used_weapon = null, sharp = 0, edge = 0)
|
||||
if(status_flags & GODMODE)
|
||||
return //godmode
|
||||
var/list/obj/item/organ/external/parts = get_damageable_organs()
|
||||
|
||||
var/update = 0
|
||||
while(parts.len && (brute>0 || burn>0) )
|
||||
var/obj/item/organ/external/picked = pick(parts)
|
||||
var/brute_per_part = brute/parts.len
|
||||
var/burn_per_part = burn/parts.len
|
||||
|
||||
var/brute_was = picked.brute_dam
|
||||
var/burn_was = picked.burn_dam
|
||||
|
||||
|
||||
update |= picked.receive_damage(brute_per_part, burn_per_part, sharp, used_weapon, list(), FALSE, FALSE)
|
||||
|
||||
brute -= (picked.brute_dam - brute_was)
|
||||
burn -= (picked.burn_dam - burn_was)
|
||||
|
||||
parts -= picked
|
||||
|
||||
if(updating_health)
|
||||
updatehealth("take overall damage")
|
||||
|
||||
if(update)
|
||||
UpdateDamageIcon()
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
This function restores all organs.
|
||||
*/
|
||||
/mob/living/carbon/human/restore_all_organs()
|
||||
for(var/obj/item/organ/external/current_organ in bodyparts)
|
||||
current_organ.rejuvenate()
|
||||
|
||||
/mob/living/carbon/human/proc/HealDamage(zone, brute, burn)
|
||||
var/obj/item/organ/external/E = get_organ(zone)
|
||||
if(istype(E, /obj/item/organ/external))
|
||||
if(E.heal_damage(brute, burn))
|
||||
UpdateDamageIcon()
|
||||
else
|
||||
return 0
|
||||
|
||||
|
||||
/mob/living/carbon/human/get_organ(zone)
|
||||
if(!zone)
|
||||
zone = "chest"
|
||||
if(zone in list("eyes", "mouth"))
|
||||
zone = "head"
|
||||
|
||||
return bodyparts_by_name[zone]
|
||||
|
||||
/mob/living/carbon/human/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, sharp = 0, obj/used_weapon = null)
|
||||
//Handle other types of damage
|
||||
if((damagetype != BRUTE) && (damagetype != BURN))
|
||||
..(damage, damagetype, def_zone, blocked)
|
||||
return 1
|
||||
|
||||
//Handle BRUTE and BURN damage
|
||||
handle_suit_punctures(damagetype, damage)
|
||||
//Handle species apply_damage procs
|
||||
return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, sharp, used_weapon)
|
||||
//Updates the mob's health from organs and mob damage variables
|
||||
/mob/living/carbon/human/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = maxHealth
|
||||
stat = CONSCIOUS
|
||||
return
|
||||
|
||||
var/total_burn = 0
|
||||
var/total_brute = 0
|
||||
|
||||
for(var/obj/item/organ/external/O in bodyparts) //hardcoded to streamline things a bit
|
||||
total_brute += O.brute_dam //calculates health based on organ brute and burn
|
||||
total_burn += O.burn_dam
|
||||
|
||||
health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
|
||||
|
||||
//TODO: fix husking
|
||||
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD)
|
||||
ChangeToHusk()
|
||||
update_stat("updatehealth([reason])")
|
||||
med_hud_set_health()
|
||||
med_hud_set_status()
|
||||
handle_hud_icons_health()
|
||||
|
||||
/mob/living/carbon/human/adjustBrainLoss(amount, updating = TRUE, use_brain_mod = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return STATUS_UPDATE_NONE //godmode
|
||||
|
||||
if(dna.species && dna.species.has_organ["brain"])
|
||||
var/obj/item/organ/internal/brain/sponge = get_int_organ(/obj/item/organ/internal/brain)
|
||||
if(sponge)
|
||||
if(dna.species && amount > 0)
|
||||
if(use_brain_mod)
|
||||
amount = amount * dna.species.brain_mod
|
||||
sponge.damage = Clamp(sponge.damage + amount, 0, 120)
|
||||
if(sponge.damage >= 120)
|
||||
visible_message("<span class='alert'><B>[src]</B> goes limp, [p_their()] facial expression utterly blank.</span>")
|
||||
death()
|
||||
if(updating)
|
||||
update_stat("adjustBrainLoss")
|
||||
return STATUS_UPDATE_STAT
|
||||
|
||||
/mob/living/carbon/human/setBrainLoss(amount, updating = TRUE, use_brain_mod = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return STATUS_UPDATE_NONE //godmode
|
||||
|
||||
if(dna.species && dna.species.has_organ["brain"])
|
||||
var/obj/item/organ/internal/brain/sponge = get_int_organ(/obj/item/organ/internal/brain)
|
||||
if(sponge)
|
||||
if(dna.species && amount > 0)
|
||||
if(use_brain_mod)
|
||||
amount = amount * dna.species.brain_mod
|
||||
sponge.damage = Clamp(amount, 0, 120)
|
||||
if(sponge.damage >= 120)
|
||||
visible_message("<span class='alert'><B>[src]</B> goes limp, [p_their()] facial expression utterly blank.</span>")
|
||||
death()
|
||||
if(updating)
|
||||
update_stat("setBrainLoss")
|
||||
return STATUS_UPDATE_STAT
|
||||
|
||||
/mob/living/carbon/human/getBrainLoss()
|
||||
if(status_flags & GODMODE)
|
||||
return 0 //godmode
|
||||
|
||||
if(dna.species && dna.species.has_organ["brain"])
|
||||
var/obj/item/organ/internal/brain/sponge = get_int_organ(/obj/item/organ/internal/brain)
|
||||
if(sponge)
|
||||
return min(sponge.damage,maxHealth*2)
|
||||
else
|
||||
return 200
|
||||
else
|
||||
return 0
|
||||
|
||||
//These procs fetch a cumulative total damage from all organs
|
||||
/mob/living/carbon/human/getBruteLoss()
|
||||
var/amount = 0
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
amount += O.brute_dam
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/human/getFireLoss()
|
||||
var/amount = 0
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
amount += O.burn_dam
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/human/adjustBruteLoss(amount, updating_health = TRUE, damage_source = null, robotic = FALSE)
|
||||
if(amount > 0)
|
||||
if(dna.species)
|
||||
amount = amount * dna.species.brute_mod
|
||||
take_overall_damage(amount, 0, updating_health, used_weapon = damage_source)
|
||||
else
|
||||
heal_overall_damage(-amount, 0, updating_health, FALSE, robotic)
|
||||
// brainless default for now
|
||||
return STATUS_UPDATE_HEALTH
|
||||
|
||||
/mob/living/carbon/human/adjustFireLoss(amount, updating_health = TRUE, damage_source = null, robotic = FALSE)
|
||||
if(amount > 0)
|
||||
if(dna.species)
|
||||
amount = amount * dna.species.burn_mod
|
||||
take_overall_damage(0, amount, updating_health, used_weapon = damage_source)
|
||||
else
|
||||
heal_overall_damage(0, -amount, updating_health, FALSE, robotic)
|
||||
// brainless default for now
|
||||
return STATUS_UPDATE_HEALTH
|
||||
|
||||
/mob/living/carbon/human/proc/adjustBruteLossByPart(amount, organ_name, obj/damage_source = null, updating_health = TRUE)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.brute_mod
|
||||
if(organ_name in bodyparts_by_name)
|
||||
var/obj/item/organ/external/O = get_organ(organ_name)
|
||||
|
||||
if(amount > 0)
|
||||
O.receive_damage(amount, 0, sharp=is_sharp(damage_source), used_weapon=damage_source, list(), FALSE, updating_health)
|
||||
else
|
||||
//if you don't want to heal robot organs, they you will have to check that yourself before using this proc.
|
||||
O.heal_damage(-amount, 0, internal = 0, robo_repair = O.is_robotic(), updating_health = updating_health)
|
||||
return STATUS_UPDATE_HEALTH
|
||||
|
||||
/mob/living/carbon/human/proc/adjustFireLossByPart(amount, organ_name, obj/damage_source = null, updating_health = TRUE)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.burn_mod
|
||||
|
||||
if(organ_name in bodyparts_by_name)
|
||||
var/obj/item/organ/external/O = get_organ(organ_name)
|
||||
|
||||
if(amount > 0)
|
||||
O.receive_damage(0, amount, sharp=is_sharp(damage_source), used_weapon=damage_source, forbidden_limbs = list(), ignore_resists = FALSE, updating_health = updating_health)
|
||||
else
|
||||
//if you don't want to heal robot organs, they you will have to check that yourself before using this proc.
|
||||
O.heal_damage(0, -amount, internal = 0, robo_repair = O.is_robotic(), updating_health = updating_health)
|
||||
return STATUS_UPDATE_HEALTH
|
||||
|
||||
|
||||
/mob/living/carbon/human/Paralyse(amount)
|
||||
// Notify our AI if they can now control the suit.
|
||||
if(wearing_rig && !stat && paralysis < amount) //We are passing out right this second.
|
||||
wearing_rig.notify_ai("<span class='danger'>Warning: user consciousness failure. Mobility control passed to integrated intelligence system.</span>")
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/adjustCloneLoss(amount)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.clone_mod
|
||||
. = ..()
|
||||
|
||||
var/heal_prob = max(0, 80 - getCloneLoss())
|
||||
var/mut_prob = min(80, getCloneLoss() + 10)
|
||||
if(amount > 0) //cloneloss is being added
|
||||
if(prob(mut_prob))
|
||||
var/list/obj/item/organ/external/candidates = list() //TYPECASTED LISTS ARE NOT A FUCKING THING WHAT THE FUCK
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
if(O.is_robotic())
|
||||
continue
|
||||
if(!(O.status & ORGAN_MUTATED))
|
||||
candidates |= O
|
||||
|
||||
if(candidates.len)
|
||||
var/obj/item/organ/external/O = pick(candidates)
|
||||
O.mutate()
|
||||
to_chat(src, "<span class='notice'>Something is not right with your [O.name]...</span>")
|
||||
O.add_autopsy_data("Mutation", amount)
|
||||
return
|
||||
|
||||
else //cloneloss is being subtracted
|
||||
if(prob(heal_prob))
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
if(O.status & ORGAN_MUTATED)
|
||||
O.unmutate()
|
||||
to_chat(src, "<span class='notice'>Your [O.name] is shaped normally again.</span>")
|
||||
return
|
||||
|
||||
|
||||
if(getCloneLoss() < 1) //no cloneloss, fixes organs
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
if(O.status & ORGAN_MUTATED)
|
||||
O.unmutate()
|
||||
to_chat(src, "<span class='notice'>Your [O.name] is shaped normally again.</span>")
|
||||
|
||||
|
||||
// Defined here solely to take species flags into account without having to recast at mob/living level.
|
||||
/mob/living/carbon/human/adjustOxyLoss(amount)
|
||||
if(NO_BREATHE in dna.species.species_traits)
|
||||
oxyloss = 0
|
||||
return FALSE
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.oxy_mod
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/setOxyLoss(amount)
|
||||
if(NO_BREATHE in dna.species.species_traits)
|
||||
oxyloss = 0
|
||||
return FALSE
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.oxy_mod
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/adjustToxLoss(amount)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.tox_mod
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/setToxLoss(amount)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.tox_mod
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/adjustStaminaLoss(amount, updating = TRUE)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.stamina_mod
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/setStaminaLoss(amount, updating = TRUE)
|
||||
if(dna.species && amount > 0)
|
||||
amount = amount * dna.species.stamina_mod
|
||||
. = ..()
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
//Returns a list of damaged organs
|
||||
/mob/living/carbon/human/proc/get_damaged_organs(brute, burn, flags = AFFECT_ALL_ORGANS)
|
||||
var/list/obj/item/organ/external/parts = list()
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
if((brute && O.brute_dam) || (burn && O.burn_dam))
|
||||
if(!(flags & AFFECT_ROBOTIC_ORGAN) && O.is_robotic())
|
||||
continue
|
||||
if(!(flags & AFFECT_ORGANIC_ORGAN) && !O.is_robotic())
|
||||
continue
|
||||
parts += O
|
||||
return parts
|
||||
|
||||
//Returns a list of damageable organs
|
||||
/mob/living/carbon/human/proc/get_damageable_organs()
|
||||
var/list/obj/item/organ/external/parts = list()
|
||||
for(var/obj/item/organ/external/O in bodyparts)
|
||||
if(O.brute_dam + O.burn_dam < O.max_damage)
|
||||
parts += O
|
||||
return parts
|
||||
|
||||
//Heals ONE external organ, organ gets randomly selected from damaged ones.
|
||||
//It automatically updates damage overlays if necesary
|
||||
//It automatically updates health status
|
||||
/mob/living/carbon/human/heal_organ_damage(brute, burn, updating_health = TRUE)
|
||||
var/list/obj/item/organ/external/parts = get_damaged_organs(brute,burn)
|
||||
if(!parts.len)
|
||||
return
|
||||
var/obj/item/organ/external/picked = pick(parts)
|
||||
if(picked.heal_damage(brute,burn, updating_health))
|
||||
UpdateDamageIcon()
|
||||
|
||||
//Damages ONE external organ, organ gets randomly selected from damagable ones.
|
||||
//It automatically updates damage overlays if necesary
|
||||
//It automatically updates health status
|
||||
/mob/living/carbon/human/take_organ_damage(brute, burn, updating_health = TRUE, sharp = 0, edge = 0)
|
||||
var/list/obj/item/organ/external/parts = get_damageable_organs()
|
||||
if(!parts.len)
|
||||
return
|
||||
var/obj/item/organ/external/picked = pick(parts)
|
||||
if(picked.receive_damage(brute, burn, sharp, updating_health))
|
||||
UpdateDamageIcon()
|
||||
|
||||
|
||||
//Heal MANY external organs, in random order
|
||||
/mob/living/carbon/human/heal_overall_damage(brute, burn, updating_health = TRUE, internal=0, robotic=0)
|
||||
var/list/obj/item/organ/external/parts = get_damaged_organs(brute,burn)
|
||||
|
||||
var/update = 0
|
||||
while(parts.len && ( brute > 0 || burn > 0) )
|
||||
var/obj/item/organ/external/picked = pick(parts)
|
||||
|
||||
var/brute_was = picked.brute_dam
|
||||
var/burn_was = picked.burn_dam
|
||||
|
||||
update |= picked.heal_damage(brute,burn, internal, robotic, updating_health = FALSE)
|
||||
|
||||
brute -= (brute_was-picked.brute_dam)
|
||||
burn -= (burn_was-picked.burn_dam)
|
||||
|
||||
parts -= picked
|
||||
|
||||
if(updating_health)
|
||||
updatehealth("heal overall damage")
|
||||
if(update)
|
||||
UpdateDamageIcon()
|
||||
|
||||
// damage MANY external organs, in random order
|
||||
/mob/living/carbon/human/take_overall_damage(brute, burn, updating_health = TRUE, used_weapon = null, sharp = 0, edge = 0)
|
||||
if(status_flags & GODMODE)
|
||||
return //godmode
|
||||
var/list/obj/item/organ/external/parts = get_damageable_organs()
|
||||
|
||||
var/update = 0
|
||||
while(parts.len && (brute>0 || burn>0) )
|
||||
var/obj/item/organ/external/picked = pick(parts)
|
||||
var/brute_per_part = brute/parts.len
|
||||
var/burn_per_part = burn/parts.len
|
||||
|
||||
var/brute_was = picked.brute_dam
|
||||
var/burn_was = picked.burn_dam
|
||||
|
||||
|
||||
update |= picked.receive_damage(brute_per_part, burn_per_part, sharp, used_weapon, list(), FALSE, FALSE)
|
||||
|
||||
brute -= (picked.brute_dam - brute_was)
|
||||
burn -= (picked.burn_dam - burn_was)
|
||||
|
||||
parts -= picked
|
||||
|
||||
if(updating_health)
|
||||
updatehealth("take overall damage")
|
||||
|
||||
if(update)
|
||||
UpdateDamageIcon()
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
This function restores all organs.
|
||||
*/
|
||||
/mob/living/carbon/human/restore_all_organs()
|
||||
for(var/obj/item/organ/external/current_organ in bodyparts)
|
||||
current_organ.rejuvenate()
|
||||
|
||||
/mob/living/carbon/human/proc/HealDamage(zone, brute, burn)
|
||||
var/obj/item/organ/external/E = get_organ(zone)
|
||||
if(istype(E, /obj/item/organ/external))
|
||||
if(E.heal_damage(brute, burn))
|
||||
UpdateDamageIcon()
|
||||
else
|
||||
return 0
|
||||
|
||||
|
||||
/mob/living/carbon/human/get_organ(zone)
|
||||
if(!zone)
|
||||
zone = "chest"
|
||||
if(zone in list("eyes", "mouth"))
|
||||
zone = "head"
|
||||
|
||||
return bodyparts_by_name[zone]
|
||||
|
||||
/mob/living/carbon/human/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, sharp = 0, obj/used_weapon = null)
|
||||
//Handle other types of damage
|
||||
if((damagetype != BRUTE) && (damagetype != BURN))
|
||||
..(damage, damagetype, def_zone, blocked)
|
||||
return 1
|
||||
|
||||
//Handle BRUTE and BURN damage
|
||||
handle_suit_punctures(damagetype, damage)
|
||||
//Handle species apply_damage procs
|
||||
return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, sharp, used_weapon)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,74 +1,74 @@
|
||||
var/global/default_martial_art = new/datum/martial_art
|
||||
/mob/living/carbon/human
|
||||
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPMINDSHIELD_HUD,IMPCHEM_HUD,IMPTRACK_HUD,SPECIALROLE_HUD,GLAND_HUD)
|
||||
pressure_resistance = 25
|
||||
//Marking colour and style
|
||||
var/list/m_colours = DEFAULT_MARKING_COLOURS //All colours set to #000000.
|
||||
var/list/m_styles = DEFAULT_MARKING_STYLES //All markings set to None.
|
||||
|
||||
var/s_tone = 0 //Skin tone
|
||||
|
||||
//Skin colour
|
||||
var/skin_colour = "#000000"
|
||||
|
||||
var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup
|
||||
var/lip_color = "white"
|
||||
|
||||
var/age = 30 //Player's age (pure fluff)
|
||||
|
||||
var/underwear = "Nude" //Which underwear the player wants
|
||||
var/undershirt = "Nude" //Which undershirt the player wants
|
||||
var/socks = "Nude" //Which socks the player wants
|
||||
var/backbag = 2 //Which backpack type the player has chosen. Nothing, Satchel or Backpack.
|
||||
|
||||
//Equipment slots
|
||||
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/l_ear = null
|
||||
var/obj/item/r_ear = null
|
||||
var/obj/item/wear_id = null
|
||||
var/obj/item/wear_pda = null
|
||||
var/obj/item/r_store = null
|
||||
var/obj/item/l_store = null
|
||||
var/obj/item/s_store = null
|
||||
|
||||
var/icon/stand_icon = null
|
||||
var/icon/lying_icon = null
|
||||
|
||||
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/datum/personal_crafting/handcrafting
|
||||
|
||||
var/datum/martial_art/martial_art = null
|
||||
|
||||
var/special_voice = "" // For changing our voice. Used by a symptom.
|
||||
|
||||
var/hand_blood_color
|
||||
|
||||
var/name_override //For temporary visible name changes
|
||||
|
||||
var/xylophone = 0 //For the spoooooooky xylophone cooldown
|
||||
|
||||
var/mob/remoteview_target = null
|
||||
var/meatleft = 3 //For chef item
|
||||
var/decaylevel = 0 // For rotting bodies
|
||||
var/max_blood = BLOOD_VOLUME_NORMAL // For stuff in the vessel
|
||||
var/bleed_rate = 0
|
||||
var/bleedsuppress = 0 //for stopping bloodloss
|
||||
|
||||
var/check_mutations=0 // Check mutations on next life tick
|
||||
|
||||
var/heartbeat = 0
|
||||
var/receiving_cpr = FALSE
|
||||
|
||||
var/fire_dmi = 'icons/mob/OnFire.dmi'
|
||||
var/fire_sprite = "Standing"
|
||||
|
||||
var/datum/body_accessory/body_accessory = null
|
||||
var/tail // Name of tail image in species effects icon file.
|
||||
|
||||
var/list/splinted_limbs = list() //limbs we know are splinted
|
||||
var/global/default_martial_art = new/datum/martial_art
|
||||
/mob/living/carbon/human
|
||||
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPMINDSHIELD_HUD,IMPCHEM_HUD,IMPTRACK_HUD,SPECIALROLE_HUD,GLAND_HUD)
|
||||
pressure_resistance = 25
|
||||
//Marking colour and style
|
||||
var/list/m_colours = DEFAULT_MARKING_COLOURS //All colours set to #000000.
|
||||
var/list/m_styles = DEFAULT_MARKING_STYLES //All markings set to None.
|
||||
|
||||
var/s_tone = 0 //Skin tone
|
||||
|
||||
//Skin colour
|
||||
var/skin_colour = "#000000"
|
||||
|
||||
var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup
|
||||
var/lip_color = "white"
|
||||
|
||||
var/age = 30 //Player's age (pure fluff)
|
||||
|
||||
var/underwear = "Nude" //Which underwear the player wants
|
||||
var/undershirt = "Nude" //Which undershirt the player wants
|
||||
var/socks = "Nude" //Which socks the player wants
|
||||
var/backbag = 2 //Which backpack type the player has chosen. Nothing, Satchel or Backpack.
|
||||
|
||||
//Equipment slots
|
||||
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/l_ear = null
|
||||
var/obj/item/r_ear = null
|
||||
var/obj/item/wear_id = null
|
||||
var/obj/item/wear_pda = null
|
||||
var/obj/item/r_store = null
|
||||
var/obj/item/l_store = null
|
||||
var/obj/item/s_store = null
|
||||
|
||||
var/icon/stand_icon = null
|
||||
var/icon/lying_icon = null
|
||||
|
||||
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/datum/personal_crafting/handcrafting
|
||||
|
||||
var/datum/martial_art/martial_art = null
|
||||
|
||||
var/special_voice = "" // For changing our voice. Used by a symptom.
|
||||
|
||||
var/hand_blood_color
|
||||
|
||||
var/name_override //For temporary visible name changes
|
||||
|
||||
var/xylophone = 0 //For the spoooooooky xylophone cooldown
|
||||
|
||||
var/mob/remoteview_target = null
|
||||
var/meatleft = 3 //For chef item
|
||||
var/decaylevel = 0 // For rotting bodies
|
||||
var/max_blood = BLOOD_VOLUME_NORMAL // For stuff in the vessel
|
||||
var/bleed_rate = 0
|
||||
var/bleedsuppress = 0 //for stopping bloodloss
|
||||
|
||||
var/check_mutations=0 // Check mutations on next life tick
|
||||
|
||||
var/heartbeat = 0
|
||||
var/receiving_cpr = FALSE
|
||||
|
||||
var/fire_dmi = 'icons/mob/OnFire.dmi'
|
||||
var/fire_sprite = "Standing"
|
||||
|
||||
var/datum/body_accessory/body_accessory = null
|
||||
var/tail // Name of tail image in species effects icon file.
|
||||
|
||||
var/list/splinted_limbs = list() //limbs we know are splinted
|
||||
|
||||
@@ -1,133 +1,133 @@
|
||||
/mob/living/carbon/human/movement_delay()
|
||||
. = 0
|
||||
. += ..()
|
||||
. += config.human_delay
|
||||
. += dna.species.movement_delay(src)
|
||||
|
||||
/mob/living/carbon/human/Process_Spacemove(movement_dir = 0)
|
||||
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
//Do we have a working jetpack?
|
||||
var/obj/item/tank/jetpack/thrust
|
||||
if(istype(back, /obj/item/tank/jetpack))
|
||||
thrust = back
|
||||
else if(istype(wear_suit, /obj/item/clothing/suit/space/hardsuit))
|
||||
var/obj/item/clothing/suit/space/hardsuit/C = wear_suit
|
||||
thrust = C.jetpack
|
||||
else if(istype(back,/obj/item/rig))
|
||||
var/obj/item/rig/rig = back
|
||||
for(var/obj/item/rig_module/maneuvering_jets/module in rig.installed_modules)
|
||||
thrust = module.jets
|
||||
break
|
||||
|
||||
if(thrust)
|
||||
if((movement_dir || thrust.stabilizers) && thrust.allow_thrust(0.01, src))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/mob_has_gravity()
|
||||
. = ..()
|
||||
if(!.)
|
||||
if(mob_negates_gravity())
|
||||
. = 1
|
||||
|
||||
/mob/living/carbon/human/mob_negates_gravity()
|
||||
return shoes && shoes.negates_gravity()
|
||||
|
||||
/mob/living/carbon/human/Move(NewLoc, direct)
|
||||
. = ..()
|
||||
if(.) // did we actually move?
|
||||
if(!lying && !buckled && !throwing)
|
||||
for(var/obj/item/organ/external/splinted in splinted_limbs)
|
||||
splinted.update_splints()
|
||||
|
||||
if(!has_gravity(loc))
|
||||
return
|
||||
|
||||
var/obj/item/clothing/shoes/S = shoes
|
||||
|
||||
//Bloody footprints
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/item/organ/external/l_foot = get_organ("l_foot")
|
||||
var/obj/item/organ/external/r_foot = get_organ("r_foot")
|
||||
var/hasfeet = TRUE
|
||||
if(!l_foot && !r_foot)
|
||||
hasfeet = FALSE
|
||||
|
||||
if(shoes)
|
||||
if(S.bloody_shoes && S.bloody_shoes[S.blood_state])
|
||||
for(var/obj/effect/decal/cleanable/blood/footprints/oldFP in T)
|
||||
if(oldFP && oldFP.blood_state == S.blood_state && oldFP.basecolor == S.blood_color)
|
||||
return
|
||||
//No oldFP or it's a different kind of blood
|
||||
S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state] - BLOOD_LOSS_PER_STEP)
|
||||
if(S.bloody_shoes[S.blood_state] > BLOOD_LOSS_IN_SPREAD)
|
||||
createFootprintsFrom(shoes, dir, T)
|
||||
update_inv_shoes()
|
||||
else if(hasfeet)
|
||||
if(bloody_feet && bloody_feet[blood_state])
|
||||
for(var/obj/effect/decal/cleanable/blood/footprints/oldFP in T)
|
||||
if(oldFP && oldFP.blood_state == blood_state && oldFP.basecolor == feet_blood_color)
|
||||
return
|
||||
bloody_feet[blood_state] = max(0, bloody_feet[blood_state] - BLOOD_LOSS_PER_STEP)
|
||||
if(bloody_feet[blood_state] > BLOOD_LOSS_IN_SPREAD)
|
||||
createFootprintsFrom(src, dir, T)
|
||||
update_inv_shoes()
|
||||
//End bloody footprints
|
||||
if(S)
|
||||
S.step_action(src)
|
||||
|
||||
/mob/living/carbon/human/handle_footstep(turf/T)
|
||||
if(..())
|
||||
if(T.footstep_sounds["human"])
|
||||
var/S = pick(T.footstep_sounds["human"])
|
||||
if(S)
|
||||
if(m_intent == MOVE_INTENT_RUN)
|
||||
if(!(step_count % 2)) //every other turf makes a sound
|
||||
return 0
|
||||
|
||||
if(istype(shoes, /obj/item/clothing/shoes))
|
||||
var/obj/item/clothing/shoes/shooess = shoes
|
||||
if(shooess.silence_steps)
|
||||
return 0 //silent
|
||||
if(shooess.shoe_sound)
|
||||
return //Handle it on the shoe
|
||||
|
||||
var/range = -(world.view - 2)
|
||||
if(m_intent == MOVE_INTENT_WALK)
|
||||
range -= 0.333
|
||||
if(!shoes)
|
||||
range -= 0.333
|
||||
|
||||
//shoes + running
|
||||
//-(7 - 2) = -(5) = -5 | -5 - 0 = -5 | (7 + -5) = 2 | 2 * 3 = 6 | range(6) = range(6)
|
||||
//running OR shoes
|
||||
//-(7 - 2) = (-5) = -5 | -5 - 0.333 = -5.333 | (7 + -5.333) = 1.667 | 1.667 * 3 = 5.001 | range(5.001) = range(5)
|
||||
//walking AND no shoes
|
||||
//-(7 - 2) = (-5) = -5 | -5 - (0.333 * 2) = -5.666 | (7 + -5.666) = 1.334 | 1.334 * 3 = 4.002 | range(4.002) = range(4)
|
||||
|
||||
var/volume = 13
|
||||
if(m_intent == MOVE_INTENT_WALK)
|
||||
volume -= 4
|
||||
if(!shoes)
|
||||
volume -= 4
|
||||
|
||||
if(!has_organ("l_foot") && !has_organ("r_foot"))
|
||||
return 0 //no feet no footsteps
|
||||
|
||||
if(buckled || lying || throwing)
|
||||
return 0 //people flying, lying down or sitting do not step
|
||||
|
||||
if(!has_gravity(src))
|
||||
if(step_count % 3) //this basically says, every three moves make a noise
|
||||
return 0 //1st - none, 1%3==1, 2nd - none, 2%3==2, 3rd - noise, 3%3==0
|
||||
|
||||
if(dna.species.silent_steps)
|
||||
return 0 //species is silent
|
||||
|
||||
playsound(T, S, volume, 1, range)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
/mob/living/carbon/human/movement_delay()
|
||||
. = 0
|
||||
. += ..()
|
||||
. += config.human_delay
|
||||
. += dna.species.movement_delay(src)
|
||||
|
||||
/mob/living/carbon/human/Process_Spacemove(movement_dir = 0)
|
||||
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
//Do we have a working jetpack?
|
||||
var/obj/item/tank/jetpack/thrust
|
||||
if(istype(back, /obj/item/tank/jetpack))
|
||||
thrust = back
|
||||
else if(istype(wear_suit, /obj/item/clothing/suit/space/hardsuit))
|
||||
var/obj/item/clothing/suit/space/hardsuit/C = wear_suit
|
||||
thrust = C.jetpack
|
||||
else if(istype(back,/obj/item/rig))
|
||||
var/obj/item/rig/rig = back
|
||||
for(var/obj/item/rig_module/maneuvering_jets/module in rig.installed_modules)
|
||||
thrust = module.jets
|
||||
break
|
||||
|
||||
if(thrust)
|
||||
if((movement_dir || thrust.stabilizers) && thrust.allow_thrust(0.01, src))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/mob_has_gravity()
|
||||
. = ..()
|
||||
if(!.)
|
||||
if(mob_negates_gravity())
|
||||
. = 1
|
||||
|
||||
/mob/living/carbon/human/mob_negates_gravity()
|
||||
return shoes && shoes.negates_gravity()
|
||||
|
||||
/mob/living/carbon/human/Move(NewLoc, direct)
|
||||
. = ..()
|
||||
if(.) // did we actually move?
|
||||
if(!lying && !buckled && !throwing)
|
||||
for(var/obj/item/organ/external/splinted in splinted_limbs)
|
||||
splinted.update_splints()
|
||||
|
||||
if(!has_gravity(loc))
|
||||
return
|
||||
|
||||
var/obj/item/clothing/shoes/S = shoes
|
||||
|
||||
//Bloody footprints
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/item/organ/external/l_foot = get_organ("l_foot")
|
||||
var/obj/item/organ/external/r_foot = get_organ("r_foot")
|
||||
var/hasfeet = TRUE
|
||||
if(!l_foot && !r_foot)
|
||||
hasfeet = FALSE
|
||||
|
||||
if(shoes)
|
||||
if(S.bloody_shoes && S.bloody_shoes[S.blood_state])
|
||||
for(var/obj/effect/decal/cleanable/blood/footprints/oldFP in T)
|
||||
if(oldFP && oldFP.blood_state == S.blood_state && oldFP.basecolor == S.blood_color)
|
||||
return
|
||||
//No oldFP or it's a different kind of blood
|
||||
S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state] - BLOOD_LOSS_PER_STEP)
|
||||
if(S.bloody_shoes[S.blood_state] > BLOOD_LOSS_IN_SPREAD)
|
||||
createFootprintsFrom(shoes, dir, T)
|
||||
update_inv_shoes()
|
||||
else if(hasfeet)
|
||||
if(bloody_feet && bloody_feet[blood_state])
|
||||
for(var/obj/effect/decal/cleanable/blood/footprints/oldFP in T)
|
||||
if(oldFP && oldFP.blood_state == blood_state && oldFP.basecolor == feet_blood_color)
|
||||
return
|
||||
bloody_feet[blood_state] = max(0, bloody_feet[blood_state] - BLOOD_LOSS_PER_STEP)
|
||||
if(bloody_feet[blood_state] > BLOOD_LOSS_IN_SPREAD)
|
||||
createFootprintsFrom(src, dir, T)
|
||||
update_inv_shoes()
|
||||
//End bloody footprints
|
||||
if(S)
|
||||
S.step_action(src)
|
||||
|
||||
/mob/living/carbon/human/handle_footstep(turf/T)
|
||||
if(..())
|
||||
if(T.footstep_sounds["human"])
|
||||
var/S = pick(T.footstep_sounds["human"])
|
||||
if(S)
|
||||
if(m_intent == MOVE_INTENT_RUN)
|
||||
if(!(step_count % 2)) //every other turf makes a sound
|
||||
return 0
|
||||
|
||||
if(istype(shoes, /obj/item/clothing/shoes))
|
||||
var/obj/item/clothing/shoes/shooess = shoes
|
||||
if(shooess.silence_steps)
|
||||
return 0 //silent
|
||||
if(shooess.shoe_sound)
|
||||
return //Handle it on the shoe
|
||||
|
||||
var/range = -(world.view - 2)
|
||||
if(m_intent == MOVE_INTENT_WALK)
|
||||
range -= 0.333
|
||||
if(!shoes)
|
||||
range -= 0.333
|
||||
|
||||
//shoes + running
|
||||
//-(7 - 2) = -(5) = -5 | -5 - 0 = -5 | (7 + -5) = 2 | 2 * 3 = 6 | range(6) = range(6)
|
||||
//running OR shoes
|
||||
//-(7 - 2) = (-5) = -5 | -5 - 0.333 = -5.333 | (7 + -5.333) = 1.667 | 1.667 * 3 = 5.001 | range(5.001) = range(5)
|
||||
//walking AND no shoes
|
||||
//-(7 - 2) = (-5) = -5 | -5 - (0.333 * 2) = -5.666 | (7 + -5.666) = 1.334 | 1.334 * 3 = 4.002 | range(4.002) = range(4)
|
||||
|
||||
var/volume = 13
|
||||
if(m_intent == MOVE_INTENT_WALK)
|
||||
volume -= 4
|
||||
if(!shoes)
|
||||
volume -= 4
|
||||
|
||||
if(!has_organ("l_foot") && !has_organ("r_foot"))
|
||||
return 0 //no feet no footsteps
|
||||
|
||||
if(buckled || lying || throwing)
|
||||
return 0 //people flying, lying down or sitting do not step
|
||||
|
||||
if(!has_gravity(src))
|
||||
if(step_count % 3) //this basically says, every three moves make a noise
|
||||
return 0 //1st - none, 1%3==1, 2nd - none, 2%3==2, 3rd - noise, 3%3==0
|
||||
|
||||
if(dna.species.silent_steps)
|
||||
return 0 //species is silent
|
||||
|
||||
playsound(T, S, volume, 1, range)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
@@ -1,437 +1,437 @@
|
||||
/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/is_in_hands(var/typepath)
|
||||
if(istype(l_hand,typepath))
|
||||
return l_hand
|
||||
if(istype(r_hand,typepath))
|
||||
return r_hand
|
||||
return 0
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/has_organ(name)
|
||||
var/obj/item/organ/external/O = bodyparts_by_name[name]
|
||||
return O
|
||||
|
||||
/mob/living/carbon/human/proc/has_organ_for_slot(slot)
|
||||
switch(slot)
|
||||
if(slot_back)
|
||||
return has_organ("chest")
|
||||
if(slot_wear_mask)
|
||||
return has_organ("head")
|
||||
if(slot_handcuffed)
|
||||
return has_organ("l_hand") && has_organ("r_hand")
|
||||
if(slot_legcuffed)
|
||||
return has_organ("l_leg") && has_organ("r_leg")
|
||||
if(slot_l_hand)
|
||||
return has_organ("l_hand")
|
||||
if(slot_r_hand)
|
||||
return has_organ("r_hand")
|
||||
if(slot_belt)
|
||||
return has_organ("chest")
|
||||
if(slot_wear_id)
|
||||
// the only relevant check for this is the uniform check
|
||||
return TRUE
|
||||
if(slot_wear_pda)
|
||||
return TRUE
|
||||
if(slot_l_ear)
|
||||
return has_organ("head")
|
||||
if(slot_r_ear)
|
||||
return has_organ("head")
|
||||
if(slot_glasses)
|
||||
return has_organ("head")
|
||||
if(slot_gloves)
|
||||
return has_organ("l_hand") && has_organ("r_hand")
|
||||
if(slot_head)
|
||||
return has_organ("head")
|
||||
if(slot_shoes)
|
||||
return has_organ("r_foot") && has_organ("l_foot")
|
||||
if(slot_wear_suit)
|
||||
return has_organ("chest")
|
||||
if(slot_w_uniform)
|
||||
return has_organ("chest")
|
||||
if(slot_l_store)
|
||||
return has_organ("chest")
|
||||
if(slot_r_store)
|
||||
return has_organ("chest")
|
||||
if(slot_s_store)
|
||||
return has_organ("chest")
|
||||
if(slot_in_backpack)
|
||||
return TRUE
|
||||
if(slot_tie)
|
||||
return TRUE
|
||||
|
||||
// The actual dropping happens at the mob level - checks to prevent drops should
|
||||
// come here
|
||||
/mob/living/carbon/human/canUnEquip(obj/item/I, force)
|
||||
. = ..()
|
||||
var/obj/item/organ/O = I
|
||||
if(istype(O) && O.owner == src)
|
||||
. = 0 // keep a good grip on your heart
|
||||
|
||||
/mob/living/carbon/human/unEquip(obj/item/I, force)
|
||||
. = ..() //See mob.dm for an explanation on this and some rage about people copypasting instead of calling ..() like they should.
|
||||
if(!. || !I)
|
||||
return
|
||||
|
||||
if(I == wear_suit)
|
||||
if(s_store)
|
||||
unEquip(s_store, 1) //It makes no sense for your suit storage to stay on you if you drop your suit.
|
||||
wear_suit = null
|
||||
if(I.flags_inv & HIDEJUMPSUIT)
|
||||
update_inv_w_uniform()
|
||||
update_inv_wear_suit()
|
||||
else if(I == w_uniform)
|
||||
if(r_store)
|
||||
unEquip(r_store, 1) //Again, makes sense for pockets to drop.
|
||||
if(l_store)
|
||||
unEquip(l_store, 1)
|
||||
if(wear_id)
|
||||
unEquip(wear_id)
|
||||
if(belt)
|
||||
unEquip(belt)
|
||||
w_uniform = null
|
||||
update_inv_w_uniform()
|
||||
else if(I == gloves)
|
||||
gloves = null
|
||||
update_inv_gloves()
|
||||
else if(I == glasses)
|
||||
glasses = null
|
||||
var/obj/item/clothing/glasses/G = I
|
||||
if(G.tint)
|
||||
update_tint()
|
||||
if(G.prescription)
|
||||
update_nearsighted_effects()
|
||||
if(G.vision_flags || G.see_in_dark || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
|
||||
update_sight()
|
||||
update_inv_glasses()
|
||||
update_client_colour()
|
||||
else if(I == head)
|
||||
head = null
|
||||
if(I.flags & BLOCKHAIR || I.flags & BLOCKHEADHAIR)
|
||||
update_hair() //rebuild hair
|
||||
update_fhair()
|
||||
update_head_accessory()
|
||||
// Bandanas and paper hats go on the head but are not head clothing
|
||||
if(istype(I,/obj/item/clothing/head))
|
||||
var/obj/item/clothing/head/hat = I
|
||||
if(hat.vision_flags || hat.see_in_dark || !isnull(hat.lighting_alpha))
|
||||
update_sight()
|
||||
head_update(I)
|
||||
update_inv_head()
|
||||
else if(I == r_ear)
|
||||
r_ear = null
|
||||
update_inv_ears()
|
||||
else if(I == l_ear)
|
||||
l_ear = null
|
||||
update_inv_ears()
|
||||
else if(I == shoes)
|
||||
shoes = null
|
||||
update_inv_shoes()
|
||||
else if(I == belt)
|
||||
belt = null
|
||||
update_inv_belt()
|
||||
else if(I == wear_mask)
|
||||
wear_mask = null
|
||||
if(I.flags & BLOCKHAIR || I.flags & BLOCKHEADHAIR)
|
||||
update_hair() //rebuild hair
|
||||
update_fhair()
|
||||
update_head_accessory()
|
||||
if(internal && !get_organ_slot("breathing_tube"))
|
||||
internal = null
|
||||
update_action_buttons_icon()
|
||||
wear_mask_update(I, toggle_off = FALSE)
|
||||
sec_hud_set_ID()
|
||||
update_inv_wear_mask()
|
||||
else if(I == wear_id)
|
||||
wear_id = null
|
||||
sec_hud_set_ID()
|
||||
update_inv_wear_id()
|
||||
else if(I == wear_pda)
|
||||
wear_pda = null
|
||||
update_inv_wear_pda()
|
||||
else if(I == r_store)
|
||||
r_store = null
|
||||
update_inv_pockets()
|
||||
else if(I == l_store)
|
||||
l_store = null
|
||||
update_inv_pockets()
|
||||
else if(I == s_store)
|
||||
s_store = null
|
||||
update_inv_s_store()
|
||||
else if(I == back)
|
||||
back = null
|
||||
update_inv_back()
|
||||
else if(I == r_hand)
|
||||
r_hand = null
|
||||
update_inv_r_hand()
|
||||
else if(I == l_hand)
|
||||
l_hand = null
|
||||
update_inv_l_hand()
|
||||
|
||||
|
||||
|
||||
|
||||
//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()
|
||||
//set redraw_mob to 0 if you don't wish the hud to be updated - if you're doing it manually in your own proc.
|
||||
/mob/living/carbon/human/equip_to_slot(obj/item/I, slot, redraw_mob = 1)
|
||||
if(!slot)
|
||||
return
|
||||
if(!istype(I))
|
||||
return
|
||||
if(!has_organ_for_slot(slot))
|
||||
return
|
||||
|
||||
if(I == src.l_hand)
|
||||
src.l_hand = null
|
||||
update_inv_l_hand() //So items actually disappear from hands.
|
||||
else if(I == src.r_hand)
|
||||
src.r_hand = null
|
||||
update_inv_r_hand()
|
||||
|
||||
I.screen_loc = null
|
||||
I.forceMove(src)
|
||||
I.equipped(src, slot)
|
||||
I.layer = ABOVE_HUD_LAYER
|
||||
I.plane = ABOVE_HUD_PLANE
|
||||
|
||||
switch(slot)
|
||||
if(slot_back)
|
||||
back = I
|
||||
update_inv_back(redraw_mob)
|
||||
if(slot_wear_mask)
|
||||
wear_mask = I
|
||||
if((wear_mask.flags & BLOCKHAIR) || (wear_mask.flags & BLOCKHEADHAIR))
|
||||
update_hair(redraw_mob) //rebuild hair
|
||||
update_fhair(redraw_mob)
|
||||
update_head_accessory(redraw_mob)
|
||||
if(hud_list.len)
|
||||
sec_hud_set_ID()
|
||||
wear_mask_update(I, toggle_off = TRUE)
|
||||
update_inv_wear_mask(redraw_mob)
|
||||
if(slot_handcuffed)
|
||||
handcuffed = I
|
||||
update_inv_handcuffed(redraw_mob)
|
||||
if(slot_legcuffed)
|
||||
legcuffed = I
|
||||
update_inv_legcuffed(redraw_mob)
|
||||
if(slot_l_hand)
|
||||
l_hand = I
|
||||
update_inv_l_hand(redraw_mob)
|
||||
if(slot_r_hand)
|
||||
r_hand = I
|
||||
update_inv_r_hand(redraw_mob)
|
||||
if(slot_belt)
|
||||
belt = I
|
||||
update_inv_belt(redraw_mob)
|
||||
if(slot_wear_id)
|
||||
wear_id = I
|
||||
if(hud_list.len)
|
||||
sec_hud_set_ID()
|
||||
update_inv_wear_id(redraw_mob)
|
||||
if(slot_wear_pda)
|
||||
wear_pda = I
|
||||
update_inv_wear_pda(redraw_mob)
|
||||
if(slot_l_ear)
|
||||
l_ear = I
|
||||
if(l_ear.slot_flags & SLOT_TWOEARS)
|
||||
var/obj/item/clothing/ears/offear/O = new(I)
|
||||
O.forceMove(src)
|
||||
r_ear = O
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
update_inv_ears(redraw_mob)
|
||||
if(slot_r_ear)
|
||||
r_ear = I
|
||||
if(r_ear.slot_flags & SLOT_TWOEARS)
|
||||
var/obj/item/clothing/ears/offear/O = new(I)
|
||||
O.forceMove(src)
|
||||
l_ear = O
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
update_inv_ears(redraw_mob)
|
||||
if(slot_glasses)
|
||||
glasses = I
|
||||
var/obj/item/clothing/glasses/G = I
|
||||
if(G.tint)
|
||||
update_tint()
|
||||
if(G.prescription)
|
||||
update_nearsighted_effects()
|
||||
if(G.vision_flags || G.see_in_dark || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
|
||||
update_sight()
|
||||
update_inv_glasses(redraw_mob)
|
||||
update_client_colour()
|
||||
if(slot_gloves)
|
||||
gloves = I
|
||||
update_inv_gloves(redraw_mob)
|
||||
if(slot_head)
|
||||
head = I
|
||||
if((head.flags & BLOCKHAIR) || (head.flags & BLOCKHEADHAIR))
|
||||
update_hair(redraw_mob) //rebuild hair
|
||||
update_fhair(redraw_mob)
|
||||
update_head_accessory(redraw_mob)
|
||||
// paper + bandanas
|
||||
if(istype(I, /obj/item/clothing/head))
|
||||
var/obj/item/clothing/head/hat = I
|
||||
if(hat.vision_flags || hat.see_in_dark || !isnull(hat.lighting_alpha))
|
||||
update_sight()
|
||||
head_update(I)
|
||||
update_inv_head(redraw_mob)
|
||||
if(slot_shoes)
|
||||
shoes = I
|
||||
update_inv_shoes(redraw_mob)
|
||||
if(slot_wear_suit)
|
||||
wear_suit = I
|
||||
update_inv_wear_suit(redraw_mob)
|
||||
if(slot_w_uniform)
|
||||
w_uniform = I
|
||||
update_inv_w_uniform(redraw_mob)
|
||||
if(slot_l_store)
|
||||
l_store = I
|
||||
update_inv_pockets(redraw_mob)
|
||||
if(slot_r_store)
|
||||
r_store = I
|
||||
update_inv_pockets(redraw_mob)
|
||||
if(slot_s_store)
|
||||
s_store = I
|
||||
update_inv_s_store(redraw_mob)
|
||||
if(slot_in_backpack)
|
||||
if(get_active_hand() == I)
|
||||
unEquip(I)
|
||||
I.forceMove(back)
|
||||
if(slot_tie)
|
||||
var/obj/item/clothing/under/uniform = src.w_uniform
|
||||
uniform.attackby(I, src)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You are trying to equip this item to an unsupported inventory slot. Report this to a coder!</span>")
|
||||
|
||||
/mob/living/carbon/human/put_in_hands(obj/item/I)
|
||||
if(!I)
|
||||
return FALSE
|
||||
if(put_in_active_hand(I))
|
||||
return TRUE
|
||||
else if(put_in_inactive_hand(I))
|
||||
return TRUE
|
||||
else
|
||||
. = ..()
|
||||
|
||||
// Return the item currently in the slot ID
|
||||
/mob/living/carbon/human/get_item_by_slot(slot_id)
|
||||
switch(slot_id)
|
||||
if(slot_back)
|
||||
return back
|
||||
if(slot_wear_mask)
|
||||
return wear_mask
|
||||
if(slot_handcuffed)
|
||||
return handcuffed
|
||||
if(slot_legcuffed)
|
||||
return legcuffed
|
||||
if(slot_l_hand)
|
||||
return l_hand
|
||||
if(slot_r_hand)
|
||||
return r_hand
|
||||
if(slot_belt)
|
||||
return belt
|
||||
if(slot_wear_id)
|
||||
return wear_id
|
||||
if(slot_wear_pda)
|
||||
return wear_pda
|
||||
if(slot_l_ear)
|
||||
return l_ear
|
||||
if(slot_r_ear)
|
||||
return r_ear
|
||||
if(slot_glasses)
|
||||
return glasses
|
||||
if(slot_gloves)
|
||||
return gloves
|
||||
if(slot_head)
|
||||
return head
|
||||
if(slot_shoes)
|
||||
return shoes
|
||||
if(slot_wear_suit)
|
||||
return wear_suit
|
||||
if(slot_w_uniform)
|
||||
return w_uniform
|
||||
if(slot_l_store)
|
||||
return l_store
|
||||
if(slot_r_store)
|
||||
return r_store
|
||||
if(slot_s_store)
|
||||
return s_store
|
||||
return null
|
||||
|
||||
/mob/living/carbon/human/get_all_slots()
|
||||
. = get_head_slots() | get_body_slots()
|
||||
|
||||
/mob/living/carbon/human/proc/get_body_slots()
|
||||
return list(
|
||||
l_hand,
|
||||
r_hand,
|
||||
back,
|
||||
s_store,
|
||||
handcuffed,
|
||||
legcuffed,
|
||||
wear_suit,
|
||||
gloves,
|
||||
shoes,
|
||||
belt,
|
||||
wear_id,
|
||||
wear_pda,
|
||||
l_store,
|
||||
r_store,
|
||||
w_uniform
|
||||
)
|
||||
|
||||
/mob/living/carbon/human/proc/get_head_slots()
|
||||
return list(
|
||||
head,
|
||||
wear_mask,
|
||||
glasses,
|
||||
r_ear,
|
||||
l_ear,
|
||||
)
|
||||
|
||||
// humans have their pickpocket gloves, so they get no message when stealing things
|
||||
/mob/living/carbon/human/stripPanelUnequip(obj/item/what, mob/who, where)
|
||||
var/is_silent = 0
|
||||
var/obj/item/clothing/gloves/G = gloves
|
||||
if(istype(G))
|
||||
is_silent = G.pickpocket
|
||||
|
||||
..(what, who, where, silent = is_silent)
|
||||
|
||||
// humans have their pickpocket gloves, so they get no message when stealing things
|
||||
/mob/living/carbon/human/stripPanelEquip(obj/item/what, mob/who, where)
|
||||
var/is_silent = 0
|
||||
var/obj/item/clothing/gloves/G = gloves
|
||||
if(istype(G))
|
||||
is_silent = G.pickpocket
|
||||
|
||||
..(what, who, where, silent = is_silent)
|
||||
|
||||
/mob/living/carbon/human/can_equip(obj/item/I, slot, disable_warning = FALSE)
|
||||
return dna.species.can_equip(I, slot, disable_warning, src)
|
||||
|
||||
/mob/living/carbon/human/proc/equipOutfit(outfit, visualsOnly = FALSE)
|
||||
var/datum/outfit/O = null
|
||||
|
||||
if(ispath(outfit))
|
||||
O = new outfit
|
||||
else
|
||||
O = outfit
|
||||
if(!istype(O))
|
||||
return 0
|
||||
if(!O)
|
||||
return 0
|
||||
|
||||
return O.equip(src, visualsOnly)
|
||||
|
||||
//delete all equipment without dropping anything
|
||||
/mob/living/carbon/human/proc/delete_equipment()
|
||||
for(var/slot in get_all_slots())//order matters, dependant slots go first
|
||||
qdel(slot)
|
||||
/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/is_in_hands(var/typepath)
|
||||
if(istype(l_hand,typepath))
|
||||
return l_hand
|
||||
if(istype(r_hand,typepath))
|
||||
return r_hand
|
||||
return 0
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/has_organ(name)
|
||||
var/obj/item/organ/external/O = bodyparts_by_name[name]
|
||||
return O
|
||||
|
||||
/mob/living/carbon/human/proc/has_organ_for_slot(slot)
|
||||
switch(slot)
|
||||
if(slot_back)
|
||||
return has_organ("chest")
|
||||
if(slot_wear_mask)
|
||||
return has_organ("head")
|
||||
if(slot_handcuffed)
|
||||
return has_organ("l_hand") && has_organ("r_hand")
|
||||
if(slot_legcuffed)
|
||||
return has_organ("l_leg") && has_organ("r_leg")
|
||||
if(slot_l_hand)
|
||||
return has_organ("l_hand")
|
||||
if(slot_r_hand)
|
||||
return has_organ("r_hand")
|
||||
if(slot_belt)
|
||||
return has_organ("chest")
|
||||
if(slot_wear_id)
|
||||
// the only relevant check for this is the uniform check
|
||||
return TRUE
|
||||
if(slot_wear_pda)
|
||||
return TRUE
|
||||
if(slot_l_ear)
|
||||
return has_organ("head")
|
||||
if(slot_r_ear)
|
||||
return has_organ("head")
|
||||
if(slot_glasses)
|
||||
return has_organ("head")
|
||||
if(slot_gloves)
|
||||
return has_organ("l_hand") && has_organ("r_hand")
|
||||
if(slot_head)
|
||||
return has_organ("head")
|
||||
if(slot_shoes)
|
||||
return has_organ("r_foot") && has_organ("l_foot")
|
||||
if(slot_wear_suit)
|
||||
return has_organ("chest")
|
||||
if(slot_w_uniform)
|
||||
return has_organ("chest")
|
||||
if(slot_l_store)
|
||||
return has_organ("chest")
|
||||
if(slot_r_store)
|
||||
return has_organ("chest")
|
||||
if(slot_s_store)
|
||||
return has_organ("chest")
|
||||
if(slot_in_backpack)
|
||||
return TRUE
|
||||
if(slot_tie)
|
||||
return TRUE
|
||||
|
||||
// The actual dropping happens at the mob level - checks to prevent drops should
|
||||
// come here
|
||||
/mob/living/carbon/human/canUnEquip(obj/item/I, force)
|
||||
. = ..()
|
||||
var/obj/item/organ/O = I
|
||||
if(istype(O) && O.owner == src)
|
||||
. = 0 // keep a good grip on your heart
|
||||
|
||||
/mob/living/carbon/human/unEquip(obj/item/I, force)
|
||||
. = ..() //See mob.dm for an explanation on this and some rage about people copypasting instead of calling ..() like they should.
|
||||
if(!. || !I)
|
||||
return
|
||||
|
||||
if(I == wear_suit)
|
||||
if(s_store)
|
||||
unEquip(s_store, 1) //It makes no sense for your suit storage to stay on you if you drop your suit.
|
||||
wear_suit = null
|
||||
if(I.flags_inv & HIDEJUMPSUIT)
|
||||
update_inv_w_uniform()
|
||||
update_inv_wear_suit()
|
||||
else if(I == w_uniform)
|
||||
if(r_store)
|
||||
unEquip(r_store, 1) //Again, makes sense for pockets to drop.
|
||||
if(l_store)
|
||||
unEquip(l_store, 1)
|
||||
if(wear_id)
|
||||
unEquip(wear_id)
|
||||
if(belt)
|
||||
unEquip(belt)
|
||||
w_uniform = null
|
||||
update_inv_w_uniform()
|
||||
else if(I == gloves)
|
||||
gloves = null
|
||||
update_inv_gloves()
|
||||
else if(I == glasses)
|
||||
glasses = null
|
||||
var/obj/item/clothing/glasses/G = I
|
||||
if(G.tint)
|
||||
update_tint()
|
||||
if(G.prescription)
|
||||
update_nearsighted_effects()
|
||||
if(G.vision_flags || G.see_in_dark || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
|
||||
update_sight()
|
||||
update_inv_glasses()
|
||||
update_client_colour()
|
||||
else if(I == head)
|
||||
head = null
|
||||
if(I.flags & BLOCKHAIR || I.flags & BLOCKHEADHAIR)
|
||||
update_hair() //rebuild hair
|
||||
update_fhair()
|
||||
update_head_accessory()
|
||||
// Bandanas and paper hats go on the head but are not head clothing
|
||||
if(istype(I,/obj/item/clothing/head))
|
||||
var/obj/item/clothing/head/hat = I
|
||||
if(hat.vision_flags || hat.see_in_dark || !isnull(hat.lighting_alpha))
|
||||
update_sight()
|
||||
head_update(I)
|
||||
update_inv_head()
|
||||
else if(I == r_ear)
|
||||
r_ear = null
|
||||
update_inv_ears()
|
||||
else if(I == l_ear)
|
||||
l_ear = null
|
||||
update_inv_ears()
|
||||
else if(I == shoes)
|
||||
shoes = null
|
||||
update_inv_shoes()
|
||||
else if(I == belt)
|
||||
belt = null
|
||||
update_inv_belt()
|
||||
else if(I == wear_mask)
|
||||
wear_mask = null
|
||||
if(I.flags & BLOCKHAIR || I.flags & BLOCKHEADHAIR)
|
||||
update_hair() //rebuild hair
|
||||
update_fhair()
|
||||
update_head_accessory()
|
||||
if(internal && !get_organ_slot("breathing_tube"))
|
||||
internal = null
|
||||
update_action_buttons_icon()
|
||||
wear_mask_update(I, toggle_off = FALSE)
|
||||
sec_hud_set_ID()
|
||||
update_inv_wear_mask()
|
||||
else if(I == wear_id)
|
||||
wear_id = null
|
||||
sec_hud_set_ID()
|
||||
update_inv_wear_id()
|
||||
else if(I == wear_pda)
|
||||
wear_pda = null
|
||||
update_inv_wear_pda()
|
||||
else if(I == r_store)
|
||||
r_store = null
|
||||
update_inv_pockets()
|
||||
else if(I == l_store)
|
||||
l_store = null
|
||||
update_inv_pockets()
|
||||
else if(I == s_store)
|
||||
s_store = null
|
||||
update_inv_s_store()
|
||||
else if(I == back)
|
||||
back = null
|
||||
update_inv_back()
|
||||
else if(I == r_hand)
|
||||
r_hand = null
|
||||
update_inv_r_hand()
|
||||
else if(I == l_hand)
|
||||
l_hand = null
|
||||
update_inv_l_hand()
|
||||
|
||||
|
||||
|
||||
|
||||
//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()
|
||||
//set redraw_mob to 0 if you don't wish the hud to be updated - if you're doing it manually in your own proc.
|
||||
/mob/living/carbon/human/equip_to_slot(obj/item/I, slot, redraw_mob = 1)
|
||||
if(!slot)
|
||||
return
|
||||
if(!istype(I))
|
||||
return
|
||||
if(!has_organ_for_slot(slot))
|
||||
return
|
||||
|
||||
if(I == src.l_hand)
|
||||
src.l_hand = null
|
||||
update_inv_l_hand() //So items actually disappear from hands.
|
||||
else if(I == src.r_hand)
|
||||
src.r_hand = null
|
||||
update_inv_r_hand()
|
||||
|
||||
I.screen_loc = null
|
||||
I.forceMove(src)
|
||||
I.equipped(src, slot)
|
||||
I.layer = ABOVE_HUD_LAYER
|
||||
I.plane = ABOVE_HUD_PLANE
|
||||
|
||||
switch(slot)
|
||||
if(slot_back)
|
||||
back = I
|
||||
update_inv_back(redraw_mob)
|
||||
if(slot_wear_mask)
|
||||
wear_mask = I
|
||||
if((wear_mask.flags & BLOCKHAIR) || (wear_mask.flags & BLOCKHEADHAIR))
|
||||
update_hair(redraw_mob) //rebuild hair
|
||||
update_fhair(redraw_mob)
|
||||
update_head_accessory(redraw_mob)
|
||||
if(hud_list.len)
|
||||
sec_hud_set_ID()
|
||||
wear_mask_update(I, toggle_off = TRUE)
|
||||
update_inv_wear_mask(redraw_mob)
|
||||
if(slot_handcuffed)
|
||||
handcuffed = I
|
||||
update_inv_handcuffed(redraw_mob)
|
||||
if(slot_legcuffed)
|
||||
legcuffed = I
|
||||
update_inv_legcuffed(redraw_mob)
|
||||
if(slot_l_hand)
|
||||
l_hand = I
|
||||
update_inv_l_hand(redraw_mob)
|
||||
if(slot_r_hand)
|
||||
r_hand = I
|
||||
update_inv_r_hand(redraw_mob)
|
||||
if(slot_belt)
|
||||
belt = I
|
||||
update_inv_belt(redraw_mob)
|
||||
if(slot_wear_id)
|
||||
wear_id = I
|
||||
if(hud_list.len)
|
||||
sec_hud_set_ID()
|
||||
update_inv_wear_id(redraw_mob)
|
||||
if(slot_wear_pda)
|
||||
wear_pda = I
|
||||
update_inv_wear_pda(redraw_mob)
|
||||
if(slot_l_ear)
|
||||
l_ear = I
|
||||
if(l_ear.slot_flags & SLOT_TWOEARS)
|
||||
var/obj/item/clothing/ears/offear/O = new(I)
|
||||
O.forceMove(src)
|
||||
r_ear = O
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
update_inv_ears(redraw_mob)
|
||||
if(slot_r_ear)
|
||||
r_ear = I
|
||||
if(r_ear.slot_flags & SLOT_TWOEARS)
|
||||
var/obj/item/clothing/ears/offear/O = new(I)
|
||||
O.forceMove(src)
|
||||
l_ear = O
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
update_inv_ears(redraw_mob)
|
||||
if(slot_glasses)
|
||||
glasses = I
|
||||
var/obj/item/clothing/glasses/G = I
|
||||
if(G.tint)
|
||||
update_tint()
|
||||
if(G.prescription)
|
||||
update_nearsighted_effects()
|
||||
if(G.vision_flags || G.see_in_dark || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
|
||||
update_sight()
|
||||
update_inv_glasses(redraw_mob)
|
||||
update_client_colour()
|
||||
if(slot_gloves)
|
||||
gloves = I
|
||||
update_inv_gloves(redraw_mob)
|
||||
if(slot_head)
|
||||
head = I
|
||||
if((head.flags & BLOCKHAIR) || (head.flags & BLOCKHEADHAIR))
|
||||
update_hair(redraw_mob) //rebuild hair
|
||||
update_fhair(redraw_mob)
|
||||
update_head_accessory(redraw_mob)
|
||||
// paper + bandanas
|
||||
if(istype(I, /obj/item/clothing/head))
|
||||
var/obj/item/clothing/head/hat = I
|
||||
if(hat.vision_flags || hat.see_in_dark || !isnull(hat.lighting_alpha))
|
||||
update_sight()
|
||||
head_update(I)
|
||||
update_inv_head(redraw_mob)
|
||||
if(slot_shoes)
|
||||
shoes = I
|
||||
update_inv_shoes(redraw_mob)
|
||||
if(slot_wear_suit)
|
||||
wear_suit = I
|
||||
update_inv_wear_suit(redraw_mob)
|
||||
if(slot_w_uniform)
|
||||
w_uniform = I
|
||||
update_inv_w_uniform(redraw_mob)
|
||||
if(slot_l_store)
|
||||
l_store = I
|
||||
update_inv_pockets(redraw_mob)
|
||||
if(slot_r_store)
|
||||
r_store = I
|
||||
update_inv_pockets(redraw_mob)
|
||||
if(slot_s_store)
|
||||
s_store = I
|
||||
update_inv_s_store(redraw_mob)
|
||||
if(slot_in_backpack)
|
||||
if(get_active_hand() == I)
|
||||
unEquip(I)
|
||||
I.forceMove(back)
|
||||
if(slot_tie)
|
||||
var/obj/item/clothing/under/uniform = src.w_uniform
|
||||
uniform.attackby(I, src)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You are trying to equip this item to an unsupported inventory slot. Report this to a coder!</span>")
|
||||
|
||||
/mob/living/carbon/human/put_in_hands(obj/item/I)
|
||||
if(!I)
|
||||
return FALSE
|
||||
if(put_in_active_hand(I))
|
||||
return TRUE
|
||||
else if(put_in_inactive_hand(I))
|
||||
return TRUE
|
||||
else
|
||||
. = ..()
|
||||
|
||||
// Return the item currently in the slot ID
|
||||
/mob/living/carbon/human/get_item_by_slot(slot_id)
|
||||
switch(slot_id)
|
||||
if(slot_back)
|
||||
return back
|
||||
if(slot_wear_mask)
|
||||
return wear_mask
|
||||
if(slot_handcuffed)
|
||||
return handcuffed
|
||||
if(slot_legcuffed)
|
||||
return legcuffed
|
||||
if(slot_l_hand)
|
||||
return l_hand
|
||||
if(slot_r_hand)
|
||||
return r_hand
|
||||
if(slot_belt)
|
||||
return belt
|
||||
if(slot_wear_id)
|
||||
return wear_id
|
||||
if(slot_wear_pda)
|
||||
return wear_pda
|
||||
if(slot_l_ear)
|
||||
return l_ear
|
||||
if(slot_r_ear)
|
||||
return r_ear
|
||||
if(slot_glasses)
|
||||
return glasses
|
||||
if(slot_gloves)
|
||||
return gloves
|
||||
if(slot_head)
|
||||
return head
|
||||
if(slot_shoes)
|
||||
return shoes
|
||||
if(slot_wear_suit)
|
||||
return wear_suit
|
||||
if(slot_w_uniform)
|
||||
return w_uniform
|
||||
if(slot_l_store)
|
||||
return l_store
|
||||
if(slot_r_store)
|
||||
return r_store
|
||||
if(slot_s_store)
|
||||
return s_store
|
||||
return null
|
||||
|
||||
/mob/living/carbon/human/get_all_slots()
|
||||
. = get_head_slots() | get_body_slots()
|
||||
|
||||
/mob/living/carbon/human/proc/get_body_slots()
|
||||
return list(
|
||||
l_hand,
|
||||
r_hand,
|
||||
back,
|
||||
s_store,
|
||||
handcuffed,
|
||||
legcuffed,
|
||||
wear_suit,
|
||||
gloves,
|
||||
shoes,
|
||||
belt,
|
||||
wear_id,
|
||||
wear_pda,
|
||||
l_store,
|
||||
r_store,
|
||||
w_uniform
|
||||
)
|
||||
|
||||
/mob/living/carbon/human/proc/get_head_slots()
|
||||
return list(
|
||||
head,
|
||||
wear_mask,
|
||||
glasses,
|
||||
r_ear,
|
||||
l_ear,
|
||||
)
|
||||
|
||||
// humans have their pickpocket gloves, so they get no message when stealing things
|
||||
/mob/living/carbon/human/stripPanelUnequip(obj/item/what, mob/who, where)
|
||||
var/is_silent = 0
|
||||
var/obj/item/clothing/gloves/G = gloves
|
||||
if(istype(G))
|
||||
is_silent = G.pickpocket
|
||||
|
||||
..(what, who, where, silent = is_silent)
|
||||
|
||||
// humans have their pickpocket gloves, so they get no message when stealing things
|
||||
/mob/living/carbon/human/stripPanelEquip(obj/item/what, mob/who, where)
|
||||
var/is_silent = 0
|
||||
var/obj/item/clothing/gloves/G = gloves
|
||||
if(istype(G))
|
||||
is_silent = G.pickpocket
|
||||
|
||||
..(what, who, where, silent = is_silent)
|
||||
|
||||
/mob/living/carbon/human/can_equip(obj/item/I, slot, disable_warning = FALSE)
|
||||
return dna.species.can_equip(I, slot, disable_warning, src)
|
||||
|
||||
/mob/living/carbon/human/proc/equipOutfit(outfit, visualsOnly = FALSE)
|
||||
var/datum/outfit/O = null
|
||||
|
||||
if(ispath(outfit))
|
||||
O = new outfit
|
||||
else
|
||||
O = outfit
|
||||
if(!istype(O))
|
||||
return 0
|
||||
if(!O)
|
||||
return 0
|
||||
|
||||
return O.equip(src, visualsOnly)
|
||||
|
||||
//delete all equipment without dropping anything
|
||||
/mob/living/carbon/human/proc/delete_equipment()
|
||||
for(var/slot in get_all_slots())//order matters, dependant slots go first
|
||||
qdel(slot)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
/mob/living/carbon/human/Login()
|
||||
if(player_logged)
|
||||
overlays -= image('icons/effects/effects.dmi', icon_state = "zzz_glow")
|
||||
..()
|
||||
|
||||
if(ventcrawler)
|
||||
to_chat(src, "<span class='notice'>You can ventcrawl! Use alt+click on vents to quickly travel about the station.</span>")
|
||||
update_pipe_vision()
|
||||
return
|
||||
/mob/living/carbon/human/Login()
|
||||
if(player_logged)
|
||||
overlays -= image('icons/effects/effects.dmi', icon_state = "zzz_glow")
|
||||
..()
|
||||
|
||||
if(ventcrawler)
|
||||
to_chat(src, "<span class='notice'>You can ventcrawl! Use alt+click on vents to quickly travel about the station.</span>")
|
||||
update_pipe_vision()
|
||||
return
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/mob/living/carbon/human/Logout()
|
||||
..()
|
||||
if(mind && mind.active && stat != DEAD)
|
||||
overlays += image('icons/effects/effects.dmi', icon_state = "zzz_glow")
|
||||
overlays += image('icons/effects/effects.dmi', icon_state = "zzz_glow")
|
||||
|
||||
@@ -1,259 +1,259 @@
|
||||
/mob/living/carbon/human/say(var/message, var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
|
||||
..(message, sanitize = sanitize, ignore_speech_problems = ignore_speech_problems, ignore_atmospherics = ignore_atmospherics) //ohgod we should really be passing a datum here.
|
||||
|
||||
/mob/living/carbon/human/GetAltName()
|
||||
if(name != GetVoice())
|
||||
return " (as [get_id_name("Unknown")])"
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/proc/forcesay(list/append)
|
||||
if(stat == CONSCIOUS)
|
||||
if(client)
|
||||
var/virgin = 1 //has the text been modified yet?
|
||||
var/temp = winget(client, "input", "text")
|
||||
if(findtextEx(temp, "Say \"", 1, 7) && length(temp) > 5) //case sensitive means
|
||||
|
||||
temp = replacetext(temp, ";", "") //general radio
|
||||
|
||||
if(findtext(trim_left(temp), ":", 6, 7)) //dept radio
|
||||
temp = copytext(trim_left(temp), 8)
|
||||
virgin = 0
|
||||
|
||||
if(virgin)
|
||||
temp = copytext(trim_left(temp), 6) //normal speech
|
||||
virgin = 0
|
||||
|
||||
while(findtext(trim_left(temp), ":", 1, 2)) //dept radio again (necessary)
|
||||
temp = copytext(trim_left(temp), 3)
|
||||
|
||||
if(findtext(temp, "*", 1, 2)) //emotes
|
||||
return
|
||||
temp = copytext(trim_left(temp), 1, rand(5,8))
|
||||
|
||||
var/trimmed = trim_left(temp)
|
||||
if(length(trimmed))
|
||||
if(append)
|
||||
temp += pick(append)
|
||||
|
||||
say(temp)
|
||||
winset(client, "input", "text=[null]")
|
||||
|
||||
/mob/living/carbon/human/say_understands(var/mob/other, var/datum/language/speaking = null)
|
||||
if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak.
|
||||
return 1
|
||||
|
||||
if(dna.species.can_understand(other))
|
||||
return 1
|
||||
|
||||
//These only pertain to common. Languages are handled by mob/say_understands()
|
||||
if(!speaking)
|
||||
if(istype(other, /mob/living/simple_animal/diona))
|
||||
if(other.languages.len >= 2) //They've sucked down some blood and can speak common now.
|
||||
return 1
|
||||
if(issilicon(other))
|
||||
return 1
|
||||
if(isbot(other))
|
||||
return 1
|
||||
if(isbrain(other))
|
||||
return 1
|
||||
if(isslime(other))
|
||||
return 1
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/proc/HasVoiceChanger()
|
||||
if(istype(back, /obj/item/rig))
|
||||
var/obj/item/rig/rig = back
|
||||
if(rig.speech && rig.speech.voice_holder && rig.speech.voice_holder.active && rig.speech.voice_holder.voice)
|
||||
return rig.speech.voice_holder.voice
|
||||
|
||||
for(var/obj/item/gear in list(wear_mask, wear_suit, head))
|
||||
if(!gear)
|
||||
continue
|
||||
|
||||
var/obj/item/voice_changer/changer = locate() in gear
|
||||
if(changer && changer.active)
|
||||
if(changer.voice)
|
||||
return changer.voice
|
||||
else if(wear_id)
|
||||
var/obj/item/card/id/idcard = wear_id.GetID()
|
||||
if(istype(idcard))
|
||||
return idcard.registered_name
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/GetVoice()
|
||||
var/has_changer = HasVoiceChanger()
|
||||
|
||||
if(has_changer)
|
||||
return has_changer
|
||||
|
||||
if(mind && mind.changeling && mind.changeling.mimicing)
|
||||
return mind.changeling.mimicing
|
||||
|
||||
if(GetSpecialVoice())
|
||||
return GetSpecialVoice()
|
||||
|
||||
return real_name
|
||||
|
||||
/mob/living/carbon/human/IsVocal()
|
||||
var/obj/item/organ/internal/cyberimp/brain/speech_translator/translator = locate(/obj/item/organ/internal/cyberimp/brain/speech_translator) in internal_organs
|
||||
if(translator && translator.active)
|
||||
return TRUE
|
||||
// how do species that don't breathe talk? magic, that's what.
|
||||
var/breathes = (!(NO_BREATHE in dna.species.species_traits))
|
||||
var/obj/item/organ/internal/L = get_organ_slot("lungs")
|
||||
if((breathes && !L) || breathes && L && (L.status & ORGAN_DEAD))
|
||||
return FALSE
|
||||
if(getOxyLoss() > 10 || losebreath >= 4)
|
||||
emote("gasp")
|
||||
return FALSE
|
||||
if(mind)
|
||||
return !mind.miming
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/proc/SetSpecialVoice(var/new_voice)
|
||||
if(new_voice)
|
||||
special_voice = new_voice
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/UnsetSpecialVoice()
|
||||
special_voice = ""
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/GetSpecialVoice()
|
||||
return special_voice
|
||||
|
||||
/mob/living/carbon/human/handle_speech_problems(list/message_pieces, var/verb)
|
||||
var/span = ""
|
||||
var/obj/item/organ/internal/cyberimp/brain/speech_translator/translator = locate(/obj/item/organ/internal/cyberimp/brain/speech_translator) in internal_organs
|
||||
if(translator)
|
||||
if(translator.active)
|
||||
span = translator.speech_span
|
||||
for(var/datum/multilingual_say_piece/S in message_pieces)
|
||||
S.message = "<span class='[span]'>[S.message]</span>"
|
||||
verb = translator.speech_verb
|
||||
return list("verb" = verb)
|
||||
if(mind)
|
||||
span = mind.speech_span
|
||||
if((COMIC in mutations) \
|
||||
|| (locate(/obj/item/organ/internal/cyberimp/brain/clown_voice) in internal_organs) \
|
||||
|| GetComponent(/datum/component/jestosterone))
|
||||
span = "sans"
|
||||
|
||||
if(WINGDINGS in mutations)
|
||||
span = "wingdings"
|
||||
|
||||
var/list/parent = ..()
|
||||
verb = parent["verb"]
|
||||
|
||||
for(var/datum/multilingual_say_piece/S in message_pieces)
|
||||
if(S.speaking && S.speaking.flags & NO_STUTTER)
|
||||
continue
|
||||
|
||||
if(silent || (disabilities & MUTE))
|
||||
S.message = ""
|
||||
|
||||
if(istype(wear_mask, /obj/item/clothing/mask/horsehead))
|
||||
var/obj/item/clothing/mask/horsehead/hoers = wear_mask
|
||||
if(hoers.voicechange)
|
||||
S.message = pick("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!")
|
||||
verb = pick("whinnies", "neighs", "says")
|
||||
|
||||
if(dna)
|
||||
for(var/datum/dna/gene/gene in dna_genes)
|
||||
if(!gene.block)
|
||||
continue
|
||||
if(gene.is_active(src))
|
||||
S.message = gene.OnSay(src, S.message)
|
||||
|
||||
var/braindam = getBrainLoss()
|
||||
if(braindam >= 60)
|
||||
if(prob(braindam / 4))
|
||||
S.message = stutter(S.message)
|
||||
verb = "gibbers"
|
||||
if(prob(braindam))
|
||||
S.message = uppertext(S.message)
|
||||
verb = "yells loudly"
|
||||
|
||||
if(span)
|
||||
S.message = "<span class='[span]'>[S.message]</span>"
|
||||
return list("verb" = verb)
|
||||
|
||||
/mob/living/carbon/human/handle_message_mode(var/message_mode, list/message_pieces, var/verb, var/used_radios)
|
||||
switch(message_mode)
|
||||
if("intercom")
|
||||
for(var/obj/item/radio/intercom/I in view(1, src))
|
||||
spawn(0)
|
||||
I.talk_into(src, message_pieces, null, verb)
|
||||
used_radios += I
|
||||
|
||||
if("headset")
|
||||
var/obj/item/radio/R = null
|
||||
if(isradio(l_ear))
|
||||
R = l_ear
|
||||
used_radios += R
|
||||
if(R.talk_into(src, message_pieces, null, verb))
|
||||
return
|
||||
|
||||
if(isradio(r_ear))
|
||||
R = r_ear
|
||||
used_radios += R
|
||||
if(R.talk_into(src, message_pieces, null, verb))
|
||||
return
|
||||
|
||||
if("right ear")
|
||||
var/obj/item/radio/R
|
||||
if(isradio(r_ear))
|
||||
R = r_ear
|
||||
else if(isradio(r_hand))
|
||||
R = r_hand
|
||||
if(R)
|
||||
used_radios += R
|
||||
R.talk_into(src, message_pieces, null, verb)
|
||||
|
||||
if("left ear")
|
||||
var/obj/item/radio/R
|
||||
if(isradio(l_ear))
|
||||
R = l_ear
|
||||
else if(isradio(l_hand))
|
||||
R = l_hand
|
||||
if(R)
|
||||
used_radios += R
|
||||
R.talk_into(src, message_pieces, null, verb)
|
||||
|
||||
if("whisper")
|
||||
whisper_say(message_pieces)
|
||||
return 1
|
||||
else
|
||||
if(message_mode)
|
||||
if(isradio(l_ear))
|
||||
used_radios += l_ear
|
||||
if(l_ear.talk_into(src, message_pieces, message_mode, verb))
|
||||
return
|
||||
|
||||
if(isradio(r_ear))
|
||||
used_radios += r_ear
|
||||
if(r_ear.talk_into(src, message_pieces, message_mode, verb))
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/handle_speech_sound()
|
||||
var/list/returns[3]
|
||||
if(dna.species.speech_sounds && prob(dna.species.speech_chance))
|
||||
returns[1] = sound(pick(dna.species.speech_sounds))
|
||||
returns[2] = 50
|
||||
returns[3] = get_age_pitch()
|
||||
return returns
|
||||
|
||||
/mob/living/carbon/human/binarycheck()
|
||||
. = FALSE
|
||||
var/obj/item/radio/headset/R
|
||||
if(istype(l_ear, /obj/item/radio/headset))
|
||||
R = l_ear
|
||||
if(R.translate_binary)
|
||||
. = TRUE
|
||||
|
||||
if(istype(r_ear, /obj/item/radio/headset))
|
||||
R = r_ear
|
||||
if(R.translate_binary)
|
||||
. = TRUE
|
||||
/mob/living/carbon/human/say(var/message, var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
|
||||
..(message, sanitize = sanitize, ignore_speech_problems = ignore_speech_problems, ignore_atmospherics = ignore_atmospherics) //ohgod we should really be passing a datum here.
|
||||
|
||||
/mob/living/carbon/human/GetAltName()
|
||||
if(name != GetVoice())
|
||||
return " (as [get_id_name("Unknown")])"
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/proc/forcesay(list/append)
|
||||
if(stat == CONSCIOUS)
|
||||
if(client)
|
||||
var/virgin = 1 //has the text been modified yet?
|
||||
var/temp = winget(client, "input", "text")
|
||||
if(findtextEx(temp, "Say \"", 1, 7) && length(temp) > 5) //case sensitive means
|
||||
|
||||
temp = replacetext(temp, ";", "") //general radio
|
||||
|
||||
if(findtext(trim_left(temp), ":", 6, 7)) //dept radio
|
||||
temp = copytext(trim_left(temp), 8)
|
||||
virgin = 0
|
||||
|
||||
if(virgin)
|
||||
temp = copytext(trim_left(temp), 6) //normal speech
|
||||
virgin = 0
|
||||
|
||||
while(findtext(trim_left(temp), ":", 1, 2)) //dept radio again (necessary)
|
||||
temp = copytext(trim_left(temp), 3)
|
||||
|
||||
if(findtext(temp, "*", 1, 2)) //emotes
|
||||
return
|
||||
temp = copytext(trim_left(temp), 1, rand(5,8))
|
||||
|
||||
var/trimmed = trim_left(temp)
|
||||
if(length(trimmed))
|
||||
if(append)
|
||||
temp += pick(append)
|
||||
|
||||
say(temp)
|
||||
winset(client, "input", "text=[null]")
|
||||
|
||||
/mob/living/carbon/human/say_understands(var/mob/other, var/datum/language/speaking = null)
|
||||
if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak.
|
||||
return 1
|
||||
|
||||
if(dna.species.can_understand(other))
|
||||
return 1
|
||||
|
||||
//These only pertain to common. Languages are handled by mob/say_understands()
|
||||
if(!speaking)
|
||||
if(istype(other, /mob/living/simple_animal/diona))
|
||||
if(other.languages.len >= 2) //They've sucked down some blood and can speak common now.
|
||||
return 1
|
||||
if(issilicon(other))
|
||||
return 1
|
||||
if(isbot(other))
|
||||
return 1
|
||||
if(isbrain(other))
|
||||
return 1
|
||||
if(isslime(other))
|
||||
return 1
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/proc/HasVoiceChanger()
|
||||
if(istype(back, /obj/item/rig))
|
||||
var/obj/item/rig/rig = back
|
||||
if(rig.speech && rig.speech.voice_holder && rig.speech.voice_holder.active && rig.speech.voice_holder.voice)
|
||||
return rig.speech.voice_holder.voice
|
||||
|
||||
for(var/obj/item/gear in list(wear_mask, wear_suit, head))
|
||||
if(!gear)
|
||||
continue
|
||||
|
||||
var/obj/item/voice_changer/changer = locate() in gear
|
||||
if(changer && changer.active)
|
||||
if(changer.voice)
|
||||
return changer.voice
|
||||
else if(wear_id)
|
||||
var/obj/item/card/id/idcard = wear_id.GetID()
|
||||
if(istype(idcard))
|
||||
return idcard.registered_name
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/GetVoice()
|
||||
var/has_changer = HasVoiceChanger()
|
||||
|
||||
if(has_changer)
|
||||
return has_changer
|
||||
|
||||
if(mind && mind.changeling && mind.changeling.mimicing)
|
||||
return mind.changeling.mimicing
|
||||
|
||||
if(GetSpecialVoice())
|
||||
return GetSpecialVoice()
|
||||
|
||||
return real_name
|
||||
|
||||
/mob/living/carbon/human/IsVocal()
|
||||
var/obj/item/organ/internal/cyberimp/brain/speech_translator/translator = locate(/obj/item/organ/internal/cyberimp/brain/speech_translator) in internal_organs
|
||||
if(translator && translator.active)
|
||||
return TRUE
|
||||
// how do species that don't breathe talk? magic, that's what.
|
||||
var/breathes = (!(NO_BREATHE in dna.species.species_traits))
|
||||
var/obj/item/organ/internal/L = get_organ_slot("lungs")
|
||||
if((breathes && !L) || breathes && L && (L.status & ORGAN_DEAD))
|
||||
return FALSE
|
||||
if(getOxyLoss() > 10 || losebreath >= 4)
|
||||
emote("gasp")
|
||||
return FALSE
|
||||
if(mind)
|
||||
return !mind.miming
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/proc/SetSpecialVoice(var/new_voice)
|
||||
if(new_voice)
|
||||
special_voice = new_voice
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/UnsetSpecialVoice()
|
||||
special_voice = ""
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/GetSpecialVoice()
|
||||
return special_voice
|
||||
|
||||
/mob/living/carbon/human/handle_speech_problems(list/message_pieces, var/verb)
|
||||
var/span = ""
|
||||
var/obj/item/organ/internal/cyberimp/brain/speech_translator/translator = locate(/obj/item/organ/internal/cyberimp/brain/speech_translator) in internal_organs
|
||||
if(translator)
|
||||
if(translator.active)
|
||||
span = translator.speech_span
|
||||
for(var/datum/multilingual_say_piece/S in message_pieces)
|
||||
S.message = "<span class='[span]'>[S.message]</span>"
|
||||
verb = translator.speech_verb
|
||||
return list("verb" = verb)
|
||||
if(mind)
|
||||
span = mind.speech_span
|
||||
if((COMIC in mutations) \
|
||||
|| (locate(/obj/item/organ/internal/cyberimp/brain/clown_voice) in internal_organs) \
|
||||
|| GetComponent(/datum/component/jestosterone))
|
||||
span = "sans"
|
||||
|
||||
if(WINGDINGS in mutations)
|
||||
span = "wingdings"
|
||||
|
||||
var/list/parent = ..()
|
||||
verb = parent["verb"]
|
||||
|
||||
for(var/datum/multilingual_say_piece/S in message_pieces)
|
||||
if(S.speaking && S.speaking.flags & NO_STUTTER)
|
||||
continue
|
||||
|
||||
if(silent || (disabilities & MUTE))
|
||||
S.message = ""
|
||||
|
||||
if(istype(wear_mask, /obj/item/clothing/mask/horsehead))
|
||||
var/obj/item/clothing/mask/horsehead/hoers = wear_mask
|
||||
if(hoers.voicechange)
|
||||
S.message = pick("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!")
|
||||
verb = pick("whinnies", "neighs", "says")
|
||||
|
||||
if(dna)
|
||||
for(var/datum/dna/gene/gene in dna_genes)
|
||||
if(!gene.block)
|
||||
continue
|
||||
if(gene.is_active(src))
|
||||
S.message = gene.OnSay(src, S.message)
|
||||
|
||||
var/braindam = getBrainLoss()
|
||||
if(braindam >= 60)
|
||||
if(prob(braindam / 4))
|
||||
S.message = stutter(S.message)
|
||||
verb = "gibbers"
|
||||
if(prob(braindam))
|
||||
S.message = uppertext(S.message)
|
||||
verb = "yells loudly"
|
||||
|
||||
if(span)
|
||||
S.message = "<span class='[span]'>[S.message]</span>"
|
||||
return list("verb" = verb)
|
||||
|
||||
/mob/living/carbon/human/handle_message_mode(var/message_mode, list/message_pieces, var/verb, var/used_radios)
|
||||
switch(message_mode)
|
||||
if("intercom")
|
||||
for(var/obj/item/radio/intercom/I in view(1, src))
|
||||
spawn(0)
|
||||
I.talk_into(src, message_pieces, null, verb)
|
||||
used_radios += I
|
||||
|
||||
if("headset")
|
||||
var/obj/item/radio/R = null
|
||||
if(isradio(l_ear))
|
||||
R = l_ear
|
||||
used_radios += R
|
||||
if(R.talk_into(src, message_pieces, null, verb))
|
||||
return
|
||||
|
||||
if(isradio(r_ear))
|
||||
R = r_ear
|
||||
used_radios += R
|
||||
if(R.talk_into(src, message_pieces, null, verb))
|
||||
return
|
||||
|
||||
if("right ear")
|
||||
var/obj/item/radio/R
|
||||
if(isradio(r_ear))
|
||||
R = r_ear
|
||||
else if(isradio(r_hand))
|
||||
R = r_hand
|
||||
if(R)
|
||||
used_radios += R
|
||||
R.talk_into(src, message_pieces, null, verb)
|
||||
|
||||
if("left ear")
|
||||
var/obj/item/radio/R
|
||||
if(isradio(l_ear))
|
||||
R = l_ear
|
||||
else if(isradio(l_hand))
|
||||
R = l_hand
|
||||
if(R)
|
||||
used_radios += R
|
||||
R.talk_into(src, message_pieces, null, verb)
|
||||
|
||||
if("whisper")
|
||||
whisper_say(message_pieces)
|
||||
return 1
|
||||
else
|
||||
if(message_mode)
|
||||
if(isradio(l_ear))
|
||||
used_radios += l_ear
|
||||
if(l_ear.talk_into(src, message_pieces, message_mode, verb))
|
||||
return
|
||||
|
||||
if(isradio(r_ear))
|
||||
used_radios += r_ear
|
||||
if(r_ear.talk_into(src, message_pieces, message_mode, verb))
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/handle_speech_sound()
|
||||
var/list/returns[3]
|
||||
if(dna.species.speech_sounds && prob(dna.species.speech_chance))
|
||||
returns[1] = sound(pick(dna.species.speech_sounds))
|
||||
returns[2] = 50
|
||||
returns[3] = get_age_pitch()
|
||||
return returns
|
||||
|
||||
/mob/living/carbon/human/binarycheck()
|
||||
. = FALSE
|
||||
var/obj/item/radio/headset/R
|
||||
if(istype(l_ear, /obj/item/radio/headset))
|
||||
R = l_ear
|
||||
if(R.translate_binary)
|
||||
. = TRUE
|
||||
|
||||
if(istype(r_ear, /obj/item/radio/headset))
|
||||
R = r_ear
|
||||
if(R.translate_binary)
|
||||
. = TRUE
|
||||
|
||||
@@ -980,4 +980,4 @@ It'll return null if the organ doesn't correspond, so include null checks when u
|
||||
. = FALSE
|
||||
var/obj/item/organ/internal/ears/ears = H.get_int_organ(/obj/item/organ/internal/ears)
|
||||
if(istype(ears) && !ears.deaf)
|
||||
. = TRUE
|
||||
. = TRUE
|
||||
|
||||
@@ -43,4 +43,4 @@
|
||||
/datum/species/abductor/on_species_loss(mob/living/carbon/human/H)
|
||||
..()
|
||||
var/datum/atom_hud/abductor_hud = huds[DATA_HUD_ABDUCTOR]
|
||||
abductor_hud.remove_hud_from(H)
|
||||
abductor_hud.remove_hud_from(H)
|
||||
|
||||
@@ -117,4 +117,4 @@
|
||||
/datum/species/diona/pod/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.faction -= "plants"
|
||||
C.faction -= "vines"
|
||||
C.faction -= "vines"
|
||||
|
||||
@@ -722,4 +722,4 @@
|
||||
H.mind.miming = TRUE
|
||||
|
||||
/datum/unarmed_attack/golem/tranquillite
|
||||
attack_sound = null
|
||||
attack_sound = null
|
||||
|
||||
@@ -18,4 +18,4 @@
|
||||
|
||||
reagent_tag = PROCESS_ORG
|
||||
//Has standard darksight of 2.
|
||||
|
||||
|
||||
|
||||
@@ -39,4 +39,4 @@
|
||||
"is twisting their own neck!",
|
||||
"is cracking their exoskeleton!",
|
||||
"is stabbing themselves with their mandibles!",
|
||||
"is holding their breath!")
|
||||
"is holding their breath!")
|
||||
|
||||
@@ -38,4 +38,4 @@
|
||||
var/turf/T = get_turf(H)
|
||||
H.visible_message("<span class='warning'>[H]'s body explodes, leaving behind a pile of microscopic crystals!</span>")
|
||||
explosion(T, 0, 0, 2, 2) // Create a small explosion burst upon death
|
||||
qdel(H)
|
||||
qdel(H)
|
||||
|
||||
@@ -70,4 +70,4 @@
|
||||
else if(light_amount < 2) //heal in the dark
|
||||
H.heal_overall_damage(1,1)
|
||||
H.clear_alert("lightexposure")
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -79,4 +79,4 @@
|
||||
H.adjustToxLoss(-5)
|
||||
H.adjustBrainLoss(-25)
|
||||
H.adjustCloneLoss(-1)
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -52,4 +52,4 @@
|
||||
|
||||
/datum/species/skrell/on_species_loss(mob/living/carbon/human/H)
|
||||
..()
|
||||
REMOVE_TRAIT(H, TRAIT_WATERBREATH, "species")
|
||||
REMOVE_TRAIT(H, TRAIT_WATERBREATH, "species")
|
||||
|
||||
@@ -196,4 +196,4 @@
|
||||
|
||||
#undef SLIMEPERSON_HUNGERCOST
|
||||
#undef SLIMEPERSON_MINHUNGER
|
||||
#undef SLIMEPERSON_REGROWTHDELAY
|
||||
#undef SLIMEPERSON_REGROWTHDELAY
|
||||
|
||||
@@ -56,4 +56,4 @@
|
||||
"is holding their breath!")
|
||||
|
||||
/datum/species/tajaran/handle_death(gibbed, mob/living/carbon/human/H)
|
||||
H.stop_tail_wagging(1)
|
||||
H.stop_tail_wagging(1)
|
||||
|
||||
@@ -50,4 +50,4 @@
|
||||
"is holding their breath!")
|
||||
|
||||
/datum/species/vulpkanin/handle_death(gibbed, mob/living/carbon/human/H)
|
||||
H.stop_tail_wagging(1)
|
||||
H.stop_tail_wagging(1)
|
||||
|
||||
@@ -75,4 +75,4 @@
|
||||
add_attack_logs(user, target, "Antennae removed")
|
||||
return 0
|
||||
else
|
||||
..()
|
||||
..()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,4 +24,4 @@
|
||||
. = dna.species.can_hear(src)
|
||||
|
||||
/mob/living/carbon/human/check_death_method()
|
||||
return dna.species.dies_at_threshold
|
||||
return dna.species.dies_at_threshold
|
||||
|
||||
@@ -437,4 +437,4 @@
|
||||
if(85 to INFINITY) severity = 6
|
||||
overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
|
||||
else
|
||||
clear_fullscreen("brute")
|
||||
clear_fullscreen("brute")
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
stam_paralyzed = TRUE
|
||||
update_canmove()
|
||||
if(!prev && getStaminaLoss() < 120) // Puts you a little further into the initial stamcrit, makes stamcrit harder to outright counter with chems.
|
||||
adjustStaminaLoss(30, FALSE)
|
||||
adjustStaminaLoss(30, FALSE)
|
||||
|
||||
@@ -87,4 +87,4 @@
|
||||
|
||||
//update whether our back item appears on our hud.
|
||||
/mob/living/carbon/proc/update_hud_back(obj/item/I)
|
||||
return
|
||||
return
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
. = FALSE
|
||||
var/obj/item/organ/internal/ears/ears = get_int_organ(/obj/item/organ/internal/ears)
|
||||
if(istype(ears) && !ears.deaf)
|
||||
. = TRUE
|
||||
. = TRUE
|
||||
|
||||
@@ -1,342 +1,342 @@
|
||||
|
||||
/*
|
||||
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/sharp = 0, var/used_weapon = null)
|
||||
blocked = (100-blocked)/100
|
||||
if(!damage || (blocked <= 0)) return 0
|
||||
switch(damagetype)
|
||||
if(BRUTE)
|
||||
adjustBruteLoss(damage * blocked)
|
||||
if(BURN)
|
||||
adjustFireLoss(damage * blocked)
|
||||
if(TOX)
|
||||
adjustToxLoss(damage * blocked)
|
||||
if(OXY)
|
||||
adjustOxyLoss(damage * blocked)
|
||||
if(CLONE)
|
||||
adjustCloneLoss(damage * blocked)
|
||||
if(STAMINA)
|
||||
adjustStaminaLoss(damage * blocked)
|
||||
updatehealth("apply damage")
|
||||
return 1
|
||||
|
||||
/mob/living/proc/apply_damage_type(damage = 0, damagetype = BRUTE) //like apply damage except it always uses the damage procs
|
||||
switch(damagetype)
|
||||
if(BRUTE)
|
||||
return adjustBruteLoss(damage)
|
||||
if(BURN)
|
||||
return adjustFireLoss(damage)
|
||||
if(TOX)
|
||||
return adjustToxLoss(damage)
|
||||
if(OXY)
|
||||
return adjustOxyLoss(damage)
|
||||
if(CLONE)
|
||||
return adjustCloneLoss(damage)
|
||||
if(STAMINA)
|
||||
return adjustStaminaLoss(damage)
|
||||
if(BRAIN)
|
||||
return adjustBrainLoss(damage)
|
||||
|
||||
/mob/living/proc/get_damage_amount(damagetype = BRUTE)
|
||||
switch(damagetype)
|
||||
if(BRUTE)
|
||||
return getBruteLoss()
|
||||
if(BURN)
|
||||
return getFireLoss()
|
||||
if(TOX)
|
||||
return getToxLoss()
|
||||
if(OXY)
|
||||
return getOxyLoss()
|
||||
if(CLONE)
|
||||
return getCloneLoss()
|
||||
if(STAMINA)
|
||||
return getStaminaLoss()
|
||||
|
||||
|
||||
/mob/living/proc/apply_damages(var/brute = 0, var/burn = 0, var/tox = 0, var/oxy = 0, var/clone = 0, var/def_zone = null, var/blocked = 0, var/stamina = 0)
|
||||
if(blocked >= 100) return 0
|
||||
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(stamina) apply_damage(stamina, STAMINA, def_zone, blocked)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
/mob/living/proc/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0, var/negate_armor = 0)
|
||||
blocked = (100-blocked)/100
|
||||
if(!effect || (blocked <= 0))
|
||||
return 0
|
||||
switch(effecttype)
|
||||
if(STUN)
|
||||
Stun(effect * blocked)
|
||||
if(WEAKEN)
|
||||
Weaken(effect * blocked)
|
||||
if(PARALYZE)
|
||||
Paralyse(effect * blocked)
|
||||
if(IRRADIATE)
|
||||
var/rad_damage = effect
|
||||
if(!negate_armor) // Setting negate_armor overrides radiation armor checks, which are automatic otherwise
|
||||
rad_damage = max(effect * ((100-run_armor_check(null, "rad", "Your clothes feel warm.", "Your clothes feel warm."))/100),0)
|
||||
radiation += rad_damage
|
||||
if(SLUR)
|
||||
Slur(effect * blocked)
|
||||
if(STUTTER)
|
||||
Stuttering(effect * blocked)
|
||||
if(EYE_BLUR)
|
||||
EyeBlurry(effect * blocked)
|
||||
if(DROWSY)
|
||||
Drowsy(effect * blocked)
|
||||
if(JITTER)
|
||||
if(status_flags & CANSTUN)
|
||||
Jitter(effect * blocked)
|
||||
updatehealth("apply effect")
|
||||
return 1
|
||||
|
||||
/mob/living/proc/apply_effects(var/stun = 0, var/weaken = 0, var/paralyze = 0, var/irradiate = 0, var/slur = 0, var/stutter = 0, var/eyeblur = 0, var/drowsy = 0, var/blocked = 0, var/stamina = 0, var/jitter = 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(slur) apply_effect(slur, SLUR, blocked)
|
||||
if(stutter) apply_effect(stutter, STUTTER, blocked)
|
||||
if(eyeblur) apply_effect(eyeblur, EYE_BLUR, blocked)
|
||||
if(drowsy) apply_effect(drowsy, DROWSY, blocked)
|
||||
if(stamina) apply_damage(stamina, STAMINA, null, blocked)
|
||||
if(jitter) apply_effect(jitter, JITTER, blocked)
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/proc/getBruteLoss()
|
||||
return bruteloss
|
||||
|
||||
/mob/living/proc/adjustBruteLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_bruteloss = bruteloss
|
||||
bruteloss = max(bruteloss + amount, 0)
|
||||
if(old_bruteloss == bruteloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("adjustBruteLoss")
|
||||
|
||||
/mob/living/proc/getOxyLoss()
|
||||
return oxyloss
|
||||
|
||||
/mob/living/proc/adjustOxyLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
oxyloss = 0
|
||||
return FALSE //godmode
|
||||
if(BREATHLESS in mutations)
|
||||
oxyloss = 0
|
||||
return FALSE
|
||||
var/old_oxyloss = oxyloss
|
||||
oxyloss = max(oxyloss + amount, 0)
|
||||
if(old_oxyloss == oxyloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("adjustOxyLoss")
|
||||
|
||||
/mob/living/proc/setOxyLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
oxyloss = 0
|
||||
return FALSE //godmode
|
||||
if(BREATHLESS in mutations)
|
||||
oxyloss = 0
|
||||
return FALSE
|
||||
var/old_oxyloss = oxyloss
|
||||
oxyloss = amount
|
||||
if(old_oxyloss == oxyloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("setOxyLoss")
|
||||
|
||||
/mob/living/proc/getToxLoss()
|
||||
return toxloss
|
||||
|
||||
/mob/living/proc/adjustToxLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_toxloss = toxloss
|
||||
toxloss = max(toxloss + amount, 0)
|
||||
if(old_toxloss == toxloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("adjustToxLoss")
|
||||
|
||||
/mob/living/proc/setToxLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_toxloss = toxloss
|
||||
toxloss = amount
|
||||
if(old_toxloss == toxloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("setToxLoss")
|
||||
|
||||
/mob/living/proc/getFireLoss()
|
||||
return fireloss
|
||||
|
||||
/mob/living/proc/adjustFireLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_fireloss = fireloss
|
||||
fireloss = max(fireloss + amount, 0)
|
||||
if(old_fireloss == fireloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("adjustFireLoss")
|
||||
|
||||
/mob/living/proc/getCloneLoss()
|
||||
return cloneloss
|
||||
|
||||
/mob/living/proc/adjustCloneLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_cloneloss = cloneloss
|
||||
cloneloss = max(cloneloss + amount, 0)
|
||||
if(old_cloneloss == cloneloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("adjustCloneLoss")
|
||||
|
||||
/mob/living/proc/setCloneLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_cloneloss = cloneloss
|
||||
cloneloss = amount
|
||||
if(old_cloneloss == cloneloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("setCloneLoss")
|
||||
|
||||
/mob/living/proc/getBrainLoss()
|
||||
return 0
|
||||
|
||||
/mob/living/proc/adjustBrainLoss(amount, updating = TRUE)
|
||||
return STATUS_UPDATE_NONE
|
||||
|
||||
/mob/living/proc/setBrainLoss(amount, updating = TRUE)
|
||||
return STATUS_UPDATE_NONE
|
||||
|
||||
/mob/living/proc/getStaminaLoss()
|
||||
return staminaloss
|
||||
|
||||
/mob/living/proc/adjustStaminaLoss(amount, updating = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE
|
||||
var/old_stamloss = staminaloss
|
||||
staminaloss = min(max(staminaloss + amount, 0), 120)
|
||||
if(old_stamloss == staminaloss)
|
||||
updating = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_STAMINA
|
||||
if(amount > 0)
|
||||
stam_regen_start_time = world.time + STAMINA_REGEN_BLOCK_TIME
|
||||
if(updating)
|
||||
update_stamina()
|
||||
|
||||
/mob/living/proc/setStaminaLoss(amount, updating = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE
|
||||
var/old_stamloss = staminaloss
|
||||
staminaloss = min(max(amount, 0), 120)
|
||||
if(old_stamloss == staminaloss)
|
||||
updating = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_STAMINA
|
||||
if(amount > 0)
|
||||
stam_regen_start_time = world.time + STAMINA_REGEN_BLOCK_TIME
|
||||
if(updating)
|
||||
update_stamina()
|
||||
|
||||
/mob/living/proc/getMaxHealth()
|
||||
return maxHealth
|
||||
|
||||
/mob/living/proc/setMaxHealth(var/newMaxHealth)
|
||||
maxHealth = newMaxHealth
|
||||
|
||||
|
||||
|
||||
// heal ONE external organ, organ gets randomly selected from damaged ones.
|
||||
/mob/living/proc/heal_organ_damage(brute, burn, updating_health = TRUE)
|
||||
adjustBruteLoss(-brute, FALSE)
|
||||
adjustFireLoss(-burn, FALSE)
|
||||
if(updating_health)
|
||||
updatehealth("heal organ damage")
|
||||
|
||||
// damage ONE external organ, organ gets randomly selected from damaged ones.
|
||||
/mob/living/proc/take_organ_damage(brute, burn, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
adjustBruteLoss(brute, FALSE)
|
||||
adjustFireLoss(burn, FALSE)
|
||||
if(updating_health)
|
||||
updatehealth("take organ damage")
|
||||
|
||||
// heal MANY external organs, in random order
|
||||
/mob/living/proc/heal_overall_damage(brute, burn, updating_health = TRUE)
|
||||
adjustBruteLoss(-brute, FALSE)
|
||||
adjustFireLoss(-burn, FALSE)
|
||||
if(updating_health)
|
||||
updatehealth("heal overall damage")
|
||||
|
||||
// damage MANY external organs, in random order
|
||||
/mob/living/proc/take_overall_damage(brute, burn, updating_health = TRUE, used_weapon = null)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
adjustBruteLoss(brute, FALSE)
|
||||
adjustFireLoss(burn, FALSE)
|
||||
if(updating_health)
|
||||
updatehealth("take overall damage")
|
||||
|
||||
/mob/living/proc/has_organic_damage()
|
||||
return (maxHealth - health)
|
||||
|
||||
//heal up to amount damage, in a given order
|
||||
/mob/living/proc/heal_ordered_damage(amount, list/damage_types)
|
||||
. = amount //we'll return the amount of damage healed
|
||||
for(var/i in damage_types)
|
||||
var/amount_to_heal = min(amount, get_damage_amount(i)) //heal only up to the amount of damage we have
|
||||
if(amount_to_heal)
|
||||
apply_damage_type(-amount_to_heal, i)
|
||||
amount -= amount_to_heal //remove what we healed from our current amount
|
||||
if(!amount)
|
||||
break
|
||||
. -= amount //if there's leftover healing, remove it from what we return
|
||||
|
||||
/*
|
||||
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/sharp = 0, var/used_weapon = null)
|
||||
blocked = (100-blocked)/100
|
||||
if(!damage || (blocked <= 0)) return 0
|
||||
switch(damagetype)
|
||||
if(BRUTE)
|
||||
adjustBruteLoss(damage * blocked)
|
||||
if(BURN)
|
||||
adjustFireLoss(damage * blocked)
|
||||
if(TOX)
|
||||
adjustToxLoss(damage * blocked)
|
||||
if(OXY)
|
||||
adjustOxyLoss(damage * blocked)
|
||||
if(CLONE)
|
||||
adjustCloneLoss(damage * blocked)
|
||||
if(STAMINA)
|
||||
adjustStaminaLoss(damage * blocked)
|
||||
updatehealth("apply damage")
|
||||
return 1
|
||||
|
||||
/mob/living/proc/apply_damage_type(damage = 0, damagetype = BRUTE) //like apply damage except it always uses the damage procs
|
||||
switch(damagetype)
|
||||
if(BRUTE)
|
||||
return adjustBruteLoss(damage)
|
||||
if(BURN)
|
||||
return adjustFireLoss(damage)
|
||||
if(TOX)
|
||||
return adjustToxLoss(damage)
|
||||
if(OXY)
|
||||
return adjustOxyLoss(damage)
|
||||
if(CLONE)
|
||||
return adjustCloneLoss(damage)
|
||||
if(STAMINA)
|
||||
return adjustStaminaLoss(damage)
|
||||
if(BRAIN)
|
||||
return adjustBrainLoss(damage)
|
||||
|
||||
/mob/living/proc/get_damage_amount(damagetype = BRUTE)
|
||||
switch(damagetype)
|
||||
if(BRUTE)
|
||||
return getBruteLoss()
|
||||
if(BURN)
|
||||
return getFireLoss()
|
||||
if(TOX)
|
||||
return getToxLoss()
|
||||
if(OXY)
|
||||
return getOxyLoss()
|
||||
if(CLONE)
|
||||
return getCloneLoss()
|
||||
if(STAMINA)
|
||||
return getStaminaLoss()
|
||||
|
||||
|
||||
/mob/living/proc/apply_damages(var/brute = 0, var/burn = 0, var/tox = 0, var/oxy = 0, var/clone = 0, var/def_zone = null, var/blocked = 0, var/stamina = 0)
|
||||
if(blocked >= 100) return 0
|
||||
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(stamina) apply_damage(stamina, STAMINA, def_zone, blocked)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
/mob/living/proc/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0, var/negate_armor = 0)
|
||||
blocked = (100-blocked)/100
|
||||
if(!effect || (blocked <= 0))
|
||||
return 0
|
||||
switch(effecttype)
|
||||
if(STUN)
|
||||
Stun(effect * blocked)
|
||||
if(WEAKEN)
|
||||
Weaken(effect * blocked)
|
||||
if(PARALYZE)
|
||||
Paralyse(effect * blocked)
|
||||
if(IRRADIATE)
|
||||
var/rad_damage = effect
|
||||
if(!negate_armor) // Setting negate_armor overrides radiation armor checks, which are automatic otherwise
|
||||
rad_damage = max(effect * ((100-run_armor_check(null, "rad", "Your clothes feel warm.", "Your clothes feel warm."))/100),0)
|
||||
radiation += rad_damage
|
||||
if(SLUR)
|
||||
Slur(effect * blocked)
|
||||
if(STUTTER)
|
||||
Stuttering(effect * blocked)
|
||||
if(EYE_BLUR)
|
||||
EyeBlurry(effect * blocked)
|
||||
if(DROWSY)
|
||||
Drowsy(effect * blocked)
|
||||
if(JITTER)
|
||||
if(status_flags & CANSTUN)
|
||||
Jitter(effect * blocked)
|
||||
updatehealth("apply effect")
|
||||
return 1
|
||||
|
||||
/mob/living/proc/apply_effects(var/stun = 0, var/weaken = 0, var/paralyze = 0, var/irradiate = 0, var/slur = 0, var/stutter = 0, var/eyeblur = 0, var/drowsy = 0, var/blocked = 0, var/stamina = 0, var/jitter = 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(slur) apply_effect(slur, SLUR, blocked)
|
||||
if(stutter) apply_effect(stutter, STUTTER, blocked)
|
||||
if(eyeblur) apply_effect(eyeblur, EYE_BLUR, blocked)
|
||||
if(drowsy) apply_effect(drowsy, DROWSY, blocked)
|
||||
if(stamina) apply_damage(stamina, STAMINA, null, blocked)
|
||||
if(jitter) apply_effect(jitter, JITTER, blocked)
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/proc/getBruteLoss()
|
||||
return bruteloss
|
||||
|
||||
/mob/living/proc/adjustBruteLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_bruteloss = bruteloss
|
||||
bruteloss = max(bruteloss + amount, 0)
|
||||
if(old_bruteloss == bruteloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("adjustBruteLoss")
|
||||
|
||||
/mob/living/proc/getOxyLoss()
|
||||
return oxyloss
|
||||
|
||||
/mob/living/proc/adjustOxyLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
oxyloss = 0
|
||||
return FALSE //godmode
|
||||
if(BREATHLESS in mutations)
|
||||
oxyloss = 0
|
||||
return FALSE
|
||||
var/old_oxyloss = oxyloss
|
||||
oxyloss = max(oxyloss + amount, 0)
|
||||
if(old_oxyloss == oxyloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("adjustOxyLoss")
|
||||
|
||||
/mob/living/proc/setOxyLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
oxyloss = 0
|
||||
return FALSE //godmode
|
||||
if(BREATHLESS in mutations)
|
||||
oxyloss = 0
|
||||
return FALSE
|
||||
var/old_oxyloss = oxyloss
|
||||
oxyloss = amount
|
||||
if(old_oxyloss == oxyloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("setOxyLoss")
|
||||
|
||||
/mob/living/proc/getToxLoss()
|
||||
return toxloss
|
||||
|
||||
/mob/living/proc/adjustToxLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_toxloss = toxloss
|
||||
toxloss = max(toxloss + amount, 0)
|
||||
if(old_toxloss == toxloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("adjustToxLoss")
|
||||
|
||||
/mob/living/proc/setToxLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_toxloss = toxloss
|
||||
toxloss = amount
|
||||
if(old_toxloss == toxloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("setToxLoss")
|
||||
|
||||
/mob/living/proc/getFireLoss()
|
||||
return fireloss
|
||||
|
||||
/mob/living/proc/adjustFireLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_fireloss = fireloss
|
||||
fireloss = max(fireloss + amount, 0)
|
||||
if(old_fireloss == fireloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("adjustFireLoss")
|
||||
|
||||
/mob/living/proc/getCloneLoss()
|
||||
return cloneloss
|
||||
|
||||
/mob/living/proc/adjustCloneLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_cloneloss = cloneloss
|
||||
cloneloss = max(cloneloss + amount, 0)
|
||||
if(old_cloneloss == cloneloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("adjustCloneLoss")
|
||||
|
||||
/mob/living/proc/setCloneLoss(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
var/old_cloneloss = cloneloss
|
||||
cloneloss = amount
|
||||
if(old_cloneloss == cloneloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth("setCloneLoss")
|
||||
|
||||
/mob/living/proc/getBrainLoss()
|
||||
return 0
|
||||
|
||||
/mob/living/proc/adjustBrainLoss(amount, updating = TRUE)
|
||||
return STATUS_UPDATE_NONE
|
||||
|
||||
/mob/living/proc/setBrainLoss(amount, updating = TRUE)
|
||||
return STATUS_UPDATE_NONE
|
||||
|
||||
/mob/living/proc/getStaminaLoss()
|
||||
return staminaloss
|
||||
|
||||
/mob/living/proc/adjustStaminaLoss(amount, updating = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE
|
||||
var/old_stamloss = staminaloss
|
||||
staminaloss = min(max(staminaloss + amount, 0), 120)
|
||||
if(old_stamloss == staminaloss)
|
||||
updating = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_STAMINA
|
||||
if(amount > 0)
|
||||
stam_regen_start_time = world.time + STAMINA_REGEN_BLOCK_TIME
|
||||
if(updating)
|
||||
update_stamina()
|
||||
|
||||
/mob/living/proc/setStaminaLoss(amount, updating = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE
|
||||
var/old_stamloss = staminaloss
|
||||
staminaloss = min(max(amount, 0), 120)
|
||||
if(old_stamloss == staminaloss)
|
||||
updating = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_STAMINA
|
||||
if(amount > 0)
|
||||
stam_regen_start_time = world.time + STAMINA_REGEN_BLOCK_TIME
|
||||
if(updating)
|
||||
update_stamina()
|
||||
|
||||
/mob/living/proc/getMaxHealth()
|
||||
return maxHealth
|
||||
|
||||
/mob/living/proc/setMaxHealth(var/newMaxHealth)
|
||||
maxHealth = newMaxHealth
|
||||
|
||||
|
||||
|
||||
// heal ONE external organ, organ gets randomly selected from damaged ones.
|
||||
/mob/living/proc/heal_organ_damage(brute, burn, updating_health = TRUE)
|
||||
adjustBruteLoss(-brute, FALSE)
|
||||
adjustFireLoss(-burn, FALSE)
|
||||
if(updating_health)
|
||||
updatehealth("heal organ damage")
|
||||
|
||||
// damage ONE external organ, organ gets randomly selected from damaged ones.
|
||||
/mob/living/proc/take_organ_damage(brute, burn, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
adjustBruteLoss(brute, FALSE)
|
||||
adjustFireLoss(burn, FALSE)
|
||||
if(updating_health)
|
||||
updatehealth("take organ damage")
|
||||
|
||||
// heal MANY external organs, in random order
|
||||
/mob/living/proc/heal_overall_damage(brute, burn, updating_health = TRUE)
|
||||
adjustBruteLoss(-brute, FALSE)
|
||||
adjustFireLoss(-burn, FALSE)
|
||||
if(updating_health)
|
||||
updatehealth("heal overall damage")
|
||||
|
||||
// damage MANY external organs, in random order
|
||||
/mob/living/proc/take_overall_damage(brute, burn, updating_health = TRUE, used_weapon = null)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE //godmode
|
||||
adjustBruteLoss(brute, FALSE)
|
||||
adjustFireLoss(burn, FALSE)
|
||||
if(updating_health)
|
||||
updatehealth("take overall damage")
|
||||
|
||||
/mob/living/proc/has_organic_damage()
|
||||
return (maxHealth - health)
|
||||
|
||||
//heal up to amount damage, in a given order
|
||||
/mob/living/proc/heal_ordered_damage(amount, list/damage_types)
|
||||
. = amount //we'll return the amount of damage healed
|
||||
for(var/i in damage_types)
|
||||
var/amount_to_heal = min(amount, get_damage_amount(i)) //heal only up to the amount of damage we have
|
||||
if(amount_to_heal)
|
||||
apply_damage_type(-amount_to_heal, i)
|
||||
amount -= amount_to_heal //remove what we healed from our current amount
|
||||
if(!amount)
|
||||
break
|
||||
. -= amount //if there's leftover healing, remove it from what we return
|
||||
|
||||
@@ -100,4 +100,4 @@
|
||||
visible_message("<span class='danger'><b>[src]</b> starts convulsing violently!</span>", "You feel as if your body is tearing itself apart!")
|
||||
Weaken(15)
|
||||
do_jitter_animation(1000, -1)
|
||||
addtimer(CALLBACK(src, .proc/gib), rand(20, 100))
|
||||
addtimer(CALLBACK(src, .proc/gib), rand(20, 100))
|
||||
|
||||
@@ -220,4 +220,4 @@
|
||||
return
|
||||
|
||||
/mob/living/proc/handle_hud_icons_health()
|
||||
return
|
||||
return
|
||||
|
||||
@@ -1,360 +1,360 @@
|
||||
|
||||
/*
|
||||
run_armor_check(a,b)
|
||||
args
|
||||
a:def_zone - What part is getting hit, if null will check entire body
|
||||
b:attack_flag - What type of attack, bullet, laser, energy, melee
|
||||
|
||||
Returns
|
||||
0 - no block
|
||||
1 - halfblock
|
||||
2 - fullblock
|
||||
*/
|
||||
/mob/living/proc/run_armor_check(var/def_zone = null, var/attack_flag = "melee", var/absorb_text = null, var/soften_text = null, armour_penetration, penetrated_text)
|
||||
var/armor = getarmor(def_zone, attack_flag)
|
||||
|
||||
//the if "armor" check is because this is used for everything on /living, including humans
|
||||
if(armor && armor < 100 && armour_penetration) // Armor with 100+ protection can not be penetrated for admin items
|
||||
armor = max(0, armor - armour_penetration)
|
||||
if(penetrated_text)
|
||||
to_chat(src, "<span class='userdanger'>[penetrated_text]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='userdanger'>Your armor was penetrated!</span>")
|
||||
|
||||
if(armor >= 100)
|
||||
if(absorb_text)
|
||||
to_chat(src, "<span class='userdanger'>[absorb_text]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='userdanger'>Your armor absorbs the blow!</span>")
|
||||
else if(armor > 0)
|
||||
if(soften_text)
|
||||
to_chat(src, "<span class='userdanger'>[soften_text]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='userdanger'>Your armor softens the blow!</span>")
|
||||
return armor
|
||||
|
||||
//if null is passed for def_zone, then this should return something appropriate for all zones (e.g. area effect damage)
|
||||
/mob/living/proc/getarmor(var/def_zone, var/type)
|
||||
return 0
|
||||
|
||||
/mob/living/proc/is_mouth_covered(head_only = FALSE, mask_only = FALSE)
|
||||
return FALSE
|
||||
|
||||
/mob/living/proc/is_eyes_covered(check_glasses = TRUE, check_head = TRUE, check_mask = TRUE)
|
||||
return FALSE
|
||||
|
||||
/mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone)
|
||||
//Armor
|
||||
var/armor = run_armor_check(def_zone, P.flag, armour_penetration = P.armour_penetration)
|
||||
if(!P.nodamage)
|
||||
apply_damage(P.damage, P.damage_type, def_zone, armor)
|
||||
if(P.dismemberment)
|
||||
check_projectile_dismemberment(P, def_zone)
|
||||
return P.on_hit(src, armor, def_zone)
|
||||
|
||||
/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
|
||||
return 0
|
||||
|
||||
/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, override = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_ELECTROCUTE_ACT, shock_damage)
|
||||
if(status_flags & GODMODE) //godmode
|
||||
return FALSE
|
||||
if(NO_SHOCK in mutations) //shockproof
|
||||
return FALSE
|
||||
if(tesla_shock && tesla_ignore)
|
||||
return FALSE
|
||||
if(shock_damage > 0)
|
||||
if(!illusion)
|
||||
adjustFireLoss(shock_damage)
|
||||
visible_message(
|
||||
"<span class='danger'>[src] was shocked by \the [source]!</span>",
|
||||
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>",
|
||||
"<span class='italics'>You hear a heavy electrical crack.</span>")
|
||||
return shock_damage
|
||||
|
||||
/mob/living/emp_act(severity)
|
||||
var/list/L = src.get_contents()
|
||||
for(var/obj/O in L)
|
||||
O.emp_act(severity)
|
||||
..()
|
||||
|
||||
/obj/item/proc/get_volume_by_throwforce_and_or_w_class()
|
||||
if(throwforce && w_class)
|
||||
return Clamp((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
|
||||
else if(w_class)
|
||||
return Clamp(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
|
||||
else
|
||||
return 0
|
||||
|
||||
//this proc handles being hit by a thrown atom
|
||||
/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/I = AM
|
||||
var/zone = ran_zone("chest", 65)//Hits a random part of the body, geared towards the chest
|
||||
var/dtype = BRUTE
|
||||
var/volume = I.get_volume_by_throwforce_and_or_w_class()
|
||||
SEND_SIGNAL(I, COMSIG_MOVABLE_IMPACT_ZONE, src, zone)
|
||||
dtype = I.damtype
|
||||
|
||||
if(I.throwforce > 0) //If the weapon's throwforce is greater than zero...
|
||||
if(I.throwhitsound) //...and throwhitsound is defined...
|
||||
playsound(loc, I.throwhitsound, volume, TRUE, -1) //...play the weapon's throwhitsound.
|
||||
else if(I.hitsound) //Otherwise, if the weapon's hitsound is defined...
|
||||
playsound(loc, I.hitsound, volume, TRUE, -1) //...play the weapon's hitsound.
|
||||
else if(!I.throwhitsound) //Otherwise, if throwhitsound isn't defined...
|
||||
playsound(loc, 'sound/weapons/genhit.ogg',volume, TRUE, -1) //...play genhit.ogg.
|
||||
|
||||
else if(!I.throwhitsound && I.throwforce > 0) //Otherwise, if the item doesn't have a throwhitsound and has a throwforce greater than zero...
|
||||
playsound(loc, 'sound/weapons/genhit1.ogg', volume, 1, -1)//...play genhit1.ogg
|
||||
if(!I.throwforce)// Otherwise, if the item's throwforce is 0...
|
||||
playsound(loc, 'sound/weapons/throwtap.ogg', 1, volume, -1)//...play throwtap.ogg.
|
||||
if(!blocked)
|
||||
visible_message("<span class='danger'>[src] has been hit by [I].</span>",
|
||||
"<span class='userdanger'>[src] has been hit by [I].</span>")
|
||||
var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].", I.armour_penetration)
|
||||
apply_damage(I.throwforce, dtype, zone, armor, is_sharp(I), I)
|
||||
if(I.thrownby)
|
||||
add_attack_logs(I.thrownby, src, "Hit with thrown [I]")
|
||||
else
|
||||
return 1
|
||||
else
|
||||
playsound(loc, 'sound/weapons/genhit.ogg', 50, TRUE, -1)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/mech_melee_attack(obj/mecha/M)
|
||||
if(M.occupant.a_intent == INTENT_HARM)
|
||||
if(HAS_TRAIT(M.occupant, TRAIT_PACIFISM))
|
||||
to_chat(M.occupant, "<span class='warning'>You don't want to harm other living beings!</span>")
|
||||
return
|
||||
M.do_attack_animation(src)
|
||||
if(M.damtype == "brute")
|
||||
step_away(src,M,15)
|
||||
switch(M.damtype)
|
||||
if("brute")
|
||||
Paralyse(1)
|
||||
take_overall_damage(rand(M.force/2, M.force))
|
||||
playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE)
|
||||
if("fire")
|
||||
take_overall_damage(0, rand(M.force/2, M.force))
|
||||
playsound(src, 'sound/items/welder.ogg', 50, TRUE)
|
||||
if("tox")
|
||||
M.mech_toxin_damage(src)
|
||||
else
|
||||
return
|
||||
updatehealth("mech melee attack")
|
||||
M.occupant_message("<span class='danger'>You hit [src].</span>")
|
||||
visible_message("<span class='danger'>[M.name] hits [src]!</span>", "<span class='userdanger'>[M.name] hits you!</span>")
|
||||
add_attack_logs(M.occupant, src, "Mecha-meleed with [M]")
|
||||
else
|
||||
step_away(src,M)
|
||||
add_attack_logs(M.occupant, src, "Mecha-pushed with [M]", ATKLOG_ALL)
|
||||
M.occupant_message("<span class='warning'>You push [src] out of the way.</span>")
|
||||
visible_message("<span class='warning'>[M] pushes [src] out of the way.</span>")
|
||||
|
||||
//Mobs on Fire
|
||||
/mob/living/proc/IgniteMob()
|
||||
if(fire_stacks > 0 && !on_fire)
|
||||
on_fire = 1
|
||||
visible_message("<span class='warning'>[src] catches fire!</span>", \
|
||||
"<span class='userdanger'>You're set on fire!</span>")
|
||||
set_light(light_range + 3,l_color = "#ED9200")
|
||||
throw_alert("fire", /obj/screen/alert/fire)
|
||||
update_fire()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/proc/ExtinguishMob()
|
||||
if(on_fire)
|
||||
on_fire = 0
|
||||
fire_stacks = 0
|
||||
set_light(max(0,light_range - 3))
|
||||
clear_alert("fire")
|
||||
update_fire()
|
||||
|
||||
/mob/living/proc/update_fire()
|
||||
return
|
||||
|
||||
/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
|
||||
fire_stacks = Clamp(fire_stacks + add_fire_stacks, -20, 20)
|
||||
if(on_fire && fire_stacks <= 0)
|
||||
ExtinguishMob()
|
||||
|
||||
/mob/living/proc/handle_fire()
|
||||
if(fire_stacks < 0) //If we've doused ourselves in water to avoid fire, dry off slowly
|
||||
fire_stacks = min(0, fire_stacks + 1)//So we dry ourselves back to default, nonflammable.
|
||||
if(!on_fire)
|
||||
return 1
|
||||
if(fire_stacks > 0)
|
||||
adjust_fire_stacks(-0.1) //the fire is slowly consumed
|
||||
else
|
||||
ExtinguishMob()
|
||||
return
|
||||
var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
|
||||
if(G.oxygen < 1)
|
||||
ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
|
||||
return
|
||||
var/turf/location = get_turf(src)
|
||||
location.hotspot_expose(700, 50, 1)
|
||||
|
||||
/mob/living/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
|
||||
..()
|
||||
adjust_fire_stacks(3)
|
||||
IgniteMob()
|
||||
|
||||
//Share fire evenly between the two mobs
|
||||
//Called in MobBump() and Crossed()
|
||||
/mob/living/proc/spreadFire(mob/living/L)
|
||||
if(!istype(L))
|
||||
return
|
||||
var/L_old_on_fire = L.on_fire
|
||||
|
||||
if(on_fire) //Only spread fire stacks if we're on fire
|
||||
fire_stacks /= 2
|
||||
L.fire_stacks += fire_stacks
|
||||
if(L.IgniteMob())
|
||||
log_game("[key_name(src)] bumped into [key_name(L)] and set them on fire")
|
||||
|
||||
if(L_old_on_fire) //Only ignite us and gain their stacks if they were onfire before we bumped them
|
||||
L.fire_stacks /= 2
|
||||
fire_stacks += L.fire_stacks
|
||||
IgniteMob()
|
||||
|
||||
/mob/living/can_be_pulled(user, grab_state, force)
|
||||
return ..() && !(buckled && buckled.buckle_prevents_pull)
|
||||
|
||||
/mob/living/water_act(volume, temperature, source, method = REAGENT_TOUCH)
|
||||
. = ..()
|
||||
adjust_fire_stacks(-(volume * 0.2))
|
||||
|
||||
//This is called when the mob is thrown into a dense turf
|
||||
/mob/living/proc/turf_collision(var/turf/T, var/speed)
|
||||
src.take_organ_damage(speed*5)
|
||||
|
||||
/mob/living/proc/near_wall(var/direction,var/distance=1)
|
||||
var/turf/T = get_step(get_turf(src),direction)
|
||||
var/turf/last_turf = src.loc
|
||||
var/i = 1
|
||||
|
||||
while(i>0 && i<=distance)
|
||||
if(T.density) //Turf is a wall!
|
||||
return last_turf
|
||||
i++
|
||||
last_turf = T
|
||||
T = get_step(T,direction)
|
||||
|
||||
return 0
|
||||
|
||||
// End BS12 momentum-transfer code.
|
||||
|
||||
/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = FALSE)
|
||||
if(user == src || anchored)
|
||||
return 0
|
||||
if(!(status_flags & CANPUSH))
|
||||
return 0
|
||||
|
||||
for(var/obj/item/grab/G in grabbed_by)
|
||||
if(G.assailant == user)
|
||||
to_chat(user, "<span class='notice'>You already grabbed [src].</span>")
|
||||
return
|
||||
|
||||
add_attack_logs(user, src, "Grabbed passively", ATKLOG_ALL)
|
||||
|
||||
var/obj/item/grab/G = new /obj/item/grab(user, src)
|
||||
if(buckled)
|
||||
to_chat(user, "<span class='notice'>You cannot grab [src]; [p_they()] [p_are()] buckled in!</span>")
|
||||
if(!G) //the grab will delete itself in New if src is anchored
|
||||
return 0
|
||||
user.put_in_active_hand(G)
|
||||
G.synch()
|
||||
LAssailant = user
|
||||
|
||||
playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
/*if(user.dir == src.dir)
|
||||
G.state = GRAB_AGGRESSIVE
|
||||
G.last_upgrade = world.time
|
||||
if(!supress_message)
|
||||
visible_message("<span class='warning'>[user] has grabbed [src] from behind!</span>")
|
||||
else*///This is an example of how you can make special types of grabs simply based on direction.
|
||||
if(!supress_message)
|
||||
visible_message("<span class='warning'>[user] has grabbed [src] passively!</span>")
|
||||
|
||||
return G
|
||||
|
||||
/mob/living/attack_slime(mob/living/simple_animal/slime/M)
|
||||
if(!SSticker)
|
||||
to_chat(M, "You cannot attack people before the game has started.")
|
||||
return
|
||||
|
||||
if(M.buckled)
|
||||
if(M in buckled_mobs)
|
||||
M.Feedstop()
|
||||
return // can't attack while eating!
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_PACIFISM))
|
||||
to_chat(M, "<span class='warning'>You don't want to hurt anyone!</span>")
|
||||
return FALSE
|
||||
|
||||
if(stat != DEAD)
|
||||
add_attack_logs(M, src, "Slime'd")
|
||||
M.do_attack_animation(src)
|
||||
visible_message("<span class='danger'>\The [M.name] glomps [src]!</span>", "<span class='userdanger'>\The [M.name] glomps you!</span>")
|
||||
return TRUE
|
||||
|
||||
/mob/living/attack_animal(mob/living/simple_animal/M)
|
||||
M.face_atom(src)
|
||||
if((M.a_intent == INTENT_HELP && M.ckey) || M.melee_damage_upper == 0)
|
||||
M.custom_emote(1, "[M.friendly] [src].")
|
||||
return FALSE
|
||||
if(HAS_TRAIT(M, TRAIT_PACIFISM))
|
||||
to_chat(M, "<span class='warning'>You don't want to hurt anyone!</span>")
|
||||
return FALSE
|
||||
|
||||
if(M.attack_sound)
|
||||
playsound(loc, M.attack_sound, 50, 1, 1)
|
||||
M.do_attack_animation(src)
|
||||
visible_message("<span class='danger'>\The [M] [M.attacktext] [src]!</span>", \
|
||||
"<span class='userdanger'>\The [M] [M.attacktext] [src]!</span>")
|
||||
add_attack_logs(M, src, "Animal attacked")
|
||||
return TRUE
|
||||
|
||||
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
|
||||
switch(L.a_intent)
|
||||
if(INTENT_HELP)
|
||||
visible_message("<span class='notice'>[L.name] rubs its head against [src].</span>")
|
||||
return 0
|
||||
|
||||
else
|
||||
if(HAS_TRAIT(L, TRAIT_PACIFISM))
|
||||
to_chat(L, "<span class='warning'>You don't want to hurt anyone!</span>")
|
||||
return
|
||||
|
||||
L.do_attack_animation(src)
|
||||
if(prob(90))
|
||||
add_attack_logs(L, src, "Larva attacked")
|
||||
visible_message("<span class='danger'>[L.name] bites [src]!</span>", \
|
||||
"<span class='userdanger'>[L.name] bites [src]!</span>")
|
||||
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
|
||||
return 1
|
||||
else
|
||||
visible_message("<span class='danger'>[L.name] has attempted to bite [src]!</span>", \
|
||||
"<span class='userdanger'>[L.name] has attempted to bite [src]!</span>")
|
||||
return 0
|
||||
|
||||
/mob/living/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
switch(M.a_intent)
|
||||
if(INTENT_HELP)
|
||||
visible_message("<span class='notice'>[M] caresses [src] with its scythe like arm.</span>")
|
||||
return FALSE
|
||||
if(INTENT_GRAB)
|
||||
grabbedby(M)
|
||||
return FALSE
|
||||
if(INTENT_HARM)
|
||||
if(HAS_TRAIT(M, TRAIT_PACIFISM))
|
||||
to_chat(M, "<span class='warning'>You don't want to hurt anyone!</span>")
|
||||
return FALSE
|
||||
M.do_attack_animation(src)
|
||||
return TRUE
|
||||
if(INTENT_DISARM)
|
||||
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
|
||||
return TRUE
|
||||
|
||||
/*
|
||||
run_armor_check(a,b)
|
||||
args
|
||||
a:def_zone - What part is getting hit, if null will check entire body
|
||||
b:attack_flag - What type of attack, bullet, laser, energy, melee
|
||||
|
||||
Returns
|
||||
0 - no block
|
||||
1 - halfblock
|
||||
2 - fullblock
|
||||
*/
|
||||
/mob/living/proc/run_armor_check(var/def_zone = null, var/attack_flag = "melee", var/absorb_text = null, var/soften_text = null, armour_penetration, penetrated_text)
|
||||
var/armor = getarmor(def_zone, attack_flag)
|
||||
|
||||
//the if "armor" check is because this is used for everything on /living, including humans
|
||||
if(armor && armor < 100 && armour_penetration) // Armor with 100+ protection can not be penetrated for admin items
|
||||
armor = max(0, armor - armour_penetration)
|
||||
if(penetrated_text)
|
||||
to_chat(src, "<span class='userdanger'>[penetrated_text]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='userdanger'>Your armor was penetrated!</span>")
|
||||
|
||||
if(armor >= 100)
|
||||
if(absorb_text)
|
||||
to_chat(src, "<span class='userdanger'>[absorb_text]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='userdanger'>Your armor absorbs the blow!</span>")
|
||||
else if(armor > 0)
|
||||
if(soften_text)
|
||||
to_chat(src, "<span class='userdanger'>[soften_text]</span>")
|
||||
else
|
||||
to_chat(src, "<span class='userdanger'>Your armor softens the blow!</span>")
|
||||
return armor
|
||||
|
||||
//if null is passed for def_zone, then this should return something appropriate for all zones (e.g. area effect damage)
|
||||
/mob/living/proc/getarmor(var/def_zone, var/type)
|
||||
return 0
|
||||
|
||||
/mob/living/proc/is_mouth_covered(head_only = FALSE, mask_only = FALSE)
|
||||
return FALSE
|
||||
|
||||
/mob/living/proc/is_eyes_covered(check_glasses = TRUE, check_head = TRUE, check_mask = TRUE)
|
||||
return FALSE
|
||||
|
||||
/mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone)
|
||||
//Armor
|
||||
var/armor = run_armor_check(def_zone, P.flag, armour_penetration = P.armour_penetration)
|
||||
if(!P.nodamage)
|
||||
apply_damage(P.damage, P.damage_type, def_zone, armor)
|
||||
if(P.dismemberment)
|
||||
check_projectile_dismemberment(P, def_zone)
|
||||
return P.on_hit(src, armor, def_zone)
|
||||
|
||||
/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
|
||||
return 0
|
||||
|
||||
/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, override = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_ELECTROCUTE_ACT, shock_damage)
|
||||
if(status_flags & GODMODE) //godmode
|
||||
return FALSE
|
||||
if(NO_SHOCK in mutations) //shockproof
|
||||
return FALSE
|
||||
if(tesla_shock && tesla_ignore)
|
||||
return FALSE
|
||||
if(shock_damage > 0)
|
||||
if(!illusion)
|
||||
adjustFireLoss(shock_damage)
|
||||
visible_message(
|
||||
"<span class='danger'>[src] was shocked by \the [source]!</span>",
|
||||
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>",
|
||||
"<span class='italics'>You hear a heavy electrical crack.</span>")
|
||||
return shock_damage
|
||||
|
||||
/mob/living/emp_act(severity)
|
||||
var/list/L = src.get_contents()
|
||||
for(var/obj/O in L)
|
||||
O.emp_act(severity)
|
||||
..()
|
||||
|
||||
/obj/item/proc/get_volume_by_throwforce_and_or_w_class()
|
||||
if(throwforce && w_class)
|
||||
return Clamp((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
|
||||
else if(w_class)
|
||||
return Clamp(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
|
||||
else
|
||||
return 0
|
||||
|
||||
//this proc handles being hit by a thrown atom
|
||||
/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/I = AM
|
||||
var/zone = ran_zone("chest", 65)//Hits a random part of the body, geared towards the chest
|
||||
var/dtype = BRUTE
|
||||
var/volume = I.get_volume_by_throwforce_and_or_w_class()
|
||||
SEND_SIGNAL(I, COMSIG_MOVABLE_IMPACT_ZONE, src, zone)
|
||||
dtype = I.damtype
|
||||
|
||||
if(I.throwforce > 0) //If the weapon's throwforce is greater than zero...
|
||||
if(I.throwhitsound) //...and throwhitsound is defined...
|
||||
playsound(loc, I.throwhitsound, volume, TRUE, -1) //...play the weapon's throwhitsound.
|
||||
else if(I.hitsound) //Otherwise, if the weapon's hitsound is defined...
|
||||
playsound(loc, I.hitsound, volume, TRUE, -1) //...play the weapon's hitsound.
|
||||
else if(!I.throwhitsound) //Otherwise, if throwhitsound isn't defined...
|
||||
playsound(loc, 'sound/weapons/genhit.ogg',volume, TRUE, -1) //...play genhit.ogg.
|
||||
|
||||
else if(!I.throwhitsound && I.throwforce > 0) //Otherwise, if the item doesn't have a throwhitsound and has a throwforce greater than zero...
|
||||
playsound(loc, 'sound/weapons/genhit1.ogg', volume, 1, -1)//...play genhit1.ogg
|
||||
if(!I.throwforce)// Otherwise, if the item's throwforce is 0...
|
||||
playsound(loc, 'sound/weapons/throwtap.ogg', 1, volume, -1)//...play throwtap.ogg.
|
||||
if(!blocked)
|
||||
visible_message("<span class='danger'>[src] has been hit by [I].</span>",
|
||||
"<span class='userdanger'>[src] has been hit by [I].</span>")
|
||||
var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].", I.armour_penetration)
|
||||
apply_damage(I.throwforce, dtype, zone, armor, is_sharp(I), I)
|
||||
if(I.thrownby)
|
||||
add_attack_logs(I.thrownby, src, "Hit with thrown [I]")
|
||||
else
|
||||
return 1
|
||||
else
|
||||
playsound(loc, 'sound/weapons/genhit.ogg', 50, TRUE, -1)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/mech_melee_attack(obj/mecha/M)
|
||||
if(M.occupant.a_intent == INTENT_HARM)
|
||||
if(HAS_TRAIT(M.occupant, TRAIT_PACIFISM))
|
||||
to_chat(M.occupant, "<span class='warning'>You don't want to harm other living beings!</span>")
|
||||
return
|
||||
M.do_attack_animation(src)
|
||||
if(M.damtype == "brute")
|
||||
step_away(src,M,15)
|
||||
switch(M.damtype)
|
||||
if("brute")
|
||||
Paralyse(1)
|
||||
take_overall_damage(rand(M.force/2, M.force))
|
||||
playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE)
|
||||
if("fire")
|
||||
take_overall_damage(0, rand(M.force/2, M.force))
|
||||
playsound(src, 'sound/items/welder.ogg', 50, TRUE)
|
||||
if("tox")
|
||||
M.mech_toxin_damage(src)
|
||||
else
|
||||
return
|
||||
updatehealth("mech melee attack")
|
||||
M.occupant_message("<span class='danger'>You hit [src].</span>")
|
||||
visible_message("<span class='danger'>[M.name] hits [src]!</span>", "<span class='userdanger'>[M.name] hits you!</span>")
|
||||
add_attack_logs(M.occupant, src, "Mecha-meleed with [M]")
|
||||
else
|
||||
step_away(src,M)
|
||||
add_attack_logs(M.occupant, src, "Mecha-pushed with [M]", ATKLOG_ALL)
|
||||
M.occupant_message("<span class='warning'>You push [src] out of the way.</span>")
|
||||
visible_message("<span class='warning'>[M] pushes [src] out of the way.</span>")
|
||||
|
||||
//Mobs on Fire
|
||||
/mob/living/proc/IgniteMob()
|
||||
if(fire_stacks > 0 && !on_fire)
|
||||
on_fire = 1
|
||||
visible_message("<span class='warning'>[src] catches fire!</span>", \
|
||||
"<span class='userdanger'>You're set on fire!</span>")
|
||||
set_light(light_range + 3,l_color = "#ED9200")
|
||||
throw_alert("fire", /obj/screen/alert/fire)
|
||||
update_fire()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/proc/ExtinguishMob()
|
||||
if(on_fire)
|
||||
on_fire = 0
|
||||
fire_stacks = 0
|
||||
set_light(max(0,light_range - 3))
|
||||
clear_alert("fire")
|
||||
update_fire()
|
||||
|
||||
/mob/living/proc/update_fire()
|
||||
return
|
||||
|
||||
/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
|
||||
fire_stacks = Clamp(fire_stacks + add_fire_stacks, -20, 20)
|
||||
if(on_fire && fire_stacks <= 0)
|
||||
ExtinguishMob()
|
||||
|
||||
/mob/living/proc/handle_fire()
|
||||
if(fire_stacks < 0) //If we've doused ourselves in water to avoid fire, dry off slowly
|
||||
fire_stacks = min(0, fire_stacks + 1)//So we dry ourselves back to default, nonflammable.
|
||||
if(!on_fire)
|
||||
return 1
|
||||
if(fire_stacks > 0)
|
||||
adjust_fire_stacks(-0.1) //the fire is slowly consumed
|
||||
else
|
||||
ExtinguishMob()
|
||||
return
|
||||
var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
|
||||
if(G.oxygen < 1)
|
||||
ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
|
||||
return
|
||||
var/turf/location = get_turf(src)
|
||||
location.hotspot_expose(700, 50, 1)
|
||||
|
||||
/mob/living/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
|
||||
..()
|
||||
adjust_fire_stacks(3)
|
||||
IgniteMob()
|
||||
|
||||
//Share fire evenly between the two mobs
|
||||
//Called in MobBump() and Crossed()
|
||||
/mob/living/proc/spreadFire(mob/living/L)
|
||||
if(!istype(L))
|
||||
return
|
||||
var/L_old_on_fire = L.on_fire
|
||||
|
||||
if(on_fire) //Only spread fire stacks if we're on fire
|
||||
fire_stacks /= 2
|
||||
L.fire_stacks += fire_stacks
|
||||
if(L.IgniteMob())
|
||||
log_game("[key_name(src)] bumped into [key_name(L)] and set them on fire")
|
||||
|
||||
if(L_old_on_fire) //Only ignite us and gain their stacks if they were onfire before we bumped them
|
||||
L.fire_stacks /= 2
|
||||
fire_stacks += L.fire_stacks
|
||||
IgniteMob()
|
||||
|
||||
/mob/living/can_be_pulled(user, grab_state, force)
|
||||
return ..() && !(buckled && buckled.buckle_prevents_pull)
|
||||
|
||||
/mob/living/water_act(volume, temperature, source, method = REAGENT_TOUCH)
|
||||
. = ..()
|
||||
adjust_fire_stacks(-(volume * 0.2))
|
||||
|
||||
//This is called when the mob is thrown into a dense turf
|
||||
/mob/living/proc/turf_collision(var/turf/T, var/speed)
|
||||
src.take_organ_damage(speed*5)
|
||||
|
||||
/mob/living/proc/near_wall(var/direction,var/distance=1)
|
||||
var/turf/T = get_step(get_turf(src),direction)
|
||||
var/turf/last_turf = src.loc
|
||||
var/i = 1
|
||||
|
||||
while(i>0 && i<=distance)
|
||||
if(T.density) //Turf is a wall!
|
||||
return last_turf
|
||||
i++
|
||||
last_turf = T
|
||||
T = get_step(T,direction)
|
||||
|
||||
return 0
|
||||
|
||||
// End BS12 momentum-transfer code.
|
||||
|
||||
/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = FALSE)
|
||||
if(user == src || anchored)
|
||||
return 0
|
||||
if(!(status_flags & CANPUSH))
|
||||
return 0
|
||||
|
||||
for(var/obj/item/grab/G in grabbed_by)
|
||||
if(G.assailant == user)
|
||||
to_chat(user, "<span class='notice'>You already grabbed [src].</span>")
|
||||
return
|
||||
|
||||
add_attack_logs(user, src, "Grabbed passively", ATKLOG_ALL)
|
||||
|
||||
var/obj/item/grab/G = new /obj/item/grab(user, src)
|
||||
if(buckled)
|
||||
to_chat(user, "<span class='notice'>You cannot grab [src]; [p_they()] [p_are()] buckled in!</span>")
|
||||
if(!G) //the grab will delete itself in New if src is anchored
|
||||
return 0
|
||||
user.put_in_active_hand(G)
|
||||
G.synch()
|
||||
LAssailant = user
|
||||
|
||||
playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
/*if(user.dir == src.dir)
|
||||
G.state = GRAB_AGGRESSIVE
|
||||
G.last_upgrade = world.time
|
||||
if(!supress_message)
|
||||
visible_message("<span class='warning'>[user] has grabbed [src] from behind!</span>")
|
||||
else*///This is an example of how you can make special types of grabs simply based on direction.
|
||||
if(!supress_message)
|
||||
visible_message("<span class='warning'>[user] has grabbed [src] passively!</span>")
|
||||
|
||||
return G
|
||||
|
||||
/mob/living/attack_slime(mob/living/simple_animal/slime/M)
|
||||
if(!SSticker)
|
||||
to_chat(M, "You cannot attack people before the game has started.")
|
||||
return
|
||||
|
||||
if(M.buckled)
|
||||
if(M in buckled_mobs)
|
||||
M.Feedstop()
|
||||
return // can't attack while eating!
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_PACIFISM))
|
||||
to_chat(M, "<span class='warning'>You don't want to hurt anyone!</span>")
|
||||
return FALSE
|
||||
|
||||
if(stat != DEAD)
|
||||
add_attack_logs(M, src, "Slime'd")
|
||||
M.do_attack_animation(src)
|
||||
visible_message("<span class='danger'>\The [M.name] glomps [src]!</span>", "<span class='userdanger'>\The [M.name] glomps you!</span>")
|
||||
return TRUE
|
||||
|
||||
/mob/living/attack_animal(mob/living/simple_animal/M)
|
||||
M.face_atom(src)
|
||||
if((M.a_intent == INTENT_HELP && M.ckey) || M.melee_damage_upper == 0)
|
||||
M.custom_emote(1, "[M.friendly] [src].")
|
||||
return FALSE
|
||||
if(HAS_TRAIT(M, TRAIT_PACIFISM))
|
||||
to_chat(M, "<span class='warning'>You don't want to hurt anyone!</span>")
|
||||
return FALSE
|
||||
|
||||
if(M.attack_sound)
|
||||
playsound(loc, M.attack_sound, 50, 1, 1)
|
||||
M.do_attack_animation(src)
|
||||
visible_message("<span class='danger'>\The [M] [M.attacktext] [src]!</span>", \
|
||||
"<span class='userdanger'>\The [M] [M.attacktext] [src]!</span>")
|
||||
add_attack_logs(M, src, "Animal attacked")
|
||||
return TRUE
|
||||
|
||||
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
|
||||
switch(L.a_intent)
|
||||
if(INTENT_HELP)
|
||||
visible_message("<span class='notice'>[L.name] rubs its head against [src].</span>")
|
||||
return 0
|
||||
|
||||
else
|
||||
if(HAS_TRAIT(L, TRAIT_PACIFISM))
|
||||
to_chat(L, "<span class='warning'>You don't want to hurt anyone!</span>")
|
||||
return
|
||||
|
||||
L.do_attack_animation(src)
|
||||
if(prob(90))
|
||||
add_attack_logs(L, src, "Larva attacked")
|
||||
visible_message("<span class='danger'>[L.name] bites [src]!</span>", \
|
||||
"<span class='userdanger'>[L.name] bites [src]!</span>")
|
||||
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
|
||||
return 1
|
||||
else
|
||||
visible_message("<span class='danger'>[L.name] has attempted to bite [src]!</span>", \
|
||||
"<span class='userdanger'>[L.name] has attempted to bite [src]!</span>")
|
||||
return 0
|
||||
|
||||
/mob/living/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
switch(M.a_intent)
|
||||
if(INTENT_HELP)
|
||||
visible_message("<span class='notice'>[M] caresses [src] with its scythe like arm.</span>")
|
||||
return FALSE
|
||||
if(INTENT_GRAB)
|
||||
grabbedby(M)
|
||||
return FALSE
|
||||
if(INTENT_HARM)
|
||||
if(HAS_TRAIT(M, TRAIT_PACIFISM))
|
||||
to_chat(M, "<span class='warning'>You don't want to hurt anyone!</span>")
|
||||
return FALSE
|
||||
M.do_attack_animation(src)
|
||||
return TRUE
|
||||
if(INTENT_DISARM)
|
||||
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
|
||||
return TRUE
|
||||
|
||||
@@ -1,74 +1,74 @@
|
||||
/mob/living
|
||||
see_invisible = SEE_INVISIBLE_LIVING
|
||||
pressure_resistance = 10
|
||||
|
||||
//Health and life related vars
|
||||
var/maxHealth = 100 //Maximum health that should be possible.
|
||||
var/health = 100 //A mob's health
|
||||
|
||||
|
||||
//Damage related vars, NOTE: THESE SHOULD ONLY BE MODIFIED BY PROCS
|
||||
var/bruteloss = 0 //Brutal damage caused by brute force (punching, being clubbed by a toolbox ect... this also accounts for pressure damage)
|
||||
var/oxyloss = 0 //Oxygen depravation damage (no air in lungs)
|
||||
var/toxloss = 0 //Toxic damage caused by being poisoned or radiated
|
||||
var/fireloss = 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/staminaloss = 0 //Stamina damage, or exhaustion. You recover it slowly naturally, and are stunned if it gets too high. Holodeck and hallucinations deal this.
|
||||
|
||||
|
||||
var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out.
|
||||
|
||||
//Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects.
|
||||
var/incorporeal_move = 0 //0 is off, 1 is normal, 2 is for ninjas.
|
||||
|
||||
var/now_pushing = null
|
||||
|
||||
var/atom/movable/cameraFollow = null
|
||||
|
||||
var/on_fire = 0 //The "Are we on fire?" var
|
||||
var/fire_stacks = 0 //Tracks how many stacks of fire we have on, max is usually 20
|
||||
|
||||
var/implanting = 0 //Used for the mind-slave implant
|
||||
var/floating = 0
|
||||
var/mob_size = MOB_SIZE_HUMAN
|
||||
var/metabolism_efficiency = 1 //more or less efficiency to metabolize helpful/harmful reagents and regulate body temperature..
|
||||
var/digestion_ratio = 1 //controls how quickly reagents metabolize; largely governered by species attributes.
|
||||
|
||||
var/bloodcrawl = 0 //0 No blood crawling, 1 blood crawling, 2 blood crawling+mob devour
|
||||
var/holder = null //The holder for blood crawling
|
||||
|
||||
var/ventcrawler = 0 //0 No vent crawling, 1 vent crawling in the nude, 2 vent crawling always
|
||||
var/list/icon/pipes_shown = list()
|
||||
var/last_played_vent
|
||||
|
||||
var/smoke_delay = 0 //used to prevent spam with smoke reagent reaction on mob.
|
||||
|
||||
var/step_count = 0
|
||||
|
||||
var/list/butcher_results = null
|
||||
|
||||
var/list/weather_immunities = list()
|
||||
|
||||
var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them.
|
||||
|
||||
var/gene_stability = DEFAULT_GENE_STABILITY
|
||||
var/ignore_gene_stability = 0
|
||||
|
||||
var/obj/effect/proc_holder/ranged_ability //Any ranged ability the mob has, as a click override
|
||||
|
||||
var/tesla_ignore = FALSE
|
||||
|
||||
var/list/say_log = list() //a log of what we've said, plain text, no spans or junk, essentially just each individual "message"
|
||||
var/list/emote_log = list() //like say_log but for emotes
|
||||
|
||||
var/list/recent_tastes = list()
|
||||
var/blood_volume = 0 //how much blood the mob has
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,SPECIALROLE_HUD)
|
||||
|
||||
var/list/status_effects //a list of all status effects the mob has
|
||||
|
||||
var/deathgasp_on_death = FALSE
|
||||
|
||||
var/stun_absorption = null //converted to a list of stun absorption sources this mob has when one is added
|
||||
var/stam_regen_start_time = 0 //used to halt stamina regen temporarily
|
||||
var/stam_paralyzed = FALSE //knocks you down
|
||||
/mob/living
|
||||
see_invisible = SEE_INVISIBLE_LIVING
|
||||
pressure_resistance = 10
|
||||
|
||||
//Health and life related vars
|
||||
var/maxHealth = 100 //Maximum health that should be possible.
|
||||
var/health = 100 //A mob's health
|
||||
|
||||
|
||||
//Damage related vars, NOTE: THESE SHOULD ONLY BE MODIFIED BY PROCS
|
||||
var/bruteloss = 0 //Brutal damage caused by brute force (punching, being clubbed by a toolbox ect... this also accounts for pressure damage)
|
||||
var/oxyloss = 0 //Oxygen depravation damage (no air in lungs)
|
||||
var/toxloss = 0 //Toxic damage caused by being poisoned or radiated
|
||||
var/fireloss = 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/staminaloss = 0 //Stamina damage, or exhaustion. You recover it slowly naturally, and are stunned if it gets too high. Holodeck and hallucinations deal this.
|
||||
|
||||
|
||||
var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out.
|
||||
|
||||
//Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects.
|
||||
var/incorporeal_move = 0 //0 is off, 1 is normal, 2 is for ninjas.
|
||||
|
||||
var/now_pushing = null
|
||||
|
||||
var/atom/movable/cameraFollow = null
|
||||
|
||||
var/on_fire = 0 //The "Are we on fire?" var
|
||||
var/fire_stacks = 0 //Tracks how many stacks of fire we have on, max is usually 20
|
||||
|
||||
var/implanting = 0 //Used for the mind-slave implant
|
||||
var/floating = 0
|
||||
var/mob_size = MOB_SIZE_HUMAN
|
||||
var/metabolism_efficiency = 1 //more or less efficiency to metabolize helpful/harmful reagents and regulate body temperature..
|
||||
var/digestion_ratio = 1 //controls how quickly reagents metabolize; largely governered by species attributes.
|
||||
|
||||
var/bloodcrawl = 0 //0 No blood crawling, 1 blood crawling, 2 blood crawling+mob devour
|
||||
var/holder = null //The holder for blood crawling
|
||||
|
||||
var/ventcrawler = 0 //0 No vent crawling, 1 vent crawling in the nude, 2 vent crawling always
|
||||
var/list/icon/pipes_shown = list()
|
||||
var/last_played_vent
|
||||
|
||||
var/smoke_delay = 0 //used to prevent spam with smoke reagent reaction on mob.
|
||||
|
||||
var/step_count = 0
|
||||
|
||||
var/list/butcher_results = null
|
||||
|
||||
var/list/weather_immunities = list()
|
||||
|
||||
var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them.
|
||||
|
||||
var/gene_stability = DEFAULT_GENE_STABILITY
|
||||
var/ignore_gene_stability = 0
|
||||
|
||||
var/obj/effect/proc_holder/ranged_ability //Any ranged ability the mob has, as a click override
|
||||
|
||||
var/tesla_ignore = FALSE
|
||||
|
||||
var/list/say_log = list() //a log of what we've said, plain text, no spans or junk, essentially just each individual "message"
|
||||
var/list/emote_log = list() //like say_log but for emotes
|
||||
|
||||
var/list/recent_tastes = list()
|
||||
var/blood_volume = 0 //how much blood the mob has
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,SPECIALROLE_HUD)
|
||||
|
||||
var/list/status_effects //a list of all status effects the mob has
|
||||
|
||||
var/deathgasp_on_death = FALSE
|
||||
|
||||
var/stun_absorption = null //converted to a list of stun absorption sources this mob has when one is added
|
||||
var/stam_regen_start_time = 0 //used to halt stamina regen temporarily
|
||||
var/stam_paralyzed = FALSE //knocks you down
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/mob/living/Logout()
|
||||
update_z(null)
|
||||
if(ranged_ability && client)
|
||||
ranged_ability.remove_mousepointer(client)
|
||||
..()
|
||||
if(mind)
|
||||
if(!key) //key and mind have become seperated. I believe this is for when a staff member aghosts.
|
||||
mind.active = 0 //This is to stop say, a mind.transfer_to call on a corpse causing a ghost to re-enter its body.
|
||||
//This causes instant sleep and tags a player as SSD. See life.dm for furthering SSD.
|
||||
if(mind.active)
|
||||
Sleeping(2)
|
||||
player_logged = 1
|
||||
last_logout = world.time
|
||||
/mob/living/Logout()
|
||||
update_z(null)
|
||||
if(ranged_ability && client)
|
||||
ranged_ability.remove_mousepointer(client)
|
||||
..()
|
||||
if(mind)
|
||||
if(!key) //key and mind have become seperated. I believe this is for when a staff member aghosts.
|
||||
mind.active = 0 //This is to stop say, a mind.transfer_to call on a corpse causing a ghost to re-enter its body.
|
||||
//This causes instant sleep and tags a player as SSD. See life.dm for furthering SSD.
|
||||
if(mind.active)
|
||||
Sleeping(2)
|
||||
player_logged = 1
|
||||
last_logout = world.time
|
||||
|
||||
+475
-475
@@ -1,475 +1,475 @@
|
||||
var/list/department_radio_keys = list(
|
||||
":r" = "right ear", "#r" = "right ear", ".r" = "right ear",
|
||||
":l" = "left ear", "#l" = "left ear", ".l" = "left ear",
|
||||
":i" = "intercom", "#i" = "intercom", ".i" = "intercom",
|
||||
":h" = "department", "#h" = "department", ".h" = "department",
|
||||
":+" = "special", "#+" = "special", ".+" = "special", //activate radio-specific special functions
|
||||
":c" = "Command", "#c" = "Command", ".c" = "Command",
|
||||
":n" = "Science", "#n" = "Science", ".n" = "Science",
|
||||
":m" = "Medical", "#m" = "Medical", ".m" = "Medical",
|
||||
":e" = "Engineering", "#e" = "Engineering", ".e" = "Engineering",
|
||||
":s" = "Security", "#s" = "Security", ".s" = "Security",
|
||||
":w" = "whisper", "#w" = "whisper", ".w" = "whisper",
|
||||
":t" = "Syndicate", "#t" = "Syndicate", ".t" = "Syndicate",
|
||||
":u" = "Supply", "#u" = "Supply", ".u" = "Supply",
|
||||
":z" = "Service", "#z" = "Service", ".z" = "Service",
|
||||
":p" = "AI Private", "#p" = "AI Private", ".p" = "AI Private",
|
||||
":x" = "cords", "#x" = "cords", ".x" = "cords",
|
||||
|
||||
":R" = "right ear", "#R" = "right ear", ".R" = "right ear",
|
||||
":L" = "left ear", "#L" = "left ear", ".L" = "left ear",
|
||||
":I" = "intercom", "#I" = "intercom", ".I" = "intercom",
|
||||
":H" = "department", "#H" = "department", ".H" = "department",
|
||||
":C" = "Command", "#C" = "Command", ".C" = "Command",
|
||||
":N" = "Science", "#N" = "Science", ".N" = "Science",
|
||||
":M" = "Medical", "#M" = "Medical", ".M" = "Medical",
|
||||
":E" = "Engineering", "#E" = "Engineering", ".E" = "Engineering",
|
||||
":S" = "Security", "#S" = "Security", ".S" = "Security",
|
||||
":W" = "whisper", "#W" = "whisper", ".W" = "whisper",
|
||||
":T" = "Syndicate", "#T" = "Syndicate", ".T" = "Syndicate",
|
||||
":U" = "Supply", "#U" = "Supply", ".U" = "Supply",
|
||||
":Z" = "Service", "#Z" = "Service", ".Z" = "Service",
|
||||
":P" = "AI Private", "#P" = "AI Private", ".P" = "AI Private",
|
||||
":$" = "Response Team", "#$" = "Response Team", ".$" = "Response Team",
|
||||
":-" = "Special Ops", "#-" = "Special Ops", ".-" = "Special Ops",
|
||||
":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam",
|
||||
":X" = "cords", "#X" = "cords", ".X" = "cords"
|
||||
)
|
||||
|
||||
|
||||
var/list/channel_to_radio_key = new
|
||||
proc/get_radio_key_from_channel(var/channel)
|
||||
var/key = channel_to_radio_key[channel]
|
||||
if(!key)
|
||||
for(var/radio_key in department_radio_keys)
|
||||
if(department_radio_keys[radio_key] == channel)
|
||||
key = radio_key
|
||||
break
|
||||
if(!key)
|
||||
key = ""
|
||||
channel_to_radio_key[channel] = key
|
||||
|
||||
return key
|
||||
|
||||
/mob/living/proc/binarycheck()
|
||||
return FALSE
|
||||
|
||||
/mob/proc/get_default_language()
|
||||
return null
|
||||
|
||||
/mob/living/get_default_language()
|
||||
return default_language
|
||||
|
||||
/mob/living/proc/handle_speech_problems(list/message_pieces, var/verb)
|
||||
var/robot = isSynthetic()
|
||||
for(var/datum/multilingual_say_piece/S in message_pieces)
|
||||
if(S.speaking && S.speaking.flags & NO_STUTTER)
|
||||
continue
|
||||
|
||||
if((HULK in mutations) && health >= 25)
|
||||
S.message = "[uppertext(S.message)]!!!"
|
||||
verb = pick("yells", "roars", "hollers")
|
||||
|
||||
if(slurring)
|
||||
if(robot)
|
||||
S.message = slur(S.message, list("@", "!", "#", "$", "%", "&", "?"))
|
||||
else
|
||||
S.message = slur(S.message)
|
||||
verb = "slurs"
|
||||
|
||||
if(stuttering)
|
||||
if(robot)
|
||||
S.message = robostutter(S.message)
|
||||
else
|
||||
S.message = stutter(S.message)
|
||||
verb = "stammers"
|
||||
|
||||
if(cultslurring)
|
||||
S.message = cultslur(S.message)
|
||||
verb = "slurs"
|
||||
|
||||
if(!IsVocal())
|
||||
S.message = ""
|
||||
return list("verb" = verb)
|
||||
|
||||
/mob/living/proc/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
|
||||
switch(message_mode)
|
||||
if("whisper") //all mobs can whisper by default
|
||||
whisper_say(message_pieces)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/proc/handle_speech_sound()
|
||||
var/list/returns[3]
|
||||
returns[1] = null
|
||||
returns[2] = null
|
||||
returns[3] = null
|
||||
return returns
|
||||
|
||||
|
||||
/mob/living/say(var/message, var/verb = "says", var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
|
||||
if(client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
|
||||
return
|
||||
|
||||
if(sanitize)
|
||||
message = trim_strip_html_properly(message)
|
||||
|
||||
if(stat)
|
||||
if(stat == DEAD)
|
||||
return say_dead(message)
|
||||
return
|
||||
|
||||
var/message_mode = parse_message_mode(message, "headset")
|
||||
|
||||
if(copytext(message, 1, 2) == "*")
|
||||
return emote(copytext(message, 2))
|
||||
|
||||
//parse the radio code and consume it
|
||||
if(message_mode)
|
||||
if(message_mode == "headset")
|
||||
message = copytext(message, 2) //it would be really nice if the parse procs could do this for us.
|
||||
else
|
||||
message = copytext(message, 3)
|
||||
|
||||
message = trim_left(message)
|
||||
|
||||
//parse the language code and consume it
|
||||
var/list/message_pieces = parse_languages(message)
|
||||
if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quirk to just easily deal with HIVEMIND languages
|
||||
var/datum/multilingual_say_piece/S = message_pieces // Yay BYOND's hilarious typecasting
|
||||
S.speaking.broadcast(src, S.message)
|
||||
return 1
|
||||
|
||||
|
||||
if(!LAZYLEN(message_pieces))
|
||||
log_runtime(EXCEPTION("Message failed to generate pieces. [message] - [json_encode(message_pieces)]"))
|
||||
return 0
|
||||
|
||||
if(message_mode == "cords")
|
||||
if(iscarbon(src))
|
||||
var/mob/living/carbon/C = src
|
||||
var/obj/item/organ/internal/vocal_cords/V = C.get_int_organ(/obj/item/organ/internal/vocal_cords)
|
||||
if(V && V.can_speak_with())
|
||||
C.say(V.handle_speech(message), sanitize = FALSE, ignore_speech_problems = TRUE, ignore_atmospherics = TRUE)
|
||||
V.speak_with(message) //words come before actions
|
||||
return 1
|
||||
|
||||
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
|
||||
verb = say_quote(message, first_piece.speaking)
|
||||
|
||||
if(is_muzzled())
|
||||
var/obj/item/clothing/mask/muzzle/G = wear_mask
|
||||
if(G.mute == MUZZLE_MUTE_ALL) //if the mask is supposed to mute you completely or just muffle you
|
||||
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
|
||||
return
|
||||
else if(G.mute == MUZZLE_MUTE_MUFFLE)
|
||||
muffledspeech_all(message_pieces)
|
||||
verb = "mumbles"
|
||||
|
||||
if(!ignore_speech_problems)
|
||||
var/list/hsp = handle_speech_problems(message_pieces, verb)
|
||||
verb = hsp["verb"]
|
||||
|
||||
|
||||
var/list/used_radios = list()
|
||||
if(handle_message_mode(message_mode, message_pieces, verb, used_radios))
|
||||
return 1
|
||||
|
||||
|
||||
var/list/handle_v = handle_speech_sound()
|
||||
var/sound/speech_sound = handle_v[1]
|
||||
var/sound_vol = handle_v[2]
|
||||
var/sound_frequency = handle_v[3]
|
||||
|
||||
var/italics = 0
|
||||
var/message_range = world.view
|
||||
|
||||
//speaking into radios
|
||||
if(used_radios.len)
|
||||
italics = 1
|
||||
message_range = 1
|
||||
if(first_piece.speaking)
|
||||
message_range = first_piece.speaking.get_talkinto_msg_range(message)
|
||||
|
||||
var/msg
|
||||
if(!first_piece.speaking || !(first_piece.speaking.flags & NO_TALK_MSG))
|
||||
msg = "<span class='notice'>[src] talks into [used_radios[1]]</span>"
|
||||
|
||||
if(msg)
|
||||
for(var/mob/living/M in hearers(5, src) - src)
|
||||
M.show_message(msg)
|
||||
|
||||
if(speech_sound)
|
||||
sound_vol *= 0.5
|
||||
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
var/list/listening = list()
|
||||
var/list/listening_obj = list()
|
||||
|
||||
if(T)
|
||||
//make sure the air can transmit speech - speaker's side
|
||||
var/datum/gas_mixture/environment = T.return_air()
|
||||
var/pressure = environment ? environment.return_pressure() : 0
|
||||
if(!ignore_atmospherics)
|
||||
if(pressure < SOUND_MINIMUM_PRESSURE)
|
||||
message_range = 1
|
||||
|
||||
if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
|
||||
italics = TRUE
|
||||
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
|
||||
|
||||
var/list/hear = hear(message_range, T)
|
||||
var/list/hearturfs = list()
|
||||
|
||||
for(var/I in hear)
|
||||
if(ismob(I))
|
||||
var/mob/M = I
|
||||
listening += M
|
||||
hearturfs += get_turf(M)
|
||||
for(var/obj/O in M.contents)
|
||||
listening_obj |= O
|
||||
if(isobj(I))
|
||||
var/obj/O = I
|
||||
hearturfs += get_turf(O)
|
||||
listening_obj |= O
|
||||
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(isobserver(M))
|
||||
if(M.get_preference(CHAT_GHOSTEARS) && client) // The client check is so that ghosts don't have to listen to mice.
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(message_range < world.view && (get_dist(T, M) <= world.view))
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(get_turf(M) in hearturfs)
|
||||
listening |= M
|
||||
|
||||
var/list/speech_bubble_recipients = list()
|
||||
var/speech_bubble_test = say_test(message)
|
||||
|
||||
for(var/mob/M in listening)
|
||||
M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol, sound_frequency)
|
||||
if(M.client)
|
||||
speech_bubble_recipients.Add(M.client)
|
||||
spawn(0)
|
||||
if(loc && !isturf(loc))
|
||||
var/atom/A = loc //Non-turf, let it handle the speech bubble
|
||||
A.speech_bubble("hR[speech_bubble_test]", A, speech_bubble_recipients)
|
||||
else //Turf, leave speech bubbles to the mob
|
||||
speech_bubble("h[speech_bubble_test]", src, speech_bubble_recipients)
|
||||
|
||||
for(var/obj/O in listening_obj)
|
||||
spawn(0)
|
||||
if(O) //It's possible that it could be deleted in the meantime.
|
||||
O.hear_talk(src, message_pieces, verb)
|
||||
|
||||
//Log of what we've said, plain message, no spans or junk
|
||||
say_log += message
|
||||
log_say(message, src)
|
||||
return 1
|
||||
|
||||
/obj/effect/speech_bubble
|
||||
var/mob/parent
|
||||
|
||||
/mob/living/proc/GetVoice()
|
||||
return name
|
||||
|
||||
/mob/living/emote(act, type, message, force) //emote code is terrible, this is so that anything that isn't already snowflaked to shit can call the parent and handle emoting sanely
|
||||
if(client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
|
||||
return
|
||||
|
||||
if(stat)
|
||||
return 0
|
||||
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(act && type && message) //parent call
|
||||
log_emote(message, src)
|
||||
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
if(!M.client)
|
||||
continue //skip monkeys and leavers
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(isobserver(M) && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src, null)) && client) // The client check makes sure people with ghost sight don't get spammed by simple mobs emoting.
|
||||
M.show_message(message)
|
||||
|
||||
switch(type)
|
||||
if(1) //Visible
|
||||
visible_message(message)
|
||||
return 1
|
||||
if(2) //Audible
|
||||
audible_message(message)
|
||||
return 1
|
||||
|
||||
else //everything else failed, emote is probably invalid
|
||||
if(act == "help")
|
||||
return //except help, because help is handled individually
|
||||
to_chat(src, "<span class='notice'>Unusable emote '[act]'. Say *help for a list.</span>")
|
||||
|
||||
/mob/living/whisper(message as text)
|
||||
message = trim_strip_html_properly(message)
|
||||
|
||||
//parse the language code and consume it
|
||||
var/list/message_pieces = parse_languages(message)
|
||||
if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quirk to just easily deal with HIVEMIND languages
|
||||
var/datum/multilingual_say_piece/S = message_pieces // Yay BYOND's hilarious typecasting
|
||||
S.speaking.broadcast(src, S.message)
|
||||
return 1
|
||||
|
||||
whisper_say(message_pieces)
|
||||
|
||||
// for weird circumstances where you're inside an atom that is also you, like pai's
|
||||
/mob/living/proc/get_whisper_loc()
|
||||
return src
|
||||
|
||||
/mob/living/proc/whisper_say(list/message_pieces, verb = "whispers")
|
||||
if(client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
|
||||
return
|
||||
|
||||
if(stat)
|
||||
if(stat == DEAD)
|
||||
return say_dead(message_pieces)
|
||||
return
|
||||
|
||||
if(is_muzzled())
|
||||
if(istype(wear_mask, /obj/item/clothing/mask/muzzle/tapegag)) //just for tape
|
||||
to_chat(src, "<span class='danger'>Your mouth is taped and you cannot speak!</span>")
|
||||
else
|
||||
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
|
||||
return
|
||||
|
||||
var/message = multilingual_to_message(message_pieces)
|
||||
|
||||
say_log += "whisper: [message]"
|
||||
log_whisper(message, src)
|
||||
var/message_range = 1
|
||||
var/eavesdropping_range = 2
|
||||
var/watching_range = 5
|
||||
var/italics = 1
|
||||
var/adverb_added = FALSE
|
||||
var/not_heard //the message displayed to people who could not hear the whispering
|
||||
|
||||
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
|
||||
if(first_piece.speaking)
|
||||
if(first_piece.speaking.whisper_verb)
|
||||
verb = first_piece.speaking.whisper_verb
|
||||
not_heard = "[verb] something"
|
||||
else
|
||||
var/adverb = pick("quietly", "softly")
|
||||
adverb_added = TRUE
|
||||
verb = "[first_piece.speaking.speech_verb] [adverb]"
|
||||
not_heard = "[first_piece.speaking.speech_verb] something [adverb]"
|
||||
else
|
||||
not_heard = "[verb] something"
|
||||
|
||||
var/list/hsp = handle_speech_problems(message_pieces, verb)
|
||||
verb = hsp["verb"]
|
||||
if(verb == "yells loudly")
|
||||
verb = "slurs emphatically"
|
||||
else if(!adverb_added)
|
||||
var/adverb = pick("quietly", "softly")
|
||||
verb = "[verb] [adverb]"
|
||||
|
||||
var/atom/whisper_loc = get_whisper_loc()
|
||||
var/list/listening = hear(message_range, whisper_loc)
|
||||
listening |= src
|
||||
|
||||
var/list/hearturfs = list()
|
||||
|
||||
// Pass whispers on to anything inside the immediate listeners.
|
||||
// This comes before the ghosts do so that ghosts don't act as whisper relays
|
||||
for(var/atom/L in listening)
|
||||
if(ismob(L))
|
||||
for(var/mob/C in L.contents)
|
||||
if(isliving(C))
|
||||
listening += C
|
||||
hearturfs += get_turf(L)
|
||||
if(isobj(L))
|
||||
hearturfs += get_turf(L)
|
||||
|
||||
// Loop through all players to see if they need to hear it.
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(isobserver(M))
|
||||
if(M.get_preference(CHAT_GHOSTEARS)) // The client check is so that ghosts don't have to listen to mice.
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(message_range < world.view && (get_dist(whisper_loc, M) <= world.view))
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(get_turf(M) in hearturfs)
|
||||
listening |= M
|
||||
|
||||
//pass on the message to objects that can hear us.
|
||||
for(var/obj/O in view(message_range, whisper_loc))
|
||||
spawn(0)
|
||||
if(O)
|
||||
O.hear_talk(src, message_pieces, verb)
|
||||
|
||||
var/list/eavesdropping = hearers(eavesdropping_range, whisper_loc)
|
||||
eavesdropping -= src
|
||||
eavesdropping -= listening
|
||||
|
||||
var/list/watching = hearers(watching_range, whisper_loc)
|
||||
watching -= src
|
||||
watching -= listening
|
||||
watching -= eavesdropping
|
||||
|
||||
//now mobs
|
||||
var/list/speech_bubble_recipients = list()
|
||||
var/speech_bubble_test = say_test(message)
|
||||
|
||||
for(var/mob/M in listening)
|
||||
M.hear_say(message_pieces, verb, italics, src)
|
||||
if(M.client)
|
||||
speech_bubble_recipients.Add(M.client)
|
||||
|
||||
if(eavesdropping.len)
|
||||
stars_all(message_pieces) //hopefully passing the message twice through stars() won't hurt... I guess if you already don't understand the language, when they speak it too quietly to hear normally you would be able to catch even less.
|
||||
for(var/mob/M in eavesdropping)
|
||||
M.hear_say(message_pieces, verb, italics, src)
|
||||
if(M.client)
|
||||
speech_bubble_recipients.Add(M.client)
|
||||
|
||||
spawn(0)
|
||||
var/image/I = image('icons/mob/talk.dmi', src, "h[speech_bubble_test]", MOB_LAYER + 1)
|
||||
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
||||
flick_overlay(I, speech_bubble_recipients, 30)
|
||||
|
||||
if(watching.len)
|
||||
var/rendered = "<span class='game say'><span class='name'>[name]</span> [not_heard].</span>"
|
||||
for(var/mob/M in watching)
|
||||
M.show_message(rendered, 2)
|
||||
|
||||
return 1
|
||||
|
||||
/mob/living/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list())
|
||||
var/image/I = image('icons/mob/talk.dmi', bubble_loc, bubble_state, MOB_LAYER + 1)
|
||||
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
||||
flick_overlay(I, bubble_recipients, 30)
|
||||
var/list/department_radio_keys = list(
|
||||
":r" = "right ear", "#r" = "right ear", ".r" = "right ear",
|
||||
":l" = "left ear", "#l" = "left ear", ".l" = "left ear",
|
||||
":i" = "intercom", "#i" = "intercom", ".i" = "intercom",
|
||||
":h" = "department", "#h" = "department", ".h" = "department",
|
||||
":+" = "special", "#+" = "special", ".+" = "special", //activate radio-specific special functions
|
||||
":c" = "Command", "#c" = "Command", ".c" = "Command",
|
||||
":n" = "Science", "#n" = "Science", ".n" = "Science",
|
||||
":m" = "Medical", "#m" = "Medical", ".m" = "Medical",
|
||||
":e" = "Engineering", "#e" = "Engineering", ".e" = "Engineering",
|
||||
":s" = "Security", "#s" = "Security", ".s" = "Security",
|
||||
":w" = "whisper", "#w" = "whisper", ".w" = "whisper",
|
||||
":t" = "Syndicate", "#t" = "Syndicate", ".t" = "Syndicate",
|
||||
":u" = "Supply", "#u" = "Supply", ".u" = "Supply",
|
||||
":z" = "Service", "#z" = "Service", ".z" = "Service",
|
||||
":p" = "AI Private", "#p" = "AI Private", ".p" = "AI Private",
|
||||
":x" = "cords", "#x" = "cords", ".x" = "cords",
|
||||
|
||||
":R" = "right ear", "#R" = "right ear", ".R" = "right ear",
|
||||
":L" = "left ear", "#L" = "left ear", ".L" = "left ear",
|
||||
":I" = "intercom", "#I" = "intercom", ".I" = "intercom",
|
||||
":H" = "department", "#H" = "department", ".H" = "department",
|
||||
":C" = "Command", "#C" = "Command", ".C" = "Command",
|
||||
":N" = "Science", "#N" = "Science", ".N" = "Science",
|
||||
":M" = "Medical", "#M" = "Medical", ".M" = "Medical",
|
||||
":E" = "Engineering", "#E" = "Engineering", ".E" = "Engineering",
|
||||
":S" = "Security", "#S" = "Security", ".S" = "Security",
|
||||
":W" = "whisper", "#W" = "whisper", ".W" = "whisper",
|
||||
":T" = "Syndicate", "#T" = "Syndicate", ".T" = "Syndicate",
|
||||
":U" = "Supply", "#U" = "Supply", ".U" = "Supply",
|
||||
":Z" = "Service", "#Z" = "Service", ".Z" = "Service",
|
||||
":P" = "AI Private", "#P" = "AI Private", ".P" = "AI Private",
|
||||
":$" = "Response Team", "#$" = "Response Team", ".$" = "Response Team",
|
||||
":-" = "Special Ops", "#-" = "Special Ops", ".-" = "Special Ops",
|
||||
":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam",
|
||||
":X" = "cords", "#X" = "cords", ".X" = "cords"
|
||||
)
|
||||
|
||||
|
||||
var/list/channel_to_radio_key = new
|
||||
proc/get_radio_key_from_channel(var/channel)
|
||||
var/key = channel_to_radio_key[channel]
|
||||
if(!key)
|
||||
for(var/radio_key in department_radio_keys)
|
||||
if(department_radio_keys[radio_key] == channel)
|
||||
key = radio_key
|
||||
break
|
||||
if(!key)
|
||||
key = ""
|
||||
channel_to_radio_key[channel] = key
|
||||
|
||||
return key
|
||||
|
||||
/mob/living/proc/binarycheck()
|
||||
return FALSE
|
||||
|
||||
/mob/proc/get_default_language()
|
||||
return null
|
||||
|
||||
/mob/living/get_default_language()
|
||||
return default_language
|
||||
|
||||
/mob/living/proc/handle_speech_problems(list/message_pieces, var/verb)
|
||||
var/robot = isSynthetic()
|
||||
for(var/datum/multilingual_say_piece/S in message_pieces)
|
||||
if(S.speaking && S.speaking.flags & NO_STUTTER)
|
||||
continue
|
||||
|
||||
if((HULK in mutations) && health >= 25)
|
||||
S.message = "[uppertext(S.message)]!!!"
|
||||
verb = pick("yells", "roars", "hollers")
|
||||
|
||||
if(slurring)
|
||||
if(robot)
|
||||
S.message = slur(S.message, list("@", "!", "#", "$", "%", "&", "?"))
|
||||
else
|
||||
S.message = slur(S.message)
|
||||
verb = "slurs"
|
||||
|
||||
if(stuttering)
|
||||
if(robot)
|
||||
S.message = robostutter(S.message)
|
||||
else
|
||||
S.message = stutter(S.message)
|
||||
verb = "stammers"
|
||||
|
||||
if(cultslurring)
|
||||
S.message = cultslur(S.message)
|
||||
verb = "slurs"
|
||||
|
||||
if(!IsVocal())
|
||||
S.message = ""
|
||||
return list("verb" = verb)
|
||||
|
||||
/mob/living/proc/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
|
||||
switch(message_mode)
|
||||
if("whisper") //all mobs can whisper by default
|
||||
whisper_say(message_pieces)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/proc/handle_speech_sound()
|
||||
var/list/returns[3]
|
||||
returns[1] = null
|
||||
returns[2] = null
|
||||
returns[3] = null
|
||||
return returns
|
||||
|
||||
|
||||
/mob/living/say(var/message, var/verb = "says", var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
|
||||
if(client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
|
||||
return
|
||||
|
||||
if(sanitize)
|
||||
message = trim_strip_html_properly(message)
|
||||
|
||||
if(stat)
|
||||
if(stat == DEAD)
|
||||
return say_dead(message)
|
||||
return
|
||||
|
||||
var/message_mode = parse_message_mode(message, "headset")
|
||||
|
||||
if(copytext(message, 1, 2) == "*")
|
||||
return emote(copytext(message, 2))
|
||||
|
||||
//parse the radio code and consume it
|
||||
if(message_mode)
|
||||
if(message_mode == "headset")
|
||||
message = copytext(message, 2) //it would be really nice if the parse procs could do this for us.
|
||||
else
|
||||
message = copytext(message, 3)
|
||||
|
||||
message = trim_left(message)
|
||||
|
||||
//parse the language code and consume it
|
||||
var/list/message_pieces = parse_languages(message)
|
||||
if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quirk to just easily deal with HIVEMIND languages
|
||||
var/datum/multilingual_say_piece/S = message_pieces // Yay BYOND's hilarious typecasting
|
||||
S.speaking.broadcast(src, S.message)
|
||||
return 1
|
||||
|
||||
|
||||
if(!LAZYLEN(message_pieces))
|
||||
log_runtime(EXCEPTION("Message failed to generate pieces. [message] - [json_encode(message_pieces)]"))
|
||||
return 0
|
||||
|
||||
if(message_mode == "cords")
|
||||
if(iscarbon(src))
|
||||
var/mob/living/carbon/C = src
|
||||
var/obj/item/organ/internal/vocal_cords/V = C.get_int_organ(/obj/item/organ/internal/vocal_cords)
|
||||
if(V && V.can_speak_with())
|
||||
C.say(V.handle_speech(message), sanitize = FALSE, ignore_speech_problems = TRUE, ignore_atmospherics = TRUE)
|
||||
V.speak_with(message) //words come before actions
|
||||
return 1
|
||||
|
||||
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
|
||||
verb = say_quote(message, first_piece.speaking)
|
||||
|
||||
if(is_muzzled())
|
||||
var/obj/item/clothing/mask/muzzle/G = wear_mask
|
||||
if(G.mute == MUZZLE_MUTE_ALL) //if the mask is supposed to mute you completely or just muffle you
|
||||
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
|
||||
return
|
||||
else if(G.mute == MUZZLE_MUTE_MUFFLE)
|
||||
muffledspeech_all(message_pieces)
|
||||
verb = "mumbles"
|
||||
|
||||
if(!ignore_speech_problems)
|
||||
var/list/hsp = handle_speech_problems(message_pieces, verb)
|
||||
verb = hsp["verb"]
|
||||
|
||||
|
||||
var/list/used_radios = list()
|
||||
if(handle_message_mode(message_mode, message_pieces, verb, used_radios))
|
||||
return 1
|
||||
|
||||
|
||||
var/list/handle_v = handle_speech_sound()
|
||||
var/sound/speech_sound = handle_v[1]
|
||||
var/sound_vol = handle_v[2]
|
||||
var/sound_frequency = handle_v[3]
|
||||
|
||||
var/italics = 0
|
||||
var/message_range = world.view
|
||||
|
||||
//speaking into radios
|
||||
if(used_radios.len)
|
||||
italics = 1
|
||||
message_range = 1
|
||||
if(first_piece.speaking)
|
||||
message_range = first_piece.speaking.get_talkinto_msg_range(message)
|
||||
|
||||
var/msg
|
||||
if(!first_piece.speaking || !(first_piece.speaking.flags & NO_TALK_MSG))
|
||||
msg = "<span class='notice'>[src] talks into [used_radios[1]]</span>"
|
||||
|
||||
if(msg)
|
||||
for(var/mob/living/M in hearers(5, src) - src)
|
||||
M.show_message(msg)
|
||||
|
||||
if(speech_sound)
|
||||
sound_vol *= 0.5
|
||||
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
var/list/listening = list()
|
||||
var/list/listening_obj = list()
|
||||
|
||||
if(T)
|
||||
//make sure the air can transmit speech - speaker's side
|
||||
var/datum/gas_mixture/environment = T.return_air()
|
||||
var/pressure = environment ? environment.return_pressure() : 0
|
||||
if(!ignore_atmospherics)
|
||||
if(pressure < SOUND_MINIMUM_PRESSURE)
|
||||
message_range = 1
|
||||
|
||||
if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
|
||||
italics = TRUE
|
||||
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
|
||||
|
||||
var/list/hear = hear(message_range, T)
|
||||
var/list/hearturfs = list()
|
||||
|
||||
for(var/I in hear)
|
||||
if(ismob(I))
|
||||
var/mob/M = I
|
||||
listening += M
|
||||
hearturfs += get_turf(M)
|
||||
for(var/obj/O in M.contents)
|
||||
listening_obj |= O
|
||||
if(isobj(I))
|
||||
var/obj/O = I
|
||||
hearturfs += get_turf(O)
|
||||
listening_obj |= O
|
||||
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(isobserver(M))
|
||||
if(M.get_preference(CHAT_GHOSTEARS) && client) // The client check is so that ghosts don't have to listen to mice.
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(message_range < world.view && (get_dist(T, M) <= world.view))
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(get_turf(M) in hearturfs)
|
||||
listening |= M
|
||||
|
||||
var/list/speech_bubble_recipients = list()
|
||||
var/speech_bubble_test = say_test(message)
|
||||
|
||||
for(var/mob/M in listening)
|
||||
M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol, sound_frequency)
|
||||
if(M.client)
|
||||
speech_bubble_recipients.Add(M.client)
|
||||
spawn(0)
|
||||
if(loc && !isturf(loc))
|
||||
var/atom/A = loc //Non-turf, let it handle the speech bubble
|
||||
A.speech_bubble("hR[speech_bubble_test]", A, speech_bubble_recipients)
|
||||
else //Turf, leave speech bubbles to the mob
|
||||
speech_bubble("h[speech_bubble_test]", src, speech_bubble_recipients)
|
||||
|
||||
for(var/obj/O in listening_obj)
|
||||
spawn(0)
|
||||
if(O) //It's possible that it could be deleted in the meantime.
|
||||
O.hear_talk(src, message_pieces, verb)
|
||||
|
||||
//Log of what we've said, plain message, no spans or junk
|
||||
say_log += message
|
||||
log_say(message, src)
|
||||
return 1
|
||||
|
||||
/obj/effect/speech_bubble
|
||||
var/mob/parent
|
||||
|
||||
/mob/living/proc/GetVoice()
|
||||
return name
|
||||
|
||||
/mob/living/emote(act, type, message, force) //emote code is terrible, this is so that anything that isn't already snowflaked to shit can call the parent and handle emoting sanely
|
||||
if(client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
|
||||
return
|
||||
|
||||
if(stat)
|
||||
return 0
|
||||
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(act && type && message) //parent call
|
||||
log_emote(message, src)
|
||||
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
if(!M.client)
|
||||
continue //skip monkeys and leavers
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(isobserver(M) && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src, null)) && client) // The client check makes sure people with ghost sight don't get spammed by simple mobs emoting.
|
||||
M.show_message(message)
|
||||
|
||||
switch(type)
|
||||
if(1) //Visible
|
||||
visible_message(message)
|
||||
return 1
|
||||
if(2) //Audible
|
||||
audible_message(message)
|
||||
return 1
|
||||
|
||||
else //everything else failed, emote is probably invalid
|
||||
if(act == "help")
|
||||
return //except help, because help is handled individually
|
||||
to_chat(src, "<span class='notice'>Unusable emote '[act]'. Say *help for a list.</span>")
|
||||
|
||||
/mob/living/whisper(message as text)
|
||||
message = trim_strip_html_properly(message)
|
||||
|
||||
//parse the language code and consume it
|
||||
var/list/message_pieces = parse_languages(message)
|
||||
if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quirk to just easily deal with HIVEMIND languages
|
||||
var/datum/multilingual_say_piece/S = message_pieces // Yay BYOND's hilarious typecasting
|
||||
S.speaking.broadcast(src, S.message)
|
||||
return 1
|
||||
|
||||
whisper_say(message_pieces)
|
||||
|
||||
// for weird circumstances where you're inside an atom that is also you, like pai's
|
||||
/mob/living/proc/get_whisper_loc()
|
||||
return src
|
||||
|
||||
/mob/living/proc/whisper_say(list/message_pieces, verb = "whispers")
|
||||
if(client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
|
||||
return
|
||||
|
||||
if(stat)
|
||||
if(stat == DEAD)
|
||||
return say_dead(message_pieces)
|
||||
return
|
||||
|
||||
if(is_muzzled())
|
||||
if(istype(wear_mask, /obj/item/clothing/mask/muzzle/tapegag)) //just for tape
|
||||
to_chat(src, "<span class='danger'>Your mouth is taped and you cannot speak!</span>")
|
||||
else
|
||||
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
|
||||
return
|
||||
|
||||
var/message = multilingual_to_message(message_pieces)
|
||||
|
||||
say_log += "whisper: [message]"
|
||||
log_whisper(message, src)
|
||||
var/message_range = 1
|
||||
var/eavesdropping_range = 2
|
||||
var/watching_range = 5
|
||||
var/italics = 1
|
||||
var/adverb_added = FALSE
|
||||
var/not_heard //the message displayed to people who could not hear the whispering
|
||||
|
||||
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
|
||||
if(first_piece.speaking)
|
||||
if(first_piece.speaking.whisper_verb)
|
||||
verb = first_piece.speaking.whisper_verb
|
||||
not_heard = "[verb] something"
|
||||
else
|
||||
var/adverb = pick("quietly", "softly")
|
||||
adverb_added = TRUE
|
||||
verb = "[first_piece.speaking.speech_verb] [adverb]"
|
||||
not_heard = "[first_piece.speaking.speech_verb] something [adverb]"
|
||||
else
|
||||
not_heard = "[verb] something"
|
||||
|
||||
var/list/hsp = handle_speech_problems(message_pieces, verb)
|
||||
verb = hsp["verb"]
|
||||
if(verb == "yells loudly")
|
||||
verb = "slurs emphatically"
|
||||
else if(!adverb_added)
|
||||
var/adverb = pick("quietly", "softly")
|
||||
verb = "[verb] [adverb]"
|
||||
|
||||
var/atom/whisper_loc = get_whisper_loc()
|
||||
var/list/listening = hear(message_range, whisper_loc)
|
||||
listening |= src
|
||||
|
||||
var/list/hearturfs = list()
|
||||
|
||||
// Pass whispers on to anything inside the immediate listeners.
|
||||
// This comes before the ghosts do so that ghosts don't act as whisper relays
|
||||
for(var/atom/L in listening)
|
||||
if(ismob(L))
|
||||
for(var/mob/C in L.contents)
|
||||
if(isliving(C))
|
||||
listening += C
|
||||
hearturfs += get_turf(L)
|
||||
if(isobj(L))
|
||||
hearturfs += get_turf(L)
|
||||
|
||||
// Loop through all players to see if they need to hear it.
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(isobserver(M))
|
||||
if(M.get_preference(CHAT_GHOSTEARS)) // The client check is so that ghosts don't have to listen to mice.
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(message_range < world.view && (get_dist(whisper_loc, M) <= world.view))
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(get_turf(M) in hearturfs)
|
||||
listening |= M
|
||||
|
||||
//pass on the message to objects that can hear us.
|
||||
for(var/obj/O in view(message_range, whisper_loc))
|
||||
spawn(0)
|
||||
if(O)
|
||||
O.hear_talk(src, message_pieces, verb)
|
||||
|
||||
var/list/eavesdropping = hearers(eavesdropping_range, whisper_loc)
|
||||
eavesdropping -= src
|
||||
eavesdropping -= listening
|
||||
|
||||
var/list/watching = hearers(watching_range, whisper_loc)
|
||||
watching -= src
|
||||
watching -= listening
|
||||
watching -= eavesdropping
|
||||
|
||||
//now mobs
|
||||
var/list/speech_bubble_recipients = list()
|
||||
var/speech_bubble_test = say_test(message)
|
||||
|
||||
for(var/mob/M in listening)
|
||||
M.hear_say(message_pieces, verb, italics, src)
|
||||
if(M.client)
|
||||
speech_bubble_recipients.Add(M.client)
|
||||
|
||||
if(eavesdropping.len)
|
||||
stars_all(message_pieces) //hopefully passing the message twice through stars() won't hurt... I guess if you already don't understand the language, when they speak it too quietly to hear normally you would be able to catch even less.
|
||||
for(var/mob/M in eavesdropping)
|
||||
M.hear_say(message_pieces, verb, italics, src)
|
||||
if(M.client)
|
||||
speech_bubble_recipients.Add(M.client)
|
||||
|
||||
spawn(0)
|
||||
var/image/I = image('icons/mob/talk.dmi', src, "h[speech_bubble_test]", MOB_LAYER + 1)
|
||||
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
||||
flick_overlay(I, speech_bubble_recipients, 30)
|
||||
|
||||
if(watching.len)
|
||||
var/rendered = "<span class='game say'><span class='name'>[name]</span> [not_heard].</span>"
|
||||
for(var/mob/M in watching)
|
||||
M.show_message(rendered, 2)
|
||||
|
||||
return 1
|
||||
|
||||
/mob/living/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list())
|
||||
var/image/I = image('icons/mob/talk.dmi', bubble_loc, bubble_state, MOB_LAYER + 1)
|
||||
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
||||
flick_overlay(I, bubble_recipients, 30)
|
||||
|
||||
+1323
-1323
File diff suppressed because it is too large
Load Diff
@@ -1,41 +1,41 @@
|
||||
/mob/living/silicon/ai/death(gibbed)
|
||||
// Only execute the below if we successfully died
|
||||
. = ..(gibbed)
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(custom_sprite == 1)//check for custom AI sprite, defaulting to blue screen if no.
|
||||
icon_state = "[ckey]-ai_dead"
|
||||
else if("[icon_state]_dead" in icon_states(icon,1))
|
||||
icon_state = "[icon_state]_dead"
|
||||
else
|
||||
icon_state = "ai_dead"
|
||||
if(eyeobj)
|
||||
eyeobj.setLoc(get_turf(src))
|
||||
|
||||
GLOB.shuttle_caller_list -= src
|
||||
SSshuttle.autoEvac()
|
||||
|
||||
if(nuking)
|
||||
set_security_level("red")
|
||||
nuking = 0
|
||||
for(var/obj/item/pinpointer/point in GLOB.pinpointer_list)
|
||||
point.the_disk = null //Point back to the disk.
|
||||
|
||||
if(doomsday_device)
|
||||
doomsday_device.timing = 0
|
||||
SSshuttle.emergencyNoEscape = 0
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
|
||||
SSshuttle.emergency.mode = SHUTTLE_DOCKED
|
||||
SSshuttle.emergency.timer = world.time
|
||||
priority_announcement.Announce("Hostile environment resolved. You have 3 minutes to board the Emergency Shuttle.", "Priority Announcement", 'sound/AI/shuttledock.ogg')
|
||||
qdel(doomsday_device)
|
||||
|
||||
if(explosive)
|
||||
spawn(10)
|
||||
explosion(src.loc, 3, 6, 12, 15)
|
||||
|
||||
for(var/obj/machinery/ai_status_display/O in world) //change status
|
||||
O.mode = 2
|
||||
|
||||
if(istype(loc, /obj/item/aicard))
|
||||
loc.icon_state = "aicard-404"
|
||||
/mob/living/silicon/ai/death(gibbed)
|
||||
// Only execute the below if we successfully died
|
||||
. = ..(gibbed)
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(custom_sprite == 1)//check for custom AI sprite, defaulting to blue screen if no.
|
||||
icon_state = "[ckey]-ai_dead"
|
||||
else if("[icon_state]_dead" in icon_states(icon,1))
|
||||
icon_state = "[icon_state]_dead"
|
||||
else
|
||||
icon_state = "ai_dead"
|
||||
if(eyeobj)
|
||||
eyeobj.setLoc(get_turf(src))
|
||||
|
||||
GLOB.shuttle_caller_list -= src
|
||||
SSshuttle.autoEvac()
|
||||
|
||||
if(nuking)
|
||||
set_security_level("red")
|
||||
nuking = 0
|
||||
for(var/obj/item/pinpointer/point in GLOB.pinpointer_list)
|
||||
point.the_disk = null //Point back to the disk.
|
||||
|
||||
if(doomsday_device)
|
||||
doomsday_device.timing = 0
|
||||
SSshuttle.emergencyNoEscape = 0
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
|
||||
SSshuttle.emergency.mode = SHUTTLE_DOCKED
|
||||
SSshuttle.emergency.timer = world.time
|
||||
priority_announcement.Announce("Hostile environment resolved. You have 3 minutes to board the Emergency Shuttle.", "Priority Announcement", 'sound/AI/shuttledock.ogg')
|
||||
qdel(doomsday_device)
|
||||
|
||||
if(explosive)
|
||||
spawn(10)
|
||||
explosion(src.loc, 3, 6, 12, 15)
|
||||
|
||||
for(var/obj/machinery/ai_status_display/O in world) //change status
|
||||
O.mode = 2
|
||||
|
||||
if(istype(loc, /obj/item/aicard))
|
||||
loc.icon_state = "aicard-404"
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
/mob/living/silicon/ai/examine(mob/user)
|
||||
. = ..()
|
||||
var/msg = "<span class='info'>"
|
||||
if(src.stat == DEAD)
|
||||
msg += "<span class='deadsay'>It appears to be powered-down.</span>\n"
|
||||
else
|
||||
msg += "<span class='warning'>"
|
||||
if(src.getBruteLoss())
|
||||
if(src.getBruteLoss() < 30)
|
||||
msg += "It looks slightly dented.\n"
|
||||
else
|
||||
msg += "<B>It looks severely dented!</B>\n"
|
||||
if(src.getFireLoss())
|
||||
if(src.getFireLoss() < 30)
|
||||
msg += "It looks slightly charred.\n"
|
||||
else
|
||||
msg += "<B>Its casing is melted and heat-warped!</B>\n"
|
||||
if(src.stat == UNCONSCIOUS)
|
||||
msg += "It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".\n"
|
||||
if(!shunted && !client)
|
||||
msg += "[src]Core.exe has stopped responding! NTOS is searching for a solution to the problem...\n"
|
||||
msg += "</span>"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
. += msg
|
||||
user.showLaws(src)
|
||||
|
||||
|
||||
/mob/proc/showLaws(var/mob/living/silicon/S)
|
||||
return
|
||||
|
||||
/mob/dead/observer/showLaws(var/mob/living/silicon/S)
|
||||
if(antagHUD || check_rights(R_ADMIN, 0, src))
|
||||
S.laws.show_laws(src)
|
||||
/mob/living/silicon/ai/examine(mob/user)
|
||||
. = ..()
|
||||
var/msg = "<span class='info'>"
|
||||
if(src.stat == DEAD)
|
||||
msg += "<span class='deadsay'>It appears to be powered-down.</span>\n"
|
||||
else
|
||||
msg += "<span class='warning'>"
|
||||
if(src.getBruteLoss())
|
||||
if(src.getBruteLoss() < 30)
|
||||
msg += "It looks slightly dented.\n"
|
||||
else
|
||||
msg += "<B>It looks severely dented!</B>\n"
|
||||
if(src.getFireLoss())
|
||||
if(src.getFireLoss() < 30)
|
||||
msg += "It looks slightly charred.\n"
|
||||
else
|
||||
msg += "<B>Its casing is melted and heat-warped!</B>\n"
|
||||
if(src.stat == UNCONSCIOUS)
|
||||
msg += "It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".\n"
|
||||
if(!shunted && !client)
|
||||
msg += "[src]Core.exe has stopped responding! NTOS is searching for a solution to the problem...\n"
|
||||
msg += "</span>"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
. += msg
|
||||
user.showLaws(src)
|
||||
|
||||
|
||||
/mob/proc/showLaws(var/mob/living/silicon/S)
|
||||
return
|
||||
|
||||
/mob/dead/observer/showLaws(var/mob/living/silicon/S)
|
||||
if(antagHUD || check_rights(R_ADMIN, 0, src))
|
||||
S.laws.show_laws(src)
|
||||
|
||||
@@ -197,4 +197,4 @@ var/datum/cameranet/cameranet = new()
|
||||
if(cameranet.chunkGenerated(x, y, z))
|
||||
var/datum/camerachunk/chunk = cameranet.getCameraChunk(x, y, z)
|
||||
usr.client.debug_variables(chunk)
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -1,151 +1,151 @@
|
||||
// AI EYE
|
||||
//
|
||||
// An invisible (no icon) 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/camera/aiEye
|
||||
name = "Inactive AI Eye"
|
||||
|
||||
icon = 'icons/mob/ai.dmi' //Allows ghosts to see what the AI is looking at.
|
||||
icon_state = "eye"
|
||||
alpha = 127
|
||||
invisibility = SEE_INVISIBLE_OBSERVER
|
||||
|
||||
var/list/visibleCameraChunks = list()
|
||||
var/mob/living/silicon/ai/ai = null
|
||||
var/relay_speech = FALSE
|
||||
var/use_static = TRUE
|
||||
var/static_visibility_range = 16
|
||||
|
||||
|
||||
// Use this when setting the aiEye's location.
|
||||
// It will also stream the chunk that the new loc is in.
|
||||
|
||||
/mob/camera/aiEye/setLoc(T)
|
||||
if(ai)
|
||||
if(!isturf(ai.loc))
|
||||
return
|
||||
T = get_turf(T)
|
||||
loc = T
|
||||
if(use_static)
|
||||
ai.camera_visibility(src)
|
||||
if(ai.client && !ai.multicam_on)
|
||||
ai.client.eye = src
|
||||
update_parallax_contents()
|
||||
//Holopad
|
||||
if(ai.master_multicam)
|
||||
ai.master_multicam.refresh_view()
|
||||
if(istype(ai.current, /obj/machinery/hologram/holopad))
|
||||
var/obj/machinery/hologram/holopad/H = ai.current
|
||||
H.move_hologram(ai, T)
|
||||
|
||||
/mob/camera/aiEye/Move()
|
||||
return 0
|
||||
|
||||
/mob/camera/aiEye/proc/GetViewerClient()
|
||||
if(ai)
|
||||
return ai.client
|
||||
return null
|
||||
|
||||
/mob/camera/aiEye/proc/RemoveImages()
|
||||
var/client/C = GetViewerClient()
|
||||
if(C && use_static)
|
||||
for(var/V in visibleCameraChunks)
|
||||
var/datum/camerachunk/chunk = V
|
||||
C.images -= chunk.obscured
|
||||
|
||||
/mob/camera/aiEye/Destroy()
|
||||
if(ai)
|
||||
ai.all_eyes -= src
|
||||
ai = null
|
||||
for(var/V in visibleCameraChunks)
|
||||
var/datum/camerachunk/chunk = V
|
||||
chunk.remove(src)
|
||||
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)) && (AI.eyeobj.z == z))
|
||||
AI.cameraFollow = null
|
||||
if(isturf(loc) || isturf(src))
|
||||
AI.eyeobj.setLoc(src)
|
||||
|
||||
// AI MOVEMENT
|
||||
|
||||
// This will move the AIEye. It will also cause lights near the eye to light up, if toggled.
|
||||
// This is handled in the proc below this one.
|
||||
|
||||
/client/proc/AIMove(n, direct, var/mob/living/silicon/ai/user)
|
||||
|
||||
var/initial = initial(user.sprint)
|
||||
var/max_sprint = 50
|
||||
|
||||
if(user.cooldown && user.cooldown < world.timeofday) // 3 seconds
|
||||
user.sprint = initial
|
||||
|
||||
for(var/i = 0; i < max(user.sprint, initial); i += 20)
|
||||
var/turf/step = get_turf(get_step(user.eyeobj, direct))
|
||||
if(step)
|
||||
user.eyeobj.setLoc(step)
|
||||
|
||||
user.cooldown = world.timeofday + 5
|
||||
if(user.acceleration)
|
||||
user.sprint = min(user.sprint + 0.5, max_sprint)
|
||||
else
|
||||
user.sprint = initial
|
||||
|
||||
if(!user.tracking)
|
||||
user.cameraFollow = null
|
||||
|
||||
//user.unset_machine() //Uncomment this if it causes problems.
|
||||
//user.lightNearbyCamera()
|
||||
if(user.camera_light_on)
|
||||
user.light_cameras()
|
||||
|
||||
// Return to the Core.
|
||||
/mob/living/silicon/ai/proc/core()
|
||||
set category = "AI Commands"
|
||||
set name = "AI Core"
|
||||
|
||||
view_core()
|
||||
|
||||
/mob/living/silicon/ai/proc/view_core()
|
||||
|
||||
current = null
|
||||
cameraFollow = null
|
||||
unset_machine()
|
||||
|
||||
if(src.eyeobj && src.loc)
|
||||
src.eyeobj.loc = src.loc
|
||||
else
|
||||
to_chat(src, "ERROR: Eyeobj not found. Creating new eye...")
|
||||
create_eye()
|
||||
|
||||
eyeobj.setLoc(loc)
|
||||
|
||||
/mob/living/silicon/ai/proc/create_eye()
|
||||
if(eyeobj)
|
||||
return
|
||||
eyeobj = new /mob/camera/aiEye()
|
||||
all_eyes += eyeobj
|
||||
eyeobj.ai = src
|
||||
eyeobj.setLoc(loc)
|
||||
eyeobj.name = "[name] (AI Eye)"
|
||||
|
||||
/mob/living/silicon/ai/proc/toggle_acceleration()
|
||||
set category = "AI Commands"
|
||||
set name = "Toggle Camera Acceleration"
|
||||
|
||||
if(usr.stat == 2)
|
||||
return //won't work if dead
|
||||
acceleration = !acceleration
|
||||
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
|
||||
|
||||
/mob/camera/aiEye/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency)
|
||||
if(relay_speech)
|
||||
if(istype(ai))
|
||||
ai.relay_speech(speaker, message_pieces, verb)
|
||||
else
|
||||
var/mob/M = ai
|
||||
M.hear_say(message_pieces, verb, italics, speaker, speech_sound, sound_vol, sound_frequency)
|
||||
// AI EYE
|
||||
//
|
||||
// An invisible (no icon) 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/camera/aiEye
|
||||
name = "Inactive AI Eye"
|
||||
|
||||
icon = 'icons/mob/ai.dmi' //Allows ghosts to see what the AI is looking at.
|
||||
icon_state = "eye"
|
||||
alpha = 127
|
||||
invisibility = SEE_INVISIBLE_OBSERVER
|
||||
|
||||
var/list/visibleCameraChunks = list()
|
||||
var/mob/living/silicon/ai/ai = null
|
||||
var/relay_speech = FALSE
|
||||
var/use_static = TRUE
|
||||
var/static_visibility_range = 16
|
||||
|
||||
|
||||
// Use this when setting the aiEye's location.
|
||||
// It will also stream the chunk that the new loc is in.
|
||||
|
||||
/mob/camera/aiEye/setLoc(T)
|
||||
if(ai)
|
||||
if(!isturf(ai.loc))
|
||||
return
|
||||
T = get_turf(T)
|
||||
loc = T
|
||||
if(use_static)
|
||||
ai.camera_visibility(src)
|
||||
if(ai.client && !ai.multicam_on)
|
||||
ai.client.eye = src
|
||||
update_parallax_contents()
|
||||
//Holopad
|
||||
if(ai.master_multicam)
|
||||
ai.master_multicam.refresh_view()
|
||||
if(istype(ai.current, /obj/machinery/hologram/holopad))
|
||||
var/obj/machinery/hologram/holopad/H = ai.current
|
||||
H.move_hologram(ai, T)
|
||||
|
||||
/mob/camera/aiEye/Move()
|
||||
return 0
|
||||
|
||||
/mob/camera/aiEye/proc/GetViewerClient()
|
||||
if(ai)
|
||||
return ai.client
|
||||
return null
|
||||
|
||||
/mob/camera/aiEye/proc/RemoveImages()
|
||||
var/client/C = GetViewerClient()
|
||||
if(C && use_static)
|
||||
for(var/V in visibleCameraChunks)
|
||||
var/datum/camerachunk/chunk = V
|
||||
C.images -= chunk.obscured
|
||||
|
||||
/mob/camera/aiEye/Destroy()
|
||||
if(ai)
|
||||
ai.all_eyes -= src
|
||||
ai = null
|
||||
for(var/V in visibleCameraChunks)
|
||||
var/datum/camerachunk/chunk = V
|
||||
chunk.remove(src)
|
||||
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)) && (AI.eyeobj.z == z))
|
||||
AI.cameraFollow = null
|
||||
if(isturf(loc) || isturf(src))
|
||||
AI.eyeobj.setLoc(src)
|
||||
|
||||
// AI MOVEMENT
|
||||
|
||||
// This will move the AIEye. It will also cause lights near the eye to light up, if toggled.
|
||||
// This is handled in the proc below this one.
|
||||
|
||||
/client/proc/AIMove(n, direct, var/mob/living/silicon/ai/user)
|
||||
|
||||
var/initial = initial(user.sprint)
|
||||
var/max_sprint = 50
|
||||
|
||||
if(user.cooldown && user.cooldown < world.timeofday) // 3 seconds
|
||||
user.sprint = initial
|
||||
|
||||
for(var/i = 0; i < max(user.sprint, initial); i += 20)
|
||||
var/turf/step = get_turf(get_step(user.eyeobj, direct))
|
||||
if(step)
|
||||
user.eyeobj.setLoc(step)
|
||||
|
||||
user.cooldown = world.timeofday + 5
|
||||
if(user.acceleration)
|
||||
user.sprint = min(user.sprint + 0.5, max_sprint)
|
||||
else
|
||||
user.sprint = initial
|
||||
|
||||
if(!user.tracking)
|
||||
user.cameraFollow = null
|
||||
|
||||
//user.unset_machine() //Uncomment this if it causes problems.
|
||||
//user.lightNearbyCamera()
|
||||
if(user.camera_light_on)
|
||||
user.light_cameras()
|
||||
|
||||
// Return to the Core.
|
||||
/mob/living/silicon/ai/proc/core()
|
||||
set category = "AI Commands"
|
||||
set name = "AI Core"
|
||||
|
||||
view_core()
|
||||
|
||||
/mob/living/silicon/ai/proc/view_core()
|
||||
|
||||
current = null
|
||||
cameraFollow = null
|
||||
unset_machine()
|
||||
|
||||
if(src.eyeobj && src.loc)
|
||||
src.eyeobj.loc = src.loc
|
||||
else
|
||||
to_chat(src, "ERROR: Eyeobj not found. Creating new eye...")
|
||||
create_eye()
|
||||
|
||||
eyeobj.setLoc(loc)
|
||||
|
||||
/mob/living/silicon/ai/proc/create_eye()
|
||||
if(eyeobj)
|
||||
return
|
||||
eyeobj = new /mob/camera/aiEye()
|
||||
all_eyes += eyeobj
|
||||
eyeobj.ai = src
|
||||
eyeobj.setLoc(loc)
|
||||
eyeobj.name = "[name] (AI Eye)"
|
||||
|
||||
/mob/living/silicon/ai/proc/toggle_acceleration()
|
||||
set category = "AI Commands"
|
||||
set name = "Toggle Camera Acceleration"
|
||||
|
||||
if(usr.stat == 2)
|
||||
return //won't work if dead
|
||||
acceleration = !acceleration
|
||||
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
|
||||
|
||||
/mob/camera/aiEye/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency)
|
||||
if(relay_speech)
|
||||
if(istype(ai))
|
||||
ai.relay_speech(speaker, message_pieces, verb)
|
||||
else
|
||||
var/mob/M = ai
|
||||
M.hear_say(message_pieces, verb, italics, speaker, speech_sound, sound_vol, sound_frequency)
|
||||
|
||||
@@ -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,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, "<b>Obey these laws:</b>")
|
||||
|
||||
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 GLOB.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, "<b>Obey these laws:</b>")
|
||||
|
||||
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 GLOB.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,154 +1,154 @@
|
||||
#define POWER_RESTORATION_OFF 0
|
||||
#define POWER_RESTORATION_START 1
|
||||
#define POWER_RESTORATION_SEARCH_APC 2
|
||||
#define POWER_RESTORATION_APC_FOUND 3
|
||||
|
||||
/mob/living/silicon/ai/Life(seconds, times_fired)
|
||||
//doesn't call parent because it's a horrible mess
|
||||
if(stat == DEAD)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(stat != CONSCIOUS) //ai's fucked
|
||||
cameraFollow = null
|
||||
reset_perspective(null)
|
||||
unset_machine()
|
||||
|
||||
updatehealth("life")
|
||||
if(stat == DEAD)
|
||||
return
|
||||
update_gravity(mob_has_gravity())
|
||||
|
||||
if(!eyeobj || QDELETED(eyeobj) || !eyeobj.loc)
|
||||
view_core()
|
||||
|
||||
if(machine)
|
||||
machine.check_eye(src)
|
||||
|
||||
if(malfhack && malfhack.aidisabled)
|
||||
to_chat(src, "<span class='danger'>ERROR: APC access disabled, hack attempt canceled.</span>")
|
||||
deltimer(malfhacking)
|
||||
// This proc handles cleanup of screen notifications and
|
||||
// messenging the client
|
||||
malfhacked(malfhack)
|
||||
|
||||
if(aiRestorePowerRoutine)
|
||||
adjustOxyLoss(1)
|
||||
else
|
||||
adjustOxyLoss(-1)
|
||||
|
||||
handle_stunned()
|
||||
|
||||
var/area/my_area = get_area(src)
|
||||
|
||||
if(!lacks_power())
|
||||
if(aiRestorePowerRoutine > 1)
|
||||
update_blind_effects()
|
||||
aiRestorePowerRoutine = 0
|
||||
update_sight()
|
||||
to_chat(src, "Alert cancelled. Power has been restored[aiRestorePowerRoutine == 2 ? "without our assistance" : ""].")
|
||||
else
|
||||
if(lacks_power())
|
||||
if(!aiRestorePowerRoutine)
|
||||
update_blind_effects()
|
||||
aiRestorePowerRoutine = 1
|
||||
update_sight()
|
||||
to_chat(src, "<span class='danger'>You have lost power!</span>")
|
||||
if(!is_special_character(src))
|
||||
set_zeroth_law("")
|
||||
|
||||
spawn(20)
|
||||
to_chat(src, "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection.")
|
||||
end_multicam()
|
||||
sleep(50)
|
||||
my_area = get_area(src)
|
||||
T = get_turf(src)
|
||||
if(!lacks_power())
|
||||
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
|
||||
aiRestorePowerRoutine = 0
|
||||
update_blind_effects()
|
||||
update_sight()
|
||||
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)
|
||||
T = get_turf(src)
|
||||
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)
|
||||
|
||||
my_area = get_area(src)
|
||||
T = get_turf(src)
|
||||
|
||||
var/obj/machinery/power/apc/theAPC = null
|
||||
|
||||
var/PRP
|
||||
for(PRP = 1, PRP <= 4, PRP++)
|
||||
for(var/obj/machinery/power/apc/APC in my_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!")
|
||||
aiRestorePowerRoutine = 2
|
||||
return
|
||||
|
||||
if(!lacks_power())
|
||||
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
|
||||
aiRestorePowerRoutine = 0
|
||||
update_blind_effects()
|
||||
update_sight()
|
||||
to_chat(src, "Here are your current laws:")
|
||||
show_laws()
|
||||
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)
|
||||
//bring up APC dialog
|
||||
apc_override = 1
|
||||
theAPC.attack_ai(src)
|
||||
apc_override = 0
|
||||
aiRestorePowerRoutine = 3
|
||||
sleep(50)
|
||||
theAPC = null
|
||||
|
||||
process_queued_alarms()
|
||||
|
||||
/mob/living/silicon/ai/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = 100
|
||||
stat = CONSCIOUS
|
||||
else
|
||||
health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss()
|
||||
update_stat("updatehealth([reason])")
|
||||
diag_hud_set_status()
|
||||
diag_hud_set_health()
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/lacks_power()
|
||||
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/rejuvenate()
|
||||
..()
|
||||
add_ai_verbs(src)
|
||||
#define POWER_RESTORATION_OFF 0
|
||||
#define POWER_RESTORATION_START 1
|
||||
#define POWER_RESTORATION_SEARCH_APC 2
|
||||
#define POWER_RESTORATION_APC_FOUND 3
|
||||
|
||||
/mob/living/silicon/ai/Life(seconds, times_fired)
|
||||
//doesn't call parent because it's a horrible mess
|
||||
if(stat == DEAD)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(stat != CONSCIOUS) //ai's fucked
|
||||
cameraFollow = null
|
||||
reset_perspective(null)
|
||||
unset_machine()
|
||||
|
||||
updatehealth("life")
|
||||
if(stat == DEAD)
|
||||
return
|
||||
update_gravity(mob_has_gravity())
|
||||
|
||||
if(!eyeobj || QDELETED(eyeobj) || !eyeobj.loc)
|
||||
view_core()
|
||||
|
||||
if(machine)
|
||||
machine.check_eye(src)
|
||||
|
||||
if(malfhack && malfhack.aidisabled)
|
||||
to_chat(src, "<span class='danger'>ERROR: APC access disabled, hack attempt canceled.</span>")
|
||||
deltimer(malfhacking)
|
||||
// This proc handles cleanup of screen notifications and
|
||||
// messenging the client
|
||||
malfhacked(malfhack)
|
||||
|
||||
if(aiRestorePowerRoutine)
|
||||
adjustOxyLoss(1)
|
||||
else
|
||||
adjustOxyLoss(-1)
|
||||
|
||||
handle_stunned()
|
||||
|
||||
var/area/my_area = get_area(src)
|
||||
|
||||
if(!lacks_power())
|
||||
if(aiRestorePowerRoutine > 1)
|
||||
update_blind_effects()
|
||||
aiRestorePowerRoutine = 0
|
||||
update_sight()
|
||||
to_chat(src, "Alert cancelled. Power has been restored[aiRestorePowerRoutine == 2 ? "without our assistance" : ""].")
|
||||
else
|
||||
if(lacks_power())
|
||||
if(!aiRestorePowerRoutine)
|
||||
update_blind_effects()
|
||||
aiRestorePowerRoutine = 1
|
||||
update_sight()
|
||||
to_chat(src, "<span class='danger'>You have lost power!</span>")
|
||||
if(!is_special_character(src))
|
||||
set_zeroth_law("")
|
||||
|
||||
spawn(20)
|
||||
to_chat(src, "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection.")
|
||||
end_multicam()
|
||||
sleep(50)
|
||||
my_area = get_area(src)
|
||||
T = get_turf(src)
|
||||
if(!lacks_power())
|
||||
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
|
||||
aiRestorePowerRoutine = 0
|
||||
update_blind_effects()
|
||||
update_sight()
|
||||
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)
|
||||
T = get_turf(src)
|
||||
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)
|
||||
|
||||
my_area = get_area(src)
|
||||
T = get_turf(src)
|
||||
|
||||
var/obj/machinery/power/apc/theAPC = null
|
||||
|
||||
var/PRP
|
||||
for(PRP = 1, PRP <= 4, PRP++)
|
||||
for(var/obj/machinery/power/apc/APC in my_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!")
|
||||
aiRestorePowerRoutine = 2
|
||||
return
|
||||
|
||||
if(!lacks_power())
|
||||
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
|
||||
aiRestorePowerRoutine = 0
|
||||
update_blind_effects()
|
||||
update_sight()
|
||||
to_chat(src, "Here are your current laws:")
|
||||
show_laws()
|
||||
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)
|
||||
//bring up APC dialog
|
||||
apc_override = 1
|
||||
theAPC.attack_ai(src)
|
||||
apc_override = 0
|
||||
aiRestorePowerRoutine = 3
|
||||
sleep(50)
|
||||
theAPC = null
|
||||
|
||||
process_queued_alarms()
|
||||
|
||||
/mob/living/silicon/ai/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = 100
|
||||
stat = CONSCIOUS
|
||||
else
|
||||
health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss()
|
||||
update_stat("updatehealth([reason])")
|
||||
diag_hud_set_status()
|
||||
diag_hud_set_health()
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/lacks_power()
|
||||
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/rejuvenate()
|
||||
..()
|
||||
add_ai_verbs(src)
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/mob/living/silicon/ai/Login() //ThisIsDumb(TM) TODO: tidy this up �_� ~Carn
|
||||
..()
|
||||
for(var/obj/effect/rune/rune in world)
|
||||
var/image/blood = image(loc = rune)
|
||||
blood.override = 1
|
||||
client.images += blood
|
||||
regenerate_icons()
|
||||
|
||||
if(stat != DEAD)
|
||||
for(var/obj/machinery/ai_status_display/O in GLOB.machines) //change status
|
||||
O.mode = 1
|
||||
O.emotion = "Neutral"
|
||||
if(multicam_on)
|
||||
end_multicam()
|
||||
view_core()
|
||||
/mob/living/silicon/ai/Login() //ThisIsDumb(TM) TODO: tidy this up �_� ~Carn
|
||||
..()
|
||||
for(var/obj/effect/rune/rune in world)
|
||||
var/image/blood = image(loc = rune)
|
||||
blood.override = 1
|
||||
client.images += blood
|
||||
regenerate_icons()
|
||||
|
||||
if(stat != DEAD)
|
||||
for(var/obj/machinery/ai_status_display/O in GLOB.machines) //change status
|
||||
O.mode = 1
|
||||
O.emotion = "Neutral"
|
||||
if(multicam_on)
|
||||
end_multicam()
|
||||
view_core()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/mob/living/silicon/ai/Logout()
|
||||
..()
|
||||
for(var/obj/machinery/ai_status_display/O in world) //change status
|
||||
O.mode = 0
|
||||
src.view_core()
|
||||
return
|
||||
/mob/living/silicon/ai/Logout()
|
||||
..()
|
||||
for(var/obj/machinery/ai_status_display/O in world) //change status
|
||||
O.mode = 0
|
||||
src.view_core()
|
||||
return
|
||||
|
||||
@@ -1,185 +1,185 @@
|
||||
/*
|
||||
* AI Saycode
|
||||
*/
|
||||
|
||||
|
||||
/mob/living/silicon/ai/handle_track(var/message, var/verb = "says", var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear)
|
||||
if(hard_to_hear)
|
||||
return
|
||||
|
||||
var/jobname // the mob's "job"
|
||||
var/mob/living/carbon/human/impersonating //The crewmember being impersonated, if any.
|
||||
var/changed_voice
|
||||
|
||||
if(ishuman(speaker))
|
||||
var/mob/living/carbon/human/H = speaker
|
||||
|
||||
var/obj/item/card/id/id = H.wear_id
|
||||
if((istype(id) && id.is_untrackable()) && H.HasVoiceChanger())
|
||||
changed_voice = 1
|
||||
var/mob/living/carbon/human/I = locate(speaker_name)
|
||||
if(I)
|
||||
impersonating = I
|
||||
jobname = impersonating.get_assignment()
|
||||
else
|
||||
jobname = "Unknown"
|
||||
else
|
||||
jobname = H.get_assignment()
|
||||
|
||||
else if(iscarbon(speaker)) // Nonhuman carbon mob
|
||||
jobname = "No ID"
|
||||
else if(isAI(speaker))
|
||||
jobname = "AI"
|
||||
else if(isrobot(speaker))
|
||||
jobname = "Cyborg"
|
||||
else if(ispAI(speaker))
|
||||
jobname = "Personal AI"
|
||||
else if(isAutoAnnouncer(speaker))
|
||||
var/mob/living/automatedannouncer/AA = speaker
|
||||
jobname = AA.role
|
||||
else
|
||||
jobname = "Unknown"
|
||||
|
||||
var/track = ""
|
||||
var/mob/mob_to_track = null
|
||||
if(changed_voice)
|
||||
if(impersonating)
|
||||
mob_to_track = impersonating
|
||||
else
|
||||
track = "[speaker_name] ([jobname])"
|
||||
else
|
||||
if(istype(follow_target, /mob/living/simple_animal/bot))
|
||||
track = "<a href='byond://?src=[UID()];trackbot=\ref[follow_target]'>[speaker_name] ([jobname])</a>"
|
||||
else
|
||||
mob_to_track = speaker
|
||||
|
||||
if(mob_to_track)
|
||||
track = "<a href='byond://?src=[UID()];track=\ref[mob_to_track]'>[speaker_name] ([jobname])</a>"
|
||||
track += " <a href='byond://?src=[UID()];open=\ref[mob_to_track]'>\[Open\]</a>"
|
||||
|
||||
return track
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* AI VOX Announcements
|
||||
*/
|
||||
|
||||
var/announcing_vox = 0 // Stores the time of the last announcement
|
||||
#define VOX_DELAY 100
|
||||
#define VOX_PATH "sound/vox_fem/"
|
||||
|
||||
/mob/living/silicon/ai/verb/announcement_help()
|
||||
set name = "Announcement Help"
|
||||
set desc = "Display a list of vocal words to announce to the crew."
|
||||
set category = "AI Commands"
|
||||
|
||||
var/dat = "Here is a list of words you can type into the 'Announcement' button to create sentences to vocally announce to everyone on the same level at you.<BR> \
|
||||
<UL><LI>You can also click on the word to preview it.</LI>\
|
||||
<LI>You can only say 30 words for every announcement.</LI>\
|
||||
<LI>Do not use punctuation as you would normally, if you want a pause you can use the full stop and comma characters by separating them with spaces, like so: 'Alpha . Test , Bravo'.</LI></UL>\
|
||||
<font class='bad'>WARNING:</font><BR>Misuse of the announcement system will get you job banned.<HR>"
|
||||
|
||||
var/index = 0
|
||||
for(var/word in vox_sounds)
|
||||
index++
|
||||
dat += "<A href='?src=[UID()];say_word=[word]'>[capitalize(word)]</A>"
|
||||
if(index != vox_sounds.len)
|
||||
dat += " / "
|
||||
|
||||
var/datum/browser/popup = new(src, "announce_help", "Announcement Help", 500, 400)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_announcement()
|
||||
if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO))
|
||||
return
|
||||
|
||||
if(announcing_vox > world.time)
|
||||
to_chat(src, "<span class='warning'>Please wait [round((announcing_vox - world.time) / 10)] seconds.</span>")
|
||||
return
|
||||
|
||||
var/message = clean_input("WARNING: Misuse of this verb can result in you being job banned. More help is available in 'Announcement Help'", "Announcement", last_announcement, src)
|
||||
|
||||
last_announcement = message
|
||||
|
||||
if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO))
|
||||
return
|
||||
|
||||
if(!message || announcing_vox > world.time)
|
||||
return
|
||||
|
||||
var/list/words = splittext(trim(message), " ")
|
||||
var/list/incorrect_words = list()
|
||||
|
||||
if(words.len > 30)
|
||||
words.len = 30
|
||||
|
||||
for(var/word in words)
|
||||
word = lowertext(trim(word))
|
||||
if(!word)
|
||||
words -= word
|
||||
continue
|
||||
if(!vox_sounds[word])
|
||||
incorrect_words += word
|
||||
|
||||
if(incorrect_words.len)
|
||||
to_chat(src, "<span class='warning'>These words are not available on the announcement system: [english_list(incorrect_words)].</span>")
|
||||
return
|
||||
|
||||
announcing_vox = world.time + VOX_DELAY
|
||||
|
||||
log_game("[key_name(src)] made a vocal announcement: [message].")
|
||||
message_admins("[key_name_admin(src)] made a vocal announcement: [message].")
|
||||
|
||||
for(var/word in words)
|
||||
play_vox_word(word, src.z, null)
|
||||
|
||||
ai_voice_announcement_to_text(words)
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_voice_announcement_to_text(words)
|
||||
var/words_string = jointext(words, " ")
|
||||
var/formatted_message = "<h1 class='alert'>A.I. Announcement</h1>"
|
||||
formatted_message += "<br><span class='alert'>[words_string]</span>"
|
||||
formatted_message += "<br><span class='alert'> -[src]</span>"
|
||||
|
||||
for(var/player in GLOB.player_list)
|
||||
var/mob/M = player
|
||||
if(M.client && !(M.client.prefs.sound & SOUND_AI_VOICE))
|
||||
var/turf/T = get_turf(M)
|
||||
if(T && T.z == z && M.can_hear())
|
||||
SEND_SOUND(M, 'sound/misc/notice2.ogg')
|
||||
to_chat(M, formatted_message)
|
||||
|
||||
/proc/play_vox_word(word, z_level, mob/only_listener)
|
||||
|
||||
word = lowertext(word)
|
||||
|
||||
if(vox_sounds[word])
|
||||
|
||||
var/sound_file = vox_sounds[word]
|
||||
var/sound/voice = sound(sound_file, wait = 1, channel = CHANNEL_VOX)
|
||||
voice.status = SOUND_STREAM
|
||||
|
||||
// If there is no single listener, broadcast to everyone in the same z level
|
||||
if(!only_listener)
|
||||
// Play voice for all mobs in the z level
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M.client && M.client.prefs.sound & SOUND_AI_VOICE)
|
||||
var/turf/T = get_turf(M)
|
||||
if(T && T.z == z_level && M.can_hear())
|
||||
M << voice
|
||||
else
|
||||
only_listener << voice
|
||||
return 1
|
||||
return 0
|
||||
|
||||
// VOX sounds moved to /code/defines/vox_sounds.dm
|
||||
|
||||
/client/proc/preload_vox()
|
||||
var/list/vox_files = flist(VOX_PATH)
|
||||
for(var/file in vox_files)
|
||||
// to_chat(src, "Downloading [file]")
|
||||
var/sound/S = sound("[VOX_PATH][file]")
|
||||
src << browse_rsc(S)
|
||||
/*
|
||||
* AI Saycode
|
||||
*/
|
||||
|
||||
|
||||
/mob/living/silicon/ai/handle_track(var/message, var/verb = "says", var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear)
|
||||
if(hard_to_hear)
|
||||
return
|
||||
|
||||
var/jobname // the mob's "job"
|
||||
var/mob/living/carbon/human/impersonating //The crewmember being impersonated, if any.
|
||||
var/changed_voice
|
||||
|
||||
if(ishuman(speaker))
|
||||
var/mob/living/carbon/human/H = speaker
|
||||
|
||||
var/obj/item/card/id/id = H.wear_id
|
||||
if((istype(id) && id.is_untrackable()) && H.HasVoiceChanger())
|
||||
changed_voice = 1
|
||||
var/mob/living/carbon/human/I = locate(speaker_name)
|
||||
if(I)
|
||||
impersonating = I
|
||||
jobname = impersonating.get_assignment()
|
||||
else
|
||||
jobname = "Unknown"
|
||||
else
|
||||
jobname = H.get_assignment()
|
||||
|
||||
else if(iscarbon(speaker)) // Nonhuman carbon mob
|
||||
jobname = "No ID"
|
||||
else if(isAI(speaker))
|
||||
jobname = "AI"
|
||||
else if(isrobot(speaker))
|
||||
jobname = "Cyborg"
|
||||
else if(ispAI(speaker))
|
||||
jobname = "Personal AI"
|
||||
else if(isAutoAnnouncer(speaker))
|
||||
var/mob/living/automatedannouncer/AA = speaker
|
||||
jobname = AA.role
|
||||
else
|
||||
jobname = "Unknown"
|
||||
|
||||
var/track = ""
|
||||
var/mob/mob_to_track = null
|
||||
if(changed_voice)
|
||||
if(impersonating)
|
||||
mob_to_track = impersonating
|
||||
else
|
||||
track = "[speaker_name] ([jobname])"
|
||||
else
|
||||
if(istype(follow_target, /mob/living/simple_animal/bot))
|
||||
track = "<a href='byond://?src=[UID()];trackbot=\ref[follow_target]'>[speaker_name] ([jobname])</a>"
|
||||
else
|
||||
mob_to_track = speaker
|
||||
|
||||
if(mob_to_track)
|
||||
track = "<a href='byond://?src=[UID()];track=\ref[mob_to_track]'>[speaker_name] ([jobname])</a>"
|
||||
track += " <a href='byond://?src=[UID()];open=\ref[mob_to_track]'>\[Open\]</a>"
|
||||
|
||||
return track
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* AI VOX Announcements
|
||||
*/
|
||||
|
||||
var/announcing_vox = 0 // Stores the time of the last announcement
|
||||
#define VOX_DELAY 100
|
||||
#define VOX_PATH "sound/vox_fem/"
|
||||
|
||||
/mob/living/silicon/ai/verb/announcement_help()
|
||||
set name = "Announcement Help"
|
||||
set desc = "Display a list of vocal words to announce to the crew."
|
||||
set category = "AI Commands"
|
||||
|
||||
var/dat = "Here is a list of words you can type into the 'Announcement' button to create sentences to vocally announce to everyone on the same level at you.<BR> \
|
||||
<UL><LI>You can also click on the word to preview it.</LI>\
|
||||
<LI>You can only say 30 words for every announcement.</LI>\
|
||||
<LI>Do not use punctuation as you would normally, if you want a pause you can use the full stop and comma characters by separating them with spaces, like so: 'Alpha . Test , Bravo'.</LI></UL>\
|
||||
<font class='bad'>WARNING:</font><BR>Misuse of the announcement system will get you job banned.<HR>"
|
||||
|
||||
var/index = 0
|
||||
for(var/word in vox_sounds)
|
||||
index++
|
||||
dat += "<A href='?src=[UID()];say_word=[word]'>[capitalize(word)]</A>"
|
||||
if(index != vox_sounds.len)
|
||||
dat += " / "
|
||||
|
||||
var/datum/browser/popup = new(src, "announce_help", "Announcement Help", 500, 400)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_announcement()
|
||||
if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO))
|
||||
return
|
||||
|
||||
if(announcing_vox > world.time)
|
||||
to_chat(src, "<span class='warning'>Please wait [round((announcing_vox - world.time) / 10)] seconds.</span>")
|
||||
return
|
||||
|
||||
var/message = clean_input("WARNING: Misuse of this verb can result in you being job banned. More help is available in 'Announcement Help'", "Announcement", last_announcement, src)
|
||||
|
||||
last_announcement = message
|
||||
|
||||
if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO))
|
||||
return
|
||||
|
||||
if(!message || announcing_vox > world.time)
|
||||
return
|
||||
|
||||
var/list/words = splittext(trim(message), " ")
|
||||
var/list/incorrect_words = list()
|
||||
|
||||
if(words.len > 30)
|
||||
words.len = 30
|
||||
|
||||
for(var/word in words)
|
||||
word = lowertext(trim(word))
|
||||
if(!word)
|
||||
words -= word
|
||||
continue
|
||||
if(!vox_sounds[word])
|
||||
incorrect_words += word
|
||||
|
||||
if(incorrect_words.len)
|
||||
to_chat(src, "<span class='warning'>These words are not available on the announcement system: [english_list(incorrect_words)].</span>")
|
||||
return
|
||||
|
||||
announcing_vox = world.time + VOX_DELAY
|
||||
|
||||
log_game("[key_name(src)] made a vocal announcement: [message].")
|
||||
message_admins("[key_name_admin(src)] made a vocal announcement: [message].")
|
||||
|
||||
for(var/word in words)
|
||||
play_vox_word(word, src.z, null)
|
||||
|
||||
ai_voice_announcement_to_text(words)
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_voice_announcement_to_text(words)
|
||||
var/words_string = jointext(words, " ")
|
||||
var/formatted_message = "<h1 class='alert'>A.I. Announcement</h1>"
|
||||
formatted_message += "<br><span class='alert'>[words_string]</span>"
|
||||
formatted_message += "<br><span class='alert'> -[src]</span>"
|
||||
|
||||
for(var/player in GLOB.player_list)
|
||||
var/mob/M = player
|
||||
if(M.client && !(M.client.prefs.sound & SOUND_AI_VOICE))
|
||||
var/turf/T = get_turf(M)
|
||||
if(T && T.z == z && M.can_hear())
|
||||
SEND_SOUND(M, 'sound/misc/notice2.ogg')
|
||||
to_chat(M, formatted_message)
|
||||
|
||||
/proc/play_vox_word(word, z_level, mob/only_listener)
|
||||
|
||||
word = lowertext(word)
|
||||
|
||||
if(vox_sounds[word])
|
||||
|
||||
var/sound_file = vox_sounds[word]
|
||||
var/sound/voice = sound(sound_file, wait = 1, channel = CHANNEL_VOX)
|
||||
voice.status = SOUND_STREAM
|
||||
|
||||
// If there is no single listener, broadcast to everyone in the same z level
|
||||
if(!only_listener)
|
||||
// Play voice for all mobs in the z level
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M.client && M.client.prefs.sound & SOUND_AI_VOICE)
|
||||
var/turf/T = get_turf(M)
|
||||
if(T && T.z == z_level && M.can_hear())
|
||||
M << voice
|
||||
else
|
||||
only_listener << voice
|
||||
return 1
|
||||
return 0
|
||||
|
||||
// VOX sounds moved to /code/defines/vox_sounds.dm
|
||||
|
||||
/client/proc/preload_vox()
|
||||
var/list/vox_files = flist(VOX_PATH)
|
||||
for(var/file in vox_files)
|
||||
// to_chat(src, "Downloading [file]")
|
||||
var/sound/S = sound("[VOX_PATH][file]")
|
||||
src << browse_rsc(S)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/mob/living/silicon/decoy/death(gibbed)
|
||||
// Only execute the below if we successfully died
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
icon_state = "ai-crash"
|
||||
for(var/obj/machinery/ai_status_display/O in world) //change status
|
||||
if(atoms_share_level(O, src))
|
||||
O.mode = 2
|
||||
gib()
|
||||
/mob/living/silicon/decoy/death(gibbed)
|
||||
// Only execute the below if we successfully died
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
icon_state = "ai-crash"
|
||||
for(var/obj/machinery/ai_status_display/O in world) //change status
|
||||
if(atoms_share_level(O, src))
|
||||
O.mode = 2
|
||||
gib()
|
||||
|
||||
@@ -1,62 +1,62 @@
|
||||
/mob/living/silicon/decoy
|
||||
name = "AI"
|
||||
icon = 'icons/mob/ai.dmi'//
|
||||
icon_state = "ai"
|
||||
anchored = 1 // -- TLE
|
||||
canmove = 0
|
||||
a_intent = INTENT_HARM // This is apparently the only thing that stops other mobs walking through them as if they were thin air.
|
||||
|
||||
/mob/living/silicon/decoy/New()
|
||||
src.icon = 'icons/mob/ai.dmi'
|
||||
src.icon_state = "ai"
|
||||
src.anchored = 1
|
||||
src.canmove = 0
|
||||
|
||||
/mob/living/silicon/decoy/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/aicard))
|
||||
to_chat(user, "<span class='warning'>You cannot find an intellicard slot on [src].</span>")
|
||||
return TRUE
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/decoy/welder_act()
|
||||
return
|
||||
|
||||
/mob/living/silicon/decoy/syndicate
|
||||
faction = list("syndicate")
|
||||
name = "R.O.D.G.E.R"
|
||||
desc = "Red Operations, Depot General Emission Regulator"
|
||||
icon_state = "ai-magma"
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/New()
|
||||
. = ..()
|
||||
icon_state = "ai-magma"
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot
|
||||
universal_speak = TRUE
|
||||
universal_understand = TRUE
|
||||
var/raised_alert = FALSE
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot/proc/raise_alert()
|
||||
raised_alert = TRUE
|
||||
var/area/syndicate_depot/core/depotarea = get_area(src) // Cannot use myArea or areaMaster as neither will be defined for this mob type
|
||||
if(istype(depotarea))
|
||||
depotarea.increase_alert("AI Unit Offline")
|
||||
else
|
||||
say("Connection failure!")
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot/death(pass)
|
||||
if(!raised_alert)
|
||||
raise_alert()
|
||||
. = ..(pass)
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot/adjustBruteLoss(dmg)
|
||||
. = ..(dmg)
|
||||
updatehealth()
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot/adjustFireLoss(dmg)
|
||||
. = ..(dmg)
|
||||
updatehealth()
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot/ex_act(severity)
|
||||
adjustBruteLoss(250)
|
||||
/mob/living/silicon/decoy
|
||||
name = "AI"
|
||||
icon = 'icons/mob/ai.dmi'//
|
||||
icon_state = "ai"
|
||||
anchored = 1 // -- TLE
|
||||
canmove = 0
|
||||
a_intent = INTENT_HARM // This is apparently the only thing that stops other mobs walking through them as if they were thin air.
|
||||
|
||||
/mob/living/silicon/decoy/New()
|
||||
src.icon = 'icons/mob/ai.dmi'
|
||||
src.icon_state = "ai"
|
||||
src.anchored = 1
|
||||
src.canmove = 0
|
||||
|
||||
/mob/living/silicon/decoy/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/aicard))
|
||||
to_chat(user, "<span class='warning'>You cannot find an intellicard slot on [src].</span>")
|
||||
return TRUE
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/decoy/welder_act()
|
||||
return
|
||||
|
||||
/mob/living/silicon/decoy/syndicate
|
||||
faction = list("syndicate")
|
||||
name = "R.O.D.G.E.R"
|
||||
desc = "Red Operations, Depot General Emission Regulator"
|
||||
icon_state = "ai-magma"
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/New()
|
||||
. = ..()
|
||||
icon_state = "ai-magma"
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot
|
||||
universal_speak = TRUE
|
||||
universal_understand = TRUE
|
||||
var/raised_alert = FALSE
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot/proc/raise_alert()
|
||||
raised_alert = TRUE
|
||||
var/area/syndicate_depot/core/depotarea = get_area(src) // Cannot use myArea or areaMaster as neither will be defined for this mob type
|
||||
if(istype(depotarea))
|
||||
depotarea.increase_alert("AI Unit Offline")
|
||||
else
|
||||
say("Connection failure!")
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot/death(pass)
|
||||
if(!raised_alert)
|
||||
raise_alert()
|
||||
. = ..(pass)
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot/adjustBruteLoss(dmg)
|
||||
. = ..(dmg)
|
||||
updatehealth()
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot/adjustFireLoss(dmg)
|
||||
. = ..(dmg)
|
||||
updatehealth()
|
||||
|
||||
/mob/living/silicon/decoy/syndicate/depot/ex_act(severity)
|
||||
adjustBruteLoss(250)
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
/mob/living/silicon/decoy/Life(seconds, times_fired)
|
||||
return
|
||||
|
||||
|
||||
/mob/living/silicon/decoy/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = 100
|
||||
stat = CONSCIOUS
|
||||
else
|
||||
health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss()
|
||||
update_stat("updatehealth([reason])")
|
||||
|
||||
|
||||
/mob/living/silicon/decoy/update_stat(reason = "none given")
|
||||
if(stat == DEAD)
|
||||
return
|
||||
if(health <= 0)
|
||||
death()
|
||||
create_debug_log("died of damage, trigger reason: [reason]")
|
||||
/mob/living/silicon/decoy/Life(seconds, times_fired)
|
||||
return
|
||||
|
||||
|
||||
/mob/living/silicon/decoy/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = 100
|
||||
stat = CONSCIOUS
|
||||
else
|
||||
health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss()
|
||||
update_stat("updatehealth([reason])")
|
||||
|
||||
|
||||
/mob/living/silicon/decoy/update_stat(reason = "none given")
|
||||
if(stat == DEAD)
|
||||
return
|
||||
if(health <= 0)
|
||||
death()
|
||||
create_debug_log("died of damage, trigger reason: [reason]")
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/mob/living/silicon/Login()
|
||||
SetSleeping(0)
|
||||
if(mind && SSticker && SSticker.mode)
|
||||
SSticker.mode.remove_revolutionary(mind, 1)
|
||||
SSticker.mode.remove_cultist(mind, 1)
|
||||
SSticker.mode.remove_wizard(mind)
|
||||
SSticker.mode.remove_changeling(mind)
|
||||
SSticker.mode.remove_vampire(mind)
|
||||
SSticker.mode.remove_thrall(mind, 0)
|
||||
SSticker.mode.remove_shadowling(mind)
|
||||
SSticker.mode.remove_abductor(mind)
|
||||
..()
|
||||
/mob/living/silicon/Login()
|
||||
SetSleeping(0)
|
||||
if(mind && SSticker && SSticker.mode)
|
||||
SSticker.mode.remove_revolutionary(mind, 1)
|
||||
SSticker.mode.remove_cultist(mind, 1)
|
||||
SSticker.mode.remove_wizard(mind)
|
||||
SSticker.mode.remove_changeling(mind)
|
||||
SSticker.mode.remove_vampire(mind)
|
||||
SSticker.mode.remove_thrall(mind, 0)
|
||||
SSticker.mode.remove_shadowling(mind)
|
||||
SSticker.mode.remove_abductor(mind)
|
||||
..()
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/mob/living/silicon/pai/death(gibbed, cleanWipe)
|
||||
if(can_die())
|
||||
if(!cleanWipe)
|
||||
force_fold_out()
|
||||
|
||||
visible_message("<span class=warning>[src] emits a dull beep before it loses power and collapses.</span>", "<span class=warning>You hear a dull beep followed by the sound of glass crunching.</span>")
|
||||
name = "pAI debris"
|
||||
desc = "The unfortunate remains of some poor personal AI device."
|
||||
icon_state = "[chassis]_dead"
|
||||
|
||||
// Only execute the below if we successfully died
|
||||
. = ..(gibbed)
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
if(icon_state != "[chassis]_dead" || cleanWipe)
|
||||
qdel(src)
|
||||
/mob/living/silicon/pai/death(gibbed, cleanWipe)
|
||||
if(can_die())
|
||||
if(!cleanWipe)
|
||||
force_fold_out()
|
||||
|
||||
visible_message("<span class=warning>[src] emits a dull beep before it loses power and collapses.</span>", "<span class=warning>You hear a dull beep followed by the sound of glass crunching.</span>")
|
||||
name = "pAI debris"
|
||||
desc = "The unfortunate remains of some poor personal AI device."
|
||||
icon_state = "[chassis]_dead"
|
||||
|
||||
// Only execute the below if we successfully died
|
||||
. = ..(gibbed)
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
if(icon_state != "[chassis]_dead" || cleanWipe)
|
||||
qdel(src)
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
/mob/living/silicon/pai/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(.)
|
||||
//if(secHUD == 1)
|
||||
// process_sec_hud(src, 1)
|
||||
////if(medHUD == 1)
|
||||
// process_med_hud(src, 1)
|
||||
if(silence_time)
|
||||
if(world.timeofday >= silence_time)
|
||||
silence_time = null
|
||||
to_chat(src, "<font color=green>Communication circuit reinitialized. Speech and messaging functionality restored.</font>")
|
||||
|
||||
if(cable)
|
||||
if(get_dist(src, cable) > 1)
|
||||
var/turf/T = get_turf_or_move(loc)
|
||||
for(var/mob/M in viewers(T))
|
||||
M.show_message("<span class='warning'>The data cable rapidly retracts back into its spool.</span>", 3, "<span class='warning'>You hear a click and the sound of wire spooling rapidly.</span>", 2)
|
||||
qdel(src.cable)
|
||||
cable = null
|
||||
|
||||
/mob/living/silicon/pai/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = 100
|
||||
stat = CONSCIOUS
|
||||
else
|
||||
health = 100 - getBruteLoss() - getFireLoss()
|
||||
update_stat("updatehealth([reason])")
|
||||
/mob/living/silicon/pai/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(.)
|
||||
//if(secHUD == 1)
|
||||
// process_sec_hud(src, 1)
|
||||
////if(medHUD == 1)
|
||||
// process_med_hud(src, 1)
|
||||
if(silence_time)
|
||||
if(world.timeofday >= silence_time)
|
||||
silence_time = null
|
||||
to_chat(src, "<font color=green>Communication circuit reinitialized. Speech and messaging functionality restored.</font>")
|
||||
|
||||
if(cable)
|
||||
if(get_dist(src, cable) > 1)
|
||||
var/turf/T = get_turf_or_move(loc)
|
||||
for(var/mob/M in viewers(T))
|
||||
M.show_message("<span class='warning'>The data cable rapidly retracts back into its spool.</span>", 3, "<span class='warning'>You hear a click and the sound of wire spooling rapidly.</span>", 2)
|
||||
qdel(src.cable)
|
||||
cable = null
|
||||
|
||||
/mob/living/silicon/pai/updatehealth(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
health = 100
|
||||
stat = CONSCIOUS
|
||||
else
|
||||
health = 100 - getBruteLoss() - getFireLoss()
|
||||
update_stat("updatehealth([reason])")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user