Merge pull request #755 from ArchieBeepBoop/reagentsagain

Ports reagents id removal and typepath usage
This commit is contained in:
QuoteFox
2020-12-23 17:48:37 +00:00
committed by GitHub
323 changed files with 31959 additions and 32469 deletions
+7 -7
View File
@@ -155,7 +155,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 == "blood" || blood_id == "jellyblood") //normal blood
if(blood_id == /datum/reagent/blood || blood_id == /datum/reagent/blood/jellyblood) //normal blood
if(blood_data["viruses"])
for(var/thing in blood_data["viruses"])
var/datum/disease/D = thing
@@ -175,7 +175,7 @@
return
/mob/living/carbon/get_blood_data(blood_id)
if(blood_id == "blood" || blood_id == "jellyblood") //actual blood reagent
if(blood_id == /datum/reagent/blood || /datum/reagent/blood/jellyblood) //actual blood reagent
var/blood_data = list()
//set the blood data
blood_data["donor"] = src
@@ -191,7 +191,7 @@
blood_data["resistances"] = disease_resistances.Copy()
var/list/temp_chem = list()
for(var/datum/reagent/R in reagents.reagent_list)
temp_chem[R.id] = R.volume
temp_chem[R.type] = R.volume
blood_data["trace_chem"] = list2params(temp_chem)
if(mind)
blood_data["mind"] = mind
@@ -226,21 +226,21 @@
/mob/living/simple_animal/get_blood_id()
if(blood_volume)
return "blood"
return /datum/reagent/blood
/mob/living/carbon/monkey/get_blood_id()
if(!(HAS_TRAIT(src, TRAIT_NOCLONE)))
return "blood"
return /datum/reagent/blood
/mob/living/carbon/get_blood_id()
if(isjellyperson(src))
return "jellyblood"
return /datum/reagent/blood/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 "blood"
return /datum/reagent/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("demonsblood"))
else if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/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("devilskiss"))
if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/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
+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("neurine")) //Neurine fixes dead brains
if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent(/datum/reagent/medicine/neurine)) //Neurine fixes dead brains
. = TRUE //don't do attack animation.
var/cached_Bdamage = brainmob?.health
var/datum/reagent/medicine/neurine/N = O.reagents.has_reagent("neurine")
var/datum/reagent/medicine/mannitol/M1 = O.reagents.has_reagent("mannitol")
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)
if(O.reagents.has_reagent("mannitol"))//Just a quick way to bolster the effects if someone mixes up a batch.
if(O.reagents.has_reagent(/datum/reagent/medicine/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("neurine", 10))
if(!O.reagents.has_reagent(/datum/reagent/medicine/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("mannitol")) //attempt to heal the brain
if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent(/datum/reagent/medicine/mannitol)) //attempt to heal the brain
. = TRUE //don't do attack animation.
var/datum/reagent/medicine/mannitol/M = O.reagents.has_reagent("mannitol")
var/datum/reagent/medicine/mannitol/M = reagents.has_reagent(/datum/reagent/medicine/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("mannitol", 10))
if(!O.reagents.has_reagent(/datum/reagent/medicine/mannitol, 10))
to_chat(user, "<span class='warning'>There's not enough mannitol in [O] to restore [src]!</span>")
return
@@ -27,7 +27,7 @@
/obj/item/organ/alien/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent("sacid", 10)
S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
return S
@@ -46,7 +46,7 @@
/obj/item/organ/alien/plasmavessel/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent("plasma", storedPlasma/10)
S.reagents.add_reagent(/datum/reagent/toxin/plasma, storedPlasma/10)
return S
/obj/item/organ/alien/plasmavessel/large
@@ -1,137 +1,137 @@
// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability
// It functions almost identically (see code/datums/diseases/alien_embryo.dm)
/obj/item/organ/body_egg/alien_embryo
name = "alien embryo"
icon = 'icons/mob/alien.dmi'
icon_state = "larva0_dead"
var/stage = 0
var/bursting = FALSE
/obj/item/organ/body_egg/alien_embryo/on_find(mob/living/finder)
..()
if(stage < 4)
to_chat(finder, "It's small and weak, barely the size of a foetus.")
else
to_chat(finder, "It's grown quite large, and writhes slightly as you look at it.")
if(prob(10))
AttemptGrow(0)
/obj/item/organ/body_egg/alien_embryo/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent("sacid", 10)
return S
/obj/item/organ/body_egg/alien_embryo/on_life()
.=..()
switch(stage)
if(2, 3)
if(prob(2))
owner.emote("sneeze")
if(prob(2))
owner.emote("cough")
if(prob(2))
to_chat(owner, "<span class='danger'>Your throat feels sore.</span>")
if(prob(2))
to_chat(owner, "<span class='danger'>Mucous runs down the back of your throat.</span>")
if(4)
if(prob(2))
owner.emote("sneeze")
if(prob(2))
owner.emote("cough")
if(prob(4))
to_chat(owner, "<span class='danger'>Your muscles ache.</span>")
if(prob(20))
owner.take_bodypart_damage(1)
if(prob(4))
to_chat(owner, "<span class='danger'>Your stomach hurts.</span>")
if(prob(20))
owner.adjustToxLoss(1)
if(5)
to_chat(owner, "<span class='danger'>You feel something tearing its way out of your stomach...</span>")
owner.adjustToxLoss(10)
/obj/item/organ/body_egg/alien_embryo/egg_process()
if(stage < 5 && prob(3))
stage++
INVOKE_ASYNC(src, .proc/RefreshInfectionImage)
if(stage == 5 && prob(50))
for(var/datum/surgery/S in owner.surgeries)
if(S.location == BODY_ZONE_CHEST && istype(S.get_surgery_step(), /datum/surgery_step/manipulate_organs))
AttemptGrow(0)
return
AttemptGrow()
/obj/item/organ/body_egg/alien_embryo/proc/AttemptGrow(var/kill_on_sucess=TRUE)
if(!owner || bursting)
return
bursting = TRUE
var/list/candidates = pollGhostCandidates("Do you want to play as an alien larva that will burst out of [owner]?", ROLE_ALIEN, null, ROLE_ALIEN, 100, POLL_IGNORE_ALIEN_LARVA)
if(QDELETED(src) || QDELETED(owner))
return
if(!candidates.len || !owner)
bursting = FALSE
stage = 4
return
var/mob/dead/observer/ghost = pick(candidates)
var/mutable_appearance/overlay = mutable_appearance('icons/mob/alien.dmi', "burst_lie")
owner.add_overlay(overlay)
var/atom/xeno_loc = get_turf(owner)
var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc)
new_xeno.key = ghost.key
SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention
new_xeno.canmove = 0 //so we don't move during the bursting animation
new_xeno.notransform = 1
new_xeno.invisibility = INVISIBILITY_MAXIMUM
sleep(6)
if(QDELETED(src) || QDELETED(owner))
return
if(new_xeno)
new_xeno.canmove = 1
new_xeno.notransform = 0
new_xeno.invisibility = 0
if(kill_on_sucess) //ITS TOO LATE
new_xeno.visible_message("<span class='danger'>[new_xeno] bursts out of [owner]!</span>", "<span class='userdanger'>You exit [owner], your previous host.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
owner.apply_damage(rand(100,300),BRUTE,zone,FALSE) //Random high damage to torso so health sensors don't metagame.
owner.spill_organs(TRUE,FALSE,TRUE) //Lets still make the death gruesome and impossible to just simply defib someone.
owner.death(FALSE) //Just in case some freak occurance occurs where you somehow survive all your organs being removed from you and the 100-300 brute damage.
else //When it is removed via surgery at a late stage, rather than forced.
new_xeno.visible_message("<span class='danger'>[new_xeno] wriggles out of [owner]!</span>", "<span class='userdanger'>You exit [owner], your previous host.</span>")
owner.adjustBruteLoss(40)
owner.cut_overlay(overlay)
qdel(src)
/*----------------------------------------
Proc: AddInfectionImages(C)
Des: Adds the infection image to all aliens for this embryo
----------------------------------------*/
/obj/item/organ/body_egg/alien_embryo/AddInfectionImages()
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
if(alien.client)
var/I = image('icons/mob/alien.dmi', loc = owner, icon_state = "infected[stage]")
alien.client.images += I
/*----------------------------------------
Proc: RemoveInfectionImage(C)
Des: Removes all images from the mob infected by this embryo
----------------------------------------*/
/obj/item/organ/body_egg/alien_embryo/RemoveInfectionImages()
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
if(alien.client)
for(var/image/I in alien.client.images)
if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == owner)
qdel(I)
// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability
// It functions almost identically (see code/datums/diseases/alien_embryo.dm)
/obj/item/organ/body_egg/alien_embryo
name = "alien embryo"
icon = 'icons/mob/alien.dmi'
icon_state = "larva0_dead"
var/stage = 0
var/bursting = FALSE
/obj/item/organ/body_egg/alien_embryo/on_find(mob/living/finder)
..()
if(stage < 4)
to_chat(finder, "It's small and weak, barely the size of a foetus.")
else
to_chat(finder, "It's grown quite large, and writhes slightly as you look at it.")
if(prob(10))
AttemptGrow(0)
/obj/item/organ/body_egg/alien_embryo/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
return S
/obj/item/organ/body_egg/alien_embryo/on_life()
.=..()
switch(stage)
if(2, 3)
if(prob(2))
owner.emote("sneeze")
if(prob(2))
owner.emote("cough")
if(prob(2))
to_chat(owner, "<span class='danger'>Your throat feels sore.</span>")
if(prob(2))
to_chat(owner, "<span class='danger'>Mucous runs down the back of your throat.</span>")
if(4)
if(prob(2))
owner.emote("sneeze")
if(prob(2))
owner.emote("cough")
if(prob(4))
to_chat(owner, "<span class='danger'>Your muscles ache.</span>")
if(prob(20))
owner.take_bodypart_damage(1)
if(prob(4))
to_chat(owner, "<span class='danger'>Your stomach hurts.</span>")
if(prob(20))
owner.adjustToxLoss(1)
if(5)
to_chat(owner, "<span class='danger'>You feel something tearing its way out of your stomach...</span>")
owner.adjustToxLoss(10)
/obj/item/organ/body_egg/alien_embryo/egg_process()
if(stage < 5 && prob(3))
stage++
INVOKE_ASYNC(src, .proc/RefreshInfectionImage)
if(stage == 5 && prob(50))
for(var/datum/surgery/S in owner.surgeries)
if(S.location == BODY_ZONE_CHEST && istype(S.get_surgery_step(), /datum/surgery_step/manipulate_organs))
AttemptGrow(0)
return
AttemptGrow()
/obj/item/organ/body_egg/alien_embryo/proc/AttemptGrow(var/kill_on_sucess=TRUE)
if(!owner || bursting)
return
bursting = TRUE
var/list/candidates = pollGhostCandidates("Do you want to play as an alien larva that will burst out of [owner]?", ROLE_ALIEN, null, ROLE_ALIEN, 100, POLL_IGNORE_ALIEN_LARVA)
if(QDELETED(src) || QDELETED(owner))
return
if(!candidates.len || !owner)
bursting = FALSE
stage = 4
return
var/mob/dead/observer/ghost = pick(candidates)
var/mutable_appearance/overlay = mutable_appearance('icons/mob/alien.dmi', "burst_lie")
owner.add_overlay(overlay)
var/atom/xeno_loc = get_turf(owner)
var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc)
new_xeno.key = ghost.key
SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention
new_xeno.canmove = 0 //so we don't move during the bursting animation
new_xeno.notransform = 1
new_xeno.invisibility = INVISIBILITY_MAXIMUM
sleep(6)
if(QDELETED(src) || QDELETED(owner))
return
if(new_xeno)
new_xeno.canmove = 1
new_xeno.notransform = 0
new_xeno.invisibility = 0
if(kill_on_sucess) //ITS TOO LATE
new_xeno.visible_message("<span class='danger'>[new_xeno] bursts out of [owner]!</span>", "<span class='userdanger'>You exit [owner], your previous host.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
owner.apply_damage(rand(100,300),BRUTE,zone,FALSE) //Random high damage to torso so health sensors don't metagame.
owner.spill_organs(TRUE,FALSE,TRUE) //Lets still make the death gruesome and impossible to just simply defib someone.
owner.death(FALSE) //Just in case some freak occurance occurs where you somehow survive all your organs being removed from you and the 100-300 brute damage.
else //When it is removed via surgery at a late stage, rather than forced.
new_xeno.visible_message("<span class='danger'>[new_xeno] wriggles out of [owner]!</span>", "<span class='userdanger'>You exit [owner], your previous host.</span>")
owner.adjustBruteLoss(40)
owner.cut_overlay(overlay)
qdel(src)
/*----------------------------------------
Proc: AddInfectionImages(C)
Des: Adds the infection image to all aliens for this embryo
----------------------------------------*/
/obj/item/organ/body_egg/alien_embryo/AddInfectionImages()
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
if(alien.client)
var/I = image('icons/mob/alien.dmi', loc = owner, icon_state = "infected[stage]")
alien.client.images += I
/*----------------------------------------
Proc: RemoveInfectionImage(C)
Des: Removes all images from the mob infected by this embryo
----------------------------------------*/
/obj/item/organ/body_egg/alien_embryo/RemoveInfectionImages()
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
if(alien.client)
for(var/image/I in alien.client.images)
if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == owner)
qdel(I)
+1 -1
View File
@@ -518,7 +518,7 @@
add_splatter_floor(T)
if(stun)
adjustBruteLoss(3)
else if(src.reagents.has_reagent("blazaam"))
else if(src.reagents.has_reagent(/datum/reagent/consumable/ethanol/blazaam))
if(T)
T.add_vomit_floor(src, VOMIT_PURPLE)
else
+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("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(/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
+420 -421
View File
@@ -1,421 +1,420 @@
/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"
//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("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()
/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"
//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 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()
@@ -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.id == exotic_blood)
if(chem.type == exotic_blood)
H.blood_volume = min(H.blood_volume + round(chem.volume, 0.1), BLOOD_VOLUME_MAXIMUM)
H.reagents.del_reagent(chem.id)
H.reagents.del_reagent(chem.type)
return 1
return FALSE
@@ -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.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
/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
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.id == "weedkiller")
if(chem.type == /datum/reagent/toxin/plantbgone/weedkiller)
H.adjustToxLoss(3)
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
H.reagents.remove_reagent(chem.type, 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.id == "plantbgone")
if(chem.type == /datum/reagent/toxin/plantbgone)
H.adjustToxLoss(3)
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
H.reagents.remove_reagent(chem.type, 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.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
/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
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("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(/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
+3 -3
View File
@@ -1228,7 +1228,7 @@
clamp_unconscious_to = 0,
clamp_immobility_to = 0,
reset_misc = TRUE,
healing_chems = list("inaprovaline" = 3, "synaptizine" = 10, "regen_jelly" = 10, "stimulants" = 10),
healing_chems = list(/datum/reagent/medicine/inaprovaline = 3, /datum/reagent/medicine/synaptizine = 10, /datum/reagent/medicine/regen_jelly = 10, /datum/reagent/medicine/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()
for(var/chem in healing_chems)
reagents.add_reagent(chem, healing_chems[chem])
if(healing_chems)
reagents.add_reagent_list(healing_chems)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -45,7 +45,7 @@
if(isliving(A))
if(ishuman(A))
var/mob/living/carbon/human/H = A
if(H.reagents.has_reagent("astral") && !H.mind)
if(H.reagents.has_reagent(/datum/reagent/fermi/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>")
File diff suppressed because it is too large Load Diff
@@ -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("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(/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)
@@ -1,319 +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("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
..()
//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
/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
..()
@@ -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("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>")
//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>")
@@ -114,9 +114,9 @@
icon_state = "mouse_gray_dead"
bitesize = 3
eatverb = "devour"
list_reagents = list("nutriment" = 3, "vitamin" = 2)
list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2)
foodtype = GROSS | MEAT | RAW
grind_results = list("blood" = 20, "liquidgibs" = 5)
grind_results = list(/datum/reagent/blood = 20, /datum/reagent/liquidgibs = 5)
/obj/item/reagent_containers/food/snacks/deadmouse/on_grind()
reagents.clear_reagents()
@@ -1,6 +1,6 @@
/mob/living/simple_animal/hostile/retaliate/poison
var/poison_per_bite = 0
var/poison_type = "toxin"
var/poison_per_bite = 0
var/poison_type = /datum/reagent/toxin
/mob/living/simple_animal/hostile/retaliate/poison/AttackingTarget()
. = ..()
@@ -140,7 +140,7 @@
var/mob/living/L = target
if(L.reagents)
beegent.reaction_mob(L, INJECT)
L.reagents.add_reagent(beegent.id, rand(1,5))
L.reagents.add_reagent(beegent.type, 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[initial(R.id)])
assign_reagent(GLOB.chemical_reagents_list[R])
/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.id, rand(1,5))
L.reagents.add_reagent(beegent.type, 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.id != beegent.id || B.beegent && !beegent || !B.beegent && beegent)
if(B.beegent && beegent && B.beegent.type != beegent.type || B.beegent && !beegent || !B.beegent && beegent)
return TRUE
return FALSE
@@ -253,9 +253,10 @@
/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
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/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)
var/obj/item/queen_bee/qb = new(user.drop_location())
qb.queen = new(qb)
if(queen && queen.beegent)
@@ -266,8 +267,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.id, 5))
S.reagents.remove_reagent(R.id,5)
if(R && S.reagents.has_reagent(R.type, 5))
S.reagents.remove_reagent(R.type,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
File diff suppressed because it is too large Load Diff
@@ -42,7 +42,7 @@
..()
if(iscarbon(target))
var/mob/living/carbon/C = target
C.reagents.add_reagent("leaper_venom", 5)
C.reagents.add_reagent(/datum/reagent/toxin/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("leaper_venom", 5)
C.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5)
if(isanimal(L))
var/mob/living/simple_animal/A = L
A.adjustHealth(25)
@@ -105,7 +105,6 @@
/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
@@ -131,7 +131,7 @@
/obj/item/udder/gutlunch/generateMilk()
if(prob(60))
reagents.add_reagent("cream", rand(2, 5))
reagents.add_reagent(/datum/reagent/consumable/cream, rand(2, 5))
if(prob(45))
reagents.add_reagent("salglu_solution", rand(2,5))
reagents.add_reagent(/datum/reagent/medicine/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("mushroomhallucinogen", powerlevel)
S.reagents.add_reagent("omnizine", powerlevel)
S.reagents.add_reagent("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(/datum/reagent/drug/mushroomhallucinogen, powerlevel)
S.reagents.add_reagent(/datum/reagent/medicine/omnizine, powerlevel)
S.reagents.add_reagent(/datum/reagent/medicine/synaptizine, powerlevel)
@@ -141,9 +141,9 @@
. = ..()
remove_movespeed_modifier(MOVESPEED_ID_SLIME_REAGENTMOD, TRUE)
var/amount = 0
if(reagents.has_reagent("morphine")) // morphine slows slimes down
if(reagents.has_reagent(/datum/reagent/medicine/morphine)) // morphine slows slimes down
amount = 2
if(reagents.has_reagent("frostoil")) // Frostoil also makes them move VEEERRYYYYY slow
if(reagents.has_reagent(/datum/reagent/consumable/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)