Revert "Merge branch 'punishesarchie' of https://github.com/MalricB/Hyper-Station-13 into punishesarchie"

This reverts commit 1945c166b4, reversing
changes made to c8d20ea83c.
This commit is contained in:
CygnusB
2021-01-19 06:40:28 -03:00
parent 1945c166b4
commit 8cda8bbd16
1465 changed files with 202589 additions and 377073 deletions
@@ -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)
+7 -11
View File
@@ -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))
+6 -5
View File
@@ -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]")
+1 -1
View File
@@ -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
+9 -12
View File
@@ -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)
+2 -2
View File
@@ -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 -1
View File
@@ -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
+8 -8
View File
@@ -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)
+2 -24
View File
@@ -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 ..()
+486 -486
View File
@@ -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
View File
@@ -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 ..()
+1 -2
View File
@@ -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'
+414 -426
View File
@@ -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)
+26 -18
View File
@@ -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
+175 -175
View File
@@ -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
+15 -1
View File
@@ -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
-1
View File
@@ -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()
+13 -6
View File
@@ -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)
+3 -3
View File
@@ -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
+2 -4
View File
@@ -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.
+37 -41
View File
@@ -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)
File diff suppressed because it is too large Load Diff
+197 -197
View File
@@ -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
+1 -2
View File
@@ -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 ..()
-3
View File
@@ -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))
+6 -24
View File
@@ -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
+5 -5
View File
@@ -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)
+13 -18
View File
@@ -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)
-1
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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
-3
View File
@@ -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
View File
@@ -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
View File
@@ -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
+3 -3
View File
@@ -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
+1 -1
View File
@@ -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)