mirror of
https://github.com/KabKebab/GS13.git
synced 2026-07-13 00:47:42 +01:00
Revert "Merge branch 'punishesarchie' of https://github.com/MalricB/Hyper-Station-13 into punishesarchie"
This reverts commit1945c166b4, reversing changes made toc8d20ea83c.
This commit is contained in:
@@ -185,7 +185,7 @@
|
||||
name = "Flat Top (Big)"
|
||||
icon_state = "hair_bigflattop"
|
||||
|
||||
/datum/sprite_accessory/hair/flow
|
||||
/datum/sprite_accessory/hair/fag
|
||||
name = "Flow Hair"
|
||||
icon_state = "hair_f"
|
||||
|
||||
@@ -470,7 +470,3 @@
|
||||
/datum/sprite_accessory/hair/quotey
|
||||
name = "Tail Hair"
|
||||
icon_state = "hair_tailhair"
|
||||
|
||||
/datum/sprite_accessory/hair/mommy
|
||||
name = "Hairfre"
|
||||
icon_state = "hair_hairfre"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/datum/notificationpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "notificationpanel", "Notification Preferences", 270, 360, master_ui, state)
|
||||
ui = new(user, src, ui_key, "notificationpanel", "Notification Preferences", 700, 700, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/datum/notificationpanel/ui_data(mob/user)
|
||||
|
||||
@@ -232,16 +232,14 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
var/b_val
|
||||
var/g_val
|
||||
var/color_format = length(input_color)
|
||||
if(color_format != length_char(input_color))
|
||||
return 0
|
||||
if(color_format == 3)
|
||||
r_val = hex2num(copytext(input_color, 1, 2)) * 16
|
||||
g_val = hex2num(copytext(input_color, 2, 3)) * 16
|
||||
b_val = hex2num(copytext(input_color, 3, 0)) * 16
|
||||
r_val = hex2num(copytext(input_color, 1, 2))*16
|
||||
g_val = hex2num(copytext(input_color, 2, 3))*16
|
||||
b_val = hex2num(copytext(input_color, 3, 0))*16
|
||||
else if(color_format == 6)
|
||||
r_val = hex2num(copytext(input_color, 1, 3))
|
||||
g_val = hex2num(copytext(input_color, 3, 5))
|
||||
b_val = hex2num(copytext(input_color, 5, 7))
|
||||
b_val = hex2num(copytext(input_color, 5, 0))
|
||||
else
|
||||
return 0 //If the color format is not 3 or 6, you're using an unexpected way to represent a color.
|
||||
|
||||
@@ -255,7 +253,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
if(b_val > 255)
|
||||
b_val = 255
|
||||
|
||||
return copytext(rgb(r_val, g_val, b_val), 2)
|
||||
return num2hex(r_val, 2) + num2hex(g_val, 2) + num2hex(b_val, 2)
|
||||
|
||||
/*
|
||||
Transfer_mind is there to check if mob is being deleted/not going to have a body.
|
||||
@@ -264,7 +262,7 @@ Works together with spawning an observer, noted above.
|
||||
|
||||
/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE, penalize = FALSE)
|
||||
penalize = suiciding || penalize // suicide squad.
|
||||
if(!key || key[1] == "@" || (SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special, penalize) & COMPONENT_BLOCK_GHOSTING))
|
||||
if(!key || cmptext(copytext(key,1,2),"@") || (SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special, penalize) & COMPONENT_BLOCK_GHOSTING))
|
||||
return //mob has no key, is an aghost or some component hijacked.
|
||||
stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now
|
||||
var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc.
|
||||
@@ -325,8 +323,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
ghostize(0, penalize = TRUE)
|
||||
|
||||
/mob/dead/observer/Move(NewLoc, direct, glide_size_override = 32)
|
||||
if(SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_MOVE, NewLoc) & COMPONENT_MOVABLE_BLOCK_PRE_MOVE)
|
||||
return
|
||||
if(updatedir)
|
||||
setDir(direct)//only update dir if we actually need it, so overlays won't spin on base sprites that don't have directions of their own
|
||||
var/oldloc = loc
|
||||
@@ -361,7 +357,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if(!can_reenter_corpse)
|
||||
to_chat(src, "<span class='warning'>You cannot re-enter your body.</span>")
|
||||
return
|
||||
if(mind.current.key && mind.current.key[1] != "@") //makes sure we don't accidentally kick any clients
|
||||
if(mind.current.key && copytext(mind.current.key,1,2)!="@") //makes sure we don't accidentally kick any clients
|
||||
to_chat(usr, "<span class='warning'>Another consciousness is in your body...It is resisting you.</span>")
|
||||
return
|
||||
client.change_view(CONFIG_GET(string/default_view))
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/mob/dead/observer/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
if (!message)
|
||||
return
|
||||
|
||||
var/message_mode = get_message_mode(message)
|
||||
if(client && (message_mode == MODE_ADMIN || message_mode == MODE_DEADMIN))
|
||||
message = copytext_char(message, 3)
|
||||
message = trim_left(message)
|
||||
message = copytext(message, 3)
|
||||
if(findtext(message, " ", 1, 2))
|
||||
message = copytext(message, 2)
|
||||
|
||||
if(message_mode == MODE_ADMIN)
|
||||
client.cmd_admin_say(message)
|
||||
@@ -21,7 +22,7 @@
|
||||
|
||||
. = say_dead(message)
|
||||
|
||||
/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
var/atom/movable/to_follow = speaker
|
||||
if(radio_freq)
|
||||
@@ -37,6 +38,6 @@
|
||||
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
|
||||
create_chat_message(speaker, message_language, raw_message, spans, message_mode)
|
||||
// Recompose the message, because it's scrambled by default
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
to_chat(src, "[link] [message]")
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
var/param = message
|
||||
var/custom_param = findchar(act, " ")
|
||||
if(custom_param)
|
||||
param = copytext(act, custom_param + length(act[custom_param]))
|
||||
param = copytext(act, custom_param + 1, length(act) + 1)
|
||||
act = copytext(act, 1, custom_param)
|
||||
|
||||
var/datum/emote/E
|
||||
|
||||
@@ -35,9 +35,6 @@
|
||||
|
||||
if(bleed_rate < 0)
|
||||
bleed_rate = 0
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_NOMARROW)) //Bloodsuckers don't need to be here.
|
||||
return
|
||||
|
||||
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
|
||||
|
||||
@@ -155,7 +152,7 @@
|
||||
if(iscarbon(AM))
|
||||
var/mob/living/carbon/C = AM
|
||||
if(blood_id == C.get_blood_id())//both mobs have the same blood substance
|
||||
if(blood_id == /datum/reagent/blood || blood_id == /datum/reagent/blood/jellyblood) //normal blood
|
||||
if(blood_id == "blood" || blood_id == "jellyblood") //normal blood
|
||||
if(blood_data["viruses"])
|
||||
for(var/thing in blood_data["viruses"])
|
||||
var/datum/disease/D = thing
|
||||
@@ -175,7 +172,7 @@
|
||||
return
|
||||
|
||||
/mob/living/carbon/get_blood_data(blood_id)
|
||||
if(blood_id == /datum/reagent/blood || /datum/reagent/blood/jellyblood) //actual blood reagent
|
||||
if(blood_id == "blood" || blood_id == "jellyblood") //actual blood reagent
|
||||
var/blood_data = list()
|
||||
//set the blood data
|
||||
blood_data["donor"] = src
|
||||
@@ -185,13 +182,13 @@
|
||||
var/datum/disease/D = thing
|
||||
blood_data["viruses"] += D.Copy()
|
||||
|
||||
blood_data["blood_DNA"] = dna.unique_enzymes
|
||||
blood_data["blood_DNA"] = copytext(dna.unique_enzymes,1,0)
|
||||
blood_data["bloodcolor"] = bloodtype_to_color(dna.blood_type)
|
||||
if(disease_resistances && disease_resistances.len)
|
||||
blood_data["resistances"] = disease_resistances.Copy()
|
||||
var/list/temp_chem = list()
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
temp_chem[R.type] = R.volume
|
||||
temp_chem[R.id] = R.volume
|
||||
blood_data["trace_chem"] = list2params(temp_chem)
|
||||
if(mind)
|
||||
blood_data["mind"] = mind
|
||||
@@ -204,7 +201,7 @@
|
||||
|
||||
if(!suiciding)
|
||||
blood_data["cloneable"] = 1
|
||||
blood_data["blood_type"] = dna.blood_type
|
||||
blood_data["blood_type"] = copytext(dna.blood_type,1,0)
|
||||
blood_data["gender"] = gender
|
||||
blood_data["real_name"] = real_name
|
||||
blood_data["features"] = dna.features
|
||||
@@ -226,21 +223,21 @@
|
||||
|
||||
/mob/living/simple_animal/get_blood_id()
|
||||
if(blood_volume)
|
||||
return /datum/reagent/blood
|
||||
return "blood"
|
||||
|
||||
/mob/living/carbon/monkey/get_blood_id()
|
||||
if(!(HAS_TRAIT(src, TRAIT_NOCLONE)))
|
||||
return /datum/reagent/blood
|
||||
return "blood"
|
||||
|
||||
/mob/living/carbon/get_blood_id()
|
||||
if(isjellyperson(src))
|
||||
return /datum/reagent/blood/jellyblood
|
||||
return "jellyblood"
|
||||
if(dna?.species?.exotic_blood)
|
||||
return dna.species.exotic_blood
|
||||
else if((NOBLOOD in dna.species.species_traits) || (HAS_TRAIT(src, TRAIT_NOCLONE)))
|
||||
return
|
||||
else
|
||||
return /datum/reagent/blood
|
||||
return "blood"
|
||||
|
||||
// This is has more potential uses, and is probably faster than the old proc.
|
||||
/proc/get_safe_blood(bloodtype)
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
|
||||
if(victim.stat == CONSCIOUS)
|
||||
src.visible_message("<span class='warning'>[victim] kicks free of the blood pool just before entering it!</span>", null, "<span class='notice'>You hear splashing and struggling.</span>")
|
||||
else if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/demonsblood))
|
||||
else if(victim.reagents && victim.reagents.has_reagent("demonsblood"))
|
||||
visible_message("<span class='warning'>Something prevents [victim] from entering the pool!</span>", "<span class='warning'>A strange force is blocking [victim] from entering!</span>", "<span class='notice'>You hear a splash and a thud.</span>")
|
||||
else
|
||||
victim.forceMove(src)
|
||||
@@ -104,7 +104,7 @@
|
||||
if(!victim)
|
||||
return FALSE
|
||||
|
||||
if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/devilskiss))
|
||||
if(victim.reagents && victim.reagents.has_reagent("devilskiss"))
|
||||
to_chat(src, "<span class='warning'><b>AAH! THEIR FLESH! IT BURNS!</b></span>")
|
||||
adjustBruteLoss(25) //I can't use adjustHealth() here because bloodcrawl affects /mob/living and adjustHealth() only affects simple mobs
|
||||
var/found_bloodpool = FALSE
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/obj/item/mmi
|
||||
name = "Man-Machine Interface"
|
||||
desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity, that nevertheless has become standard-issue on Kinaris stations."
|
||||
desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity, that nevertheless has become standard-issue on Nanotrasen stations."
|
||||
icon = 'icons/obj/assemblies.dmi'
|
||||
icon_state = "mmi_off"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
@@ -102,16 +102,16 @@
|
||||
if(istype(O, /obj/item/organ_storage)) //BUG_PROBABLE_CAUSE
|
||||
return //Borg organ bags shouldn't be killing brains
|
||||
|
||||
if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent(/datum/reagent/medicine/neurine)) //Neurine fixes dead brains
|
||||
if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent("neurine")) //Neurine fixes dead brains
|
||||
. = TRUE //don't do attack animation.
|
||||
var/cached_Bdamage = brainmob?.health
|
||||
var/datum/reagent/medicine/neurine/N = reagents.has_reagent(/datum/reagent/medicine/neurine)
|
||||
var/datum/reagent/medicine/mannitol/M1 = reagents.has_reagent(/datum/reagent/medicine/mannitol)
|
||||
var/datum/reagent/medicine/neurine/N = O.reagents.has_reagent("neurine")
|
||||
var/datum/reagent/medicine/mannitol/M1 = O.reagents.has_reagent("mannitol")
|
||||
|
||||
if(O.reagents.has_reagent(/datum/reagent/medicine/mannitol))//Just a quick way to bolster the effects if someone mixes up a batch.
|
||||
if(O.reagents.has_reagent("mannitol"))//Just a quick way to bolster the effects if someone mixes up a batch.
|
||||
N.volume *= (M1.volume*0.5)
|
||||
|
||||
if(!O.reagents.has_reagent(/datum/reagent/medicine/neurine, 10))
|
||||
if(!O.reagents.has_reagent("neurine", 10))
|
||||
to_chat(user, "<span class='warning'>There's not enough neurine in [O] to restore [src]!</span>")
|
||||
return
|
||||
|
||||
@@ -134,14 +134,14 @@
|
||||
gain_trauma_type(BRAIN_TRAUMA_SPECIAL)
|
||||
return
|
||||
|
||||
if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent(/datum/reagent/medicine/mannitol)) //attempt to heal the brain
|
||||
if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent("mannitol")) //attempt to heal the brain
|
||||
. = TRUE //don't do attack animation.
|
||||
var/datum/reagent/medicine/mannitol/M = reagents.has_reagent(/datum/reagent/medicine/mannitol)
|
||||
var/datum/reagent/medicine/mannitol/M = O.reagents.has_reagent("mannitol")
|
||||
if(brain_death || brainmob?.health <= HEALTH_THRESHOLD_DEAD) //if the brain is fucked anyway, do nothing
|
||||
to_chat(user, "<span class='warning'>[src] is far too damaged, you'll have to use neurine on it!</span>")
|
||||
return
|
||||
|
||||
if(!O.reagents.has_reagent(/datum/reagent/medicine/mannitol, 10))
|
||||
if(!O.reagents.has_reagent("mannitol", 10))
|
||||
to_chat(user, "<span class='warning'>There's not enough mannitol in [O] to restore [src]!</span>")
|
||||
return
|
||||
|
||||
|
||||
@@ -120,8 +120,7 @@ Des: Removes all infected images from the alien.
|
||||
/mob/living/carbon/alien/proc/RemoveInfectionImages()
|
||||
if (client)
|
||||
for(var/image/I in client.images)
|
||||
var/searchfor = "infected"
|
||||
if(findtext(I.icon_state, searchfor, 1, length(searchfor) + 1))
|
||||
if(dd_hasprefix_case(I.icon_state, "infected"))
|
||||
qdel(I)
|
||||
return
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
/obj/item/organ/alien/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
|
||||
S.reagents.add_reagent("sacid", 10)
|
||||
return S
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.reagents.add_reagent(/datum/reagent/toxin/plasma, storedPlasma/10)
|
||||
S.reagents.add_reagent("plasma", storedPlasma/10)
|
||||
return S
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/large
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
/obj/item/organ/body_egg/alien_embryo/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
|
||||
S.reagents.add_reagent("sacid", 10)
|
||||
return S
|
||||
|
||||
/obj/item/organ/body_egg/alien_embryo/on_life()
|
||||
@@ -133,6 +133,5 @@ Des: Removes all images from the mob infected by this embryo
|
||||
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
|
||||
if(alien.client)
|
||||
for(var/image/I in alien.client.images)
|
||||
var/searchfor = "infected"
|
||||
if(I.loc == owner && findtext(I.icon_state, searchfor, 1, length(searchfor) + 1))
|
||||
if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == owner)
|
||||
qdel(I)
|
||||
|
||||
@@ -518,7 +518,7 @@
|
||||
add_splatter_floor(T)
|
||||
if(stun)
|
||||
adjustBruteLoss(3)
|
||||
else if(src.reagents.has_reagent(/datum/reagent/consumable/ethanol/blazaam))
|
||||
else if(src.reagents.has_reagent("blazaam"))
|
||||
if(T)
|
||||
T.add_vomit_floor(src, VOMIT_PURPLE)
|
||||
else
|
||||
@@ -561,7 +561,7 @@
|
||||
health = round(maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute, DAMAGE_PRECISION)
|
||||
staminaloss = round(total_stamina, DAMAGE_PRECISION)
|
||||
update_stat()
|
||||
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD*2) && stat == DEAD )
|
||||
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
|
||||
become_husk("burn")
|
||||
med_hud_set_health()
|
||||
if(stat == SOFT_CRIT)
|
||||
@@ -804,8 +804,6 @@
|
||||
/mob/living/carbon/update_stat()
|
||||
if(status_flags & GODMODE)
|
||||
return
|
||||
if(stat != CONSCIOUS)
|
||||
clear_typing_indicator()
|
||||
if(stat != DEAD)
|
||||
if(health <= HEALTH_THRESHOLD_DEAD && !HAS_TRAIT(src, TRAIT_NODEATH))
|
||||
death()
|
||||
@@ -813,13 +811,9 @@
|
||||
if(IsUnconscious() || IsSleeping() || getOxyLoss() > 50 || (HAS_TRAIT(src, TRAIT_DEATHCOMA)) || (health <= HEALTH_THRESHOLD_FULLCRIT && !HAS_TRAIT(src, TRAIT_NOHARDCRIT)))
|
||||
stat = UNCONSCIOUS
|
||||
blind_eyes(1)
|
||||
if(combatmode)
|
||||
toggle_combat_mode(TRUE, TRUE)
|
||||
else
|
||||
if(health <= crit_threshold && !HAS_TRAIT(src, TRAIT_NOSOFTCRIT))
|
||||
stat = SOFT_CRIT
|
||||
if(combatmode)
|
||||
toggle_combat_mode(TRUE, TRUE)
|
||||
else
|
||||
stat = CONSCIOUS
|
||||
adjust_blindness(-1)
|
||||
@@ -980,19 +974,3 @@
|
||||
if(mood)
|
||||
if(mood.sanity < SANITY_UNSTABLE)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/can_see_reagents()
|
||||
. = ..()
|
||||
if(.) //No need to run through all of this if it's already true.
|
||||
return
|
||||
if(isclothing(head))
|
||||
var/obj/item/clothing/H = head
|
||||
if(H.clothing_flags & SCAN_REAGENTS)
|
||||
return TRUE
|
||||
if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/transfer_ckey(mob/new_mob, send_signal = TRUE)
|
||||
if(combatmode)
|
||||
toggle_combat_mode(TRUE, TRUE)
|
||||
return ..()
|
||||
|
||||
@@ -1,486 +1,486 @@
|
||||
|
||||
/mob/living/carbon/get_eye_protection()
|
||||
var/number = ..()
|
||||
|
||||
if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head
|
||||
var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item
|
||||
number += HFP.flash_protect
|
||||
|
||||
if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses
|
||||
var/obj/item/clothing/glasses/GFP = src.glasses
|
||||
number += GFP.flash_protect
|
||||
|
||||
if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask
|
||||
var/obj/item/clothing/mask/MFP = src.wear_mask
|
||||
number += MFP.flash_protect
|
||||
|
||||
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
|
||||
if(!E)
|
||||
number = INFINITY //Can't get flashed without eyes
|
||||
else
|
||||
number += E.flash_protect
|
||||
|
||||
return number
|
||||
|
||||
/mob/living/carbon/get_ear_protection()
|
||||
var/number = ..()
|
||||
var/obj/item/organ/ears/E = getorganslot(ORGAN_SLOT_EARS)
|
||||
if(!E)
|
||||
number = INFINITY
|
||||
else
|
||||
number += E.bang_protect
|
||||
return number
|
||||
|
||||
/mob/living/carbon/is_mouth_covered(head_only = 0, mask_only = 0)
|
||||
if( (!mask_only && head && (head.flags_cover & HEADCOVERSMOUTH)) || (!head_only && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH)) )
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/is_eyes_covered(check_glasses = 1, check_head = 1, check_mask = 1)
|
||||
if(check_glasses && glasses && (glasses.flags_cover & GLASSESCOVERSEYES))
|
||||
return TRUE
|
||||
if(check_head && head && (head.flags_cover & HEADCOVERSEYES))
|
||||
return TRUE
|
||||
if(check_mask && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH))
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(def_zone)
|
||||
if(affecting && affecting.dismemberable && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
|
||||
affecting.dismember(P.damtype)
|
||||
|
||||
/mob/living/carbon/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
|
||||
. = ..()
|
||||
if(!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) && !skip_throw_mode_check && !in_throw_mode)
|
||||
return
|
||||
if(get_active_held_item() || restrained())
|
||||
return
|
||||
I.attack_hand(src)
|
||||
if(get_active_held_item() == I) //if our attack_hand() picks up the item...
|
||||
visible_message("<span class='warning'>[src] catches [I]!</span>") //catch that sucker!
|
||||
throw_mode_off()
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/embed_item(obj/item/I)
|
||||
throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
|
||||
var/obj/item/bodypart/L = pick(bodyparts)
|
||||
L.embedded_objects |= I
|
||||
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
|
||||
I.forceMove(src)
|
||||
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
|
||||
visible_message("<span class='danger'>[I] embeds itself in [src]'s [L.name]!</span>","<span class='userdanger'>[I] embeds itself in your [L.name]!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
|
||||
|
||||
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
|
||||
//CIT CHANGES START HERE - combatmode and resting checks
|
||||
var/totitemdamage = I.force
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/tempcarb = user
|
||||
if(!tempcarb.combatmode)
|
||||
totitemdamage *= 0.5
|
||||
if(user.resting)
|
||||
totitemdamage *= 0.5
|
||||
if(!combatmode)
|
||||
totitemdamage *= 1.5
|
||||
//CIT CHANGES END HERE
|
||||
if(user != src && check_shields(I, totitemdamage, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
|
||||
return FALSE
|
||||
var/obj/item/bodypart/affecting
|
||||
if(user == src)
|
||||
affecting = get_bodypart(check_zone(user.zone_selected)) //we're self-mutilating! yay!
|
||||
else
|
||||
affecting = get_bodypart(ran_zone(user.zone_selected))
|
||||
if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest)
|
||||
affecting = bodyparts[1]
|
||||
SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
|
||||
send_item_attack_message(I, user, affecting.name)
|
||||
if(I.force)
|
||||
apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage
|
||||
if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
|
||||
var/basebloodychance = affecting.brute_dam + totitemdamage
|
||||
if(prob(basebloodychance))
|
||||
I.add_mob_blood(src)
|
||||
bleed(totitemdamage)
|
||||
if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood
|
||||
user.add_mob_blood(src)
|
||||
|
||||
if(affecting.body_zone == BODY_ZONE_HEAD)
|
||||
if(wear_mask && prob(basebloodychance))
|
||||
wear_mask.add_mob_blood(src)
|
||||
update_inv_wear_mask()
|
||||
if(wear_neck && prob(basebloodychance))
|
||||
wear_neck.add_mob_blood(src)
|
||||
update_inv_neck()
|
||||
if(head && prob(basebloodychance))
|
||||
head.add_mob_blood(src)
|
||||
update_inv_head()
|
||||
|
||||
//dismemberment
|
||||
var/probability = I.get_dismemberment_chance(affecting)
|
||||
if(prob(probability))
|
||||
if(affecting.dismember(I.damtype))
|
||||
I.add_mob_blood(src)
|
||||
playsound(get_turf(src), I.get_dismember_sound(), 80, 1)
|
||||
return TRUE //successful attack
|
||||
|
||||
/mob/living/carbon/attack_drone(mob/living/simple_animal/drone/user)
|
||||
return //so we don't call the carbon's attack_hand().
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/mob/living/carbon/attack_hand(mob/living/carbon/human/user)
|
||||
. = ..()
|
||||
if(.) //was the attack blocked?
|
||||
return
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
|
||||
user.ContactContractDisease(D)
|
||||
|
||||
for(var/thing in user.diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
|
||||
ContactContractDisease(D)
|
||||
|
||||
if(lying && surgeries.len)
|
||||
if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
|
||||
for(var/datum/surgery/S in surgeries)
|
||||
if(S.next_step(user, user.a_intent))
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
|
||||
|
||||
if(can_inject(M, TRUE))
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if((D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) && prob(85))
|
||||
M.ContactContractDisease(D)
|
||||
|
||||
for(var/thing in M.diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
|
||||
ContactContractDisease(D)
|
||||
|
||||
if(M.a_intent == INTENT_HELP)
|
||||
help_shake_act(M)
|
||||
return 0
|
||||
|
||||
. = ..()
|
||||
if(.) //successful monkey bite.
|
||||
for(var/thing in M.diseases)
|
||||
var/datum/disease/D = thing
|
||||
ForceContractDisease(D)
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(M.powerlevel > 0)
|
||||
var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
|
||||
if(prob(stunprob))
|
||||
M.powerlevel -= 3
|
||||
if(M.powerlevel < 0)
|
||||
M.powerlevel = 0
|
||||
|
||||
visible_message("<span class='danger'>The [M.name] has shocked [src]!</span>", \
|
||||
"<span class='userdanger'>The [M.name] has shocked [src]!</span>")
|
||||
|
||||
do_sparks(5, TRUE, src)
|
||||
var/power = M.powerlevel + rand(0,3)
|
||||
Knockdown(power*20)
|
||||
if(stuttering < power)
|
||||
stuttering = power
|
||||
if (prob(stunprob) && M.powerlevel >= 8)
|
||||
adjustFireLoss(M.powerlevel * rand(6,10))
|
||||
updatehealth()
|
||||
|
||||
/mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone)
|
||||
if(!attacker.limb_destroyer)
|
||||
return dam_zone
|
||||
var/obj/item/bodypart/affecting
|
||||
if(dam_zone && attacker.client)
|
||||
affecting = get_bodypart(ran_zone(dam_zone))
|
||||
else
|
||||
var/list/things_to_ruin = shuffle(bodyparts.Copy())
|
||||
for(var/B in things_to_ruin)
|
||||
var/obj/item/bodypart/bodypart = B
|
||||
if(bodypart.body_zone == BODY_ZONE_HEAD || bodypart.body_zone == BODY_ZONE_CHEST)
|
||||
continue
|
||||
if(!affecting || ((affecting.get_damage() / affecting.max_damage) < (bodypart.get_damage() / bodypart.max_damage)))
|
||||
affecting = bodypart
|
||||
if(affecting)
|
||||
dam_zone = affecting.body_zone
|
||||
if(affecting.get_damage() >= affecting.max_damage)
|
||||
affecting.dismember()
|
||||
return null
|
||||
return affecting.body_zone
|
||||
return dam_zone
|
||||
|
||||
|
||||
/mob/living/carbon/blob_act(obj/structure/blob/B)
|
||||
if (stat == DEAD)
|
||||
return
|
||||
else
|
||||
show_message("<span class='userdanger'>The blob attacks!</span>")
|
||||
adjustBruteLoss(10)
|
||||
|
||||
/mob/living/carbon/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_CONTENTS)
|
||||
return
|
||||
for(var/X in internal_organs)
|
||||
var/obj/item/organ/O = X
|
||||
O.emp_act(severity)
|
||||
|
||||
/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
|
||||
if(tesla_shock && (flags_1 & TESLA_IGNORE_1))
|
||||
return FALSE
|
||||
if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
|
||||
return FALSE
|
||||
shock_damage *= siemens_coeff
|
||||
if(dna && dna.species)
|
||||
shock_damage *= dna.species.siemens_coeff
|
||||
if(shock_damage<1 && !override)
|
||||
return 0
|
||||
if(reagents.has_reagent(/datum/reagent/teslium))
|
||||
shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging!
|
||||
if(illusion)
|
||||
adjustStaminaLoss(shock_damage)
|
||||
else
|
||||
take_overall_damage(0,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>" \
|
||||
)
|
||||
jitteriness += 1000 //High numbers for violent convulsions
|
||||
do_jitter_animation(jitteriness)
|
||||
stuttering += 2
|
||||
if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
|
||||
Stun(40)
|
||||
spawn(20)
|
||||
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
|
||||
if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
|
||||
Knockdown(60)
|
||||
if(override)
|
||||
return override
|
||||
else
|
||||
return shock_damage
|
||||
|
||||
/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
|
||||
if(on_fire)
|
||||
to_chat(M, "<span class='warning'>You can't put [p_them()] out with just your bare hands!</span>")
|
||||
return
|
||||
|
||||
if(health >= 0 && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
|
||||
|
||||
if(lying)
|
||||
if(buckled)
|
||||
to_chat(M, "<span class='warning'>You need to unbuckle [src] first to do that!")
|
||||
return
|
||||
M.visible_message("<span class='notice'>[M] shakes [src] trying to get [p_them()] up!</span>", \
|
||||
"<span class='notice'>You shake [src] trying to get [p_them()] up!</span>")
|
||||
|
||||
else if(check_zone(M.zone_selected) == "head")
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/datum/species/pref_species = H.dna.species
|
||||
|
||||
if(HAS_TRAIT(H, TRAIT_HEADPAT_SLUT))
|
||||
M.visible_message("<span class='notice'>[M] gives [H] a pat on the head to make [p_them()] feel better! They seem incredibly pleased!</span>", \
|
||||
"<span class='notice'>You give [H] a pat on the head to make [p_them()] feel better! They seem to like it way too much</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "lewd_headpat", /datum/mood_event/lewd_headpat)
|
||||
H.adjustArousalLoss(5) //Headpats are hot af
|
||||
else
|
||||
M.visible_message("<span class='notice'>[M] gives [H] a pat on the head to make [p_them()] feel better!</span>", \
|
||||
"<span class='notice'>You give [H] a pat on the head to make [p_them()] feel better!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
|
||||
|
||||
if(HAS_TRAIT(M, TRAIT_FRIENDLY))
|
||||
var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
|
||||
if (mood.sanity >= SANITY_GREAT)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
|
||||
else if (mood.sanity >= SANITY_DISTURBED)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
|
||||
if(H.dna.species.can_wag_tail(H))
|
||||
if("tail_human" in pref_species.default_features)
|
||||
if(H.dna.features["tail_human"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
if("tail_lizard" in pref_species.default_features)
|
||||
if(H.dna.features["tail_lizard"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
if("mam_tail" in pref_species.default_features)
|
||||
if(H.dna.features["mam_tail"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
else if(check_zone(M.zone_selected) == "mouth")
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/datum/species/pref_species = H.dna.species
|
||||
|
||||
M.visible_message("<span class='notice'>[M] gives [H] a boop on the nose.", \
|
||||
"<span class='notice'>You give [H] a boop on the nose!</span>")
|
||||
|
||||
if(H.dna.species.can_wag_tail(H))
|
||||
if("tail_human" in pref_species.default_features)
|
||||
if(H.dna.features["tail_human"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
if("tail_lizard" in pref_species.default_features)
|
||||
if(H.dna.features["tail_lizard"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
if("mam_tail" in pref_species.default_features)
|
||||
if(H.dna.features["mam_tail"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
else
|
||||
M.visible_message("<span class='notice'>[M] hugs [src] to make [p_them()] feel better!</span>", \
|
||||
"<span class='notice'>You hug [src] to make [p_them()] feel better!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug)
|
||||
if(HAS_TRAIT(M, TRAIT_FRIENDLY))
|
||||
var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
|
||||
if (mood.sanity >= SANITY_GREAT)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
|
||||
else if (mood.sanity >= SANITY_DISTURBED)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
|
||||
|
||||
AdjustStun(-60)
|
||||
AdjustKnockdown(-60)
|
||||
AdjustUnconscious(-60)
|
||||
AdjustSleeping(-100)
|
||||
if(recoveringstam)
|
||||
adjustStaminaLoss(-15)
|
||||
else if(resting)
|
||||
resting = 0
|
||||
update_canmove()
|
||||
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
|
||||
|
||||
/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
|
||||
. = ..()
|
||||
|
||||
var/damage = intensity - get_eye_protection()
|
||||
if(.) // we've been flashed
|
||||
var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
|
||||
if (!eyes)
|
||||
return
|
||||
if(visual)
|
||||
return
|
||||
|
||||
if (damage == 1)
|
||||
to_chat(src, "<span class='warning'>Your eyes sting a little.</span>")
|
||||
if(prob(40))
|
||||
adjust_eye_damage(1)
|
||||
|
||||
else if (damage == 2)
|
||||
to_chat(src, "<span class='warning'>Your eyes burn.</span>")
|
||||
adjust_eye_damage(rand(2, 4))
|
||||
|
||||
else if( damage >= 3)
|
||||
to_chat(src, "<span class='warning'>Your eyes itch and burn severely!</span>")
|
||||
adjust_eye_damage(rand(12, 16))
|
||||
|
||||
if(eyes.eye_damage > 10)
|
||||
blind_eyes(damage)
|
||||
blur_eyes(damage * rand(3, 6))
|
||||
|
||||
if(eyes.eye_damage > 20)
|
||||
if(prob(eyes.eye_damage - 20))
|
||||
if(!HAS_TRAIT(src, TRAIT_NEARSIGHT))
|
||||
to_chat(src, "<span class='warning'>Your eyes start to burn badly!</span>")
|
||||
become_nearsighted(EYE_DAMAGE)
|
||||
|
||||
else if(prob(eyes.eye_damage - 25))
|
||||
if(!HAS_TRAIT(src, TRAIT_BLIND))
|
||||
to_chat(src, "<span class='warning'>You can't see anything!</span>")
|
||||
become_blind(EYE_DAMAGE)
|
||||
|
||||
else
|
||||
to_chat(src, "<span class='warning'>Your eyes are really starting to hurt. This can't be good for you!</span>")
|
||||
if(has_bane(BANE_LIGHT))
|
||||
mind.disrupt_spells(-500)
|
||||
return 1
|
||||
else if(damage == 0) // just enough protection
|
||||
if(prob(20))
|
||||
to_chat(src, "<span class='notice'>Something bright flashes in the corner of your vision!</span>")
|
||||
if(has_bane(BANE_LIGHT))
|
||||
mind.disrupt_spells(0)
|
||||
|
||||
|
||||
/mob/living/carbon/soundbang_act(intensity = 1, stun_pwr = 20, damage_pwr = 5, deafen_pwr = 15)
|
||||
var/list/reflist = list(intensity) // Need to wrap this in a list so we can pass a reference
|
||||
SEND_SIGNAL(src, COMSIG_CARBON_SOUNDBANG, reflist)
|
||||
intensity = reflist[1]
|
||||
var/ear_safety = get_ear_protection()
|
||||
var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
|
||||
var/effect_amount = intensity - ear_safety
|
||||
if(effect_amount > 0)
|
||||
if(stun_pwr)
|
||||
Knockdown(stun_pwr*effect_amount)
|
||||
|
||||
if(istype(ears) && (deafen_pwr || damage_pwr))
|
||||
var/ear_damage = damage_pwr * effect_amount
|
||||
var/deaf = deafen_pwr * effect_amount
|
||||
adjustEarDamage(ear_damage,deaf)
|
||||
|
||||
if(ears.damage >= 15)
|
||||
to_chat(src, "<span class='warning'>Your ears start to ring badly!</span>")
|
||||
if(prob(ears.damage - 5))
|
||||
to_chat(src, "<span class='userdanger'>You can't hear anything!</span>")
|
||||
ears.damage = min(ears.damage, ears.maxHealth)
|
||||
// you need earmuffs, inacusiate, or replacement
|
||||
else if(ears.damage >= 5)
|
||||
to_chat(src, "<span class='warning'>Your ears start to ring!</span>")
|
||||
SEND_SOUND(src, sound('sound/weapons/flash_ring.ogg',0,1,0,250))
|
||||
return effect_amount //how soundbanged we are
|
||||
|
||||
|
||||
/mob/living/carbon/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
|
||||
if(damage_type != BRUTE && damage_type != BURN)
|
||||
return
|
||||
damage_amount *= 0.5 //0.5 multiplier for balance reason, we don't want clothes to be too easily destroyed
|
||||
if(!def_zone || def_zone == BODY_ZONE_HEAD)
|
||||
var/obj/item/clothing/hit_clothes
|
||||
if(wear_mask)
|
||||
hit_clothes = wear_mask
|
||||
if(wear_neck)
|
||||
hit_clothes = wear_neck
|
||||
if(head)
|
||||
hit_clothes = head
|
||||
if(hit_clothes)
|
||||
hit_clothes.take_damage(damage_amount, damage_type, damage_flag, 0)
|
||||
|
||||
/mob/living/carbon/can_hear()
|
||||
. = FALSE
|
||||
var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
|
||||
if(istype(ears) && !ears.deaf)
|
||||
. = TRUE
|
||||
|
||||
/mob/living/carbon/get_eye_protection()
|
||||
var/number = ..()
|
||||
|
||||
if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head
|
||||
var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item
|
||||
number += HFP.flash_protect
|
||||
|
||||
if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses
|
||||
var/obj/item/clothing/glasses/GFP = src.glasses
|
||||
number += GFP.flash_protect
|
||||
|
||||
if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask
|
||||
var/obj/item/clothing/mask/MFP = src.wear_mask
|
||||
number += MFP.flash_protect
|
||||
|
||||
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
|
||||
if(!E)
|
||||
number = INFINITY //Can't get flashed without eyes
|
||||
else
|
||||
number += E.flash_protect
|
||||
|
||||
return number
|
||||
|
||||
/mob/living/carbon/get_ear_protection()
|
||||
var/number = ..()
|
||||
var/obj/item/organ/ears/E = getorganslot(ORGAN_SLOT_EARS)
|
||||
if(!E)
|
||||
number = INFINITY
|
||||
else
|
||||
number += E.bang_protect
|
||||
return number
|
||||
|
||||
/mob/living/carbon/is_mouth_covered(head_only = 0, mask_only = 0)
|
||||
if( (!mask_only && head && (head.flags_cover & HEADCOVERSMOUTH)) || (!head_only && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH)) )
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/is_eyes_covered(check_glasses = 1, check_head = 1, check_mask = 1)
|
||||
if(check_glasses && glasses && (glasses.flags_cover & GLASSESCOVERSEYES))
|
||||
return TRUE
|
||||
if(check_head && head && (head.flags_cover & HEADCOVERSEYES))
|
||||
return TRUE
|
||||
if(check_mask && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH))
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(def_zone)
|
||||
if(affecting && affecting.dismemberable && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
|
||||
affecting.dismember(P.damtype)
|
||||
|
||||
/mob/living/carbon/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
|
||||
. = ..()
|
||||
if(!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) && !skip_throw_mode_check && !in_throw_mode)
|
||||
return
|
||||
if(get_active_held_item() || restrained())
|
||||
return
|
||||
I.attack_hand(src)
|
||||
if(get_active_held_item() == I) //if our attack_hand() picks up the item...
|
||||
visible_message("<span class='warning'>[src] catches [I]!</span>") //catch that sucker!
|
||||
throw_mode_off()
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/embed_item(obj/item/I)
|
||||
throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
|
||||
var/obj/item/bodypart/L = pick(bodyparts)
|
||||
L.embedded_objects |= I
|
||||
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
|
||||
I.forceMove(src)
|
||||
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
|
||||
visible_message("<span class='danger'>[I] embeds itself in [src]'s [L.name]!</span>","<span class='userdanger'>[I] embeds itself in your [L.name]!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
|
||||
|
||||
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
|
||||
//CIT CHANGES START HERE - combatmode and resting checks
|
||||
var/totitemdamage = I.force
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/tempcarb = user
|
||||
if(!tempcarb.combatmode)
|
||||
totitemdamage *= 0.5
|
||||
if(user.resting)
|
||||
totitemdamage *= 0.5
|
||||
if(!combatmode)
|
||||
totitemdamage *= 1.5
|
||||
//CIT CHANGES END HERE
|
||||
if(user != src && check_shields(I, totitemdamage, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
|
||||
return FALSE
|
||||
var/obj/item/bodypart/affecting
|
||||
if(user == src)
|
||||
affecting = get_bodypart(check_zone(user.zone_selected)) //we're self-mutilating! yay!
|
||||
else
|
||||
affecting = get_bodypart(ran_zone(user.zone_selected))
|
||||
if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest)
|
||||
affecting = bodyparts[1]
|
||||
SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
|
||||
send_item_attack_message(I, user, affecting.name)
|
||||
if(I.force)
|
||||
apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage
|
||||
if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
|
||||
var/basebloodychance = affecting.brute_dam + totitemdamage
|
||||
if(prob(basebloodychance))
|
||||
I.add_mob_blood(src)
|
||||
bleed(totitemdamage)
|
||||
if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood
|
||||
user.add_mob_blood(src)
|
||||
|
||||
if(affecting.body_zone == BODY_ZONE_HEAD)
|
||||
if(wear_mask && prob(basebloodychance))
|
||||
wear_mask.add_mob_blood(src)
|
||||
update_inv_wear_mask()
|
||||
if(wear_neck && prob(basebloodychance))
|
||||
wear_neck.add_mob_blood(src)
|
||||
update_inv_neck()
|
||||
if(head && prob(basebloodychance))
|
||||
head.add_mob_blood(src)
|
||||
update_inv_head()
|
||||
|
||||
//dismemberment
|
||||
var/probability = I.get_dismemberment_chance(affecting)
|
||||
if(prob(probability))
|
||||
if(affecting.dismember(I.damtype))
|
||||
I.add_mob_blood(src)
|
||||
playsound(get_turf(src), I.get_dismember_sound(), 80, 1)
|
||||
return TRUE //successful attack
|
||||
|
||||
/mob/living/carbon/attack_drone(mob/living/simple_animal/drone/user)
|
||||
return //so we don't call the carbon's attack_hand().
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/mob/living/carbon/attack_hand(mob/living/carbon/human/user)
|
||||
. = ..()
|
||||
if(.) //was the attack blocked?
|
||||
return
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
|
||||
user.ContactContractDisease(D)
|
||||
|
||||
for(var/thing in user.diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
|
||||
ContactContractDisease(D)
|
||||
|
||||
if(lying && surgeries.len)
|
||||
if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
|
||||
for(var/datum/surgery/S in surgeries)
|
||||
if(S.next_step(user, user.a_intent))
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
|
||||
|
||||
if(can_inject(M, TRUE))
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if((D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) && prob(85))
|
||||
M.ContactContractDisease(D)
|
||||
|
||||
for(var/thing in M.diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
|
||||
ContactContractDisease(D)
|
||||
|
||||
if(M.a_intent == INTENT_HELP)
|
||||
help_shake_act(M)
|
||||
return 0
|
||||
|
||||
. = ..()
|
||||
if(.) //successful monkey bite.
|
||||
for(var/thing in M.diseases)
|
||||
var/datum/disease/D = thing
|
||||
ForceContractDisease(D)
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(M.powerlevel > 0)
|
||||
var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
|
||||
if(prob(stunprob))
|
||||
M.powerlevel -= 3
|
||||
if(M.powerlevel < 0)
|
||||
M.powerlevel = 0
|
||||
|
||||
visible_message("<span class='danger'>The [M.name] has shocked [src]!</span>", \
|
||||
"<span class='userdanger'>The [M.name] has shocked [src]!</span>")
|
||||
|
||||
do_sparks(5, TRUE, src)
|
||||
var/power = M.powerlevel + rand(0,3)
|
||||
Knockdown(power*20)
|
||||
if(stuttering < power)
|
||||
stuttering = power
|
||||
if (prob(stunprob) && M.powerlevel >= 8)
|
||||
adjustFireLoss(M.powerlevel * rand(6,10))
|
||||
updatehealth()
|
||||
|
||||
/mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone)
|
||||
if(!attacker.limb_destroyer)
|
||||
return dam_zone
|
||||
var/obj/item/bodypart/affecting
|
||||
if(dam_zone && attacker.client)
|
||||
affecting = get_bodypart(ran_zone(dam_zone))
|
||||
else
|
||||
var/list/things_to_ruin = shuffle(bodyparts.Copy())
|
||||
for(var/B in things_to_ruin)
|
||||
var/obj/item/bodypart/bodypart = B
|
||||
if(bodypart.body_zone == BODY_ZONE_HEAD || bodypart.body_zone == BODY_ZONE_CHEST)
|
||||
continue
|
||||
if(!affecting || ((affecting.get_damage() / affecting.max_damage) < (bodypart.get_damage() / bodypart.max_damage)))
|
||||
affecting = bodypart
|
||||
if(affecting)
|
||||
dam_zone = affecting.body_zone
|
||||
if(affecting.get_damage() >= affecting.max_damage)
|
||||
affecting.dismember()
|
||||
return null
|
||||
return affecting.body_zone
|
||||
return dam_zone
|
||||
|
||||
|
||||
/mob/living/carbon/blob_act(obj/structure/blob/B)
|
||||
if (stat == DEAD)
|
||||
return
|
||||
else
|
||||
show_message("<span class='userdanger'>The blob attacks!</span>")
|
||||
adjustBruteLoss(10)
|
||||
|
||||
/mob/living/carbon/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_CONTENTS)
|
||||
return
|
||||
for(var/X in internal_organs)
|
||||
var/obj/item/organ/O = X
|
||||
O.emp_act(severity)
|
||||
|
||||
/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
|
||||
if(tesla_shock && (flags_1 & TESLA_IGNORE_1))
|
||||
return FALSE
|
||||
if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
|
||||
return FALSE
|
||||
shock_damage *= siemens_coeff
|
||||
if(dna && dna.species)
|
||||
shock_damage *= dna.species.siemens_coeff
|
||||
if(shock_damage<1 && !override)
|
||||
return 0
|
||||
if(reagents.has_reagent("teslium"))
|
||||
shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging!
|
||||
if(illusion)
|
||||
adjustStaminaLoss(shock_damage)
|
||||
else
|
||||
take_overall_damage(0,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>" \
|
||||
)
|
||||
jitteriness += 1000 //High numbers for violent convulsions
|
||||
do_jitter_animation(jitteriness)
|
||||
stuttering += 2
|
||||
if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
|
||||
Stun(40)
|
||||
spawn(20)
|
||||
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
|
||||
if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
|
||||
Knockdown(60)
|
||||
if(override)
|
||||
return override
|
||||
else
|
||||
return shock_damage
|
||||
|
||||
/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
|
||||
if(on_fire)
|
||||
to_chat(M, "<span class='warning'>You can't put [p_them()] out with just your bare hands!</span>")
|
||||
return
|
||||
|
||||
if(health >= 0 && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
|
||||
|
||||
if(lying)
|
||||
if(buckled)
|
||||
to_chat(M, "<span class='warning'>You need to unbuckle [src] first to do that!")
|
||||
return
|
||||
M.visible_message("<span class='notice'>[M] shakes [src] trying to get [p_them()] up!</span>", \
|
||||
"<span class='notice'>You shake [src] trying to get [p_them()] up!</span>")
|
||||
|
||||
else if(check_zone(M.zone_selected) == "head")
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/datum/species/pref_species = H.dna.species
|
||||
|
||||
if(HAS_TRAIT(H, TRAIT_HEADPAT_SLUT))
|
||||
M.visible_message("<span class='notice'>[M] gives [H] a pat on the head to make [p_them()] feel better! They seem incredibly pleased!</span>", \
|
||||
"<span class='notice'>You give [H] a pat on the head to make [p_them()] feel better! They seem to like it way too much</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "lewd_headpat", /datum/mood_event/lewd_headpat)
|
||||
H.adjustArousalLoss(5) //Headpats are hot af
|
||||
else
|
||||
M.visible_message("<span class='notice'>[M] gives [H] a pat on the head to make [p_them()] feel better!</span>", \
|
||||
"<span class='notice'>You give [H] a pat on the head to make [p_them()] feel better!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
|
||||
|
||||
if(HAS_TRAIT(M, TRAIT_FRIENDLY))
|
||||
var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
|
||||
if (mood.sanity >= SANITY_GREAT)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
|
||||
else if (mood.sanity >= SANITY_DISTURBED)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
|
||||
if(H.dna.species.can_wag_tail(H))
|
||||
if("tail_human" in pref_species.default_features)
|
||||
if(H.dna.features["tail_human"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
if("tail_lizard" in pref_species.default_features)
|
||||
if(H.dna.features["tail_lizard"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
if("mam_tail" in pref_species.default_features)
|
||||
if(H.dna.features["mam_tail"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
else if(check_zone(M.zone_selected) == "mouth")
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/datum/species/pref_species = H.dna.species
|
||||
|
||||
M.visible_message("<span class='notice'>[M] gives [H] a boop on the nose.", \
|
||||
"<span class='notice'>You give [H] a boop on the nose!</span>")
|
||||
|
||||
if(H.dna.species.can_wag_tail(H))
|
||||
if("tail_human" in pref_species.default_features)
|
||||
if(H.dna.features["tail_human"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
if("tail_lizard" in pref_species.default_features)
|
||||
if(H.dna.features["tail_lizard"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
if("mam_tail" in pref_species.default_features)
|
||||
if(H.dna.features["mam_tail"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
else
|
||||
M.visible_message("<span class='notice'>[M] hugs [src] to make [p_them()] feel better!</span>", \
|
||||
"<span class='notice'>You hug [src] to make [p_them()] feel better!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug)
|
||||
if(HAS_TRAIT(M, TRAIT_FRIENDLY))
|
||||
var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
|
||||
if (mood.sanity >= SANITY_GREAT)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
|
||||
else if (mood.sanity >= SANITY_DISTURBED)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
|
||||
|
||||
AdjustStun(-60)
|
||||
AdjustKnockdown(-60)
|
||||
AdjustUnconscious(-60)
|
||||
AdjustSleeping(-100)
|
||||
if(recoveringstam)
|
||||
adjustStaminaLoss(-15)
|
||||
else if(resting)
|
||||
resting = 0
|
||||
update_canmove()
|
||||
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
|
||||
|
||||
/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
|
||||
. = ..()
|
||||
|
||||
var/damage = intensity - get_eye_protection()
|
||||
if(.) // we've been flashed
|
||||
var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
|
||||
if (!eyes)
|
||||
return
|
||||
if(visual)
|
||||
return
|
||||
|
||||
if (damage == 1)
|
||||
to_chat(src, "<span class='warning'>Your eyes sting a little.</span>")
|
||||
if(prob(40))
|
||||
adjust_eye_damage(1)
|
||||
|
||||
else if (damage == 2)
|
||||
to_chat(src, "<span class='warning'>Your eyes burn.</span>")
|
||||
adjust_eye_damage(rand(2, 4))
|
||||
|
||||
else if( damage >= 3)
|
||||
to_chat(src, "<span class='warning'>Your eyes itch and burn severely!</span>")
|
||||
adjust_eye_damage(rand(12, 16))
|
||||
|
||||
if(eyes.eye_damage > 10)
|
||||
blind_eyes(damage)
|
||||
blur_eyes(damage * rand(3, 6))
|
||||
|
||||
if(eyes.eye_damage > 20)
|
||||
if(prob(eyes.eye_damage - 20))
|
||||
if(!HAS_TRAIT(src, TRAIT_NEARSIGHT))
|
||||
to_chat(src, "<span class='warning'>Your eyes start to burn badly!</span>")
|
||||
become_nearsighted(EYE_DAMAGE)
|
||||
|
||||
else if(prob(eyes.eye_damage - 25))
|
||||
if(!HAS_TRAIT(src, TRAIT_BLIND))
|
||||
to_chat(src, "<span class='warning'>You can't see anything!</span>")
|
||||
become_blind(EYE_DAMAGE)
|
||||
|
||||
else
|
||||
to_chat(src, "<span class='warning'>Your eyes are really starting to hurt. This can't be good for you!</span>")
|
||||
if(has_bane(BANE_LIGHT))
|
||||
mind.disrupt_spells(-500)
|
||||
return 1
|
||||
else if(damage == 0) // just enough protection
|
||||
if(prob(20))
|
||||
to_chat(src, "<span class='notice'>Something bright flashes in the corner of your vision!</span>")
|
||||
if(has_bane(BANE_LIGHT))
|
||||
mind.disrupt_spells(0)
|
||||
|
||||
|
||||
/mob/living/carbon/soundbang_act(intensity = 1, stun_pwr = 20, damage_pwr = 5, deafen_pwr = 15)
|
||||
var/list/reflist = list(intensity) // Need to wrap this in a list so we can pass a reference
|
||||
SEND_SIGNAL(src, COMSIG_CARBON_SOUNDBANG, reflist)
|
||||
intensity = reflist[1]
|
||||
var/ear_safety = get_ear_protection()
|
||||
var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
|
||||
var/effect_amount = intensity - ear_safety
|
||||
if(effect_amount > 0)
|
||||
if(stun_pwr)
|
||||
Knockdown(stun_pwr*effect_amount)
|
||||
|
||||
if(istype(ears) && (deafen_pwr || damage_pwr))
|
||||
var/ear_damage = damage_pwr * effect_amount
|
||||
var/deaf = deafen_pwr * effect_amount
|
||||
adjustEarDamage(ear_damage,deaf)
|
||||
|
||||
if(ears.damage >= 15)
|
||||
to_chat(src, "<span class='warning'>Your ears start to ring badly!</span>")
|
||||
if(prob(ears.damage - 5))
|
||||
to_chat(src, "<span class='userdanger'>You can't hear anything!</span>")
|
||||
ears.damage = min(ears.damage, ears.maxHealth)
|
||||
// you need earmuffs, inacusiate, or replacement
|
||||
else if(ears.damage >= 5)
|
||||
to_chat(src, "<span class='warning'>Your ears start to ring!</span>")
|
||||
SEND_SOUND(src, sound('sound/weapons/flash_ring.ogg',0,1,0,250))
|
||||
return effect_amount //how soundbanged we are
|
||||
|
||||
|
||||
/mob/living/carbon/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
|
||||
if(damage_type != BRUTE && damage_type != BURN)
|
||||
return
|
||||
damage_amount *= 0.5 //0.5 multiplier for balance reason, we don't want clothes to be too easily destroyed
|
||||
if(!def_zone || def_zone == BODY_ZONE_HEAD)
|
||||
var/obj/item/clothing/hit_clothes
|
||||
if(wear_mask)
|
||||
hit_clothes = wear_mask
|
||||
if(wear_neck)
|
||||
hit_clothes = wear_neck
|
||||
if(head)
|
||||
hit_clothes = head
|
||||
if(hit_clothes)
|
||||
hit_clothes.take_damage(damage_amount, damage_type, damage_flag, 0)
|
||||
|
||||
/mob/living/carbon/can_hear()
|
||||
. = FALSE
|
||||
var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
|
||||
if(istype(ears) && !ears.deaf)
|
||||
. = TRUE
|
||||
|
||||
@@ -64,8 +64,6 @@
|
||||
|
||||
|
||||
/mob/living/carbon/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
if (!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL))
|
||||
return FALSE
|
||||
if(!forced && (status_flags & GODMODE))
|
||||
return FALSE
|
||||
if(amount > 0)
|
||||
@@ -75,8 +73,6 @@
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
if (!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL)) //Vamps don't heal naturally.
|
||||
return FALSE
|
||||
if(!forced && (status_flags & GODMODE))
|
||||
return FALSE
|
||||
if(amount > 0)
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
|
||||
if(!gibbed)
|
||||
emote("deathgasp")
|
||||
if(combatmode)
|
||||
toggle_combat_mode(TRUE, TRUE)
|
||||
|
||||
. = ..()
|
||||
|
||||
@@ -65,8 +63,3 @@
|
||||
var/obj/item/bodypart/BP = X
|
||||
BP.drop_limb()
|
||||
BP.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5)
|
||||
|
||||
/mob/living/carbon/ghostize(can_reenter_corpse = TRUE, special = FALSE, penalize = FALSE)
|
||||
if(combatmode)
|
||||
toggle_combat_mode(TRUE, TRUE)
|
||||
return ..()
|
||||
|
||||
@@ -92,8 +92,7 @@
|
||||
. += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly unsimian manner."
|
||||
|
||||
if(combatmode)
|
||||
. += "[t_He] [t_is] visibly tense[resting ? "." : ", and [t_is] standing in combative stance."]\n"
|
||||
. += common_trait_examine()
|
||||
. += "[t_He] [t_is] visibly tense[resting ? "." : ", and [t_is] standing in combative stance."]"
|
||||
|
||||
var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
|
||||
if(mood)
|
||||
|
||||
@@ -187,9 +187,3 @@
|
||||
key_third_person = "chimes"
|
||||
message = "chimes."
|
||||
sound = 'sound/machines/chime.ogg'
|
||||
|
||||
/datum/emote/sound/human/squeak
|
||||
key = "squeak"
|
||||
key_third_person = "squeaks"
|
||||
message = "lets out a squeak."
|
||||
sound = 'sound/effects/mousesqueek.ogg'
|
||||
|
||||
@@ -1,426 +1,414 @@
|
||||
/mob/living/carbon/human/examine(mob/user) //User is the person being examined
|
||||
//this is very slightly better than it was because you can use it more places. still can't do \his[src] though.
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_His = p_their(TRUE)
|
||||
var/t_his = p_their()
|
||||
var/t_him = p_them()
|
||||
var/t_has = p_have()
|
||||
var/t_is = p_are()
|
||||
var/obscure_name
|
||||
var/dispSize = round(12*size_multiplier) // gets the character's sprite size percent and converts it to the nearest half foot
|
||||
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
if(HAS_TRAIT(L, TRAIT_PROSOPAGNOSIA))
|
||||
obscure_name = TRUE
|
||||
|
||||
. = list("<span class='info'>*---------*\nThis is <EM>[!obscure_name ? name : "Unknown"]</EM>!")
|
||||
|
||||
var/vampDesc = ReturnVampExamine(user) // Vamps recognize the names of other vamps.
|
||||
var/vassDesc = ReturnVassalExamine(user) // Vassals recognize each other's marks.
|
||||
if (vampDesc != "") // If we don't do it this way, we add a blank space to the string...something to do with this --> . += ""
|
||||
. += vampDesc
|
||||
if (vassDesc != "")
|
||||
. += vassDesc
|
||||
|
||||
var/list/obscured = check_obscured_slots()
|
||||
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
|
||||
|
||||
if(ishuman(src)) //user just returned, y'know, the user's own species. dumb.
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/datum/species/pref_species = H.dna.species
|
||||
if(get_visible_name() == "Unknown") // same as flavor text, but hey it works.
|
||||
. += "You can't make out what species they are."
|
||||
else if(skipface)
|
||||
. += "You can't make out what species they are."
|
||||
else
|
||||
. += "[t_He] [t_is] a [H.dna.custom_species ? H.dna.custom_species : pref_species.name]!"
|
||||
|
||||
//uniform
|
||||
if(w_uniform && !(SLOT_W_UNIFORM in obscured))
|
||||
//accessory
|
||||
var/accessory_msg
|
||||
if(istype(w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/U = w_uniform
|
||||
if(U.attached_accessory)
|
||||
accessory_msg += " with [icon2html(U.attached_accessory, user)] \a [U.attached_accessory]"
|
||||
|
||||
. += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_msg]."
|
||||
//head
|
||||
if(head)
|
||||
. += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head."
|
||||
//suit/armor
|
||||
if(wear_suit)
|
||||
. += "[t_He] [t_is] wearing [wear_suit.get_examine_string(user)]."
|
||||
//suit/armor storage
|
||||
if(s_store && !(SLOT_S_STORE in obscured))
|
||||
. += "[t_He] [t_is] carrying [s_store.get_examine_string(user)] on [t_his] [wear_suit.name]."
|
||||
//back
|
||||
if(back)
|
||||
. += "[t_He] [t_has] [back.get_examine_string(user)] on [t_his] back."
|
||||
|
||||
//Hands
|
||||
for(var/obj/item/I in held_items)
|
||||
if(!(I.item_flags & ABSTRACT))
|
||||
. += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))]."
|
||||
|
||||
//gloves
|
||||
if(gloves && !(SLOT_GLOVES in obscured))
|
||||
. += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands."
|
||||
else if(length(blood_DNA))
|
||||
var/hand_number = get_num_arms(FALSE)
|
||||
if(hand_number)
|
||||
. += "<span class='warning'>[t_He] [t_has] [hand_number > 1 ? "" : "a"] blood-stained hand[hand_number > 1 ? "s" : ""]!</span>"
|
||||
//handcuffed?
|
||||
if(handcuffed)
|
||||
if(istype(handcuffed, /obj/item/restraints/handcuffs/cable))
|
||||
. += "<span class='warning'>[t_He] [t_is] [icon2html(handcuffed, user)] restrained with cable!</span>"
|
||||
else
|
||||
. += "<span class='warning'>[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!</span>"
|
||||
|
||||
//belt
|
||||
if(belt)
|
||||
. += "[t_He] [t_has] [belt.get_examine_string(user)] about [t_his] waist."
|
||||
|
||||
//shoes
|
||||
if(shoes && !(SLOT_SHOES in obscured))
|
||||
. += "[t_He] [t_is] wearing [shoes.get_examine_string(user)] on [t_his] feet."
|
||||
|
||||
//mask
|
||||
if(wear_mask && !(SLOT_WEAR_MASK in obscured))
|
||||
. += "[t_He] [t_has] [wear_mask.get_examine_string(user)] on [t_his] face."
|
||||
|
||||
if(wear_neck && !(SLOT_NECK in obscured))
|
||||
. += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck."
|
||||
|
||||
//eyes
|
||||
if(!(SLOT_GLASSES in obscured))
|
||||
if(glasses)
|
||||
. += "[t_He] [t_has] [glasses.get_examine_string(user)] covering [t_his] eyes."
|
||||
else if(eye_color == BLOODCULT_EYE && iscultist(src) && HAS_TRAIT(src, TRAIT_CULT_EYES))
|
||||
. += "<span class='warning'><B>[t_His] eyes are glowing an unnatural red!</B></span>"
|
||||
|
||||
//ears
|
||||
if(ears && !(SLOT_EARS in obscured))
|
||||
. += "[t_He] [t_has] [ears.get_examine_string(user)] on [t_his] ears."
|
||||
|
||||
//ID
|
||||
if(wear_id)
|
||||
. += "[t_He] [t_is] wearing [wear_id.get_examine_string(user)]."
|
||||
|
||||
//Status effects
|
||||
var/effects_exam = status_effect_examines()
|
||||
if(!isnull(effects_exam))
|
||||
. += effects_exam
|
||||
|
||||
//Approximate character height based on current sprite scale
|
||||
if(dispSize % 2) // returns 1 or 0. 1 meaning the height is not exact and the code below will execute, 0 meaning the height is exact and the else will trigger.
|
||||
dispSize = dispSize - 1 //makes it even
|
||||
dispSize = dispSize / 2 //rounds it out
|
||||
. += "[t_He] appears to be around [dispSize] and a half feet tall."
|
||||
else
|
||||
dispSize = dispSize / 2
|
||||
. += "[t_He] appears to be around [dispSize] feet tall."
|
||||
|
||||
//Can be picked up?
|
||||
if(can_be_held)
|
||||
. += "[t_He] might be able to be picked up with <b>Alt+Click</b>!\n"
|
||||
|
||||
//Heat Detection
|
||||
if(breedable)
|
||||
if(HAS_TRAIT(src, TRAIT_HEAT))
|
||||
. += "<span class='love'>[t_He] [t_is] currently in heat.</span>"
|
||||
|
||||
//CIT CHANGES START HERE - adds genital details to examine text
|
||||
if(LAZYLEN(internal_organs))
|
||||
for(var/obj/item/organ/genital/dicc in internal_organs)
|
||||
if(istype(dicc) && dicc.is_exposed())
|
||||
. += "[dicc.desc]"
|
||||
|
||||
var/cursed_stuff = attempt_vr(src,"examine_bellies",args) //vore Code
|
||||
if(!isnull(cursed_stuff))
|
||||
. += cursed_stuff
|
||||
//END OF CIT CHANGES
|
||||
|
||||
//Jitters
|
||||
switch(jitteriness)
|
||||
if(300 to INFINITY)
|
||||
. += "<span class='warning'><B>[t_He] [t_is] convulsing violently!</B></span>"
|
||||
if(200 to 300)
|
||||
. += "<span class='warning'>[t_He] [t_is] extremely jittery.</span>"
|
||||
if(100 to 200)
|
||||
. += "<span class='warning'>[t_He] [t_is] twitching ever so slightly.</span>"
|
||||
|
||||
var/appears_dead = 0
|
||||
if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
|
||||
appears_dead = 1
|
||||
if(suiciding)
|
||||
. += "<span class='warning'>[t_He] appear[p_s()] to have committed suicide... there is no hope of recovery.</span>"
|
||||
if(hellbound)
|
||||
. += "<span class='warning'>[t_His] soul seems to have been ripped out of [t_his] body. Revival is impossible.</span>"
|
||||
if(getorgan(/obj/item/organ/brain) && !key && !get_ghost(FALSE, TRUE))
|
||||
. += "<span class='deadsay'>[t_He] [t_is] limp and unresponsive; there are no signs of life and [t_his] soul has departed...</span>"
|
||||
else
|
||||
. += "<span class='deadsay'>[t_He] [t_is] limp and unresponsive; there are no signs of life...</span>"
|
||||
|
||||
if(get_bodypart(BODY_ZONE_HEAD) && !getorgan(/obj/item/organ/brain))
|
||||
. += "<span class='deadsay'>It appears that [t_his] brain is missing...</span>"
|
||||
|
||||
var/temp = getBruteLoss() //no need to calculate each of these twice
|
||||
|
||||
var/list/msg = list()
|
||||
|
||||
var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
var/list/disabled = list()
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(BP.disabled)
|
||||
disabled += BP
|
||||
missing -= BP.body_zone
|
||||
for(var/obj/item/I in BP.embedded_objects)
|
||||
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
|
||||
if(BP.broken)
|
||||
msg += "<B>[t_He] [t_has] \a [I] broken [BP.name]!</B>\n"
|
||||
|
||||
for(var/X in disabled)
|
||||
var/obj/item/bodypart/BP = X
|
||||
var/damage_text
|
||||
if(!(BP.get_damage(include_stamina = FALSE) >= BP.max_damage)) //Stamina is disabling the limb
|
||||
damage_text = "limp and lifeless"
|
||||
else
|
||||
damage_text = (BP.brute_dam >= BP.burn_dam) ? BP.heavy_brute_msg : BP.heavy_burn_msg
|
||||
msg += "<B>[capitalize(t_his)] [BP.name] is [damage_text]!</B>\n"
|
||||
|
||||
//stores missing limbs
|
||||
var/l_limbs_missing = 0
|
||||
var/r_limbs_missing = 0
|
||||
for(var/t in missing)
|
||||
if(t==BODY_ZONE_HEAD)
|
||||
msg += "<span class='deadsay'><B>[t_His] [parse_zone(t)] is missing!</B><span class='warning'>\n"
|
||||
continue
|
||||
if(t == BODY_ZONE_L_ARM || t == BODY_ZONE_L_LEG)
|
||||
l_limbs_missing++
|
||||
else if(t == BODY_ZONE_R_ARM || t == BODY_ZONE_R_LEG)
|
||||
r_limbs_missing++
|
||||
|
||||
msg += "<B>[capitalize(t_his)] [parse_zone(t)] is missing!</B>\n"
|
||||
|
||||
if(l_limbs_missing >= 2 && r_limbs_missing == 0)
|
||||
msg += "[t_He] look[p_s()] all right now.\n"
|
||||
else if(l_limbs_missing == 0 && r_limbs_missing >= 2)
|
||||
msg += "[t_He] really keeps to the left.\n"
|
||||
else if(l_limbs_missing >= 2 && r_limbs_missing >= 2)
|
||||
msg += "[t_He] [p_do()]n't seem all there.\n"
|
||||
|
||||
if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
|
||||
if(temp)
|
||||
if(temp < 25)
|
||||
msg += "[t_He] [t_has] minor bruising.\n"
|
||||
else if(temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> bruising!\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_has] severe bruising!</B>\n"
|
||||
|
||||
temp = getFireLoss()
|
||||
if(temp)
|
||||
if(temp < 25)
|
||||
msg += "[t_He] [t_has] minor burns.\n"
|
||||
else if (temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> burns!\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_has] severe burns!</B>\n"
|
||||
|
||||
temp = getCloneLoss()
|
||||
if(temp)
|
||||
if(temp < 25)
|
||||
msg += "[t_He] [t_has] minor cellular damage.\n"
|
||||
else if(temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> cellular damage!\n"
|
||||
else
|
||||
msg += "<b>[t_He] [t_has] severe cellular damage!</b>\n"
|
||||
|
||||
|
||||
if(fire_stacks > 0)
|
||||
msg += "[t_He] [t_is] covered in something flammable.\n"
|
||||
if(fire_stacks < 0)
|
||||
msg += "[t_He] look[p_s()] a little soaked.\n"
|
||||
|
||||
|
||||
if(pulledby && pulledby.grab_state)
|
||||
msg += "[t_He] [t_is] restrained by [pulledby]'s grip.\n"
|
||||
|
||||
if(nutrition < NUTRITION_LEVEL_STARVING - 50)
|
||||
msg += "[t_He] [t_is] severely malnourished.\n"
|
||||
else if(nutrition >= NUTRITION_LEVEL_FAT)
|
||||
if(user.nutrition < NUTRITION_LEVEL_STARVING - 50)
|
||||
msg += "[t_He] [t_is] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n"
|
||||
else
|
||||
msg += "[t_He] [t_is] quite chubby.\n"
|
||||
switch(disgust)
|
||||
if(DISGUST_LEVEL_GROSS to DISGUST_LEVEL_VERYGROSS)
|
||||
msg += "[t_He] look[p_s()] a bit grossed out.\n"
|
||||
if(DISGUST_LEVEL_VERYGROSS to DISGUST_LEVEL_DISGUSTED)
|
||||
msg += "[t_He] look[p_s()] really grossed out.\n"
|
||||
if(DISGUST_LEVEL_DISGUSTED to INFINITY)
|
||||
msg += "[t_He] look[p_s()] extremely disgusted.\n"
|
||||
|
||||
if(ShowAsPaleExamine())
|
||||
msg += "[t_He] [t_has] pale skin.\n"
|
||||
|
||||
if(bleedsuppress)
|
||||
msg += "[t_He] [t_is] bandaged with something.\n"
|
||||
else if(bleed_rate)
|
||||
if(reagents.has_reagent("heparin"))
|
||||
msg += "<b>[t_He] [t_is] bleeding uncontrollably!</b>\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_is] bleeding!</B>\n"
|
||||
|
||||
if(reagents.has_reagent(/datum/reagent/teslium))
|
||||
msg += "[t_He] [t_is] emitting a gentle blue glow!\n"
|
||||
|
||||
if(islist(stun_absorption))
|
||||
for(var/i in stun_absorption)
|
||||
if(stun_absorption[i]["end_time"] > world.time && stun_absorption[i]["examine_message"])
|
||||
msg += "[t_He] [t_is][stun_absorption[i]["examine_message"]]\n"
|
||||
|
||||
if(drunkenness && !skipface && !appears_dead) //Drunkenness
|
||||
switch(drunkenness)
|
||||
if(11 to 21)
|
||||
msg += "[t_He] [t_is] slightly flushed.\n"
|
||||
if(21.01 to 41) //.01s are used in case drunkenness ends up to be a small decimal
|
||||
msg += "[t_He] [t_is] flushed.\n"
|
||||
if(41.01 to 51)
|
||||
msg += "[t_He] [t_is] quite flushed and [t_his] breath smells of alcohol.\n"
|
||||
if(51.01 to 61)
|
||||
msg += "[t_He] [t_is] very flushed and [t_his] movements jerky, with breath reeking of alcohol.\n"
|
||||
if(61.01 to 91)
|
||||
msg += "[t_He] look[p_s()] like a drunken mess.\n"
|
||||
if(91.01 to INFINITY)
|
||||
msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
|
||||
|
||||
if(reagents.has_reagent(/datum/reagent/fermi/astral))
|
||||
if(mind)
|
||||
msg += " and they have a strange, abnormal look to them.\n"
|
||||
else
|
||||
msg += " and they don't look like they're all there.\n"
|
||||
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
if(src != user && HAS_TRAIT(L, TRAIT_EMPATH) && !appears_dead)
|
||||
if (a_intent != INTENT_HELP)
|
||||
msg += "[t_He] seem[p_s()] to be on guard.\n"
|
||||
if (getOxyLoss() >= 10)
|
||||
msg += "[t_He] seem[p_s()] winded.\n"
|
||||
if (getToxLoss() >= 10)
|
||||
msg += "[t_He] seem[p_s()] sickly.\n"
|
||||
var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
|
||||
if(mood.sanity <= SANITY_DISTURBED)
|
||||
msg += "[t_He] seem[p_s()] distressed.\n"
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "empath", /datum/mood_event/sad_empath, src)
|
||||
if(mood.shown_mood >= 6) //So roundstart people aren't all "happy" and that antags don't show their true happiness.
|
||||
msg += "[t_He] seem[p_s()] to have had something nice happen to them recently.\n"
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "empathH", /datum/mood_event/happy_empath, src)
|
||||
if (HAS_TRAIT(src, TRAIT_BLIND))
|
||||
msg += "[t_He] appear[p_s()] to be staring off into space.\n"
|
||||
if (HAS_TRAIT(src, TRAIT_DEAF))
|
||||
msg += "[t_He] appear[p_s()] to not be responding to noises.\n"
|
||||
|
||||
msg += "</span>"
|
||||
|
||||
var/obj/item/organ/vocal_cords/Vc = user.getorganslot(ORGAN_SLOT_VOICE)
|
||||
if(Vc)
|
||||
if(istype(Vc, /obj/item/organ/vocal_cords/velvet))
|
||||
if(client?.prefs.lewdchem)
|
||||
msg += "<span class='velvet'><i>You feel your chords resonate looking at them.</i></span>\n"
|
||||
|
||||
|
||||
if(!appears_dead)
|
||||
if(stat == UNCONSCIOUS)
|
||||
msg += "[t_He] [t_is]n't responding to anything around [t_him] and seem[p_s()] to be asleep.\n"
|
||||
else
|
||||
if(HAS_TRAIT(src, TRAIT_DUMB))
|
||||
msg += "[t_He] [t_has] a stupid expression on [t_his] face.\n"
|
||||
if(InCritical())
|
||||
msg += "[t_He] [t_is] barely conscious.\n"
|
||||
if(getorgan(/obj/item/organ/brain))
|
||||
if(!key)
|
||||
msg += "<span class='deadsay'>[t_He] [t_is] totally catatonic. The stresses of life in deep-space must have been too much for [t_him]. Any recovery is unlikely.</span>\n"
|
||||
else if(!client)
|
||||
msg += "[t_He] [t_has] a blank, absent-minded stare and appears completely unresponsive to anything. [t_He] may snap out of it soon.\n"
|
||||
|
||||
if(digitalcamo)
|
||||
msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly inhuman manner.\n"
|
||||
|
||||
if (length(msg))
|
||||
. += "<span class='warning'>[msg.Join("")]</span>"
|
||||
msg += common_trait_examine()
|
||||
|
||||
var/traitstring = get_trait_string()
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/organ/cyberimp/eyes/hud/CIH = H.getorgan(/obj/item/organ/cyberimp/eyes/hud)
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud) || CIH)
|
||||
var/perpname = get_face_name(get_id_name(""))
|
||||
if(perpname)
|
||||
var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general)
|
||||
if(R)
|
||||
. += "<span class='deptradio'>Rank:</span> [R.fields["rank"]]\n<a href='?src=[REF(src)];hud=1;photo_front=1'>\[Front photo\]</a><a href='?src=[REF(src)];hud=1;photo_side=1'>\[Side photo\]</a>"
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/medical))
|
||||
var/cyberimp_detect
|
||||
for(var/obj/item/organ/cyberimp/CI in internal_organs)
|
||||
if(CI.status == ORGAN_ROBOTIC && !CI.syndicate_implant)
|
||||
cyberimp_detect += "[name] is modified with a [CI.name]."
|
||||
if(cyberimp_detect)
|
||||
. += "Detected cybernetic modifications:"
|
||||
. += cyberimp_detect
|
||||
if(R)
|
||||
var/health_r = R.fields["p_stat"]
|
||||
. += "<a href='?src=[REF(src)];hud=m;p_stat=1'>\[[health_r]\]</a>"
|
||||
health_r = R.fields["m_stat"]
|
||||
. += "<a href='?src=[REF(src)];hud=m;m_stat=1'>\[[health_r]\]</a>"
|
||||
R = find_record("name", perpname, GLOB.data_core.medical)
|
||||
if(R)
|
||||
. += "<a href='?src=[REF(src)];hud=m;evaluation=1'>\[Medical evaluation\]</a>"
|
||||
if(traitstring)
|
||||
. += "<span class='info'>Detected physiological traits:\n[traitstring]"
|
||||
|
||||
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/security))
|
||||
if(!user.stat && user != src)
|
||||
//|| !user.canmove || user.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at.
|
||||
var/criminal = "None"
|
||||
|
||||
R = find_record("name", perpname, GLOB.data_core.security)
|
||||
if(R)
|
||||
criminal = R.fields["criminal"]
|
||||
|
||||
. += jointext(list("<span class='deptradio'>Criminal status:</span> <a href='?src=[REF(src)];hud=s;status=1'>\[[criminal]\]</a>",
|
||||
"<span class='deptradio'>Security record:</span> <a href='?src=[REF(src)];hud=s;view=1'>\[View\]</a>",
|
||||
"<a href='?src=[REF(src)];hud=s;add_crime=1'>\[Add crime\]</a>",
|
||||
"<a href='?src=[REF(src)];hud=s;view_comment=1'>\[View comment log\]</a>",
|
||||
"<a href='?src=[REF(src)];hud=s;add_comment=1'>\[Add comment\]</a>"), "")
|
||||
else if(isobserver(user) && traitstring)
|
||||
. += "<span class='info'><b>Traits:</b> [traitstring]</span>"
|
||||
|
||||
if(print_flavor_text())
|
||||
if(get_visible_name() == "Unknown") //Are we sure we know who this is? Don't show flavor text unless we can recognize them. Prevents certain metagaming with impersonation.
|
||||
. += "...?"
|
||||
else if(skipface) //Sometimes we're not unknown, but impersonating someone in a hardsuit, let's not reveal our flavor text then either.
|
||||
. += "...?"
|
||||
else
|
||||
. += "[print_flavor_text()]"
|
||||
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, msg)
|
||||
. += "*---------*</span>"
|
||||
|
||||
/mob/living/proc/status_effect_examines(pronoun_replacement) //You can include this in any mob's examine() to show the examine texts of status effects!
|
||||
var/list/dat = list()
|
||||
if(!pronoun_replacement)
|
||||
pronoun_replacement = p_they(TRUE)
|
||||
for(var/V in status_effects)
|
||||
var/datum/status_effect/E = V
|
||||
if(E.examine_text)
|
||||
var/new_text = replacetext(E.examine_text, "SUBJECTPRONOUN", pronoun_replacement)
|
||||
new_text = replacetext(new_text, "[pronoun_replacement] is", "[pronoun_replacement] [p_are()]") //To make sure something become "They are" or "She is", not "They are" and "She are"
|
||||
dat += "[new_text]\n" //dat.Join("\n") doesn't work here, for some reason
|
||||
if(dat.len)
|
||||
return dat.Join()
|
||||
/mob/living/carbon/human/examine(mob/user) //User is the person being examined
|
||||
//this is very slightly better than it was because you can use it more places. still can't do \his[src] though.
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_His = p_their(TRUE)
|
||||
var/t_his = p_their()
|
||||
var/t_him = p_them()
|
||||
var/t_has = p_have()
|
||||
var/t_is = p_are()
|
||||
var/obscure_name
|
||||
var/dispSize = round(12*size_multiplier) // gets the character's sprite size percent and converts it to the nearest half foot
|
||||
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
if(HAS_TRAIT(L, TRAIT_PROSOPAGNOSIA))
|
||||
obscure_name = TRUE
|
||||
|
||||
. = list("<span class='info'>*---------*\nThis is <EM>[!obscure_name ? name : "Unknown"]</EM>!")
|
||||
|
||||
var/list/obscured = check_obscured_slots()
|
||||
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
|
||||
|
||||
if(ishuman(src)) //user just returned, y'know, the user's own species. dumb.
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/datum/species/pref_species = H.dna.species
|
||||
if(get_visible_name() == "Unknown") // same as flavor text, but hey it works.
|
||||
. += "You can't make out what species they are."
|
||||
else if(skipface)
|
||||
. += "You can't make out what species they are."
|
||||
else
|
||||
. += "[t_He] [t_is] a [H.dna.custom_species ? H.dna.custom_species : pref_species.name]!"
|
||||
|
||||
//uniform
|
||||
if(w_uniform && !(SLOT_W_UNIFORM in obscured))
|
||||
//accessory
|
||||
var/accessory_msg
|
||||
if(istype(w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/U = w_uniform
|
||||
if(U.attached_accessory)
|
||||
accessory_msg += " with [icon2html(U.attached_accessory, user)] \a [U.attached_accessory]"
|
||||
|
||||
. += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_msg]."
|
||||
//head
|
||||
if(head)
|
||||
. += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head."
|
||||
//suit/armor
|
||||
if(wear_suit)
|
||||
. += "[t_He] [t_is] wearing [wear_suit.get_examine_string(user)]."
|
||||
//suit/armor storage
|
||||
if(s_store && !(SLOT_S_STORE in obscured))
|
||||
. += "[t_He] [t_is] carrying [s_store.get_examine_string(user)] on [t_his] [wear_suit.name]."
|
||||
//back
|
||||
if(back)
|
||||
. += "[t_He] [t_has] [back.get_examine_string(user)] on [t_his] back."
|
||||
|
||||
//Hands
|
||||
for(var/obj/item/I in held_items)
|
||||
if(!(I.item_flags & ABSTRACT))
|
||||
. += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))]."
|
||||
|
||||
//gloves
|
||||
if(gloves && !(SLOT_GLOVES in obscured))
|
||||
. += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands."
|
||||
else if(length(blood_DNA))
|
||||
var/hand_number = get_num_arms(FALSE)
|
||||
if(hand_number)
|
||||
. += "<span class='warning'>[t_He] [t_has] [hand_number > 1 ? "" : "a"] blood-stained hand[hand_number > 1 ? "s" : ""]!</span>"
|
||||
//handcuffed?
|
||||
if(handcuffed)
|
||||
if(istype(handcuffed, /obj/item/restraints/handcuffs/cable))
|
||||
. += "<span class='warning'>[t_He] [t_is] [icon2html(handcuffed, user)] restrained with cable!</span>"
|
||||
else
|
||||
. += "<span class='warning'>[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!</span>"
|
||||
|
||||
//belt
|
||||
if(belt)
|
||||
. += "[t_He] [t_has] [belt.get_examine_string(user)] about [t_his] waist."
|
||||
|
||||
//shoes
|
||||
if(shoes && !(SLOT_SHOES in obscured))
|
||||
. += "[t_He] [t_is] wearing [shoes.get_examine_string(user)] on [t_his] feet."
|
||||
|
||||
//mask
|
||||
if(wear_mask && !(SLOT_WEAR_MASK in obscured))
|
||||
. += "[t_He] [t_has] [wear_mask.get_examine_string(user)] on [t_his] face."
|
||||
|
||||
if(wear_neck && !(SLOT_NECK in obscured))
|
||||
. += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck."
|
||||
|
||||
//eyes
|
||||
if(!(SLOT_GLASSES in obscured))
|
||||
if(glasses)
|
||||
. += "[t_He] [t_has] [glasses.get_examine_string(user)] covering [t_his] eyes."
|
||||
else if(eye_color == BLOODCULT_EYE && iscultist(src) && HAS_TRAIT(src, TRAIT_CULT_EYES))
|
||||
. += "<span class='warning'><B>[t_His] eyes are glowing an unnatural red!</B></span>"
|
||||
|
||||
//ears
|
||||
if(ears && !(SLOT_EARS in obscured))
|
||||
. += "[t_He] [t_has] [ears.get_examine_string(user)] on [t_his] ears."
|
||||
|
||||
//ID
|
||||
if(wear_id)
|
||||
. += "[t_He] [t_is] wearing [wear_id.get_examine_string(user)]."
|
||||
|
||||
//Status effects
|
||||
var/effects_exam = status_effect_examines()
|
||||
if(!isnull(effects_exam))
|
||||
. += effects_exam
|
||||
|
||||
//Approximate character height based on current sprite scale
|
||||
if(dispSize % 2) // returns 1 or 0. 1 meaning the height is not exact and the code below will execute, 0 meaning the height is exact and the else will trigger.
|
||||
dispSize = dispSize - 1 //makes it even
|
||||
dispSize = dispSize / 2 //rounds it out
|
||||
. += "[t_He] appears to be around [dispSize] and a half feet tall."
|
||||
else
|
||||
dispSize = dispSize / 2
|
||||
. += "[t_He] appears to be around [dispSize] feet tall."
|
||||
|
||||
//Can be picked up?
|
||||
if(can_be_held)
|
||||
. += "[t_He] might be able to be picked up with <b>Alt+Click</b>!\n"
|
||||
|
||||
//CIT CHANGES START HERE - adds genital details to examine text
|
||||
if(LAZYLEN(internal_organs))
|
||||
for(var/obj/item/organ/genital/dicc in internal_organs)
|
||||
if(istype(dicc) && dicc.is_exposed())
|
||||
. += "[dicc.desc]"
|
||||
|
||||
var/cursed_stuff = attempt_vr(src,"examine_bellies",args) //vore Code
|
||||
if(!isnull(cursed_stuff))
|
||||
. += cursed_stuff
|
||||
//END OF CIT CHANGES
|
||||
|
||||
//Jitters
|
||||
switch(jitteriness)
|
||||
if(300 to INFINITY)
|
||||
. += "<span class='warning'><B>[t_He] [t_is] convulsing violently!</B></span>"
|
||||
if(200 to 300)
|
||||
. += "<span class='warning'>[t_He] [t_is] extremely jittery.</span>"
|
||||
if(100 to 200)
|
||||
. += "<span class='warning'>[t_He] [t_is] twitching ever so slightly.</span>"
|
||||
|
||||
var/appears_dead = 0
|
||||
if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
|
||||
appears_dead = 1
|
||||
if(suiciding)
|
||||
. += "<span class='warning'>[t_He] appear[p_s()] to have committed suicide... there is no hope of recovery.</span>"
|
||||
if(hellbound)
|
||||
. += "<span class='warning'>[t_His] soul seems to have been ripped out of [t_his] body. Revival is impossible.</span>"
|
||||
if(getorgan(/obj/item/organ/brain) && !key && !get_ghost(FALSE, TRUE))
|
||||
. += "<span class='deadsay'>[t_He] [t_is] limp and unresponsive; there are no signs of life and [t_his] soul has departed...</span>"
|
||||
else
|
||||
. += "<span class='deadsay'>[t_He] [t_is] limp and unresponsive; there are no signs of life...</span>"
|
||||
|
||||
if(get_bodypart(BODY_ZONE_HEAD) && !getorgan(/obj/item/organ/brain))
|
||||
. += "<span class='deadsay'>It appears that [t_his] brain is missing...</span>"
|
||||
|
||||
var/temp = getBruteLoss() //no need to calculate each of these twice
|
||||
|
||||
var/list/msg = list()
|
||||
|
||||
var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
var/list/disabled = list()
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(BP.disabled)
|
||||
disabled += BP
|
||||
missing -= BP.body_zone
|
||||
for(var/obj/item/I in BP.embedded_objects)
|
||||
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
|
||||
if(BP.broken)
|
||||
msg += "<B>[t_He] [t_has] \a [I] broken [BP.name]!</B>\n"
|
||||
|
||||
for(var/X in disabled)
|
||||
var/obj/item/bodypart/BP = X
|
||||
var/damage_text
|
||||
if(!(BP.get_damage(include_stamina = FALSE) >= BP.max_damage)) //Stamina is disabling the limb
|
||||
damage_text = "limp and lifeless"
|
||||
else
|
||||
damage_text = (BP.brute_dam >= BP.burn_dam) ? BP.heavy_brute_msg : BP.heavy_burn_msg
|
||||
msg += "<B>[capitalize(t_his)] [BP.name] is [damage_text]!</B>\n"
|
||||
|
||||
//stores missing limbs
|
||||
var/l_limbs_missing = 0
|
||||
var/r_limbs_missing = 0
|
||||
for(var/t in missing)
|
||||
if(t==BODY_ZONE_HEAD)
|
||||
msg += "<span class='deadsay'><B>[t_His] [parse_zone(t)] is missing!</B><span class='warning'>\n"
|
||||
continue
|
||||
if(t == BODY_ZONE_L_ARM || t == BODY_ZONE_L_LEG)
|
||||
l_limbs_missing++
|
||||
else if(t == BODY_ZONE_R_ARM || t == BODY_ZONE_R_LEG)
|
||||
r_limbs_missing++
|
||||
|
||||
msg += "<B>[capitalize(t_his)] [parse_zone(t)] is missing!</B>\n"
|
||||
|
||||
if(l_limbs_missing >= 2 && r_limbs_missing == 0)
|
||||
msg += "[t_He] look[p_s()] all right now.\n"
|
||||
else if(l_limbs_missing == 0 && r_limbs_missing >= 2)
|
||||
msg += "[t_He] really keeps to the left.\n"
|
||||
else if(l_limbs_missing >= 2 && r_limbs_missing >= 2)
|
||||
msg += "[t_He] [p_do()]n't seem all there.\n"
|
||||
|
||||
if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
|
||||
if(temp)
|
||||
if(temp < 25)
|
||||
msg += "[t_He] [t_has] minor bruising.\n"
|
||||
else if(temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> bruising!\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_has] severe bruising!</B>\n"
|
||||
|
||||
temp = getFireLoss()
|
||||
if(temp)
|
||||
if(temp < 25)
|
||||
msg += "[t_He] [t_has] minor burns.\n"
|
||||
else if (temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> burns!\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_has] severe burns!</B>\n"
|
||||
|
||||
temp = getCloneLoss()
|
||||
if(temp)
|
||||
if(temp < 25)
|
||||
msg += "[t_He] [t_has] minor cellular damage.\n"
|
||||
else if(temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> cellular damage!\n"
|
||||
else
|
||||
msg += "<b>[t_He] [t_has] severe cellular damage!</b>\n"
|
||||
|
||||
|
||||
if(fire_stacks > 0)
|
||||
msg += "[t_He] [t_is] covered in something flammable.\n"
|
||||
if(fire_stacks < 0)
|
||||
msg += "[t_He] look[p_s()] a little soaked.\n"
|
||||
|
||||
|
||||
if(pulledby && pulledby.grab_state)
|
||||
msg += "[t_He] [t_is] restrained by [pulledby]'s grip.\n"
|
||||
|
||||
if(nutrition < NUTRITION_LEVEL_STARVING - 50)
|
||||
msg += "[t_He] [t_is] severely malnourished.\n"
|
||||
else if(nutrition >= NUTRITION_LEVEL_FAT)
|
||||
if(user.nutrition < NUTRITION_LEVEL_STARVING - 50)
|
||||
msg += "[t_He] [t_is] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n"
|
||||
else
|
||||
msg += "[t_He] [t_is] quite chubby.\n"
|
||||
switch(disgust)
|
||||
if(DISGUST_LEVEL_GROSS to DISGUST_LEVEL_VERYGROSS)
|
||||
msg += "[t_He] look[p_s()] a bit grossed out.\n"
|
||||
if(DISGUST_LEVEL_VERYGROSS to DISGUST_LEVEL_DISGUSTED)
|
||||
msg += "[t_He] look[p_s()] really grossed out.\n"
|
||||
if(DISGUST_LEVEL_DISGUSTED to INFINITY)
|
||||
msg += "[t_He] look[p_s()] extremely disgusted.\n"
|
||||
|
||||
if(blood_volume < (BLOOD_VOLUME_SAFE*blood_ratio))
|
||||
msg += "[t_He] [t_has] pale skin.\n"
|
||||
|
||||
if(bleedsuppress)
|
||||
msg += "[t_He] [t_is] bandaged with something.\n"
|
||||
else if(bleed_rate)
|
||||
if(reagents.has_reagent("heparin"))
|
||||
msg += "<b>[t_He] [t_is] bleeding uncontrollably!</b>\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_is] bleeding!</B>\n"
|
||||
|
||||
if(reagents.has_reagent("teslium"))
|
||||
msg += "[t_He] [t_is] emitting a gentle blue glow!\n"
|
||||
|
||||
if(islist(stun_absorption))
|
||||
for(var/i in stun_absorption)
|
||||
if(stun_absorption[i]["end_time"] > world.time && stun_absorption[i]["examine_message"])
|
||||
msg += "[t_He] [t_is][stun_absorption[i]["examine_message"]]\n"
|
||||
|
||||
if(drunkenness && !skipface && !appears_dead) //Drunkenness
|
||||
switch(drunkenness)
|
||||
if(11 to 21)
|
||||
msg += "[t_He] [t_is] slightly flushed.\n"
|
||||
if(21.01 to 41) //.01s are used in case drunkenness ends up to be a small decimal
|
||||
msg += "[t_He] [t_is] flushed.\n"
|
||||
if(41.01 to 51)
|
||||
msg += "[t_He] [t_is] quite flushed and [t_his] breath smells of alcohol.\n"
|
||||
if(51.01 to 61)
|
||||
msg += "[t_He] [t_is] very flushed and [t_his] movements jerky, with breath reeking of alcohol.\n"
|
||||
if(61.01 to 91)
|
||||
msg += "[t_He] look[p_s()] like a drunken mess.\n"
|
||||
if(91.01 to INFINITY)
|
||||
msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
|
||||
|
||||
if(reagents.has_reagent("astral"))
|
||||
msg += "[t_He] have wild, spacey eyes"
|
||||
if(mind)
|
||||
msg += " and have a strange, abnormal look to them.\n"
|
||||
else
|
||||
msg += " and don't look like they're all there.\n"
|
||||
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
if(src != user && HAS_TRAIT(L, TRAIT_EMPATH) && !appears_dead)
|
||||
if (a_intent != INTENT_HELP)
|
||||
msg += "[t_He] seem[p_s()] to be on guard.\n"
|
||||
if (getOxyLoss() >= 10)
|
||||
msg += "[t_He] seem[p_s()] winded.\n"
|
||||
if (getToxLoss() >= 10)
|
||||
msg += "[t_He] seem[p_s()] sickly.\n"
|
||||
var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
|
||||
if(mood.sanity <= SANITY_DISTURBED)
|
||||
msg += "[t_He] seem[p_s()] distressed.\n"
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "empath", /datum/mood_event/sad_empath, src)
|
||||
if(mood.shown_mood >= 6) //So roundstart people aren't all "happy" and that antags don't show their true happiness.
|
||||
msg += "[t_He] seem[p_s()] to have had something nice happen to them recently.\n"
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "empathH", /datum/mood_event/happy_empath, src)
|
||||
if (HAS_TRAIT(src, TRAIT_BLIND))
|
||||
msg += "[t_He] appear[p_s()] to be staring off into space.\n"
|
||||
if (HAS_TRAIT(src, TRAIT_DEAF))
|
||||
msg += "[t_He] appear[p_s()] to not be responding to noises.\n"
|
||||
|
||||
msg += "</span>"
|
||||
|
||||
var/obj/item/organ/vocal_cords/Vc = user.getorganslot(ORGAN_SLOT_VOICE)
|
||||
if(Vc)
|
||||
if(istype(Vc, /obj/item/organ/vocal_cords/velvet))
|
||||
if(client?.prefs.lewdchem)
|
||||
msg += "<span class='velvet'><i>You feel your chords resonate looking at them.</i></span>\n"
|
||||
|
||||
|
||||
if(!appears_dead)
|
||||
if(stat == UNCONSCIOUS)
|
||||
msg += "[t_He] [t_is]n't responding to anything around [t_him] and seem[p_s()] to be asleep.\n"
|
||||
else
|
||||
if(HAS_TRAIT(src, TRAIT_DUMB))
|
||||
msg += "[t_He] [t_has] a stupid expression on [t_his] face.\n"
|
||||
if(InCritical())
|
||||
msg += "[t_He] [t_is] barely conscious.\n"
|
||||
if(getorgan(/obj/item/organ/brain))
|
||||
if(!key)
|
||||
msg += "<span class='deadsay'>[t_He] [t_is] totally catatonic. The stresses of life in deep-space must have been too much for [t_him]. Any recovery is unlikely.</span>\n"
|
||||
else if(!client)
|
||||
msg += "[t_He] [t_has] a blank, absent-minded stare and appears completely unresponsive to anything. [t_He] may snap out of it soon.\n"
|
||||
|
||||
if(digitalcamo)
|
||||
msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly inhuman manner.\n"
|
||||
|
||||
if (length(msg))
|
||||
. += "<span class='warning'>[msg.Join("")]</span>"
|
||||
|
||||
var/traitstring = get_trait_string()
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/organ/cyberimp/eyes/hud/CIH = H.getorgan(/obj/item/organ/cyberimp/eyes/hud)
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud) || CIH)
|
||||
var/perpname = get_face_name(get_id_name(""))
|
||||
if(perpname)
|
||||
var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general)
|
||||
if(R)
|
||||
. += "<span class='deptradio'>Rank:</span> [R.fields["rank"]]\n<a href='?src=[REF(src)];hud=1;photo_front=1'>\[Front photo\]</a><a href='?src=[REF(src)];hud=1;photo_side=1'>\[Side photo\]</a>"
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/medical))
|
||||
var/cyberimp_detect
|
||||
for(var/obj/item/organ/cyberimp/CI in internal_organs)
|
||||
if(CI.status == ORGAN_ROBOTIC && !CI.syndicate_implant)
|
||||
cyberimp_detect += "[name] is modified with a [CI.name]."
|
||||
if(cyberimp_detect)
|
||||
. += "Detected cybernetic modifications:"
|
||||
. += cyberimp_detect
|
||||
if(R)
|
||||
var/health_r = R.fields["p_stat"]
|
||||
. += "<a href='?src=[REF(src)];hud=m;p_stat=1'>\[[health_r]\]</a>"
|
||||
health_r = R.fields["m_stat"]
|
||||
. += "<a href='?src=[REF(src)];hud=m;m_stat=1'>\[[health_r]\]</a>"
|
||||
R = find_record("name", perpname, GLOB.data_core.medical)
|
||||
if(R)
|
||||
. += "<a href='?src=[REF(src)];hud=m;evaluation=1'>\[Medical evaluation\]</a>"
|
||||
if(traitstring)
|
||||
. += "<span class='info'>Detected physiological traits:\n[traitstring]"
|
||||
|
||||
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/security))
|
||||
if(!user.stat && user != src)
|
||||
//|| !user.canmove || user.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at.
|
||||
var/criminal = "None"
|
||||
|
||||
R = find_record("name", perpname, GLOB.data_core.security)
|
||||
if(R)
|
||||
criminal = R.fields["criminal"]
|
||||
|
||||
. += jointext(list("<span class='deptradio'>Criminal status:</span> <a href='?src=[REF(src)];hud=s;status=1'>\[[criminal]\]</a>",
|
||||
"<span class='deptradio'>Security record:</span> <a href='?src=[REF(src)];hud=s;view=1'>\[View\]</a>",
|
||||
"<a href='?src=[REF(src)];hud=s;add_crime=1'>\[Add crime\]</a>",
|
||||
"<a href='?src=[REF(src)];hud=s;view_comment=1'>\[View comment log\]</a>",
|
||||
"<a href='?src=[REF(src)];hud=s;add_comment=1'>\[Add comment\]</a>"), "")
|
||||
else if(isobserver(user) && traitstring)
|
||||
. += "<span class='info'><b>Traits:</b> [traitstring]</span>"
|
||||
|
||||
if(print_flavor_text())
|
||||
if(get_visible_name() == "Unknown") //Are we sure we know who this is? Don't show flavor text unless we can recognize them. Prevents certain metagaming with impersonation.
|
||||
. += "...?"
|
||||
else if(skipface) //Sometimes we're not unknown, but impersonating someone in a hardsuit, let's not reveal our flavor text then either.
|
||||
. += "...?"
|
||||
else
|
||||
. += "[print_flavor_text()]"
|
||||
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, msg)
|
||||
. += "*---------*</span>"
|
||||
|
||||
/mob/living/proc/status_effect_examines(pronoun_replacement) //You can include this in any mob's examine() to show the examine texts of status effects!
|
||||
var/list/dat = list()
|
||||
if(!pronoun_replacement)
|
||||
pronoun_replacement = p_they(TRUE)
|
||||
for(var/V in status_effects)
|
||||
var/datum/status_effect/E = V
|
||||
if(E.examine_text)
|
||||
var/new_text = replacetext(E.examine_text, "SUBJECTPRONOUN", pronoun_replacement)
|
||||
new_text = replacetext(new_text, "[pronoun_replacement] is", "[pronoun_replacement] [p_are()]") //To make sure something become "They are" or "She is", not "They are" and "She are"
|
||||
dat += "[new_text]\n" //dat.Join("\n") doesn't work here, for some reason
|
||||
if(dat.len)
|
||||
return dat.Join()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -118,8 +118,7 @@
|
||||
|
||||
/mob/living/carbon/human/can_use_guns(obj/item/G)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
|
||||
if(src.dna.check_mutation(HULK))
|
||||
to_chat(src, "<span class='warning'>Your meaty finger is much too large for the trigger guard!</span>")
|
||||
@@ -132,12 +131,7 @@
|
||||
to_chat(src, "<span class='warning'>Use of ranged weaponry would bring dishonor to the clan.</span>")
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/can_see_reagents()
|
||||
. = ..()
|
||||
if(.) //No need to run through all of this if it's already true.
|
||||
return
|
||||
if(isclothing(glasses) && (glasses.clothing_flags & SCAN_REAGENTS))
|
||||
return TRUE
|
||||
return .
|
||||
|
||||
/*
|
||||
/mob/living/carbon/human/transfer_blood_dna(list/blood_dna)
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/mob/living/carbon/human/say_mod(input, message_mode)
|
||||
verb_say = dna.species.say_mod
|
||||
. = ..()
|
||||
if(message_mode != MODE_CUSTOM_SAY && message_mode != MODE_WHISPER_CRIT)
|
||||
switch(slurring)
|
||||
if(10 to 25)
|
||||
return "jumbles"
|
||||
if(25 to 50)
|
||||
return "slurs"
|
||||
if(50 to INFINITY)
|
||||
return "garbles"
|
||||
switch(slurring)
|
||||
if(10 to 25)
|
||||
return "jumbles"
|
||||
if(25 to 50)
|
||||
return "slurs"
|
||||
if(50 to INFINITY)
|
||||
return "garbles"
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/GetVoice()
|
||||
if(istype(wear_mask, /obj/item/clothing/mask/chameleon))
|
||||
@@ -87,22 +87,30 @@
|
||||
/mob/living/carbon/human/proc/forcesay(list/append) //this proc is at the bottom of the file because quote fuckery makes notepad++ cri
|
||||
if(stat == CONSCIOUS)
|
||||
if(client)
|
||||
var/virgin = 1 //has the text been modified yet?
|
||||
var/temp = winget(client, "input", "text")
|
||||
var/say_starter = "Say \"" //"
|
||||
if(findtextEx(temp, say_starter, 1, length(say_starter) + 1) && length(temp) > length(say_starter)) //case sensitive means
|
||||
if(findtextEx(temp, "Say \"", 1, 7) && length(temp) > 5) //"case sensitive means
|
||||
|
||||
temp = trim_left(copytext(temp, length(say_starter + 1)))
|
||||
temp = replacetext(temp, ";", "", 1, 2) //general radio
|
||||
while(trim_left(temp)[1] == ":") //dept radio again (necessary)
|
||||
temp = copytext_char(trim_left(temp), 3)
|
||||
temp = replacetext(temp, ";", "") //general radio
|
||||
|
||||
if(temp[1] == "*") //emotes
|
||||
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
|
||||
|
||||
var/trimmed = trim_left(temp)
|
||||
if(length(trimmed))
|
||||
if(append)
|
||||
trimmed += pick(append)
|
||||
temp += pick(append)
|
||||
|
||||
say(trimmed)
|
||||
say(temp)
|
||||
winset(client, "input", "text=[null]")
|
||||
|
||||
@@ -1205,9 +1205,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
|
||||
H.update_mutant_bodyparts()
|
||||
|
||||
/datum/species/proc/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.type == exotic_blood)
|
||||
if(chem.id == exotic_blood)
|
||||
H.blood_volume = min(H.blood_volume + round(chem.volume, 0.1), BLOOD_VOLUME_MAXIMUM)
|
||||
H.reagents.del_reagent(chem.type)
|
||||
H.reagents.del_reagent(chem.id)
|
||||
return 1
|
||||
return FALSE
|
||||
|
||||
@@ -1222,8 +1222,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
|
||||
////////
|
||||
|
||||
/datum/species/proc/handle_digestion(mob/living/carbon/human/H)
|
||||
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
|
||||
return //hunger is for BABIES
|
||||
|
||||
//The fucking TRAIT_FAT mutation is the dumbest shit ever. It makes the code so difficult to work with
|
||||
if(HAS_TRAIT(H, TRAIT_FAT))//I share your pain, past coder.
|
||||
@@ -1519,7 +1517,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
|
||||
|
||||
target.lastattacker = user.real_name
|
||||
target.lastattackerckey = user.ckey
|
||||
user.dna.species.spec_unarmedattacked(user, target)
|
||||
|
||||
if(user.limb_destroyer)
|
||||
target.dismembering_strike(user, affecting.body_zone)
|
||||
@@ -1533,9 +1530,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
|
||||
else if(target.lying)
|
||||
target.forcesay(GLOB.hit_appends)
|
||||
|
||||
/datum/species/proc/spec_unarmedattacked(mob/living/carbon/human/user, mob/living/carbon/human/target)
|
||||
return
|
||||
|
||||
/datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
|
||||
// CITADEL EDIT slap mouthy gits and booty
|
||||
var/aim_for_mouth = user.zone_selected == "mouth"
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
/datum/species/abductor
|
||||
name = "Abductor"
|
||||
id = "abductor"
|
||||
say_mod = "gibbers"
|
||||
sexes = FALSE
|
||||
species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL)
|
||||
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NOGUNS,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
mutanttongue = /obj/item/organ/tongue/abductor
|
||||
|
||||
/datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
|
||||
abductor_hud.add_hud_to(C)
|
||||
|
||||
/datum/species/abductor/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
|
||||
abductor_hud.remove_hud_from(C)
|
||||
/datum/species/abductor
|
||||
name = "Abductor"
|
||||
id = "abductor"
|
||||
say_mod = "gibbers"
|
||||
sexes = FALSE
|
||||
species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL)
|
||||
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NOGUNS,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
mutanttongue = /obj/item/organ/tongue/abductor
|
||||
var/scientist = FALSE // vars to not pollute spieces list with castes
|
||||
|
||||
/datum/species/abductor/copy_properties_from(datum/species/abductor/old_species)
|
||||
scientist = old_species.scientist
|
||||
|
||||
/datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
|
||||
abductor_hud.add_hud_to(C)
|
||||
|
||||
/datum/species/abductor/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
|
||||
abductor_hud.remove_hud_from(C)
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
/datum/species/fly
|
||||
name = "Flyperson"
|
||||
id = "fly"
|
||||
say_mod = "buzzes"
|
||||
species_traits = list(NOEYES)
|
||||
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
|
||||
mutanttongue = /obj/item/organ/tongue/fly
|
||||
mutantliver = /obj/item/organ/liver/fly
|
||||
mutantstomach = /obj/item/organ/stomach/fly
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/fly
|
||||
disliked_food = null
|
||||
liked_food = GROSS
|
||||
exotic_bloodtype = "BUG"
|
||||
|
||||
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.type == /datum/reagent/toxin/pestkiller)
|
||||
H.adjustToxLoss(3)
|
||||
H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
|
||||
return 1
|
||||
|
||||
|
||||
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(istype(chem, /datum/reagent/consumable))
|
||||
var/datum/reagent/consumable/nutri_check = chem
|
||||
if(nutri_check.nutriment_factor > 0)
|
||||
var/turf/pos = get_turf(H)
|
||||
H.vomit(0, FALSE, FALSE, 2, TRUE)
|
||||
playsound(pos, 'sound/effects/splat.ogg', 50, 1)
|
||||
H.visible_message("<span class='danger'>[H] vomits on the floor!</span>", \
|
||||
"<span class='userdanger'>You throw up on the floor!</span>")
|
||||
..()
|
||||
|
||||
/datum/species/fly/check_weakness(obj/item/weapon, mob/living/attacker)
|
||||
if(istype(weapon, /obj/item/melee/flyswatter))
|
||||
return 29 //Flyswatters deal 30x damage to flypeople.
|
||||
return 0
|
||||
/datum/species/fly
|
||||
name = "Flyperson"
|
||||
id = "fly"
|
||||
say_mod = "buzzes"
|
||||
species_traits = list(NOEYES)
|
||||
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
|
||||
mutanttongue = /obj/item/organ/tongue/fly
|
||||
mutantliver = /obj/item/organ/liver/fly
|
||||
mutantstomach = /obj/item/organ/stomach/fly
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/fly
|
||||
disliked_food = null
|
||||
liked_food = GROSS
|
||||
exotic_bloodtype = "BUG"
|
||||
|
||||
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.id == "pestkiller")
|
||||
H.adjustToxLoss(3)
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
return 1
|
||||
|
||||
|
||||
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(istype(chem, /datum/reagent/consumable))
|
||||
var/datum/reagent/consumable/nutri_check = chem
|
||||
if(nutri_check.nutriment_factor > 0)
|
||||
var/turf/pos = get_turf(H)
|
||||
H.vomit(0, FALSE, FALSE, 2, TRUE)
|
||||
playsound(pos, 'sound/effects/splat.ogg', 50, 1)
|
||||
H.visible_message("<span class='danger'>[H] vomits on the floor!</span>", \
|
||||
"<span class='userdanger'>You throw up on the floor!</span>")
|
||||
..()
|
||||
|
||||
/datum/species/fly/check_weakness(obj/item/weapon, mob/living/attacker)
|
||||
if(istype(weapon, /obj/item/melee/flyswatter))
|
||||
return 29 //Flyswatters deal 30x damage to flypeople.
|
||||
return 0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -47,9 +47,9 @@
|
||||
QDEL_NULL(mush)
|
||||
|
||||
/datum/species/mush/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.type == /datum/reagent/toxin/plantbgone/weedkiller)
|
||||
if(chem.id == "weedkiller")
|
||||
H.adjustToxLoss(3)
|
||||
H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
return TRUE
|
||||
|
||||
/datum/species/mush/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
H.take_overall_damage(2,0)
|
||||
|
||||
/datum/species/pod/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.type == /datum/reagent/toxin/plantbgone)
|
||||
if(chem.id == "plantbgone")
|
||||
H.adjustToxLoss(3)
|
||||
H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
return 1
|
||||
|
||||
/datum/species/pod/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
|
||||
|
||||
@@ -1,129 +1,129 @@
|
||||
/datum/species/synth
|
||||
name = "Synth" //inherited from the real species, for health scanners and things
|
||||
id = "synth"
|
||||
say_mod = "beep boops" //inherited from a user's real species
|
||||
sexes = 0
|
||||
species_traits = list(NOTRANSSTING,NOGENITALS,NOAROUSAL) //all of these + whatever we inherit from the real species
|
||||
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
|
||||
dangerous_existence = 1
|
||||
blacklisted = 1
|
||||
meat = null
|
||||
gib_types = /obj/effect/gibspawner/robot
|
||||
damage_overlay_type = "synth"
|
||||
limbs_id = "synth"
|
||||
var/list/initial_species_traits = list(NOTRANSSTING) //for getting these values back for assume_disguise()
|
||||
var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOLIMBDISABLE,TRAIT_NOBREATH)
|
||||
var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
|
||||
var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
|
||||
|
||||
/datum/species/synth/military
|
||||
name = "Military Synth"
|
||||
id = "military_synth"
|
||||
armor = 25
|
||||
punchdamagelow = 10
|
||||
punchdamagehigh = 19
|
||||
punchstunthreshold = 14 //about 50% chance to stun
|
||||
disguise_fail_health = 50
|
||||
|
||||
/datum/species/synth/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
|
||||
..()
|
||||
assume_disguise(old_species, H)
|
||||
RegisterSignal(H, COMSIG_MOB_SAY, .proc/handle_speech)
|
||||
H.grant_language(/datum/language/machine)
|
||||
|
||||
/datum/species/synth/on_species_loss(mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
UnregisterSignal(H, COMSIG_MOB_SAY)
|
||||
H.remove_language(/datum/language/machine)
|
||||
|
||||
/datum/species/synth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.type == /datum/reagent/medicine/synthflesh)
|
||||
chem.reaction_mob(H, TOUCH, 2 ,0) //heal a little
|
||||
H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H)
|
||||
if(S && !istype(S, type))
|
||||
name = S.name
|
||||
say_mod = S.say_mod
|
||||
sexes = S.sexes
|
||||
species_traits = initial_species_traits.Copy()
|
||||
inherent_traits = initial_inherent_traits.Copy()
|
||||
species_traits |= S.species_traits
|
||||
inherent_traits |= S.inherent_traits
|
||||
attack_verb = S.attack_verb
|
||||
attack_sound = S.attack_sound
|
||||
miss_sound = S.miss_sound
|
||||
meat = S.meat
|
||||
mutant_bodyparts = S.mutant_bodyparts.Copy()
|
||||
mutant_organs = S.mutant_organs.Copy()
|
||||
default_features = S.default_features.Copy()
|
||||
nojumpsuit = S.nojumpsuit
|
||||
no_equip = S.no_equip.Copy()
|
||||
limbs_id = S.limbs_id
|
||||
use_skintones = S.use_skintones
|
||||
fixed_mut_color = S.fixed_mut_color
|
||||
hair_color = S.hair_color
|
||||
fake_species = new S.type
|
||||
else
|
||||
name = initial(name)
|
||||
say_mod = initial(say_mod)
|
||||
species_traits = initial_species_traits.Copy()
|
||||
inherent_traits = initial_inherent_traits.Copy()
|
||||
attack_verb = initial(attack_verb)
|
||||
attack_sound = initial(attack_sound)
|
||||
miss_sound = initial(miss_sound)
|
||||
mutant_bodyparts = list()
|
||||
default_features = list()
|
||||
nojumpsuit = initial(nojumpsuit)
|
||||
no_equip = list()
|
||||
qdel(fake_species)
|
||||
fake_species = null
|
||||
meat = initial(meat)
|
||||
limbs_id = "synth"
|
||||
use_skintones = 0
|
||||
sexes = 0
|
||||
fixed_mut_color = ""
|
||||
hair_color = ""
|
||||
|
||||
for(var/X in H.bodyparts) //propagates the damage_overlay changes
|
||||
var/obj/item/bodypart/BP = X
|
||||
BP.update_limb()
|
||||
H.update_body_parts() //to update limb icon cache with the new damage overlays
|
||||
|
||||
//Proc redirects:
|
||||
//Passing procs onto the fake_species, to ensure we look as much like them as possible
|
||||
|
||||
/datum/species/synth/handle_hair(mob/living/carbon/human/H, forced_colour)
|
||||
if(fake_species)
|
||||
fake_species.handle_hair(H, forced_colour)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/handle_body(mob/living/carbon/human/H)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H,forced_colour)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/datum/species/synth/proc/handle_speech(datum/source, list/speech_args)
|
||||
if (isliving(source)) // yeah it's gonna be living but just to be clean
|
||||
var/mob/living/L = source
|
||||
if(fake_species && L.health > disguise_fail_health)
|
||||
switch (fake_species.type)
|
||||
if (/datum/species/golem/bananium)
|
||||
speech_args[SPEECH_SPANS] |= SPAN_CLOWN
|
||||
if (/datum/species/golem/clockwork)
|
||||
speech_args[SPEECH_SPANS] |= SPAN_ROBOT
|
||||
/datum/species/synth
|
||||
name = "Synth" //inherited from the real species, for health scanners and things
|
||||
id = "synth"
|
||||
say_mod = "beep boops" //inherited from a user's real species
|
||||
sexes = 0
|
||||
species_traits = list(NOTRANSSTING,NOGENITALS,NOAROUSAL) //all of these + whatever we inherit from the real species
|
||||
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
|
||||
dangerous_existence = 1
|
||||
blacklisted = 1
|
||||
meat = null
|
||||
gib_types = /obj/effect/gibspawner/robot
|
||||
damage_overlay_type = "synth"
|
||||
limbs_id = "synth"
|
||||
var/list/initial_species_traits = list(NOTRANSSTING) //for getting these values back for assume_disguise()
|
||||
var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOLIMBDISABLE,TRAIT_NOBREATH)
|
||||
var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
|
||||
var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
|
||||
|
||||
/datum/species/synth/military
|
||||
name = "Military Synth"
|
||||
id = "military_synth"
|
||||
armor = 25
|
||||
punchdamagelow = 10
|
||||
punchdamagehigh = 19
|
||||
punchstunthreshold = 14 //about 50% chance to stun
|
||||
disguise_fail_health = 50
|
||||
|
||||
/datum/species/synth/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
|
||||
..()
|
||||
assume_disguise(old_species, H)
|
||||
RegisterSignal(H, COMSIG_MOB_SAY, .proc/handle_speech)
|
||||
H.grant_language(/datum/language/machine)
|
||||
|
||||
/datum/species/synth/on_species_loss(mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
UnregisterSignal(H, COMSIG_MOB_SAY)
|
||||
H.remove_language(/datum/language/machine)
|
||||
|
||||
/datum/species/synth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.id == "synthflesh")
|
||||
chem.reaction_mob(H, TOUCH, 2 ,0) //heal a little
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H)
|
||||
if(S && !istype(S, type))
|
||||
name = S.name
|
||||
say_mod = S.say_mod
|
||||
sexes = S.sexes
|
||||
species_traits = initial_species_traits.Copy()
|
||||
inherent_traits = initial_inherent_traits.Copy()
|
||||
species_traits |= S.species_traits
|
||||
inherent_traits |= S.inherent_traits
|
||||
attack_verb = S.attack_verb
|
||||
attack_sound = S.attack_sound
|
||||
miss_sound = S.miss_sound
|
||||
meat = S.meat
|
||||
mutant_bodyparts = S.mutant_bodyparts.Copy()
|
||||
mutant_organs = S.mutant_organs.Copy()
|
||||
default_features = S.default_features.Copy()
|
||||
nojumpsuit = S.nojumpsuit
|
||||
no_equip = S.no_equip.Copy()
|
||||
limbs_id = S.limbs_id
|
||||
use_skintones = S.use_skintones
|
||||
fixed_mut_color = S.fixed_mut_color
|
||||
hair_color = S.hair_color
|
||||
fake_species = new S.type
|
||||
else
|
||||
name = initial(name)
|
||||
say_mod = initial(say_mod)
|
||||
species_traits = initial_species_traits.Copy()
|
||||
inherent_traits = initial_inherent_traits.Copy()
|
||||
attack_verb = initial(attack_verb)
|
||||
attack_sound = initial(attack_sound)
|
||||
miss_sound = initial(miss_sound)
|
||||
mutant_bodyparts = list()
|
||||
default_features = list()
|
||||
nojumpsuit = initial(nojumpsuit)
|
||||
no_equip = list()
|
||||
qdel(fake_species)
|
||||
fake_species = null
|
||||
meat = initial(meat)
|
||||
limbs_id = "synth"
|
||||
use_skintones = 0
|
||||
sexes = 0
|
||||
fixed_mut_color = ""
|
||||
hair_color = ""
|
||||
|
||||
for(var/X in H.bodyparts) //propagates the damage_overlay changes
|
||||
var/obj/item/bodypart/BP = X
|
||||
BP.update_limb()
|
||||
H.update_body_parts() //to update limb icon cache with the new damage overlays
|
||||
|
||||
//Proc redirects:
|
||||
//Passing procs onto the fake_species, to ensure we look as much like them as possible
|
||||
|
||||
/datum/species/synth/handle_hair(mob/living/carbon/human/H, forced_colour)
|
||||
if(fake_species)
|
||||
fake_species.handle_hair(H, forced_colour)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/handle_body(mob/living/carbon/human/H)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H,forced_colour)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/datum/species/synth/proc/handle_speech(datum/source, list/speech_args)
|
||||
if (isliving(source)) // yeah it's gonna be living but just to be clean
|
||||
var/mob/living/L = source
|
||||
if(fake_species && L.health > disguise_fail_health)
|
||||
switch (fake_species.type)
|
||||
if (/datum/species/golem/bananium)
|
||||
speech_args[SPEECH_SPANS] |= SPAN_CLOWN
|
||||
if (/datum/species/golem/clockwork)
|
||||
speech_args[SPEECH_SPANS] |= SPAN_ROBOT
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,175 +1,175 @@
|
||||
/mob/living/carbon/monkey
|
||||
name = "monkey"
|
||||
verb_say = "chimpers"
|
||||
initial_language_holder = /datum/language_holder/monkey
|
||||
icon = 'icons/mob/monkey.dmi'
|
||||
icon_state = ""
|
||||
gender = NEUTER
|
||||
pass_flags = PASSTABLE
|
||||
ventcrawler = VENTCRAWLER_NUDE
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1)
|
||||
type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/monkey
|
||||
gib_type = /obj/effect/decal/cleanable/blood/gibs
|
||||
unique_name = TRUE
|
||||
bodyparts = list(/obj/item/bodypart/chest/monkey, /obj/item/bodypart/head/monkey, /obj/item/bodypart/l_arm/monkey,
|
||||
/obj/item/bodypart/r_arm/monkey, /obj/item/bodypart/r_leg/monkey, /obj/item/bodypart/l_leg/monkey)
|
||||
hud_type = /datum/hud/monkey
|
||||
|
||||
/mob/living/carbon/monkey/Initialize(mapload, cubespawned=FALSE, mob/spawner)
|
||||
verbs += /mob/living/proc/mob_sleep
|
||||
verbs += /mob/living/proc/lay_down
|
||||
|
||||
if(unique_name) //used to exclude pun pun
|
||||
gender = pick(MALE, FEMALE)
|
||||
real_name = name
|
||||
|
||||
//initialize limbs
|
||||
create_bodyparts()
|
||||
create_internal_organs()
|
||||
|
||||
. = ..()
|
||||
|
||||
if (cubespawned)
|
||||
var/cap = CONFIG_GET(number/monkeycap)
|
||||
if (LAZYLEN(SSmobs.cubemonkeys) > cap)
|
||||
if (spawner)
|
||||
to_chat(spawner, "<span class='warning'>Bluespace harmonics prevent the spawning of more than [cap] monkeys on the station at one time!</span>")
|
||||
return INITIALIZE_HINT_QDEL
|
||||
SSmobs.cubemonkeys += src
|
||||
|
||||
create_dna(src)
|
||||
dna.initialize_dna(random_blood_type())
|
||||
|
||||
/mob/living/carbon/monkey/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/mob_holder, "monkey", null, null, null, SLOT_HEAD)
|
||||
|
||||
/mob/living/carbon/monkey/Destroy()
|
||||
SSmobs.cubemonkeys -= src
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/monkey/create_internal_organs()
|
||||
internal_organs += new /obj/item/organ/appendix
|
||||
internal_organs += new /obj/item/organ/lungs
|
||||
internal_organs += new /obj/item/organ/heart
|
||||
internal_organs += new /obj/item/organ/brain
|
||||
internal_organs += new /obj/item/organ/tongue
|
||||
internal_organs += new /obj/item/organ/eyes
|
||||
internal_organs += new /obj/item/organ/ears
|
||||
internal_organs += new /obj/item/organ/liver
|
||||
internal_organs += new /obj/item/organ/stomach
|
||||
..()
|
||||
|
||||
/mob/living/carbon/monkey/on_reagent_change()
|
||||
. = ..()
|
||||
remove_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE)
|
||||
var/amount
|
||||
if(reagents.has_reagent(/datum/reagent/medicine/morphine))
|
||||
amount = -1
|
||||
if(reagents.has_reagent("nuka_cola"))
|
||||
amount = -1
|
||||
if(amount)
|
||||
add_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
|
||||
|
||||
/mob/living/carbon/monkey/updatehealth()
|
||||
. = ..()
|
||||
var/slow = 0
|
||||
var/health_deficiency = (100 - health)
|
||||
if(health_deficiency >= 45)
|
||||
slow += (health_deficiency / 25)
|
||||
add_movespeed_modifier(MOVESPEED_ID_MONKEY_HEALTH_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = slow)
|
||||
|
||||
/mob/living/carbon/monkey/adjust_bodytemperature(amount)
|
||||
. = ..()
|
||||
var/slow = 0
|
||||
if (bodytemperature < 283.222)
|
||||
slow += (283.222 - bodytemperature) / 10 * 1.75
|
||||
if(slow <= 0)
|
||||
return
|
||||
add_movespeed_modifier(MOVESPEED_ID_MONKEY_TEMPERATURE_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
|
||||
|
||||
/mob/living/carbon/monkey/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Intent: [a_intent]")
|
||||
stat(null, "Move Mode: [m_intent]")
|
||||
if(client && mind)
|
||||
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling)
|
||||
stat("Chemical Storage", "[changeling.chem_charges]/[changeling.chem_storage]")
|
||||
stat("Absorbed DNA", changeling.absorbedcount)
|
||||
return
|
||||
|
||||
|
||||
/mob/living/carbon/monkey/verb/removeinternal()
|
||||
set name = "Remove Internals"
|
||||
set category = "IC"
|
||||
internal = null
|
||||
return
|
||||
|
||||
|
||||
/mob/living/carbon/monkey/IsAdvancedToolUser()//Unless its monkey mode monkeys cant use advanced tools
|
||||
if(mind && is_monkey(mind))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/monkey/reagent_check(datum/reagent/R) //can metabolize all reagents
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/monkey/canBeHandcuffed()
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/monkey/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
|
||||
if(judgement_criteria & JUDGE_EMAGGED)
|
||||
return 10 //Everyone is a criminal!
|
||||
|
||||
var/threatcount = 0
|
||||
|
||||
//Securitrons can't identify monkeys
|
||||
if( !(judgement_criteria & JUDGE_IGNOREMONKEYS) && (judgement_criteria & JUDGE_IDCHECK) )
|
||||
threatcount += 4
|
||||
|
||||
//Lasertag bullshit
|
||||
if(lasercolor)
|
||||
if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve
|
||||
if(is_holding_item_of_type(/obj/item/gun/energy/laser/redtag))
|
||||
threatcount += 4
|
||||
|
||||
if(lasercolor == "r")
|
||||
if(is_holding_item_of_type(/obj/item/gun/energy/laser/bluetag))
|
||||
threatcount += 4
|
||||
|
||||
return threatcount
|
||||
|
||||
//Check for weapons
|
||||
if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck )
|
||||
for(var/obj/item/I in held_items) //if they're holding a gun
|
||||
if(weaponcheck.Invoke(I))
|
||||
threatcount += 4
|
||||
if(weaponcheck.Invoke(back)) //if a weapon is present in the back slot
|
||||
threatcount += 4 //trigger look_for_perp() since they're nonhuman and very likely hostile
|
||||
|
||||
//mindshield implants imply trustworthyness
|
||||
if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
|
||||
threatcount -= 1
|
||||
|
||||
return threatcount
|
||||
|
||||
/mob/living/carbon/monkey/IsVocal()
|
||||
if(!getorganslot(ORGAN_SLOT_LUNGS))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/monkey/can_use_guns(obj/item/G)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/monkey/angry
|
||||
aggressive = TRUE
|
||||
|
||||
/mob/living/carbon/monkey/angry/Initialize()
|
||||
. = ..()
|
||||
if(prob(10))
|
||||
var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src)
|
||||
equip_to_slot_or_del(helmet,SLOT_HEAD)
|
||||
helmet.attack_self(src) // todo encapsulate toggle
|
||||
/mob/living/carbon/monkey
|
||||
name = "monkey"
|
||||
verb_say = "chimpers"
|
||||
initial_language_holder = /datum/language_holder/monkey
|
||||
icon = 'icons/mob/monkey.dmi'
|
||||
icon_state = ""
|
||||
gender = NEUTER
|
||||
pass_flags = PASSTABLE
|
||||
ventcrawler = VENTCRAWLER_NUDE
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1)
|
||||
type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/monkey
|
||||
gib_type = /obj/effect/decal/cleanable/blood/gibs
|
||||
unique_name = TRUE
|
||||
bodyparts = list(/obj/item/bodypart/chest/monkey, /obj/item/bodypart/head/monkey, /obj/item/bodypart/l_arm/monkey,
|
||||
/obj/item/bodypart/r_arm/monkey, /obj/item/bodypart/r_leg/monkey, /obj/item/bodypart/l_leg/monkey)
|
||||
hud_type = /datum/hud/monkey
|
||||
|
||||
/mob/living/carbon/monkey/Initialize(mapload, cubespawned=FALSE, mob/spawner)
|
||||
verbs += /mob/living/proc/mob_sleep
|
||||
verbs += /mob/living/proc/lay_down
|
||||
|
||||
if(unique_name) //used to exclude pun pun
|
||||
gender = pick(MALE, FEMALE)
|
||||
real_name = name
|
||||
|
||||
//initialize limbs
|
||||
create_bodyparts()
|
||||
create_internal_organs()
|
||||
|
||||
. = ..()
|
||||
|
||||
if (cubespawned)
|
||||
var/cap = CONFIG_GET(number/monkeycap)
|
||||
if (LAZYLEN(SSmobs.cubemonkeys) > cap)
|
||||
if (spawner)
|
||||
to_chat(spawner, "<span class='warning'>Bluespace harmonics prevent the spawning of more than [cap] monkeys on the station at one time!</span>")
|
||||
return INITIALIZE_HINT_QDEL
|
||||
SSmobs.cubemonkeys += src
|
||||
|
||||
create_dna(src)
|
||||
dna.initialize_dna(random_blood_type())
|
||||
|
||||
/mob/living/carbon/monkey/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/mob_holder, "monkey", null, null, null, SLOT_HEAD)
|
||||
|
||||
/mob/living/carbon/monkey/Destroy()
|
||||
SSmobs.cubemonkeys -= src
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/monkey/create_internal_organs()
|
||||
internal_organs += new /obj/item/organ/appendix
|
||||
internal_organs += new /obj/item/organ/lungs
|
||||
internal_organs += new /obj/item/organ/heart
|
||||
internal_organs += new /obj/item/organ/brain
|
||||
internal_organs += new /obj/item/organ/tongue
|
||||
internal_organs += new /obj/item/organ/eyes
|
||||
internal_organs += new /obj/item/organ/ears
|
||||
internal_organs += new /obj/item/organ/liver
|
||||
internal_organs += new /obj/item/organ/stomach
|
||||
..()
|
||||
|
||||
/mob/living/carbon/monkey/on_reagent_change()
|
||||
. = ..()
|
||||
remove_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE)
|
||||
var/amount
|
||||
if(reagents.has_reagent("morphine"))
|
||||
amount = -1
|
||||
if(reagents.has_reagent("nuka_cola"))
|
||||
amount = -1
|
||||
if(amount)
|
||||
add_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
|
||||
|
||||
/mob/living/carbon/monkey/updatehealth()
|
||||
. = ..()
|
||||
var/slow = 0
|
||||
var/health_deficiency = (100 - health)
|
||||
if(health_deficiency >= 45)
|
||||
slow += (health_deficiency / 25)
|
||||
add_movespeed_modifier(MOVESPEED_ID_MONKEY_HEALTH_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = slow)
|
||||
|
||||
/mob/living/carbon/monkey/adjust_bodytemperature(amount)
|
||||
. = ..()
|
||||
var/slow = 0
|
||||
if (bodytemperature < 283.222)
|
||||
slow += (283.222 - bodytemperature) / 10 * 1.75
|
||||
if(slow <= 0)
|
||||
return
|
||||
add_movespeed_modifier(MOVESPEED_ID_MONKEY_TEMPERATURE_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
|
||||
|
||||
/mob/living/carbon/monkey/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Intent: [a_intent]")
|
||||
stat(null, "Move Mode: [m_intent]")
|
||||
if(client && mind)
|
||||
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling)
|
||||
stat("Chemical Storage", "[changeling.chem_charges]/[changeling.chem_storage]")
|
||||
stat("Absorbed DNA", changeling.absorbedcount)
|
||||
return
|
||||
|
||||
|
||||
/mob/living/carbon/monkey/verb/removeinternal()
|
||||
set name = "Remove Internals"
|
||||
set category = "IC"
|
||||
internal = null
|
||||
return
|
||||
|
||||
|
||||
/mob/living/carbon/monkey/IsAdvancedToolUser()//Unless its monkey mode monkeys cant use advanced tools
|
||||
if(mind && is_monkey(mind))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/monkey/reagent_check(datum/reagent/R) //can metabolize all reagents
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/monkey/canBeHandcuffed()
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/monkey/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
|
||||
if(judgement_criteria & JUDGE_EMAGGED)
|
||||
return 10 //Everyone is a criminal!
|
||||
|
||||
var/threatcount = 0
|
||||
|
||||
//Securitrons can't identify monkeys
|
||||
if( !(judgement_criteria & JUDGE_IGNOREMONKEYS) && (judgement_criteria & JUDGE_IDCHECK) )
|
||||
threatcount += 4
|
||||
|
||||
//Lasertag bullshit
|
||||
if(lasercolor)
|
||||
if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve
|
||||
if(is_holding_item_of_type(/obj/item/gun/energy/laser/redtag))
|
||||
threatcount += 4
|
||||
|
||||
if(lasercolor == "r")
|
||||
if(is_holding_item_of_type(/obj/item/gun/energy/laser/bluetag))
|
||||
threatcount += 4
|
||||
|
||||
return threatcount
|
||||
|
||||
//Check for weapons
|
||||
if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck )
|
||||
for(var/obj/item/I in held_items) //if they're holding a gun
|
||||
if(weaponcheck.Invoke(I))
|
||||
threatcount += 4
|
||||
if(weaponcheck.Invoke(back)) //if a weapon is present in the back slot
|
||||
threatcount += 4 //trigger look_for_perp() since they're nonhuman and very likely hostile
|
||||
|
||||
//mindshield implants imply trustworthyness
|
||||
if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
|
||||
threatcount -= 1
|
||||
|
||||
return threatcount
|
||||
|
||||
/mob/living/carbon/monkey/IsVocal()
|
||||
if(!getorganslot(ORGAN_SLOT_LUNGS))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/monkey/can_use_guns(obj/item/G)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/monkey/angry
|
||||
aggressive = TRUE
|
||||
|
||||
/mob/living/carbon/monkey/angry/Initialize()
|
||||
. = ..()
|
||||
if(prob(10))
|
||||
var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src)
|
||||
equip_to_slot_or_del(helmet,SLOT_HEAD)
|
||||
helmet.attack_self(src) // todo encapsulate toggle
|
||||
|
||||
@@ -17,4 +17,18 @@
|
||||
if(T)
|
||||
. = T.could_speak_in_language(dt)
|
||||
else
|
||||
. = initial(dt.flags) & TONGUELESS_SPEECH
|
||||
. = initial(dt.flags) & TONGUELESS_SPEECH
|
||||
|
||||
/mob/living/carbon/hear_intercept(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(!client)
|
||||
return
|
||||
for(var/T in get_traumas())
|
||||
var/datum/brain_trauma/trauma = T
|
||||
message = trauma.on_hear(message, speaker, message_language, raw_message, radio_freq)
|
||||
|
||||
if (src.mind.has_antag_datum(/datum/antagonist/traitor))
|
||||
message = GLOB.syndicate_code_phrase_regex.Replace(message, "<span class='blue'>$1</span>")
|
||||
message = GLOB.syndicate_code_response_regex.Replace(message, "<span class='red'>$1</span>")
|
||||
|
||||
return message
|
||||
|
||||
@@ -84,7 +84,6 @@
|
||||
update_canmove()
|
||||
med_hud_set_health()
|
||||
med_hud_set_status()
|
||||
clear_typing_indicator()
|
||||
if(!gibbed && !QDELETED(src))
|
||||
addtimer(CALLBACK(src, .proc/med_hud_set_status), (DEFIB_TIME_LIMIT * 10) + 1)
|
||||
stop_pulling()
|
||||
|
||||
@@ -58,9 +58,9 @@
|
||||
message = "coughs!"
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
|
||||
/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional)
|
||||
/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE)
|
||||
. = ..()
|
||||
if(HAS_TRAIT(user, TRAIT_SOOTHED_THROAT))
|
||||
if(user.reagents && (user.reagents.get_reagent("menthol") || user.reagents.get_reagent("peppermint_patty")))
|
||||
return FALSE
|
||||
|
||||
/datum/emote/living/dance
|
||||
@@ -405,10 +405,17 @@
|
||||
message = null
|
||||
|
||||
/datum/emote/living/custom/proc/check_invalid(mob/user, input)
|
||||
if(stop_bad_mime.Find(input, 1, 1))
|
||||
. = TRUE
|
||||
if(copytext(input,1,5) == "says")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
return TRUE
|
||||
return FALSE
|
||||
else if(copytext(input,1,9) == "exclaims")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
else if(copytext(input,1,6) == "yells")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
else if(copytext(input,1,5) == "asks")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
else
|
||||
. = FALSE
|
||||
|
||||
/datum/emote/living/custom/run_emote(mob/user, params, type_override = null)
|
||||
if(jobban_isbanned(user, "emote"))
|
||||
@@ -420,7 +427,7 @@
|
||||
to_chat(user, "You cannot send IC messages (muted).")
|
||||
return FALSE
|
||||
else if(!params)
|
||||
var/custom_emote = stripped_multiline_input("Choose an emote to display.", "Custom Emote", null, MAX_MESSAGE_LEN)
|
||||
var/custom_emote = copytext(sanitize(input("Choose an emote to display.") as message|null), 1, MAX_MESSAGE_LEN) //CIT CHANGE - expands emote textbox
|
||||
if(custom_emote && !check_invalid(user, custom_emote))
|
||||
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
|
||||
switch(type)
|
||||
|
||||
@@ -1228,7 +1228,7 @@
|
||||
clamp_unconscious_to = 0,
|
||||
clamp_immobility_to = 0,
|
||||
reset_misc = TRUE,
|
||||
healing_chems = list(/datum/reagent/medicine/inaprovaline = 3, /datum/reagent/medicine/synaptizine = 10, /datum/reagent/medicine/regen_jelly = 10, /datum/reagent/medicine/stimulants = 10),
|
||||
healing_chems = list("inaprovaline" = 3, "synaptizine" = 10, "regen_jelly" = 10, "stimulants" = 10),
|
||||
message = "<span class='boldnotice'>You feel a surge of energy!</span>",
|
||||
stamina_buffer_boost = 0, //restores stamina buffer rather than just health
|
||||
scale_stamina_loss_recovery, //defaults to null. if this is set, restores loss * this stamina. make sure it's a fraction.
|
||||
@@ -1255,6 +1255,6 @@
|
||||
updatehealth()
|
||||
update_stamina()
|
||||
update_canmove()
|
||||
if(healing_chems)
|
||||
reagents.add_reagent_list(healing_chems)
|
||||
for(var/chem in healing_chems)
|
||||
reagents.add_reagent(chem, healing_chems[chem])
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -59,9 +59,7 @@
|
||||
var/custom_body_size = 100
|
||||
var/breedable = 0
|
||||
var/impregchance = 0
|
||||
//h13 noncon settings
|
||||
var/Noncon = 0
|
||||
var/ERP = 0
|
||||
|
||||
|
||||
var/list/mob_biotypes = list(MOB_ORGANIC)
|
||||
var/metabolism_efficiency = 1 //more or less efficiency to metabolize helpful/harmful reagents and regulate body temperature..
|
||||
@@ -111,7 +109,7 @@
|
||||
var/last_words //used for database logging
|
||||
|
||||
var/list/obj/effect/proc_holder/abilities = list()
|
||||
|
||||
|
||||
var/can_be_held = FALSE
|
||||
|
||||
var/radiation = 0 //If the mob is irradiated.
|
||||
|
||||
@@ -89,7 +89,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE, MODE_SING = TRUE)
|
||||
|
||||
if(sanitize)
|
||||
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
if(!message || message == "")
|
||||
return
|
||||
|
||||
@@ -99,10 +99,11 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
var/in_critical = InCritical()
|
||||
|
||||
if(one_character_prefix[message_mode])
|
||||
message = copytext_char(message, 2)
|
||||
message = copytext(message, 2)
|
||||
else if(message_mode || saymode)
|
||||
message = copytext_char(message, 3)
|
||||
message = trim_left(message)
|
||||
message = copytext(message, 3)
|
||||
if(findtext(message, " ", 1, 2))
|
||||
message = copytext(message, 2)
|
||||
|
||||
if(message_mode == MODE_ADMIN)
|
||||
if(client)
|
||||
@@ -134,10 +135,11 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
// No, you cannot speak in xenocommon just because you know the key
|
||||
if(can_speak_in_language(message_language))
|
||||
language = message_language
|
||||
message = copytext_char(message, 3)
|
||||
message = copytext(message, 3)
|
||||
|
||||
// Trim the space if they said ",0 I LOVE LANGUAGES"
|
||||
message = trim_left(message)
|
||||
if(findtext(message, " ", 1, 2))
|
||||
message = copytext(message, 2)
|
||||
|
||||
if(!language)
|
||||
language = get_default_language()
|
||||
@@ -165,8 +167,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
if(fullcrit)
|
||||
var/health_diff = round(-HEALTH_THRESHOLD_DEAD + health)
|
||||
// If we cut our message short, abruptly end it with a-..
|
||||
var/message_len = length_char(message)
|
||||
message = copytext_char(message, 1, health_diff) + "[message_len > health_diff ? "-.." : "..."]"
|
||||
var/message_len = length(message)
|
||||
message = copytext(message, 1, health_diff) + "[message_len > health_diff ? "-.." : "..."]"
|
||||
message = Ellipsis(message, 10, 1)
|
||||
message_mode = MODE_WHISPER_CRIT
|
||||
succumbed = TRUE
|
||||
@@ -219,19 +221,11 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
|
||||
if(succumbed)
|
||||
succumb()
|
||||
to_chat(src, compose_message(src, language, message, null, spans, message_mode))
|
||||
to_chat(src, compose_message(src, language, message, , spans, message_mode))
|
||||
|
||||
return 1
|
||||
|
||||
/mob/living/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, face_name = FALSE, atom/movable/source)
|
||||
. = ..()
|
||||
if(isliving(speaker))
|
||||
var/turf/sourceturf = get_turf(source)
|
||||
var/turf/T = get_turf(src)
|
||||
if(sourceturf && T && !(sourceturf in get_hear(5, T)))
|
||||
. = "<span class='small'>[.]</span>"
|
||||
|
||||
/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(!client)
|
||||
return
|
||||
@@ -251,10 +245,10 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
playsound_local(src,'sound/voice/radio.ogg', 30, 1)
|
||||
|
||||
// Recompose message for AI hrefs, language incomprehension.
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
|
||||
message = hear_intercept(message, speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
message = hear_intercept(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
|
||||
show_message(message, MSG_AUDIBLE, deaf_message, deaf_type)
|
||||
show_message(message, 2, deaf_message, deaf_type)
|
||||
return message
|
||||
|
||||
/mob/living/proc/hear_intercept(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
@@ -268,8 +262,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source)
|
||||
var/list/the_dead = list()
|
||||
var/list/yellareas //CIT CHANGE - adds the ability for yelling to penetrate walls and echo throughout areas
|
||||
if(!eavesdrop_range && say_test(message) == "2") //CIT CHANGE - ditto
|
||||
yellareas = get_areas_in_range(message_range*0.5, source) //CIT CHANGE - ditto
|
||||
if(say_test(message) == "2") //CIT CHANGE - ditto
|
||||
yellareas = get_areas_in_range(message_range*0.5,src) //CIT CHANGE - ditto
|
||||
for(var/_M in GLOB.player_list)
|
||||
var/mob/M = _M
|
||||
if(M.stat != DEAD) //not dead, not important
|
||||
@@ -280,7 +274,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
continue
|
||||
if(!M.client || !client) //client is so that ghosts don't have to listen to mice
|
||||
continue
|
||||
if(get_dist(M, source) > 7 || M.z != z) //they're out of range of normal hearing
|
||||
if(get_dist(M, src) > 7 || M.z != z) //they're out of range of normal hearing
|
||||
if(eavesdropping_modes[message_mode] && !(M.client.prefs.chat_toggles & CHAT_GHOSTWHISPER)) //they're whispering and we have hearing whispers at any range off
|
||||
continue
|
||||
if(!(M.client.prefs.chat_toggles & CHAT_GHOSTEARS)) //they're talking normally and we have hearing at any range off
|
||||
@@ -292,15 +286,15 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
var/eavesrendered
|
||||
if(eavesdrop_range)
|
||||
eavesdropping = stars(message)
|
||||
eavesrendered = compose_message(src, message_language, eavesdropping, null, spans, message_mode, FALSE, source)
|
||||
eavesrendered = compose_message(src, message_language, eavesdropping, , spans, message_mode)
|
||||
|
||||
var/rendered = compose_message(src, message_language, message, null, spans, message_mode, FALSE, source)
|
||||
var/rendered = compose_message(src, message_language, message, , spans, message_mode)
|
||||
for(var/_AM in listening)
|
||||
var/atom/movable/AM = _AM
|
||||
if(eavesdrop_range && get_dist(source, AM) > message_range && !(the_dead[AM]))
|
||||
AM.Hear(eavesrendered, src, message_language, eavesdropping, null, spans, message_mode, source)
|
||||
AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mode)
|
||||
else
|
||||
AM.Hear(rendered, src, message_language, message, null, spans, message_mode, source)
|
||||
AM.Hear(rendered, src, message_language, message, , spans, message_mode)
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message)
|
||||
|
||||
//speech bubble
|
||||
@@ -342,13 +336,13 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
return 1
|
||||
|
||||
/mob/living/proc/get_key(message)
|
||||
var/key = message[1]
|
||||
var/key = copytext(message, 1, 2)
|
||||
if(key in GLOB.department_radio_prefixes)
|
||||
return lowertext(message[1 + length(key)])
|
||||
return lowertext(copytext(message, 2, 3))
|
||||
|
||||
/mob/living/proc/get_message_language(message)
|
||||
if(message[1] == ",")
|
||||
var/key = message[1 + length(message[1])]
|
||||
if(copytext(message, 1, 2) == ",")
|
||||
var/key = copytext(message, 2, 3)
|
||||
for(var/ld in GLOB.all_languages)
|
||||
var/datum/language/LD = ld
|
||||
if(initial(LD.key) == key)
|
||||
@@ -411,16 +405,18 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
return 0
|
||||
|
||||
/mob/living/say_mod(input, message_mode)
|
||||
. = ..()
|
||||
if(message_mode == MODE_WHISPER_CRIT)
|
||||
if(message_mode == MODE_WHISPER)
|
||||
. = verb_whisper
|
||||
else if(message_mode == MODE_WHISPER_CRIT)
|
||||
. = "[verb_whisper] in [p_their()] last breath"
|
||||
else if(message_mode != MODE_CUSTOM_SAY)
|
||||
if(message_mode == MODE_WHISPER)
|
||||
. = verb_whisper
|
||||
else if(stuttering)
|
||||
. = "stammers"
|
||||
else if(derpspeech)
|
||||
. = "gibbers"
|
||||
else if(stuttering)
|
||||
. = "stammers"
|
||||
else if(derpspeech)
|
||||
. = "gibbers"
|
||||
else if(message_mode == MODE_SING)
|
||||
. = verb_sing
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/mob/living/whisper(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
say("#[message]", bubble_type, spans, sanitize, language, ignore_spam, forced)
|
||||
|
||||
+1001
-1001
File diff suppressed because it is too large
Load Diff
@@ -1,197 +1,197 @@
|
||||
// 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"
|
||||
|
||||
invisibility = INVISIBILITY_MAXIMUM
|
||||
hud_possible = list(ANTAG_HUD, AI_DETECT_HUD = HUD_LIST_LIST)
|
||||
var/list/visibleCameraChunks = list()
|
||||
var/mob/living/silicon/ai/ai = null
|
||||
var/relay_speech = FALSE
|
||||
var/use_static = USE_STATIC_OPAQUE
|
||||
var/static_visibility_range = 16
|
||||
var/ai_detector_visible = TRUE
|
||||
var/ai_detector_color = COLOR_RED
|
||||
|
||||
/mob/camera/aiEye/Initialize()
|
||||
. = ..()
|
||||
GLOB.aiEyes += src
|
||||
update_ai_detect_hud()
|
||||
setLoc(loc, TRUE)
|
||||
|
||||
/mob/camera/aiEye/proc/update_ai_detect_hud()
|
||||
var/datum/atom_hud/ai_detector/hud = GLOB.huds[DATA_HUD_AI_DETECT]
|
||||
var/list/old_images = hud_list[AI_DETECT_HUD]
|
||||
if(!ai_detector_visible)
|
||||
hud.remove_from_hud(src)
|
||||
QDEL_LIST(old_images)
|
||||
return
|
||||
|
||||
if(!hud.hudusers.len)
|
||||
//no one is watching, do not bother updating anything
|
||||
return
|
||||
hud.remove_from_hud(src)
|
||||
|
||||
var/static/list/vis_contents_objects = list()
|
||||
var/obj/effect/overlay/ai_detect_hud/hud_obj = vis_contents_objects[ai_detector_color]
|
||||
if(!hud_obj)
|
||||
hud_obj = new /obj/effect/overlay/ai_detect_hud()
|
||||
hud_obj.color = ai_detector_color
|
||||
vis_contents_objects[ai_detector_color] = hud_obj
|
||||
|
||||
var/list/new_images = list()
|
||||
var/list/turfs = get_visible_turfs()
|
||||
for(var/T in turfs)
|
||||
var/image/I = (old_images.len > new_images.len) ? old_images[new_images.len + 1] : image(null, T)
|
||||
I.loc = T
|
||||
I.vis_contents += hud_obj
|
||||
new_images += I
|
||||
for(var/i in (new_images.len + 1) to old_images.len)
|
||||
qdel(old_images[i])
|
||||
hud_list[AI_DETECT_HUD] = new_images
|
||||
hud.add_to_hud(src)
|
||||
|
||||
/mob/camera/aiEye/proc/get_visible_turfs()
|
||||
if(!isturf(loc))
|
||||
return list()
|
||||
var/client/C = GetViewerClient()
|
||||
var/view = C ? getviewsize(C.view) : getviewsize(world.view)
|
||||
var/turf/lowerleft = locate(max(1, x - (view[1] - 1)/2), max(1, y - (view[2] - 1)/2), z)
|
||||
var/turf/upperright = locate(min(world.maxx, lowerleft.x + (view[1] - 1)), min(world.maxy, lowerleft.y + (view[2] - 1)), lowerleft.z)
|
||||
return block(lowerleft, upperright)
|
||||
|
||||
// Use this when setting the aiEye's location.
|
||||
// It will also stream the chunk that the new loc is in.
|
||||
|
||||
/mob/camera/aiEye/proc/setLoc(T, force_update = FALSE)
|
||||
if(ai)
|
||||
if(!isturf(ai.loc))
|
||||
return
|
||||
T = get_turf(T)
|
||||
if(!force_update && (T == get_turf(src)) )
|
||||
return //we are already here!
|
||||
if (T)
|
||||
forceMove(T)
|
||||
else
|
||||
moveToNullspace()
|
||||
if(use_static != USE_STATIC_NONE)
|
||||
ai.camera_visibility(src)
|
||||
if(ai.client && !ai.multicam_on)
|
||||
ai.client.eye = src
|
||||
update_ai_detect_hud()
|
||||
update_parallax_contents()
|
||||
//Holopad
|
||||
if(istype(ai.current, /obj/machinery/holopad))
|
||||
var/obj/machinery/holopad/H = ai.current
|
||||
H.move_hologram(ai, T)
|
||||
if(ai.camera_light_on)
|
||||
ai.light_cameras()
|
||||
if(ai.master_multicam)
|
||||
ai.master_multicam.refresh_view()
|
||||
|
||||
/mob/camera/aiEye/Move()
|
||||
return 0
|
||||
|
||||
/mob/camera/aiEye/proc/GetViewerClient()
|
||||
if(ai)
|
||||
return ai.client
|
||||
return null
|
||||
|
||||
/mob/camera/aiEye/Destroy()
|
||||
if(ai)
|
||||
ai.all_eyes -= src
|
||||
ai = null
|
||||
for(var/V in visibleCameraChunks)
|
||||
var/datum/camerachunk/c = V
|
||||
c.remove(src)
|
||||
GLOB.aiEyes -= src
|
||||
if(ai_detector_visible)
|
||||
var/datum/atom_hud/ai_detector/hud = GLOB.huds[DATA_HUD_AI_DETECT]
|
||||
hud.remove_from_hud(src)
|
||||
var/list/L = hud_list[AI_DETECT_HUD]
|
||||
QDEL_LIST(L)
|
||||
return ..()
|
||||
|
||||
/atom/proc/move_camera_by_click()
|
||||
if(isAI(usr))
|
||||
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)
|
||||
|
||||
// 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, 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
|
||||
|
||||
// Return to the Core.
|
||||
/mob/living/silicon/ai/proc/view_core()
|
||||
if(istype(current,/obj/machinery/holopad))
|
||||
var/obj/machinery/holopad/H = current
|
||||
H.clear_holo(src)
|
||||
else
|
||||
current = null
|
||||
cameraFollow = null
|
||||
unset_machine()
|
||||
|
||||
if(!eyeobj || !eyeobj.loc || QDELETED(eyeobj))
|
||||
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/verb/toggle_acceleration()
|
||||
set category = "AI Commands"
|
||||
set name = "Toggle Camera Acceleration"
|
||||
|
||||
if(incapacitated())
|
||||
return
|
||||
acceleration = !acceleration
|
||||
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
|
||||
|
||||
/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker))
|
||||
ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
|
||||
/obj/effect/overlay/ai_detect_hud
|
||||
name = ""
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
icon = 'icons/effects/alphacolors.dmi'
|
||||
icon_state = ""
|
||||
alpha = 100
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
plane = GAME_PLANE
|
||||
// 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"
|
||||
|
||||
invisibility = INVISIBILITY_MAXIMUM
|
||||
hud_possible = list(ANTAG_HUD, AI_DETECT_HUD = HUD_LIST_LIST)
|
||||
var/list/visibleCameraChunks = list()
|
||||
var/mob/living/silicon/ai/ai = null
|
||||
var/relay_speech = FALSE
|
||||
var/use_static = USE_STATIC_OPAQUE
|
||||
var/static_visibility_range = 16
|
||||
var/ai_detector_visible = TRUE
|
||||
var/ai_detector_color = COLOR_RED
|
||||
|
||||
/mob/camera/aiEye/Initialize()
|
||||
. = ..()
|
||||
GLOB.aiEyes += src
|
||||
update_ai_detect_hud()
|
||||
setLoc(loc, TRUE)
|
||||
|
||||
/mob/camera/aiEye/proc/update_ai_detect_hud()
|
||||
var/datum/atom_hud/ai_detector/hud = GLOB.huds[DATA_HUD_AI_DETECT]
|
||||
var/list/old_images = hud_list[AI_DETECT_HUD]
|
||||
if(!ai_detector_visible)
|
||||
hud.remove_from_hud(src)
|
||||
QDEL_LIST(old_images)
|
||||
return
|
||||
|
||||
if(!hud.hudusers.len)
|
||||
//no one is watching, do not bother updating anything
|
||||
return
|
||||
hud.remove_from_hud(src)
|
||||
|
||||
var/static/list/vis_contents_objects = list()
|
||||
var/obj/effect/overlay/ai_detect_hud/hud_obj = vis_contents_objects[ai_detector_color]
|
||||
if(!hud_obj)
|
||||
hud_obj = new /obj/effect/overlay/ai_detect_hud()
|
||||
hud_obj.color = ai_detector_color
|
||||
vis_contents_objects[ai_detector_color] = hud_obj
|
||||
|
||||
var/list/new_images = list()
|
||||
var/list/turfs = get_visible_turfs()
|
||||
for(var/T in turfs)
|
||||
var/image/I = (old_images.len > new_images.len) ? old_images[new_images.len + 1] : image(null, T)
|
||||
I.loc = T
|
||||
I.vis_contents += hud_obj
|
||||
new_images += I
|
||||
for(var/i in (new_images.len + 1) to old_images.len)
|
||||
qdel(old_images[i])
|
||||
hud_list[AI_DETECT_HUD] = new_images
|
||||
hud.add_to_hud(src)
|
||||
|
||||
/mob/camera/aiEye/proc/get_visible_turfs()
|
||||
if(!isturf(loc))
|
||||
return list()
|
||||
var/client/C = GetViewerClient()
|
||||
var/view = C ? getviewsize(C.view) : getviewsize(world.view)
|
||||
var/turf/lowerleft = locate(max(1, x - (view[1] - 1)/2), max(1, y - (view[2] - 1)/2), z)
|
||||
var/turf/upperright = locate(min(world.maxx, lowerleft.x + (view[1] - 1)), min(world.maxy, lowerleft.y + (view[2] - 1)), lowerleft.z)
|
||||
return block(lowerleft, upperright)
|
||||
|
||||
// Use this when setting the aiEye's location.
|
||||
// It will also stream the chunk that the new loc is in.
|
||||
|
||||
/mob/camera/aiEye/proc/setLoc(T, force_update = FALSE)
|
||||
if(ai)
|
||||
if(!isturf(ai.loc))
|
||||
return
|
||||
T = get_turf(T)
|
||||
if(!force_update && (T == get_turf(src)) )
|
||||
return //we are already here!
|
||||
if (T)
|
||||
forceMove(T)
|
||||
else
|
||||
moveToNullspace()
|
||||
if(use_static != USE_STATIC_NONE)
|
||||
ai.camera_visibility(src)
|
||||
if(ai.client && !ai.multicam_on)
|
||||
ai.client.eye = src
|
||||
update_ai_detect_hud()
|
||||
update_parallax_contents()
|
||||
//Holopad
|
||||
if(istype(ai.current, /obj/machinery/holopad))
|
||||
var/obj/machinery/holopad/H = ai.current
|
||||
H.move_hologram(ai, T)
|
||||
if(ai.camera_light_on)
|
||||
ai.light_cameras()
|
||||
if(ai.master_multicam)
|
||||
ai.master_multicam.refresh_view()
|
||||
|
||||
/mob/camera/aiEye/Move()
|
||||
return 0
|
||||
|
||||
/mob/camera/aiEye/proc/GetViewerClient()
|
||||
if(ai)
|
||||
return ai.client
|
||||
return null
|
||||
|
||||
/mob/camera/aiEye/Destroy()
|
||||
if(ai)
|
||||
ai.all_eyes -= src
|
||||
ai = null
|
||||
for(var/V in visibleCameraChunks)
|
||||
var/datum/camerachunk/c = V
|
||||
c.remove(src)
|
||||
GLOB.aiEyes -= src
|
||||
if(ai_detector_visible)
|
||||
var/datum/atom_hud/ai_detector/hud = GLOB.huds[DATA_HUD_AI_DETECT]
|
||||
hud.remove_from_hud(src)
|
||||
var/list/L = hud_list[AI_DETECT_HUD]
|
||||
QDEL_LIST(L)
|
||||
return ..()
|
||||
|
||||
/atom/proc/move_camera_by_click()
|
||||
if(isAI(usr))
|
||||
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)
|
||||
|
||||
// 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, 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
|
||||
|
||||
// Return to the Core.
|
||||
/mob/living/silicon/ai/proc/view_core()
|
||||
if(istype(current,/obj/machinery/holopad))
|
||||
var/obj/machinery/holopad/H = current
|
||||
H.clear_holo(src)
|
||||
else
|
||||
current = null
|
||||
cameraFollow = null
|
||||
unset_machine()
|
||||
|
||||
if(!eyeobj || !eyeobj.loc || QDELETED(eyeobj))
|
||||
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/verb/toggle_acceleration()
|
||||
set category = "AI Commands"
|
||||
set name = "Toggle Camera Acceleration"
|
||||
|
||||
if(incapacitated())
|
||||
return
|
||||
acceleration = !acceleration
|
||||
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
|
||||
|
||||
/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker))
|
||||
ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
|
||||
/obj/effect/overlay/ai_detect_hud
|
||||
name = ""
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
icon = 'icons/effects/alphacolors.dmi'
|
||||
icon_state = ""
|
||||
alpha = 100
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
plane = GAME_PLANE
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
..()
|
||||
|
||||
/mob/living/silicon/ai/get_message_mode(message)
|
||||
var/static/regex/holopad_finder = regex(@"[:.#][hH]")
|
||||
if(holopad_finder.Find(message, 1, 1))
|
||||
if(copytext(message, 1, 3) in list(":h", ":H", ".h", ".H", "#h", "#H"))
|
||||
return MODE_HOLOPAD
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -4,7 +4,4 @@
|
||||
var/datum/antagonist/rev/rev = mind.has_antag_datum(/datum/antagonist/rev)
|
||||
if(rev)
|
||||
rev.remove_revolutionary(TRUE)
|
||||
var/datum/antagonist/bloodsucker/V = mind.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
if(V)
|
||||
mind.remove_antag_datum(V)
|
||||
..()
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
/datum/paiCandidate/proc/savefile_path(mob/user)
|
||||
return "data/player_saves/[user.ckey[1]]/[user.ckey]/pai.sav"
|
||||
return "data/player_saves/[copytext(user.ckey, 1, 2)]/[user.ckey]/pai.sav"
|
||||
|
||||
/datum/paiCandidate/proc/savefile_save(mob/user)
|
||||
if(IsGuestKey(user.key))
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list())
|
||||
|
||||
var/speed = list("enabled"=FALSE, "timer"=null, "ref"=null) // VTEC stats
|
||||
var/speed = 0 // VTEC speed boost.
|
||||
var/magpulse = FALSE // Magboot-like effect.
|
||||
var/ionpulse = FALSE // Jetpack-like effect.
|
||||
var/ionpulse_on = FALSE // Jetpack-like effect.
|
||||
@@ -1042,6 +1042,10 @@
|
||||
if(hud_used)
|
||||
hud_used.update_robot_modules_display()
|
||||
|
||||
if (hasExpanded)
|
||||
resize = 0.5
|
||||
hasExpanded = FALSE
|
||||
update_transform()
|
||||
module.transform_to(/obj/item/robot_module)
|
||||
|
||||
// Remove upgrades.
|
||||
@@ -1051,7 +1055,7 @@
|
||||
|
||||
upgrades.Cut()
|
||||
|
||||
removeVTecStats()
|
||||
speed = 0
|
||||
ionpulse = FALSE
|
||||
revert_shell()
|
||||
|
||||
@@ -1083,13 +1087,6 @@
|
||||
magpulse = module.magpulsing
|
||||
updatename()
|
||||
|
||||
/mob/living/silicon/robot/update_transform()
|
||||
. = ..()
|
||||
if (hasExpanded)
|
||||
var/matrix/ntransform = matrix(transform)
|
||||
ntransform.Scale(2) //This seems a bit big
|
||||
ntransform.Translate(0, 16)
|
||||
transform = ntransform
|
||||
|
||||
/mob/living/silicon/robot/proc/place_on_head(obj/item/new_hat)
|
||||
if(hat)
|
||||
@@ -1245,18 +1242,3 @@
|
||||
connected_ai.aicamera.stored[i] = TRUE
|
||||
for(var/i in connected_ai.aicamera.stored)
|
||||
aicamera.stored[i] = TRUE
|
||||
|
||||
/mob/living/silicon/robot/proc/removeVTecStats()
|
||||
if (!speed["enabled"])
|
||||
return FALSE
|
||||
|
||||
speed["enabled"] = FALSE
|
||||
deltimer(speed["timer"])
|
||||
RemoveAbility(speed["ref"])
|
||||
remove_movespeed_modifier(MOVESPEED_ID_SILICON_VTEC)
|
||||
|
||||
speed["ref"] = null
|
||||
speed["timer"] = null
|
||||
|
||||
update_transform()
|
||||
return TRUE
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,10 +10,9 @@
|
||||
bubble_icon = "machine"
|
||||
weather_immunities = list("ash")
|
||||
possible_a_intents = list(INTENT_HELP, INTENT_HARM)
|
||||
mob_biotypes = list(MOB_SILICON)
|
||||
mob_biotypes = list(MOB_ROBOTIC)
|
||||
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
|
||||
speech_span = SPAN_ROBOT
|
||||
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
|
||||
|
||||
var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS
|
||||
var/last_lawchange_announce = 0
|
||||
@@ -71,6 +70,9 @@
|
||||
/mob/living/silicon/contents_explosion(severity, target)
|
||||
return
|
||||
|
||||
/mob/living/silicon/prevent_content_explosion()
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/proc/cancelAlarm()
|
||||
return
|
||||
|
||||
@@ -388,7 +390,6 @@
|
||||
if (aicamera)
|
||||
return aicamera.selectpicture(user)
|
||||
|
||||
/*
|
||||
/mob/living/silicon/update_transform()
|
||||
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
|
||||
var/changed = 0
|
||||
@@ -399,7 +400,7 @@
|
||||
|
||||
if(changed)
|
||||
animate(src, transform = ntransform, time = 2,easing = EASE_IN|EASE_OUT)
|
||||
return ..() */
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/is_literate()
|
||||
return 1
|
||||
@@ -409,4 +410,3 @@
|
||||
|
||||
/mob/living/silicon/handle_high_gravity(gravity)
|
||||
return
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
unsuitable_atmos_damage = 0
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 100000
|
||||
blood_volume = 0
|
||||
|
||||
/mob/living/simple_animal/astral/death()
|
||||
icon_state = "shade_dead"
|
||||
@@ -45,7 +44,7 @@
|
||||
if(isliving(A))
|
||||
if(ishuman(A))
|
||||
var/mob/living/carbon/human/H = A
|
||||
if(H.reagents.has_reagent(/datum/reagent/fermi/astral) && !H.mind)
|
||||
if(H.reagents.has_reagent("astral") && !H.mind)
|
||||
var/datum/reagent/fermi/astral/As = locate(/datum/reagent/fermi/astral) in H.reagents.reagent_list
|
||||
if(As.originalmind == src.mind && As.current_cycle < 10 && H.stat != DEAD) //So you can return to your body.
|
||||
to_chat(src, "<span class='warning'><b><i>The intensity of the astrogen in your body is too much allow you to return to yourself yet!</b></i></span>")
|
||||
@@ -59,9 +58,3 @@
|
||||
return
|
||||
to_chat(A, "[src] projects into your mind, <b><i> \"[message]\"</b></i>")
|
||||
log_game("FERMICHEM: [src] has astrally transmitted [message] into [A]")
|
||||
|
||||
//Delete the mob if there's no mind! Pay that mob no mind.
|
||||
/mob/living/simple_animal/astral/Life()
|
||||
if(!mind)
|
||||
qdel(src)
|
||||
. = ..()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
||||
icon_state = "mulebot0"
|
||||
density = TRUE
|
||||
move_resist = MOVE_FORCE_STRONG
|
||||
animate_movement = FORWARD_STEPS
|
||||
animate_movement = 1
|
||||
health = 50
|
||||
maxHealth = 50
|
||||
damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
@@ -29,14 +29,10 @@
|
||||
model = "MULE"
|
||||
bot_core_type = /obj/machinery/bot_core/mulebot
|
||||
|
||||
var/ui_x = 350
|
||||
var/ui_y = 425
|
||||
|
||||
var/id
|
||||
|
||||
path_image_color = "#7F5200"
|
||||
|
||||
var/base_icon = "mulebot"
|
||||
var/atom/movable/load = null
|
||||
var/mob/living/passenger = null
|
||||
var/turf/target // this is turf to navigate to (location of beacon)
|
||||
@@ -78,16 +74,16 @@
|
||||
/mob/living/simple_animal/bot/mulebot/proc/set_id(new_id)
|
||||
id = new_id
|
||||
if(paicard)
|
||||
bot_name = "[initial(name)] ([new_id])"
|
||||
bot_name = "\improper MULEbot ([new_id])"
|
||||
else
|
||||
name = "[initial(name)] ([new_id])"
|
||||
name = "\improper MULEbot ([new_id])"
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/bot_reset()
|
||||
..()
|
||||
reached_target = 0
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/attackby(obj/item/I, mob/user, params)
|
||||
if(I.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
..()
|
||||
if(open)
|
||||
on = FALSE
|
||||
@@ -95,13 +91,13 @@
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
cell = I
|
||||
visible_message("<span class='notice'>[user] inserts a cell into [src].</span>",
|
||||
visible_message("[user] inserts a cell into [src].",
|
||||
"<span class='notice'>You insert the new cell into [src].</span>")
|
||||
else if(I.tool_behaviour == TOOL_CROWBAR && open && cell)
|
||||
else if(istype(I, /obj/item/crowbar) && open && cell)
|
||||
cell.add_fingerprint(usr)
|
||||
cell.forceMove(loc)
|
||||
cell = null
|
||||
visible_message("<span class='notice'>[user] crowbars out the power cell from [src].</span>",
|
||||
visible_message("[user] crowbars out the power cell from [src].",
|
||||
"<span class='notice'>You pry the powercell out of [src].</span>")
|
||||
else if(is_wire_tool(I) && open)
|
||||
return attack_hand(user)
|
||||
@@ -125,13 +121,13 @@
|
||||
locked = !locked
|
||||
to_chat(user, "<span class='notice'>You [locked ? "lock" : "unlock"] [src]'s controls!</span>")
|
||||
flick("mulebot-emagged", src)
|
||||
playsound(src, "sparks", 100, FALSE)
|
||||
playsound(src, "sparks", 100, 0)
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/update_icon()
|
||||
if(open)
|
||||
icon_state="[base_icon]-hatch"
|
||||
icon_state="mulebot-hatch"
|
||||
else
|
||||
icon_state = "[base_icon][wires.is_cut(WIRE_AVOIDANCE)]"
|
||||
icon_state = "mulebot[wires.is_cut(WIRE_AVOIDANCE)]"
|
||||
cut_overlays()
|
||||
if(load && !ismob(load))//buckling handles the mob offsets
|
||||
load.pixel_y = initial(load.pixel_y) + 9
|
||||
@@ -153,8 +149,7 @@
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/bullet_act(obj/item/projectile/Proj)
|
||||
. = ..()
|
||||
if(. && !QDELETED(src)) //Got hit and not blown up yet.
|
||||
if(..())
|
||||
if(prob(50) && !isnull(load))
|
||||
unload(0)
|
||||
if(prob(25))
|
||||
@@ -173,7 +168,7 @@
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "mulebot", name, ui_x, ui_y, master_ui, state)
|
||||
ui = new(user, src, ui_key, "mulebot", name, 600, 375, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/ui_data(mob/user)
|
||||
@@ -193,15 +188,12 @@
|
||||
else
|
||||
data["load"] = load ? load.name : null
|
||||
data["destination"] = destination ? destination : null
|
||||
data["home"] = home_destination
|
||||
data["destinations"] = GLOB.deliverybeacontags
|
||||
data["cell"] = cell ? TRUE : FALSE
|
||||
data["cellPercent"] = cell ? cell.percent() : null
|
||||
data["autoReturn"] = auto_return
|
||||
data["autoPickup"] = auto_pickup
|
||||
data["reportDelivery"] = report_delivery
|
||||
data["haspai"] = paicard ? TRUE : FALSE
|
||||
data["id"] = id
|
||||
return data
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/ui_act(action, params)
|
||||
@@ -221,10 +213,10 @@
|
||||
return
|
||||
. = TRUE
|
||||
else
|
||||
bot_control(action, usr, params) // Kill this later.
|
||||
bot_control(action, usr) // Kill this later.
|
||||
. = TRUE
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/bot_control(command, mob/user, list/params = list(), pda = FALSE)
|
||||
/mob/living/simple_animal/bot/mulebot/bot_control(command, mob/user, pda = 0)
|
||||
if(pda && wires.is_cut(WIRE_RX)) // MULE wireless is controlled by wires.
|
||||
return
|
||||
|
||||
@@ -239,27 +231,15 @@
|
||||
if(mode == BOT_IDLE || mode == BOT_DELIVER)
|
||||
start_home()
|
||||
if("destination")
|
||||
var/new_dest
|
||||
if(pda)
|
||||
new_dest = input(user, "Enter Destination:", name, destination) as null|anything in GLOB.deliverybeacontags
|
||||
else
|
||||
new_dest = params["value"]
|
||||
var/new_dest = input(user, "Enter Destination:", name, destination) as null|anything in GLOB.deliverybeacontags
|
||||
if(new_dest)
|
||||
set_destination(new_dest)
|
||||
if("setid")
|
||||
var/new_id
|
||||
if(pda)
|
||||
new_id = stripped_input(user, "Enter ID:", name, id, MAX_NAME_LEN)
|
||||
else
|
||||
new_id = params["value"]
|
||||
var/new_id = stripped_input(user, "Enter ID:", name, id, MAX_NAME_LEN)
|
||||
if(new_id)
|
||||
set_id(new_id)
|
||||
if("sethome")
|
||||
var/new_home
|
||||
if(pda)
|
||||
new_home = input(user, "Enter Home:", name, home_destination) as null|anything in GLOB.deliverybeacontags
|
||||
else
|
||||
new_home = params["value"]
|
||||
var/new_home = input(user, "Enter Home:", name, home_destination) as null|anything in GLOB.deliverybeacontags
|
||||
if(new_home)
|
||||
home_destination = new_home
|
||||
if("unload")
|
||||
@@ -334,28 +314,26 @@
|
||||
/mob/living/simple_animal/bot/mulebot/proc/buzz(type)
|
||||
switch(type)
|
||||
if(SIGH)
|
||||
audible_message("<span class='hear'>[src] makes a sighing buzz.</span>")
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
|
||||
audible_message("[src] makes a sighing buzz.", "<span class='italics'>You hear an electronic buzzing sound.</span>")
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
if(ANNOYED)
|
||||
audible_message("<span class='hear'>[src] makes an annoyed buzzing sound.</span>")
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, FALSE)
|
||||
audible_message("[src] makes an annoyed buzzing sound.", "<span class='italics'>You hear an electronic buzzing sound.</span>")
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
if(DELIGHT)
|
||||
audible_message("<span class='hear'>[src] makes a delighted ping!</span>")
|
||||
playsound(loc, 'sound/machines/ping.ogg', 50, FALSE)
|
||||
audible_message("[src] makes a delighted ping!", "<span class='italics'>You hear a ping.</span>")
|
||||
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
|
||||
|
||||
// mousedrop a crate to load the bot
|
||||
// can load anything if hacked
|
||||
/mob/living/simple_animal/bot/mulebot/MouseDrop_T(atom/movable/AM, mob/user)
|
||||
|
||||
if(user.incapacitated() || user.lying)
|
||||
return
|
||||
|
||||
if(!istype(AM))
|
||||
return
|
||||
|
||||
if(!istype(AM) || isdead(AM) || iscameramob(AM) || istype(AM, /obj/effect/dummy/phased_mob))
|
||||
return
|
||||
|
||||
load(AM)
|
||||
|
||||
// called to load a crate
|
||||
@@ -468,8 +446,10 @@
|
||||
process_bot()
|
||||
num_steps--
|
||||
if(mode != BOT_IDLE)
|
||||
var/process_timer = addtimer(CALLBACK(src, .proc/process_bot), 2, TIMER_LOOP|TIMER_STOPPABLE)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/deltimer, process_timer), (num_steps*2) + 1)
|
||||
spawn(0)
|
||||
for(var/i=num_steps,i>0,i--)
|
||||
sleep(2)
|
||||
process_bot()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/proc/process_bot()
|
||||
if(!on || client)
|
||||
@@ -508,7 +488,6 @@
|
||||
B.setDir(newdir)
|
||||
bloodiness--
|
||||
|
||||
|
||||
var/oldloc = loc
|
||||
var/moved = step_towards(src, next) // attempt to move
|
||||
if(cell)
|
||||
@@ -534,7 +513,11 @@
|
||||
buzz(SIGH)
|
||||
mode = BOT_WAIT_FOR_NAV
|
||||
blockcount = 0
|
||||
addtimer(CALLBACK(src, .proc/process_blocked, next), 2 SECONDS)
|
||||
spawn(20)
|
||||
calc_path(avoid=next)
|
||||
if(path.len > 0)
|
||||
buzz(DELIGHT)
|
||||
mode = BOT_BLOCKED
|
||||
return
|
||||
return
|
||||
else
|
||||
@@ -547,26 +530,18 @@
|
||||
|
||||
if(BOT_NAV) // calculate new path
|
||||
mode = BOT_WAIT_FOR_NAV
|
||||
INVOKE_ASYNC(src, .proc/process_nav)
|
||||
spawn(0)
|
||||
calc_path()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/proc/process_blocked(turf/next)
|
||||
calc_path(avoid=next)
|
||||
if(path.len > 0)
|
||||
buzz(DELIGHT)
|
||||
mode = BOT_BLOCKED
|
||||
if(path.len > 0)
|
||||
blockcount = 0
|
||||
mode = BOT_BLOCKED
|
||||
buzz(DELIGHT)
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/proc/process_nav()
|
||||
calc_path()
|
||||
else
|
||||
buzz(SIGH)
|
||||
|
||||
if(path.len > 0)
|
||||
blockcount = 0
|
||||
mode = BOT_BLOCKED
|
||||
buzz(DELIGHT)
|
||||
|
||||
else
|
||||
buzz(SIGH)
|
||||
|
||||
mode = BOT_NO_ROUTE
|
||||
mode = BOT_NO_ROUTE
|
||||
|
||||
// calculates a path to the current destination
|
||||
// given an optional turf to avoid
|
||||
@@ -596,28 +571,26 @@
|
||||
/mob/living/simple_animal/bot/mulebot/proc/start_home()
|
||||
if(!on)
|
||||
return
|
||||
INVOKE_ASYNC(src, .proc/do_start_home)
|
||||
spawn(0)
|
||||
set_destination(home_destination)
|
||||
mode = BOT_BLOCKED
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/proc/do_start_home()
|
||||
set_destination(home_destination)
|
||||
mode = BOT_BLOCKED
|
||||
|
||||
// called when bot reaches current target
|
||||
/mob/living/simple_animal/bot/mulebot/proc/at_target()
|
||||
if(!reached_target)
|
||||
radio_channel = RADIO_CHANNEL_SUPPLY //Supply channel
|
||||
audible_message("<span class='hear'>[src] makes a chiming sound!</span>")
|
||||
playsound(loc, 'sound/machines/chime.ogg', 50, FALSE)
|
||||
radio_channel = "Supply" //Supply channel
|
||||
audible_message("[src] makes a chiming sound!", "<span class='italics'>You hear a chime.</span>")
|
||||
playsound(loc, 'sound/machines/chime.ogg', 50, 0)
|
||||
reached_target = 1
|
||||
|
||||
if(pathset) //The AI called us here, so notify it of our arrival.
|
||||
loaddir = dir //The MULE will attempt to load a crate in whatever direction the MULE is "facing".
|
||||
if(calling_ai)
|
||||
to_chat(calling_ai, "<span class='notice'>[icon2html(src, calling_ai)] [src] wirelessly plays a chiming sound!</span>")
|
||||
playsound(calling_ai, 'sound/machines/chime.ogg',40, FALSE)
|
||||
playsound(calling_ai, 'sound/machines/chime.ogg',40, 0)
|
||||
calling_ai = null
|
||||
radio_channel = RADIO_CHANNEL_AI_PRIVATE //Report on AI Private instead if the AI is controlling us.
|
||||
radio_channel = "AI Private" //Report on AI Private instead if the AI is controlling us.
|
||||
|
||||
if(load) // if loaded, unload at target
|
||||
if(report_delivery)
|
||||
@@ -669,7 +642,7 @@
|
||||
log_combat(src, H, "run over", null, "(DAMTYPE: [uppertext(BRUTE)])")
|
||||
H.visible_message("<span class='danger'>[src] drives over [H]!</span>", \
|
||||
"<span class='userdanger'>[src] drives over you!</span>")
|
||||
playsound(loc, 'sound/effects/splat.ogg', 50, TRUE)
|
||||
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
|
||||
var/damage = rand(5,15)
|
||||
H.apply_damage(2*damage, BRUTE, BODY_ZONE_HEAD, run_armor_check(BODY_ZONE_HEAD, "melee"))
|
||||
@@ -758,7 +731,7 @@
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/insertpai(mob/user, obj/item/paicard/card)
|
||||
if(..())
|
||||
visible_message("<span class='notice'>[src] safeties are locked on.</span>")
|
||||
visible_message("[src] safeties are locked on.")
|
||||
|
||||
#undef SIGH
|
||||
#undef ANNOYED
|
||||
@@ -766,4 +739,3 @@
|
||||
|
||||
/obj/machinery/bot_core/mulebot
|
||||
req_access = list(ACCESS_CARGO)
|
||||
|
||||
@@ -1,446 +1,446 @@
|
||||
/mob/living/simple_animal/bot/secbot
|
||||
name = "\improper Securitron"
|
||||
desc = "A little security robot. He looks less than thrilled."
|
||||
icon = 'icons/mob/aibots.dmi'
|
||||
icon_state = "secbot"
|
||||
density = FALSE
|
||||
anchored = FALSE
|
||||
health = 25
|
||||
maxHealth = 25
|
||||
damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
pass_flags = PASSMOB
|
||||
|
||||
radio_key = /obj/item/encryptionkey/secbot //AI Priv + Security
|
||||
radio_channel = RADIO_CHANNEL_SECURITY //Security channel
|
||||
bot_type = SEC_BOT
|
||||
model = "Securitron"
|
||||
bot_core_type = /obj/machinery/bot_core/secbot
|
||||
window_id = "autosec"
|
||||
window_name = "Automatic Security Unit v1.6"
|
||||
allow_pai = 0
|
||||
data_hud_type = DATA_HUD_SECURITY_ADVANCED
|
||||
path_image_color = "#FF0000"
|
||||
|
||||
var/baton_type = /obj/item/melee/baton
|
||||
var/mob/living/carbon/target
|
||||
var/oldtarget_name
|
||||
var/threatlevel = FALSE
|
||||
var/target_lastloc //Loc of target when arrested.
|
||||
var/last_found //There's a delay
|
||||
var/declare_arrests = TRUE //When making an arrest, should it notify everyone on the security channel?
|
||||
var/idcheck = FALSE //If true, arrest people with no IDs
|
||||
var/weaponscheck = FALSE //If true, arrest people for weapons if they lack access
|
||||
var/check_records = TRUE //Does it check security records?
|
||||
var/arrest_type = FALSE //If true, don't handcuff
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/beepsky
|
||||
name = "Officer Beep O'sky"
|
||||
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
|
||||
idcheck = FALSE
|
||||
weaponscheck = FALSE
|
||||
auto_patrol = TRUE
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/beepsky/jr
|
||||
name = "Officer Pipsqueak"
|
||||
desc = "It's Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/beepsky/jr/Initialize()
|
||||
. = ..()
|
||||
resize = 0.8
|
||||
update_transform()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/beepsky/explode()
|
||||
var/atom/Tsec = drop_location()
|
||||
new /obj/item/stock_parts/cell/potato(Tsec)
|
||||
var/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/S = new(Tsec)
|
||||
S.reagents.add_reagent(/datum/reagent/consumable/ethanol/whiskey, 15)
|
||||
S.on_reagent_change(ADD_REAGENT)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/pingsky
|
||||
name = "Officer Pingsky"
|
||||
desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
|
||||
radio_channel = RADIO_CHANNEL_AI_PRIVATE
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/Initialize()
|
||||
. = ..()
|
||||
update_icon()
|
||||
var/datum/job/detective/J = new/datum/job/detective
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
//SECHUD
|
||||
var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
|
||||
secsensor.add_hud_to(src)
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/update_icon()
|
||||
if(mode == BOT_HUNT)
|
||||
icon_state = "[initial(icon_state)]-c"
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/turn_off()
|
||||
..()
|
||||
mode = BOT_IDLE
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/bot_reset()
|
||||
..()
|
||||
target = null
|
||||
oldtarget_name = null
|
||||
anchored = FALSE
|
||||
walk_to(src,0)
|
||||
last_found = world.time
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/set_custom_texts()
|
||||
|
||||
text_hack = "You overload [name]'s target identification system."
|
||||
text_dehack = "You reboot [name] and restore the target identification."
|
||||
text_dehack_fail = "[name] refuses to accept your authority!"
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/get_controls(mob/user)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += showpai(user)
|
||||
dat += text({"
|
||||
<TT><B>Securitron v1.6 controls</B></TT><BR><BR>
|
||||
Status: []<BR>
|
||||
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel panel is [open ? "opened" : "closed"]"},
|
||||
|
||||
"<A href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</A>" )
|
||||
|
||||
if(!locked || issilicon(user) || IsAdminGhost(user))
|
||||
dat += text({"<BR>
|
||||
Arrest Unidentifiable Persons: []<BR>
|
||||
Arrest for Unauthorized Weapons: []<BR>
|
||||
Arrest for Warrant: []<BR>
|
||||
Operating Mode: []<BR>
|
||||
Report Arrests[]<BR>
|
||||
Auto Patrol: []"},
|
||||
|
||||
"<A href='?src=[REF(src)];operation=idcheck'>[idcheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=[REF(src)];operation=weaponscheck'>[weaponscheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=[REF(src)];operation=ignorerec'>[check_records ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=[REF(src)];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A>",
|
||||
"<A href='?src=[REF(src)];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=[REF(src)];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>" )
|
||||
|
||||
return dat
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked))
|
||||
return TRUE
|
||||
|
||||
switch(href_list["operation"])
|
||||
if("idcheck")
|
||||
idcheck = !idcheck
|
||||
update_controls()
|
||||
if("weaponscheck")
|
||||
weaponscheck = !weaponscheck
|
||||
update_controls()
|
||||
if("ignorerec")
|
||||
check_records = !check_records
|
||||
update_controls()
|
||||
if("switchmode")
|
||||
arrest_type = !arrest_type
|
||||
update_controls()
|
||||
if("declarearrests")
|
||||
declare_arrests = !declare_arrests
|
||||
update_controls()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H)
|
||||
var/judgement_criteria = judgement_criteria()
|
||||
threatlevel = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
|
||||
threatlevel += 6
|
||||
if(threatlevel >= 4)
|
||||
target = H
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/judgement_criteria()
|
||||
var/final = FALSE
|
||||
if(idcheck)
|
||||
final = final|JUDGE_IDCHECK
|
||||
if(check_records)
|
||||
final = final|JUDGE_RECORDCHECK
|
||||
if(weaponscheck)
|
||||
final = final|JUDGE_WEAPONCHECK
|
||||
if(emagged == 2)
|
||||
final = final|JUDGE_EMAGGED
|
||||
return final
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
|
||||
if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
|
||||
retaliate(H)
|
||||
if(special_retaliate_after_attack(H))
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/attackby(obj/item/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
|
||||
return
|
||||
if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
|
||||
retaliate(user)
|
||||
if(special_retaliate_after_attack(user))
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
|
||||
..()
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
to_chat(user, "<span class='danger'>You short out [src]'s target assessment circuits.</span>")
|
||||
oldtarget_name = user.name
|
||||
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
declare_arrests = FALSE
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
|
||||
if(istype(Proj , /obj/item/projectile/beam)||istype(Proj, /obj/item/projectile/bullet))
|
||||
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
|
||||
if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer))
|
||||
retaliate(Proj.firer)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
|
||||
if(!on)
|
||||
return
|
||||
if(iscarbon(A))
|
||||
var/mob/living/carbon/C = A
|
||||
if(C.canmove || arrest_type) // CIT CHANGE - makes sentient secbots check for canmove rather than !isstun.
|
||||
stun_attack(A)
|
||||
else if(C.canBeHandcuffed() && !C.handcuffed)
|
||||
cuff(A)
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/I = AM
|
||||
if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
|
||||
var/mob/living/carbon/human/H = I.thrownby
|
||||
retaliate(H)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
|
||||
mode = BOT_ARREST
|
||||
playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
|
||||
C.visible_message("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
|
||||
addtimer(CALLBACK(src, .proc/attempt_handcuff, C), 60)
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/attempt_handcuff(mob/living/carbon/C)
|
||||
if( !on || !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
return
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C)
|
||||
C.update_handcuffed()
|
||||
playsound(src, "law", 50, 0)
|
||||
back_to_idle()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
|
||||
var/judgement_criteria = judgement_criteria()
|
||||
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
|
||||
icon_state = "secbot-c"
|
||||
addtimer(CALLBACK(src, .proc/update_icon), 2)
|
||||
var/threat = 5
|
||||
if(ishuman(C))
|
||||
C.stuttering = 5
|
||||
C.Knockdown(100)
|
||||
var/mob/living/carbon/human/H = C
|
||||
threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
|
||||
else
|
||||
C.Knockdown(100)
|
||||
C.stuttering = 5
|
||||
threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
|
||||
|
||||
log_combat(src,C,"stunned")
|
||||
if(declare_arrests)
|
||||
var/area/location = get_area(src)
|
||||
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
|
||||
C.visible_message("<span class='danger'>[src] has stunned [C]!</span>",\
|
||||
"<span class='userdanger'>[src] has stunned you!</span>")
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/handle_automated_action()
|
||||
if(!..())
|
||||
return
|
||||
|
||||
switch(mode)
|
||||
|
||||
if(BOT_IDLE) // idle
|
||||
|
||||
walk_to(src,0)
|
||||
look_for_perp() // see if any criminals are in range
|
||||
if(!mode && auto_patrol) // still idle, and set to patrol
|
||||
mode = BOT_START_PATROL // switch to patrol mode
|
||||
|
||||
if(BOT_HUNT) // hunting for perp
|
||||
|
||||
// if can't reach perp for long enough, go idle
|
||||
if(frustration >= 8)
|
||||
walk_to(src,0)
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(target) // make sure target exists
|
||||
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
|
||||
stun_attack(target)
|
||||
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = TRUE
|
||||
target_lastloc = target.loc
|
||||
return
|
||||
|
||||
else // not next to perp
|
||||
var/turf/olddist = get_dist(src, target)
|
||||
walk_to(src, target,1,4)
|
||||
if((get_dist(src, target)) >= (olddist))
|
||||
frustration++
|
||||
else
|
||||
frustration = 0
|
||||
else
|
||||
back_to_idle()
|
||||
|
||||
if(BOT_PREP_ARREST) // preparing to arrest target
|
||||
|
||||
// see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
|
||||
if( !Adjacent(target) || !isturf(target.loc) || target.getStaminaLoss() <= 120 || !target.recoveringstam) //CIT CHANGE - replaces amountknockdown with checks for stamina so secbots dont run into an infinite loop
|
||||
back_to_hunt()
|
||||
return
|
||||
|
||||
if(iscarbon(target) && target.canBeHandcuffed())
|
||||
if(!arrest_type)
|
||||
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
|
||||
cuff(target)
|
||||
else
|
||||
back_to_idle()
|
||||
return
|
||||
else
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(BOT_ARREST)
|
||||
if(!target)
|
||||
anchored = FALSE
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
return
|
||||
|
||||
if(target.handcuffed) //no target or target cuffed? back to idle.
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && !target.recoveringstam && target.getStaminaLoss() <= 120)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again. CIT CHANGE - replaces amountknockdown with recoveringstam and staminaloss check
|
||||
back_to_hunt()
|
||||
return
|
||||
else //Try arresting again if the target escapes.
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = FALSE
|
||||
|
||||
if(BOT_START_PATROL)
|
||||
look_for_perp()
|
||||
start_patrol()
|
||||
|
||||
if(BOT_PATROL)
|
||||
look_for_perp()
|
||||
bot_patrol()
|
||||
|
||||
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
|
||||
anchored = FALSE
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
INVOKE_ASYNC(src, .proc/handle_automated_action)
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
|
||||
anchored = FALSE
|
||||
frustration = 0
|
||||
mode = BOT_HUNT
|
||||
INVOKE_ASYNC(src, .proc/handle_automated_action)
|
||||
// look for a criminal in view of the bot
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
|
||||
anchored = FALSE
|
||||
var/judgement_criteria = judgement_criteria()
|
||||
for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
|
||||
if((C.stat) || (C.handcuffed))
|
||||
continue
|
||||
|
||||
if((C.name == oldtarget_name) && (world.time < last_found + 100))
|
||||
continue
|
||||
|
||||
threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
|
||||
|
||||
if(!threatlevel)
|
||||
continue
|
||||
|
||||
else if(threatlevel >= 4)
|
||||
target = C
|
||||
oldtarget_name = C.name
|
||||
speak("Level [threatlevel] infraction alert!")
|
||||
playsound(loc, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
|
||||
visible_message("<b>[src]</b> points at [C.name]!")
|
||||
mode = BOT_HUNT
|
||||
INVOKE_ASYNC(src, .proc/handle_automated_action)
|
||||
break
|
||||
else
|
||||
continue
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
|
||||
if(slot_item && (slot_item.item_flags & NEEDS_PERMIT))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/explode()
|
||||
|
||||
walk_to(src,0)
|
||||
visible_message("<span class='boldannounce'>[src] blows apart!</span>")
|
||||
var/atom/Tsec = drop_location()
|
||||
|
||||
var/obj/item/bot_assembly/secbot/Sa = new (Tsec)
|
||||
Sa.build_step = 1
|
||||
Sa.add_overlay("hs_hole")
|
||||
Sa.created_name = name
|
||||
new /obj/item/assembly/prox_sensor(Tsec)
|
||||
drop_part(baton_type, Tsec)
|
||||
|
||||
if(prob(50))
|
||||
drop_part(robot_arm, Tsec)
|
||||
|
||||
do_sparks(3, TRUE, src)
|
||||
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
|
||||
..()
|
||||
if(!isalien(target))
|
||||
target = user
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
|
||||
if(has_gravity() && ismob(AM) && target)
|
||||
var/mob/living/carbon/C = AM
|
||||
if(!istype(C) || !C || in_range(src, target))
|
||||
return
|
||||
knockOver(C)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/machinery/bot_core/secbot
|
||||
req_access = list(ACCESS_SECURITY)
|
||||
/mob/living/simple_animal/bot/secbot
|
||||
name = "\improper Securitron"
|
||||
desc = "A little security robot. He looks less than thrilled."
|
||||
icon = 'icons/mob/aibots.dmi'
|
||||
icon_state = "secbot"
|
||||
density = FALSE
|
||||
anchored = FALSE
|
||||
health = 25
|
||||
maxHealth = 25
|
||||
damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
pass_flags = PASSMOB
|
||||
|
||||
radio_key = /obj/item/encryptionkey/secbot //AI Priv + Security
|
||||
radio_channel = RADIO_CHANNEL_SECURITY //Security channel
|
||||
bot_type = SEC_BOT
|
||||
model = "Securitron"
|
||||
bot_core_type = /obj/machinery/bot_core/secbot
|
||||
window_id = "autosec"
|
||||
window_name = "Automatic Security Unit v1.6"
|
||||
allow_pai = 0
|
||||
data_hud_type = DATA_HUD_SECURITY_ADVANCED
|
||||
path_image_color = "#FF0000"
|
||||
|
||||
var/baton_type = /obj/item/melee/baton
|
||||
var/mob/living/carbon/target
|
||||
var/oldtarget_name
|
||||
var/threatlevel = FALSE
|
||||
var/target_lastloc //Loc of target when arrested.
|
||||
var/last_found //There's a delay
|
||||
var/declare_arrests = TRUE //When making an arrest, should it notify everyone on the security channel?
|
||||
var/idcheck = FALSE //If true, arrest people with no IDs
|
||||
var/weaponscheck = FALSE //If true, arrest people for weapons if they lack access
|
||||
var/check_records = TRUE //Does it check security records?
|
||||
var/arrest_type = FALSE //If true, don't handcuff
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/beepsky
|
||||
name = "Officer Beep O'sky"
|
||||
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
|
||||
idcheck = FALSE
|
||||
weaponscheck = FALSE
|
||||
auto_patrol = TRUE
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/beepsky/jr
|
||||
name = "Officer Pipsqueak"
|
||||
desc = "It's Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/beepsky/jr/Initialize()
|
||||
. = ..()
|
||||
resize = 0.8
|
||||
update_transform()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/beepsky/explode()
|
||||
var/atom/Tsec = drop_location()
|
||||
new /obj/item/stock_parts/cell/potato(Tsec)
|
||||
var/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/S = new(Tsec)
|
||||
S.reagents.add_reagent("whiskey", 15)
|
||||
S.on_reagent_change(ADD_REAGENT)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/pingsky
|
||||
name = "Officer Pingsky"
|
||||
desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
|
||||
radio_channel = RADIO_CHANNEL_AI_PRIVATE
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/Initialize()
|
||||
. = ..()
|
||||
update_icon()
|
||||
var/datum/job/detective/J = new/datum/job/detective
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
//SECHUD
|
||||
var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
|
||||
secsensor.add_hud_to(src)
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/update_icon()
|
||||
if(mode == BOT_HUNT)
|
||||
icon_state = "[initial(icon_state)]-c"
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/turn_off()
|
||||
..()
|
||||
mode = BOT_IDLE
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/bot_reset()
|
||||
..()
|
||||
target = null
|
||||
oldtarget_name = null
|
||||
anchored = FALSE
|
||||
walk_to(src,0)
|
||||
last_found = world.time
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/set_custom_texts()
|
||||
|
||||
text_hack = "You overload [name]'s target identification system."
|
||||
text_dehack = "You reboot [name] and restore the target identification."
|
||||
text_dehack_fail = "[name] refuses to accept your authority!"
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/get_controls(mob/user)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += showpai(user)
|
||||
dat += text({"
|
||||
<TT><B>Securitron v1.6 controls</B></TT><BR><BR>
|
||||
Status: []<BR>
|
||||
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel panel is [open ? "opened" : "closed"]"},
|
||||
|
||||
"<A href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</A>" )
|
||||
|
||||
if(!locked || issilicon(user) || IsAdminGhost(user))
|
||||
dat += text({"<BR>
|
||||
Arrest Unidentifiable Persons: []<BR>
|
||||
Arrest for Unauthorized Weapons: []<BR>
|
||||
Arrest for Warrant: []<BR>
|
||||
Operating Mode: []<BR>
|
||||
Report Arrests[]<BR>
|
||||
Auto Patrol: []"},
|
||||
|
||||
"<A href='?src=[REF(src)];operation=idcheck'>[idcheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=[REF(src)];operation=weaponscheck'>[weaponscheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=[REF(src)];operation=ignorerec'>[check_records ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=[REF(src)];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A>",
|
||||
"<A href='?src=[REF(src)];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=[REF(src)];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>" )
|
||||
|
||||
return dat
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked))
|
||||
return TRUE
|
||||
|
||||
switch(href_list["operation"])
|
||||
if("idcheck")
|
||||
idcheck = !idcheck
|
||||
update_controls()
|
||||
if("weaponscheck")
|
||||
weaponscheck = !weaponscheck
|
||||
update_controls()
|
||||
if("ignorerec")
|
||||
check_records = !check_records
|
||||
update_controls()
|
||||
if("switchmode")
|
||||
arrest_type = !arrest_type
|
||||
update_controls()
|
||||
if("declarearrests")
|
||||
declare_arrests = !declare_arrests
|
||||
update_controls()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H)
|
||||
var/judgement_criteria = judgement_criteria()
|
||||
threatlevel = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
|
||||
threatlevel += 6
|
||||
if(threatlevel >= 4)
|
||||
target = H
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/judgement_criteria()
|
||||
var/final = FALSE
|
||||
if(idcheck)
|
||||
final = final|JUDGE_IDCHECK
|
||||
if(check_records)
|
||||
final = final|JUDGE_RECORDCHECK
|
||||
if(weaponscheck)
|
||||
final = final|JUDGE_WEAPONCHECK
|
||||
if(emagged == 2)
|
||||
final = final|JUDGE_EMAGGED
|
||||
return final
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
|
||||
if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
|
||||
retaliate(H)
|
||||
if(special_retaliate_after_attack(H))
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/attackby(obj/item/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
|
||||
return
|
||||
if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
|
||||
retaliate(user)
|
||||
if(special_retaliate_after_attack(user))
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
|
||||
..()
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
to_chat(user, "<span class='danger'>You short out [src]'s target assessment circuits.</span>")
|
||||
oldtarget_name = user.name
|
||||
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
declare_arrests = FALSE
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
|
||||
if(istype(Proj , /obj/item/projectile/beam)||istype(Proj, /obj/item/projectile/bullet))
|
||||
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
|
||||
if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer))
|
||||
retaliate(Proj.firer)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
|
||||
if(!on)
|
||||
return
|
||||
if(iscarbon(A))
|
||||
var/mob/living/carbon/C = A
|
||||
if(C.canmove || arrest_type) // CIT CHANGE - makes sentient secbots check for canmove rather than !isstun.
|
||||
stun_attack(A)
|
||||
else if(C.canBeHandcuffed() && !C.handcuffed)
|
||||
cuff(A)
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/I = AM
|
||||
if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
|
||||
var/mob/living/carbon/human/H = I.thrownby
|
||||
retaliate(H)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
|
||||
mode = BOT_ARREST
|
||||
playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
|
||||
C.visible_message("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
|
||||
addtimer(CALLBACK(src, .proc/attempt_handcuff, C), 60)
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/attempt_handcuff(mob/living/carbon/C)
|
||||
if( !on || !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
return
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C)
|
||||
C.update_handcuffed()
|
||||
playsound(src, "law", 50, 0)
|
||||
back_to_idle()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
|
||||
var/judgement_criteria = judgement_criteria()
|
||||
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
|
||||
icon_state = "secbot-c"
|
||||
addtimer(CALLBACK(src, .proc/update_icon), 2)
|
||||
var/threat = 5
|
||||
if(ishuman(C))
|
||||
C.stuttering = 5
|
||||
C.Knockdown(100)
|
||||
var/mob/living/carbon/human/H = C
|
||||
threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
|
||||
else
|
||||
C.Knockdown(100)
|
||||
C.stuttering = 5
|
||||
threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
|
||||
|
||||
log_combat(src,C,"stunned")
|
||||
if(declare_arrests)
|
||||
var/area/location = get_area(src)
|
||||
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
|
||||
C.visible_message("<span class='danger'>[src] has stunned [C]!</span>",\
|
||||
"<span class='userdanger'>[src] has stunned you!</span>")
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/handle_automated_action()
|
||||
if(!..())
|
||||
return
|
||||
|
||||
switch(mode)
|
||||
|
||||
if(BOT_IDLE) // idle
|
||||
|
||||
walk_to(src,0)
|
||||
look_for_perp() // see if any criminals are in range
|
||||
if(!mode && auto_patrol) // still idle, and set to patrol
|
||||
mode = BOT_START_PATROL // switch to patrol mode
|
||||
|
||||
if(BOT_HUNT) // hunting for perp
|
||||
|
||||
// if can't reach perp for long enough, go idle
|
||||
if(frustration >= 8)
|
||||
walk_to(src,0)
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(target) // make sure target exists
|
||||
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
|
||||
stun_attack(target)
|
||||
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = TRUE
|
||||
target_lastloc = target.loc
|
||||
return
|
||||
|
||||
else // not next to perp
|
||||
var/turf/olddist = get_dist(src, target)
|
||||
walk_to(src, target,1,4)
|
||||
if((get_dist(src, target)) >= (olddist))
|
||||
frustration++
|
||||
else
|
||||
frustration = 0
|
||||
else
|
||||
back_to_idle()
|
||||
|
||||
if(BOT_PREP_ARREST) // preparing to arrest target
|
||||
|
||||
// see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
|
||||
if( !Adjacent(target) || !isturf(target.loc) || target.getStaminaLoss() <= 120 || !target.recoveringstam) //CIT CHANGE - replaces amountknockdown with checks for stamina so secbots dont run into an infinite loop
|
||||
back_to_hunt()
|
||||
return
|
||||
|
||||
if(iscarbon(target) && target.canBeHandcuffed())
|
||||
if(!arrest_type)
|
||||
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
|
||||
cuff(target)
|
||||
else
|
||||
back_to_idle()
|
||||
return
|
||||
else
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(BOT_ARREST)
|
||||
if(!target)
|
||||
anchored = FALSE
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
return
|
||||
|
||||
if(target.handcuffed) //no target or target cuffed? back to idle.
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && !target.recoveringstam && target.getStaminaLoss() <= 120)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again. CIT CHANGE - replaces amountknockdown with recoveringstam and staminaloss check
|
||||
back_to_hunt()
|
||||
return
|
||||
else //Try arresting again if the target escapes.
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = FALSE
|
||||
|
||||
if(BOT_START_PATROL)
|
||||
look_for_perp()
|
||||
start_patrol()
|
||||
|
||||
if(BOT_PATROL)
|
||||
look_for_perp()
|
||||
bot_patrol()
|
||||
|
||||
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
|
||||
anchored = FALSE
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
INVOKE_ASYNC(src, .proc/handle_automated_action)
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
|
||||
anchored = FALSE
|
||||
frustration = 0
|
||||
mode = BOT_HUNT
|
||||
INVOKE_ASYNC(src, .proc/handle_automated_action)
|
||||
// look for a criminal in view of the bot
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
|
||||
anchored = FALSE
|
||||
var/judgement_criteria = judgement_criteria()
|
||||
for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
|
||||
if((C.stat) || (C.handcuffed))
|
||||
continue
|
||||
|
||||
if((C.name == oldtarget_name) && (world.time < last_found + 100))
|
||||
continue
|
||||
|
||||
threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
|
||||
|
||||
if(!threatlevel)
|
||||
continue
|
||||
|
||||
else if(threatlevel >= 4)
|
||||
target = C
|
||||
oldtarget_name = C.name
|
||||
speak("Level [threatlevel] infraction alert!")
|
||||
playsound(loc, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
|
||||
visible_message("<b>[src]</b> points at [C.name]!")
|
||||
mode = BOT_HUNT
|
||||
INVOKE_ASYNC(src, .proc/handle_automated_action)
|
||||
break
|
||||
else
|
||||
continue
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
|
||||
if(slot_item && (slot_item.item_flags & NEEDS_PERMIT))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/explode()
|
||||
|
||||
walk_to(src,0)
|
||||
visible_message("<span class='boldannounce'>[src] blows apart!</span>")
|
||||
var/atom/Tsec = drop_location()
|
||||
|
||||
var/obj/item/bot_assembly/secbot/Sa = new (Tsec)
|
||||
Sa.build_step = 1
|
||||
Sa.add_overlay("hs_hole")
|
||||
Sa.created_name = name
|
||||
new /obj/item/assembly/prox_sensor(Tsec)
|
||||
drop_part(baton_type, Tsec)
|
||||
|
||||
if(prob(50))
|
||||
drop_part(robot_arm, Tsec)
|
||||
|
||||
do_sparks(3, TRUE, src)
|
||||
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
|
||||
..()
|
||||
if(!isalien(target))
|
||||
target = user
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
|
||||
if(has_gravity() && ismob(AM) && target)
|
||||
var/mob/living/carbon/C = AM
|
||||
if(!istype(C) || !C || in_range(src, target))
|
||||
return
|
||||
knockOver(C)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/machinery/bot_core/secbot
|
||||
req_access = list(ACCESS_SECURITY)
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
initial_language_holder = /datum/language_holder/construct
|
||||
deathmessage = "collapses in a shattered heap."
|
||||
hud_type = /datum/hud/constructs
|
||||
blood_volume = 0
|
||||
var/list/construct_spells = list()
|
||||
var/playstyle_string = "<span class='big bold'>You are a generic construct!</span><b> Your job is to not exist, and you should probably adminhelp this.</b>"
|
||||
var/master = null
|
||||
|
||||
@@ -1,320 +1,319 @@
|
||||
//Cat
|
||||
/mob/living/simple_animal/pet/cat
|
||||
name = "cat"
|
||||
desc = "Kitty!!"
|
||||
icon = 'icons/mob/pets.dmi'
|
||||
icon_state = "cat2"
|
||||
icon_living = "cat2"
|
||||
icon_dead = "cat2_dead"
|
||||
gender = MALE
|
||||
speak = list("Meow!", "Esp!", "Purr!", "HSSSSS")
|
||||
speak_emote = list("purrs", "meows")
|
||||
emote_hear = list("meows.", "mews.")
|
||||
emote_see = list("shakes its head.", "shivers.")
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
see_in_dark = 6
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
pass_flags = PASSTABLE
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
minbodytemp = 200
|
||||
maxbodytemp = 400
|
||||
unsuitable_atmos_damage = 1
|
||||
animal_species = /mob/living/simple_animal/pet/cat
|
||||
childtype = list(/mob/living/simple_animal/pet/cat/kitten)
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2, /obj/item/organ/ears/cat = 1, /obj/item/organ/tail/cat = 1)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
var/turns_since_scan = 0
|
||||
var/mob/living/simple_animal/mouse/movement_target
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
collar_type = "cat"
|
||||
size_multiplier = 0.5
|
||||
|
||||
var/held_icon = "cat2"
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Initialize()
|
||||
. = ..()
|
||||
verbs += /mob/living/proc/lay_down
|
||||
|
||||
/mob/living/simple_animal/pet/cat/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/wuv, "purrs!", EMOTE_AUDIBLE, /datum/mood_event/pet_animal, "hisses!", EMOTE_AUDIBLE)
|
||||
AddElement(/datum/element/mob_holder, held_icon)
|
||||
|
||||
/mob/living/simple_animal/pet/cat/update_canmove()
|
||||
..()
|
||||
if(client && stat != DEAD)
|
||||
if (resting)
|
||||
icon_state = "[icon_living]_rest"
|
||||
collar_type = "[initial(collar_type)]_rest"
|
||||
else
|
||||
icon_state = "[icon_living]"
|
||||
collar_type = "[initial(collar_type)]"
|
||||
regenerate_icons()
|
||||
|
||||
|
||||
/mob/living/simple_animal/pet/cat/space
|
||||
name = "space cat"
|
||||
desc = "It's a cat... in space!"
|
||||
icon_state = "spacecat"
|
||||
icon_living = "spacecat"
|
||||
icon_dead = "spacecat_dead"
|
||||
held_icon = "spacecat"
|
||||
unsuitable_atmos_damage = 0
|
||||
minbodytemp = TCMB
|
||||
maxbodytemp = T0C + 40
|
||||
|
||||
/mob/living/simple_animal/pet/cat/original
|
||||
name = "Batsy"
|
||||
desc = "The product of alien DNA and bored geneticists."
|
||||
gender = FEMALE
|
||||
icon_state = "original"
|
||||
icon_living = "original"
|
||||
icon_dead = "original_dead"
|
||||
held_icon = "original"
|
||||
collar_type = null
|
||||
unique_pet = TRUE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/kitten
|
||||
name = "kitten"
|
||||
desc = "D'aaawwww."
|
||||
icon_state = "kitten"
|
||||
icon_living = "kitten"
|
||||
icon_dead = "kitten_dead"
|
||||
density = FALSE
|
||||
pass_flags = PASSMOB
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
collar_type = "kitten"
|
||||
held_icon = "cat"
|
||||
|
||||
//RUNTIME IS ALIVE! SQUEEEEEEEE~
|
||||
/mob/living/simple_animal/pet/cat/Runtime
|
||||
name = "Runtime"
|
||||
desc = "GCAT"
|
||||
icon_state = "cat"
|
||||
icon_living = "cat"
|
||||
icon_dead = "cat_dead"
|
||||
gender = FEMALE
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
unique_pet = TRUE
|
||||
var/list/family = list()//var restored from savefile, has count of each child type
|
||||
var/list/children = list()//Actual mob instances of children
|
||||
var/cats_deployed = 0
|
||||
//var/memory_saved = FALSE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Runtime/Initialize()
|
||||
if(prob(5))
|
||||
icon_state = "original"
|
||||
icon_living = "original"
|
||||
icon_dead = "original_dead"
|
||||
//Read_Memory()
|
||||
. = ..()
|
||||
/*
|
||||
/mob/living/simple_animal/pet/cat/Runtime/Life()
|
||||
if(!cats_deployed && SSticker.current_state >= GAME_STATE_SETTING_UP)
|
||||
Deploy_The_Cats()
|
||||
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
|
||||
Write_Memory()
|
||||
memory_saved = TRUE
|
||||
..()
|
||||
*/
|
||||
/mob/living/simple_animal/pet/cat/Runtime/make_babies()
|
||||
var/mob/baby = ..()
|
||||
if(baby)
|
||||
children += baby
|
||||
return baby
|
||||
/*
|
||||
/mob/living/simple_animal/pet/cat/Runtime/death()
|
||||
if(!memory_saved)
|
||||
Write_Memory(TRUE)
|
||||
..()
|
||||
*/
|
||||
/mob/living/simple_animal/pet/cat/Runtime/proc/Read_Memory()
|
||||
if(fexists("data/npc_saves/Runtime.sav")) //legacy compatability to convert old format to new
|
||||
var/savefile/S = new /savefile("data/npc_saves/Runtime.sav")
|
||||
S["family"] >> family
|
||||
fdel("data/npc_saves/Runtime.sav")
|
||||
else
|
||||
var/json_file = file("data/npc_saves/Runtime.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
family = json["family"]
|
||||
if(isnull(family))
|
||||
family = list()
|
||||
//All you people can't fucking control yourselves and keep letting runtime breed his own children, so it's time to at -LEAST- take the function that saves cats for the next round out the back and shoot it with a 12 gauge
|
||||
/*
|
||||
/mob/living/simple_animal/pet/cat/Runtime/proc/Write_Memory(dead)
|
||||
var/json_file = file("data/npc_saves/Runtime.json")
|
||||
var/list/file_data = list()
|
||||
family = list()
|
||||
if(!dead)
|
||||
for(var/mob/living/simple_animal/pet/cat/kitten/C in children)
|
||||
if(istype(C,type) || C.stat || !C.z || !C.butcher_results) //That last one is a work around for hologram cats
|
||||
continue
|
||||
if(C.type in family)
|
||||
family[C.type] += 1
|
||||
else
|
||||
family[C.type] = 1
|
||||
file_data["family"] = family
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Runtime/proc/Deploy_The_Cats()
|
||||
cats_deployed = 1
|
||||
for(var/cat_type in family)
|
||||
if(family[cat_type] > 0)
|
||||
for(var/i in 1 to min(family[cat_type],100)) //Limits to about 500 cats, you wouldn't think this would be needed (BUT IT IS)
|
||||
new cat_type(loc)
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Proc
|
||||
name = "Proc"
|
||||
gender = MALE
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
unique_pet = TRUE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Life()
|
||||
if(!stat && !buckled && !client)
|
||||
if(prob(1))
|
||||
emote("me", 1, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
|
||||
icon_state = "[icon_living]_rest"
|
||||
collar_type = "[initial(collar_type)]_rest"
|
||||
resting = 1
|
||||
update_canmove()
|
||||
else if (prob(1))
|
||||
emote("me", 1, pick("sits down.", "crouches on its hind legs.", "looks alert."))
|
||||
icon_state = "[icon_living]_sit"
|
||||
collar_type = "[initial(collar_type)]_sit"
|
||||
resting = 1
|
||||
update_canmove()
|
||||
else if (prob(1))
|
||||
if (resting)
|
||||
emote("me", 1, pick("gets up and meows.", "walks around.", "stops resting."))
|
||||
icon_state = "[icon_living]"
|
||||
collar_type = "[initial(collar_type)]"
|
||||
resting = 0
|
||||
update_canmove()
|
||||
else
|
||||
emote("me", 1, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
|
||||
|
||||
//MICE!
|
||||
if((src.loc) && isturf(src.loc))
|
||||
if(!stat && !resting && !buckled)
|
||||
for(var/mob/living/simple_animal/mouse/M in view(1,src))
|
||||
if(!M.stat && Adjacent(M))
|
||||
emote("me", 1, "splats \the [M]!")
|
||||
M.splat()
|
||||
movement_target = null
|
||||
stop_automated_movement = 0
|
||||
break
|
||||
for(var/obj/item/toy/cattoy/T in view(1,src))
|
||||
if (T.cooldown < (world.time - 400))
|
||||
emote("me", 1, "bats \the [T] around with its paw!")
|
||||
T.cooldown = world.time
|
||||
|
||||
..()
|
||||
|
||||
make_babies()
|
||||
|
||||
if(!stat && !resting && !buckled)
|
||||
turns_since_scan++
|
||||
if(turns_since_scan > 5)
|
||||
walk_to(src,0)
|
||||
turns_since_scan = 0
|
||||
if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) ))
|
||||
movement_target = null
|
||||
stop_automated_movement = 0
|
||||
if( !movement_target || !(movement_target.loc in oview(src, 3)) )
|
||||
movement_target = null
|
||||
stop_automated_movement = 0
|
||||
for(var/mob/living/simple_animal/mouse/snack in oview(src,3))
|
||||
if(isturf(snack.loc) && !snack.stat)
|
||||
movement_target = snack
|
||||
break
|
||||
if(movement_target)
|
||||
stop_automated_movement = 1
|
||||
walk_to(src,movement_target,0,3)
|
||||
|
||||
/mob/living/simple_animal/pet/cat/cak //I told you I'd do it, Remie
|
||||
name = "Keeki"
|
||||
desc = "It's a cat made out of cake."
|
||||
icon_state = "cak"
|
||||
icon_living = "cak"
|
||||
icon_dead = "cak_dead"
|
||||
health = 50
|
||||
maxHealth = 50
|
||||
gender = FEMALE
|
||||
harm_intent_damage = 10
|
||||
butcher_results = list(/obj/item/organ/brain = 1, /obj/item/organ/heart = 1, /obj/item/reagent_containers/food/snacks/cakeslice/birthday = 3, \
|
||||
/obj/item/reagent_containers/food/snacks/meat/slab = 2)
|
||||
response_harm = "takes a bite out of"
|
||||
attacked_sound = 'sound/items/eatfood.ogg'
|
||||
deathmessage = "loses its false life and collapses!"
|
||||
death_sound = "bodyfall"
|
||||
held_icon = "cak"
|
||||
|
||||
/mob/living/simple_animal/pet/cat/cak/CheckParts(list/parts)
|
||||
..()
|
||||
var/obj/item/organ/brain/B = locate(/obj/item/organ/brain) in contents
|
||||
if(!B || !B.brainmob || !B.brainmob.mind)
|
||||
return
|
||||
B.brainmob.mind.transfer_to(src)
|
||||
to_chat(src, "<span class='big bold'>You are a cak!</span><b> You're a harmless cat/cake hybrid that everyone loves. People can take bites out of you if they're hungry, but you regenerate health \
|
||||
so quickly that it generally doesn't matter. You're remarkably resilient to any damage besides this and it's hard for you to really die at all. You should go around and bring happiness and \
|
||||
free cake to the station!</b>")
|
||||
var/new_name = stripped_input(src, "Enter your name, or press \"Cancel\" to stick with Keeki.", "Name Change")
|
||||
if(new_name)
|
||||
to_chat(src, "<span class='notice'>Your name is now <b>\"new_name\"</b>!</span>")
|
||||
name = new_name
|
||||
|
||||
/mob/living/simple_animal/pet/cat/cak/Life()
|
||||
..()
|
||||
if(stat)
|
||||
return
|
||||
if(health < maxHealth)
|
||||
adjustBruteLoss(-8) //Fast life regen
|
||||
for(var/obj/item/reagent_containers/food/snacks/donut/D in range(1, src)) //Frosts nearby donuts!
|
||||
if(!D.is_decorated)
|
||||
D.decorate_donut()
|
||||
|
||||
/mob/living/simple_animal/pet/cat/cak/attack_hand(mob/living/L)
|
||||
. = ..()
|
||||
if(.) //the attack was blocked
|
||||
return
|
||||
if(L.a_intent == INTENT_HARM && L.reagents && !stat)
|
||||
L.reagents.add_reagent(/datum/reagent/consumable/nutriment, 0.4)
|
||||
L.reagents.add_reagent(/datum/reagent/consumable/nutriment/vitamin, 0.4)
|
||||
|
||||
//Cat made
|
||||
/mob/living/simple_animal/pet/cat/custom_cat
|
||||
name = "White cat" //Incase it somehow gets spawned without an ID
|
||||
desc = "A cute white catto!"
|
||||
icon_state = "custom_cat"
|
||||
icon_living = "custom_cat"
|
||||
icon_dead = "custom_cat_dead"
|
||||
gender = FEMALE
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
health = 50 //So people can't instakill it s
|
||||
maxHealth = 50
|
||||
speak = list("Meowrowr!", "Mew!", "Miauen!")
|
||||
speak_emote = list("wigglepurrs", "mewls")
|
||||
emote_hear = list("meows.", "mews.")
|
||||
emote_see = list("looks at you eagerly for pets!", "wiggles enthusiastically.")
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
var/pseudo_death = FALSE
|
||||
var/mob/living/carbon/human/origin
|
||||
|
||||
/mob/living/simple_animal/pet/cat/custom_cat/death()
|
||||
if (pseudo_death == TRUE) //secret cat chem
|
||||
icon_state = "custom_cat_dead"
|
||||
Stun(1000)
|
||||
canmove = 0
|
||||
friendly = "deads at"
|
||||
return
|
||||
else
|
||||
..()
|
||||
//Cat
|
||||
/mob/living/simple_animal/pet/cat
|
||||
name = "cat"
|
||||
desc = "Kitty!!"
|
||||
icon = 'icons/mob/pets.dmi'
|
||||
icon_state = "cat2"
|
||||
icon_living = "cat2"
|
||||
icon_dead = "cat2_dead"
|
||||
gender = MALE
|
||||
speak = list("Meow!", "Esp!", "Purr!", "HSSSSS")
|
||||
speak_emote = list("purrs", "meows")
|
||||
emote_hear = list("meows.", "mews.")
|
||||
emote_see = list("shakes its head.", "shivers.")
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
see_in_dark = 6
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
pass_flags = PASSTABLE
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
minbodytemp = 200
|
||||
maxbodytemp = 400
|
||||
unsuitable_atmos_damage = 1
|
||||
animal_species = /mob/living/simple_animal/pet/cat
|
||||
childtype = list(/mob/living/simple_animal/pet/cat/kitten)
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2, /obj/item/organ/ears/cat = 1, /obj/item/organ/tail/cat = 1)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
var/turns_since_scan = 0
|
||||
var/mob/living/simple_animal/mouse/movement_target
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
collar_type = "cat"
|
||||
size_multiplier = 0.5
|
||||
|
||||
var/held_icon = "cat2"
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Initialize()
|
||||
. = ..()
|
||||
verbs += /mob/living/proc/lay_down
|
||||
|
||||
/mob/living/simple_animal/pet/cat/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/wuv, "purrs!", EMOTE_AUDIBLE, /datum/mood_event/pet_animal, "hisses!", EMOTE_AUDIBLE)
|
||||
AddElement(/datum/element/mob_holder, held_icon)
|
||||
|
||||
/mob/living/simple_animal/pet/cat/update_canmove()
|
||||
..()
|
||||
if(client && stat != DEAD)
|
||||
if (resting)
|
||||
icon_state = "[icon_living]_rest"
|
||||
collar_type = "[initial(collar_type)]_rest"
|
||||
else
|
||||
icon_state = "[icon_living]"
|
||||
collar_type = "[initial(collar_type)]"
|
||||
regenerate_icons()
|
||||
|
||||
|
||||
/mob/living/simple_animal/pet/cat/space
|
||||
name = "space cat"
|
||||
desc = "It's a cat... in space!"
|
||||
icon_state = "spacecat"
|
||||
icon_living = "spacecat"
|
||||
icon_dead = "spacecat_dead"
|
||||
held_icon = "spacecat"
|
||||
unsuitable_atmos_damage = 0
|
||||
minbodytemp = TCMB
|
||||
maxbodytemp = T0C + 40
|
||||
|
||||
/mob/living/simple_animal/pet/cat/original
|
||||
name = "Batsy"
|
||||
desc = "The product of alien DNA and bored geneticists."
|
||||
gender = FEMALE
|
||||
icon_state = "original"
|
||||
icon_living = "original"
|
||||
icon_dead = "original_dead"
|
||||
held_icon = "original"
|
||||
collar_type = null
|
||||
unique_pet = TRUE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/kitten
|
||||
name = "kitten"
|
||||
desc = "D'aaawwww."
|
||||
icon_state = "kitten"
|
||||
icon_living = "kitten"
|
||||
icon_dead = "kitten_dead"
|
||||
density = FALSE
|
||||
pass_flags = PASSMOB
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
collar_type = "kitten"
|
||||
held_icon = "cat"
|
||||
|
||||
//RUNTIME IS ALIVE! SQUEEEEEEEE~
|
||||
/mob/living/simple_animal/pet/cat/Runtime
|
||||
name = "Runtime"
|
||||
desc = "GCAT"
|
||||
icon_state = "cat"
|
||||
icon_living = "cat"
|
||||
icon_dead = "cat_dead"
|
||||
gender = FEMALE
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
unique_pet = TRUE
|
||||
var/list/family = list()//var restored from savefile, has count of each child type
|
||||
var/list/children = list()//Actual mob instances of children
|
||||
var/cats_deployed = 0
|
||||
//var/memory_saved = FALSE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Runtime/Initialize()
|
||||
if(prob(5))
|
||||
icon_state = "original"
|
||||
icon_living = "original"
|
||||
icon_dead = "original_dead"
|
||||
//Read_Memory()
|
||||
. = ..()
|
||||
/*
|
||||
/mob/living/simple_animal/pet/cat/Runtime/Life()
|
||||
if(!cats_deployed && SSticker.current_state >= GAME_STATE_SETTING_UP)
|
||||
Deploy_The_Cats()
|
||||
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
|
||||
Write_Memory()
|
||||
memory_saved = TRUE
|
||||
..()
|
||||
*/
|
||||
/mob/living/simple_animal/pet/cat/Runtime/make_babies()
|
||||
var/mob/baby = ..()
|
||||
if(baby)
|
||||
children += baby
|
||||
return baby
|
||||
/*
|
||||
/mob/living/simple_animal/pet/cat/Runtime/death()
|
||||
if(!memory_saved)
|
||||
Write_Memory(TRUE)
|
||||
..()
|
||||
*/
|
||||
/mob/living/simple_animal/pet/cat/Runtime/proc/Read_Memory()
|
||||
if(fexists("data/npc_saves/Runtime.sav")) //legacy compatability to convert old format to new
|
||||
var/savefile/S = new /savefile("data/npc_saves/Runtime.sav")
|
||||
S["family"] >> family
|
||||
fdel("data/npc_saves/Runtime.sav")
|
||||
else
|
||||
var/json_file = file("data/npc_saves/Runtime.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
family = json["family"]
|
||||
if(isnull(family))
|
||||
family = list()
|
||||
//All you people can't fucking control yourselves and keep letting runtime breed his own children, so it's time to at -LEAST- take the function that saves cats for the next round out the back and shoot it with a 12 gauge
|
||||
/*
|
||||
/mob/living/simple_animal/pet/cat/Runtime/proc/Write_Memory(dead)
|
||||
var/json_file = file("data/npc_saves/Runtime.json")
|
||||
var/list/file_data = list()
|
||||
family = list()
|
||||
if(!dead)
|
||||
for(var/mob/living/simple_animal/pet/cat/kitten/C in children)
|
||||
if(istype(C,type) || C.stat || !C.z || !C.butcher_results) //That last one is a work around for hologram cats
|
||||
continue
|
||||
if(C.type in family)
|
||||
family[C.type] += 1
|
||||
else
|
||||
family[C.type] = 1
|
||||
file_data["family"] = family
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Runtime/proc/Deploy_The_Cats()
|
||||
cats_deployed = 1
|
||||
for(var/cat_type in family)
|
||||
if(family[cat_type] > 0)
|
||||
for(var/i in 1 to min(family[cat_type],100)) //Limits to about 500 cats, you wouldn't think this would be needed (BUT IT IS)
|
||||
new cat_type(loc)
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Proc
|
||||
name = "Proc"
|
||||
gender = MALE
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
unique_pet = TRUE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Life()
|
||||
if(!stat && !buckled && !client)
|
||||
if(prob(1))
|
||||
emote("me", 1, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
|
||||
icon_state = "[icon_living]_rest"
|
||||
collar_type = "[initial(collar_type)]_rest"
|
||||
resting = 1
|
||||
update_canmove()
|
||||
else if (prob(1))
|
||||
emote("me", 1, pick("sits down.", "crouches on its hind legs.", "looks alert."))
|
||||
icon_state = "[icon_living]_sit"
|
||||
collar_type = "[initial(collar_type)]_sit"
|
||||
resting = 1
|
||||
update_canmove()
|
||||
else if (prob(1))
|
||||
if (resting)
|
||||
emote("me", 1, pick("gets up and meows.", "walks around.", "stops resting."))
|
||||
icon_state = "[icon_living]"
|
||||
collar_type = "[initial(collar_type)]"
|
||||
resting = 0
|
||||
update_canmove()
|
||||
else
|
||||
emote("me", 1, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
|
||||
|
||||
//MICE!
|
||||
if((src.loc) && isturf(src.loc))
|
||||
if(!stat && !resting && !buckled)
|
||||
for(var/mob/living/simple_animal/mouse/M in view(1,src))
|
||||
if(!M.stat && Adjacent(M))
|
||||
emote("me", 1, "splats \the [M]!")
|
||||
M.splat()
|
||||
movement_target = null
|
||||
stop_automated_movement = 0
|
||||
break
|
||||
for(var/obj/item/toy/cattoy/T in view(1,src))
|
||||
if (T.cooldown < (world.time - 400))
|
||||
emote("me", 1, "bats \the [T] around with its paw!")
|
||||
T.cooldown = world.time
|
||||
|
||||
..()
|
||||
|
||||
make_babies()
|
||||
|
||||
if(!stat && !resting && !buckled)
|
||||
turns_since_scan++
|
||||
if(turns_since_scan > 5)
|
||||
walk_to(src,0)
|
||||
turns_since_scan = 0
|
||||
if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) ))
|
||||
movement_target = null
|
||||
stop_automated_movement = 0
|
||||
if( !movement_target || !(movement_target.loc in oview(src, 3)) )
|
||||
movement_target = null
|
||||
stop_automated_movement = 0
|
||||
for(var/mob/living/simple_animal/mouse/snack in oview(src,3))
|
||||
if(isturf(snack.loc) && !snack.stat)
|
||||
movement_target = snack
|
||||
break
|
||||
if(movement_target)
|
||||
stop_automated_movement = 1
|
||||
walk_to(src,movement_target,0,3)
|
||||
|
||||
/mob/living/simple_animal/pet/cat/cak //I told you I'd do it, Remie
|
||||
name = "Keeki"
|
||||
desc = "It's a cat made out of cake."
|
||||
icon_state = "cak"
|
||||
icon_living = "cak"
|
||||
icon_dead = "cak_dead"
|
||||
health = 50
|
||||
maxHealth = 50
|
||||
gender = FEMALE
|
||||
harm_intent_damage = 10
|
||||
butcher_results = list(/obj/item/organ/brain = 1, /obj/item/organ/heart = 1, /obj/item/reagent_containers/food/snacks/cakeslice/birthday = 3, \
|
||||
/obj/item/reagent_containers/food/snacks/meat/slab = 2)
|
||||
response_harm = "takes a bite out of"
|
||||
attacked_sound = 'sound/items/eatfood.ogg'
|
||||
deathmessage = "loses its false life and collapses!"
|
||||
death_sound = "bodyfall"
|
||||
held_icon = "cak"
|
||||
|
||||
/mob/living/simple_animal/pet/cat/cak/CheckParts(list/parts)
|
||||
..()
|
||||
var/obj/item/organ/brain/B = locate(/obj/item/organ/brain) in contents
|
||||
if(!B || !B.brainmob || !B.brainmob.mind)
|
||||
return
|
||||
B.brainmob.mind.transfer_to(src)
|
||||
to_chat(src, "<span class='big bold'>You are a cak!</span><b> You're a harmless cat/cake hybrid that everyone loves. People can take bites out of you if they're hungry, but you regenerate health \
|
||||
so quickly that it generally doesn't matter. You're remarkably resilient to any damage besides this and it's hard for you to really die at all. You should go around and bring happiness and \
|
||||
free cake to the station!</b>")
|
||||
var/new_name = stripped_input(src, "Enter your name, or press \"Cancel\" to stick with Keeki.", "Name Change")
|
||||
if(new_name)
|
||||
to_chat(src, "<span class='notice'>Your name is now <b>\"new_name\"</b>!</span>")
|
||||
name = new_name
|
||||
|
||||
/mob/living/simple_animal/pet/cat/cak/Life()
|
||||
..()
|
||||
if(stat)
|
||||
return
|
||||
if(health < maxHealth)
|
||||
adjustBruteLoss(-8) //Fast life regen
|
||||
for(var/obj/item/reagent_containers/food/snacks/donut/D in range(1, src)) //Frosts nearby donuts!
|
||||
if(!D.is_decorated)
|
||||
D.decorate_donut()
|
||||
|
||||
/mob/living/simple_animal/pet/cat/cak/attack_hand(mob/living/L)
|
||||
. = ..()
|
||||
if(.) //the attack was blocked
|
||||
return
|
||||
if(L.a_intent == INTENT_HARM && L.reagents && !stat)
|
||||
L.reagents.add_reagent("nutriment", 0.4)
|
||||
L.reagents.add_reagent("vitamin", 0.4)
|
||||
|
||||
//Cat made
|
||||
/mob/living/simple_animal/pet/cat/custom_cat
|
||||
name = "White cat" //Incase it somehow gets spawned without an ID
|
||||
desc = "A cute white catto!"
|
||||
icon_state = "custom_cat"
|
||||
icon_living = "custom_cat"
|
||||
icon_dead = "custom_cat_dead"
|
||||
gender = FEMALE
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
health = 50 //So people can't instakill it s
|
||||
maxHealth = 50
|
||||
speak = list("Meowrowr!", "Mew!", "Miauen!")
|
||||
speak_emote = list("wigglepurrs", "mewls")
|
||||
emote_hear = list("meows.", "mews.")
|
||||
emote_see = list("looks at you eagerly for pets!", "wiggles enthusiastically.")
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
var/pseudo_death = FALSE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/custom_cat/death()
|
||||
if (pseudo_death == TRUE) //secret cat chem
|
||||
icon_state = "custom_cat_dead"
|
||||
Stun(1000)
|
||||
canmove = 0
|
||||
friendly = "deads at"
|
||||
return
|
||||
else
|
||||
..()
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
desc = "This station is just crawling with bugs."
|
||||
icon_state = "cockroach"
|
||||
icon_dead = "cockroach"
|
||||
blood_volume = 50
|
||||
health = 1
|
||||
maxHealth = 1
|
||||
turns_per_move = 5
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
speak_emote = list("clicks")
|
||||
emote_hear = list("clicks.")
|
||||
emote_see = list("clacks.")
|
||||
blood_volume = 350
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1)
|
||||
|
||||
@@ -279,12 +279,3 @@
|
||||
|
||||
/mob/living/simple_animal/drone/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
|
||||
return 0 //So they don't die trying to fix wiring
|
||||
|
||||
/mob/living/simple_animal/drone/can_see_reagents()
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(isclothing(head))
|
||||
var/obj/item/clothing/H = head
|
||||
if(H.clothing_flags & SCAN_REAGENTS)
|
||||
return TRUE
|
||||
|
||||
@@ -1,348 +1,348 @@
|
||||
//goat
|
||||
/mob/living/simple_animal/hostile/retaliate/goat
|
||||
name = "goat"
|
||||
desc = "Not known for their pleasant disposition."
|
||||
icon_state = "goat"
|
||||
icon_living = "goat"
|
||||
icon_dead = "goat_dead"
|
||||
speak = list("EHEHEHEHEH","eh?")
|
||||
speak_emote = list("brays")
|
||||
emote_hear = list("brays.")
|
||||
emote_see = list("shakes its head.", "stamps a foot.", "glares around.")
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
see_in_dark = 6
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 4)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
faction = list("neutral")
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
attack_same = 1
|
||||
attacktext = "kicks"
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
health = 40
|
||||
maxHealth = 40
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 2
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
stop_automated_movement_when_pulled = 1
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
var/obj/item/udder/udder = null
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Initialize()
|
||||
udder = new()
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Destroy()
|
||||
qdel(udder)
|
||||
udder = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Life()
|
||||
. = ..()
|
||||
if(.)
|
||||
//chance to go crazy and start wacking stuff
|
||||
if(!enemies.len && prob(1))
|
||||
Retaliate()
|
||||
|
||||
if(enemies.len && prob(10))
|
||||
enemies = list()
|
||||
LoseTarget()
|
||||
src.visible_message("<span class='notice'>[src] calms down.</span>")
|
||||
if(stat == CONSCIOUS)
|
||||
udder.generateMilk()
|
||||
eat_plants()
|
||||
if(!pulledby)
|
||||
for(var/direction in shuffle(list(1,2,4,8,5,6,9,10)))
|
||||
var/step = get_step(src, direction)
|
||||
if(step)
|
||||
if(locate(/obj/structure/spacevine) in step || locate(/obj/structure/glowshroom) in step)
|
||||
Move(step, get_dir(src, step))
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Retaliate()
|
||||
..()
|
||||
src.visible_message("<span class='danger'>[src] gets an evil-looking gleam in [p_their()] eye.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Move()
|
||||
. = ..()
|
||||
if(!stat)
|
||||
eat_plants()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/proc/eat_plants()
|
||||
var/eaten = FALSE
|
||||
var/obj/structure/spacevine/SV = locate(/obj/structure/spacevine) in loc
|
||||
if(SV)
|
||||
SV.eat(src)
|
||||
eaten = TRUE
|
||||
|
||||
var/obj/structure/glowshroom/GS = locate(/obj/structure/glowshroom) in loc
|
||||
if(GS)
|
||||
qdel(GS)
|
||||
eaten = TRUE
|
||||
|
||||
if(eaten && prob(10))
|
||||
say("Nom")
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/attackby(obj/item/O, mob/user, params)
|
||||
if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass))
|
||||
udder.milkAnimal(O, user)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/AttackingTarget()
|
||||
. = ..()
|
||||
if(. && ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(istype(H.dna.species, /datum/species/pod))
|
||||
var/obj/item/bodypart/NB = pick(H.bodyparts)
|
||||
H.visible_message("<span class='warning'>[src] takes a big chomp out of [H]!</span>", \
|
||||
"<span class='userdanger'>[src] takes a big chomp out of your [NB]!</span>")
|
||||
NB.dismember()
|
||||
//cow
|
||||
/mob/living/simple_animal/cow
|
||||
name = "cow"
|
||||
desc = "Known for their milk, just don't tip them over."
|
||||
icon_state = "cow"
|
||||
icon_living = "cow"
|
||||
icon_dead = "cow_dead"
|
||||
icon_gib = "cow_gib"
|
||||
gender = FEMALE
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
speak = list("moo?","moo","MOOOOOO")
|
||||
speak_emote = list("moos","moos hauntingly")
|
||||
emote_hear = list("brays.")
|
||||
emote_see = list("shakes its head.")
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
see_in_dark = 6
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 6)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
attacktext = "kicks"
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
health = 50
|
||||
maxHealth = 50
|
||||
var/obj/item/udder/udder = null
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/cow/Initialize()
|
||||
udder = new()
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/cow/Destroy()
|
||||
qdel(udder)
|
||||
udder = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/cow/attackby(obj/item/O, mob/user, params)
|
||||
if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass))
|
||||
udder.milkAnimal(O, user)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/cow/Life()
|
||||
. = ..()
|
||||
if(stat == CONSCIOUS)
|
||||
udder.generateMilk()
|
||||
|
||||
/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M)
|
||||
if(!stat && M.a_intent == INTENT_DISARM && icon_state != icon_dead)
|
||||
M.visible_message("<span class='warning'>[M] tips over [src].</span>",
|
||||
"<span class='notice'>You tip over [src].</span>")
|
||||
to_chat(src, "<span class='userdanger'>You are tipped over by [M]!</span>")
|
||||
Knockdown(60,ignore_canknockdown = TRUE)
|
||||
icon_state = icon_dead
|
||||
spawn(rand(20,50))
|
||||
if(!stat && M)
|
||||
icon_state = icon_living
|
||||
var/external
|
||||
var/internal
|
||||
switch(pick(1,2,3,4))
|
||||
if(1,2,3)
|
||||
var/text = pick("imploringly.", "pleadingly.",
|
||||
"with a resigned expression.")
|
||||
external = "[src] looks at [M] [text]"
|
||||
internal = "You look at [M] [text]"
|
||||
if(4)
|
||||
external = "[src] seems resigned to its fate."
|
||||
internal = "You resign yourself to your fate."
|
||||
visible_message("<span class='notice'>[external]</span>",
|
||||
"<span class='revennotice'>[internal]</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/chick
|
||||
name = "\improper chick"
|
||||
desc = "Adorable! They make such a racket though."
|
||||
icon_state = "chick"
|
||||
icon_living = "chick"
|
||||
icon_dead = "chick_dead"
|
||||
icon_gib = "chick_gib"
|
||||
gender = FEMALE
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
speak = list("Cherp.","Cherp?","Chirrup.","Cheep!")
|
||||
speak_emote = list("cheeps")
|
||||
emote_hear = list("cheeps.")
|
||||
emote_see = list("pecks at the ground.","flaps its tiny wings.")
|
||||
density = FALSE
|
||||
speak_chance = 2
|
||||
turns_per_move = 2
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 1)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
attacktext = "kicks"
|
||||
health = 3
|
||||
maxHealth = 3
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
var/amount_grown = 0
|
||||
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
|
||||
mob_size = MOB_SIZE_TINY
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/chick/Initialize()
|
||||
. = ..()
|
||||
pixel_x = rand(-6, 6)
|
||||
pixel_y = rand(0, 10)
|
||||
|
||||
/mob/living/simple_animal/chick/Life()
|
||||
. =..()
|
||||
if(!.)
|
||||
return
|
||||
if(!stat && !ckey)
|
||||
amount_grown += rand(1,2)
|
||||
if(amount_grown >= 100)
|
||||
new /mob/living/simple_animal/chicken(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/chick/holo/Life()
|
||||
..()
|
||||
amount_grown = 0
|
||||
|
||||
/mob/living/simple_animal/chicken
|
||||
name = "\improper chicken"
|
||||
desc = "Hopefully the eggs are good this season."
|
||||
gender = FEMALE
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
icon_state = "chicken_brown"
|
||||
icon_living = "chicken_brown"
|
||||
icon_dead = "chicken_brown_dead"
|
||||
speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.")
|
||||
speak_emote = list("clucks","croons")
|
||||
emote_hear = list("clucks.")
|
||||
emote_see = list("pecks at the ground.","flaps its wings viciously.")
|
||||
density = FALSE
|
||||
speak_chance = 2
|
||||
turns_per_move = 3
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 2)
|
||||
var/egg_type = /obj/item/reagent_containers/food/snacks/egg
|
||||
var/food_type = /obj/item/reagent_containers/food/snacks/grown/wheat
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
attacktext = "kicks"
|
||||
health = 15
|
||||
maxHealth = 15
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
var/eggsleft = 0
|
||||
var/eggsFertile = TRUE
|
||||
var/body_color
|
||||
var/icon_prefix = "chicken"
|
||||
pass_flags = PASSTABLE | PASSMOB
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
var/list/feedMessages = list("It clucks happily.","It clucks happily.")
|
||||
var/list/layMessage = EGG_LAYING_MESSAGES
|
||||
var/list/validColors = list("brown","black","white")
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
var/static/chicken_count = 0
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/chicken/Initialize()
|
||||
. = ..()
|
||||
if(!body_color)
|
||||
body_color = pick(validColors)
|
||||
icon_state = "[icon_prefix]_[body_color]"
|
||||
icon_living = "[icon_prefix]_[body_color]"
|
||||
icon_dead = "[icon_prefix]_[body_color]_dead"
|
||||
pixel_x = rand(-6, 6)
|
||||
pixel_y = rand(0, 10)
|
||||
++chicken_count
|
||||
|
||||
/mob/living/simple_animal/chicken/Destroy()
|
||||
--chicken_count
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/chicken/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, food_type)) //feedin' dem chickens
|
||||
if(!stat && eggsleft < 8)
|
||||
var/feedmsg = "[user] feeds [O] to [name]! [pick(feedMessages)]"
|
||||
user.visible_message(feedmsg)
|
||||
qdel(O)
|
||||
eggsleft += rand(1, 4)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[name] doesn't seem hungry!</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/chicken/Life()
|
||||
. =..()
|
||||
if(!.)
|
||||
return
|
||||
if((!stat && prob(3) && eggsleft > 0) && egg_type)
|
||||
visible_message("<span class='alertalien'>[src] [pick(layMessage)]</span>")
|
||||
eggsleft--
|
||||
var/obj/item/E = new egg_type(get_turf(src))
|
||||
E.pixel_x = rand(-6,6)
|
||||
E.pixel_y = rand(-6,6)
|
||||
if(eggsFertile)
|
||||
if(chicken_count < MAX_CHICKENS && prob(25))
|
||||
START_PROCESSING(SSobj, E)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/egg/var/amount_grown = 0
|
||||
/obj/item/reagent_containers/food/snacks/egg/process()
|
||||
if(isturf(loc))
|
||||
amount_grown += rand(1,2)
|
||||
if(amount_grown >= 100)
|
||||
visible_message("[src] hatches with a quiet cracking sound.")
|
||||
new /mob/living/simple_animal/chick(get_turf(src))
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
qdel(src)
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
|
||||
/obj/item/udder
|
||||
name = "udder"
|
||||
|
||||
/obj/item/udder/Initialize()
|
||||
create_reagents(50)
|
||||
reagents.add_reagent(/datum/reagent/consumable/milk, 20)
|
||||
. = ..()
|
||||
|
||||
/obj/item/udder/proc/generateMilk()
|
||||
if(prob(5))
|
||||
reagents.add_reagent(/datum/reagent/consumable/milk, rand(5, 10))
|
||||
|
||||
/obj/item/udder/proc/milkAnimal(obj/O, mob/user)
|
||||
var/obj/item/reagent_containers/glass/G = O
|
||||
if(G.reagents.total_volume >= G.volume)
|
||||
to_chat(user, "<span class='danger'>[O] is full.</span>")
|
||||
return
|
||||
var/transfered = reagents.trans_to(O, rand(5,10))
|
||||
if(transfered)
|
||||
user.visible_message("[user] milks [src] using \the [O].", "<span class='notice'>You milk [src] using \the [O].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='danger'>The udder is dry. Wait a bit longer...</span>")
|
||||
//goat
|
||||
/mob/living/simple_animal/hostile/retaliate/goat
|
||||
name = "goat"
|
||||
desc = "Not known for their pleasant disposition."
|
||||
icon_state = "goat"
|
||||
icon_living = "goat"
|
||||
icon_dead = "goat_dead"
|
||||
speak = list("EHEHEHEHEH","eh?")
|
||||
speak_emote = list("brays")
|
||||
emote_hear = list("brays.")
|
||||
emote_see = list("shakes its head.", "stamps a foot.", "glares around.")
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
see_in_dark = 6
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 4)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
faction = list("neutral")
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
attack_same = 1
|
||||
attacktext = "kicks"
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
health = 40
|
||||
maxHealth = 40
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 2
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
stop_automated_movement_when_pulled = 1
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
var/obj/item/udder/udder = null
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Initialize()
|
||||
udder = new()
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Destroy()
|
||||
qdel(udder)
|
||||
udder = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Life()
|
||||
. = ..()
|
||||
if(.)
|
||||
//chance to go crazy and start wacking stuff
|
||||
if(!enemies.len && prob(1))
|
||||
Retaliate()
|
||||
|
||||
if(enemies.len && prob(10))
|
||||
enemies = list()
|
||||
LoseTarget()
|
||||
src.visible_message("<span class='notice'>[src] calms down.</span>")
|
||||
if(stat == CONSCIOUS)
|
||||
udder.generateMilk()
|
||||
eat_plants()
|
||||
if(!pulledby)
|
||||
for(var/direction in shuffle(list(1,2,4,8,5,6,9,10)))
|
||||
var/step = get_step(src, direction)
|
||||
if(step)
|
||||
if(locate(/obj/structure/spacevine) in step || locate(/obj/structure/glowshroom) in step)
|
||||
Move(step, get_dir(src, step))
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Retaliate()
|
||||
..()
|
||||
src.visible_message("<span class='danger'>[src] gets an evil-looking gleam in [p_their()] eye.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Move()
|
||||
. = ..()
|
||||
if(!stat)
|
||||
eat_plants()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/proc/eat_plants()
|
||||
var/eaten = FALSE
|
||||
var/obj/structure/spacevine/SV = locate(/obj/structure/spacevine) in loc
|
||||
if(SV)
|
||||
SV.eat(src)
|
||||
eaten = TRUE
|
||||
|
||||
var/obj/structure/glowshroom/GS = locate(/obj/structure/glowshroom) in loc
|
||||
if(GS)
|
||||
qdel(GS)
|
||||
eaten = TRUE
|
||||
|
||||
if(eaten && prob(10))
|
||||
say("Nom")
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/attackby(obj/item/O, mob/user, params)
|
||||
if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass))
|
||||
udder.milkAnimal(O, user)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/AttackingTarget()
|
||||
. = ..()
|
||||
if(. && ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(istype(H.dna.species, /datum/species/pod))
|
||||
var/obj/item/bodypart/NB = pick(H.bodyparts)
|
||||
H.visible_message("<span class='warning'>[src] takes a big chomp out of [H]!</span>", \
|
||||
"<span class='userdanger'>[src] takes a big chomp out of your [NB]!</span>")
|
||||
NB.dismember()
|
||||
//cow
|
||||
/mob/living/simple_animal/cow
|
||||
name = "cow"
|
||||
desc = "Known for their milk, just don't tip them over."
|
||||
icon_state = "cow"
|
||||
icon_living = "cow"
|
||||
icon_dead = "cow_dead"
|
||||
icon_gib = "cow_gib"
|
||||
gender = FEMALE
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
speak = list("moo?","moo","MOOOOOO")
|
||||
speak_emote = list("moos","moos hauntingly")
|
||||
emote_hear = list("brays.")
|
||||
emote_see = list("shakes its head.")
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
see_in_dark = 6
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 6)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
attacktext = "kicks"
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
health = 50
|
||||
maxHealth = 50
|
||||
var/obj/item/udder/udder = null
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/cow/Initialize()
|
||||
udder = new()
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/cow/Destroy()
|
||||
qdel(udder)
|
||||
udder = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/cow/attackby(obj/item/O, mob/user, params)
|
||||
if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass))
|
||||
udder.milkAnimal(O, user)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/cow/Life()
|
||||
. = ..()
|
||||
if(stat == CONSCIOUS)
|
||||
udder.generateMilk()
|
||||
|
||||
/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M)
|
||||
if(!stat && M.a_intent == INTENT_DISARM && icon_state != icon_dead)
|
||||
M.visible_message("<span class='warning'>[M] tips over [src].</span>",
|
||||
"<span class='notice'>You tip over [src].</span>")
|
||||
to_chat(src, "<span class='userdanger'>You are tipped over by [M]!</span>")
|
||||
Knockdown(60,ignore_canknockdown = TRUE)
|
||||
icon_state = icon_dead
|
||||
spawn(rand(20,50))
|
||||
if(!stat && M)
|
||||
icon_state = icon_living
|
||||
var/external
|
||||
var/internal
|
||||
switch(pick(1,2,3,4))
|
||||
if(1,2,3)
|
||||
var/text = pick("imploringly.", "pleadingly.",
|
||||
"with a resigned expression.")
|
||||
external = "[src] looks at [M] [text]"
|
||||
internal = "You look at [M] [text]"
|
||||
if(4)
|
||||
external = "[src] seems resigned to its fate."
|
||||
internal = "You resign yourself to your fate."
|
||||
visible_message("<span class='notice'>[external]</span>",
|
||||
"<span class='revennotice'>[internal]</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/chick
|
||||
name = "\improper chick"
|
||||
desc = "Adorable! They make such a racket though."
|
||||
icon_state = "chick"
|
||||
icon_living = "chick"
|
||||
icon_dead = "chick_dead"
|
||||
icon_gib = "chick_gib"
|
||||
gender = FEMALE
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
speak = list("Cherp.","Cherp?","Chirrup.","Cheep!")
|
||||
speak_emote = list("cheeps")
|
||||
emote_hear = list("cheeps.")
|
||||
emote_see = list("pecks at the ground.","flaps its tiny wings.")
|
||||
density = FALSE
|
||||
speak_chance = 2
|
||||
turns_per_move = 2
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 1)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
attacktext = "kicks"
|
||||
health = 3
|
||||
maxHealth = 3
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
var/amount_grown = 0
|
||||
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
|
||||
mob_size = MOB_SIZE_TINY
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/chick/Initialize()
|
||||
. = ..()
|
||||
pixel_x = rand(-6, 6)
|
||||
pixel_y = rand(0, 10)
|
||||
|
||||
/mob/living/simple_animal/chick/Life()
|
||||
. =..()
|
||||
if(!.)
|
||||
return
|
||||
if(!stat && !ckey)
|
||||
amount_grown += rand(1,2)
|
||||
if(amount_grown >= 100)
|
||||
new /mob/living/simple_animal/chicken(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/chick/holo/Life()
|
||||
..()
|
||||
amount_grown = 0
|
||||
|
||||
/mob/living/simple_animal/chicken
|
||||
name = "\improper chicken"
|
||||
desc = "Hopefully the eggs are good this season."
|
||||
gender = FEMALE
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
icon_state = "chicken_brown"
|
||||
icon_living = "chicken_brown"
|
||||
icon_dead = "chicken_brown_dead"
|
||||
speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.")
|
||||
speak_emote = list("clucks","croons")
|
||||
emote_hear = list("clucks.")
|
||||
emote_see = list("pecks at the ground.","flaps its wings viciously.")
|
||||
density = FALSE
|
||||
speak_chance = 2
|
||||
turns_per_move = 3
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 2)
|
||||
var/egg_type = /obj/item/reagent_containers/food/snacks/egg
|
||||
var/food_type = /obj/item/reagent_containers/food/snacks/grown/wheat
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "kicks"
|
||||
attacktext = "kicks"
|
||||
health = 15
|
||||
maxHealth = 15
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
var/eggsleft = 0
|
||||
var/eggsFertile = TRUE
|
||||
var/body_color
|
||||
var/icon_prefix = "chicken"
|
||||
pass_flags = PASSTABLE | PASSMOB
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
var/list/feedMessages = list("It clucks happily.","It clucks happily.")
|
||||
var/list/layMessage = EGG_LAYING_MESSAGES
|
||||
var/list/validColors = list("brown","black","white")
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
var/static/chicken_count = 0
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
/mob/living/simple_animal/chicken/Initialize()
|
||||
. = ..()
|
||||
if(!body_color)
|
||||
body_color = pick(validColors)
|
||||
icon_state = "[icon_prefix]_[body_color]"
|
||||
icon_living = "[icon_prefix]_[body_color]"
|
||||
icon_dead = "[icon_prefix]_[body_color]_dead"
|
||||
pixel_x = rand(-6, 6)
|
||||
pixel_y = rand(0, 10)
|
||||
++chicken_count
|
||||
|
||||
/mob/living/simple_animal/chicken/Destroy()
|
||||
--chicken_count
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/chicken/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, food_type)) //feedin' dem chickens
|
||||
if(!stat && eggsleft < 8)
|
||||
var/feedmsg = "[user] feeds [O] to [name]! [pick(feedMessages)]"
|
||||
user.visible_message(feedmsg)
|
||||
qdel(O)
|
||||
eggsleft += rand(1, 4)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[name] doesn't seem hungry!</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/chicken/Life()
|
||||
. =..()
|
||||
if(!.)
|
||||
return
|
||||
if((!stat && prob(3) && eggsleft > 0) && egg_type)
|
||||
visible_message("<span class='alertalien'>[src] [pick(layMessage)]</span>")
|
||||
eggsleft--
|
||||
var/obj/item/E = new egg_type(get_turf(src))
|
||||
E.pixel_x = rand(-6,6)
|
||||
E.pixel_y = rand(-6,6)
|
||||
if(eggsFertile)
|
||||
if(chicken_count < MAX_CHICKENS && prob(25))
|
||||
START_PROCESSING(SSobj, E)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/egg/var/amount_grown = 0
|
||||
/obj/item/reagent_containers/food/snacks/egg/process()
|
||||
if(isturf(loc))
|
||||
amount_grown += rand(1,2)
|
||||
if(amount_grown >= 100)
|
||||
visible_message("[src] hatches with a quiet cracking sound.")
|
||||
new /mob/living/simple_animal/chick(get_turf(src))
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
qdel(src)
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
|
||||
/obj/item/udder
|
||||
name = "udder"
|
||||
|
||||
/obj/item/udder/Initialize()
|
||||
create_reagents(50)
|
||||
reagents.add_reagent("milk", 20)
|
||||
. = ..()
|
||||
|
||||
/obj/item/udder/proc/generateMilk()
|
||||
if(prob(5))
|
||||
reagents.add_reagent("milk", rand(5, 10))
|
||||
|
||||
/obj/item/udder/proc/milkAnimal(obj/O, mob/user)
|
||||
var/obj/item/reagent_containers/glass/G = O
|
||||
if(G.reagents.total_volume >= G.volume)
|
||||
to_chat(user, "<span class='danger'>[O] is full.</span>")
|
||||
return
|
||||
var/transfered = reagents.trans_to(O, rand(5,10))
|
||||
if(transfered)
|
||||
user.visible_message("[user] milks [src] using \the [O].", "<span class='notice'>You milk [src] using \the [O].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='danger'>The udder is dry. Wait a bit longer...</span>")
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
emote_see = list("runs in a circle.", "shakes.")
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
blood_volume = 250
|
||||
see_in_dark = 6
|
||||
maxHealth = 5
|
||||
health = 5
|
||||
@@ -27,7 +26,6 @@
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
var/chew_probability = 1
|
||||
size_multiplier = 0.5
|
||||
faction = list("rat")
|
||||
|
||||
/mob/living/simple_animal/mouse/Initialize()
|
||||
. = ..()
|
||||
@@ -38,10 +36,6 @@
|
||||
icon_state = "mouse_[body_color]"
|
||||
icon_living = "mouse_[body_color]"
|
||||
icon_dead = "mouse_[body_color]_dead"
|
||||
if(name == "mouse") // Faster than checking for mobtypes, just checks if this mouse is a generic mouse.
|
||||
if(prob(1)) //1% chance to turn a generic mouse into a boommouse
|
||||
new /mob/living/simple_animal/mouse/boommouse(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/mouse/proc/splat()
|
||||
src.health = 0
|
||||
@@ -62,15 +56,11 @@
|
||||
else
|
||||
..(gibbed)
|
||||
|
||||
|
||||
/mob/living/simple_animal/mouse/Crossed(AM as mob|obj)
|
||||
if( ishuman(AM) )
|
||||
if(!stat)
|
||||
var/mob/M = AM
|
||||
to_chat(M, "<span class='notice'>[icon2html(src, M)] Squeak!</span>")
|
||||
if(istype(AM, /obj/item/reagent_containers/food/snacks/royalcheese))
|
||||
evolve()
|
||||
qdel(AM)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/mouse/handle_automated_action()
|
||||
@@ -91,40 +81,6 @@
|
||||
C.deconstruct()
|
||||
visible_message("<span class='warning'>[src] chews through the [C].</span>")
|
||||
|
||||
for(var/obj/item/reagent_containers/food/snacks/cheesewedge/cheese in range(1, src))
|
||||
if(prob(10))
|
||||
be_fruitful()
|
||||
qdel(cheese)
|
||||
return
|
||||
for(var/obj/item/reagent_containers/food/snacks/royalcheese/bigcheese in range(1, src))
|
||||
qdel(bigcheese)
|
||||
evolve()
|
||||
return
|
||||
|
||||
/**
|
||||
*Checks the mouse cap, if it's above the cap, doesn't spawn a mouse. If below, spawns a mouse and adds it to cheeserats.
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/mouse/proc/be_fruitful()
|
||||
var/cap = CONFIG_GET(number/ratcap)
|
||||
if(LAZYLEN(SSmobs.cheeserats) >= cap)
|
||||
visible_message("<span class='warning'>[src] carefully eats the cheese, hiding it from the [cap] mice on the station!</span>")
|
||||
return
|
||||
var/mob/living/newmouse = new /mob/living/simple_animal/mouse(loc)
|
||||
SSmobs.cheeserats += newmouse
|
||||
visible_message("<span class='notice'>[src] nibbles through the cheese, attracting another mouse!</span>")
|
||||
|
||||
/**
|
||||
*Spawns a new regal rat, says some good jazz, and if sentient, transfers the relivant mind.
|
||||
*/
|
||||
/mob/living/simple_animal/mouse/proc/evolve()
|
||||
var/mob/living/simple_animal/hostile/regalrat = new /mob/living/simple_animal/hostile/regalrat(loc)
|
||||
visible_message("<span class='warning'>[src] devours the cheese! He morphs into something... greater!</span>")
|
||||
regalrat.say("RISE, MY SUBJECTS! SCREEEEEEE!")
|
||||
if(mind)
|
||||
mind.transfer_to(regalrat)
|
||||
qdel(src)
|
||||
|
||||
/*
|
||||
* Mouse types
|
||||
*/
|
||||
@@ -141,10 +97,6 @@
|
||||
body_color = "brown"
|
||||
icon_state = "mouse_brown"
|
||||
|
||||
/mob/living/simple_animal/mouse/Destroy()
|
||||
SSmobs.cheeserats -= src
|
||||
return ..()
|
||||
|
||||
//TOM IS ALIVE! SQUEEEEEEEE~K :)
|
||||
/mob/living/simple_animal/mouse/brown/Tom
|
||||
name = "Tom"
|
||||
@@ -161,53 +113,10 @@
|
||||
icon_state = "mouse_gray_dead"
|
||||
bitesize = 3
|
||||
eatverb = "devour"
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2)
|
||||
list_reagents = list("nutriment" = 3, "vitamin" = 2)
|
||||
foodtype = GROSS | MEAT | RAW
|
||||
grind_results = list(/datum/reagent/blood = 20, /datum/reagent/liquidgibs = 5)
|
||||
grind_results = list("blood" = 20, "liquidgibs" = 5)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/deadmouse/on_grind()
|
||||
reagents.clear_reagents()
|
||||
|
||||
/mob/living/simple_animal/mouse/boommouse
|
||||
name = "boommouse" //obviously inspired on rimworld
|
||||
desc = "A mutated rat with a pack of... Plasma on its back? I wouldn't really touch it if I were you."
|
||||
icon = 'hyperstation/icons/mob/animal.dmi'
|
||||
icon_state = "mouse_plasma"
|
||||
icon_living = "mouse_plasma"
|
||||
icon_dead = "mouse_plasma"
|
||||
see_in_dark = 12
|
||||
maxHealth = 7
|
||||
health = 7
|
||||
chew_probability = 0
|
||||
|
||||
/mob/living/simple_animal/mouse/boommouse/Initialize()
|
||||
. = ..()
|
||||
//Force icons because mouse/initialize randomizes them
|
||||
icon = 'hyperstation/icons/mob/animal.dmi'
|
||||
icon_state = "mouse_plasma"
|
||||
icon_living = "mouse_plasma"
|
||||
icon_dead = "mouse_plasma" //No need for a dead sprite since it qdels itself on death
|
||||
|
||||
/mob/living/simple_animal/mouse/boommouse/death(gibbed, toast)
|
||||
var/turf/T = get_turf(src)
|
||||
message_admins("A boommouse explosion was triggered at [ADMIN_VERBOSEJMP(T)].")
|
||||
visible_message("<span class='danger'>The boommouse violently explodes!</span>")
|
||||
atmos_spawn_air("plasma=15;TEMP=750")
|
||||
explosion(src.loc, 0, 0, 2, 0, 1, 0, 2, 0, 0)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/mouse/boommouse/attackby(obj/item/I, mob/living/user, params)
|
||||
var/turf/T = get_turf(src)
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] is attacking a boommouse at [ADMIN_VERBOSEJMP(T)].")
|
||||
if(istype(I, /obj/item/weldingtool))
|
||||
var/obj/item/weldingtool/W = I
|
||||
if(W.welding)
|
||||
user.visible_message("<span class='warning'>[user] burns the boommouse with [user.p_their()] [W.name]!</span>", "<span class='userdanger'>That was stupid of you.</span>")
|
||||
var/message_admins = "[ADMIN_LOOKUPFLW(user)] triggered a boommouse explosion at [ADMIN_VERBOSEJMP(T)]."
|
||||
GLOB.bombers += message_admins
|
||||
message_admins(message_admins)
|
||||
user.log_message("triggered a boommouse explosion.", LOG_ATTACK)
|
||||
death()
|
||||
return ..()
|
||||
|
||||
//TODO - look into attacked_by to make this better and less shitcode
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/mob/living/simple_animal/hostile/retaliate/poison
|
||||
var/poison_per_bite = 0
|
||||
var/poison_type = /datum/reagent/toxin
|
||||
var/poison_per_bite = 0
|
||||
var/poison_type = "toxin"
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/poison/AttackingTarget()
|
||||
. = ..()
|
||||
|
||||
@@ -20,7 +20,6 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
|
||||
icon_living = "magicOrange"
|
||||
icon_dead = "magicOrange"
|
||||
speed = 0
|
||||
blood_volume = 0
|
||||
a_intent = INTENT_HARM
|
||||
stop_automated_movement = 1
|
||||
movement_type = FLYING // Immunity to chasms and landmines, etc.
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/bomb/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
altclick_listed_turf(A)
|
||||
return
|
||||
if(loc == summoner)
|
||||
to_chat(src, "<span class='danger'><B>You must be manifested to create bombs!</span></B>")
|
||||
|
||||
@@ -105,9 +105,8 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
altclick_listed_turf(A)
|
||||
return
|
||||
if(loc == summoner)
|
||||
if(src.loc == summoner)
|
||||
to_chat(src, "<span class='danger'><B>You must be manifested to warp a target!</span></B>")
|
||||
return
|
||||
if(!beacon)
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
var/mob/living/L = target
|
||||
if(L.reagents)
|
||||
beegent.reaction_mob(L, INJECT)
|
||||
L.reagents.add_reagent(beegent.type, rand(1,5))
|
||||
L.reagents.add_reagent(beegent.id, rand(1,5))
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/bees/proc/assign_reagent(datum/reagent/R)
|
||||
@@ -205,7 +205,7 @@
|
||||
/mob/living/simple_animal/hostile/poison/bees/toxin/Initialize()
|
||||
. = ..()
|
||||
var/datum/reagent/R = pick(typesof(/datum/reagent/toxin))
|
||||
assign_reagent(GLOB.chemical_reagents_list[R])
|
||||
assign_reagent(GLOB.chemical_reagents_list[initial(R.id)])
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/bees/queen
|
||||
name = "queen bee"
|
||||
@@ -225,7 +225,7 @@
|
||||
if(. && beegent && isliving(target))
|
||||
var/mob/living/L = target
|
||||
beegent.reaction_mob(L, TOUCH)
|
||||
L.reagents.add_reagent(beegent.type, rand(1,5))
|
||||
L.reagents.add_reagent(beegent.id, rand(1,5))
|
||||
|
||||
|
||||
//PEASENT BEES
|
||||
@@ -236,7 +236,7 @@
|
||||
/mob/living/simple_animal/hostile/poison/bees/proc/reagent_incompatible(mob/living/simple_animal/hostile/poison/bees/B)
|
||||
if(!B)
|
||||
return FALSE
|
||||
if(B.beegent && beegent && B.beegent.type != beegent.type || B.beegent && !beegent || !B.beegent && beegent)
|
||||
if(B.beegent && beegent && B.beegent.id != beegent.id || B.beegent && !beegent || !B.beegent && beegent)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -253,10 +253,9 @@
|
||||
/obj/item/queen_bee/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/reagent_containers/syringe))
|
||||
var/obj/item/reagent_containers/syringe/S = I
|
||||
var/jelly_amount = S.reagents.get_reagent_amount(/datum/reagent/royal_bee_jelly)
|
||||
if(jelly_amount)
|
||||
if(jelly_amount >= 5)
|
||||
S.reagents.remove_reagent(/datum/reagent/royal_bee_jelly, 5)
|
||||
if(S.reagents.has_reagent("royal_bee_jelly")) //checked twice, because I really don't want royal bee jelly to be duped
|
||||
if(S.reagents.has_reagent("royal_bee_jelly",5))
|
||||
S.reagents.remove_reagent("royal_bee_jelly", 5)
|
||||
var/obj/item/queen_bee/qb = new(user.drop_location())
|
||||
qb.queen = new(qb)
|
||||
if(queen && queen.beegent)
|
||||
@@ -267,8 +266,8 @@
|
||||
to_chat(user, "<span class='warning'>You don't have enough royal bee jelly to split a bee in two!</span>")
|
||||
else
|
||||
var/datum/reagent/R = GLOB.chemical_reagents_list[S.reagents.get_master_reagent_id()]
|
||||
if(R && S.reagents.has_reagent(R.type, 5))
|
||||
S.reagents.remove_reagent(R.type,5)
|
||||
if(R && S.reagents.has_reagent(R.id, 5))
|
||||
S.reagents.remove_reagent(R.id,5)
|
||||
queen.assign_reagent(R)
|
||||
user.visible_message("<span class='warning'>[user] injects [src]'s genome with [R.name], mutating it's DNA!</span>","<span class='warning'>You inject [src]'s genome with [R.name], mutating it's DNA!</span>")
|
||||
name = queen.name
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
spacewalk = TRUE
|
||||
stat_attack = UNCONSCIOUS
|
||||
robust_searching = 1
|
||||
blood_volume = 0
|
||||
|
||||
harm_intent_damage = 10
|
||||
obj_damage = 50
|
||||
@@ -43,4 +42,4 @@
|
||||
var/mob/living/carbon/C = target
|
||||
C.Knockdown(60)
|
||||
C.visible_message("<span class='danger'>\The [src] knocks down \the [C]!</span>", \
|
||||
"<span class='userdanger'>\The [src] knocks you down!</span>")
|
||||
"<span class='userdanger'>\The [src] knocks you down!</span>")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,6 @@
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
del_on_death = 1
|
||||
loot = list(/obj/effect/decal/cleanable/robot_debris)
|
||||
blood_volume = 0
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
..()
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
C.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5)
|
||||
C.reagents.add_reagent("leaper_venom", 5)
|
||||
return
|
||||
if(isanimal(target))
|
||||
var/mob/living/simple_animal/L = target
|
||||
@@ -96,7 +96,7 @@
|
||||
L.Knockdown(50)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5)
|
||||
C.reagents.add_reagent("leaper_venom", 5)
|
||||
if(isanimal(L))
|
||||
var/mob/living/simple_animal/A = L
|
||||
A.adjustHealth(25)
|
||||
@@ -105,6 +105,7 @@
|
||||
|
||||
/datum/reagent/toxin/leaper_venom
|
||||
name = "Leaper venom"
|
||||
id = "leaper_venom"
|
||||
description = "A toxin spat out by leapers that, while harmless in small doses, quickly creates a toxic reaction if too much is in the body."
|
||||
color = "#801E28" // rgb: 128, 30, 40
|
||||
toxpwr = 0
|
||||
|
||||
@@ -378,7 +378,7 @@ Difficulty: Very Hard
|
||||
. += observer_desc
|
||||
. += "It is activated by [activation_method]."
|
||||
|
||||
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode, atom/movable/source)
|
||||
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
..()
|
||||
if(isliving(speaker))
|
||||
ActivationReaction(speaker, ACTIVATE_SPEECH)
|
||||
@@ -651,7 +651,7 @@ Difficulty: Very Hard
|
||||
L.heal_overall_damage(heal_power, heal_power)
|
||||
new /obj/effect/temp_visual/heal(get_turf(target), "#80F5FF")
|
||||
|
||||
/mob/living/simple_animal/hostile/lightgeist/ghostize(can_reenter_corpse = TRUE, special = FALSE, penalize = FALSE)
|
||||
/mob/living/simple_animal/hostile/lightgeist/ghostize()
|
||||
. = ..()
|
||||
if(.)
|
||||
death()
|
||||
|
||||
@@ -80,7 +80,7 @@ Difficulty: Medium
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs)
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message()
|
||||
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
|
||||
return
|
||||
return ..()
|
||||
@@ -267,7 +267,6 @@ Difficulty: Medium
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
altclick_listed_turf(A)
|
||||
return
|
||||
if(swoop_cooldown >= world.time)
|
||||
to_chat(src, "<span class='warning'>You need to wait 20 seconds between swoop attacks!</span>")
|
||||
|
||||
@@ -50,7 +50,6 @@ Difficulty: Normal
|
||||
armour_penetration = 75
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
blood_volume = 0
|
||||
speed = 1
|
||||
move_to_delay = 11
|
||||
ranged = 1
|
||||
@@ -442,7 +441,7 @@ Difficulty: Normal
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/AltClickOn(atom/A) //player control handler(don't give this to a player holy fuck)
|
||||
if(!istype(A) || get_dist(A, src) <= 2)
|
||||
return altclick_listed_turf(A)
|
||||
return
|
||||
blink(A)
|
||||
|
||||
//Hierophant overlays
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway
|
||||
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
|
||||
var/list/crusher_loot
|
||||
var/medal_type
|
||||
var/score_type = BOSS_SCORE
|
||||
@@ -45,6 +44,9 @@
|
||||
QDEL_NULL(internal)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/prevent_content_explosion()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/death(gibbed)
|
||||
if(health > 0)
|
||||
return
|
||||
@@ -119,10 +121,9 @@
|
||||
recovery_time = world.time + buffer_time
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype, scoretype, crusher_kill)
|
||||
if(!medal_type || (flags_1 & ADMIN_SPAWNED_1)) //Don't award medals if the medal type isn't set
|
||||
if(!medal_type || (flags_1 & ADMIN_SPAWNED_1) || !SSmedals.hub_enabled) //Don't award medals if the medal type isn't set
|
||||
return FALSE
|
||||
if(!SSmedals.hub_enabled) // This allows subtypes to carry on other special rewards not tied with medals. (such as bubblegum's arena shuttle)
|
||||
return TRUE
|
||||
|
||||
for(var/mob/living/L in view(7,src))
|
||||
if(L.stat || !L.client)
|
||||
continue
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
sentience_type = SENTIENCE_BOSS
|
||||
layer = LARGE_MOB_LAYER
|
||||
blood_volume = 0
|
||||
var/doing_move_loop = FALSE
|
||||
var/mob/living/set_target
|
||||
var/timerid
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
|
||||
/obj/item/udder/gutlunch/generateMilk()
|
||||
if(prob(60))
|
||||
reagents.add_reagent(/datum/reagent/consumable/cream, rand(2, 5))
|
||||
reagents.add_reagent("cream", rand(2, 5))
|
||||
if(prob(45))
|
||||
reagents.add_reagent(/datum/reagent/medicine/salglu_solution, rand(2,5))
|
||||
reagents.add_reagent("salglu_solution", rand(2,5))
|
||||
|
||||
|
||||
@@ -1,192 +1,192 @@
|
||||
/mob/living/simple_animal/hostile/mushroom
|
||||
name = "walking mushroom"
|
||||
desc = "It's a massive mushroom... with legs?"
|
||||
icon_state = "mushroom_color"
|
||||
icon_living = "mushroom_color"
|
||||
icon_dead = "mushroom_dead"
|
||||
speak_chance = 0
|
||||
turns_per_move = 1
|
||||
maxHealth = 10
|
||||
health = 10
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/hugemushroomslice = 1)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "whacks"
|
||||
harm_intent_damage = 5
|
||||
obj_damage = 0
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 1
|
||||
attack_same = 2
|
||||
attacktext = "chomps"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
faction = list("mushroom")
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
stat_attack = DEAD
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
speed = 1
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
robust_searching = 1
|
||||
unique_name = 1
|
||||
speak_emote = list("squeaks")
|
||||
deathmessage = "fainted."
|
||||
var/cap_color = "#ffffff"
|
||||
var/powerlevel = 0 //Tracks our general strength level gained from eating other shrooms
|
||||
var/bruised = 0 //If someone tries to cheat the system by attacking a shroom to lower its health, punish them so that it wont award levels to shrooms that eat it
|
||||
var/recovery_cooldown = 0 //So you can't repeatedly revive it during a fight
|
||||
var/faint_ticker = 0 //If we hit three, another mushroom's gonna eat us
|
||||
var/static/mutable_appearance/cap_living //Where we store our cap icons so we dont generate them constantly to update our icon
|
||||
var/static/mutable_appearance/cap_dead
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/examine(mob/user)
|
||||
. = ..()
|
||||
if(health >= maxHealth)
|
||||
. += "<span class='info'>It looks healthy.</span>"
|
||||
else
|
||||
. += "<span class='info'>It looks like it's been roughed up.</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/Life()
|
||||
..()
|
||||
if(!stat)//Mushrooms slowly regenerate if conscious, for people who want to save them from being eaten
|
||||
adjustBruteLoss(-2)
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/Initialize()//Makes every shroom a little unique
|
||||
melee_damage_lower += rand(3, 5)
|
||||
melee_damage_upper += rand(10,20)
|
||||
maxHealth += rand(40,60)
|
||||
move_to_delay = rand(3,11)
|
||||
cap_living = cap_living || mutable_appearance(icon, "mushroom_cap")
|
||||
cap_dead = cap_dead || mutable_appearance(icon, "mushroom_cap_dead")
|
||||
|
||||
cap_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
|
||||
UpdateMushroomCap()
|
||||
health = maxHealth
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/CanAttack(atom/the_target) // Mushroom-specific version of CanAttack to handle stupid attack_same = 2 crap so we don't have to do it for literally every single simple_animal/hostile because this shit never gets spawned
|
||||
if(!the_target || isturf(the_target) || istype(the_target, /atom/movable/lighting_object))
|
||||
return FALSE
|
||||
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
return FALSE
|
||||
|
||||
if(isliving(the_target))
|
||||
var/mob/living/L = the_target
|
||||
|
||||
if (!faction_check_mob(L) && attack_same == 2)
|
||||
return FALSE
|
||||
if(L.stat > stat_attack)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/adjustHealth(amount, updating_health = TRUE, forced = FALSE) //Possibility to flee from a fight just to make it more visually interesting
|
||||
if(!retreat_distance && prob(33))
|
||||
retreat_distance = 5
|
||||
addtimer(CALLBACK(src, .proc/stop_retreat), 30)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/stop_retreat()
|
||||
retreat_distance = null
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/attack_animal(mob/living/L)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/mushroom) && stat == DEAD)
|
||||
var/mob/living/simple_animal/hostile/mushroom/M = L
|
||||
if(faint_ticker < 2)
|
||||
M.visible_message("[M] chews a bit on [src].")
|
||||
faint_ticker++
|
||||
return TRUE
|
||||
M.visible_message("<span class='warning'>[M] devours [src]!</span>")
|
||||
var/level_gain = (powerlevel - M.powerlevel)
|
||||
if(level_gain >= -1 && !bruised && !M.ckey)//Player shrooms can't level up to become robust gods.
|
||||
if(level_gain < 1)//So we still gain a level if two mushrooms were the same level
|
||||
level_gain = 1
|
||||
M.LevelUp(level_gain)
|
||||
M.adjustBruteLoss(-M.maxHealth)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/revive(full_heal = 0, admin_revive = 0)
|
||||
if(..())
|
||||
icon_state = "mushroom_color"
|
||||
UpdateMushroomCap()
|
||||
. = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/death(gibbed)
|
||||
..(gibbed)
|
||||
UpdateMushroomCap()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/UpdateMushroomCap()
|
||||
cut_overlays()
|
||||
cap_living.color = cap_color
|
||||
cap_dead.color = cap_color
|
||||
if(health == 0)
|
||||
add_overlay(cap_dead)
|
||||
else
|
||||
add_overlay(cap_living)
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/Recover()
|
||||
visible_message("[src] slowly begins to recover.")
|
||||
faint_ticker = 0
|
||||
revive(full_heal = 1)
|
||||
UpdateMushroomCap()
|
||||
recovery_cooldown = 1
|
||||
addtimer(CALLBACK(src, .proc/recovery_recharge), 300)
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/recovery_recharge()
|
||||
recovery_cooldown = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/LevelUp(level_gain)
|
||||
if(powerlevel <= 9)
|
||||
powerlevel += level_gain
|
||||
if(prob(25))
|
||||
melee_damage_lower += (level_gain * rand(1,5))
|
||||
else
|
||||
melee_damage_upper += (level_gain * rand(1,5))
|
||||
maxHealth += (level_gain * rand(1,5))
|
||||
adjustBruteLoss(-maxHealth) //They'll always heal, even if they don't gain a level, in case you want to keep this shroom around instead of harvesting it
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/Bruise()
|
||||
if(!bruised && !stat)
|
||||
src.visible_message("The [src.name] was bruised!")
|
||||
bruised = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/reagent_containers/food/snacks/grown/mushroom))
|
||||
if(stat == DEAD && !recovery_cooldown)
|
||||
Recover()
|
||||
qdel(I)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[src] won't eat it!</span>")
|
||||
return
|
||||
if(I.force)
|
||||
Bruise()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) // the attack was blocked
|
||||
return
|
||||
if(M.a_intent == INTENT_HARM)
|
||||
Bruise()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
..()
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/T = AM
|
||||
if(T.throwforce)
|
||||
Bruise()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/bullet_act()
|
||||
..()
|
||||
Bruise()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/harvest()
|
||||
var/counter
|
||||
for(counter=0, counter<=powerlevel, counter++)
|
||||
var/obj/item/reagent_containers/food/snacks/hugemushroomslice/S = new /obj/item/reagent_containers/food/snacks/hugemushroomslice(src.loc)
|
||||
S.reagents.add_reagent(/datum/reagent/drug/mushroomhallucinogen, powerlevel)
|
||||
S.reagents.add_reagent(/datum/reagent/medicine/omnizine, powerlevel)
|
||||
S.reagents.add_reagent(/datum/reagent/medicine/synaptizine, powerlevel)
|
||||
/mob/living/simple_animal/hostile/mushroom
|
||||
name = "walking mushroom"
|
||||
desc = "It's a massive mushroom... with legs?"
|
||||
icon_state = "mushroom_color"
|
||||
icon_living = "mushroom_color"
|
||||
icon_dead = "mushroom_dead"
|
||||
speak_chance = 0
|
||||
turns_per_move = 1
|
||||
maxHealth = 10
|
||||
health = 10
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/hugemushroomslice = 1)
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "whacks"
|
||||
harm_intent_damage = 5
|
||||
obj_damage = 0
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 1
|
||||
attack_same = 2
|
||||
attacktext = "chomps"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
faction = list("mushroom")
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
stat_attack = DEAD
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
speed = 1
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
robust_searching = 1
|
||||
unique_name = 1
|
||||
speak_emote = list("squeaks")
|
||||
deathmessage = "fainted."
|
||||
var/cap_color = "#ffffff"
|
||||
var/powerlevel = 0 //Tracks our general strength level gained from eating other shrooms
|
||||
var/bruised = 0 //If someone tries to cheat the system by attacking a shroom to lower its health, punish them so that it wont award levels to shrooms that eat it
|
||||
var/recovery_cooldown = 0 //So you can't repeatedly revive it during a fight
|
||||
var/faint_ticker = 0 //If we hit three, another mushroom's gonna eat us
|
||||
var/static/mutable_appearance/cap_living //Where we store our cap icons so we dont generate them constantly to update our icon
|
||||
var/static/mutable_appearance/cap_dead
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/examine(mob/user)
|
||||
. = ..()
|
||||
if(health >= maxHealth)
|
||||
. += "<span class='info'>It looks healthy.</span>"
|
||||
else
|
||||
. += "<span class='info'>It looks like it's been roughed up.</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/Life()
|
||||
..()
|
||||
if(!stat)//Mushrooms slowly regenerate if conscious, for people who want to save them from being eaten
|
||||
adjustBruteLoss(-2)
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/Initialize()//Makes every shroom a little unique
|
||||
melee_damage_lower += rand(3, 5)
|
||||
melee_damage_upper += rand(10,20)
|
||||
maxHealth += rand(40,60)
|
||||
move_to_delay = rand(3,11)
|
||||
cap_living = cap_living || mutable_appearance(icon, "mushroom_cap")
|
||||
cap_dead = cap_dead || mutable_appearance(icon, "mushroom_cap_dead")
|
||||
|
||||
cap_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
|
||||
UpdateMushroomCap()
|
||||
health = maxHealth
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/CanAttack(atom/the_target) // Mushroom-specific version of CanAttack to handle stupid attack_same = 2 crap so we don't have to do it for literally every single simple_animal/hostile because this shit never gets spawned
|
||||
if(!the_target || isturf(the_target) || istype(the_target, /atom/movable/lighting_object))
|
||||
return FALSE
|
||||
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
return FALSE
|
||||
|
||||
if(isliving(the_target))
|
||||
var/mob/living/L = the_target
|
||||
|
||||
if (!faction_check_mob(L) && attack_same == 2)
|
||||
return FALSE
|
||||
if(L.stat > stat_attack)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/adjustHealth(amount, updating_health = TRUE, forced = FALSE) //Possibility to flee from a fight just to make it more visually interesting
|
||||
if(!retreat_distance && prob(33))
|
||||
retreat_distance = 5
|
||||
addtimer(CALLBACK(src, .proc/stop_retreat), 30)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/stop_retreat()
|
||||
retreat_distance = null
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/attack_animal(mob/living/L)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/mushroom) && stat == DEAD)
|
||||
var/mob/living/simple_animal/hostile/mushroom/M = L
|
||||
if(faint_ticker < 2)
|
||||
M.visible_message("[M] chews a bit on [src].")
|
||||
faint_ticker++
|
||||
return TRUE
|
||||
M.visible_message("<span class='warning'>[M] devours [src]!</span>")
|
||||
var/level_gain = (powerlevel - M.powerlevel)
|
||||
if(level_gain >= -1 && !bruised && !M.ckey)//Player shrooms can't level up to become robust gods.
|
||||
if(level_gain < 1)//So we still gain a level if two mushrooms were the same level
|
||||
level_gain = 1
|
||||
M.LevelUp(level_gain)
|
||||
M.adjustBruteLoss(-M.maxHealth)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/revive(full_heal = 0, admin_revive = 0)
|
||||
if(..())
|
||||
icon_state = "mushroom_color"
|
||||
UpdateMushroomCap()
|
||||
. = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/death(gibbed)
|
||||
..(gibbed)
|
||||
UpdateMushroomCap()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/UpdateMushroomCap()
|
||||
cut_overlays()
|
||||
cap_living.color = cap_color
|
||||
cap_dead.color = cap_color
|
||||
if(health == 0)
|
||||
add_overlay(cap_dead)
|
||||
else
|
||||
add_overlay(cap_living)
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/Recover()
|
||||
visible_message("[src] slowly begins to recover.")
|
||||
faint_ticker = 0
|
||||
revive(full_heal = 1)
|
||||
UpdateMushroomCap()
|
||||
recovery_cooldown = 1
|
||||
addtimer(CALLBACK(src, .proc/recovery_recharge), 300)
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/recovery_recharge()
|
||||
recovery_cooldown = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/LevelUp(level_gain)
|
||||
if(powerlevel <= 9)
|
||||
powerlevel += level_gain
|
||||
if(prob(25))
|
||||
melee_damage_lower += (level_gain * rand(1,5))
|
||||
else
|
||||
melee_damage_upper += (level_gain * rand(1,5))
|
||||
maxHealth += (level_gain * rand(1,5))
|
||||
adjustBruteLoss(-maxHealth) //They'll always heal, even if they don't gain a level, in case you want to keep this shroom around instead of harvesting it
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/Bruise()
|
||||
if(!bruised && !stat)
|
||||
src.visible_message("The [src.name] was bruised!")
|
||||
bruised = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/reagent_containers/food/snacks/grown/mushroom))
|
||||
if(stat == DEAD && !recovery_cooldown)
|
||||
Recover()
|
||||
qdel(I)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[src] won't eat it!</span>")
|
||||
return
|
||||
if(I.force)
|
||||
Bruise()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) // the attack was blocked
|
||||
return
|
||||
if(M.a_intent == INTENT_HARM)
|
||||
Bruise()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
..()
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/T = AM
|
||||
if(T.throwforce)
|
||||
Bruise()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/bullet_act()
|
||||
..()
|
||||
Bruise()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/harvest()
|
||||
var/counter
|
||||
for(counter=0, counter<=powerlevel, counter++)
|
||||
var/obj/item/reagent_containers/food/snacks/hugemushroomslice/S = new /obj/item/reagent_containers/food/snacks/hugemushroomslice(src.loc)
|
||||
S.reagents.add_reagent("mushroomhallucinogen", powerlevel)
|
||||
S.reagents.add_reagent("omnizine", powerlevel)
|
||||
S.reagents.add_reagent("synaptizine", powerlevel)
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
/mob/living/simple_animal/hostile/regalrat
|
||||
name = "regal rat"
|
||||
desc = "An evolved rat, created through some strange science. It leads nearby rats with deadly efficiency to protect its kingdom. Not technically a king."
|
||||
icon_state = "regalrat"
|
||||
icon_living = "regalrat"
|
||||
icon_dead = "regalrat_dead"
|
||||
gender = NEUTER
|
||||
speak_chance = 0
|
||||
turns_per_move = 5
|
||||
maxHealth = 70
|
||||
health = 70
|
||||
see_in_dark = 5
|
||||
obj_damage = 10
|
||||
butcher_results = list(/obj/item/clothing/head/crown = 1,)
|
||||
response_help = "glare at"
|
||||
response_disarm = "skoff at"
|
||||
response_harm = "slash"
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 12
|
||||
attacktext = "slashes"
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
unique_name = TRUE
|
||||
faction = list("rat")
|
||||
var/datum/action/cooldown/coffer
|
||||
var/datum/action/cooldown/riot
|
||||
///Number assigned to rats and mice, checked when determining infighting.
|
||||
|
||||
/mob/living/simple_animal/hostile/regalrat/Initialize()
|
||||
. = ..()
|
||||
coffer = new /datum/action/cooldown/coffer
|
||||
coffer.Grant(src)
|
||||
riot = new /datum/action/cooldown/riot
|
||||
riot.Grant(src)
|
||||
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the Royal Rat, cheesey be his crown?", ROLE_SENTIENCE, null, FALSE, 100, POLL_IGNORE_SENTIENCE_POTION)
|
||||
if(LAZYLEN(candidates) && !mind)
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
key = C.key
|
||||
notify_ghosts("All rise for the rat king, ascendant to the throne in \the [get_area(src)].", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE)
|
||||
|
||||
/mob/living/simple_animal/hostile/regalrat/handle_automated_action()
|
||||
if(prob(20))
|
||||
riot.Trigger()
|
||||
else if(prob(50))
|
||||
coffer.Trigger()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/regalrat/CanAttack(atom/the_target)
|
||||
if(istype(the_target,/mob/living/simple_animal))
|
||||
var/mob/living/A = the_target
|
||||
if(istype(the_target, /mob/living/simple_animal/hostile/regalrat) && A.stat == CONSCIOUS)
|
||||
return TRUE
|
||||
if(istype(the_target, /mob/living/simple_animal/hostile/rat) && A.stat == CONSCIOUS)
|
||||
var/mob/living/simple_animal/hostile/rat/R = the_target
|
||||
if(R.faction_check_mob(src, TRUE))
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/regalrat/examine(mob/user)
|
||||
. = ..()
|
||||
if(istype(user,/mob/living/simple_animal/hostile/rat))
|
||||
var/mob/living/simple_animal/hostile/rat/ratself = user
|
||||
if(ratself.faction_check_mob(src, TRUE))
|
||||
. += "<span class='notice'>This is your king. Long live his majesty!</span>"
|
||||
else
|
||||
. += "<span class='warning'>This is a false king! Strike him down!</span>"
|
||||
else if(istype(user,/mob/living/simple_animal/hostile/regalrat))
|
||||
. += "<span class='warning'>Who is this foolish false king? This will not stand!</span>"
|
||||
|
||||
/**
|
||||
*This action creates trash, money, dirt, and cheese.
|
||||
*/
|
||||
|
||||
/datum/action/cooldown/coffer
|
||||
name = "Fill Coffers"
|
||||
desc = "Your newly granted regality and poise let you scavenge for lost junk, but more importantly, cheese."
|
||||
icon_icon = 'icons/mob/actions/actions_animal.dmi'
|
||||
background_icon_state = "bg_clock"
|
||||
button_icon_state = "coffer"
|
||||
cooldown_time = 50
|
||||
|
||||
/datum/action/cooldown/coffer/Trigger()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/turf/T = get_turf(owner)
|
||||
var/loot = rand(1,100)
|
||||
switch(loot)
|
||||
if(1 to 5)
|
||||
to_chat(owner, "<span class='notice'>Score! You find some cheese!</span>")
|
||||
new /obj/item/reagent_containers/food/snacks/cheesewedge(T)
|
||||
if(6 to 10)
|
||||
var/pickedcoin = pick(GLOB.ratking_coins)
|
||||
to_chat(owner, "<span class='notice'>You find some leftover coins. More for the royal treasury!</span>")
|
||||
for(var/i = 1 to rand(1,3))
|
||||
new pickedcoin(T)
|
||||
if(11)
|
||||
to_chat(owner, "<span class='notice'>You find a... Hunh. This coin doesn't look right.</span>")
|
||||
var/rarecoin = rand(1,2)
|
||||
if (rarecoin == 1)
|
||||
new /obj/item/coin/twoheaded(T)
|
||||
else
|
||||
new /obj/item/coin/antagtoken(T)
|
||||
if(12 to 40)
|
||||
var/pickedtrash = pick(GLOB.ratking_trash)
|
||||
to_chat(owner, "<span class='notice'>You just find more garbage and dirt. Lovely, but beneath you now.</span>")
|
||||
new /obj/effect/decal/cleanable/dirt(T)
|
||||
new pickedtrash(T)
|
||||
if(41 to 100)
|
||||
to_chat(owner, "<span class='notice'>Drat. Nothing.</span>")
|
||||
new /obj/effect/decal/cleanable/dirt(T)
|
||||
StartCooldown()
|
||||
|
||||
/**
|
||||
*This action checks all nearby mice, and converts them into hostile rats. If no mice are nearby, creates a new one.
|
||||
*/
|
||||
|
||||
/datum/action/cooldown/riot
|
||||
name = "Raise Army"
|
||||
desc = "Raise an army out of the hordes of mice and pests crawling around the maintenance shafts."
|
||||
icon_icon = 'icons/mob/actions/actions_animal.dmi'
|
||||
button_icon_state = "riot"
|
||||
background_icon_state = "bg_clock"
|
||||
cooldown_time = 80
|
||||
///Checks to see if there are any nearby mice. Does not count Rats.
|
||||
|
||||
/datum/action/cooldown/riot/Trigger()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/cap = CONFIG_GET(number/ratcap)
|
||||
var/something_from_nothing = FALSE
|
||||
for(var/mob/living/simple_animal/mouse/M in oview(owner, 5))
|
||||
var/mob/living/simple_animal/hostile/rat/new_rat = new(get_turf(M))
|
||||
something_from_nothing = TRUE
|
||||
if(M.mind && M.stat == CONSCIOUS)
|
||||
M.mind.transfer_to(new_rat)
|
||||
if(istype(owner,/mob/living/simple_animal/hostile/regalrat))
|
||||
var/mob/living/simple_animal/hostile/regalrat/giantrat = owner
|
||||
new_rat.faction = giantrat.faction
|
||||
qdel(M)
|
||||
if(!something_from_nothing)
|
||||
if(LAZYLEN(SSmobs.cheeserats) >= cap)
|
||||
to_chat(owner,"<span class='warning'>There's too many mice on this station to beckon a new one! Find them first!</span>")
|
||||
return
|
||||
new /mob/living/simple_animal/mouse(owner.loc)
|
||||
owner.visible_message("<span class='warning'>[owner] commands a mouse to its side!</span>")
|
||||
else
|
||||
owner.visible_message("<span class='warning'>[owner] commands its army to action, mutating them into rats!</span>")
|
||||
StartCooldown()
|
||||
|
||||
/mob/living/simple_animal/hostile/rat
|
||||
name = "rat"
|
||||
desc = "It's a nasty, ugly, evil, disease-ridden rodent with anger issues."
|
||||
icon_state = "mouse_gray"
|
||||
icon_living = "mouse_gray"
|
||||
icon_dead = "mouse_gray_dead"
|
||||
speak = list("Skree!","SKREEE!","Squeak?")
|
||||
speak_emote = list("squeaks")
|
||||
emote_hear = list("Hisses.")
|
||||
emote_see = list("runs in a circle.", "stands on its hind legs.")
|
||||
melee_damage_lower = 3
|
||||
melee_damage_upper = 5
|
||||
obj_damage = 5
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
see_in_dark = 6
|
||||
maxHealth = 15
|
||||
health = 15
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1)
|
||||
density = FALSE
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
|
||||
mob_size = MOB_SIZE_TINY
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
faction = list("rat")
|
||||
|
||||
/mob/living/simple_animal/hostile/rat/Initialize()
|
||||
. = ..()
|
||||
SSmobs.cheeserats += src
|
||||
AddComponent(/datum/component/swarming)
|
||||
|
||||
/mob/living/simple_animal/hostile/rat/Destroy()
|
||||
SSmobs.cheeserats -= src
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/rat/examine(mob/user)
|
||||
. = ..()
|
||||
if(istype(user,/mob/living/simple_animal/hostile/rat))
|
||||
var/mob/living/simple_animal/hostile/rat/ratself = user
|
||||
if(ratself.faction_check_mob(src, TRUE))
|
||||
. += "<span class='notice'>You both serve the same king.</span>"
|
||||
else
|
||||
. += "<span class='warning'>This fool serves a different king!</span>"
|
||||
else if(istype(user,/mob/living/simple_animal/hostile/regalrat))
|
||||
var/mob/living/simple_animal/hostile/regalrat/ratking = user
|
||||
if(ratking.faction_check_mob(src, TRUE))
|
||||
. += "<span class='notice'>This rat serves under you.</span>"
|
||||
else
|
||||
. += "<span class='warning'>This peasant serves a different king! Strike him down!</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/rat/CanAttack(atom/the_target)
|
||||
if(istype(the_target,/mob/living/simple_animal))
|
||||
var/mob/living/A = the_target
|
||||
if(istype(the_target, /mob/living/simple_animal/hostile/regalrat) && A.stat == CONSCIOUS)
|
||||
var/mob/living/simple_animal/hostile/regalrat/ratking = the_target
|
||||
if(ratking.faction_check_mob(src, TRUE))
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
if(istype(the_target, /mob/living/simple_animal/hostile/rat) && A.stat == CONSCIOUS)
|
||||
var/mob/living/simple_animal/hostile/rat/R = the_target
|
||||
if(R.faction_check_mob(src, TRUE))
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/rat/handle_automated_action()
|
||||
. = ..()
|
||||
if(prob(40))
|
||||
var/turf/open/floor/F = get_turf(src)
|
||||
if(istype(F) && !F.intact)
|
||||
var/obj/structure/cable/C = locate() in F
|
||||
if(C && prob(15))
|
||||
if(C.avail())
|
||||
visible_message("<span class='warning'>[src] chews through the [C]. It's toast!</span>")
|
||||
playsound(src, 'sound/effects/sparks2.ogg', 100, TRUE)
|
||||
C.deconstruct()
|
||||
death()
|
||||
else if(C && C.avail())
|
||||
visible_message("<span class='warning'>[src] chews through the [C]. It looks unharmed!</span>")
|
||||
playsound(src, 'sound/effects/sparks2.ogg', 100, TRUE)
|
||||
C.deconstruct()
|
||||
@@ -6,7 +6,6 @@
|
||||
icon_dead = "bat_dead"
|
||||
icon_gib = "bat_dead"
|
||||
turns_per_move = 1
|
||||
blood_volume = 250
|
||||
response_help = "brushes aside"
|
||||
response_disarm = "flails at"
|
||||
response_harm = "hits"
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
movement_type = FLYING
|
||||
pressure_resistance = 300
|
||||
gold_core_spawnable = NO_SPAWN //too spooky for science
|
||||
blood_volume = 0
|
||||
var/ghost_hair_style
|
||||
var/ghost_hair_color
|
||||
var/mutable_appearance/ghost_hair
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
emote_see = list("rattles")
|
||||
a_intent = INTENT_HARM
|
||||
maxHealth = 40
|
||||
blood_volume = 0
|
||||
health = 40
|
||||
speed = 1
|
||||
harm_intent_damage = 5
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
maxHealth = 50000
|
||||
health = 50000
|
||||
healable = 0
|
||||
blood_volume = 0
|
||||
|
||||
harm_intent_damage = 10
|
||||
obj_damage = 100
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
response_disarm = "shoves"
|
||||
response_harm = "hits"
|
||||
speed = 0
|
||||
blood_volume = 0
|
||||
stat_attack = UNCONSCIOUS
|
||||
robust_searching = 1
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
stat("Held Item", held_item)
|
||||
stat("Mode",a_intent)
|
||||
|
||||
/mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
/mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode)
|
||||
. = ..()
|
||||
if(speaker != src && prob(50)) //Dont imitate ourselves
|
||||
if(!radio_freq || prob(10))
|
||||
@@ -208,8 +208,8 @@
|
||||
ears.forceMove(drop_location())
|
||||
ears = null
|
||||
for(var/possible_phrase in speak)
|
||||
if(copytext_char(possible_phrase, 2, 3) in GLOB.department_radio_keys)
|
||||
possible_phrase = copytext_char(possible_phrase, 3)
|
||||
if(copytext(possible_phrase,1,3) in GLOB.department_radio_keys)
|
||||
possible_phrase = copytext(possible_phrase,3)
|
||||
|
||||
//Adding things to inventory
|
||||
else if(href_list["add_inv"])
|
||||
@@ -420,8 +420,8 @@
|
||||
if(prob(50))
|
||||
useradio = 1
|
||||
|
||||
if((possible_phrase[1] in GLOB.department_radio_prefixes) && (copytext_char(possible_phrase, 2, 3) in GLOB.department_radio_keys))
|
||||
possible_phrase = "[useradio?pick(available_channels):""][copytext_char(possible_phrase, 3)]" //crop out the channel prefix
|
||||
if((copytext(possible_phrase,1,2) in GLOB.department_radio_prefixes) && (copytext(possible_phrase,2,3) in GLOB.department_radio_keys))
|
||||
possible_phrase = "[useradio?pick(available_channels):""][copytext(possible_phrase,3)]" //crop out the channel prefix
|
||||
else
|
||||
possible_phrase = "[useradio?pick(available_channels):""][possible_phrase]"
|
||||
|
||||
@@ -429,8 +429,8 @@
|
||||
|
||||
else //If we have no headset or channels to use, dont try to use any!
|
||||
for(var/possible_phrase in speak)
|
||||
if((possible_phrase[1] in GLOB.department_radio_prefixes) && (copytext_char(possible_phrase, 2, 3) in GLOB.department_radio_keys))
|
||||
possible_phrase = copytext_char(possible_phrase, 3) //crop out the channel prefix
|
||||
if((copytext(possible_phrase,1,2) in GLOB.department_radio_prefixes) && (copytext(possible_phrase,2,3) in GLOB.department_radio_keys))
|
||||
possible_phrase = copytext(possible_phrase,3) //crop out the channel prefix
|
||||
newspeak.Add(possible_phrase)
|
||||
speak = newspeak
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
loot = list(/obj/item/ectoplasm)
|
||||
del_on_death = TRUE
|
||||
initial_language_holder = /datum/language_holder/construct
|
||||
blood_volume = 0
|
||||
|
||||
/mob/living/simple_animal/shade/death()
|
||||
deathmessage = "lets out a contented sigh as [p_their()] form unwinds."
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
health = 20
|
||||
maxHealth = 20
|
||||
gender = PLURAL //placeholder
|
||||
blood_volume = 550 //How much blud it has for bloodsucking
|
||||
|
||||
|
||||
status_flags = CANPUSH
|
||||
|
||||
var/icon_living = ""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode, atom/movable/source)
|
||||
/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
. = ..()
|
||||
if(speaker != src && !radio_freq && !stat)
|
||||
if (speaker in Friends)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
pass_flags = PASSTABLE
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
gender = NEUTER
|
||||
blood_volume = 0 //until someone reworks for them to have slime jelly
|
||||
var/is_adult = 0
|
||||
var/docile = 0
|
||||
faction = list("slime","neutral")
|
||||
@@ -141,9 +140,9 @@
|
||||
. = ..()
|
||||
remove_movespeed_modifier(MOVESPEED_ID_SLIME_REAGENTMOD, TRUE)
|
||||
var/amount = 0
|
||||
if(reagents.has_reagent(/datum/reagent/medicine/morphine)) // morphine slows slimes down
|
||||
if(reagents.has_reagent("morphine")) // morphine slows slimes down
|
||||
amount = 2
|
||||
if(reagents.has_reagent(/datum/reagent/consumable/frostoil)) // Frostoil also makes them move VEEERRYYYYY slow
|
||||
if(reagents.has_reagent("frostoil")) // Frostoil also makes them move VEEERRYYYYY slow
|
||||
amount = 5
|
||||
if(amount)
|
||||
add_movespeed_modifier(MOVESPEED_ID_SLIME_REAGENTMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
|
||||
|
||||
@@ -148,28 +148,23 @@
|
||||
|
||||
/////////////////////////////////// DISABILITIES ////////////////////////////////////
|
||||
|
||||
/mob/living/proc/add_quirk(quirktype, spawn_effects) //separate proc due to the way these ones are handled
|
||||
if(has_quirk(quirktype))
|
||||
/mob/living/proc/add_quirk(quirk, spawn_effects) //separate proc due to the way these ones are handled
|
||||
if(HAS_TRAIT(src, quirk))
|
||||
return
|
||||
var/datum/quirk/T = quirktype
|
||||
var/qname = initial(T.name)
|
||||
if(!SSquirks || !SSquirks.quirks[qname])
|
||||
if(!SSquirks || !SSquirks.quirks[quirk])
|
||||
return
|
||||
new quirktype (src, spawn_effects)
|
||||
var/datum/quirk/T = SSquirks.quirks[quirk]
|
||||
new T (src, spawn_effects)
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/remove_quirk(quirktype)
|
||||
for(var/datum/quirk/Q in roundstart_quirks)
|
||||
if(Q.type == quirktype)
|
||||
qdel(Q)
|
||||
return TRUE
|
||||
return FALSE
|
||||
/mob/living/proc/remove_quirk(quirk)
|
||||
var/datum/quirk/T = roundstart_quirks[quirk]
|
||||
if(T)
|
||||
qdel(T)
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/has_quirk(quirktype)
|
||||
for(var/datum/quirk/Q in roundstart_quirks)
|
||||
if(Q.type == quirktype)
|
||||
return TRUE
|
||||
return FALSE
|
||||
/mob/living/proc/has_quirk(quirk)
|
||||
return roundstart_quirks[quirk]
|
||||
|
||||
/////////////////////////////////// TRAIT PROCS ////////////////////////////////////
|
||||
|
||||
@@ -230,4 +225,4 @@
|
||||
|
||||
/mob/living/proc/ignore_slowdown(source)
|
||||
ADD_TRAIT(src, TRAIT_IGNORESLOWDOWN, source)
|
||||
update_movespeed(FALSE)
|
||||
update_movespeed(FALSE)
|
||||
@@ -8,7 +8,6 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
|
||||
/mob/living/proc/handle_ventcrawl(atom/A)
|
||||
if(!ventcrawler || !Adjacent(A))
|
||||
return
|
||||
. = TRUE //return value to stop the client from being shown the turf contents stat tab on alt-click.
|
||||
if(stat)
|
||||
to_chat(src, "You must be conscious to do this!")
|
||||
return
|
||||
|
||||
@@ -52,5 +52,4 @@
|
||||
var/datum/callback/CB = foo
|
||||
CB.Invoke()
|
||||
|
||||
mind?.hide_ckey = client?.prefs?.hide_ckey
|
||||
log_message("Client [key_name(src)] has taken ownership of mob [src]([src.type])", LOG_OWNERSHIP)
|
||||
|
||||
+101
-124
@@ -84,123 +84,109 @@
|
||||
if(!client)
|
||||
return
|
||||
|
||||
msg = copytext_char(msg, 1, MAX_MESSAGE_LEN)
|
||||
msg = copytext(msg, 1, MAX_MESSAGE_LEN)
|
||||
|
||||
if(type)
|
||||
if(type & MSG_VISUAL && eye_blind )//Vision related
|
||||
if(type & 1 && eye_blind )//Vision related
|
||||
if(!alt_msg)
|
||||
return
|
||||
else
|
||||
msg = alt_msg
|
||||
type = alt_type
|
||||
|
||||
if(type & MSG_AUDIBLE && !can_hear())//Hearing related
|
||||
if(type & 2 && !can_hear())//Hearing related
|
||||
if(!alt_msg)
|
||||
return
|
||||
else
|
||||
msg = alt_msg
|
||||
type = alt_type
|
||||
if(type & MSG_VISUAL && eye_blind)
|
||||
if(type & 1 && eye_blind)
|
||||
return
|
||||
// voice muffling
|
||||
if(stat == UNCONSCIOUS)
|
||||
if(type & MSG_AUDIBLE) //audio
|
||||
if(type & 2) //audio
|
||||
to_chat(src, "<I>... You can almost hear something ...</I>")
|
||||
return
|
||||
to_chat(src, msg)
|
||||
else
|
||||
to_chat(src, msg)
|
||||
|
||||
/**
|
||||
* Generate a visible message from this atom
|
||||
*
|
||||
* Show a message to all player mobs who sees this atom
|
||||
*
|
||||
* Show a message to the src mob (if the src is a mob)
|
||||
*
|
||||
* Use for atoms performing visible actions
|
||||
*
|
||||
* message is output to anyone who can see, e.g. "The [src] does something!"
|
||||
*
|
||||
* Vars:
|
||||
* * self_message (optional) is what the src mob sees e.g. "You do something!"
|
||||
* * blind_message (optional) is what blind people will hear e.g. "You hear something!"
|
||||
* * vision_distance (optional) define how many tiles away the message can be seen.
|
||||
* * ignored_mobs (optional) doesn't show any message to any given mob in the list.
|
||||
*/
|
||||
/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs)
|
||||
// Show a message to all player mobs who sees this atom
|
||||
// Show a message to the src mob (if the src is a mob)
|
||||
// Use for atoms performing visible actions
|
||||
// message is output to anyone who can see, e.g. "The [src] does something!"
|
||||
// self_message (optional) is what the src mob sees e.g. "You do something!"
|
||||
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
|
||||
// vision_distance (optional) define how many tiles away the message can be seen.
|
||||
// ignored_mob (optional) doesn't show any message to a given mob if TRUE.
|
||||
|
||||
/atom/proc/visible_message(message, self_message, blind_message, vision_distance, list/ignored_mobs, no_ghosts = FALSE)
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return
|
||||
var/list/hearers = get_hearers_in_view(vision_distance, src) //caches the hearers and then removes ignored mobs.
|
||||
if(!length(hearers))
|
||||
return
|
||||
if(!islist(ignored_mobs))
|
||||
ignored_mobs = list(ignored_mobs)
|
||||
hearers -= ignored_mobs
|
||||
if(self_message)
|
||||
hearers -= src
|
||||
for(var/mob/M in hearers)
|
||||
var/range = 7
|
||||
if(vision_distance)
|
||||
range = vision_distance
|
||||
for(var/mob/M in get_hearers_in_view(range, src))
|
||||
if(!M.client)
|
||||
continue
|
||||
//This entire if/else chain could be in two lines but isn't for readibilties sake.
|
||||
var/msg = message
|
||||
//CITADEL EDIT, required for vore code to remove (T != loc && T != src)) as a check
|
||||
if(M.see_invisible<invisibility) //if src is invisible to us,
|
||||
msg = blind_message
|
||||
else if(T.lighting_object && T.lighting_object.invisibility <= M.see_invisible && T.is_softly_lit()) //the light object is dark and not invisible to us
|
||||
msg = blind_message
|
||||
|
||||
if(!msg)
|
||||
if(M in ignored_mobs)
|
||||
continue
|
||||
M.show_message(msg, MSG_VISUAL,blind_message, MSG_AUDIBLE)
|
||||
var/msg = message
|
||||
if(isobserver(M) && no_ghosts)
|
||||
continue
|
||||
if(M == src) //the src always see the main message or self message
|
||||
if(self_message)
|
||||
msg = self_message
|
||||
else //CITADEL EDIT, required for vore code to remove (T != loc && T != src)) as a check
|
||||
if(M.see_invisible<invisibility) //if src is invisible to us,
|
||||
if(blind_message) // then people see blind message if there is one, otherwise nothing.
|
||||
msg = blind_message
|
||||
else
|
||||
continue
|
||||
|
||||
///Adds the functionality to self_message.
|
||||
mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs)
|
||||
. = ..()
|
||||
if(self_message)
|
||||
show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE)
|
||||
else if(T.lighting_object)
|
||||
if(T.lighting_object.invisibility <= M.see_invisible && T.is_softly_lit()) //the light object is dark and not invisible to us
|
||||
if(blind_message)
|
||||
msg = blind_message
|
||||
else
|
||||
continue
|
||||
|
||||
/**
|
||||
* Show a message to all mobs in earshot of this atom
|
||||
*
|
||||
* Use for objects performing audible actions
|
||||
*
|
||||
* vars:
|
||||
* * message is the message output to anyone who can hear.
|
||||
* * deaf_message (optional) is what deaf people will see.
|
||||
* * hearing_distance (optional) is the range, how many tiles away the message can be heard.
|
||||
* * ignored_mobs (optional) doesn't show any message to any given mob in the list.
|
||||
*/
|
||||
/atom/proc/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, list/ignored_mobs)
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return
|
||||
var/list/hearers = get_hearers_in_view(hearing_distance, src)
|
||||
if(!length(hearers))
|
||||
return
|
||||
if(!islist(ignored_mobs))
|
||||
ignored_mobs = list(ignored_mobs)
|
||||
hearers -= ignored_mobs
|
||||
if(self_message)
|
||||
hearers -= src
|
||||
for(var/mob/M in hearers)
|
||||
M.show_message(message, MSG_AUDIBLE, deaf_message, MSG_VISUAL)
|
||||
M.show_message(msg,1,blind_message,2)
|
||||
|
||||
/**
|
||||
* Show a message to all mobs in earshot of this one
|
||||
*
|
||||
* This would be for audible actions by the src mob
|
||||
*
|
||||
* vars:
|
||||
* * message is the message output to anyone who can hear.
|
||||
* * self_message (optional) is what the src mob hears.
|
||||
* * deaf_message (optional) is what deaf people will see.
|
||||
* * hearing_distance (optional) is the range, how many tiles away the message can be heard.
|
||||
* * ignored_mobs (optional) doesn't show any message to any given mob in the list.
|
||||
*/
|
||||
/mob/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, list/ignored_mobs)
|
||||
. = ..()
|
||||
if(self_message)
|
||||
show_message(self_message, MSG_AUDIBLE, deaf_message, MSG_VISUAL)
|
||||
// Show a message to all mobs in earshot of this one
|
||||
// This would be for audible actions by the src mob
|
||||
// message is the message output to anyone who can hear.
|
||||
// self_message (optional) is what the src mob hears.
|
||||
// deaf_message (optional) is what deaf people will see.
|
||||
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
|
||||
|
||||
/mob/audible_message(message, deaf_message, hearing_distance, self_message, no_ghosts = FALSE)
|
||||
var/range = 7
|
||||
if(hearing_distance)
|
||||
range = hearing_distance
|
||||
for(var/mob/M in get_hearers_in_view(range, src))
|
||||
var/msg = message
|
||||
if(self_message && M==src)
|
||||
msg = self_message
|
||||
if(no_ghosts && isobserver(M))
|
||||
continue
|
||||
M.show_message( msg, 2, deaf_message, 1)
|
||||
|
||||
// Show a message to all mobs in earshot of this atom
|
||||
// Use for objects performing audible actions
|
||||
// message is the message output to anyone who can hear.
|
||||
// deaf_message (optional) is what deaf people will see.
|
||||
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
|
||||
|
||||
/atom/proc/audible_message(message, deaf_message, hearing_distance, no_ghosts = FALSE)
|
||||
var/range = 7
|
||||
if(hearing_distance)
|
||||
range = hearing_distance
|
||||
for(var/mob/M in get_hearers_in_view(range, src))
|
||||
if(no_ghosts && isobserver(M))
|
||||
continue
|
||||
M.show_message( message, 2, deaf_message, 1)
|
||||
|
||||
/mob/proc/Life()
|
||||
set waitfor = FALSE
|
||||
@@ -404,6 +390,9 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
|
||||
if(I)
|
||||
I.attack_self(src)
|
||||
update_inv_hands()
|
||||
if(!I)//CIT CHANGE - allows "using" empty hands
|
||||
use_that_empty_hand() //CIT CHANGE - ditto
|
||||
update_inv_hands() // CIT CHANGE - ditto.
|
||||
|
||||
/mob/verb/memory()
|
||||
set name = "Notes"
|
||||
@@ -418,7 +407,7 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
|
||||
set name = "Add Note"
|
||||
set category = "IC"
|
||||
|
||||
msg = copytext_char(msg, 1, MAX_MESSAGE_LEN)
|
||||
msg = copytext(msg, 1, MAX_MESSAGE_LEN)
|
||||
msg = sanitize(msg)
|
||||
|
||||
if(mind)
|
||||
@@ -463,12 +452,12 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
|
||||
qdel(M)
|
||||
return
|
||||
|
||||
to_chat(usr, "<span class='boldnotice'>Please roleplay correctly, do not meta-game, and use information from a different character or characters, to influence your actions!</span>")
|
||||
usr.client.lastrespawn = world.time + 1800 SECONDS
|
||||
usr.client.respawn_observing = 0
|
||||
|
||||
message_admins("[client.ckey] respawned.")
|
||||
M.ckey = ckey //shamelessly copied to
|
||||
to_chat(M, "<span class='danger'>Please roleplay correctly, do not meta-game, and use information from a different character or characters, to influence your actions!</span>")
|
||||
qdel(usr)
|
||||
M.key = key
|
||||
// M.Login() //wat
|
||||
return
|
||||
|
||||
@@ -723,38 +712,6 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
|
||||
client.last_turn = world.time + MOB_FACE_DIRECTION_DELAY
|
||||
return TRUE
|
||||
|
||||
/mob/verb/eastshift()
|
||||
set hidden = TRUE
|
||||
if(!canface())
|
||||
return FALSE
|
||||
if(pixel_x <= 16)
|
||||
pixel_x++
|
||||
is_shifted = TRUE
|
||||
|
||||
/mob/verb/westshift()
|
||||
set hidden = TRUE
|
||||
if(!canface())
|
||||
return FALSE
|
||||
if(pixel_x >= -16)
|
||||
pixel_x--
|
||||
is_shifted = TRUE
|
||||
|
||||
/mob/verb/northshift()
|
||||
set hidden = TRUE
|
||||
if(!canface())
|
||||
return FALSE
|
||||
if(pixel_y <= 16)
|
||||
pixel_y++
|
||||
is_shifted = TRUE
|
||||
|
||||
/mob/verb/southshift()
|
||||
set hidden = TRUE
|
||||
if(!canface())
|
||||
return FALSE
|
||||
if(pixel_y >= -16)
|
||||
pixel_y--
|
||||
is_shifted = TRUE
|
||||
|
||||
/mob/proc/IsAdvancedToolUser()//This might need a rename but it should replace the can this mob use things check
|
||||
return FALSE
|
||||
|
||||
@@ -849,6 +806,26 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
|
||||
/mob/proc/can_interact_with(atom/A)
|
||||
return IsAdminGhost(src) || Adjacent(A)
|
||||
|
||||
//Can the mob see reagents inside of containers?
|
||||
/mob/proc/can_see_reagents()
|
||||
if(stat == DEAD) //Ghosts and such can always see reagents
|
||||
return 1
|
||||
if(has_unlimited_silicon_privilege) //Silicons can automatically view reagents
|
||||
return 1
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(H.head && istype(H.head, /obj/item/clothing))
|
||||
var/obj/item/clothing/CL = H.head
|
||||
if(CL.scan_reagents)
|
||||
return 1
|
||||
if(H.wear_mask && H.wear_mask.scan_reagents)
|
||||
return 1
|
||||
if(H.glasses && istype(H.glasses, /obj/item/clothing))
|
||||
var/obj/item/clothing/CL = H.glasses
|
||||
if(CL.scan_reagents)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Can the mob use Topic to interact with machines
|
||||
/mob/proc/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
|
||||
return
|
||||
|
||||
+146
-154
@@ -42,131 +42,128 @@
|
||||
else
|
||||
return 0
|
||||
|
||||
/**
|
||||
* Convert random parts of a passed in message to stars
|
||||
*
|
||||
* * phrase - the string to convert
|
||||
* * probability - probability any character gets changed
|
||||
*
|
||||
* This proc is dangerously laggy, avoid it or die
|
||||
*/
|
||||
/proc/stars(phrase, probability = 25)
|
||||
if(probability <= 0)
|
||||
return phrase
|
||||
phrase = html_decode(phrase)
|
||||
var/leng = length(phrase)
|
||||
. = ""
|
||||
var/char = ""
|
||||
for(var/i = 1, i <= leng, i += length(char))
|
||||
char = phrase[i]
|
||||
if(char == " " || !prob(probability))
|
||||
. += char
|
||||
/proc/stars(n, pr)
|
||||
n = html_encode(n)
|
||||
if (pr == null)
|
||||
pr = 25
|
||||
if (pr <= 0)
|
||||
return null
|
||||
else
|
||||
if (pr >= 100)
|
||||
return n
|
||||
var/te = n
|
||||
var/t = ""
|
||||
n = length(n)
|
||||
var/p = null
|
||||
p = 1
|
||||
while(p <= n)
|
||||
if ((copytext(te, p, p + 1) == " " || prob(pr)))
|
||||
t = text("[][]", t, copytext(te, p, p + 1))
|
||||
else
|
||||
. += "*"
|
||||
return sanitize(.)
|
||||
t = text("[]*", t)
|
||||
p++
|
||||
return sanitize(t)
|
||||
|
||||
/**
|
||||
* Makes you speak like you're drunk
|
||||
*/
|
||||
/proc/slur(phrase, strength = 50)
|
||||
strength = min(50, strength)
|
||||
phrase = html_decode(phrase)
|
||||
/proc/slur(n,var/strength=50)
|
||||
strength = min(strength,50)
|
||||
var/phrase = html_decode(n)
|
||||
var/leng = length(phrase)
|
||||
. = ""
|
||||
var/newletter = ""
|
||||
var/rawchar = ""
|
||||
for(var/i = 1, i <= leng, i += length(rawchar))
|
||||
rawchar = newletter = phrase[i]
|
||||
if(rand(1,100)<=strength * 0.5)
|
||||
var/lowerletter = lowertext(newletter)
|
||||
if(lowerletter == "o")
|
||||
newletter = "u"
|
||||
else if(lowerletter == "s")
|
||||
newletter = "ch"
|
||||
else if(lowerletter == "a")
|
||||
newletter = "ah"
|
||||
else if(lowerletter == "u")
|
||||
newletter = "oo"
|
||||
else if(lowerletter == "c")
|
||||
newletter = "k"
|
||||
if(rand(1,100) <= strength * 0.25)
|
||||
if(newletter == " ")
|
||||
newletter = "...huuuhhh..."
|
||||
else if(newletter == ".")
|
||||
newletter = " *BURP*."
|
||||
switch(rand(1,100) <= strength * 0.5)
|
||||
if(1)
|
||||
newletter += "'"
|
||||
if(10)
|
||||
newletter += "[newletter]"
|
||||
if(20)
|
||||
newletter += "[newletter][newletter]"
|
||||
. += "[newletter]"
|
||||
return sanitize(.)
|
||||
var/counter=length(phrase)
|
||||
var/newphrase=""
|
||||
var/newletter=""
|
||||
while(counter>=1)
|
||||
newletter=copytext(phrase,(leng-counter)+1,(leng-counter)+2)
|
||||
if(rand(1,100)<=strength*0.5)
|
||||
if(lowertext(newletter)=="o")
|
||||
newletter="u"
|
||||
if(lowertext(newletter)=="s")
|
||||
newletter="ch"
|
||||
if(lowertext(newletter)=="a")
|
||||
newletter="ah"
|
||||
if(lowertext(newletter)=="u")
|
||||
newletter="oo"
|
||||
if(lowertext(newletter)=="c")
|
||||
newletter="k"
|
||||
if(rand(1,100) <= strength*0.25)
|
||||
if(newletter==" ")
|
||||
newletter="...huuuhhh..."
|
||||
if(newletter==".")
|
||||
newletter=" *BURP*."
|
||||
if(rand(1,100) <= strength*0.5)
|
||||
if(rand(1,5) == 1)
|
||||
newletter+="'"
|
||||
if(rand(1,5) == 1)
|
||||
newletter+="[newletter]"
|
||||
if(rand(1,5) == 1)
|
||||
newletter+="[newletter][newletter]"
|
||||
newphrase+="[newletter]";counter-=1
|
||||
return newphrase
|
||||
|
||||
/// Makes you talk like you got cult stunned, which is slurring but with some dark messages
|
||||
/proc/cultslur(phrase) // Inflicted on victims of a stun talisman
|
||||
phrase = html_decode(phrase)
|
||||
|
||||
/proc/cultslur(n) // Inflicted on victims of a stun talisman
|
||||
var/phrase = html_decode(n)
|
||||
var/leng = length(phrase)
|
||||
. = ""
|
||||
var/newletter = ""
|
||||
var/rawchar = ""
|
||||
for(var/i = 1, i <= leng, i += length(rawchar))
|
||||
rawchar = newletter = phrase[i]
|
||||
if(rand(1, 2) == 2)
|
||||
var/lowerletter = lowertext(newletter)
|
||||
if(lowerletter == "o")
|
||||
newletter = "u"
|
||||
else if(lowerletter == "t")
|
||||
newletter = "ch"
|
||||
else if(lowerletter == "a")
|
||||
newletter = "ah"
|
||||
else if(lowerletter == "u")
|
||||
newletter = "oo"
|
||||
else if(lowerletter == "c")
|
||||
newletter = " NAR "
|
||||
else if(lowerletter == "s")
|
||||
newletter = " SIE "
|
||||
if(rand(1, 4) == 4)
|
||||
if(newletter == " ")
|
||||
newletter = " no hope... "
|
||||
else if(newletter == "H")
|
||||
newletter = " IT COMES... "
|
||||
var/counter=length(phrase)
|
||||
var/newphrase=""
|
||||
var/newletter=""
|
||||
while(counter>=1)
|
||||
newletter=copytext(phrase,(leng-counter)+1,(leng-counter)+2)
|
||||
if(rand(1,2)==2)
|
||||
if(lowertext(newletter)=="o")
|
||||
newletter="u"
|
||||
if(lowertext(newletter)=="t")
|
||||
newletter="ch"
|
||||
if(lowertext(newletter)=="a")
|
||||
newletter="ah"
|
||||
if(lowertext(newletter)=="u")
|
||||
newletter="oo"
|
||||
if(lowertext(newletter)=="c")
|
||||
newletter=" NAR "
|
||||
if(lowertext(newletter)=="s")
|
||||
newletter=" SIE "
|
||||
if(rand(1,4)==4)
|
||||
if(newletter==" ")
|
||||
newletter=" no hope... "
|
||||
if(newletter=="H")
|
||||
newletter=" IT COMES... "
|
||||
|
||||
switch(rand(1, 15))
|
||||
switch(rand(1,15))
|
||||
if(1)
|
||||
newletter = "'"
|
||||
newletter="'"
|
||||
if(2)
|
||||
newletter += "agn"
|
||||
newletter+="agn"
|
||||
if(3)
|
||||
newletter = "fth"
|
||||
newletter="fth"
|
||||
if(4)
|
||||
newletter = "nglu"
|
||||
newletter="nglu"
|
||||
if(5)
|
||||
newletter = "glor"
|
||||
. += newletter
|
||||
return sanitize(.)
|
||||
newletter="glor"
|
||||
newphrase+="[newletter]";counter-=1
|
||||
return newphrase
|
||||
|
||||
///Adds stuttering to the message passed in
|
||||
/proc/stutter(phrase)
|
||||
phrase = html_decode(phrase)
|
||||
var/leng = length(phrase)
|
||||
. = ""
|
||||
var/newletter = ""
|
||||
var/rawchar
|
||||
for(var/i = 1, i <= leng, i += length(rawchar))
|
||||
rawchar = newletter = phrase[i]
|
||||
if(prob(80) && !(lowertext(newletter) in list("a", "e", "i", "o", "u", " ")))
|
||||
if(prob(10))
|
||||
newletter = "[newletter]-[newletter]-[newletter]-[newletter]"
|
||||
else if(prob(20))
|
||||
newletter = "[newletter]-[newletter]-[newletter]"
|
||||
else if (prob(5))
|
||||
newletter = ""
|
||||
|
||||
/proc/stutter(n)
|
||||
var/te = html_decode(n)
|
||||
var/t = ""//placed before the message. Not really sure what it's for.
|
||||
n = length(n)//length of the entire word
|
||||
var/p = null
|
||||
p = 1//1 is the start of any word
|
||||
while(p <= n)//while P, which starts at 1 is less or equal to N which is the length.
|
||||
var/n_letter = copytext(te, p, p + 1)//copies text from a certain distance. In this case, only one letter at a time.
|
||||
if (prob(80) && (ckey(n_letter) in list("b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z")))
|
||||
if (prob(10))
|
||||
n_letter = text("[n_letter]-[n_letter]-[n_letter]-[n_letter]")//replaces the current letter with this instead.
|
||||
else
|
||||
newletter = "[newletter]-[newletter]"
|
||||
. += newletter
|
||||
return sanitize(.)
|
||||
if (prob(20))
|
||||
n_letter = text("[n_letter]-[n_letter]-[n_letter]")
|
||||
else
|
||||
if (prob(5))
|
||||
n_letter = null
|
||||
else
|
||||
n_letter = text("[n_letter]-[n_letter]")
|
||||
t = text("[t][n_letter]")//since the above is ran through for each letter, the text just adds up back to the original word.
|
||||
p++//for each letter p is increased to find where the next letter will be.
|
||||
return copytext(sanitize(t),1,MAX_MESSAGE_LEN)
|
||||
|
||||
/proc/derpspeech(message, stuttering)
|
||||
message = replacetext(message, " am ", " ")
|
||||
@@ -186,42 +183,52 @@
|
||||
return message
|
||||
|
||||
|
||||
/proc/Gibberish(text, replace_characters = FALSE, chance = 50)
|
||||
text = html_decode(text)
|
||||
. = ""
|
||||
var/rawchar = ""
|
||||
var/letter = ""
|
||||
var/lentext = length(text)
|
||||
for(var/i = 1, i <= lentext, i += length(rawchar))
|
||||
rawchar = letter = text[i]
|
||||
if(prob(chance))
|
||||
if(replace_characters)
|
||||
letter = ""
|
||||
for(var/j in 1 to rand(0, 2))
|
||||
letter += pick("#", "@", "*", "&", "%", "$", "/", "<", ">", ";", "*", "*", "*", "*", "*", "*", "*")
|
||||
. += letter
|
||||
return sanitize(.)
|
||||
/proc/Gibberish(t, p)//t is the inputted message, and any value higher than 70 for p will cause letters to be replaced instead of added
|
||||
/* Turn text into complete gibberish! */
|
||||
var/returntext = ""
|
||||
for(var/i = 1, i <= length(t), i++)
|
||||
|
||||
var/letter = copytext(t, i, i+1)
|
||||
if(prob(50))
|
||||
if(p >= 70)
|
||||
letter = ""
|
||||
|
||||
for(var/j = 1, j <= rand(0, 2), j++)
|
||||
letter += pick("#","@","*","&","%","$","/", "<", ">", ";","*","*","*","*","*","*","*")
|
||||
|
||||
returntext += letter
|
||||
|
||||
return returntext
|
||||
|
||||
|
||||
/proc/ninjaspeak(n) //NINJACODE
|
||||
/*
|
||||
The difference with stutter is that this proc can stutter more than 1 letter
|
||||
The issue here is that anything that does not have a space is treated as one word (in many instances). For instance, "LOOKING," is a word, including the comma.
|
||||
It's fairly easy to fix if dealing with single letters but not so much with compounds of letters./N
|
||||
*/
|
||||
/proc/ninjaspeak(phrase) //NINJACODE
|
||||
. = ""
|
||||
var/lentext = length_char(phrase)
|
||||
var/rawchars = ""
|
||||
var/letter = ""
|
||||
for(var/i = 1, i <= lentext, i += length_char(rawchars))
|
||||
var/end = i + rand(1,4)
|
||||
letter = rawchars = copytext_char(phrase, i, end > lentext ? 0 : end)
|
||||
var/te = html_decode(n)
|
||||
var/t = ""
|
||||
n = length(n)
|
||||
var/p = 1
|
||||
while(p <= n)
|
||||
var/n_letter
|
||||
var/n_mod = rand(1,4)
|
||||
if(p+n_mod>n+1)
|
||||
n_letter = copytext(te, p, n+1)
|
||||
else
|
||||
n_letter = copytext(te, p, p+n_mod)
|
||||
if (prob(50))
|
||||
if (prob(30))
|
||||
letter = "[letter]-[letter]-[letter]"
|
||||
n_letter = text("[n_letter]-[n_letter]-[n_letter]")
|
||||
else
|
||||
letter = "[letter]-[letter]"
|
||||
. += letter
|
||||
return copytext_char(sanitize(.),1,MAX_MESSAGE_LEN)
|
||||
n_letter = text("[n_letter]-[n_letter]")
|
||||
else
|
||||
n_letter = text("[n_letter]")
|
||||
t = text("[t][n_letter]")
|
||||
p=p+n_mod
|
||||
return copytext(sanitize(t),1,MAX_MESSAGE_LEN)
|
||||
|
||||
|
||||
/proc/shake_camera(mob/M, duration, strength=1)
|
||||
if(!M || !M.client || duration < 1)
|
||||
@@ -480,17 +487,6 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
|
||||
/mob/proc/can_hear()
|
||||
. = TRUE
|
||||
|
||||
//Examine text for traits shared by multiple types. I wish examine was less copypasted.
|
||||
/mob/proc/common_trait_examine()
|
||||
if(HAS_TRAIT(src, TRAIT_DISSECTED))
|
||||
var/dissectionmsg = ""
|
||||
if(HAS_TRAIT_FROM(src, TRAIT_DISSECTED,"Extraterrestrial Dissection"))
|
||||
dissectionmsg = " via Extraterrestrial Dissection. It is no longer worth experimenting on"
|
||||
else if(HAS_TRAIT_FROM(src, TRAIT_DISSECTED,"Experimental Dissection"))
|
||||
dissectionmsg = " via Experimental Dissection"
|
||||
else if(HAS_TRAIT_FROM(src, TRAIT_DISSECTED,"Thorough Dissection"))
|
||||
dissectionmsg = " via Thorough Dissection"
|
||||
. += "<span class='notice'>This body has been dissected and analyzed[dissectionmsg].</span><br>"
|
||||
/proc/bloodtype_to_color(var/type)
|
||||
. = BLOOD_COLOR_HUMAN
|
||||
switch(type)
|
||||
@@ -524,7 +520,3 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
|
||||
if(!held_item)
|
||||
return
|
||||
return held_item.GetID()
|
||||
|
||||
//Can the mob see reagents inside of containers?
|
||||
/mob/proc/can_see_reagents()
|
||||
return stat == DEAD || has_unlimited_silicon_privilege //Dead guys and silicons can always see reagents
|
||||
|
||||
@@ -367,9 +367,6 @@
|
||||
if(m_intent == MOVE_INTENT_RUN)
|
||||
m_intent = MOVE_INTENT_WALK
|
||||
else
|
||||
if (HAS_TRAIT(src,TRAIT_NORUNNING)) // FULPSTATION 7/10/19 So you can't run during fortitude.
|
||||
to_chat(src, "You find yourself unable to run.")
|
||||
return FALSE
|
||||
m_intent = MOVE_INTENT_RUN
|
||||
if(hud_used && hud_used.static_inventory)
|
||||
for(var/obj/screen/mov_intent/selector in hud_used.static_inventory)
|
||||
|
||||
+6
-14
@@ -23,14 +23,6 @@
|
||||
clear_typing_indicator() // clear it immediately!
|
||||
say(message)
|
||||
|
||||
/mob/say_mod(input, message_mode)
|
||||
var/customsayverb = findtext(input, "*")
|
||||
if(customsayverb && message_mode != MODE_WHISPER_CRIT)
|
||||
message_mode = MODE_CUSTOM_SAY
|
||||
return lowertext(copytext_char(input, 1, customsayverb))
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/verb/me_typing_indicator()
|
||||
set name = "me_indicator"
|
||||
set hidden = TRUE
|
||||
@@ -115,9 +107,9 @@
|
||||
deadchat_broadcast(rendered, follow_target = src, speaker_key = key)
|
||||
|
||||
/mob/proc/check_emote(message)
|
||||
if(message[1] == "*")
|
||||
emote(copytext(message, length(message[1]) + 1), intentional = TRUE)
|
||||
return TRUE
|
||||
if(copytext(message, 1, 2) == "*")
|
||||
emote(copytext(message, 2), intentional = TRUE)
|
||||
return 1
|
||||
|
||||
/mob/proc/hivecheck()
|
||||
return 0
|
||||
@@ -126,13 +118,13 @@
|
||||
return LINGHIVE_NONE
|
||||
|
||||
/mob/proc/get_message_mode(message)
|
||||
var/key = message[1]
|
||||
var/key = copytext(message, 1, 2)
|
||||
if(key == "#")
|
||||
return MODE_WHISPER
|
||||
else if(key == "%")
|
||||
return MODE_SING
|
||||
else if(key == ";")
|
||||
return MODE_HEADSET
|
||||
else if((length(message) > (length(key) + 1)) && (key in GLOB.department_radio_prefixes))
|
||||
var/key_symbol = lowertext(message[length(key) + 1])
|
||||
else if(length(message) > 2 && (key in GLOB.department_radio_prefixes))
|
||||
var/key_symbol = lowertext(copytext(message, 2, 3))
|
||||
return GLOB.department_radio_keys[key_symbol]
|
||||
|
||||
+30
-15
@@ -6,10 +6,11 @@
|
||||
set src in usr
|
||||
if(usr != src)
|
||||
to_chat(usr, "No.")
|
||||
var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", html_decode(flavor_text), MAX_MESSAGE_LEN, TRUE)
|
||||
var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", html_decode(flavor_text), MAX_MESSAGE_LEN*2, TRUE)
|
||||
|
||||
if(msg)
|
||||
flavor_text = html_encode(msg)
|
||||
if(!isnull(msg))
|
||||
msg = copytext(msg, 1, MAX_MESSAGE_LEN)
|
||||
msg = html_encode(msg)
|
||||
|
||||
flavor_text = msg
|
||||
|
||||
@@ -22,10 +23,10 @@
|
||||
if(flavor_text && flavor_text != "")
|
||||
// We are decoding and then encoding to not only get correct amount of characters, but also to prevent partial escaping characters being shown.
|
||||
var/msg = html_decode(replacetext(flavor_text, "\n", " "))
|
||||
if(length_char(msg) <= 40)
|
||||
if(length(msg) <= 40)
|
||||
return "<span class='notice'>[html_encode(msg)]</span>"
|
||||
else
|
||||
return "<span class='notice'>[html_encode(copytext_char(msg, 1, 37))]... <a href='?src=[REF(src)];flavor_more=1'>More...</span></a>"
|
||||
return "<span class='notice'>[html_encode(copytext(msg, 1, 37))]... <a href='?src=[REF(src)];flavor_more=1'>More...</span></a>"
|
||||
|
||||
/mob/proc/get_top_level_mob()
|
||||
if(istype(src.loc,/mob)&&src.loc!=src)
|
||||
@@ -52,10 +53,17 @@ proc/get_top_level_mob(var/mob/S)
|
||||
mob_type_blacklist_typecache = list(/mob/living/brain)
|
||||
|
||||
/datum/emote/living/subtle/proc/check_invalid(mob/user, input)
|
||||
if(stop_bad_mime.Find(input, 1, 1))
|
||||
. = TRUE
|
||||
if(copytext(input,1,5) == "says")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
return TRUE
|
||||
return FALSE
|
||||
else if(copytext(input,1,9) == "exclaims")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
else if(copytext(input,1,6) == "yells")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
else if(copytext(input,1,5) == "asks")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
else
|
||||
. = FALSE
|
||||
|
||||
/datum/emote/living/subtle/run_emote(mob/user, params, type_override = null)
|
||||
if(jobban_isbanned(user, "emote"))
|
||||
@@ -65,7 +73,7 @@ proc/get_top_level_mob(var/mob/S)
|
||||
to_chat(user, "You cannot send IC messages (muted).")
|
||||
return FALSE
|
||||
else if(!params)
|
||||
var/subtle_emote = stripped_multiline_input(user, "Choose an emote to display.", "Subtle" , null, MAX_MESSAGE_LEN)
|
||||
var/subtle_emote = copytext(sanitize(input("Choose an emote to display.") as message|null), 1, MAX_MESSAGE_LEN)
|
||||
if(subtle_emote && !check_invalid(user, subtle_emote))
|
||||
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
|
||||
switch(type)
|
||||
@@ -116,10 +124,17 @@ proc/get_top_level_mob(var/mob/S)
|
||||
|
||||
|
||||
/datum/emote/living/subtler/proc/check_invalid(mob/user, input)
|
||||
if(stop_bad_mime.Find(input, 1, 1))
|
||||
. = TRUE
|
||||
if(copytext(input,1,5) == "says")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
return TRUE
|
||||
return FALSE
|
||||
else if(copytext(input,1,9) == "exclaims")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
else if(copytext(input,1,6) == "yells")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
else if(copytext(input,1,5) == "asks")
|
||||
to_chat(user, "<span class='danger'>Invalid emote.</span>")
|
||||
else
|
||||
. = FALSE
|
||||
|
||||
/datum/emote/living/subtler/run_emote(mob/user, params, type_override = null)
|
||||
if(jobban_isbanned(user, "emote"))
|
||||
@@ -129,7 +144,7 @@ proc/get_top_level_mob(var/mob/S)
|
||||
to_chat(user, "You cannot send IC messages (muted).")
|
||||
return FALSE
|
||||
else if(!params)
|
||||
var/subtle_emote = stripped_multiline_input(user, "Choose an emote to display.", "Subtler" , null, MAX_MESSAGE_LEN)
|
||||
var/subtle_emote = copytext(sanitize(input("Choose an emote to display.") as message|null), 1, MAX_MESSAGE_LEN)
|
||||
if(subtle_emote && !check_invalid(user, subtle_emote))
|
||||
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
|
||||
switch(type)
|
||||
@@ -155,9 +170,9 @@ proc/get_top_level_mob(var/mob/S)
|
||||
message = "<b>[user]</b> " + "<i>[user.say_emphasis(message)]</i>"
|
||||
|
||||
if(emote_type == EMOTE_AUDIBLE)
|
||||
user.audible_message(message=message,hearing_distance=1, ignored_mobs = GLOB.dead_mob_list)
|
||||
user.audible_message(message=message,hearing_distance=1, no_ghosts = TRUE)
|
||||
else
|
||||
user.visible_message(message=message,self_message=message,vision_distance=1, ignored_mobs = GLOB.dead_mob_list)
|
||||
user.visible_message(message=message,self_message=message,vision_distance=1, no_ghosts = TRUE)
|
||||
log_emote("[key_name(user)] : (SUBTLER) [message]")
|
||||
|
||||
message = null
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
|
||||
// hash the original name?
|
||||
if(tr_flags & TR_HASHNAME)
|
||||
O.name = "monkey ([copytext_char(md5(real_name), 2, 6)])"
|
||||
O.real_name = "monkey ([copytext_char(md5(real_name), 2, 6)])"
|
||||
O.name = "monkey ([copytext(md5(real_name), 2, 6)])"
|
||||
O.real_name = "monkey ([copytext(md5(real_name), 2, 6)])"
|
||||
|
||||
//handle DNA and other attributes
|
||||
dna.transfer_identity(O)
|
||||
@@ -201,7 +201,7 @@
|
||||
dna.transfer_identity(O)
|
||||
O.updateappearance(mutcolor_update=1)
|
||||
|
||||
if(findtext(O.dna.real_name, "monkey", 1, 7)) //7 == length("monkey") + 1
|
||||
if(cmptext("monkey",copytext(O.dna.real_name,1,7)))
|
||||
O.real_name = random_unique_name(O.gender)
|
||||
O.dna.generate_unique_enzymes(O)
|
||||
else
|
||||
|
||||
@@ -32,7 +32,7 @@ GLOBAL_LIST_EMPTY(typing_indicator_overlays)
|
||||
* @param force - shows even if src.typing_indcator_enabled is FALSE.
|
||||
*/
|
||||
/mob/proc/display_typing_indicator(timeout_override = TYPING_INDICATOR_TIMEOUT, state_override = generate_typing_indicator(), force = FALSE)
|
||||
if(((!typing_indicator_enabled || (stat != CONSCIOUS)) && !force) || typing_indicator_current)
|
||||
if((!typing_indicator_enabled && !force) || typing_indicator_current)
|
||||
return
|
||||
typing_indicator_current = state_override
|
||||
add_overlay(state_override)
|
||||
|
||||
Reference in New Issue
Block a user